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