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