"Fossies" - the Fresh Open Source Software Archive 
Member "stress-1.0.5/src/stress.c" (2 Oct 2021, 20902 Bytes) of package /linux/privat/old/stress-1.0.5.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "stress.c" see the
Fossies "Dox" file reference documentation.
1 /* A program to put stress on a POSIX system (stress).
2 *
3 * Copyright 2001-2010 Amos Waterland <apw@rossby.metr.ou.edu>
4 * Copyright 2021 Joao Eriberto Mota Filho <eriberto@eriberto.pro.br>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 59
18 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <libgen.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <sys/wait.h>
32 #include "config.h"
33
34 /* By default, print all messages of severity info and above. */
35 static int global_debug = 2;
36
37 /* Name of this program */
38 static char *global_progname = PACKAGE;
39
40 /* Implemention of runtime-selectable severity message printing. */
41 #define dbg(OUT, STR, ARGS...) if (global_debug >= 3) \
42 fprintf (stdout, "%s: dbug: [%lli] ", \
43 global_progname, (long long)getpid()), \
44 fprintf(OUT, STR, ##ARGS), fflush(OUT)
45 #define out(OUT, STR, ARGS...) if (global_debug >= 2) \
46 fprintf (stdout, "%s: info: [%lli] ", \
47 global_progname, (long long)getpid()), \
48 fprintf(OUT, STR, ##ARGS), fflush(OUT)
49 #define wrn(OUT, STR, ARGS...) if (global_debug >= 1) \
50 fprintf (stderr, "%s: WARN: [%lli] (%d) ", \
51 global_progname, (long long)getpid(), __LINE__), \
52 fprintf(OUT, STR, ##ARGS), fflush(OUT)
53 #define err(OUT, STR, ARGS...) if (global_debug >= 0) \
54 fprintf (stderr, "%s: FAIL: [%lli] (%d) ", \
55 global_progname, (long long)getpid(), __LINE__), \
56 fprintf(OUT, STR, ##ARGS), fflush(OUT)
57
58 /* Implementation of check for option argument correctness. */
59 #define assert_arg(A) \
60 if (++i == argc || ((arg = argv[i])[0] == '-' && \
61 !isdigit ((int)arg[1]) )) \
62 { \
63 err (stderr, "missing argument to option '%s'\n", A); \
64 exit (1); \
65 }
66
67 /* Prototypes for utility functions. */
68 int usage (int status);
69 int version (int status);
70 long long atoll_s (const char *nptr);
71 long long atoll_b (const char *nptr);
72
73 /* Prototypes for worker functions. */
74 int hogcpu (void);
75 int hogio (void);
76 int hogvm (long long bytes, long long stride, long long hang, int keep);
77 int hoghdd (long long bytes);
78
79 int
80 main (int argc, char **argv)
81 {
82 int i, pid, children = 0, retval = 0;
83 long starttime, stoptime, runtime, forks;
84
85 /* Variables that indicate which options have been selected. */
86 int do_dryrun = 0;
87 long long do_backoff = 3000;
88 long long do_timeout = 0;
89 long long do_cpu = 0;
90 long long do_io = 0;
91 long long do_vm = 0;
92 long long do_vm_bytes = 256 * 1024 * 1024;
93 long long do_vm_stride = 4096;
94 long long do_vm_hang = -1;
95 int do_vm_keep = 0;
96 long long do_hdd = 0;
97 long long do_hdd_bytes = 1024 * 1024 * 1024;
98
99 /* Record our start time. */
100 if ((starttime = time (NULL)) == -1)
101 {
102 err (stderr, "failed to acquire current time: %s\n", strerror (errno));
103 exit (1);
104 }
105
106 /* SuSv3 does not define any error conditions for this function. */
107 global_progname = basename (argv[0]);
108
109 /* For portability, parse command line options without getopt_long. */
110 for (i = 1; i < argc; i++)
111 {
112 char *arg = argv[i];
113
114 if (strcmp (arg, "--help") == 0 || strcmp (arg, "-?") == 0)
115 {
116 usage (0);
117 }
118 else if (strcmp (arg, "--version") == 0)
119 {
120 version (0);
121 }
122 else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0)
123 {
124 global_debug = 3;
125 }
126 else if (strcmp (arg, "--quiet") == 0 || strcmp (arg, "-q") == 0)
127 {
128 global_debug = 0;
129 }
130 else if (strcmp (arg, "--dry-run") == 0 || strcmp (arg, "-n") == 0)
131 {
132 do_dryrun = 1;
133 }
134 else if (strcmp (arg, "--backoff") == 0)
135 {
136 assert_arg ("--backoff");
137 if (sscanf (arg, "%lli", &do_backoff) != 1)
138 {
139 err (stderr, "invalid number: %s\n", arg);
140 exit (1);
141 }
142 if (do_backoff < 0)
143 {
144 err (stderr, "invalid backoff factor: %lli\n", do_backoff);
145 exit (1);
146 }
147 dbg (stdout, "setting backoff coeffient to %llius\n", do_backoff);
148 }
149 else if (strcmp (arg, "--timeout") == 0 || strcmp (arg, "-t") == 0)
150 {
151 assert_arg ("--timeout");
152 do_timeout = atoll_s (arg);
153 if (do_timeout <= 0)
154 {
155 err (stderr, "invalid timeout value: %llis\n", do_timeout);
156 exit (1);
157 }
158 }
159 else if (strcmp (arg, "--cpu") == 0 || strcmp (arg, "-c") == 0)
160 {
161 assert_arg ("--cpu");
162 do_cpu = atoll_b (arg);
163 if (do_cpu <= 0)
164 {
165 err (stderr, "invalid number of cpu hogs: %lli\n", do_cpu);
166 exit (1);
167 }
168 }
169 else if (strcmp (arg, "--io") == 0 || strcmp (arg, "-i") == 0)
170 {
171 assert_arg ("--io");
172 do_io = atoll_b (arg);
173 if (do_io <= 0)
174 {
175 err (stderr, "invalid number of io hogs: %lli\n", do_io);
176 exit (1);
177 }
178 }
179 else if (strcmp (arg, "--vm") == 0 || strcmp (arg, "-m") == 0)
180 {
181 assert_arg ("--vm");
182 do_vm = atoll_b (arg);
183 if (do_vm <= 0)
184 {
185 err (stderr, "invalid number of vm hogs: %lli\n", do_vm);
186 exit (1);
187 }
188 }
189 else if (strcmp (arg, "--vm-bytes") == 0)
190 {
191 assert_arg ("--vm-bytes");
192 do_vm_bytes = atoll_b (arg);
193 if (do_vm_bytes <= 0)
194 {
195 err (stderr, "invalid vm byte value: %lli\n", do_vm_bytes);
196 exit (1);
197 }
198 }
199 else if (strcmp (arg, "--vm-stride") == 0)
200 {
201 assert_arg ("--vm-stride");
202 do_vm_stride = atoll_b (arg);
203 if (do_vm_stride <= 0)
204 {
205 err (stderr, "invalid stride value: %lli\n", do_vm_stride);
206 exit (1);
207 }
208 }
209 else if (strcmp (arg, "--vm-hang") == 0)
210 {
211 assert_arg ("--vm-hang");
212 do_vm_hang = atoll_b (arg);
213 if (do_vm_hang < 0)
214 {
215 err (stderr, "invalid value: %lli\n", do_vm_hang);
216 exit (1);
217 }
218 }
219 else if (strcmp (arg, "--vm-keep") == 0)
220 {
221 do_vm_keep = 1;
222 }
223 else if (strcmp (arg, "--hdd") == 0 || strcmp (arg, "-d") == 0)
224 {
225 assert_arg ("--hdd");
226 do_hdd = atoll_b (arg);
227 if (do_hdd <= 0)
228 {
229 err (stderr, "invalid number of hdd hogs: %lli\n", do_hdd);
230 exit (1);
231 }
232 }
233 else if (strcmp (arg, "--hdd-bytes") == 0)
234 {
235 assert_arg ("--hdd-bytes");
236 do_hdd_bytes = atoll_b (arg);
237 if (do_hdd_bytes <= 0)
238 {
239 err (stderr, "invalid hdd byte value: %lli\n", do_hdd_bytes);
240 exit (1);
241 }
242 }
243 else
244 {
245 err (stderr, "unrecognized option: %s\n", arg);
246 exit (1);
247 }
248 }
249
250 /* Print startup message if we have work to do, bail otherwise. */
251 if (do_cpu + do_io + do_vm + do_hdd)
252 {
253 out (stdout, "dispatching hogs: %lli cpu, %lli io, %lli vm, %lli hdd\n",
254 do_cpu, do_io, do_vm, do_hdd);
255 }
256 else
257 usage (0);
258
259 /* Round robin dispatch our worker processes. */
260 while ((forks = (do_cpu + do_io + do_vm + do_hdd)))
261 {
262 long long backoff, timeout = 0;
263
264 /* Calculate the backoff value so we get good fork throughput. */
265 backoff = do_backoff * forks;
266 dbg (stdout, "using backoff sleep of %llius\n", backoff);
267
268 /* If we are supposed to respect a timeout, calculate it. */
269 if (do_timeout)
270 {
271 long long currenttime;
272
273 /* Acquire current time. */
274 if ((currenttime = time (NULL)) == -1)
275 {
276 perror ("error acquiring current time");
277 exit (1);
278 }
279
280 /* Calculate timeout based on current time. */
281 timeout = do_timeout - (currenttime - starttime);
282
283 if (timeout > 0)
284 {
285 dbg (stdout, "setting timeout to %llis\n", timeout);
286 }
287 else
288 {
289 wrn (stderr, "used up time before all workers dispatched\n");
290 break;
291 }
292 }
293
294 if (do_cpu)
295 {
296 switch (pid = fork ())
297 {
298 case 0: /* child */
299 alarm (timeout);
300 usleep (backoff);
301 if (do_dryrun)
302 exit (0);
303 exit (hogcpu ());
304 case -1: /* error */
305 err (stderr, "fork failed: %s\n", strerror (errno));
306 break;
307 default: /* parent */
308 dbg (stdout, "--> hogcpu worker %lli [%i] forked\n",
309 do_cpu, pid);
310 ++children;
311 }
312 --do_cpu;
313 }
314
315 if (do_io)
316 {
317 switch (pid = fork ())
318 {
319 case 0: /* child */
320 alarm (timeout);
321 usleep (backoff);
322 if (do_dryrun)
323 exit (0);
324 exit (hogio ());
325 case -1: /* error */
326 err (stderr, "fork failed: %s\n", strerror (errno));
327 break;
328 default: /* parent */
329 dbg (stdout, "--> hogio worker %lli [%i] forked\n", do_io, pid);
330 ++children;
331 }
332 --do_io;
333 }
334
335 if (do_vm)
336 {
337 switch (pid = fork ())
338 {
339 case 0: /* child */
340 alarm (timeout);
341 usleep (backoff);
342 if (do_dryrun)
343 exit (0);
344 exit (hogvm
345 (do_vm_bytes, do_vm_stride, do_vm_hang, do_vm_keep));
346 case -1: /* error */
347 err (stderr, "fork failed: %s\n", strerror (errno));
348 break;
349 default: /* parent */
350 dbg (stdout, "--> hogvm worker %lli [%i] forked\n", do_vm, pid);
351 ++children;
352 }
353 --do_vm;
354 }
355
356 if (do_hdd)
357 {
358 switch (pid = fork ())
359 {
360 case 0: /* child */
361 alarm (timeout);
362 usleep (backoff);
363 if (do_dryrun)
364 exit (0);
365 exit (hoghdd (do_hdd_bytes));
366 case -1: /* error */
367 err (stderr, "fork failed: %s\n", strerror (errno));
368 break;
369 default: /* parent */
370 dbg (stdout, "--> hoghdd worker %lli [%i] forked\n",
371 do_hdd, pid);
372 ++children;
373 }
374 --do_hdd;
375 }
376 }
377
378 /* Wait for our children to exit. */
379 while (children)
380 {
381 int status, ret;
382
383 if ((pid = wait (&status)) > 0)
384 {
385 --children;
386
387 if (WIFEXITED (status))
388 {
389 if ((ret = WEXITSTATUS (status)) == 0)
390 {
391 dbg (stdout, "<-- worker %i returned normally\n", pid);
392 }
393 else
394 {
395 err (stderr, "<-- worker %i returned error %i\n", pid, ret);
396 ++retval;
397 wrn (stderr, "now reaping child worker processes\n");
398 if (signal (SIGUSR1, SIG_IGN) == SIG_ERR)
399 err (stderr, "handler error: %s\n", strerror (errno));
400 if (kill (-1 * getpid (), SIGUSR1) == -1)
401 err (stderr, "kill error: %s\n", strerror (errno));
402 }
403 }
404 else if (WIFSIGNALED (status))
405 {
406 if ((ret = WTERMSIG (status)) == SIGALRM)
407 {
408 dbg (stdout, "<-- worker %i signalled normally\n", pid);
409 }
410 else if ((ret = WTERMSIG (status)) == SIGUSR1)
411 {
412 dbg (stdout, "<-- worker %i reaped\n", pid);
413 }
414 else
415 {
416 err (stderr, "<-- worker %i got signal %i\n", pid, ret);
417 ++retval;
418 wrn (stderr, "now reaping child worker processes\n");
419 if (signal (SIGUSR1, SIG_IGN) == SIG_ERR)
420 err (stderr, "handler error: %s\n", strerror (errno));
421 if (kill (-1 * getpid (), SIGUSR1) == -1)
422 err (stderr, "kill error: %s\n", strerror (errno));
423 }
424 }
425 else
426 {
427 err (stderr, "<-- worker %i exited abnormally\n", pid);
428 ++retval;
429 }
430 }
431 else
432 {
433 err (stderr, "error waiting for worker: %s\n", strerror (errno));
434 ++retval;
435 break;
436 }
437 }
438
439 /* Record our stop time. */
440 if ((stoptime = time (NULL)) == -1)
441 {
442 err (stderr, "failed to acquire current time\n");
443 exit (1);
444 }
445
446 /* Calculate our runtime. */
447 runtime = stoptime - starttime;
448
449 /* Print final status message. */
450 if (retval)
451 {
452 err (stderr, "failed run completed in %lis\n", runtime);
453 }
454 else
455 {
456 out (stdout, "successful run completed in %lis\n", runtime);
457 }
458
459 exit (retval);
460 }
461
462 int
463 hogcpu (void)
464 {
465 while (1)
466 sqrt (rand ());
467
468 return 0;
469 }
470
471 int
472 hogio ()
473 {
474 while (1)
475 sync ();
476
477 return 0;
478 }
479
480 int
481 hogvm (long long bytes, long long stride, long long hang, int keep)
482 {
483 long long i;
484 char *ptr = 0;
485 char c;
486 int do_malloc = 1;
487
488 while (1)
489 {
490 if (do_malloc)
491 {
492 dbg (stdout, "allocating %lli bytes ...\n", bytes);
493 if (!(ptr = (char *) malloc (bytes * sizeof (char))))
494 {
495 err (stderr, "hogvm malloc failed: %s\n", strerror (errno));
496 return 1;
497 }
498 if (keep)
499 do_malloc = 0;
500 }
501
502 dbg (stdout, "touching bytes in strides of %lli bytes ...\n", stride);
503 for (i = 0; i < bytes; i += stride)
504 ptr[i] = 'Z'; /* Ensure that COW happens. */
505
506 if (hang == 0)
507 {
508 dbg (stdout, "sleeping forever with allocated memory\n");
509 while (1)
510 sleep (1024);
511 }
512 else if (hang > 0)
513 {
514 dbg (stdout, "sleeping for %llis with allocated memory\n", hang);
515 sleep (hang);
516 }
517
518 for (i = 0; i < bytes; i += stride)
519 {
520 c = ptr[i];
521 if (c != 'Z')
522 {
523 err (stderr, "memory corruption at: %p\n", ptr + i);
524 return 1;
525 }
526 }
527
528 if (do_malloc)
529 {
530 free (ptr);
531 dbg (stdout, "freed %lli bytes\n", bytes);
532 }
533 }
534
535 return 0;
536 }
537
538 int
539 hoghdd (long long bytes)
540 {
541 long long i, j;
542 int fd;
543 int chunk = (1024 * 1024) - 1; /* Minimize slow writing. */
544 char buff[chunk];
545
546 /* Initialize buffer with some random ASCII data. */
547 dbg (stdout, "seeding %d byte buffer with random data\n", chunk);
548 for (i = 0; i < chunk - 1; i++)
549 {
550 j = rand ();
551 j = (j < 0) ? -j : j;
552 j %= 95;
553 j += 32;
554 buff[i] = j;
555 }
556 buff[i] = '\n';
557
558 while (1)
559 {
560 char name[] = "./stress.XXXXXX";
561
562 if ((fd = mkstemp (name)) == -1)
563 {
564 err (stderr, "mkstemp failed: %s\n", strerror (errno));
565 return 1;
566 }
567
568 dbg (stdout, "opened %s for writing %lli bytes\n", name, bytes);
569
570 dbg (stdout, "unlinking %s\n", name);
571 if (unlink (name) == -1)
572 {
573 err (stderr, "unlink of %s failed: %s\n", name, strerror (errno));
574 return 1;
575 }
576
577 dbg (stdout, "fast writing to %s\n", name);
578 for (j = 0; bytes == 0 || j + chunk < bytes; j += chunk)
579 {
580 if (write (fd, buff, chunk) == -1)
581 {
582 err (stderr, "write failed: %s\n", strerror (errno));
583 return 1;
584 }
585 }
586
587 dbg (stdout, "slow writing to %s\n", name);
588 for (; bytes == 0 || j < bytes - 1; j++)
589 {
590 if (write (fd, &buff[j % chunk], 1) == -1)
591 {
592 err (stderr, "write failed: %s\n", strerror (errno));
593 return 1;
594 }
595 }
596 if (write (fd, "\n", 1) == -1)
597 {
598 err (stderr, "write failed: %s\n", strerror (errno));
599 return 1;
600 }
601 ++j;
602
603 dbg (stdout, "closing %s after %lli bytes\n", name, j);
604 close (fd);
605 }
606
607 return 0;
608 }
609
610 /* Convert a string representation of a number with an optional size suffix
611 * to a long long.
612 */
613 long long
614 atoll_b (const char *nptr)
615 {
616 int pos;
617 char suffix;
618 long long factor = 0;
619 long long value;
620
621 if ((pos = strlen (nptr) - 1) < 0)
622 {
623 err (stderr, "invalid string\n");
624 exit (1);
625 }
626
627 switch (suffix = nptr[pos])
628 {
629 case 'b':
630 case 'B':
631 factor = 0;
632 break;
633 case 'k':
634 case 'K':
635 factor = 10;
636 break;
637 case 'm':
638 case 'M':
639 factor = 20;
640 break;
641 case 'g':
642 case 'G':
643 factor = 30;
644 break;
645 default:
646 if (suffix < '0' || suffix > '9')
647 {
648 err (stderr, "unrecognized suffix: %c\n", suffix);
649 exit (1);
650 }
651 }
652
653 if (sscanf (nptr, "%lli", &value) != 1)
654 {
655 err (stderr, "invalid number: %s\n", nptr);
656 exit (1);
657 }
658
659 value = value << factor;
660
661 return value;
662 }
663
664 /* Convert a string representation of a number with an optional time suffix
665 * to a long long.
666 */
667 long long
668 atoll_s (const char *nptr)
669 {
670 int pos;
671 char suffix;
672 long long factor = 1;
673 long long value;
674
675 if ((pos = strlen (nptr) - 1) < 0)
676 {
677 err (stderr, "invalid string\n");
678 exit (1);
679 }
680
681 switch (suffix = nptr[pos])
682 {
683 case 's':
684 case 'S':
685 factor = 1;
686 break;
687 case 'm':
688 case 'M':
689 factor = 60;
690 break;
691 case 'h':
692 case 'H':
693 factor = 60 * 60;
694 break;
695 case 'd':
696 case 'D':
697 factor = 60 * 60 * 24;
698 break;
699 case 'y':
700 case 'Y':
701 factor = 60 * 60 * 24 * 365;
702 break;
703 default:
704 if (suffix < '0' || suffix > '9')
705 {
706 err (stderr, "unrecognized suffix: %c\n", suffix);
707 exit (1);
708 }
709 }
710
711 if (sscanf (nptr, "%lli", &value) != 1)
712 {
713 err (stderr, "invalid number: %s\n", nptr);
714 exit (1);
715 }
716
717 value = value * factor;
718
719 return value;
720 }
721
722 int
723 version (int status)
724 {
725 char *mesg = "%s %s\n";
726
727 fprintf (stdout, mesg, global_progname, VERSION);
728
729 if (status <= 0)
730 exit (-1 * status);
731
732 return 0;
733 }
734
735 int
736 usage (int status)
737 {
738 char *mesg =
739 "`%s' imposes certain types of compute stress on your system\n\n"
740 "Usage: %s [OPTION [ARG]] ...\n"
741 " -?, --help show this help statement\n"
742 " --version show version statement\n"
743 " -v, --verbose be verbose\n"
744 " -q, --quiet be quiet\n"
745 " -n, --dry-run show what would have been done\n"
746 " -t, --timeout N timeout after N seconds\n"
747 " --backoff N wait factor of N microseconds before work starts\n"
748 " -c, --cpu N spawn N workers spinning on sqrt()\n"
749 " -i, --io N spawn N workers spinning on sync()\n"
750 " -m, --vm N spawn N workers spinning on malloc()/free()\n"
751 " --vm-bytes B malloc B bytes per vm worker (default is 256MB)\n"
752 " --vm-stride B touch a byte every B bytes (default is 4096)\n"
753 " --vm-hang N sleep N secs before free (default none, 0 is inf)\n"
754 " --vm-keep redirty memory instead of freeing and reallocating\n"
755 " -d, --hdd N spawn N workers spinning on write()/unlink()\n"
756 " --hdd-bytes B write B bytes per hdd worker (default is 1GB)\n\n"
757 "Example: %s --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s\n\n"
758 "Note: Numbers may be suffixed with s,m,h,d,y (time) or B,K,M,G (size).\n";
759
760 fprintf (stdout, mesg, global_progname, global_progname, global_progname);
761
762 if (status <= 0)
763 exit (-1 * status);
764
765 return 0;
766 }