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