(root)/
binutils-2.41/
gprofng/
testsuite/
gprofng.display/
synprog/
synprog.c
       1  /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
       2     Contributed by Oracle.
       3  
       4     This file is part of GNU Binutils.
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  /* synprog.c - synthetic program to use for testing performance tools */
      22  #define _GNU_SOURCE
      23  #include <sched.h>
      24  #include <sys/types.h>
      25  #include <sys/param.h>
      26  #include <sys/wait.h>
      27  #include <sys/ucontext.h>
      28  #include <stdlib.h>
      29  #include <stdio.h>
      30  #include <errno.h>
      31  #include <signal.h>
      32  #include <unistd.h>
      33  #include <sched.h>
      34  #include <sys/resource.h>
      35  #include <string.h>
      36  #include <sys/mman.h>
      37  #include <dlfcn.h>
      38  #include <fcntl.h>
      39  #include "stopwatch.h"
      40  
      41  int get_ncpus ();
      42  int get_clock_rate ();
      43  void acct_init (char *);        /* initialize accounting */
      44  void iotrace_init (char *);     /* initialize IO trace accounting */
      45  void commandline (char *);      /* routine execute a scenario */
      46  void forkcopy (char *, int);    /* fork copy of self to run string */
      47  int clonecopy (void *);
      48  #define CLONE_STACK_SIZE    8388608
      49  #define CLONE_TLS_SIZE      4096
      50  #define CLONE_RED_SIZE      4096
      51  #define CLONE_IO            0x80000000      /* Clone io context */
      52  void forkchild (char *);    /* fork child to run string */
      53  void reapchildren (void);   /* reap all children */
      54  void reapchild (int);       /* reap a child after getting SIGCLD */
      55  void check_sigmask ();      /* check that SIGPROF and SIGEMT are not masked */
      56  void masksig ();            /* real code to mask SIGPROF and SIGEMT */
      57  
      58  hrtime_t progstart;
      59  hrtime_t progvstart;
      60  hrtime_t gethrustime ();
      61  static int include_system_time = 0;
      62  
      63  static hrtime_t
      64  getmyvtime ()
      65  {
      66    if (include_system_time == 0)
      67      return gethrvtime ();
      68    return gethrustime ();
      69  }
      70  
      71  void (*sigset (int sig, void (*disp)(int)))(int);
      72  #define ITIMER_REALPROF ITIMER_REAL
      73  /* Linux needs to have this defined for RTLD_NEXT and RTLD_DEFAULT */
      74  /* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT */
      75  #define RTLD_NEXT      ((void *) -1l)
      76  /* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT */
      77  #define RTLD_DEFAULT   ((void *) 0)
      78  
      79  FILE *fid;
      80  FILE *fid2;
      81  double testtime = 3.0;
      82  static char acct_file[128];
      83  static char new_name[128];
      84  static char child_name[128];
      85  
      86  /* descendant process tracking */
      87  static unsigned syn_fork = 0;
      88  static unsigned syn_exec = 0;
      89  static unsigned syn_combo = 0;
      90  
      91  /* various behavior routines */
      92  int bounce (int);       /* bounce with a->b->a->b-> ... */
      93  int callso (int);       /* so load test */
      94  int callsx (int);       /* alternate so load test */
      95  int correlate (int);    /* test correlation with profiling */
      96  int cputime (int);      /* use a bunch of user cpu time (fp) */
      97  int doabort (int);      /* force a SEGV by dereferencing NULL */
      98  int dousleep (int);     /* loop with a usleep call */
      99  int endcases (int);     /* test various code construct endcases */
     100  int fitos (int);        /* test various code construct endcases */
     101  int gpf (int);          /* show gprof fallacy */
     102  int hrv (int);          /* gethrvtime calls */
     103  int icputime (int);     /* use a bunch of user cpu time (long) */
     104  int iofile (int);       /* do operations on a temporary file */
     105  int iotest (int);       /* do various io system calls */
     106  int ioerror (int);      /* do various erroneous io system calls */
     107  int ldso (int);         /* use a bunch of time in ld.so */
     108  int masksignals (int);  /* mask the SIGEMT and SIGPROF signals */
     109  int memorymap (int);    /* do mmap operation for io tracing */
     110  int muldiv (int);       /* do integer multiply/divide for a time */
     111  int naptime (int);      /* sleep for a time */
     112  int pagethrash (int);   /* thrash around in memory */
     113  int recurse (int);      /* recursion test */
     114  int recursedeep (int);  /* deep recursion test */
     115  int sched (int);        /* loop over sched_yield calls */
     116  int sigtime (int);      /* use a bunch of time in a signal handler */
     117  int synccall (int);     /* loop over sync() system calls */
     118  int systime (int);      /* use a bunch of system time */
     119  int tailcallopt (int);  /* tail call optimization test */
     120  int underflow (int);    /* force underflow arithmetic */
     121  int unwindcases (int);  /* test various unwind corner cases */
     122  
     123  int itimer_realprof (int); /* mess with itimer ITIMER_REALPROF */
     124  int sigprof (int);      /* mess with SIGPROF sigaction */
     125  int sigprofh (int);     /* mess with SIGPROF handler */
     126  int do_chdir (int);     /* do a chdir() */
     127  int do_exec (int);      /* do an exec() call */
     128  int do_popen (int);     /* do a popen() call */
     129  int do_system (int);    /* do a system() call */
     130  int do_forkexec (int);  /* do a fork()+exec() call combo */
     131  int
     132  do_vforkexec (int);     /* do a vfork()+exec() call combo */
     133  
     134  /* lookup table for behavior scripts */
     135  struct scripttab
     136  {
     137    char *name;
     138    int (*function)(int);
     139    char *acctname;
     140    int param;
     141    int noverify;
     142  };
     143  
     144  static int CLONE_FLAGS[] = {
     145    SIGCHLD,
     146    CLONE_FILES | CLONE_FS | CLONE_SYSVSEM | CLONE_IO | SIGCHLD
     147  };
     148  
     149  /* the default script */
     150  static char DEFAULT_COMMAND[] =
     151          "icpu.md.cpu.rec.recd.dousl.gpf.fitos.ec.tco.b.nap.uf."
     152          "sys.sig.so.sx.so.sched";
     153  
     154  struct scripttab scripttab[] = {
     155    {"abt",       doabort,        "doabort",      0,  0},
     156    {"b",         bounce,         "bounce",       0,  0},
     157    {"c",         correlate,      "correlate",    0,  0},
     158    {"chdir",     do_chdir,       "chdir",        0,  0},
     159    {"chdirX",    do_chdir,       "chdir",        -1, 0},
     160    {"cpu",       cputime,        "cputime",      0,  0},
     161    {"dousl",     dousleep,       "dousleep",     0,  1},
     162    {"ec",        endcases,       "endcases",     0,  0},
     163    {"exec",      do_exec,        "exec",         0,  0},
     164    {"execX",     do_exec,        "do_exec",      -1, 0},
     165    {"fitos",     fitos,          "fitos",        0,  1},
     166    {"gpf",       gpf,            "gpf",          0,  0},
     167    {"hrv",       hrv,            "hrv",          0,  0},
     168    {"icpu",      icputime,       "icputime",     0,  0},
     169    {"iofile",    iofile,         "iofile",       0,  0},
     170    {"iotest",    iotest,         "iotest",       0,  0},
     171    {"ioerror",   ioerror,        "ioerror",      0,  0},
     172    {"itimer",    itimer_realprof, "itimer",      1,  0},
     173    {"itimer0",   itimer_realprof, "itimer",      0,  0},
     174    {"ldso",      ldso,           "ldso",         0,  0},
     175    {"masksig",   masksignals,    "masksig",      0,  0},
     176    {"md",        muldiv,         "muldiv",       0,  0},
     177    {"memorymap", memorymap,      "memorymap",    100, 0},
     178    {"nap",       naptime,        "naptime",      0,  0},
     179    {"pg",        pagethrash,     "pagethrash",   32, 0},
     180    {"popen",     do_popen,       "popen",        0,  0},
     181    {"popenX",    do_popen,       "popen",        -1, 0},
     182    {"rec",       recurse,        "recurse",      50, 0},
     183    {"recd",      recursedeep,    "<Truncated-stack>", 500, 0},
     184    {"sched",     sched,          "sched",        0,  1},
     185    {"so",        callso,         "callso",       0,  0},
     186    {"sx",        callsx,         "callsx",       0,  0},
     187    {"sig",       sigtime,        "sigtime_handler", 0,  1},
     188    {"sigprof",   sigprof,        "sigprof",      1,  0},
     189    {"sigprof0",  sigprof,        "sigprof",      0,  0},
     190    {"sigprofh",  sigprofh,       "sigprofh",     1,  0},
     191    {"sigprofh0", sigprofh,       "sigprofh",     0,  0},
     192    {"sync",      synccall,       "synccall",     0,  1},
     193    {"sys",       systime,        "systime",      0,  1},
     194    {"system",    do_system,      "system",       0,  0},
     195    {"systemX",   do_system,      "do_system",    -1, 0},
     196    {"tco",       tailcallopt,    "tailcallopt",  0,  0},
     197    {"uf",        underflow,      "underflow",    0,  1},
     198    {"forkexec",  do_forkexec,    "forkexec",     0,  0},
     199    {"vforkexec", do_vforkexec,   "vforkexec",    0,  0},
     200    {"uwdc",      unwindcases,    "unwindcases_handler", 0,  0},
     201    {NULL, NULL, NULL, 0, 0}
     202  };
     203  
     204  int
     205  main (int argc, char **argv)
     206  {
     207    int i;
     208    hrtime_t start;
     209    hrtime_t vstart;
     210    char *name;
     211    char buf[1024];
     212    char arglist[4096];
     213  
     214    // need a more robust test of whether system HWC events are being counted
     215    if (getenv ("TILDECLAUSE"))
     216      include_system_time = 1;
     217    progstart = gethrtime ();
     218    progvstart = getmyvtime ();
     219    name = getenv ("SP_COLLECTOR_TEST_TIMER");
     220    if (name)
     221      {
     222        testtime = atof (name);
     223        if (testtime <= 0)
     224          testtime = 1.0;
     225      }
     226    name = getenv ("_SP_NAME");
     227    if (name == NULL || strlen (name) == 0)
     228      strcpy (acct_file, "synprog.acct");
     229    else
     230      strcpy (acct_file, name);
     231  
     232    strcpy (arglist, argv[0]);
     233    for (i = 1; i < argc; i++)
     234      {
     235        strcat (arglist, " ");
     236        strcat (arglist, argv[i]);
     237      }
     238  
     239    sprintf (buf, "%s run", argv[0]);
     240    wlog (buf, NULL);
     241  
     242    int ncpus = get_ncpus ();
     243    acct_init (acct_file);
     244    iotrace_init ("synprog.acct2");
     245  
     246    /* Start a timer */
     247    start = gethrtime ();
     248    vstart = getmyvtime ();
     249  
     250  #ifndef NO_MS_ACCT
     251    stpwtch_calibrate ();
     252  #endif
     253  
     254    if (argc == 1)
     255      commandline (DEFAULT_COMMAND);
     256    else
     257      {
     258        i = 2;
     259        while (i < argc)
     260          {
     261            forkcopy (argv[i], i - 1);
     262            i++;
     263          }
     264  
     265        /* do the last one ourself */
     266        commandline (argv[1]);
     267      }
     268    reapchildren ();
     269    whrvlog (gethrtime () - start, getmyvtime () - vstart, buf, NULL);
     270    fflush (fid);
     271    fflush (fid2);
     272    fclose (fid);
     273    fclose (fid2);
     274    return 0;
     275  }
     276  
     277  /* acct_init: initialize accounting */
     278  void
     279  acct_init (char *acct_file)
     280  {
     281    fid = fopen (acct_file, "w");
     282    if (fid == NULL)
     283      {
     284        fprintf (stderr, "Open of %s for output failed: %s\n",
     285                 acct_file, strerror (errno));
     286        exit (1);
     287      }
     288    fprintf (fid, "MHz: %d\n", get_clock_rate ());
     289    fprintf (fid, "X   Incl. Total  Incl. CPU  Name\n");
     290    fflush (fid);
     291  
     292    /* write a record for <Unknown>, which should have zero times */
     293    fprintf (fid, "X   %6.3f        %6.3f       %s\n", 0.0, 0.0, "<Unknown>");
     294  
     295    /* set up to reap any children */
     296    (void) sigset (SIGCHLD, reapchild);
     297    /* verify the signal mask */
     298  }
     299  
     300  /* iotrace_init: initialize IO trace accounting */
     301  void
     302  iotrace_init (char *acct_file)
     303  {
     304    fid2 = fopen (acct_file, "w");
     305    if (fid2 == NULL)
     306      {
     307        fprintf (stderr, "Open of %s for output failed: %s\n",
     308                 acct_file, strerror (errno));
     309        exit (1);
     310      }
     311    fprintf (fid2, "X   Incl.BytesRead  Incl.ReadCount  ");
     312    fprintf (fid2, "Incl.BytesWritten  Incl.WriteCount  ");
     313    fprintf (fid2, "Incl.OtherIOCount   Name\n");
     314    fflush (fid2);
     315  }
     316  
     317  /* commandline -- process a command line string:
     318   *	verbs are separated by a . character; each verb is looked-up
     319   *	in a table, and the routine to process it, and argument fetched.
     320   *	the routine is called.
     321   */
     322  void
     323  commandline (char *cmdline)
     324  {
     325    char *p;
     326    char *j;
     327    char prevj;
     328    struct scripttab *k;
     329    char buf[1024];
     330    hrtime_t pstart;
     331    hrtime_t pvstart;
     332    hrtime_t pend;
     333    hrtime_t pvend;
     334    hrtime_t start = gethrtime ();
     335    hrtime_t vstart = getmyvtime ();
     336  
     337    /* Log the event */
     338    wlog (" Begin commandline", cmdline);
     339  
     340    p = cmdline;
     341    while (*p != 0)
     342      {
     343        /* find the terminator for this verb (a . or NULL) */
     344        j = p;
     345        while (*j != 0 && *j != '.')
     346          j++;
     347        prevj = *j;
     348        *j = 0;
     349  
     350        /* now look up the phase in the table */
     351        for (k = &scripttab[0];; k++)
     352          {
     353            if (k->name == NULL)
     354              break;
     355            if (strcmp (p, k->name) == 0)
     356              {
     357                /* found a match */
     358                pstart = gethrtime ();
     359                pvstart = getmyvtime ();
     360                (k->function)(k->param);
     361                pend = gethrtime ();
     362                pvend = getmyvtime ();
     363                fprintf (fid, "%c   %6.3f        %6.3f       %s\n",
     364                         k->noverify == 0 ? 'X' : 'Y',
     365                         (double) (pend - pstart) / (double) 1000000000.,
     366                         (double) (pvend - pvstart) / (double) 1000000000.,
     367                         k->acctname);
     368                fflush (fid);
     369                break;
     370              }
     371          }
     372        if (k->name == NULL)
     373          {
     374            sprintf (buf, "++ ignoring `%s'\n", p);
     375            fprintf (stderr, buf);
     376          }
     377  
     378        /* continue processing */
     379        *j = prevj;
     380        p = j;
     381        if (prevj != 0)
     382          p++;
     383      }
     384    whrvlog (gethrtime () - start, getmyvtime () - vstart, "commandline", cmdline);
     385  }
     386  
     387  int
     388  clonecopy (void * script)
     389  {
     390    syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
     391  
     392    strcpy (acct_file, child_name);
     393    /*printf("_SP_NAME=\"%s\" (for clone-child)\n", acct_file);*/
     394    acct_init (acct_file);
     395  
     396    /* execute the script */
     397    commandline ((char *) script);
     398  
     399    /* reap the child's descendants */
     400    reapchild (0);
     401    exit (0);
     402  }
     403  
     404  /* forkcopy -- fork a copy to run a script */
     405  void
     406  forkcopy (char *script, int child)
     407  {
     408    int child_pid;
     409    if (strncmp ("clone", script, 5) == 0)
     410      {
     411        //clone instead of fork
     412        /* Log the event */
     413        wlog ("cloning copy ... ", script);
     414  
     415        sprintf (child_name, "%s_C%d", acct_file, ++syn_fork);
     416        /* clone a new process */
     417        void * stack;
     418        void * stack_space;
     419        int stack_size = CLONE_STACK_SIZE;
     420  
     421        stack_space = mmap (NULL, stack_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS, -1, 0);
     422        if ((void*) - 1 == stack_space)
     423          {
     424            fprintf (stderr, "Error: mmap returned -1\n");
     425            exit (1);
     426          }
     427        mprotect (stack_space, CLONE_RED_SIZE, PROT_NONE);
     428        stack = (char *) stack_space + stack_size - CLONE_TLS_SIZE; // stack grows back
     429        child_pid = clone (clonecopy, stack, CLONE_FLAGS[(child + 1) % 2],
     430                           (void *) (script + sizeof ("clone") - 1));
     431        if (child_pid < 0)
     432          {
     433            /* error, could not fork */
     434            fprintf (stderr, "forkcopy: clone failed--error %d\n", errno);
     435            exit (1);
     436          }
     437  
     438        fprintf (stderr, "child process %d cloned by %d.\n",
     439                 child_pid, (int) getpid ());
     440        return;
     441      }
     442  
     443    /* Log the event */
     444    wlog ("forking copy ... ", script);
     445    sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
     446  
     447    /* fork a new process */
     448    child_pid = fork ();
     449    if (child_pid < 0)
     450      {
     451        /* error, could not fork */
     452        fprintf (stderr, "forkcopy: fork failed--error %d\n", errno);
     453        exit (1);
     454  
     455      }
     456    else if (child_pid == 0)
     457      {
     458        syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
     459        strcpy (acct_file, child_name);
     460        acct_init (acct_file);
     461  
     462        /* execute the script */
     463        commandline (script);
     464  
     465        /* reap the child's descendants */
     466        reapchild (0);
     467        exit (0);
     468      }
     469    fprintf (stderr, "child process %d forked by %d.\n",
     470             child_pid, (int) getpid ());
     471  }
     472  
     473  void
     474  forkchild (char * cmdline)
     475  {
     476    stopwatch_t *prog;
     477    char mbuf[1024];
     478  
     479    /* Start a stopwatch */
     480    sprintf (mbuf, "%s pid[%d]", "Synprog child", (int) getpid ());
     481    prog = stpwtch_alloc (mbuf, 0);
     482  
     483    /* process this child's command-line */
     484    commandline (cmdline);
     485  
     486    /* reap the child's descendants */
     487    reapchild (0);
     488  
     489    /* Stop print, and free the stopwatch */
     490    stpwtch_stop (prog);
     491    stpwtch_print (prog);
     492    free (prog);
     493  
     494    exit (0);
     495  }
     496  
     497  /* reap a child process, called in response to SIGCLD */
     498  void
     499  reapchild (int sig)
     500  {
     501    int status;
     502    int ret = wait (&status);
     503    sigset (SIGCLD, reapchild);
     504  }
     505  
     506  /* reap all child processes prior to exit */
     507  void
     508  reapchildren ()
     509  {
     510    int status;
     511    int ret;
     512  
     513    /* wait for all children to exit */
     514    for (;;)
     515      {
     516        while ((ret = wait (&status)) != (pid_t) - 1)
     517          fprintf (stderr, "synprog: reap child %x\n", ret);
     518        if (errno == EINTR)
     519          continue;
     520        if (errno == ECHILD)
     521          return;
     522        fprintf (stderr, "synprog: unexpected errno from wait() syscall -- %s\n",
     523                 strerror (errno));
     524      }
     525  }
     526  
     527  /* doabort -- force a SEGV */
     528  int
     529  doabort (int k)
     530  {
     531    char *nullptr = NULL;
     532    char c;
     533  
     534    /* Log the event */
     535    wlog ("start of doabort", NULL);
     536  
     537    /* and dereference a NULL */
     538    c = *nullptr;
     539  
     540    /* this should never be reached */
     541    return (int) c;
     542  }
     543  
     544  /* =============================================================== */
     545  
     546  /*	dousleep -- loop with a usleep */
     547  int
     548  dousleep (int k)
     549  {
     550    volatile double x;
     551    long long count = 0;
     552    hrtime_t start = gethrtime ();
     553    hrtime_t vstart = getmyvtime ();
     554  
     555    /* Log the event */
     556    wlog ("start of dousleep", NULL);
     557    do
     558      {
     559        x = 0.0;
     560        for (int j = 0; j < 1000000; j++)
     561          x = x + 1.0;
     562        count++;
     563      }
     564    while (start + testtime * 1e9 > gethrtime ());
     565  
     566    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     567    whrvlog (gethrtime () - start, getmyvtime () - vstart, "dousleep", NULL);
     568    /* this should never be reached */
     569    return (int) 0;
     570  }
     571  
     572  /* =============================================================== */
     573  /*	correlate -- generate CPU use, correlated with profiling clock */
     574  
     575  static void csig_handler (int);
     576  
     577  int
     578  correlate (int k)
     579  {
     580    volatile float x; /* temp variable for f.p. calculation */
     581    struct itimerval tval;
     582    int retval;
     583    long long count = 0;
     584    hrtime_t start = gethrtime ();
     585    hrtime_t vstart = getmyvtime ();
     586  
     587    /* Log the event */
     588    wlog ("start of correlate", NULL);
     589  
     590    /* set up the signal handler */
     591    sigset (SIGALRM, csig_handler);
     592  
     593    /* set an itimer, to break out of the sleep loop */
     594    tval.it_value.tv_sec = 0;
     595    tval.it_value.tv_usec = 10000;
     596    tval.it_interval.tv_sec = 0;
     597    tval.it_interval.tv_usec = 10000;
     598  
     599    retval = setitimer (ITIMER_REAL, &tval, 0);
     600    if (retval != 0)
     601      fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
     602               retval, strerror (errno));
     603    do
     604      {
     605        x = 0.0;
     606        for (int j = 0; j < 1000000; j++)
     607          x = x + 1.0;
     608        sleep (1); /* relying on the timer to break out */
     609        count++;
     610      }
     611    while (start + testtime * 1e9 > gethrtime ());
     612  
     613    /* now disable the itimer */
     614    tval.it_value.tv_sec = 0;
     615    tval.it_value.tv_usec = 0;
     616    tval.it_interval.tv_sec = 0;
     617    tval.it_interval.tv_usec = 0;
     618  
     619    retval = setitimer (ITIMER_REAL, &tval, 0);
     620    if (retval != 0)
     621      fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
     622               retval, strerror (errno));
     623    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     624    whrvlog (gethrtime () - start, getmyvtime () - vstart, "correlate", NULL);
     625    return 0;
     626  }
     627  
     628  static void
     629  csig_handler (int sig)
     630  {
     631    return;
     632  }
     633  
     634  /* cputime -- loop to use a bunch of user time (f.p.) */
     635  int
     636  cputime (int k)
     637  {
     638    volatile float x; /* temp variable for f.p. calculation */
     639    long long count = 0;
     640    hrtime_t start = gethrtime ();
     641    hrtime_t vstart = getmyvtime ();
     642  
     643    /* Log the event */
     644    wlog ("start of cputime", NULL);
     645    do
     646      {
     647        x = 0.0;
     648        for (int j = 0; j < 1000000; j++)
     649          x = x + 1.0;
     650        count++;
     651      }
     652    while (start + testtime * 1e9 > gethrtime ());
     653  
     654    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     655    whrvlog (gethrtime () - start, getmyvtime () - vstart, "cputime", NULL);
     656    return 0;
     657  }
     658  
     659  /* icputime -- loop to use a bunch of user time (long) */
     660  int
     661  icputime (int k)
     662  {
     663    volatile long x; /* temp variable for long calculation */
     664    long long count = 0;
     665    hrtime_t start = gethrtime ();
     666    hrtime_t vstart = getmyvtime ();
     667  
     668    /* Log the event */
     669    wlog ("start of icputime", NULL);
     670    do
     671      {
     672        x = 0;
     673        for (int j = 0; j < 1000000; j++)
     674          x = x + 1;
     675        count++;
     676      }
     677    while (start + testtime * 1e9 > gethrtime ());
     678  
     679    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     680    whrvlog (gethrtime () - start, getmyvtime () - vstart, "icputime", NULL);
     681    return 0;
     682  }
     683  
     684  /* hrv -- loop to do lots of gethrvtime calls */
     685  int
     686  hrv (int k)
     687  {
     688    long long count = 0;
     689    hrtime_t start = gethrtime ();
     690    hrtime_t vstart = getmyvtime ();
     691  
     692    /* Log the event */
     693    wlog ("start of hrv", NULL);
     694    do
     695      {
     696        for (int j = 0; j < 10000; j++)
     697          (void) gethrvtime ();
     698        count++;
     699      }
     700    while (start + testtime * 1e9 > gethrtime ());
     701  
     702    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     703    whrvlog (gethrtime () - start, getmyvtime () - vstart, "hrv", NULL);
     704    return 0;
     705  }
     706  
     707  /* =============================================================== */
     708  
     709  /*	ldso -- use up time in ld.so */
     710  
     711  int
     712  ldso (int k)
     713  {
     714    long long count = 0;
     715    hrtime_t start = gethrtime ();
     716    hrtime_t vstart = getmyvtime ();
     717  
     718    /* Log the event */
     719    wlog ("start of ldso", NULL);
     720    do
     721      {
     722        for (int j = 0; j < 10000; j++)
     723          (void) dlsym (RTLD_DEFAULT, "nosuchfoo");
     724        count++;
     725      }
     726    while (start + testtime * 1e9 > gethrtime ());
     727    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     728    whrvlog (gethrtime () - start, getmyvtime () - vstart, "ldso", NULL);
     729    return 0;
     730  }
     731  
     732  /* masksignals -- debug aid -- call routine to mask SIGPROF and SIGEMT */
     733  int
     734  masksignals (int n)
     735  {
     736    hrtime_t start = gethrtime ();
     737    hrtime_t vstart = getmyvtime ();
     738  
     739    /* Log the event */
     740    whrvlog (gethrtime () - start, getmyvtime () - vstart, "masksignals", NULL);
     741    return 0;
     742  }
     743  
     744  /* =============================================================== */
     745  /*	muldiv -- loop to do a bunch of integer multiply and divide */
     746  
     747  volatile int tmp_ival = 0;
     748  
     749  int
     750  muldiv (int n)
     751  {
     752    long long count = 0;
     753    hrtime_t start = gethrtime ();
     754    hrtime_t vstart = getmyvtime ();
     755  
     756    /* Log the event */
     757    wlog ("start of muldiv", NULL);
     758    do
     759      {
     760        for (int i = 0; i < 1000; i++)
     761          {
     762            for (int j = 0; j < 1000; j++)
     763              tmp_ival = j * i / (i + 1.0);
     764          }
     765        count++;
     766      }
     767    while (start + testtime * 1e9 > gethrtime ());
     768    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     769    whrvlog (gethrtime () - start, getmyvtime () - vstart, "muldiv", NULL);
     770    return 0;
     771  }
     772  
     773  
     774  /* =============================================================== */
     775  /*	underflow -- loop triggering arithmetic underflow */
     776  volatile float tmp_fval;
     777  
     778  int
     779  underflow (int k)
     780  {
     781    float x, y;
     782    long long count = 0;
     783  
     784    hrtime_t start = gethrtime ();
     785    hrtime_t vstart = getmyvtime ();
     786  
     787    /* Log the event */
     788    wlog ("start of underflow", NULL);
     789    do
     790      {
     791        x = 1.e-20;
     792        y = 1.e-20;
     793        for (int j = 0; j < 50000; j++)
     794          tmp_fval = x * y;
     795        count++;
     796      }
     797    while (start + testtime * 1e9 > gethrtime ());
     798    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     799    whrvlog (gethrtime () - start, getmyvtime () - vstart, "underflow", NULL);
     800    return 0;
     801  }
     802  
     803  /* naptime -- spend time in the system sleeping */
     804  int
     805  naptime (int k)
     806  {
     807    hrtime_t start = gethrtime ();
     808    hrtime_t vstart = getmyvtime ();
     809  
     810    /* Log the event */
     811    wlog ("start of naptime", NULL);
     812    if (k == 0)
     813      {
     814        k = testtime;
     815        if (k < 1)
     816          k = 1;
     817      }
     818    for (int i = 0; i < k; i++)
     819      sleep (1);
     820    whrvlog (gethrtime () - start, getmyvtime () - vstart, "naptime", NULL);
     821    return 0;
     822  }
     823  
     824  /* recurse -- loop to show recursion */
     825  int real_recurse (int, int); /* real routine to do recursion */
     826  
     827  int
     828  recurse (int k)
     829  {
     830    hrtime_t start = gethrtime ();
     831    hrtime_t vstart = getmyvtime ();
     832  
     833    /* Log the event */
     834    wlog ("start of recurse", NULL);
     835    if (k == 0)
     836      k = 80;
     837    (void) real_recurse (0, k);
     838    whrvlog (gethrtime () - start, getmyvtime () - vstart, "recurse", NULL);
     839    return 0;
     840  }
     841  
     842  int
     843  recursedeep (int k)
     844  {
     845    hrtime_t start = gethrtime ();
     846    hrtime_t vstart = getmyvtime ();
     847  
     848    /* Log the event */
     849    wlog ("start of recursedeep", NULL);
     850    if (k == 0)
     851      k = 500;
     852    (void) real_recurse (0, k);
     853    whrvlog (gethrtime () - start, getmyvtime () - vstart, "recursedeep", NULL);
     854    return 0;
     855  }
     856  
     857  static int rec_count = 0;
     858  
     859  int
     860  real_recurse (int i, int imax)
     861  {
     862    if (i == imax)
     863      {
     864        volatile float x;
     865        long long count = 0;
     866        hrtime_t start = gethrtime ();
     867        do
     868          {
     869            x = 0.0;
     870            for (int j = 0; j < 10000000; j++)
     871              x = x + 1.0;
     872            count++;
     873          }
     874        while (start + testtime * 1e9 > gethrtime ());
     875        fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     876        return rec_count;
     877      }
     878    else
     879      {
     880        real_recurse (i + 1, imax);
     881        rec_count++;
     882        return rec_count;
     883      }
     884  }
     885  
     886  /* gpf -- simple example showing the gprof fallacy */
     887  float gpf_a (void);
     888  float gpf_b (void);
     889  float gpf_work (int);
     890  
     891  #define MAX_GPF_WORK_COUNT 1000
     892  
     893  int
     894  gpf (int k)
     895  {
     896    long long count = 0;
     897    float x = -1.0;
     898    hrtime_t start = gethrtime ();
     899    hrtime_t vstart = getmyvtime ();
     900  
     901    /* Log the event */
     902    wlog ("start of gpf", NULL);
     903  
     904    do
     905      {
     906        x = gpf_a ();
     907        x += gpf_b ();
     908        count++;
     909        if (count == MAX_GPF_WORK_COUNT)
     910          fprintf (stderr, "Execution error -- %lld iterations of gpf_[ab]; possible compiler bug\n",
     911                   count);
     912      }
     913    while (start + testtime * 1e9 > gethrtime ());
     914  
     915    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     916    if (x < 0.0)
     917      fprintf (stderr, "Execution error -- x < 0.0; possible compiler bug (x = %f)\n", x);
     918    whrvlog (gethrtime () - start, getmyvtime () - vstart, "gpf - total", NULL);
     919    return 0;
     920  }
     921  
     922  float
     923  gpf_a ()
     924  {
     925    float x = -1.0;
     926    for (int i = 0; i < 9; i++)
     927      x += gpf_work (1);
     928    return x;
     929  }
     930  
     931  float
     932  gpf_b ()
     933  {
     934    float x = -1.0;
     935    x = gpf_work (10);
     936    return x;
     937  }
     938  
     939  float
     940  gpf_work (int amt)
     941  {
     942    volatile float x = 0.0;
     943    int imax = 4 * amt * amt;
     944    for (int i = 0; i < imax; i++)
     945      {
     946        x = 0.0;
     947        for (int j = 0; j < 200000; j++)
     948          x = x + 1.0;
     949      }
     950    return x;
     951  }
     952  
     953  /*	bounce -- example of indirect recursion */
     954  void bounce_a (int, int);
     955  void bounce_b (int, int);
     956  
     957  int
     958  bounce (int k)
     959  {
     960    long long count = 0;
     961    hrtime_t start = gethrtime ();
     962    hrtime_t vstart = getmyvtime ();
     963  
     964    /* Log the event */
     965    wlog ("start of bounce", NULL);
     966    if (k == 0)
     967      k = 20;
     968    do
     969      {
     970        bounce_a (0, k);
     971        count++;
     972      }
     973    while (start + testtime * 1e9 > gethrtime ());
     974    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
     975    whrvlog (gethrtime () - start, getmyvtime () - vstart, "bounce", NULL);
     976    return 0;
     977  }
     978  
     979  void
     980  bounce_a (int i, int imax)
     981  {
     982    if (i == imax)
     983      {
     984        volatile float x = 0.0;
     985        for (int k = 0; k < 8; k++)
     986          {
     987            for (int j = 0; j < 2000000; j++)
     988              x = x + 1.0;
     989          }
     990        return;
     991      }
     992    else
     993      bounce_b (i, imax);
     994  }
     995  
     996  void
     997  bounce_b (int i, int imax)
     998  {
     999    bounce_a (i + 1, imax);
    1000    return;
    1001  }
    1002  
    1003  /* =============================================================== */
    1004  
    1005  /*	sched -- spend time calling sched_yield() */
    1006  
    1007  int
    1008  sched (int k)
    1009  {
    1010    long long count = 0;
    1011    hrtime_t start = gethrtime ();
    1012    hrtime_t vstart = getmyvtime ();
    1013  
    1014    /* Log the event */
    1015    wlog ("start of sched", NULL);
    1016    if (k == 0)
    1017      {
    1018        k = testtime;
    1019        if (k < 1)
    1020          k = 1;
    1021      }
    1022    do
    1023      {
    1024        for (int i = 0; i < 1000000; i++)
    1025          sched_yield ();
    1026        count++;
    1027      }
    1028    while (start + testtime * 1e9 > gethrtime ());
    1029  
    1030    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
    1031    whrvlog (gethrtime () - start, getmyvtime () - vstart, "sched", NULL);
    1032    return 0;
    1033  }
    1034  
    1035  /* synccall -- spend time calling sync() */
    1036  int
    1037  synccall (int k)
    1038  {
    1039    long long count = 0;
    1040    hrtime_t start = gethrtime ();
    1041    hrtime_t vstart = getmyvtime ();
    1042  
    1043    /* Log the event */
    1044    wlog ("start of synccall", NULL);
    1045    if (k == 0)
    1046      {
    1047        k = testtime;
    1048        if (k < 1)
    1049          k = 1;
    1050      }
    1051    do
    1052      {
    1053        sync ();
    1054        count++;
    1055      }
    1056    while (start + testtime * 1e9 > gethrtime ());
    1057  
    1058    fprintf (stderr, "   Performed %lld sync() calls\n", count);
    1059    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
    1060    whrvlog (gethrtime () - start, getmyvtime () - vstart, "synccall", NULL);
    1061    return 0;
    1062  }
    1063  
    1064  /* sigtime -- spend time in a signal handler */
    1065  static void sigtime_handler (int);
    1066  
    1067  int
    1068  sigtime (int k)
    1069  {
    1070    long long count = 0;
    1071    hrtime_t start = gethrtime ();
    1072    hrtime_t vstart = getmyvtime ();
    1073  
    1074    /* Log the event */
    1075    wlog ("start of sigtime", NULL);
    1076  
    1077    /* set up the signal handler */
    1078    sigset (SIGHUP, sigtime_handler);
    1079    do
    1080      {
    1081        kill (getpid (), SIGHUP);
    1082        count++;
    1083      }
    1084    while (start + testtime * 1e9 > gethrtime ());
    1085  
    1086    sigset (SIGHUP, SIG_DFL);
    1087    fprintf (stderr, "   Sent %lld SIGHUP signals\n", count);
    1088    whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigtime", NULL);
    1089    return 0;
    1090  }
    1091  
    1092  static void
    1093  sigtime_handler (int sig)
    1094  {
    1095    volatile int x;
    1096    for (int i = 0; i < 50; i++)
    1097      {
    1098        x = 0;
    1099        for (int j = 0; j < 1000000; j++)
    1100          x = x + 1;
    1101      }
    1102    return;
    1103  }
    1104  
    1105  /* systime -- spend time in a few system calls */
    1106  int
    1107  systime (int k)
    1108  {
    1109    struct timeval ttime;
    1110    int j;
    1111    long long count = 0;
    1112    double t = testtime / 5;
    1113    if (t < 1.0)
    1114      t = 1.0;
    1115    hrtime_t start = gethrtime ();
    1116    hrtime_t rstart = start;
    1117    hrtime_t vstart = getmyvtime ();
    1118    hrtime_t rvstart = vstart;
    1119  
    1120    /* Log the event */
    1121    wlog ("start of systime", NULL);
    1122  
    1123    /* do gettimeofday calls */
    1124    do
    1125      {
    1126        for (j = 0; j < 30000; j++)
    1127          {
    1128            (void) gettimeofday (&ttime, NULL);
    1129          }
    1130        count++;
    1131      }
    1132    while (start + t * 1e9 > gethrtime ());
    1133  
    1134    hrtime_t end = gethrtime ();
    1135    hrtime_t vend = getmyvtime ();
    1136    fprintf (stderr, "   Performed %lld while-loop iterations gettimeofday\n", count);
    1137    whrvlog (end - start, vend - vstart, "systime -- 10**6 gettimeofday", NULL);
    1138  
    1139    /* do gethrtime calls */
    1140    start = gethrtime ();
    1141    vstart = getmyvtime ();
    1142    count = 0;
    1143    do
    1144      {
    1145        (void) gethrtime ();
    1146        count++;
    1147      }
    1148    while (start + t * 1e9 > gethrtime ());
    1149  
    1150    end = gethrtime ();
    1151    vend = getmyvtime ();
    1152    fprintf (stderr, "   Performed %lld while-loop iterations gethrtime\n", count);
    1153    whrvlog ((end - start), (vend - vstart), "systime -- 10**6 gethrtime", NULL);
    1154  
    1155    /* do pairs of gethrtime calls */
    1156    start = gethrtime ();
    1157    vstart = getmyvtime ();
    1158  
    1159    count = 0;
    1160    do
    1161      {
    1162        for (j = 0; j < 30000; j++)
    1163          {
    1164            (void) gethrtime ();
    1165            (void) gethrtime ();
    1166          }
    1167        count++;
    1168      }
    1169    while (start + t * 1e9 > gethrtime ());
    1170  
    1171    end = gethrtime ();
    1172    vend = getmyvtime ();
    1173    fprintf (stderr, "   Performed %lld while-loop iterations pairs of gethrtime\n",
    1174             count);
    1175    whrvlog (end - start, vend - vstart, "systime -- 10**6  pairs of gethrtime",
    1176    NULL);
    1177  
    1178    /* do gethrvtime calls */
    1179    start = gethrtime ();
    1180    vstart = getmyvtime ();
    1181  
    1182    count = 0;
    1183    do
    1184      {
    1185        for (j = 0; j < 30000; j++)
    1186          {
    1187            (void) gethrvtime ();
    1188          }
    1189        count++;
    1190      }
    1191    while (start + t * 1e9 > gethrtime ());
    1192  
    1193    end = gethrtime ();
    1194    vend = getmyvtime ();
    1195    fprintf (stderr, "   Performed %lld while-loop iterations gethrvtime\n", count);
    1196    whrvlog (end - start, vend - vstart, "systime -- 10**6 gethrvtime", NULL);
    1197  
    1198    /* do getrusage calls */
    1199    start = gethrtime ();
    1200    vstart = getmyvtime ();
    1201  
    1202    count = 0;
    1203    do
    1204      {
    1205        for (j = 0; j < 30000; j++)
    1206          {
    1207            struct rusage rusage;
    1208            (void) getrusage (RUSAGE_SELF, &rusage);
    1209          }
    1210        count++;
    1211      }
    1212    while (start + t * 1e9 > gethrtime ());
    1213  
    1214    end = gethrtime ();
    1215    vend = getmyvtime ();
    1216    fprintf (stderr, "   Performed %lld while-loop iterations getrusage\n", count);
    1217    whrvlog ((end - start), (vend - vstart), "systime -- 10**6 getrusage", NULL);
    1218    whrvlog ((gethrtime () - rstart), (getmyvtime () - rvstart), "systime", NULL);
    1219    return 0;
    1220  }
    1221  
    1222  /* unwindcases -- test various unwind corner cases */
    1223  static void unwindcases_handler (int);
    1224  
    1225  int
    1226  unwindcases (int k)
    1227  {
    1228    long long count = 0;
    1229    hrtime_t start = gethrtime ();
    1230    hrtime_t vstart = getmyvtime ();
    1231  
    1232    /* Log the event */
    1233    wlog ("start of unwindcases", NULL);
    1234  
    1235    /* set up the signal handler */
    1236    sigset (SIGHUP, unwindcases_handler);
    1237  
    1238    /* initialize the new signal mask */
    1239    sigset_t new_mask;
    1240    sigset_t old_mask;
    1241    sigfillset (&new_mask);
    1242    sigdelset (&new_mask, SIGHUP);
    1243  
    1244    /* block all signals except SIGHUP*/
    1245    sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
    1246    do
    1247      {
    1248        kill (getpid (), SIGHUP);
    1249        count++;
    1250      }
    1251    while (start + testtime * 1e9 > gethrtime ());
    1252  
    1253    sigprocmask (SIG_SETMASK, &old_mask, NULL);
    1254    sigset (SIGHUP, SIG_DFL);
    1255    fprintf (stderr, "   Sent %lld SIGHUP signals\n", count);
    1256    whrvlog (gethrtime () - start, getmyvtime () - vstart, "unwindcases", NULL);
    1257    return 0;
    1258  }
    1259  
    1260  #define unwindcases_memcpy memcpy
    1261  #define unwindcases_memset memset
    1262  #define unwindcases_memnum (4096)
    1263  
    1264  static char unwindcases_array[4097];
    1265  static volatile int srcind = 1024;
    1266  
    1267  static void
    1268  unwindcases_handler (int sig)
    1269  {
    1270    for (int i = 0; i < 1000; i++)
    1271      {
    1272        for (int j = 0; j < 1000; j++)
    1273          {
    1274            unwindcases_memset ((void*) unwindcases_array, 0, unwindcases_memnum);
    1275            for (int k = 0; k < 10; k++)
    1276              {
    1277                unwindcases_array[k] = unwindcases_array[srcind];
    1278                unwindcases_array[k + srcind / 4] = 0;
    1279                unwindcases_array[k] = unwindcases_array[strlen (unwindcases_array + k) + 1];
    1280              }
    1281            unwindcases_memcpy ((void*) unwindcases_array,
    1282                                (void*) (unwindcases_array + 4096 / 2),
    1283                                unwindcases_memnum / 2);
    1284          }
    1285      }
    1286    return;
    1287  }
    1288  
    1289  /*	tailcallopt -- call routines that would be tail-call optimized when
    1290   *		compiled with optimization
    1291   */
    1292  void tailcall_a (void);
    1293  void tailcall_b (void);
    1294  void tailcall_c (void);
    1295  
    1296  int
    1297  tailcallopt (int n)
    1298  {
    1299    long long count = 0;
    1300    hrtime_t start = gethrtime ();
    1301    hrtime_t vstart = getmyvtime ();
    1302  
    1303    /* Log the event */
    1304    wlog ("start of tailcallopt", NULL);
    1305    do
    1306      {
    1307        tailcall_a ();
    1308        count++;
    1309      }
    1310    while (start + testtime * 1e9 > gethrtime ());
    1311  
    1312    fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
    1313    whrvlog (gethrtime () - start, getmyvtime () - vstart, "tailcallopt", NULL);
    1314    return 0;
    1315  }
    1316  
    1317  void
    1318  tailcall_a ()
    1319  {
    1320    volatile float x = 0.0;
    1321    for (int j = 0; j < 4000000; j++)
    1322      x = x + 1.0;
    1323    tailcall_b ();
    1324  }
    1325  
    1326  void
    1327  tailcall_b ()
    1328  {
    1329    volatile float x = 0.0;
    1330    for (int j = 0; j < 4000000; j++)
    1331      x = x + 1.0;
    1332    tailcall_c ();
    1333  }
    1334  
    1335  void
    1336  tailcall_c ()
    1337  {
    1338    volatile float x = 0.0;
    1339    for (int j = 0; j < 4000000; j++)
    1340      x = x + 1.0;
    1341  }
    1342  
    1343  int
    1344  itimer_realprof (int k) /* mess with itimer ITIMER_REALPROF */
    1345  {
    1346    struct itimerval tval;
    1347    int retval;
    1348    hrtime_t start = gethrtime ();
    1349    hrtime_t vstart = getmyvtime ();
    1350  
    1351    /* set an itimer */
    1352    if (k != 0)
    1353      {
    1354        wlog ("start of itimer_realprof", NULL);
    1355        tval.it_interval.tv_sec = 1;
    1356        tval.it_interval.tv_usec = 300000;
    1357        tval.it_value = tval.it_interval;
    1358      }
    1359    else
    1360      {
    1361        wlog ("start of itimer_realprof(0)", NULL);
    1362        tval.it_interval.tv_sec = 0;
    1363        tval.it_interval.tv_usec = 0;
    1364        tval.it_value = tval.it_interval;
    1365      }
    1366    retval = setitimer (ITIMER_REALPROF, &tval, 0);
    1367    if (retval != 0)
    1368      fprintf (stderr, "setitimer(ITIMER_REALPROF) got %d returned: %s\n",
    1369               retval, strerror (errno));
    1370    whrvlog (gethrtime () - start, getmyvtime () - vstart, "itimer_realprof",
    1371             NULL);
    1372    return 0;
    1373  }
    1374  
    1375  static struct sigaction old_sigprof_handler;
    1376  static void sigprof_handler (int sig);
    1377  static void sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap);
    1378  
    1379  int
    1380  sigprof (int k)
    1381  {
    1382    struct sigaction act;
    1383  
    1384    hrtime_t start = gethrtime ();
    1385    hrtime_t vstart = getmyvtime ();
    1386  
    1387    /* Log the event */
    1388    wlog ("start of sigprof", NULL);
    1389  
    1390    /* query current handler */
    1391    if (sigaction (SIGPROF, NULL, &act) == -1)
    1392      printf ("\tFailed current sigaction query: %s\n", strerror (errno));
    1393    else
    1394      printf ("\tCurrently installed sigaction 0x%p\n", act.sa_sigaction);
    1395  
    1396    sigemptyset (&act.sa_mask);
    1397    act.sa_flags = SA_RESTART | SA_SIGINFO;
    1398    act.sa_sigaction = (void(*)(int, siginfo_t*, void*))sigprof_sigaction;
    1399  
    1400    if (k != 0)
    1401      {
    1402        /* install with deferral to original handler (if set) */
    1403        if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
    1404          printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
    1405        if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_DFL)
    1406          {
    1407            old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
    1408            printf ("\tReplaced default sigprof handler with 0x%p\n",
    1409                    act.sa_sigaction);
    1410          }
    1411        else
    1412          printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
    1413                  old_sigprof_handler.sa_sigaction, act.sa_sigaction);
    1414      }
    1415    else
    1416      {
    1417        /* installed without deferral to any original handler */
    1418        old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
    1419        if (sigaction (SIGPROF, &act, NULL) == -1)
    1420          printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
    1421        else
    1422          printf ("\tInstalled sigprof_sigaction 0x%p\n", act.sa_sigaction);
    1423      }
    1424  
    1425    whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprof", NULL);
    1426    return 0;
    1427  }
    1428  
    1429  int
    1430  sigprofh (int k)
    1431  {
    1432    struct sigaction act;
    1433  
    1434    hrtime_t start = gethrtime ();
    1435    hrtime_t vstart = getmyvtime ();
    1436  
    1437    /* Log the event */
    1438    wlog ("start of sigprofh", NULL);
    1439  
    1440    /* query current handler */
    1441    if (sigaction (SIGPROF, NULL, &act) == -1)
    1442      printf ("\tFailed current sigaction query: %s\n", strerror (errno));
    1443    else
    1444      printf ("\tCurrently installed handler 0x%p\n", act.sa_handler);
    1445  
    1446    sigemptyset (&act.sa_mask);
    1447    act.sa_flags = SA_RESTART;
    1448    act.sa_handler = sigprof_handler;
    1449    if (k != 0)
    1450      {
    1451        /* install with deferral to original handler (if set) */
    1452        if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
    1453          printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
    1454        if (old_sigprof_handler.sa_handler == SIG_DFL)
    1455          {
    1456            old_sigprof_handler.sa_handler = SIG_IGN;
    1457            printf ("\tReplaced default sigprof handler with 0x%p\n",
    1458                    act.sa_handler);
    1459          }
    1460        else
    1461          printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
    1462                  old_sigprof_handler.sa_handler, act.sa_handler);
    1463      }
    1464    else
    1465      {
    1466        /* installed without deferral to any original handler */
    1467        old_sigprof_handler.sa_handler = SIG_IGN;
    1468        if (sigaction (SIGPROF, &act, NULL) == -1)
    1469          printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
    1470        else
    1471          printf ("\tInstalled sigprof_handler 0x%p\n", act.sa_handler);
    1472      }
    1473  
    1474    whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprofh", NULL);
    1475    return 0;
    1476  }
    1477  
    1478  static void
    1479  sigprof_handler (int sig)
    1480  {
    1481    int j;
    1482    volatile int x;
    1483  
    1484    hrtime_t now = gethrtime ();
    1485    if (old_sigprof_handler.sa_handler == SIG_IGN)
    1486      {
    1487        whrvlog (now, 0, "sigprof_handler (ign)", NULL);
    1488        for (j = 0, x = 0; j < 1000000; j++)
    1489          x = x + 1;
    1490      }
    1491    else
    1492      {
    1493        whrvlog (now, 0, "sigprof_handler (fwd)", NULL);
    1494        for (j = 0, x = 0; j < 1000000; j++)
    1495          x = x + 1;
    1496        /* forward signal to original handler */
    1497        if (old_sigprof_handler.sa_flags & SA_SIGINFO)
    1498          (old_sigprof_handler.sa_sigaction)(sig, NULL, NULL);
    1499        else
    1500          (old_sigprof_handler.sa_handler)(sig);
    1501        printf ("\tReturned from original sigprof handler!\n");
    1502      }
    1503  
    1504    return;
    1505  }
    1506  
    1507  static void
    1508  sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap)
    1509  {
    1510    int j;
    1511    volatile int x;
    1512  
    1513    hrtime_t now = gethrtime ();
    1514    if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_IGN)
    1515      {
    1516        whrvlog (now, 0, "sigprof_sigaction (ign)", NULL);
    1517        for (j = 0, x = 0; j < 1000000; j++)
    1518          x = x + 1;
    1519      }
    1520    else
    1521      {
    1522        whrvlog (now, 0, "sigprof_sigaction (fwd)", NULL);
    1523        for (j = 0, x = 0; j < 1000000; j++)
    1524          x = x + 1;
    1525        /* forward signal to original handler */
    1526        if (old_sigprof_handler.sa_flags & SA_SIGINFO)
    1527          (old_sigprof_handler.sa_sigaction)(sig, sip, uap);
    1528        else
    1529          (old_sigprof_handler.sa_handler)(sig);
    1530        printf ("\tReturned from original sigprof sigaction!\n");
    1531      }
    1532    return;
    1533  }
    1534  
    1535  #if 0
    1536  Need to consider various signal handler / sigaction scenarios :
    1537  
    1538  1. A handler is already installed, and a new handler is being installed.
    1539  (The original handler may be one of the defaults.)
    1540  2. A handler is already installed, and a sigaction is being installed.
    1541  3. A sigaction is already installed, and a new sigaction is being installed.
    1542  4. A sigaction is already installed, and a handler is being installed.
    1543  #endif
    1544  
    1545  int
    1546  do_chdir (int k) /* switch to a new working directory */
    1547  {
    1548    char *workdir;
    1549    char *workdir0 = "/tmp";
    1550    char *workdir1 = "/";
    1551    char currworkdir[MAXPATHLEN];
    1552  
    1553    hrtime_t start = gethrtime ();
    1554    hrtime_t vstart = getmyvtime ();
    1555  
    1556    if (k != 0)
    1557      {
    1558        wlog ("start of do_chdir(X)", NULL);
    1559        workdir = workdir1;
    1560      }
    1561    else
    1562      {
    1563        wlog ("start of do_chdir", NULL);
    1564        workdir = workdir0;
    1565      }
    1566  
    1567    if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
    1568      fprintf (stderr, "old getcwd failed: %s\n", strerror (errno));
    1569    else
    1570      printf ("old getcwd returned \"%s\"\n", currworkdir);
    1571  
    1572    if (chdir (workdir) != 0)
    1573      fprintf (stderr, "chdir(\"%s\") failed: %s\n", workdir, strerror (errno));
    1574  
    1575    if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
    1576      fprintf (stderr, "new getcwd failed: %s\n", strerror (errno));
    1577    else
    1578      printf ("new getcwd returned \"%s\"\n", currworkdir);
    1579    whrvlog (gethrtime () - start, getmyvtime () - vstart, "do_chdir", NULL);
    1580    return 0;
    1581  }
    1582  
    1583  int
    1584  do_exec (int k) /* do an exec() call */
    1585  {
    1586    sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
    1587    if (putenv (new_name))
    1588      fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
    1589    if (k >= 0)
    1590      {
    1591        wlog ("about to exec", NULL);
    1592        execl ("./synprog", "synprog", "gpf.cpu.sx", NULL);
    1593        wlog ("exec failed!!!", NULL);
    1594      }
    1595    else
    1596      {
    1597        wlog ("about to execX", NULL);
    1598        execl ("./no-such-file", "no-such-file", "gpf.cpu.sx", NULL);
    1599        wlog ("execX failed (as expected)", NULL);
    1600      }
    1601    return 0;
    1602  }
    1603  
    1604  /* preloading libcollector to a setuid executable will fail! */
    1605  const char *cmdX = "/random/crash_n_burn";
    1606  const char *cmd0 = "/bin/uptime";
    1607  const char *cmd1 = "/bin/echo hello world!";
    1608  const char *cmd2 = "/usr/bin/sleep 5";
    1609  const char *cmd3 = "/usr/bin/sleep 5; /bin/echo hello world!";
    1610  const char *cmd4 = "/usr/bin/sleep 2; /bin/echo hello world!; /usr/bin/sleep 2";
    1611  const char *cmd5 = "/bin/date; /bin/sleep 2; /bin/date; /bin/sleep 2; /bin/date";
    1612  const char *cmd6 = "w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w";
    1613  const char *cmd7 = "synprog";
    1614  const char *cmd8 = "synprog icpu.sx 2>&1";
    1615  
    1616  int
    1617  do_popen (int k) /* do a popen() call */
    1618  {
    1619    int ret;
    1620    FILE *fd;
    1621    char buf[BUFSIZ];
    1622    const char *mode = "r";
    1623  
    1624    /* XXXX popen() will temporarily vfork+exec() a new child */
    1625    /* but there will be no accounting for it, unless it's synprog! */
    1626    sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
    1627    if (putenv (new_name))
    1628      fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
    1629  
    1630    /* ignore reapchild to catch child here */
    1631    (void) sigset (SIGCHLD, 0);
    1632    if (k >= 0)
    1633      {
    1634        wlog ("about to popen", NULL);
    1635        fd = popen (cmd8, mode);
    1636      }
    1637    else
    1638      {
    1639        wlog ("about to popenX!", NULL);
    1640        fd = popen (cmdX, mode);
    1641      }
    1642    if (fd == NULL)
    1643      printf ("do_popen failed: %s\n", strerror (errno));
    1644    else
    1645      printf ("do_popen succeeded: fileno=%d\n", fileno (fd));
    1646  
    1647    /* restore pre-popen environment */
    1648    sprintf (new_name, "_SP_NAME=%s", acct_file);
    1649    if (putenv (new_name))
    1650      fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
    1651  
    1652    if (fd != NULL)
    1653      {
    1654        while (fgets (buf, BUFSIZ, fd) != NULL)
    1655          printf ("&    %s", buf);
    1656  
    1657        if ((ret = pclose (fd)) == -1)
    1658          printf ("do_popen pclose error: %s\n", strerror (errno));
    1659        else
    1660          printf ("do_popen pclose returned %d\n", ret);
    1661      }
    1662  
    1663    /* set up to reap any children */
    1664    (void) sigset (SIGCHLD, reapchild);
    1665    return 0;
    1666  }
    1667  
    1668  int
    1669  do_system (int k) /* do a system() call */
    1670  {
    1671    int ret;
    1672  
    1673    /* XXXX system() will temporarily vfork+exec() a new child */
    1674    /* but there will be no accounting for it, unless it's synprog! */
    1675    sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
    1676    if (putenv (new_name))
    1677      fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
    1678  
    1679    if (k >= 0)
    1680      {
    1681        wlog ("about to system", NULL);
    1682        ret = system (cmd8);
    1683      }
    1684    else
    1685      {
    1686        wlog ("about to systemX!", NULL);
    1687        ret = system (cmd0);
    1688      }
    1689    if (ret < 0)
    1690      printf ("do_system failed: %s\n", strerror (errno));
    1691    else
    1692      printf ("do_system succeeded, ret=%d\n", ret);
    1693  
    1694    /* restore pre-system environment */
    1695    sprintf (new_name, "_SP_NAME=%s", acct_file);
    1696    if (putenv (new_name))
    1697      fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
    1698    return 0;
    1699  }
    1700  
    1701  int
    1702  do_forkexec (int k) /* do a fork()+exec() call combo */
    1703  {
    1704    int ret, pid;
    1705    int status = -1;
    1706    char arg0[128], arg1[128];
    1707    arg1[0] = (char) 0;
    1708  
    1709    /* ignore reapchild to catch child here */
    1710    (void) sigset (SIGCHLD, 0);
    1711  
    1712    sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
    1713    if ((pid = fork ()) == 0)
    1714      {
    1715        syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
    1716        strcpy (acct_file, child_name);
    1717        acct_init (acct_file);
    1718        sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
    1719        if (putenv (new_name))
    1720          {
    1721            fprintf (stderr, "Failed to name fork child! %s\n", strerror (errno));
    1722          }
    1723        (void) execl (arg0, "fork+exec", arg1[0] ? arg1 : NULL, NULL);
    1724        fprintf (stderr, "fork execl failed! %s\n", strerror (errno));
    1725        _exit (127);
    1726      }
    1727    else if (pid == -1)
    1728      fprintf (stderr, "fork failed! %s\n", strerror (errno));
    1729    else
    1730      {
    1731        do
    1732          {
    1733            ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
    1734          }
    1735        while ((ret == -1) && (errno == EINTR));
    1736  
    1737        if (ret == -1)
    1738          fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
    1739  #if 0
    1740        else
    1741          {
    1742            if (WIFEXITED (status))
    1743              printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
    1744            if (WIFSTOPPED (status))
    1745              printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
    1746            if (WIFSIGNALED (status))
    1747              printf ("WTERMSIG=%d\n", WTERMSIG (status));
    1748            if (WIFCONTINUED (status))
    1749              printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
    1750          }
    1751  #endif
    1752        if (WIFEXITED (status))
    1753          printf ("do_forkexec succeeded: child exit status=%d\n",
    1754                  WEXITSTATUS (status));
    1755        else
    1756          printf ("do_forkexec failed! status=%d\n", status);
    1757      }
    1758  
    1759    /* set up to reap any children */
    1760    (void) sigset (SIGCHLD, reapchild);
    1761    return 0;
    1762  }
    1763  
    1764  int
    1765  do_vforkexec (int k) /* do a vfork()+exec() call combo */
    1766  {
    1767    int ret, pid;
    1768    int status = 1;
    1769    char arg0[128], arg1[128];
    1770    arg1[0] = (char) 0;
    1771    /* ignore reapchild to catch child here */
    1772    (void) sigset (SIGCHLD, 0);
    1773  
    1774    sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
    1775  
    1776    if ((pid = vfork ()) == 0)
    1777      {
    1778        syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
    1779        strcpy (acct_file, child_name);
    1780        acct_init (acct_file);
    1781        sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
    1782        if (putenv (new_name))
    1783          fprintf (stderr, "Failed to name vfork child! %s\n", strerror (errno));
    1784        (void) execl (arg0, "vfork+exec", arg1[0] ? arg1 : NULL, NULL);
    1785        printf ("vfork execl failed! %s\n", strerror (errno));
    1786        _exit (127);
    1787      }
    1788    else if (pid == -1)
    1789      fprintf (stderr, "vfork failed! %s\n", strerror (errno));
    1790    else
    1791      {
    1792        do
    1793          {
    1794            ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
    1795          }
    1796        while (ret == -1 && errno == EINTR);
    1797  
    1798        if (ret == -1)
    1799          fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
    1800  #if 0
    1801        else
    1802          {
    1803            if (WIFEXITED (status))
    1804              printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
    1805            if (WIFSTOPPED (status))
    1806              printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
    1807            if (WIFSIGNALED (status))
    1808              printf ("WTERMSIG=%d\n", WTERMSIG (status));
    1809            if (WIFCONTINUED (status))
    1810              printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
    1811          }
    1812  #endif
    1813        if (WIFEXITED (status))
    1814          printf ("do_vforkexec succeeded: child exit status=%d\n",
    1815                  WEXITSTATUS (status));
    1816        else
    1817          printf ("do_vforkexec failed! status=%d\n", status);
    1818      }
    1819  
    1820    /* set up to reap any children */
    1821    (void) sigset (SIGCHLD, reapchild);
    1822    return 0;
    1823  }