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