1 /******************************************************************************/
2 /* */
3 /* Copyright (c) 2009 FUJITSU LIMITED */
4 /* */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
13 /* the GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program; if not, write to the Free Software */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18 /* */
19 /* Author: Miao Xie <miaox@cn.fujitsu.com> */
20 /* */
21 /******************************************************************************/
22
23 #include "config.h"
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <signal.h>
28 #include <err.h>
29 #include <limits.h>
30 #include <getopt.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/mman.h>
36 #include <sys/shm.h>
37 #include <syscall.h>
38 #include <pthread.h>
39
40 char *TCID = "cpuset_memory_test";
41 int TST_TOTAL = 1;
42
43 #if HAVE_LINUX_MEMPOLICY_H
44
45 #include "../cpuset_lib/cpuset.h"
46
47 static int fd;
48
49 static int opt_mmap_anon;
50 static int opt_mmap_file;
51 static int opt_mmap_lock1;
52 static int opt_mmap_lock2;
53 static int opt_shm;
54 static int opt_hugepage;
55 static int opt_check; /* check node when munmap memory (only for mmap_anon()) */
56 static int opt_thread;
57
58 static int key_id; /* used with opt_shm */
59 static unsigned long memsize;
60
61 #define FILE_HUGEPAGE "/hugetlb/hugepagefile"
62
63 #define MMAP_ANON (SCHAR_MAX + 1)
64 #define MMAP_FILE (SCHAR_MAX + 2)
65 #define MMAP_LOCK1 (SCHAR_MAX + 3)
66 #define MMAP_LOCK2 (SCHAR_MAX + 4)
67 #define SHM (SCHAR_MAX + 5)
68 #define HUGEPAGE (SCHAR_MAX + 6)
69 #define CHECK (SCHAR_MAX + 7)
70 #define THREAD (SCHAR_MAX + 8)
71
72 const struct option long_opts[] = {
73 {"mmap-anon", 0, NULL, MMAP_ANON},
74 {"mmap-file", 0, NULL, MMAP_FILE},
75 {"mmap-lock1", 0, NULL, MMAP_LOCK1},
76 {"mmap-lock2", 0, NULL, MMAP_LOCK2},
77 {"shm", 0, NULL, SHM},
78 {"hugepage", 0, NULL, HUGEPAGE},
79 {"check", 0, NULL, CHECK},
80 {"thread", 0, NULL, THREAD},
81 {"size", 1, NULL, 's'},
82 {"key", 1, NULL, 'k'},
83 {NULL, 0, NULL, 0},
84 };
85
86 /*
87 * process_options: read options from user input
88 */
process_options(int argc,char * argv[])89 void process_options(int argc, char *argv[])
90 {
91 int c;
92 char *end;
93
94 while (1) {
95 c = getopt_long(argc, argv, "s:k:", long_opts, NULL);
96 if (c == -1)
97 break;
98
99 switch (c) {
100 case 's':
101 memsize = strtoul(optarg, &end, 10);
102 if (*end != '\0')
103 errx(1, "wrong -s argument!");
104 break;
105 case 'k':
106 key_id = atoi(optarg);
107 break;
108 case MMAP_ANON:
109 opt_mmap_anon = 1;
110 break;
111 case MMAP_FILE:
112 opt_mmap_file = 1;
113 break;
114 case MMAP_LOCK1:
115 opt_mmap_lock1 = 1;
116 break;
117 case MMAP_LOCK2:
118 opt_mmap_lock2 = 1;
119 break;
120 case SHM:
121 opt_shm = 1;
122 break;
123 case HUGEPAGE:
124 opt_hugepage = 1;
125 break;
126 case CHECK:
127 opt_check = 1;
128 break;
129 case THREAD:
130 opt_thread = 1;
131 break;
132 default:
133 errx(1, "unknown option!\n");
134 break;
135 }
136 }
137
138 if (!memsize)
139 memsize = sysconf(_SC_PAGESIZE);
140 }
141
142 /*
143 * touch_memory: force allocating phy memory
144 */
touch_memory_and_echo_node(char * p,int size)145 void touch_memory_and_echo_node(char *p, int size)
146 {
147 int i;
148 int pagesize = sysconf(_SC_PAGESIZE);
149
150 for (i = 0; i < size; i += pagesize)
151 p[i] = 0xef;
152
153 printf("%d\n", cpuset_addr2node(p));
154 }
155
mmap_anon(int flag_allocated)156 void mmap_anon(int flag_allocated)
157 {
158 static char *p;
159
160 if (!flag_allocated) {
161 p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
162 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
163 if (p == MAP_FAILED)
164 err(1, "mmap(anonymous) failed");
165 touch_memory_and_echo_node(p, memsize);
166 } else {
167 if (opt_check)
168 touch_memory_and_echo_node(p, memsize);
169 if (munmap(p, memsize) == -1)
170 err(1, "munmap(anonymous) failed");
171 }
172 }
173
mmap_file(int flag_allocated)174 void mmap_file(int flag_allocated)
175 {
176 static char *p;
177 static int fd_hugepage;
178 int fd_tmp;
179
180 if (!flag_allocated) {
181 if (opt_hugepage) {
182 fd_hugepage = open(FILE_HUGEPAGE,
183 O_CREAT | O_RDWR, 0755);
184 if (fd_hugepage < 0)
185 err(1, "open hugepage file failed");
186 fd_tmp = fd_hugepage;
187 } else
188 fd_tmp = fd;
189
190 p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
191 MAP_SHARED, fd_tmp, 0);
192 if (p == MAP_FAILED) {
193 if (opt_hugepage)
194 unlink(FILE_HUGEPAGE);
195 err(1, "mmap(file) failed");
196 }
197 touch_memory_and_echo_node(p, memsize);
198 } else {
199 if (munmap(p, memsize) == -1)
200 err(1, "munmap(file) failed");
201
202 if (opt_hugepage) {
203 close(fd_hugepage);
204 unlink(FILE_HUGEPAGE);
205 }
206 }
207 }
208
mmap_lock1(int flag_allocated)209 void mmap_lock1(int flag_allocated)
210 {
211 static char *p;
212
213 if (!flag_allocated) {
214 p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
215 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, 0, 0);
216 if (p == MAP_FAILED)
217 err(1, "mmap(lock) failed");
218 touch_memory_and_echo_node(p, memsize);
219 } else {
220 if (munmap(p, memsize) == -1)
221 err(1, "munmap(lock) failed");
222 }
223 }
224
mmap_lock2(int flag_allocated)225 void mmap_lock2(int flag_allocated)
226 {
227 static char *p;
228
229 if (!flag_allocated) {
230 p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
231 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
232 if (p == MAP_FAILED)
233 err(1, "mmap failed");
234
235 if (mlock(p, memsize))
236 err(1, "mlock failed");
237 touch_memory_and_echo_node(p, memsize);
238 } else {
239 if (munmap(p, memsize) == -1)
240 err(1, "munmap failed");
241 }
242 }
243
shm(int flag_allocated)244 void shm(int flag_allocated)
245 {
246 static char *p;
247 static int shmid;
248 unsigned long flag;
249
250 key_t key;
251
252 if (!flag_allocated) {
253 flag = IPC_CREAT | SHM_R | SHM_W;
254 if (opt_hugepage)
255 flag |= SHM_HUGETLB;
256
257 key = ftok("/dev/null", key_id);
258 if (key == -1)
259 err(1, "ftok() failed\n");
260
261 shmid = shmget(key, memsize, flag);
262 if (shmid == -1)
263 err(1, "shmget() failed\n");
264 shmctl(shmid, IPC_RMID, NULL);
265
266 shmid = shmget(key, memsize, flag);
267 if (shmid == -1)
268 err(1, "shmget() failed\n");
269
270 p = shmat(shmid, NULL, 0);
271 if (p == (void *)-1) {
272 shmctl(shmid, IPC_RMID, NULL);
273 err(1, "shmat() failed\n");
274 }
275 touch_memory_and_echo_node(p, memsize);
276 } else {
277 if (shmdt(p) == -1)
278 err(1, "shmdt() failed\n");
279 if (shmctl(shmid, IPC_RMID, NULL) == -1)
280 err(1, "shmctl() failed\n");
281 }
282 }
283
thread2_routine(void * arg)284 void *thread2_routine(void __attribute__ ((unused)) * arg)
285 {
286 sigset_t set;
287 sigset_t waitset;
288 int flag_allocated;
289
290 sigemptyset(&set);
291 sigaddset(&set, SIGUSR1);
292 sigaddset(&set, SIGINT);
293 pthread_sigmask(SIG_BLOCK, &set, NULL);
294
295 sigemptyset(&waitset);
296 sigaddset(&waitset, SIGUSR2);
297 pthread_sigmask(SIG_BLOCK, &waitset, NULL);
298
299 flag_allocated = 0;
300
301 for (;;) {
302 if (sigwaitinfo(&waitset, NULL) < 0)
303 err(1, "sigwaitinfo() in thread2 failed");
304
305 mmap_anon(flag_allocated);
306 flag_allocated = !flag_allocated;
307 }
308
309 return NULL;
310 }
311
312 /*
313 * When we receive SIGUSR1, we allocate some memory according
314 * to the user intput when the process started.
315 * When we receive SIGUSR1 again, we will free all the allocated
316 * memory.
317 * Similiar for --thread option but SIGUSR2 signal is used
318 * to control thread2 behaviour.
319 */
main(int argc,char * argv[])320 int main(int argc, char *argv[])
321 {
322 sigset_t waitset;
323 int signo;
324 int flag_allocated;
325
326 pthread_t thread2;
327
328 fd = open("/dev/zero", O_RDWR);
329 if (fd < 0)
330 err(1, "open /dev/zero failed");
331
332 process_options(argc, argv);
333
334 if (opt_thread) {
335 sigset_t set;
336 sigemptyset(&set);
337 sigaddset(&set, SIGUSR2);
338
339 pthread_create(&thread2, NULL, thread2_routine, NULL);
340
341 pthread_sigmask(SIG_BLOCK, &set, NULL);
342 }
343
344
345 sigemptyset(&waitset);
346 sigaddset(&waitset, SIGINT);
347 sigaddset(&waitset, SIGUSR1);
348
349 pthread_sigmask(SIG_BLOCK, &waitset, NULL);
350
351 flag_allocated = 0;
352
353 for (;;) {
354 signo = sigwaitinfo(&waitset, NULL);
355 if (signo < 0)
356 err(1, "sigwaitinfo() failed");
357
358 if (signo == SIGUSR1) {
359 if (opt_mmap_anon)
360 mmap_anon(flag_allocated);
361
362 if (opt_mmap_file)
363 mmap_file(flag_allocated);
364
365 if (opt_mmap_lock1)
366 mmap_lock1(flag_allocated);
367
368 if (opt_mmap_lock2)
369 mmap_lock2(flag_allocated);
370
371 if (opt_shm)
372 shm(flag_allocated);
373
374 flag_allocated = !flag_allocated;
375 } else {
376 break;
377 }
378 }
379
380 if (opt_thread) {
381 void *retv;
382 pthread_cancel(thread2);
383 pthread_join(thread2, &retv);
384 }
385
386 close(fd);
387
388 return 0;
389 }
390
391 #else
main(void)392 int main(void)
393 {
394 printf("System doesn't have required mempolicy support\n");
395 return 1;
396 }
397 #endif
398