xref: /linux/tools/testing/selftests/mm/migration.c (revision c16ce856e422e73a54c41131e0332de1afe09b8b)
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 "hugepage_settings.h"
9 
10 #include <strings.h>
11 #include <pthread.h>
12 #include <numa.h>
13 #include <numaif.h>
14 #include <sys/mman.h>
15 #include <sys/prctl.h>
16 #include <sys/types.h>
17 #include <signal.h>
18 #include <time.h>
19 #include "vm_util.h"
20 
21 #define TWOMEG		(2<<20)
22 #define RUNTIME		(20)
23 #define MAX_RETRIES	100
24 #define ALIGN(x, a)	(((x) + (a - 1)) & (~((a) - 1)))
25 
26 HUGETLB_SETUP_DEFAULT_PAGES(1)
27 
28 FIXTURE(migration)
29 {
30 	pthread_t *threads;
31 	pid_t *pids;
32 	int nthreads;
33 	int n1;
34 	int n2;
35 };
36 
37 static void reset_signals(void)
38 {
39 	struct sigaction sa = { .sa_handler = SIG_DFL };
40 
41 	sigemptyset(&sa.sa_mask);
42 	sigaction(SIGTERM, &sa, NULL);
43 	sigaction(SIGHUP, &sa, NULL);
44 	sigaction(SIGINT, &sa, NULL);
45 	sigaction(SIGQUIT, &sa, NULL);
46 }
47 
48 FIXTURE_SETUP(migration)
49 {
50 	int n;
51 
52 	reset_signals();
53 
54 	if (numa_available() < 0)
55 		SKIP(return, "NUMA not available");
56 	self->nthreads = numa_num_task_cpus() - 2;
57 	self->n1 = -1;
58 	self->n2 = -1;
59 
60 	for (n = 0; n < numa_max_possible_node(); n++)
61 		if (numa_bitmask_isbitset(numa_all_nodes_ptr, n)) {
62 			if (self->n1 == -1) {
63 				self->n1 = n;
64 			} else {
65 				self->n2 = n;
66 				break;
67 			}
68 		}
69 
70 	if (self->nthreads < 1 || self->n1 < 0 || self->n2 < 0)
71 		SKIP(return, "Not enough threads or NUMA nodes available");
72 
73 	self->threads = malloc(self->nthreads * sizeof(*self->threads));
74 	ASSERT_NE(self->threads, NULL);
75 	self->pids = malloc(self->nthreads * sizeof(*self->pids));
76 	ASSERT_NE(self->pids, NULL);
77 };
78 
79 FIXTURE_TEARDOWN(migration)
80 {
81 	free(self->threads);
82 	free(self->pids);
83 }
84 
85 static bool kill_children(FIXTURE_DATA(migration) * self)
86 {
87 	bool err = false;
88 	pid_t pid;
89 	int i;
90 
91 	for (i = 0; i < self->nthreads; i++) {
92 		int status = 0;
93 
94 		pid = self->pids[i];
95 		if (pid < 0)
96 			continue;
97 		if (kill(pid, SIGTERM))
98 			err = true;
99 		if (pid != waitpid(pid, &status, 0))
100 			err = true;
101 		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGTERM)
102 			err = true;
103 	}
104 
105 	return !err;
106 }
107 
108 int migrate(uint64_t *ptr, int n1, int n2)
109 {
110 	int ret, tmp;
111 	int status = 0;
112 	struct timespec ts1, ts2;
113 	int failures = 0;
114 
115 	if (clock_gettime(CLOCK_MONOTONIC, &ts1))
116 		return -1;
117 
118 	while (1) {
119 		if (clock_gettime(CLOCK_MONOTONIC, &ts2))
120 			return -1;
121 
122 		if (ts2.tv_sec - ts1.tv_sec >= RUNTIME)
123 			return 0;
124 
125 		ret = move_pages(0, 1, (void **) &ptr, &n2, &status,
126 				MPOL_MF_MOVE_ALL);
127 		if (ret) {
128 			if (ret > 0) {
129 				/* Migration is best effort; try again */
130 				if (++failures < MAX_RETRIES)
131 					continue;
132 				printf("Didn't migrate %d pages\n", ret);
133 			}
134 			else
135 				perror("Couldn't migrate pages");
136 			return -2;
137 		}
138 		failures = 0;
139 		tmp = n2;
140 		n2 = n1;
141 		n1 = tmp;
142 	}
143 
144 	return 0;
145 }
146 
147 void *access_mem(void *ptr)
148 {
149 	while (1) {
150 		pthread_testcancel();
151 		/* Force a read from the memory pointed to by ptr. This ensures
152 		 * the memory access actually happens and prevents the compiler
153 		 * from optimizing away this entire loop.
154 		 */
155 		FORCE_READ(*(uint64_t *)ptr);
156 	}
157 
158 	return NULL;
159 }
160 
161 /*
162  * Basic migration entry testing. One thread will move pages back and forth
163  * between nodes whilst other threads try and access them triggering the
164  * migration entry wait paths in the kernel.
165  */
166 TEST_F_TIMEOUT(migration, private_anon, 2*RUNTIME)
167 {
168 	uint64_t *ptr;
169 	int i;
170 
171 	ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE,
172 		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
173 	ASSERT_NE(ptr, MAP_FAILED);
174 
175 	memset(ptr, 0xde, TWOMEG);
176 	for (i = 0; i < self->nthreads; i++)
177 		if (pthread_create(&self->threads[i], NULL, access_mem, ptr))
178 			perror("Couldn't create thread");
179 
180 	ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
181 	for (i = 0; i < self->nthreads; i++)
182 		ASSERT_EQ(pthread_cancel(self->threads[i]), 0);
183 }
184 
185 /*
186  * Same as the previous test but with shared memory.
187  */
188 TEST_F_TIMEOUT(migration, shared_anon, 2*RUNTIME)
189 {
190 	pid_t pid;
191 	uint64_t *ptr;
192 	int i, err;
193 
194 	ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE,
195 		MAP_SHARED | MAP_ANONYMOUS, -1, 0);
196 	ASSERT_NE(ptr, MAP_FAILED);
197 
198 	memset(ptr, 0xde, TWOMEG);
199 	for (i = 0; i < self->nthreads; i++) {
200 		pid = fork();
201 		if (!pid) {
202 			prctl(PR_SET_PDEATHSIG, SIGHUP);
203 			/* Parent may have died before prctl so check now. */
204 			if (getppid() == 1)
205 				kill(getpid(), SIGHUP);
206 			access_mem(ptr);
207 		} else {
208 			self->pids[i] = pid;
209 		}
210 	}
211 
212 	err = migrate(ptr, self->n1, self->n2);
213 	ASSERT_EQ(kill_children(self), true);
214 	ASSERT_EQ(err, 0);
215 }
216 
217 /*
218  * Tests the pmd migration entry paths.
219  */
220 TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)
221 {
222 	uint64_t pmdsize;
223 	uint64_t *ptr;
224 	int i;
225 
226 	if (!thp_is_enabled())
227 		SKIP(return, "Transparent Hugepages not available");
228 
229 	pmdsize = read_pmd_pagesize();
230 	if (!pmdsize)
231 		SKIP(return, "Reading PMD pagesize failed");
232 
233 	ptr = mmap(NULL, 2 * pmdsize, PROT_READ | PROT_WRITE,
234 		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
235 	ASSERT_NE(ptr, MAP_FAILED);
236 
237 	ptr = (uint64_t *) ALIGN((uintptr_t) ptr, pmdsize);
238 	ASSERT_EQ(madvise(ptr, pmdsize, MADV_HUGEPAGE), 0);
239 	memset(ptr, 0xde, pmdsize);
240 	for (i = 0; i < self->nthreads; i++)
241 		if (pthread_create(&self->threads[i], NULL, access_mem, ptr))
242 			perror("Couldn't create thread");
243 
244 	ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
245 	for (i = 0; i < self->nthreads; i++)
246 		ASSERT_EQ(pthread_cancel(self->threads[i]), 0);
247 }
248 
249 /*
250  * migration test with shared anon THP page
251  */
252 
253 TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME)
254 {
255 	uint64_t pmdsize;
256 	pid_t pid;
257 	uint64_t *ptr;
258 	int i, err;
259 
260 	if (!thp_is_enabled())
261 		SKIP(return, "Transparent Hugepages not available");
262 
263 	pmdsize = read_pmd_pagesize();
264 	if (!pmdsize)
265 		SKIP(return, "Reading PMD pagesize failed");
266 
267 	ptr = mmap(NULL, 2 * pmdsize, PROT_READ | PROT_WRITE,
268 		MAP_SHARED | MAP_ANONYMOUS, -1, 0);
269 	ASSERT_NE(ptr, MAP_FAILED);
270 
271 	ptr = (uint64_t *) ALIGN((uintptr_t) ptr, pmdsize);
272 	ASSERT_EQ(madvise(ptr, pmdsize, MADV_HUGEPAGE), 0);
273 
274 	memset(ptr, 0xde, pmdsize);
275 	for (i = 0; i < self->nthreads; i++) {
276 		pid = fork();
277 		if (!pid) {
278 			prctl(PR_SET_PDEATHSIG, SIGHUP);
279 			/* Parent may have died before prctl so check now. */
280 			if (getppid() == 1)
281 				kill(getpid(), SIGHUP);
282 			access_mem(ptr);
283 		} else {
284 			self->pids[i] = pid;
285 		}
286 	}
287 
288 	err = migrate(ptr, self->n1, self->n2);
289 	ASSERT_EQ(kill_children(self), true);
290 	ASSERT_EQ(err, 0);
291 }
292 
293 /*
294  * migration test with private anon hugetlb page
295  */
296 TEST_F_TIMEOUT(migration, private_anon_htlb, 2*RUNTIME)
297 {
298 	unsigned long hugepage_size;
299 	uint64_t *ptr;
300 	int i;
301 
302 	hugepage_size = default_huge_page_size();
303 	if (!hugepage_size)
304 		SKIP(return, "Reading HugeTLB pagesize failed");
305 
306 	if (hugetlb_free_default_pages() < 1)
307 		SKIP(return, "Not enough huge pages");
308 
309 	ptr = mmap(NULL, hugepage_size, PROT_READ | PROT_WRITE,
310 		MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
311 	ASSERT_NE(ptr, MAP_FAILED);
312 
313 	memset(ptr, 0xde, hugepage_size);
314 	for (i = 0; i < self->nthreads; i++)
315 		if (pthread_create(&self->threads[i], NULL, access_mem, ptr))
316 			perror("Couldn't create thread");
317 
318 	ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0);
319 	for (i = 0; i < self->nthreads; i++)
320 		ASSERT_EQ(pthread_cancel(self->threads[i]), 0);
321 }
322 
323 /*
324  * migration test with shared anon hugetlb page
325  */
326 TEST_F_TIMEOUT(migration, shared_anon_htlb, 2*RUNTIME)
327 {
328 	unsigned long hugepage_size;
329 	pid_t pid;
330 	uint64_t *ptr;
331 	int i, err;
332 
333 	hugepage_size = default_huge_page_size();
334 	if (!hugepage_size)
335 		SKIP(return, "Reading HugeTLB pagesize failed");
336 
337 	if (hugetlb_free_default_pages() < 1)
338 		SKIP(return, "Not enough huge pages");
339 
340 	ptr = mmap(NULL, hugepage_size, PROT_READ | PROT_WRITE,
341 		MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
342 	ASSERT_NE(ptr, MAP_FAILED);
343 
344 	memset(ptr, 0xde, hugepage_size);
345 	for (i = 0; i < self->nthreads; i++) {
346 		pid = fork();
347 		if (!pid) {
348 			prctl(PR_SET_PDEATHSIG, SIGHUP);
349 			/* Parent may have died before prctl so check now. */
350 			if (getppid() == 1)
351 				kill(getpid(), SIGHUP);
352 			access_mem(ptr);
353 		} else {
354 			self->pids[i] = pid;
355 		}
356 	}
357 
358 	err = migrate(ptr, self->n1, self->n2);
359 	ASSERT_EQ(kill_children(self), true);
360 	ASSERT_EQ(err, 0);
361 }
362 
363 TEST_HARNESS_MAIN
364