1 /* A program to put stress on a POSIX system (stress).
3 * Copyright (C) 2001, 2002 Amos Waterland <awaterl@yahoo.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc., 59
17 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 /* By default, print all messages of severity info and above. */
33 static int global_debug
= 2;
35 /* By default, just print warning for non-critical errors. */
36 static int global_ignore
= 1;
38 /* By default, retry on non-critical errors every 50ms. */
39 static int global_retry
= 50000;
41 /* By default, use this as backoff coefficient for good fork throughput. */
42 static int global_backoff
= 3000;
44 /* By default, do not timeout. */
45 static int global_timeout
= 0;
47 /* Name of this program */
48 static char *global_progname
= PACKAGE
;
50 /* By default, do not hang after allocating memory. */
51 static int global_vmhang
= 0;
53 /* Implemention of runtime-selectable severity message printing. */
54 #define dbg if (global_debug >= 3) \
55 fprintf (stdout, "%s: debug: (%d) ", global_progname, __LINE__), \
57 #define out if (global_debug >= 2) \
58 fprintf (stdout, "%s: info: ", global_progname), \
60 #define wrn if (global_debug >= 1) \
61 fprintf (stderr, "%s: warn: (%d) ", global_progname, __LINE__), \
63 #define err if (global_debug >= 0) \
64 fprintf (stderr, "%s: error: (%d) ", global_progname, __LINE__), \
67 /* Implementation of check for option argument correctness. */
68 #define assert_arg(A) \
69 if (++i == argc || ((arg = argv[i])[0] == '-' && \
70 !isdigit ((int)arg[1]) )) \
72 err (stderr, "missing argument to option '%s'\n", A); \
76 /* Prototypes for utility functions. */
77 int usage (int status
);
78 int version (int status
);
79 long long atoll_s (const char *nptr
);
80 long long atoll_b (const char *nptr
);
82 /* Prototypes for the worker functions. */
83 int hogcpu (long long forks
);
84 int hogio (long long forks
);
85 int hogvm (long long forks
, long long chunks
, long long bytes
);
86 int hoghdd (long long forks
, int clean
, long long files
, long long bytes
);
89 main (int argc
, char **argv
)
91 int i
, pid
, children
= 0, retval
= 0;
92 long starttime
, stoptime
, runtime
;
94 /* Variables that indicate which options have been selected. */
97 int do_cpu
= 0; /* Default to 1 fork. */
98 long long do_cpu_forks
= 1;
99 int do_io
= 0; /* Default to 1 fork. */
100 long long do_io_forks
= 1;
101 int do_vm
= 0; /* Default to 1 fork, 1 chunk of 256MB. */
102 long long do_vm_forks
= 1;
103 long long do_vm_chunks
= 1;
104 long long do_vm_bytes
= 256 * 1024 * 1024;
105 int do_hdd
= 0; /* Default to 1 fork, clean, 1 file of 1GB. */
106 long long do_hdd_forks
= 1;
107 int do_hdd_clean
= 0;
108 long long do_hdd_files
= 1;
109 long long do_hdd_bytes
= 1024 * 1024 * 1024;
111 /* Record our start time. */
112 if ((starttime
= time (NULL
)) == -1)
114 err (stderr
, "failed to acquire current time\n");
118 /* SuSv3 does not define any error conditions for this function. */
119 global_progname
= basename (argv
[0]);
121 /* For portability, parse command line options without getopt_long. */
122 for (i
= 1; i
< argc
; i
++)
126 if (strcmp (arg
, "--help") == 0 || strcmp (arg
, "-?") == 0)
130 else if (strcmp (arg
, "--version") == 0)
134 else if (strcmp (arg
, "--verbose") == 0 || strcmp (arg
, "-v") == 0)
138 else if (strcmp (arg
, "--quiet") == 0 || strcmp (arg
, "-q") == 0)
142 else if (strcmp (arg
, "--dry-run") == 0 || strcmp (arg
, "-n") == 0)
146 else if (strcmp (arg
, "--no-retry") == 0)
149 dbg (stdout
, "turning off ignore of non-critical errors");
151 else if (strcmp (arg
, "--retry-delay") == 0)
153 assert_arg ("--retry-delay");
154 global_retry
= atoll (arg
);
155 dbg (stdout
, "setting retry delay to %dus\n", global_retry
);
157 else if (strcmp (arg
, "--backoff") == 0)
159 assert_arg ("--backoff");
160 global_backoff
= atoll (arg
);
161 if (global_backoff
< 0)
163 err (stderr
, "invalid backoff factor: %i\n", global_backoff
);
166 dbg (stdout
, "setting backoff coeffient to %dus\n", global_backoff
);
168 else if (strcmp (arg
, "--timeout") == 0 || strcmp (arg
, "-t") == 0)
171 assert_arg ("--timeout");
172 global_timeout
= atoll_s (arg
);
173 dbg (stdout
, "setting timeout to %ds\n", global_timeout
);
175 else if (strcmp (arg
, "--cpu") == 0 || strcmp (arg
, "-c") == 0)
178 assert_arg ("--cpu");
179 do_cpu_forks
= atoll_b (arg
);
181 else if (strcmp (arg
, "--io") == 0 || strcmp (arg
, "-i") == 0)
185 do_io_forks
= atoll_b (arg
);
187 else if (strcmp (arg
, "--vm") == 0 || strcmp (arg
, "-m") == 0)
191 do_vm_forks
= atoll_b (arg
);
193 else if (strcmp (arg
, "--vm-chunks") == 0)
195 assert_arg ("--vm-chunks");
196 do_vm_chunks
= atoll_b (arg
);
198 else if (strcmp (arg
, "--vm-bytes") == 0)
200 assert_arg ("--vm-bytes");
201 do_vm_bytes
= atoll_b (arg
);
203 else if (strcmp (arg
, "--vm-hang") == 0)
207 else if (strcmp (arg
, "--hdd") == 0 || strcmp (arg
, "-d") == 0)
210 assert_arg ("--hdd");
211 do_hdd_forks
= atoll_b (arg
);
213 else if (strcmp (arg
, "--hdd-noclean") == 0)
217 else if (strcmp (arg
, "--hdd-files") == 0)
219 assert_arg ("--hdd-files");
220 do_hdd_files
= atoll_b (arg
);
222 else if (strcmp (arg
, "--hdd-bytes") == 0)
224 assert_arg ("--hdd-bytes");
225 do_hdd_bytes
= atoll_b (arg
);
229 err (stderr
, "unrecognized option: %s\n", arg
);
234 /* Hog CPU option. */
237 out (stdout
, "dispatching %lli hogcpu forks\n", do_cpu_forks
);
239 switch (pid
= fork ())
244 exit (hogcpu (do_cpu_forks
));
246 err (stderr
, "hogcpu dispatcher fork failed\n");
248 default: /* parent */
250 dbg (stdout
, "--> hogcpu dispatcher forked (%i)\n", pid
);
254 /* Hog I/O option. */
257 out (stdout
, "dispatching %lli hogio forks\n", do_io_forks
);
259 switch (pid
= fork ())
264 exit (hogio (do_io_forks
));
266 err (stderr
, "hogio dispatcher fork failed\n");
268 default: /* parent */
270 dbg (stdout
, "--> hogio dispatcher forked (%i)\n", pid
);
278 "dispatching %lli hogvm forks, each %lli chunks of %lli bytes\n",
279 do_vm_forks
, do_vm_chunks
, do_vm_bytes
);
281 switch (pid
= fork ())
286 exit (hogvm (do_vm_forks
, do_vm_chunks
, do_vm_bytes
));
288 err (stderr
, "hogvm dispatcher fork failed\n");
290 default: /* parent */
292 dbg (stdout
, "--> hogvm dispatcher forked (%i)\n", pid
);
296 /* Hog HDD option. */
299 out (stdout
, "dispatching %lli hoghdd forks, each %lli files of "
300 "%lli bytes\n", do_hdd_forks
, do_hdd_files
, do_hdd_bytes
);
302 switch (pid
= fork ())
308 (do_hdd_forks
, do_hdd_clean
, do_hdd_files
, do_hdd_bytes
));
310 err (stderr
, "hoghdd dispatcher fork failed\n");
312 default: /* parent */
314 dbg (stdout
, "--> hoghdd dispatcher forked (%i)\n", pid
);
318 /* We have no work to do, so bail out. */
322 /* Wait for our children to exit. */
327 if ((pid
= wait (&status
)) > 0)
329 if ((WIFEXITED (status
)) != 0)
331 if ((ret
= WEXITSTATUS (status
)) != 0)
333 err (stderr
, "dispatcher %i returned error %i\n", pid
, ret
);
338 dbg (stdout
, "<-- dispatcher return (%i)\n", pid
);
343 err (stderr
, "dispatcher did not exit normally\n");
351 dbg (stdout
, "wait() returned error: %s\n", strerror (errno
));
352 err (stderr
, "detected missing dispatcher children\n");
358 /* Record our stop time. */
359 if ((stoptime
= time (NULL
)) == -1)
361 err (stderr
, "failed to acquire current time\n");
365 /* Calculate our runtime. */
366 runtime
= stoptime
- starttime
;
368 /* Print final status message. */
371 err (stderr
, "failed run completed in %lis\n", runtime
);
375 out (stdout
, "successful run completed in %lis\n", runtime
);
385 "`%s' imposes certain types of compute stress on your system\n\n"
386 "Usage: %s [OPTION [ARG]] ...\n\n"
387 " -?, --help show this help statement\n"
388 " --version show version statement\n"
389 " -v, --verbose be verbose\n"
390 " -q, --quiet be quiet\n"
391 " -n, --dry-run show what would have been done\n"
392 " --no-retry exit rather than retry non-critical errors\n"
393 " --retry-delay n wait n us before continuing past error\n"
394 " -t, --timeout n timeout after n seconds\n"
395 " --backoff n wait for factor of n us before starting work\n"
396 " -c, --cpu n spawn n procs spinning on sqrt()\n"
397 " -i, --io n spawn n procs spinning on sync()\n"
398 " -m, --vm n spawn n procs spinning on malloc()\n"
399 " --vm-chunks c malloc c chunks (default is 1)\n"
400 " --vm-bytes b malloc chunks of b bytes (default is 256MB)\n"
401 " --vm-hang hang in a sleep loop after memory allocated\n"
402 " -d, --hdd n spawn n procs spinning on write()\n"
403 " --hdd-noclean do not unlink file to which random data written\n"
404 " --hdd-files f write to f files (default is 1)\n"
405 " --hdd-bytes b write b bytes (default is 1GB)\n\n"
406 "Infinity is denoted with 0. For -m, -d: n=0 means infinite redo,\n"
407 "n<0 means redo abs(n) times. Valid suffixes are m,h,d,y for time;\n"
408 "k,m,g for size.\n\n";
410 fprintf (stdout
, mesg
, global_progname
, global_progname
);
421 char *mesg
= "%s %s\n";
423 fprintf (stdout
, mesg
, global_progname
, VERSION
);
431 /* Convert a string representation of a number with an optional size suffix
435 atoll_b (const char *nptr
)
439 long long factor
= 1;
441 if ((pos
= strlen (nptr
) - 1) < 0)
443 err (stderr
, "invalid string\n");
447 switch (suffix
= nptr
[pos
])
455 factor
= 1024 * 1024;
459 factor
= 1024 * 1024 * 1024;
462 if (suffix
< '0' || suffix
> '9')
464 err (stderr
, "unrecognized suffix: %c\n", suffix
);
469 factor
= atoll (nptr
) * factor
;
474 /* Convert a string representation of a number with an optional time suffix
478 atoll_s (const char *nptr
)
482 long long factor
= 1;
484 if ((pos
= strlen (nptr
) - 1) < 0)
486 err (stderr
, "invalid string\n");
490 switch (suffix
= nptr
[pos
])
506 factor
= 60 * 60 * 24;
510 factor
= 60 * 60 * 24 * 360;
513 if (suffix
< '0' || suffix
> '9')
515 err (stderr
, "unrecognized suffix: %c\n", suffix
);
520 factor
= atoll (nptr
) * factor
;
526 hogcpu (long long forks
)
532 /* Make local copies of global variables. */
533 int ignore
= global_ignore
;
534 int retry
= global_retry
;
535 int timeout
= global_timeout
;
536 long backoff
= global_backoff
* forks
;
538 dbg (stdout
, "using backoff sleep of %lius for hogcpu\n", backoff
);
540 for (i
= 0; forks
== 0 || i
< forks
; i
++)
542 switch (pid
= fork ())
547 /* Use a backoff sleep to ensure we get good fork throughput. */
553 /* This case never falls through; alarm signal can cause exit. */
558 wrn (stderr
, "hogcpu worker fork failed, continuing\n");
563 err (stderr
, "hogcpu worker fork failed\n");
565 default: /* parent */
566 dbg (stdout
, "--> hogcpu worker forked (%i)\n", pid
);
570 /* Wait for our children to exit. */
575 if ((pid
= wait (&status
)) > 0)
577 if ((WIFEXITED (status
)) != 0)
579 if ((ret
= WEXITSTATUS (status
)) != 0)
581 err (stderr
, "hogcpu worker %i exited %i\n", pid
, ret
);
586 dbg (stdout
, "<-- hogcpu worker exited (%i)\n", pid
);
591 dbg (stdout
, "<-- hogcpu worker signalled (%i)\n", pid
);
598 dbg (stdout
, "wait() returned error: %s\n", strerror (errno
));
599 err (stderr
, "detected missing hogcpu worker children\n");
609 hogio (long long forks
)
614 /* Make local copies of global variables. */
615 int ignore
= global_ignore
;
616 int retry
= global_retry
;
617 int timeout
= global_timeout
;
618 long backoff
= global_backoff
* forks
;
620 dbg (stdout
, "using backoff sleep of %lius for hogio\n", backoff
);
622 for (i
= 0; forks
== 0 || i
< forks
; i
++)
624 switch (pid
= fork ())
629 /* Use a backoff sleep to ensure we get good fork throughput. */
635 /* This case never falls through; alarm signal can cause exit. */
640 wrn (stderr
, "hogio worker fork failed, continuing\n");
645 err (stderr
, "hogio worker fork failed\n");
647 default: /* parent */
648 dbg (stdout
, "--> hogio worker forked (%i)\n", pid
);
652 /* Wait for our children to exit. */
657 if ((pid
= wait (&status
)) > 0)
659 if ((WIFEXITED (status
)) != 0)
661 if ((ret
= WEXITSTATUS (status
)) != 0)
663 err (stderr
, "hogio worker %i exited %i\n", pid
, ret
);
668 dbg (stdout
, "<-- hogio worker exited (%i)\n", pid
);
673 dbg (stdout
, "<-- hogio worker signalled (%i)\n", pid
);
680 dbg (stdout
, "wait() returned error: %s\n", strerror (errno
));
681 err (stderr
, "detected missing hogio worker children\n");
691 hogvm (long long forks
, long long chunks
, long long bytes
)
697 /* Make local copies of global variables. */
698 int ignore
= global_ignore
;
699 int retry
= global_retry
;
700 int timeout
= global_timeout
;
701 long backoff
= global_backoff
* forks
;
703 dbg (stdout
, "using backoff sleep of %lius for hogvm\n", backoff
);
707 /* 512MB is guess at the largest value can than be malloced at once. */
708 bytes
= 512 * 1024 * 1024;
711 for (i
= 0; forks
== 0 || i
< forks
; i
++)
713 switch (pid
= fork ())
718 /* Use a backoff sleep to ensure we get good fork throughput. */
723 ptr
= (char **) malloc ( chunks
* 2);
724 for (j
= 0; chunks
== 0 || j
< chunks
; j
++)
726 if ((ptr
[j
] = (char *) malloc (bytes
* sizeof (char))))
728 for (k
= 0; k
< bytes
; k
++)
729 ptr
[j
][k
] = 'Z'; /* Ensure that COW happens. */
730 dbg (stdout
, "hogvm worker malloced %lli bytes\n", k
);
735 wrn (stderr
, "hogvm malloc failed, continuing\n");
742 err (stderr
, "hogvm malloc failed\n");
746 if (global_vmhang
&& retval
== 0)
748 dbg (stdout
, "sleeping forever with allocated memory\n");
755 "hogvm worker freeing memory and starting over\n");
756 for (j
= 0; chunks
== 0 || j
< chunks
; j
++) {
766 /* This case never falls through; alarm signal can cause exit. */
771 wrn (stderr
, "hogvm worker fork failed, continuing\n");
776 err (stderr
, "hogvm worker fork failed\n");
778 default: /* parent */
779 dbg (stdout
, "--> hogvm worker forked (%i)\n", pid
);
783 /* Wait for our children to exit. */
788 if ((pid
= wait (&status
)) > 0)
790 if ((WIFEXITED (status
)) != 0)
792 if ((ret
= WEXITSTATUS (status
)) != 0)
794 err (stderr
, "hogvm worker %i exited %i\n", pid
, ret
);
799 dbg (stdout
, "<-- hogvm worker exited (%i)\n", pid
);
804 dbg (stdout
, "<-- hogvm worker signalled (%i)\n", pid
);
811 dbg (stdout
, "wait() returned error: %s\n", strerror (errno
));
812 err (stderr
, "detected missing hogvm worker children\n");
822 hoghdd (long long forks
, int clean
, long long files
, long long bytes
)
825 int fd
, pid
, retval
= 0;
826 int chunk
= (1024 * 1024) - 1; /* Minimize slow writing. */
829 /* Make local copies of global variables. */
830 int ignore
= global_ignore
;
831 int retry
= global_retry
;
832 int timeout
= global_timeout
;
833 long backoff
= global_backoff
* forks
;
835 /* Initialize buffer with some random ASCII data. */
836 dbg (stdout
, "seeding buffer with random data\n");
837 for (i
= 0; i
< chunk
- 1; i
++)
840 j
= (j
< 0) ? -j
: j
;
847 dbg (stdout
, "using backoff sleep of %lius for hoghdd\n", backoff
);
849 for (i
= 0; forks
== 0 || i
< forks
; i
++)
851 switch (pid
= fork ())
856 /* Use a backoff sleep to ensure we get good fork throughput. */
861 for (i
= 0; i
< files
; i
++)
863 char name
[] = "./stress.XXXXXX";
865 if ((fd
= mkstemp (name
)) < 0)
868 err (stderr
, "mkstemp failed\n");
874 dbg (stdout
, "unlinking %s\n", name
);
877 err (stderr
, "unlink failed\n");
882 dbg (stdout
, "fast writing to %s\n", name
);
883 for (j
= 0; bytes
== 0 || j
+ chunk
< bytes
; j
+= chunk
)
885 if (write (fd
, buff
, chunk
) != chunk
)
887 err (stderr
, "write failed\n");
892 dbg (stdout
, "slow writing to %s\n", name
);
893 for (; bytes
== 0 || j
< bytes
- 1; j
++)
895 if (write (fd
, "Z", 1) != 1)
897 err (stderr
, "write failed\n");
901 if (write (fd
, "\n", 1) != 1)
903 err (stderr
, "write failed\n");
908 dbg (stdout
, "closing %s after writing %lli bytes\n", name
,
916 err (stderr
, "unlink failed\n");
923 dbg (stdout
, "hoghdd worker starting over\n");
930 /* This case never falls through; alarm signal can cause exit. */
935 wrn (stderr
, "hoghdd worker fork failed, continuing\n");
940 err (stderr
, "hoghdd worker fork failed\n");
942 default: /* parent */
943 dbg (stdout
, "--> hoghdd worker forked (%i)\n", pid
);
947 /* Wait for our children to exit. */
952 if ((pid
= wait (&status
)) > 0)
954 if ((WIFEXITED (status
)) != 0)
956 if ((ret
= WEXITSTATUS (status
)) != 0)
958 err (stderr
, "hoghdd worker %i exited %i\n", pid
, ret
);
963 dbg (stdout
, "<-- hoghdd worker exited (%i)\n", pid
);
968 dbg (stdout
, "<-- hoghdd worker signalled (%i)\n", pid
);
975 dbg (stdout
, "wait() returned error: %s\n", strerror (errno
));
976 err (stderr
, "detected missing hoghdd worker children\n");