int main (int argc, char **argv) { int i, pid, children = 0, retval = 0; long starttime, stoptime, runtime; /* Variables that indicate which options have been selected. */ int do_dryrun = 0; int do_timeout = 0; int do_cpu = 0; /* Default to 1 fork. */ long long do_cpu_forks = 1; int do_io = 0; /* Default to 1 fork. */ long long do_io_forks = 1; int do_vm = 0; /* Default to 1 fork, 1 chunk of 256MB. */ long long do_vm_forks = 1; long long do_vm_chunks = 1; long long do_vm_bytes = 256 * 1024 * 1024; int do_hdd = 0; /* Default to 1 fork, clean, 1 file of 1GB. */ long long do_hdd_forks = 1; int do_hdd_clean = 0; long long do_hdd_files = 1; long long do_hdd_bytes = 1024 * 1024 * 1024; /* Record our start time. */ if ((starttime = time (NULL)) == -1) { err (stderr, "failed to acquire current time\n"); exit (1); } /* SuSv3 does not define any error conditions for this function. */ global_progname = basename (argv[0]); /* For portability, parse command line options without getopt_long. */ for (i = 1; i < argc; i++) { char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-?") == 0) { usage (0); } else if (strcmp (arg, "--version") == 0) { version (0); } else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0) { global_debug = 3; } else if (strcmp (arg, "--quiet") == 0 || strcmp (arg, "-q") == 0) { global_debug = 0; } else if (strcmp (arg, "--dry-run") == 0 || strcmp (arg, "-n") == 0) { do_dryrun = 1; } else if (strcmp (arg, "--no-retry") == 0) { global_ignore = 0; dbg (stdout, "turning off ignore of non-critical errors"); } else if (strcmp (arg, "--retry-delay") == 0) { assert_arg ("--retry-delay"); global_retry = atoll (arg); dbg (stdout, "setting retry delay to %dus\n", global_retry); } else if (strcmp (arg, "--backoff") == 0) { assert_arg ("--backoff"); global_backoff = atoll (arg); if (global_backoff < 0) { err (stderr, "invalid backoff factor: %i\n", global_backoff); exit (1); } dbg (stdout, "setting backoff coeffient to %dus\n", global_backoff); } else if (strcmp (arg, "--timeout") == 0 || strcmp (arg, "-t") == 0) { do_timeout = 1; assert_arg ("--timeout"); global_timeout = atoll_s (arg); dbg (stdout, "setting timeout to %ds\n", global_timeout); } else if (strcmp (arg, "--cpu") == 0 || strcmp (arg, "-c") == 0) { do_cpu = 1; assert_arg ("--cpu"); do_cpu_forks = atoll_b (arg); } else if (strcmp (arg, "--io") == 0 || strcmp (arg, "-i") == 0) { do_io = 1; assert_arg ("--io"); do_io_forks = atoll_b (arg); } else if (strcmp (arg, "--vm") == 0 || strcmp (arg, "-m") == 0) { do_vm = 1; assert_arg ("--vm"); do_vm_forks = atoll_b (arg); } else if (strcmp (arg, "--vm-chunks") == 0) { assert_arg ("--vm-chunks"); do_vm_chunks = atoll_b (arg); } else if (strcmp (arg, "--vm-bytes") == 0) { assert_arg ("--vm-bytes"); do_vm_bytes = atoll_b (arg); } else if (strcmp (arg, "--vm-hang") == 0) { global_vmhang = 1; } else if (strcmp (arg, "--hdd") == 0 || strcmp (arg, "-d") == 0) { do_hdd = 1; assert_arg ("--hdd"); do_hdd_forks = atoll_b (arg); } else if (strcmp (arg, "--hdd-noclean") == 0) { do_hdd_clean = 2; } else if (strcmp (arg, "--hdd-files") == 0) { assert_arg ("--hdd-files"); do_hdd_files = atoll_b (arg); } else if (strcmp (arg, "--hdd-bytes") == 0) { assert_arg ("--hdd-bytes"); do_hdd_bytes = atoll_b (arg); } else { err (stderr, "unrecognized option: %s\n", arg); exit (1); } } /* Hog CPU option. */ if (do_cpu) { out (stdout, "dispatching %lli hogcpu forks\n", do_cpu_forks); switch (pid = fork ()) { case 0: /* child */ if (do_dryrun) exit (0); exit (hogcpu (do_cpu_forks)); case -1: /* error */ err (stderr, "hogcpu dispatcher fork failed\n"); exit (1); default: /* parent */ children++; dbg (stdout, "--> hogcpu dispatcher forked (%i)\n", pid); } } /* Hog I/O option. */ if (do_io) { out (stdout, "dispatching %lli hogio forks\n", do_io_forks); switch (pid = fork ()) { case 0: /* child */ if (do_dryrun) exit (0); exit (hogio (do_io_forks)); case -1: /* error */ err (stderr, "hogio dispatcher fork failed\n"); exit (1); default: /* parent */ children++; dbg (stdout, "--> hogio dispatcher forked (%i)\n", pid); } } /* Hog VM option. */ if (do_vm) { out (stdout, "dispatching %lli hogvm forks, each %lli chunks of %lli bytes\n", do_vm_forks, do_vm_chunks, do_vm_bytes); switch (pid = fork ()) { case 0: /* child */ if (do_dryrun) exit (0); exit (hogvm (do_vm_forks, do_vm_chunks, do_vm_bytes)); case -1: /* error */ err (stderr, "hogvm dispatcher fork failed\n"); exit (1); default: /* parent */ children++; dbg (stdout, "--> hogvm dispatcher forked (%i)\n", pid); } } /* Hog HDD option. */ if (do_hdd) { out (stdout, "dispatching %lli hoghdd forks, each %lli files of " "%lli bytes\n", do_hdd_forks, do_hdd_files, do_hdd_bytes); switch (pid = fork ()) { case 0: /* child */ if (do_dryrun) exit (0); exit (hoghdd (do_hdd_forks, do_hdd_clean, do_hdd_files, do_hdd_bytes)); case -1: /* error */ err (stderr, "hoghdd dispatcher fork failed\n"); exit (1); default: /* parent */ children++; dbg (stdout, "--> hoghdd dispatcher forked (%i)\n", pid); } } /* We have no work to do, so bail out. */ if (children == 0) usage (0); /* Wait for our children to exit. */ while (children) { int status, ret; if ((pid = wait (&status)) > 0) { if ((WIFEXITED (status)) != 0) { if ((ret = WEXITSTATUS (status)) != 0) { err (stderr, "dispatcher %i returned error %i\n", pid, ret); retval += ret; } else { dbg (stdout, "<-- dispatcher return (%i)\n", pid); } } else { err (stderr, "dispatcher did not exit normally\n"); ++retval; } --children; } else { dbg (stdout, "wait() returned error: %s\n", strerror (errno)); err (stderr, "detected missing dispatcher children\n"); ++retval; break; } } /* Record our stop time. */ if ((stoptime = time (NULL)) == -1) { err (stderr, "failed to acquire current time\n"); exit (1); } /* Calculate our runtime. */ runtime = stoptime - starttime; /* Print final status message. */ if (retval) { err (stderr, "failed run completed in %lis\n", runtime); } else { out (stdout, "successful run completed in %lis\n", runtime); } exit (retval); }
int main (int argc, char **argv) { int i, pid, children = 0, retval = 0; long starttime, stoptime, runtime, forks; /* Variables that indicate which options have been selected. */ int do_dryrun = 0; long long do_backoff = 3000; long long do_timeout = 0; long long do_cpu = 0; long long do_io = 0; long long do_vm = 0; long long do_vm_bytes = 256 * 1024 * 1024; long long do_vm_stride = 4096; long long do_vm_hang = -1; int do_vm_keep = 0; long long do_hdd = 0; int do_hdd_clean = 2; long long do_hdd_bytes = 1024 * 1024 * 1024; /* Record our start time. */ if ((starttime = time (NULL)) == -1) { err (stderr, "failed to acquire current time: %s\n", strerror (errno)); exit (1); } /* SuSv3 does not define any error conditions for this function. */ global_progname = basename (argv[0]); /* For portability, parse command line options without getopt_long. */ for (i = 1; i < argc; i++) { char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-?") == 0) { usage (0); } else if (strcmp (arg, "--version") == 0) { version (0); } else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0) { global_debug = 3; } else if (strcmp (arg, "--quiet") == 0 || strcmp (arg, "-q") == 0) { global_debug = 0; } else if (strcmp (arg, "--dry-run") == 0 || strcmp (arg, "-n") == 0) { do_dryrun = 1; } else if (strcmp (arg, "--backoff") == 0) { assert_arg ("--backoff"); if (sscanf (arg, "%lli", &do_backoff) != 1) { err (stderr, "invalid number: %s\n", arg); exit (1); } if (do_backoff < 0) { err (stderr, "invalid backoff factor: %lli\n", do_backoff); exit (1); } dbg (stdout, "setting backoff coeffient to %llius\n", do_backoff); } else if (strcmp (arg, "--timeout") == 0 || strcmp (arg, "-t") == 0) { assert_arg ("--timeout"); do_timeout = atoll_s (arg); if (do_timeout <= 0) { err (stderr, "invalid timeout value: %llis\n", do_timeout); exit (1); } } else if (strcmp (arg, "--cpu") == 0 || strcmp (arg, "-c") == 0) { assert_arg ("--cpu"); do_cpu = atoll_b (arg); if (do_cpu <= 0) { err (stderr, "invalid number of cpu hogs: %lli\n", do_cpu); exit (1); } } else if (strcmp (arg, "--io") == 0 || strcmp (arg, "-i") == 0) { assert_arg ("--io"); do_io = atoll_b (arg); if (do_io <= 0) { err (stderr, "invalid number of io hogs: %lli\n", do_io); exit (1); } } else if (strcmp (arg, "--vm") == 0 || strcmp (arg, "-m") == 0) { assert_arg ("--vm"); do_vm = atoll_b (arg); if (do_vm <= 0) { err (stderr, "invalid number of vm hogs: %lli\n", do_vm); exit (1); } } else if (strcmp (arg, "--vm-bytes") == 0) { assert_arg ("--vm-bytes"); do_vm_bytes = atoll_b (arg); if (do_vm_bytes <= 0) { err (stderr, "invalid vm byte value: %lli\n", do_vm_bytes); exit (1); } } else if (strcmp (arg, "--vm-stride") == 0) { assert_arg ("--vm-stride"); do_vm_stride = atoll_b (arg); if (do_vm_stride <= 0) { err (stderr, "invalid stride value: %lli\n", do_vm_stride); exit (1); } } else if (strcmp (arg, "--vm-hang") == 0) { assert_arg ("--vm-hang"); do_vm_hang = atoll_b (arg); if (do_vm_hang < 0) { err (stderr, "invalid value: %lli\n", do_vm_hang); exit (1); } } else if (strcmp (arg, "--vm-keep") == 0) { do_vm_keep = 1; } else if (strcmp (arg, "--hdd") == 0 || strcmp (arg, "-d") == 0) { assert_arg ("--hdd"); do_hdd = atoll_b (arg); if (do_hdd <= 0) { err (stderr, "invalid number of hdd hogs: %lli\n", do_hdd); exit (1); } } else if (strcmp (arg, "--hdd-noclean") == 0) { do_hdd_clean = 0; } else if (strcmp (arg, "--hdd-bytes") == 0) { assert_arg ("--hdd-bytes"); do_hdd_bytes = atoll_b (arg); if (do_hdd_bytes <= 0) { err (stderr, "invalid hdd byte value: %lli\n", do_hdd_bytes); exit (1); } } else { err (stderr, "unrecognized option: %s\n", arg); exit (1); } } /* Print startup message if we have work to do, bail otherwise. */ if (do_cpu + do_io + do_vm + do_hdd) { out (stdout, "dispatching hogs: %lli cpu, %lli io, %lli vm, %lli hdd\n", do_cpu, do_io, do_vm, do_hdd); } else usage (0); /* Round robin dispatch our worker processes. */ while ((forks = (do_cpu + do_io + do_vm + do_hdd))) { long long backoff, timeout = 0; /* Calculate the backoff value so we get good fork throughput. */ backoff = do_backoff * forks; dbg (stdout, "using backoff sleep of %llius\n", backoff); /* If we are supposed to respect a timeout, calculate it. */ if (do_timeout) { long long currenttime; /* Acquire current time. */ if ((currenttime = time (NULL)) == -1) { perror ("error acquiring current time"); exit (1); } /* Calculate timeout based on current time. */ timeout = do_timeout - (currenttime - starttime); if (timeout > 0) { dbg (stdout, "setting timeout to %llis\n", timeout); } else { wrn (stderr, "used up time before all workers dispatched\n"); break; } } if (do_cpu) { switch (pid = fork ()) { case 0: /* child */ alarm (timeout); usleep (backoff); if (do_dryrun) exit (0); exit (hogcpu ()); case -1: /* error */ err (stderr, "fork failed: %s\n", strerror (errno)); break; default: /* parent */ dbg (stdout, "--> hogcpu worker %lli [%i] forked\n", do_cpu, pid); ++children; } --do_cpu; } if (do_io) { switch (pid = fork ()) { case 0: /* child */ alarm (timeout); usleep (backoff); if (do_dryrun) exit (0); exit (hogio ()); case -1: /* error */ err (stderr, "fork failed: %s\n", strerror (errno)); break; default: /* parent */ dbg (stdout, "--> hogio worker %lli [%i] forked\n", do_io, pid); ++children; } --do_io; } if (do_vm) { switch (pid = fork ()) { case 0: /* child */ alarm (timeout); usleep (backoff); if (do_dryrun) exit (0); exit (hogvm (do_vm_bytes, do_vm_stride, do_vm_hang, do_vm_keep)); case -1: /* error */ err (stderr, "fork failed: %s\n", strerror (errno)); break; default: /* parent */ dbg (stdout, "--> hogvm worker %lli [%i] forked\n", do_vm, pid); ++children; } --do_vm; } if (do_hdd) { switch (pid = fork ()) { case 0: /* child */ alarm (timeout); usleep (backoff); if (do_dryrun) exit (0); exit (hoghdd (do_hdd_bytes, do_hdd_clean)); case -1: /* error */ err (stderr, "fork failed: %s\n", strerror (errno)); break; default: /* parent */ dbg (stdout, "--> hoghdd worker %lli [%i] forked\n", do_hdd, pid); ++children; } --do_hdd; } } /* Wait for our children to exit. */ while (children) { int status, ret; if ((pid = wait (&status)) > 0) { --children; if (WIFEXITED (status)) { if ((ret = WEXITSTATUS (status)) == 0) { dbg (stdout, "<-- worker %i returned normally\n", pid); } else { err (stderr, "<-- worker %i returned error %i\n", pid, ret); ++retval; wrn (stderr, "now reaping child worker processes\n"); if (signal (SIGUSR1, SIG_IGN) == SIG_ERR) err (stderr, "handler error: %s\n", strerror (errno)); if (kill (-1 * getpid (), SIGUSR1) == -1) err (stderr, "kill error: %s\n", strerror (errno)); } } else if (WIFSIGNALED (status)) { if ((ret = WTERMSIG (status)) == SIGALRM) { dbg (stdout, "<-- worker %i signalled normally\n", pid); } else if ((ret = WTERMSIG (status)) == SIGUSR1) { dbg (stdout, "<-- worker %i reaped\n", pid); } else { err (stderr, "<-- worker %i got signal %i\n", pid, ret); ++retval; wrn (stderr, "now reaping child worker processes\n"); if (signal (SIGUSR1, SIG_IGN) == SIG_ERR) err (stderr, "handler error: %s\n", strerror (errno)); if (kill (-1 * getpid (), SIGUSR1) == -1) err (stderr, "kill error: %s\n", strerror (errno)); } } else { err (stderr, "<-- worker %i exited abnormally\n", pid); ++retval; } } else { err (stderr, "error waiting for worker: %s\n", strerror (errno)); ++retval; break; } } /* Record our stop time. */ if ((stoptime = time (NULL)) == -1) { err (stderr, "failed to acquire current time\n"); exit (1); } /* Calculate our runtime. */ runtime = stoptime - starttime; /* Print final status message. */ if (retval) { err (stderr, "failed run completed in %lis\n", runtime); } else { out (stdout, "successful run completed in %lis\n", runtime); } exit (retval); }