blob: 1934dbb4d95cd85e5573270b6ccdbb6c2817be85 [file] [log] [blame]
robbiewc44203a2003-01-10 18:05:10 +00001/* IBM Corporation */
2/* 01/02/2003 Port to LTP avenakt@us.ibm.com */
3/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
Garrett Cooper2c282152010-12-16 00:55:50 -08004/*
robbiewc44203a2003-01-10 18:05:10 +00005 * 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.
Garrett Cooper2c282152010-12-16 00:55:50 -08009 *
robbiewc44203a2003-01-10 18:05:10 +000010 * 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
Wanlong Gao4548c6c2012-10-19 18:03:36 +080017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
robbiewc44203a2003-01-10 18:05:10 +000018 */
19
20#define _GNU_SOURCE 1
21#include <sys/types.h>
22#include <stdio.h>
23#include <fcntl.h>
24#include <signal.h>
25#include <sys/mman.h>
26#include <sys/wait.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <errno.h>
30/***** LTP Port *****/
31#include "test.h"
robbiewc44203a2003-01-10 18:05:10 +000032#define FAILED 0
33#define PASSED 1
34
35int local_flag = PASSED;
36char *TCID = "mmapstress09";
37FILE *temp;
38int TST_TOTAL = 1;
robbiewc44203a2003-01-10 18:05:10 +000039
40int anyfail();
41void ok_exit();
42/***** ** ** *****/
43
44/*
45 * This test is mostly duplicated from the tmmap test, but tests
46 * stress tests anonymous maps. It forks a specified number of children,
47 * who inherit an anonymous shared map, and who, make a given number of
48 * accesses to random pages in the map (reading & writing and comparing data).
49 * Then the child exits and the parent forks another to take its place.
50 * The test fails if a child sees incorrect data.
51 *
52 * This program continues to run until it either receives a SIGINT,
53 * or times out (if a timeout value is specified). When either of
subrata_modak4bb656a2009-02-26 12:02:09 +000054 * these things happens, it cleans up its kids, then checks
robbiewc44203a2003-01-10 18:05:10 +000055 * the map to make sure it has the correct data.
56 *
57 * usage:
58 * mmapstress09 -p nprocs [-t minutes -s mapsize -m msync -r -d]
59 *
60 * where:
61 * -p nprocs - specifies the number of mapping children
62 * to create. (nprocs + 1 children actually
63 * get created, since one is the writer child)
64 * -t minutes - specifies minutes to run. If not specified,
65 * default is to run forever until a SIGINT
66 * is received.
67 * -s mapsize - mapsize (defaults to MAPSIZE)
68 * -m - do msyncs
69 * -r - randomize number of pages map children check.
70 * (random % MAXLOOPS). If not specified, each
71 * child checks MAXLOOPS pages.
72 * -d - enable debug outputd
73 */
74
75#define MAXLOOPS 500 /* max pages for map children to write */
Wanlong Gao354ebb42012-12-07 10:10:04 +080076#define MAPSIZE (64*1024) /* default mapsize set up by parent */
robbiew4be90982003-07-31 15:15:25 +000077#ifdef roundup
78#undef roundup
79#endif
robbiewc44203a2003-01-10 18:05:10 +000080#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
81#define min(x, y) (((x) < (y)) ? (x) : (y))
82
Wanlong Gao354ebb42012-12-07 10:10:04 +080083extern time_t time(time_t *);
84extern char *ctime(const time_t *);
robbiewc44203a2003-01-10 18:05:10 +000085extern void *malloc(size_t);
86extern void exit(int);
87extern long lrand48(void);
88extern void srand(unsigned);
89extern void srand48(long);
Wanlong Gao354ebb42012-12-07 10:10:04 +080090extern int rand(void);
91extern int atoi(const char *);
robbiewc44203a2003-01-10 18:05:10 +000092
93typedef unsigned char uchar_t;
94
Wanlong Gao354ebb42012-12-07 10:10:04 +080095char *usage = "-p nprocs [-t minutes -s mapsize -m -r -d]";
robbiewc44203a2003-01-10 18:05:10 +000096
97unsigned int initrand(void);
98void finish(int sig);
99void child_mapper(unsigned procno, unsigned nprocs);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800100int mapokay(uchar_t * expbuf);
robbiewc44203a2003-01-10 18:05:10 +0000101
102int finished = 0;
103int debug = 0;
104int mapsize = MAPSIZE;
105unsigned mappages;
106int pagesize;
107unsigned randloops = 0;
108unsigned dosync = 0;
109unsigned pattern = 0;
110caddr_t mapaddr;
111
Wanlong Gao354ebb42012-12-07 10:10:04 +0800112int main(int argc, char *argv[])
robbiewc44203a2003-01-10 18:05:10 +0000113{
114 char *progname;
115 unsigned c;
116 extern char *optarg;
117 unsigned nprocs = 0;
118 unsigned procno;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800119 pid_t *pidarray = NULL;
robbiewc44203a2003-01-10 18:05:10 +0000120 pid_t pid;
121 uchar_t *buf, *ptr;
122 unsigned int seed;
subrata_modakae1b3952008-10-30 03:53:09 +0000123 float alarmtime = 0;
robbiewc44203a2003-01-10 18:05:10 +0000124 struct sigaction sa;
125 unsigned i, j;
126 uchar_t data;
127 int no_prob = 0;
128 time_t t;
129 int wait_stat;
130
131 progname = *argv;
132 pagesize = sysconf(_SC_PAGE_SIZE);
133
134 if (argc < 2) {
135 (void)fprintf(stderr, "usage: %s %s\n", progname, usage);
136 anyfail();
137 }
138
139 while ((c = getopt(argc, argv, "mdrp:t:s:")) != -1) {
140 switch (c) {
141 case 'd':
142 debug = 1;
143 break;
144 case 't':
subrata_modakae1b3952008-10-30 03:53:09 +0000145 alarmtime = atof(optarg) * 60;
robbiewc44203a2003-01-10 18:05:10 +0000146 break;
147 case 'p':
148 nprocs = atoi(optarg);
149 break;
150 case 'm':
151 dosync = 1;
152 break;
153 case 's':
154 mapsize = atoi(optarg);
155 if (mapsize < 0) {
156 (void)fprintf(stderr, "error: negative "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800157 "mapsize\n");
158 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000159 }
160 break;
161 case 'r':
162 randloops = 1;
163 break;
164 default:
165 (void)fprintf(stderr, "usage: %s %s\n", progname,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800166 usage);
167 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000168 }
169 }
170
171 /* nprocs is unsigned */
172 if (nprocs > 255) {
173 (void)fprintf(stderr, "invalid nprocs %d - (range 0-255)\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800174 nprocs);
175 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000176 }
177 (void)time(&t);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800178// (void)printf("%s: Started %s", argv[0], ctime(&t)); LTP Port
robbiewc44203a2003-01-10 18:05:10 +0000179
180 seed = initrand();
181 pattern = seed & 0xff;
182
183 if (debug) {
subrata_modak4bb656a2009-02-26 12:02:09 +0000184 (void)printf("%s mapsize %d bytes, pattern %d\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800185 progname, mapsize, pattern);
robbiewc44203a2003-01-10 18:05:10 +0000186 if (alarmtime)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800187 (void)printf("running for %f minutes\n",
188 alarmtime / 60);
robbiewc44203a2003-01-10 18:05:10 +0000189 else
190 (void)printf("running with no time limit\n");
191 }
192
Wanlong Gao354ebb42012-12-07 10:10:04 +0800193 if ((mapaddr = mmap(0, mapsize, PROT_READ | PROT_WRITE,
194 MAP_ANONYMOUS | MAP_SHARED, 0, 0))
195 == (caddr_t) - 1) {
robbiewc44203a2003-01-10 18:05:10 +0000196 perror("mmap error");
Wanlong Gao354ebb42012-12-07 10:10:04 +0800197 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000198 }
199
Cyril Hrubisd218f342014-09-23 13:14:56 +0200200 if ((buf = malloc(pagesize)) == NULL
201 || (pidarray = malloc(nprocs * sizeof(pid_t))) == NULL) {
robbiewc44203a2003-01-10 18:05:10 +0000202 perror("malloc error");
Wanlong Gao354ebb42012-12-07 10:10:04 +0800203 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000204 }
205
206 for (i = 0; i < nprocs; i++)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800207 *(pidarray + i) = 0;
robbiewc44203a2003-01-10 18:05:10 +0000208
209 /*
210 * Initialize page compare buffer, then initialize map.
211 */
212
213 for (i = 0, data = 0; i < pagesize; i++) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800214 *(buf + i) = (data + pattern) & 0xff;
robbiewc44203a2003-01-10 18:05:10 +0000215 if (++data == nprocs)
216 data = 0;
217 }
218
Wanlong Gao354ebb42012-12-07 10:10:04 +0800219 mappages = roundup(mapsize, pagesize) / pagesize;
220 ptr = (uchar_t *) mapaddr;
robbiewc44203a2003-01-10 18:05:10 +0000221
222 for (i = 0; i < mappages; i++) {
223 for (j = 0; j < pagesize; j++)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800224 *ptr++ = *(buf + j);
robbiewc44203a2003-01-10 18:05:10 +0000225 }
226
227 /*
228 * Fork off mmap children.
229 */
230 for (procno = 0; procno < nprocs; procno++) {
231 switch (pid = fork()) {
232
233 case -1:
234 perror("fork error");
235 goto cleanup;
236
237 case 0:
238 child_mapper(procno, nprocs);
239 exit(0);
240
241 default:
242 pidarray[procno] = pid;
243 }
244 }
245
246 /*
247 * Plan for death by signal. User may have specified
248 * a time limit, in which set an alarm and catch SIGALRM.
249 * Also catch and cleanup with SIGINT.
250 */
251 sa.sa_handler = finish;
252 sa.sa_flags = 0;
253 if (sigemptyset(&sa.sa_mask)) {
254 perror("sigemptyset error");
255 goto cleanup;
256 }
257
258 if (sigaction(SIGINT, &sa, 0) == -1) {
259 perror("sigaction error");
260 goto cleanup;
261 }
262
263 if (alarmtime) {
264 if (sigaction(SIGALRM, &sa, 0) == -1) {
265 perror("sigaction error");
266 goto cleanup;
267 }
268 (void)alarm(alarmtime);
269 }
270
271 /*
272 * Now wait for children and refork them as needed.
273 */
subrata_modakbdbaec52009-02-26 12:14:51 +0000274
robbiewc44203a2003-01-10 18:05:10 +0000275 while (!finished) {
276 do {
277 pid = wait(&wait_stat);
278 } while (pid == -1 && errno == EINTR);
279 /*
280 * Block signals while processing child exit.
281 */
282
283 if (sighold(SIGALRM) || sighold(SIGINT)) {
284 perror("sighold error");
285 goto cleanup;
286 }
287
288 if (pid != -1) {
289 /*
290 * Check exit status, then refork with the
291 * appropriate procno.
292 */
subrata_modak4bb656a2009-02-26 12:02:09 +0000293 if (!WIFEXITED(wait_stat)
robbiewc44203a2003-01-10 18:05:10 +0000294 || WEXITSTATUS(wait_stat) != 0) {
295 (void)fprintf(stderr, "child exit with err "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800296 "<x%x>\n", wait_stat);
robbiewc44203a2003-01-10 18:05:10 +0000297 goto cleanup;
298 }
299 for (i = 0; i < nprocs; i++)
300 if (pid == pidarray[i])
301 break;
302 if (i == nprocs) {
subrata_modak4bb656a2009-02-26 12:02:09 +0000303 (void)fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800304 "unknown child pid %d, <x%x>\n",
305 pid, wait_stat);
robbiewc44203a2003-01-10 18:05:10 +0000306 goto cleanup;
307 }
308
309 if ((pid = fork()) == -1) {
310 perror("fork error");
311 pidarray[i] = 0;
312 goto cleanup;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800313 } else if (pid == 0) { /* child */
robbiewc44203a2003-01-10 18:05:10 +0000314 child_mapper(i, nprocs);
315 exit(0);
316 } else
317 pidarray[i] = pid;
318 } else {
319 /*
320 * wait returned an error. If EINTR, then
321 * normal finish, else it's an unexpected
322 * error...
323 */
324 if (errno != EINTR || !finished) {
325 perror("unexpected wait error");
326 goto cleanup;
327 }
328 }
329 if (sigrelse(SIGALRM) || sigrelse(SIGINT)) {
330 perror("sigrelse error");
331 goto cleanup;
332 }
333 }
subrata_modakbdbaec52009-02-26 12:14:51 +0000334
robbiewc44203a2003-01-10 18:05:10 +0000335 /*
336 * Finished! Check the map for sanity, then kill all
337 * the children and done!.
338 */
339
340 if (sighold(SIGALRM)) {
341 perror("sighold error");
342 goto cleanup;
343 }
344 (void)alarm(0);
345 no_prob = 1;
346
347cleanup:
348 for (i = 0; i < nprocs; i++)
349 (void)kill(pidarray[i], SIGKILL); /* failure? oh well. */
350
351 while (wait(&wait_stat) != -1 || errno != ECHILD)
352 continue;
353
354 if (no_prob) { /* only check file if no errors */
Garrett Cooperdf3eb162010-11-28 22:44:32 -0800355 if (!mapokay(buf)) {
robbiewc44203a2003-01-10 18:05:10 +0000356 (void)fprintf(stderr, "map data incorrect!\n");
Wanlong Gao354ebb42012-12-07 10:10:04 +0800357 anyfail();
358 } else
robbiewc44203a2003-01-10 18:05:10 +0000359 (void)printf("map data okay\n");
360 }
subrata_modakbdbaec52009-02-26 12:14:51 +0000361
robbiewc44203a2003-01-10 18:05:10 +0000362 (void)time(&t);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800363// (void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP POrt
robbiewc44203a2003-01-10 18:05:10 +0000364 ok_exit();
Garrett Cooper2c282152010-12-16 00:55:50 -0800365 tst_exit();
robbiewc44203a2003-01-10 18:05:10 +0000366}
367
robbiewc44203a2003-01-10 18:05:10 +0000368/*
369 * Child process that reads/writes map. The child reads/writes
370 * its own locations on random pages of the map (its locations being
371 * determined based on nprocs & procno). After a specific number of
372 * iterations, it exits.
373 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800374void child_mapper(unsigned procno, unsigned nprocs)
robbiewc44203a2003-01-10 18:05:10 +0000375{
376 uchar_t *paddr;
377 unsigned randpage;
378 unsigned int seed;
379 unsigned loopcnt;
380 unsigned nloops;
381 unsigned i;
382
Wanlong Gao354ebb42012-12-07 10:10:04 +0800383 seed = initrand(); /* initialize random seed */
robbiewc44203a2003-01-10 18:05:10 +0000384
385 nloops = (randloops) ? (lrand48() % MAXLOOPS) : MAXLOOPS;
386
387 if (debug)
388 (void)printf("child %d (pid %d): seed %d, loop %d\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800389 procno, getpid(), seed, nloops);
robbiewc44203a2003-01-10 18:05:10 +0000390
391 /*
392 * Now loop read/writing random pages.
393 */
394
Wanlong Gao354ebb42012-12-07 10:10:04 +0800395 for (loopcnt = 0; loopcnt < nloops; loopcnt++) {
robbiewc44203a2003-01-10 18:05:10 +0000396 randpage = lrand48() % mappages;
397 /* find the page address */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800398 paddr = (uchar_t *) (mapaddr + (randpage * pagesize));
robbiewc44203a2003-01-10 18:05:10 +0000399
400 for (i = procno; i < pagesize; i += nprocs) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800401 if (*((unsigned char *)(paddr + i))
robbiewc44203a2003-01-10 18:05:10 +0000402 != ((procno + pattern) & 0xff)) {
403 (void)fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800404 "child %d: invalid data <x%x>",
405 procno,
406 *((unsigned char *)(paddr + i)));
robbiewc44203a2003-01-10 18:05:10 +0000407 (void)fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800408 " at pg %d off %d, exp <x%x>\n",
409 randpage, i,
410 (procno + pattern) & 0xff);
411 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000412 }
413 /*
414 * Now write it.
415 */
416
Wanlong Gao354ebb42012-12-07 10:10:04 +0800417 *(paddr + i) = (procno + pattern) & 0xff;
robbiewc44203a2003-01-10 18:05:10 +0000418 }
419 }
420
421 if (dosync) {
422 randpage = (unsigned)lrand48() % mappages;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800423 paddr = (uchar_t *) mapaddr + (randpage * pagesize);
424 if (msync((caddr_t) paddr, (mappages - randpage) * pagesize,
425 MS_SYNC) == -1) {
robbiewc44203a2003-01-10 18:05:10 +0000426 perror("msync error");
Wanlong Gao354ebb42012-12-07 10:10:04 +0800427 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000428 }
429 }
430
431 exit(0);
432}
433
robbiewc44203a2003-01-10 18:05:10 +0000434/*
435 * Make sure file has all the correct data.
436 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800437int mapokay(uchar_t * expbuf)
robbiewc44203a2003-01-10 18:05:10 +0000438{
439 uchar_t *ptr;
440 unsigned i, j;
441
Wanlong Gao354ebb42012-12-07 10:10:04 +0800442 ptr = (uchar_t *) mapaddr;
robbiewc44203a2003-01-10 18:05:10 +0000443 for (i = 0; i < mappages; i++) {
444 /*
445 * Compare read bytes of data.
446 */
447 for (j = 0; j < pagesize; j++) {
448 if (*ptr != expbuf[j]) {
subrata_modak4bb656a2009-02-26 12:02:09 +0000449 (void)fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800450 "bad map data: exp %c got %c)",
451 expbuf[j], *ptr);
robbiewc44203a2003-01-10 18:05:10 +0000452 (void)fprintf(stderr, ", pg %d off %d\n", i, j);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800453 anyfail();
robbiewc44203a2003-01-10 18:05:10 +0000454 }
455 ptr++;
456 }
457 }
Garrett Cooper2c282152010-12-16 00:55:50 -0800458
subrata_modak134e8962009-02-26 11:46:54 +0000459 return 1;
robbiewc44203a2003-01-10 18:05:10 +0000460}
461
Wanlong Gao354ebb42012-12-07 10:10:04 +0800462 /*ARGSUSED*/ void finish(int sig)
robbiewc44203a2003-01-10 18:05:10 +0000463{
464 finished++;
465 return;
466}
467
Wanlong Gao354ebb42012-12-07 10:10:04 +0800468unsigned int initrand(void)
robbiewc44203a2003-01-10 18:05:10 +0000469{
470 unsigned int seed;
471
472 /*
473 * Initialize random seed... Got this from a test written
474 * by scooter:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800475 * Use srand/rand to diffuse the information from the
476 * time and pid. If you start several processes, then
477 * the time and pid information don't provide much
478 * variation.
robbiewc44203a2003-01-10 18:05:10 +0000479 */
480 srand((unsigned int)getpid());
481 seed = rand();
Cyril Hrubis4e2bab82014-09-24 16:34:35 +0200482 srand((unsigned int)time(NULL));
robbiewc44203a2003-01-10 18:05:10 +0000483 seed = (seed ^ rand()) % 100000;
484 srand48((long int)seed);
485 return (seed);
486}
487
488/***** LTP Port *****/
489void ok_exit()
490{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800491 tst_resm(TPASS, "Test passed\n");
robbiewc44203a2003-01-10 18:05:10 +0000492 tst_exit();
493}
494
robbiewc44203a2003-01-10 18:05:10 +0000495int anyfail()
496{
Cyril Hrubis526fdf82014-12-04 14:35:01 +0100497 tst_brkm(TFAIL, NULL, "Test failed\n");
robbiewc44203a2003-01-10 18:05:10 +0000498}
499
Chris Dearmanec6edca2012-10-17 19:54:01 -0700500/***** ** ** *****/