]> Git Repo - J-linux.git/blob - tools/testing/selftests/mm/migration.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / tools / testing / selftests / mm / migration.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * The main purpose of the tests here is to exercise the migration entry code
4  * paths in the kernel.
5  */
6
7 #include "../kselftest_harness.h"
8 #include <strings.h>
9 #include <pthread.h>
10 #include <numa.h>
11 #include <numaif.h>
12 #include <sys/mman.h>
13 #include <sys/types.h>
14 #include <signal.h>
15 #include <time.h>
16
17 #define TWOMEG (2<<20)
18 #define RUNTIME (60)
19
20 #define ALIGN(x, a) (((x) + (a - 1)) & (~((a) - 1)))
21
22 FIXTURE(migration)
23 {
24         pthread_t *threads;
25         pid_t *pids;
26         int nthreads;
27         int n1;
28         int n2;
29 };
30
31 FIXTURE_SETUP(migration)
32 {
33         int n;
34
35         ASSERT_EQ(numa_available(), 0);
36         self->nthreads = numa_num_task_cpus() - 1;
37         self->n1 = -1;
38         self->n2 = -1;
39
40         for (n = 0; n < numa_max_possible_node(); n++)
41                 if (numa_bitmask_isbitset(numa_all_nodes_ptr, n)) {
42                         if (self->n1 == -1) {
43                                 self->n1 = n;
44                         } else {
45                                 self->n2 = n;
46                                 break;
47                         }
48                 }
49
50         self->threads = malloc(self->nthreads * sizeof(*self->threads));
51         ASSERT_NE(self->threads, NULL);
52         self->pids = malloc(self->nthreads * sizeof(*self->pids));
53         ASSERT_NE(self->pids, NULL);
54 };
55
56 FIXTURE_TEARDOWN(migration)
57 {
58         free(self->threads);
59         free(self->pids);
60 }
61
62 int migrate(uint64_t *ptr, int n1, int n2)
63 {
64         int ret, tmp;
65         int status = 0;
66         struct timespec ts1, ts2;
67
68         if (clock_gettime(CLOCK_MONOTONIC, &ts1))
69                 return -1;
70
71         while (1) {
72                 if (clock_gettime(CLOCK_MONOTONIC, &ts2))
73                         return -1;
74
75                 if (ts2.tv_sec - ts1.tv_sec >= RUNTIME)
76                         return 0;
77
78                 ret = move_pages(0, 1, (void **) &ptr, &n2, &status,
79                                 MPOL_MF_MOVE_ALL);
80                 if (ret) {
81                         if (ret > 0)
82                                 printf("Didn't migrate %d pages\n", ret);
83                         else
84                                 perror("Couldn't migrate pages");
85                         return -2;
86                 }
87
88                 tmp = n2;
89                 n2 = n1;
90                 n1 = tmp;
91         }
92
93         return 0;
94 }
95
96 void *access_mem(void *ptr)
97 {
98         uint64_t y = 0;
99         volatile uint64_t *x = ptr;
100
101         while (1) {
102                 pthread_testcancel();
103                 y += *x;
104         }
105
106         return NULL;
107 }
108
109 /*
110  * Basic migration entry testing. One thread will move pages back and forth
111  * between nodes whilst other threads try and access them triggering the
112  * migration entry wait paths in the kernel.
113  */
114 TEST_F_TIMEOUT(migration, private_anon, 2*RUNTIME)
115 {
116         uint64_t *ptr;
117         int i;
118
119         if (self->nthreads < 2 || self->n1 < 0 || self->n2 < 0)
120                 SKIP(return, "Not enough threads or NUMA nodes available");
121
122         ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE,
123                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
124         ASSERT_NE(ptr, MAP_FAILED);
125
126         memset(ptr, 0xde, TWOMEG);
127         for (i = 0; i < self->nthreads - 1; i++)
128                 if (pthread_create(&self->threads[i], NULL, access_mem, ptr))
129                         perror("Couldn't create thread");
130
131         ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
132         for (i = 0; i < self->nthreads - 1; i++)
133                 ASSERT_EQ(pthread_cancel(self->threads[i]), 0);
134 }
135
136 /*
137  * Same as the previous test but with shared memory.
138  */
139 TEST_F_TIMEOUT(migration, shared_anon, 2*RUNTIME)
140 {
141         pid_t pid;
142         uint64_t *ptr;
143         int i;
144
145         if (self->nthreads < 2 || self->n1 < 0 || self->n2 < 0)
146                 SKIP(return, "Not enough threads or NUMA nodes available");
147
148         ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE,
149                 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
150         ASSERT_NE(ptr, MAP_FAILED);
151
152         memset(ptr, 0xde, TWOMEG);
153         for (i = 0; i < self->nthreads - 1; i++) {
154                 pid = fork();
155                 if (!pid)
156                         access_mem(ptr);
157                 else
158                         self->pids[i] = pid;
159         }
160
161         ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
162         for (i = 0; i < self->nthreads - 1; i++)
163                 ASSERT_EQ(kill(self->pids[i], SIGTERM), 0);
164 }
165
166 /*
167  * Tests the pmd migration entry paths.
168  */
169 TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)
170 {
171         uint64_t *ptr;
172         int i;
173
174         if (self->nthreads < 2 || self->n1 < 0 || self->n2 < 0)
175                 SKIP(return, "Not enough threads or NUMA nodes available");
176
177         ptr = mmap(NULL, 2*TWOMEG, PROT_READ | PROT_WRITE,
178                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
179         ASSERT_NE(ptr, MAP_FAILED);
180
181         ptr = (uint64_t *) ALIGN((uintptr_t) ptr, TWOMEG);
182         ASSERT_EQ(madvise(ptr, TWOMEG, MADV_HUGEPAGE), 0);
183         memset(ptr, 0xde, TWOMEG);
184         for (i = 0; i < self->nthreads - 1; i++)
185                 if (pthread_create(&self->threads[i], NULL, access_mem, ptr))
186                         perror("Couldn't create thread");
187
188         ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
189         for (i = 0; i < self->nthreads - 1; i++)
190                 ASSERT_EQ(pthread_cancel(self->threads[i]), 0);
191 }
192
193 TEST_HARNESS_MAIN
This page took 0.038993 seconds and 4 git commands to generate.