1 /******************************************************************************/
2 /*									      */
3 /* Copyright (c) International Business Machines  Corp., 2001		      */
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 /******************************************************************************/
20 
21 /******************************************************************************/
22 /*									      */
23 /* History:	July - 16 - 2001 Created by Manoj Iyer, IBM Austin TX.	      */
24 /*			         email:manjo@austin.ibm.com		      */
25 /*                                                                            */
26 /*              July - 24 - 2001 Modified. Added loop and pass arguments to   */
27 /*                               the thread function. Fixed usage function.   */
28 /*				 added option to MAP_PRIVATE or MAP_SHARED.   */
29 /*                                                                            */
30 /*              Aug  - 01 - 2001 Modified. Added include file signal.h        */
31 /*                               has defines required by signal handler.      */
32 /*                                                                            */
33 /*		Oct  - 25 - 2001 Modified. Fixed bug in main(). Pthread_join  */
34 /*				 sets the return value of the thread in thread*/
35 /*			         return_status parameter.                     */
36 /*		Nov - 09  - 2001 Modified. Removed compile errors             */
37 /*				 - incomplete comment in line 301             */
38 /*				 - missing argument to printf in pthread_join */
39 /*                                                                            */
40 /*              Apr  - 16 - 2003 Modified - replaced tempnam() use with       */
41 /*                               mkstemp(). -Robbie Williamson                */
42 /*                               email:robbiew@us.ibm.com                     */
43 /*                                                                            */
44 /*              May  - 12 - 2003 Modified - remove the really large files     */
45 /*                               when we are done with the test - Paul Larson */
46 /*                               email:plars@linuxtestproject.org             */
47 /* File:	mmap3.c							      */
48 /*			         					      */
49 /* Description: Test the LINUX memory manager. The program is aimed at        */
50 /*              stressing the memory manager by repeaded map/write/unmap      */
51 /*		of file/memory of random size (maximum 1GB) this is done by   */
52 /*		multiple processes.					      */
53 /*			         					      */
54 /*		Create a file of random size upto 1000 times 4096, map it,    */
55 /*		change the contents of the file and unmap it. This is repeated*/
56 /*		several times for the specified number of hours by a certain. */
57 /*		number of processes.					      */
58 /*			         					      */
59 /******************************************************************************/
60 
61 /* Include Files							      */
62 #include <stdio.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <fcntl.h>
66 #include <unistd.h>
67 #include <errno.h>
68 #include <sys/mman.h>
69 #include <sched.h>
70 #include <stdlib.h>
71 #include <signal.h>
72 #include <sys/time.h>
73 #include <sys/wait.h>
74 #include <pthread.h>
75 #include <signal.h>
76 #include <string.h>
77 #include "test.h"
78 
79 /* Defines								      */
80 #ifndef TRUE
81 #define TRUE 1
82 #endif
83 #ifndef FALSE
84 #define FALSE 0
85 #endif
86 #define prtln() printf(" I AM HERE ==> %s %d\n", __FILE__, __LINE__);
87 
88 /******************************************************************************/
89 /*                                                                            */
90 /* Function:    mkfile                                                        */
91 /*                                                                            */
92 /* Description: Create a temparory file of ramdom size. 		      */
93 /*                                                                            */
94 /* Input:	NONE							      */
95 /*                                                                            */
96 /* Output:      size - size of the temp file  created 			      */
97 /*                                                                            */
98 /* Return:      int fd - file descriptor if the file was created.             */
99 /*              -1     - if it failed to create.                              */
100 /*                                                                            */
101 /******************************************************************************/
mkfile(int * size)102 static int mkfile(int *size)
103 {				/* size of the file to be generated in GB     */
104 	int fd;			/* file descriptior of tmpfile                */
105 	int index = 0;		/* index into the file, fill it with a's      */
106 	char buff[4096];	/* buffer that will be written to the file.   */
107 	char template[PATH_MAX];	/* template for temp file name                */
108 
109 	/* fill the buffer with a's and open a temp file */
110 	memset(buff, 'a', 4096);
111 	snprintf(template, PATH_MAX, "ashfileXXXXXX");
112 	if ((fd = mkstemp(template)) == -1) {
113 		perror("mkfile(): mkstemp()");
114 		return -1;
115 	}
116 	unlink(template);
117 
118 	srand(time(NULL) % 100);
119 	*size = (1 + (int)(1000.0 * rand() / (RAND_MAX + 1.0))) * 4096;
120 
121 	/* fill the file with the character a */
122 	while (index < *size) {
123 		index += 4096;
124 		if (write(fd, buff, 4096) == -1) {
125 			perror("mkfile(): write()");
126 			return -1;
127 		}
128 	}
129 
130 	/* make sure a's are written to the file. */
131 	if (fsync(fd) == -1) {
132 		perror("mkfile(): fsync()");
133 		return -1;
134 	}
135 	return fd;
136 }
137 
138 /******************************************************************************/
139 /*                                                                            */
140 /* Function:    sig_handler                                                   */
141 /*                                                                            */
142 /* Description: handle SIGALRM raised by set_timer(), SIGALRM is raised when  */
143 /*              the timer expires. If any other signal is recived exit the    */
144 /*              test.                                                         */
145 										/*                                                                            *//* Input:       signal - signal number, intrested in SIGALRM!                 */
146 /*                                                                            */
147 /* Return:      exit 1 if unexpected signal is recived                        */
148 /*              exit 0 if SIGALRM is recieved                                 */
149 /*                                                                            */
150 /******************************************************************************/
sig_handler(int signal)151 static void sig_handler(int signal)
152 {				/* signal number, set to handle SIGALRM       */
153 	if (signal != SIGALRM) {
154 		fprintf(stderr,
155 			"sig_handlder(): unexpected signal caught [%d]\n",
156 			signal);
157 		exit(-1);
158 	} else
159 		fprintf(stdout, "Test ended, success\n");
160 	exit(0);
161 }
162 
163 										/******************************************************************************//*                                                                            */
164 /* Function:	usage							      */
165 /*									      */
166 /* Description:	Print the usage message.				      */
167 /*									      */
168 /* Return:	exits with -1						      */
169 /*									      */
170 /******************************************************************************/
usage(char * progname)171 static void usage(char *progname)
172 {				/* name of this program                       */
173 	fprintf(stderr,
174 		"Usage: %s -h -l -n -p -x\n"
175 		"\t -h help, usage message.\n"
176 		"\t -l number of map - write - unmap.    default: 1000\n"
177 		"\t -n number of LWP's to create.        default: 20\n"
178 		"\t -p set mapping to MAP_PRIVATE.       default: MAP_SHARED\n"
179 		"\t -x time for which test is to be run. default: 24 Hrs\n",
180 		progname);
181 	exit(-1);
182 }
183 
184 /******************************************************************************/
185 /*									      */
186 /* Function:	map_write_unmap						      */
187 /*									      */
188 /* Description:	map a file write a character to it and unmap, this is done for*/
189 /*		user defined number of times.				      */
190 /*									      */
191 /* Input:	arg[0]		   number of times map - write -unmap is done */
192 /* 		arg[1]		   Map type:  				      */
193 /*					TRUE  - MAP_PRIVATE 		      */
194 /*					FALSE - MAP_SHARED		      */
195 /*									      */
196 /* Return:	MWU_FAIL on error.				              */
197 /*              MWU_SUCCESS on error less completion of the loop.             */
198 /*									      */
199 /******************************************************************************/
map_write_unmap(void * args)200 void *map_write_unmap(void *args)
201 {				/* file descriptor of the file to be mapped.  */
202 	int fsize;		/* size of the file to be created.            */
203 	int fd;			/* temporary file descriptor                  */
204 	int mwu_ndx = 0;	/* index to number of map/write/unmap         */
205 	caddr_t *map_address;	/* pointer to file in memory                  */
206 	int map_type;		/* MAP_PRIVATE or MAP_SHARED                  */
207 	long *mwuargs =		/* local pointer to arguments                 */
208 	    (long *)args;
209 
210 	while (mwu_ndx++ < (int)mwuargs[0]) {
211 		if ((fd = mkfile(&fsize)) == -1) {
212 			fprintf(stderr,
213 				"main(): mkfile(): Failed to create temp file.\n");
214 			pthread_exit((void *)-1);
215 		}
216 
217 		if ((int)mwuargs[1])
218 			map_type = MAP_PRIVATE;
219 		else
220 			map_type = MAP_SHARED;
221 		if ((map_address =
222 		     mmap(0, (size_t) fsize, PROT_WRITE | PROT_READ, map_type,
223 			  (int)fd, 0))
224 		    == (caddr_t *) - 1) {
225 			perror("map_write_unmap(): mmap()");
226 			pthread_exit((void *)-1);
227 		}
228 
229 		memset(map_address, 'A', fsize);
230 
231 		fprintf(stdout,
232 			"Map address = %p\nNum iter: [%d]\nTotal Num Iter: [%d]",
233 			map_address, mwu_ndx, (int)mwuargs[0]);
234 		usleep(1);
235 		if (munmap(map_address, (size_t) fsize) == -1) {
236 			perror("map_write_unmap(): mmap()");
237 			pthread_exit((void *)-1);
238 		}
239 		close(fd);
240 	}
241 	pthread_exit(NULL);
242 }
243 
244 /******************************************************************************/
245 /*                                                                            */
246 /* Function:    main                                                          */
247 /*                                                                            */
248 /* Descrption:	Create a large file of size up to a  Giga Bytes.  write to it */
249 /*		lower case alphabet 'a'. Map the file and change the contents */
250 /*		to 'A's (upper case alphabet), write the contents to the file,*/
251 /*		and unmap the file from memory. Spwan a certian number of     */
252 /*		LWP's that will do the above.				      */
253 /*                                                                            */
254 /* Return:	exits with -1 on error					      */
255 /*		exits with a 0 on success.				      */
256 /*                                                                            */
257 /******************************************************************************/
main(int argc,char ** argv)258 int main(int argc,		/* number of input parameters.                        */
259 	 char **argv)
260 {				/* pointer to the command line arguments.       */
261 	int c;			/* command line options                       */
262 	int num_iter;		/* number of iteration to perform             */
263 	int num_thrd;		/* number of threads to create                */
264 	int thrd_ndx;		/* index into the array of threads.           */
265 	float exec_time;	/* period for which the test is executed      */
266 	void *status;		/* exit status for light weight process       */
267 	int sig_ndx;		/* index into signal handler structure.       */
268 	pthread_t thid[1000];	/* pids of process that will map/write/unmap  */
269 	long chld_args[3];	/* arguments to funcs execed by child process */
270 	extern char *optarg;	/* arguments passed to each option            */
271 	struct sigaction sigptr;	/* set up signal, for interval timer          */
272 	int map_private =	/* if TRUE mapping is private, ie, MAP_PRIVATE */
273 	    FALSE;
274 
275 	static struct signal_info {
276 		int signum;	/* signal number that hasto be handled                */
277 		char *signame;	/* name of the signal to be handled.                  */
278 	} sig_info[] = {
279 		{
280 		SIGHUP, "SIGHUP"}, {
281 		SIGINT, "SIGINT"}, {
282 		SIGQUIT, "SIGQUIT"}, {
283 		SIGABRT, "SIGABRT"}, {
284 		SIGBUS, "SIGBUS"}, {
285 		SIGSEGV, "SIGSEGV"}, {
286 		SIGALRM, "SIGALRM"}, {
287 		SIGUSR1, "SIGUSR1"}, {
288 		SIGUSR2, "SIGUSR2"}, {
289 		-1, "ENDSIG"}
290 	};
291 
292 	/* set up the default values */
293 	num_iter = 1000;	/* repeate map - write - unmap operation 1000 times   */
294 	num_thrd = 40;		/* number of LWP's to create                          */
295 	exec_time = 24;		/* minimum time period for which to run the tests     */
296 
297 	while ((c = getopt(argc, argv, "h:l:n:px:")) != -1) {
298 		switch (c) {
299 		case 'h':
300 			usage(argv[0]);
301 			break;
302 		case 'l':
303 			if ((num_iter = atoi(optarg)) == 0)
304 				num_iter = 1000;
305 			break;
306 		case 'n':
307 			if ((num_thrd = atoi(optarg)) == 0)
308 				num_thrd = 20;
309 			break;
310 		case 'p':
311 			map_private = TRUE;
312 			break;
313 		case 'x':
314 			if ((exec_time = atof(optarg)) == 0)
315 				exec_time = 24;
316 			break;
317 		default:
318 			usage(argv[0]);
319 			break;
320 		}
321 	}
322 
323 	/* set up signals */
324 	sigptr.sa_handler = (void (*)(int signal))sig_handler;
325 	sigfillset(&sigptr.sa_mask);
326 	sigptr.sa_flags = SA_SIGINFO;
327 	for (sig_ndx = 0; sig_info[sig_ndx].signum != -1; sig_ndx++) {
328 		sigaddset(&sigptr.sa_mask, sig_info[sig_ndx].signum);
329 		if (sigaction(sig_info[sig_ndx].signum, &sigptr,
330 			      NULL) == -1) {
331 			perror("man(): sigaction()");
332 			fprintf(stderr,
333 				"could not set handler for SIGALRM, errno = %d\n",
334 				errno);
335 			exit(-1);
336 		}
337 	}
338 	chld_args[0] = num_iter;
339 	chld_args[1] = map_private;
340 	alarm(exec_time * 3600.00);
341 
342 	fprintf(stdout,
343 		"\n\n\nTest is set to run with the following parameters:\n"
344 		"\tDuration of test: [%f]hrs\n"
345 		"\tNumber of threads created: [%d]\n"
346 		"\tnumber of map-write-unmaps: [%d]\n"
347 		"\tmap_private?(T=1 F=0): [%d]\n\n\n\n", exec_time, num_thrd,
348 		num_iter, map_private);
349 
350 	for (;;) {
351 		/* create num_thrd number of threads. */
352 		for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
353 			if (pthread_create
354 			    (&thid[thrd_ndx], NULL, map_write_unmap,
355 			     chld_args)) {
356 				perror("main(): pthread_create()");
357 				exit(-1);
358 			}
359 			sched_yield();
360 		}
361 
362 		/* wait for the children to terminate */
363 		for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
364 			if (pthread_join(thid[thrd_ndx], &status)) {
365 				perror("main(): pthread_create()");
366 				exit(-1);
367 			} else {
368 				if (status) {
369 					fprintf(stderr,
370 						"thread [%d] - process exited with errors %ld\n",
371 						WEXITSTATUS((long)status),
372 						(long)status);
373 					exit(-1);
374 				}
375 			}
376 		}
377 	}
378 	exit(0);
379 }
380