1 /* A program to put stress on a POSIX system (stress).
2 *
3 * Copyright (C) 2001, 2002 Amos Waterland <awaterl@yahoo.com>
4 *
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)
8 * any later version.
9 *
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
13 * more details.
14 *
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <libgen.h>
23 #include <math.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <sys/wait.h>
31
32 /* By default, print all messages of severity info and above. */
33 static int global_debug = 2;
34
35 /* By default, just print warning for non-critical errors. */
36 static int global_ignore = 1;
37
38 /* By default, retry on non-critical errors every 50ms. */
39 static int global_retry = 50000;
40
41 /* By default, use this as backoff coefficient for good fork throughput. */
42 static int global_backoff = 3000;
43
44 /* By default, do not timeout. */
45 static int global_timeout = 0;
46
47 /* Name of this program */
48 static char *global_progname = PACKAGE;
49
50 /* By default, do not hang after allocating memory. */
51 static int global_vmhang = 0;
52
53 /* Implemention of runtime-selectable severity message printing. */
54 #define dbg if (global_debug >= 3) \
55 fprintf (stdout, "%s: debug: (%d) ", global_progname, __LINE__), \
56 fprintf
57 #define out if (global_debug >= 2) \
58 fprintf (stdout, "%s: info: ", global_progname), \
59 fprintf
60 #define wrn if (global_debug >= 1) \
61 fprintf (stderr, "%s: warn: (%d) ", global_progname, __LINE__), \
62 fprintf
63 #define err if (global_debug >= 0) \
64 fprintf (stderr, "%s: error: (%d) ", global_progname, __LINE__), \
65 fprintf
66
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]) )) \
71 { \
72 err (stderr, "missing argument to option '%s'\n", A); \
73 exit (1); \
74 }
75
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);
81
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);
87
main(int argc,char ** argv)88 int main(int argc, char **argv)
89 {
90 int i, pid, children = 0, retval = 0;
91 long starttime, stoptime, runtime;
92
93 /* Variables that indicate which options have been selected. */
94 int do_dryrun = 0;
95 int do_timeout = 0;
96 int do_cpu = 0; /* Default to 1 fork. */
97 long long do_cpu_forks = 1;
98 int do_io = 0; /* Default to 1 fork. */
99 long long do_io_forks = 1;
100 int do_vm = 0; /* Default to 1 fork, 1 chunk of 256MB. */
101 long long do_vm_forks = 1;
102 long long do_vm_chunks = 1;
103 long long do_vm_bytes = 256 * 1024 * 1024;
104 int do_hdd = 0; /* Default to 1 fork, clean, 1 file of 1GB. */
105 long long do_hdd_forks = 1;
106 int do_hdd_clean = 0;
107 long long do_hdd_files = 1;
108 long long do_hdd_bytes = 1024 * 1024 * 1024;
109
110 /* Record our start time. */
111 if ((starttime = time(NULL)) == -1) {
112 err(stderr, "failed to acquire current time\n");
113 exit(1);
114 }
115
116 /* SuSv3 does not define any error conditions for this function. */
117 global_progname = basename(argv[0]);
118
119 /* For portability, parse command line options without getopt_long. */
120 for (i = 1; i < argc; i++) {
121 char *arg = argv[i];
122
123 if (strcmp(arg, "--help") == 0 || strcmp(arg, "-?") == 0) {
124 usage(0);
125 } else if (strcmp(arg, "--version") == 0) {
126 version(0);
127 } else if (strcmp(arg, "--verbose") == 0
128 || strcmp(arg, "-v") == 0) {
129 global_debug = 3;
130 } else if (strcmp(arg, "--quiet") == 0
131 || strcmp(arg, "-q") == 0) {
132 global_debug = 0;
133 } else if (strcmp(arg, "--dry-run") == 0
134 || strcmp(arg, "-n") == 0) {
135 do_dryrun = 1;
136 } else if (strcmp(arg, "--no-retry") == 0) {
137 global_ignore = 0;
138 dbg(stdout,
139 "turning off ignore of non-critical errors");
140 } else if (strcmp(arg, "--retry-delay") == 0) {
141 assert_arg("--retry-delay");
142 global_retry = atoll(arg);
143 dbg(stdout, "setting retry delay to %dus\n",
144 global_retry);
145 } else if (strcmp(arg, "--backoff") == 0) {
146 assert_arg("--backoff");
147 global_backoff = atoll(arg);
148 if (global_backoff < 0) {
149 err(stderr, "invalid backoff factor: %i\n",
150 global_backoff);
151 exit(1);
152 }
153 dbg(stdout, "setting backoff coeffient to %dus\n",
154 global_backoff);
155 } else if (strcmp(arg, "--timeout") == 0
156 || strcmp(arg, "-t") == 0) {
157 do_timeout = 1;
158 assert_arg("--timeout");
159 global_timeout = atoll_s(arg);
160 dbg(stdout, "setting timeout to %ds\n", global_timeout);
161 } else if (strcmp(arg, "--cpu") == 0 || strcmp(arg, "-c") == 0) {
162 do_cpu = 1;
163 assert_arg("--cpu");
164 do_cpu_forks = atoll_b(arg);
165 } else if (strcmp(arg, "--io") == 0 || strcmp(arg, "-i") == 0) {
166 do_io = 1;
167 assert_arg("--io");
168 do_io_forks = atoll_b(arg);
169 } else if (strcmp(arg, "--vm") == 0 || strcmp(arg, "-m") == 0) {
170 do_vm = 1;
171 assert_arg("--vm");
172 do_vm_forks = atoll_b(arg);
173 } else if (strcmp(arg, "--vm-chunks") == 0) {
174 assert_arg("--vm-chunks");
175 do_vm_chunks = atoll_b(arg);
176 } else if (strcmp(arg, "--vm-bytes") == 0) {
177 assert_arg("--vm-bytes");
178 do_vm_bytes = atoll_b(arg);
179 } else if (strcmp(arg, "--vm-hang") == 0) {
180 global_vmhang = 1;
181 } else if (strcmp(arg, "--hdd") == 0 || strcmp(arg, "-d") == 0) {
182 do_hdd = 1;
183 assert_arg("--hdd");
184 do_hdd_forks = atoll_b(arg);
185 } else if (strcmp(arg, "--hdd-noclean") == 0) {
186 do_hdd_clean = 2;
187 } else if (strcmp(arg, "--hdd-files") == 0) {
188 assert_arg("--hdd-files");
189 do_hdd_files = atoll_b(arg);
190 } else if (strcmp(arg, "--hdd-bytes") == 0) {
191 assert_arg("--hdd-bytes");
192 do_hdd_bytes = atoll_b(arg);
193 } else {
194 err(stderr, "unrecognized option: %s\n", arg);
195 exit(1);
196 }
197 }
198
199 /* Hog CPU option. */
200 if (do_cpu) {
201 out(stdout, "dispatching %lli hogcpu forks\n", do_cpu_forks);
202
203 switch (pid = fork()) {
204 case 0: /* child */
205 if (do_dryrun)
206 exit(0);
207 exit(hogcpu(do_cpu_forks));
208 case -1: /* error */
209 err(stderr, "hogcpu dispatcher fork failed\n");
210 exit(1);
211 default: /* parent */
212 children++;
213 dbg(stdout, "--> hogcpu dispatcher forked (%i)\n", pid);
214 }
215 }
216
217 /* Hog I/O option. */
218 if (do_io) {
219 out(stdout, "dispatching %lli hogio forks\n", do_io_forks);
220
221 switch (pid = fork()) {
222 case 0: /* child */
223 if (do_dryrun)
224 exit(0);
225 exit(hogio(do_io_forks));
226 case -1: /* error */
227 err(stderr, "hogio dispatcher fork failed\n");
228 exit(1);
229 default: /* parent */
230 children++;
231 dbg(stdout, "--> hogio dispatcher forked (%i)\n", pid);
232 }
233 }
234
235 /* Hog VM option. */
236 if (do_vm) {
237 out(stdout,
238 "dispatching %lli hogvm forks, each %lli chunks of %lli bytes\n",
239 do_vm_forks, do_vm_chunks, do_vm_bytes);
240
241 switch (pid = fork()) {
242 case 0: /* child */
243 if (do_dryrun)
244 exit(0);
245 exit(hogvm(do_vm_forks, do_vm_chunks, do_vm_bytes));
246 case -1: /* error */
247 err(stderr, "hogvm dispatcher fork failed\n");
248 exit(1);
249 default: /* parent */
250 children++;
251 dbg(stdout, "--> hogvm dispatcher forked (%i)\n", pid);
252 }
253 }
254
255 /* Hog HDD option. */
256 if (do_hdd) {
257 out(stdout, "dispatching %lli hoghdd forks, each %lli files of "
258 "%lli bytes\n", do_hdd_forks, do_hdd_files, do_hdd_bytes);
259
260 switch (pid = fork()) {
261 case 0: /* child */
262 if (do_dryrun)
263 exit(0);
264 exit(hoghdd
265 (do_hdd_forks, do_hdd_clean, do_hdd_files,
266 do_hdd_bytes));
267 case -1: /* error */
268 err(stderr, "hoghdd dispatcher fork failed\n");
269 exit(1);
270 default: /* parent */
271 children++;
272 dbg(stdout, "--> hoghdd dispatcher forked (%i)\n", pid);
273 }
274 }
275
276 /* We have no work to do, so bail out. */
277 if (children == 0)
278 usage(0);
279
280 /* Wait for our children to exit. */
281 while (children) {
282 int status, ret;
283
284 if ((pid = wait(&status)) > 0) {
285 if ((WIFEXITED(status)) != 0) {
286 if ((ret = WEXITSTATUS(status)) != 0) {
287 err(stderr,
288 "dispatcher %i returned error %i\n",
289 pid, ret);
290 retval += ret;
291 } else {
292 dbg(stdout,
293 "<-- dispatcher return (%i)\n",
294 pid);
295 }
296 } else {
297 err(stderr,
298 "dispatcher did not exit normally\n");
299 ++retval;
300 }
301
302 --children;
303 } else {
304 dbg(stdout, "wait() returned error: %s\n",
305 strerror(errno));
306 err(stderr, "detected missing dispatcher children\n");
307 ++retval;
308 break;
309 }
310 }
311
312 /* Record our stop time. */
313 if ((stoptime = time(NULL)) == -1) {
314 err(stderr, "failed to acquire current time\n");
315 exit(1);
316 }
317
318 /* Calculate our runtime. */
319 runtime = stoptime - starttime;
320
321 /* Print final status message. */
322 if (retval) {
323 err(stderr, "failed run completed in %lis\n", runtime);
324 } else {
325 out(stdout, "successful run completed in %lis\n", runtime);
326 }
327
328 exit(retval);
329 }
330
usage(int status)331 int usage(int status)
332 {
333 char *mesg =
334 "`%s' imposes certain types of compute stress on your system\n\n"
335 "Usage: %s [OPTION [ARG]] ...\n\n"
336 " -?, --help show this help statement\n"
337 " --version show version statement\n"
338 " -v, --verbose be verbose\n"
339 " -q, --quiet be quiet\n"
340 " -n, --dry-run show what would have been done\n"
341 " --no-retry exit rather than retry non-critical errors\n"
342 " --retry-delay n wait n us before continuing past error\n"
343 " -t, --timeout n timeout after n seconds\n"
344 " --backoff n wait for factor of n us before starting work\n"
345 " -c, --cpu n spawn n procs spinning on sqrt()\n"
346 " -i, --io n spawn n procs spinning on sync()\n"
347 " -m, --vm n spawn n procs spinning on malloc()\n"
348 " --vm-chunks c malloc c chunks (default is 1)\n"
349 " --vm-bytes b malloc chunks of b bytes (default is 256MB)\n"
350 " --vm-hang hang in a sleep loop after memory allocated\n"
351 " -d, --hdd n spawn n procs spinning on write()\n"
352 " --hdd-noclean do not unlink file to which random data written\n"
353 " --hdd-files f write to f files (default is 1)\n"
354 " --hdd-bytes b write b bytes (default is 1GB)\n\n"
355 "Infinity is denoted with 0. For -m, -d: n=0 means infinite redo,\n"
356 "n<0 means redo abs(n) times. Valid suffixes are m,h,d,y for time;\n"
357 "k,m,g for size.\n\n";
358
359 fprintf(stdout, mesg, global_progname, global_progname);
360
361 if (status <= 0)
362 exit(-1 * status);
363
364 return 0;
365 }
366
version(int status)367 int version(int status)
368 {
369 char *mesg = "%s %s\n";
370
371 fprintf(stdout, mesg, global_progname, VERSION);
372
373 if (status <= 0)
374 exit(-1 * status);
375
376 return 0;
377 }
378
379 /* Convert a string representation of a number with an optional size suffix
380 * to a long long.
381 */
atoll_b(const char * nptr)382 long long atoll_b(const char *nptr)
383 {
384 int pos;
385 char suffix;
386 long long factor = 1;
387
388 if ((pos = strlen(nptr) - 1) < 0) {
389 err(stderr, "invalid string\n");
390 exit(1);
391 }
392
393 switch (suffix = nptr[pos]) {
394 case 'k':
395 case 'K':
396 factor = 1024;
397 break;
398 case 'm':
399 case 'M':
400 factor = 1024 * 1024;
401 break;
402 case 'g':
403 case 'G':
404 factor = 1024 * 1024 * 1024;
405 break;
406 default:
407 if (suffix < '0' || suffix > '9') {
408 err(stderr, "unrecognized suffix: %c\n", suffix);
409 exit(1);
410 }
411 }
412
413 factor = atoll(nptr) * factor;
414
415 return factor;
416 }
417
418 /* Convert a string representation of a number with an optional time suffix
419 * to a long long.
420 */
atoll_s(const char * nptr)421 long long atoll_s(const char *nptr)
422 {
423 int pos;
424 char suffix;
425 long long factor = 1;
426
427 if ((pos = strlen(nptr) - 1) < 0) {
428 err(stderr, "invalid string\n");
429 exit(1);
430 }
431
432 switch (suffix = nptr[pos]) {
433 case 's':
434 case 'S':
435 factor = 1;
436 break;
437 case 'm':
438 case 'M':
439 factor = 60;
440 break;
441 case 'h':
442 case 'H':
443 factor = 60 * 60;
444 break;
445 case 'd':
446 case 'D':
447 factor = 60 * 60 * 24;
448 break;
449 case 'y':
450 case 'Y':
451 factor = 60 * 60 * 24 * 360;
452 break;
453 default:
454 if (suffix < '0' || suffix > '9') {
455 err(stderr, "unrecognized suffix: %c\n", suffix);
456 exit(1);
457 }
458 }
459
460 factor = atoll(nptr) * factor;
461
462 return factor;
463 }
464
hogcpu(long long forks)465 int hogcpu(long long forks)
466 {
467 long long i;
468 double d;
469 int pid, retval = 0;
470
471 /* Make local copies of global variables. */
472 int ignore = global_ignore;
473 int retry = global_retry;
474 int timeout = global_timeout;
475 long backoff = global_backoff * forks;
476
477 dbg(stdout, "using backoff sleep of %lius for hogcpu\n", backoff);
478
479 for (i = 0; forks == 0 || i < forks; i++) {
480 switch (pid = fork()) {
481 case 0: /* child */
482 alarm(timeout);
483
484 /* Use a backoff sleep to ensure we get good fork throughput. */
485 usleep(backoff);
486
487 while (1)
488 d = sqrt(rand());
489
490 /* This case never falls through; alarm signal can cause exit. */
491 case -1: /* error */
492 if (ignore) {
493 ++retval;
494 wrn(stderr,
495 "hogcpu worker fork failed, continuing\n");
496 usleep(retry);
497 continue;
498 }
499
500 err(stderr, "hogcpu worker fork failed\n");
501 return 1;
502 default: /* parent */
503 dbg(stdout, "--> hogcpu worker forked (%i)\n", pid);
504 }
505 }
506
507 /* Wait for our children to exit. */
508 while (i) {
509 int status, ret;
510
511 if ((pid = wait(&status)) > 0) {
512 if ((WIFEXITED(status)) != 0) {
513 if ((ret = WEXITSTATUS(status)) != 0) {
514 err(stderr,
515 "hogcpu worker %i exited %i\n", pid,
516 ret);
517 retval += ret;
518 } else {
519 dbg(stdout,
520 "<-- hogcpu worker exited (%i)\n",
521 pid);
522 }
523 } else {
524 dbg(stdout,
525 "<-- hogcpu worker signalled (%i)\n", pid);
526 }
527
528 --i;
529 } else {
530 dbg(stdout, "wait() returned error: %s\n",
531 strerror(errno));
532 err(stderr,
533 "detected missing hogcpu worker children\n");
534 ++retval;
535 break;
536 }
537 }
538
539 return retval;
540 }
541
hogio(long long forks)542 int hogio(long long forks)
543 {
544 long long i;
545 int pid, retval = 0;
546
547 /* Make local copies of global variables. */
548 int ignore = global_ignore;
549 int retry = global_retry;
550 int timeout = global_timeout;
551 long backoff = global_backoff * forks;
552
553 dbg(stdout, "using backoff sleep of %lius for hogio\n", backoff);
554
555 for (i = 0; forks == 0 || i < forks; i++) {
556 switch (pid = fork()) {
557 case 0: /* child */
558 alarm(timeout);
559
560 /* Use a backoff sleep to ensure we get good fork throughput. */
561 usleep(backoff);
562
563 while (1)
564 sync();
565
566 /* This case never falls through; alarm signal can cause exit. */
567 case -1: /* error */
568 if (ignore) {
569 ++retval;
570 wrn(stderr,
571 "hogio worker fork failed, continuing\n");
572 usleep(retry);
573 continue;
574 }
575
576 err(stderr, "hogio worker fork failed\n");
577 return 1;
578 default: /* parent */
579 dbg(stdout, "--> hogio worker forked (%i)\n", pid);
580 }
581 }
582
583 /* Wait for our children to exit. */
584 while (i) {
585 int status, ret;
586
587 if ((pid = wait(&status)) > 0) {
588 if ((WIFEXITED(status)) != 0) {
589 if ((ret = WEXITSTATUS(status)) != 0) {
590 err(stderr,
591 "hogio worker %i exited %i\n", pid,
592 ret);
593 retval += ret;
594 } else {
595 dbg(stdout,
596 "<-- hogio worker exited (%i)\n",
597 pid);
598 }
599 } else {
600 dbg(stdout, "<-- hogio worker signalled (%i)\n",
601 pid);
602 }
603
604 --i;
605 } else {
606 dbg(stdout, "wait() returned error: %s\n",
607 strerror(errno));
608 err(stderr, "detected missing hogio worker children\n");
609 ++retval;
610 break;
611 }
612 }
613
614 return retval;
615 }
616
hogvm(long long forks,long long chunks,long long bytes)617 int hogvm(long long forks, long long chunks, long long bytes)
618 {
619 long long i, j, k;
620 int pid, retval = 0;
621 char **ptr;
622
623 /* Make local copies of global variables. */
624 int ignore = global_ignore;
625 int retry = global_retry;
626 int timeout = global_timeout;
627 long backoff = global_backoff * forks;
628
629 dbg(stdout, "using backoff sleep of %lius for hogvm\n", backoff);
630
631 if (bytes == 0) {
632 /* 512MB is guess at the largest value can than be malloced at once. */
633 bytes = 512 * 1024 * 1024;
634 }
635
636 for (i = 0; forks == 0 || i < forks; i++) {
637 switch (pid = fork()) {
638 case 0: /* child */
639 alarm(timeout);
640
641 /* Use a backoff sleep to ensure we get good fork throughput. */
642 usleep(backoff);
643
644 /* If chunks is 0, ptr will allocate 0 bytes's
645 * memory, it will cause the process to crash
646 * during runtime, so adjust to 1 */
647 if (chunks == 0)
648 chunks = 1;
649
650 while (1) {
651 ptr = (char **)malloc(chunks *
652 sizeof(char *));
653 for (j = 0; j < chunks; j++) {
654 if ((ptr[j] =
655 (char *)malloc(bytes *
656 sizeof(char)))) {
657 for (k = 0; k < bytes; k++)
658 ptr[j][k] = 'Z'; /* Ensure that COW happens. */
659 dbg(stdout,
660 "hogvm worker malloced %lli bytes\n",
661 k);
662 } else if (ignore) {
663 ++retval;
664 wrn(stderr,
665 "hogvm malloc failed, continuing\n");
666 usleep(retry);
667 continue;
668 } else {
669 ++retval;
670 err(stderr,
671 "hogvm malloc failed\n");
672 break;
673 }
674 }
675 if (global_vmhang && retval == 0) {
676 dbg(stdout,
677 "sleeping forever with allocated memory\n");
678 while (1)
679 sleep(1024);
680 }
681 if (retval == 0) {
682 dbg(stdout,
683 "hogvm worker freeing memory and starting over\n");
684 for (j = 0; j < chunks; j++)
685 free(ptr[j]);
686 free(ptr);
687 continue;
688 }
689
690 exit(retval);
691 }
692
693 /* This case never falls through; alarm signal can cause exit. */
694 case -1: /* error */
695 if (ignore) {
696 ++retval;
697 wrn(stderr,
698 "hogvm worker fork failed, continuing\n");
699 usleep(retry);
700 continue;
701 }
702
703 err(stderr, "hogvm worker fork failed\n");
704 return 1;
705 default: /* parent */
706 dbg(stdout, "--> hogvm worker forked (%i)\n", pid);
707 }
708 }
709
710 /* Wait for our children to exit. */
711 while (i) {
712 int status, ret;
713
714 if ((pid = wait(&status)) > 0) {
715 if ((WIFEXITED(status)) != 0) {
716 if ((ret = WEXITSTATUS(status)) != 0) {
717 err(stderr,
718 "hogvm worker %i exited %i\n", pid,
719 ret);
720 retval += ret;
721 } else {
722 dbg(stdout,
723 "<-- hogvm worker exited (%i)\n",
724 pid);
725 }
726 } else {
727 dbg(stdout, "<-- hogvm worker signalled (%i)\n",
728 pid);
729 }
730
731 --i;
732 } else {
733 dbg(stdout, "wait() returned error: %s\n",
734 strerror(errno));
735 err(stderr, "detected missing hogvm worker children\n");
736 ++retval;
737 break;
738 }
739 }
740
741 return retval;
742 }
743
hoghdd(long long forks,int clean,long long files,long long bytes)744 int hoghdd(long long forks, int clean, long long files, long long bytes)
745 {
746 long long i, j;
747 int fd, pid, retval = 0;
748 int chunk = (1024 * 1024) - 1; /* Minimize slow writing. */
749 char buff[chunk];
750
751 /* Make local copies of global variables. */
752 int ignore = global_ignore;
753 int retry = global_retry;
754 int timeout = global_timeout;
755 long backoff = global_backoff * forks;
756
757 /* Initialize buffer with some random ASCII data. */
758 dbg(stdout, "seeding buffer with random data\n");
759 for (i = 0; i < chunk - 1; i++) {
760 j = rand();
761 j = (j < 0) ? -j : j;
762 j %= 95;
763 j += 32;
764 buff[i] = j;
765 }
766 buff[i] = '\n';
767
768 dbg(stdout, "using backoff sleep of %lius for hoghdd\n", backoff);
769
770 for (i = 0; forks == 0 || i < forks; i++) {
771 switch (pid = fork()) {
772 case 0: /* child */
773 alarm(timeout);
774
775 /* Use a backoff sleep to ensure we get good fork throughput. */
776 usleep(backoff);
777
778 while (1) {
779 for (i = 0; i < files; i++) {
780 char name[] = "./stress.XXXXXX";
781
782 if ((fd = mkstemp(name)) < 0) {
783 perror("mkstemp");
784 err(stderr, "mkstemp failed\n");
785 exit(1);
786 }
787
788 if (clean == 0) {
789 dbg(stdout, "unlinking %s\n",
790 name);
791 if (unlink(name)) {
792 err(stderr,
793 "unlink failed\n");
794 exit(1);
795 }
796 }
797
798 dbg(stdout, "fast writing to %s\n",
799 name);
800 for (j = 0;
801 bytes == 0 || j + chunk < bytes;
802 j += chunk) {
803 if (write(fd, buff, chunk) !=
804 chunk) {
805 err(stderr,
806 "write failed\n");
807 exit(1);
808 }
809 }
810
811 dbg(stdout, "slow writing to %s\n",
812 name);
813 for (; bytes == 0 || j < bytes - 1; j++) {
814 if (write(fd, "Z", 1) != 1) {
815 err(stderr,
816 "write failed\n");
817 exit(1);
818 }
819 }
820 if (write(fd, "\n", 1) != 1) {
821 err(stderr, "write failed\n");
822 exit(1);
823 }
824 ++j;
825
826 dbg(stdout,
827 "closing %s after writing %lli bytes\n",
828 name, j);
829 close(fd);
830
831 if (clean == 1) {
832 if (unlink(name)) {
833 err(stderr,
834 "unlink failed\n");
835 exit(1);
836 }
837 }
838 }
839 if (retval == 0) {
840 dbg(stdout,
841 "hoghdd worker starting over\n");
842 continue;
843 }
844
845 exit(retval);
846 }
847
848 /* This case never falls through; alarm signal can cause exit. */
849 case -1: /* error */
850 if (ignore) {
851 ++retval;
852 wrn(stderr,
853 "hoghdd worker fork failed, continuing\n");
854 usleep(retry);
855 continue;
856 }
857
858 err(stderr, "hoghdd worker fork failed\n");
859 return 1;
860 default: /* parent */
861 dbg(stdout, "--> hoghdd worker forked (%i)\n", pid);
862 }
863 }
864
865 /* Wait for our children to exit. */
866 while (i) {
867 int status, ret;
868
869 if ((pid = wait(&status)) > 0) {
870 if ((WIFEXITED(status)) != 0) {
871 if ((ret = WEXITSTATUS(status)) != 0) {
872 err(stderr,
873 "hoghdd worker %i exited %i\n", pid,
874 ret);
875 retval += ret;
876 } else {
877 dbg(stdout,
878 "<-- hoghdd worker exited (%i)\n",
879 pid);
880 }
881 } else {
882 dbg(stdout,
883 "<-- hoghdd worker signalled (%i)\n", pid);
884 }
885
886 --i;
887 } else {
888 dbg(stdout, "wait() returned error: %s\n",
889 strerror(errno));
890 err(stderr,
891 "detected missing hoghdd worker children\n");
892 ++retval;
893 break;
894 }
895 }
896
897 return retval;
898 }
899