1823 lines
47 KiB
C
1823 lines
47 KiB
C
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
/* synprog.c - synthetic program to use for testing performance tools */
|
|
#define _GNU_SOURCE
|
|
#include <sched.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/ucontext.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <sched.h>
|
|
#include <sys/resource.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <dlfcn.h>
|
|
#include <fcntl.h>
|
|
#include "stopwatch.h"
|
|
|
|
int get_ncpus ();
|
|
int get_clock_rate ();
|
|
void acct_init (char *); /* initialize accounting */
|
|
void iotrace_init (char *); /* initialize IO trace accounting */
|
|
void commandline (char *); /* routine execute a scenario */
|
|
void forkcopy (char *, int); /* fork copy of self to run string */
|
|
int clonecopy (void *);
|
|
#define CLONE_STACK_SIZE 8388608
|
|
#define CLONE_TLS_SIZE 4096
|
|
#define CLONE_RED_SIZE 4096
|
|
#define CLONE_IO 0x80000000 /* Clone io context */
|
|
void forkchild (char *); /* fork child to run string */
|
|
void reapchildren (void); /* reap all children */
|
|
void reapchild (int); /* reap a child after getting SIGCLD */
|
|
void check_sigmask (); /* check that SIGPROF and SIGEMT are not masked */
|
|
void masksig (); /* real code to mask SIGPROF and SIGEMT */
|
|
|
|
hrtime_t progstart;
|
|
hrtime_t progvstart;
|
|
hrtime_t gethrustime ();
|
|
static int include_system_time = 0;
|
|
|
|
static hrtime_t
|
|
getmyvtime ()
|
|
{
|
|
if (include_system_time == 0)
|
|
return gethrvtime ();
|
|
return gethrustime ();
|
|
}
|
|
|
|
void (*sigset (int sig, void (*disp)(int)))(int);
|
|
#define ITIMER_REALPROF ITIMER_REAL
|
|
/* Linux needs to have this defined for RTLD_NEXT and RTLD_DEFAULT */
|
|
/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT */
|
|
#define RTLD_NEXT ((void *) -1l)
|
|
/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT */
|
|
#define RTLD_DEFAULT ((void *) 0)
|
|
|
|
FILE *fid;
|
|
FILE *fid2;
|
|
double testtime = 3.0;
|
|
static char acct_file[128];
|
|
static char new_name[128];
|
|
static char child_name[128];
|
|
|
|
/* descendant process tracking */
|
|
static unsigned syn_fork = 0;
|
|
static unsigned syn_exec = 0;
|
|
static unsigned syn_combo = 0;
|
|
|
|
/* various behavior routines */
|
|
int bounce (int); /* bounce with a->b->a->b-> ... */
|
|
int callso (int); /* so load test */
|
|
int callsx (int); /* alternate so load test */
|
|
int correlate (int); /* test correlation with profiling */
|
|
int cputime (int); /* use a bunch of user cpu time (fp) */
|
|
int doabort (int); /* force a SEGV by dereferencing NULL */
|
|
int dousleep (int); /* loop with a usleep call */
|
|
int endcases (int); /* test various code construct endcases */
|
|
int fitos (int); /* test various code construct endcases */
|
|
int gpf (int); /* show gprof fallacy */
|
|
int hrv (int); /* gethrvtime calls */
|
|
int icputime (int); /* use a bunch of user cpu time (long) */
|
|
int iofile (int); /* do operations on a temporary file */
|
|
int iotest (int); /* do various io system calls */
|
|
int ioerror (int); /* do various erroneous io system calls */
|
|
int ldso (int); /* use a bunch of time in ld.so */
|
|
int masksignals (int); /* mask the SIGEMT and SIGPROF signals */
|
|
int memorymap (int); /* do mmap operation for io tracing */
|
|
int muldiv (int); /* do integer multiply/divide for a time */
|
|
int naptime (int); /* sleep for a time */
|
|
int pagethrash (int); /* thrash around in memory */
|
|
int recurse (int); /* recursion test */
|
|
int recursedeep (int); /* deep recursion test */
|
|
int sched (int); /* loop over sched_yield calls */
|
|
int sigtime (int); /* use a bunch of time in a signal handler */
|
|
int synccall (int); /* loop over sync() system calls */
|
|
int systime (int); /* use a bunch of system time */
|
|
int tailcallopt (int); /* tail call optimization test */
|
|
int underflow (int); /* force underflow arithmetic */
|
|
int unwindcases (int); /* test various unwind corner cases */
|
|
|
|
int itimer_realprof (int); /* mess with itimer ITIMER_REALPROF */
|
|
int sigprof (int); /* mess with SIGPROF sigaction */
|
|
int sigprofh (int); /* mess with SIGPROF handler */
|
|
int do_chdir (int); /* do a chdir() */
|
|
int do_exec (int); /* do an exec() call */
|
|
int do_popen (int); /* do a popen() call */
|
|
int do_system (int); /* do a system() call */
|
|
int do_forkexec (int); /* do a fork()+exec() call combo */
|
|
int
|
|
do_vforkexec (int); /* do a vfork()+exec() call combo */
|
|
|
|
/* lookup table for behavior scripts */
|
|
struct scripttab
|
|
{
|
|
char *name;
|
|
int (*function)(int);
|
|
char *acctname;
|
|
int param;
|
|
int noverify;
|
|
};
|
|
|
|
static int CLONE_FLAGS[] = {
|
|
SIGCHLD,
|
|
CLONE_FILES | CLONE_FS | CLONE_SYSVSEM | CLONE_IO | SIGCHLD
|
|
};
|
|
|
|
/* the default script */
|
|
static char DEFAULT_COMMAND[] =
|
|
"icpu.md.cpu.rec.recd.dousl.gpf.fitos.ec.tco.b.nap.uf."
|
|
"sys.sig.so.sx.so.sched.uwdc";
|
|
|
|
struct scripttab scripttab[] = {
|
|
{"abt", doabort, "doabort", 0, 0},
|
|
{"b", bounce, "bounce", 0, 0},
|
|
{"c", correlate, "correlate", 0, 0},
|
|
{"chdir", do_chdir, "chdir", 0, 0},
|
|
{"chdirX", do_chdir, "chdir", -1, 0},
|
|
{"cpu", cputime, "cputime", 0, 0},
|
|
{"dousl", dousleep, "dousleep", 0, 1},
|
|
{"ec", endcases, "endcases", 0, 0},
|
|
{"exec", do_exec, "exec", 0, 0},
|
|
{"execX", do_exec, "do_exec", -1, 0},
|
|
{"fitos", fitos, "fitos", 0, 1},
|
|
{"gpf", gpf, "gpf", 0, 0},
|
|
{"hrv", hrv, "hrv", 0, 0},
|
|
{"icpu", icputime, "icputime", 0, 0},
|
|
{"iofile", iofile, "iofile", 0, 0},
|
|
{"iotest", iotest, "iotest", 0, 0},
|
|
{"ioerror", ioerror, "ioerror", 0, 0},
|
|
{"itimer", itimer_realprof, "itimer", 1, 0},
|
|
{"itimer0", itimer_realprof, "itimer", 0, 0},
|
|
{"ldso", ldso, "ldso", 0, 0},
|
|
{"masksig", masksignals, "masksig", 0, 0},
|
|
{"md", muldiv, "muldiv", 0, 0},
|
|
{"memorymap", memorymap, "memorymap", 100, 0},
|
|
{"nap", naptime, "naptime", 0, 0},
|
|
{"pg", pagethrash, "pagethrash", 32, 0},
|
|
{"popen", do_popen, "popen", 0, 0},
|
|
{"popenX", do_popen, "popen", -1, 0},
|
|
{"rec", recurse, "recurse", 50, 0},
|
|
{"recd", recursedeep, "<Truncated-stack>", 500, 0},
|
|
{"sched", sched, "sched", 0, 1},
|
|
{"so", callso, "callso", 0, 0},
|
|
{"sx", callsx, "callsx", 0, 0},
|
|
{"sig", sigtime, "sigtime", 0, 1},
|
|
{"sigprof", sigprof, "sigprof", 1, 0},
|
|
{"sigprof0", sigprof, "sigprof", 0, 0},
|
|
{"sigprofh", sigprofh, "sigprofh", 1, 0},
|
|
{"sigprofh0", sigprofh, "sigprofh", 0, 0},
|
|
{"sync", synccall, "synccall", 0, 1},
|
|
{"sys", systime, "systime", 0, 1},
|
|
{"system", do_system, "system", 0, 0},
|
|
{"systemX", do_system, "do_system", -1, 0},
|
|
{"tco", tailcallopt, "tailcallopt", 0, 0},
|
|
{"uf", underflow, "underflow", 0, 1},
|
|
{"forkexec", do_forkexec, "forkexec", 0, 0},
|
|
{"vforkexec", do_vforkexec, "vforkexec", 0, 0},
|
|
{"uwdc", unwindcases, "unwindcases", 0, 0},
|
|
{NULL, NULL, NULL, 0, 0}
|
|
};
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
int i;
|
|
hrtime_t start;
|
|
hrtime_t vstart;
|
|
char *name;
|
|
char buf[1024];
|
|
char arglist[4096];
|
|
|
|
// need a more robust test of whether system HWC events are being counted
|
|
if (getenv ("TILDECLAUSE"))
|
|
include_system_time = 1;
|
|
progstart = gethrtime ();
|
|
progvstart = getmyvtime ();
|
|
name = getenv ("SP_COLLECTOR_TEST_TIMER");
|
|
if (name)
|
|
{
|
|
testtime = atof (name);
|
|
if (testtime <= 0)
|
|
testtime = 1.0;
|
|
}
|
|
name = getenv ("_SP_NAME");
|
|
if (name == NULL || strlen (name) == 0)
|
|
strcpy (acct_file, "synprog.acct");
|
|
else
|
|
strcpy (acct_file, name);
|
|
|
|
strcpy (arglist, argv[0]);
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
strcat (arglist, " ");
|
|
strcat (arglist, argv[i]);
|
|
}
|
|
|
|
sprintf (buf, "%s run", argv[0]);
|
|
wlog (buf, NULL);
|
|
|
|
int ncpus = get_ncpus ();
|
|
acct_init (acct_file);
|
|
iotrace_init ("synprog.acct2");
|
|
|
|
/* Start a timer */
|
|
start = gethrtime ();
|
|
vstart = getmyvtime ();
|
|
|
|
#ifndef NO_MS_ACCT
|
|
stpwtch_calibrate ();
|
|
#endif
|
|
|
|
if (argc == 1)
|
|
commandline (DEFAULT_COMMAND);
|
|
else
|
|
{
|
|
i = 2;
|
|
while (i < argc)
|
|
{
|
|
forkcopy (argv[i], i - 1);
|
|
i++;
|
|
}
|
|
|
|
/* do the last one ourself */
|
|
commandline (argv[1]);
|
|
}
|
|
reapchildren ();
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, buf, NULL);
|
|
fflush (fid);
|
|
fflush (fid2);
|
|
fclose (fid);
|
|
fclose (fid2);
|
|
return 0;
|
|
}
|
|
|
|
/* acct_init: initialize accounting */
|
|
void
|
|
acct_init (char *acct_file)
|
|
{
|
|
fid = fopen (acct_file, "w");
|
|
if (fid == NULL)
|
|
{
|
|
fprintf (stderr, "Open of %s for output failed: %s\n",
|
|
acct_file, strerror (errno));
|
|
exit (1);
|
|
}
|
|
fprintf (fid, "MHz: %d\n", get_clock_rate ());
|
|
fprintf (fid, "X Incl. Total Incl. CPU Name\n");
|
|
fflush (fid);
|
|
|
|
/* write a record for <Unknown>, which should have zero times */
|
|
fprintf (fid, "X %6.3f %6.3f %s\n", 0.0, 0.0, "<Unknown>");
|
|
|
|
/* set up to reap any children */
|
|
(void) sigset (SIGCHLD, reapchild);
|
|
/* verify the signal mask */
|
|
}
|
|
|
|
/* iotrace_init: initialize IO trace accounting */
|
|
void
|
|
iotrace_init (char *acct_file)
|
|
{
|
|
fid2 = fopen (acct_file, "w");
|
|
if (fid2 == NULL)
|
|
{
|
|
fprintf (stderr, "Open of %s for output failed: %s\n",
|
|
acct_file, strerror (errno));
|
|
exit (1);
|
|
}
|
|
fprintf (fid2, "X Incl.BytesRead Incl.ReadCount ");
|
|
fprintf (fid2, "Incl.BytesWritten Incl.WriteCount ");
|
|
fprintf (fid2, "Incl.OtherIOCount Name\n");
|
|
fflush (fid2);
|
|
}
|
|
|
|
/* commandline -- process a command line string:
|
|
* verbs are separated by a . character; each verb is looked-up
|
|
* in a table, and the routine to process it, and argument fetched.
|
|
* the routine is called.
|
|
*/
|
|
void
|
|
commandline (char *cmdline)
|
|
{
|
|
char *p;
|
|
char *j;
|
|
char prevj;
|
|
struct scripttab *k;
|
|
char buf[1024];
|
|
hrtime_t pstart;
|
|
hrtime_t pvstart;
|
|
hrtime_t pend;
|
|
hrtime_t pvend;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog (" Begin commandline", cmdline);
|
|
|
|
p = cmdline;
|
|
while (*p != 0)
|
|
{
|
|
/* find the terminator for this verb (a . or NULL) */
|
|
j = p;
|
|
while (*j != 0 && *j != '.')
|
|
j++;
|
|
prevj = *j;
|
|
*j = 0;
|
|
|
|
/* now look up the phase in the table */
|
|
for (k = &scripttab[0];; k++)
|
|
{
|
|
if (k->name == NULL)
|
|
break;
|
|
if (strcmp (p, k->name) == 0)
|
|
{
|
|
/* found a match */
|
|
pstart = gethrtime ();
|
|
pvstart = getmyvtime ();
|
|
(k->function)(k->param);
|
|
pend = gethrtime ();
|
|
pvend = getmyvtime ();
|
|
fprintf (fid, "%c %6.3f %6.3f %s\n",
|
|
k->noverify == 0 ? 'X' : 'Y',
|
|
(double) (pend - pstart) / (double) 1000000000.,
|
|
(double) (pvend - pvstart) / (double) 1000000000.,
|
|
k->acctname);
|
|
fflush (fid);
|
|
break;
|
|
}
|
|
}
|
|
if (k->name == NULL)
|
|
{
|
|
sprintf (buf, "++ ignoring `%s'\n", p);
|
|
fprintf (stderr, buf);
|
|
}
|
|
|
|
/* continue processing */
|
|
*j = prevj;
|
|
p = j;
|
|
if (prevj != 0)
|
|
p++;
|
|
}
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "commandline", cmdline);
|
|
}
|
|
|
|
int
|
|
clonecopy (void * script)
|
|
{
|
|
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
|
|
|
|
strcpy (acct_file, child_name);
|
|
/*printf("_SP_NAME=\"%s\" (for clone-child)\n", acct_file);*/
|
|
acct_init (acct_file);
|
|
|
|
/* execute the script */
|
|
commandline ((char *) script);
|
|
|
|
/* reap the child's descendants */
|
|
reapchild (0);
|
|
exit (0);
|
|
}
|
|
|
|
/* forkcopy -- fork a copy to run a script */
|
|
void
|
|
forkcopy (char *script, int child)
|
|
{
|
|
int child_pid;
|
|
if (strncmp ("clone", script, 5) == 0)
|
|
{
|
|
//clone instead of fork
|
|
/* Log the event */
|
|
wlog ("cloning copy ... ", script);
|
|
|
|
sprintf (child_name, "%s_C%d", acct_file, ++syn_fork);
|
|
/* clone a new process */
|
|
void * stack;
|
|
void * stack_space;
|
|
int stack_size = CLONE_STACK_SIZE;
|
|
|
|
stack_space = mmap (NULL, stack_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS, -1, 0);
|
|
if ((void*) - 1 == stack_space)
|
|
{
|
|
fprintf (stderr, "Error: mmap returned -1\n");
|
|
exit (1);
|
|
}
|
|
mprotect (stack_space, CLONE_RED_SIZE, PROT_NONE);
|
|
stack = (char *) stack_space + stack_size - CLONE_TLS_SIZE; // stack grows back
|
|
child_pid = clone (clonecopy, stack, CLONE_FLAGS[(child + 1) % 2],
|
|
(void *) (script + sizeof ("clone") - 1));
|
|
if (child_pid < 0)
|
|
{
|
|
/* error, could not fork */
|
|
fprintf (stderr, "forkcopy: clone failed--error %d\n", errno);
|
|
exit (1);
|
|
}
|
|
|
|
fprintf (stderr, "child process %d cloned by %d.\n",
|
|
child_pid, (int) getpid ());
|
|
return;
|
|
}
|
|
|
|
/* Log the event */
|
|
wlog ("forking copy ... ", script);
|
|
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
|
|
|
|
/* fork a new process */
|
|
child_pid = fork ();
|
|
if (child_pid < 0)
|
|
{
|
|
/* error, could not fork */
|
|
fprintf (stderr, "forkcopy: fork failed--error %d\n", errno);
|
|
exit (1);
|
|
|
|
}
|
|
else if (child_pid == 0)
|
|
{
|
|
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
|
|
strcpy (acct_file, child_name);
|
|
acct_init (acct_file);
|
|
|
|
/* execute the script */
|
|
commandline (script);
|
|
|
|
/* reap the child's descendants */
|
|
reapchild (0);
|
|
exit (0);
|
|
}
|
|
fprintf (stderr, "child process %d forked by %d.\n",
|
|
child_pid, (int) getpid ());
|
|
}
|
|
|
|
void
|
|
forkchild (char * cmdline)
|
|
{
|
|
stopwatch_t *prog;
|
|
char mbuf[1024];
|
|
|
|
/* Start a stopwatch */
|
|
sprintf (mbuf, "%s pid[%d]", "Synprog child", (int) getpid ());
|
|
prog = stpwtch_alloc (mbuf, 0);
|
|
|
|
/* process this child's command-line */
|
|
commandline (cmdline);
|
|
|
|
/* reap the child's descendants */
|
|
reapchild (0);
|
|
|
|
/* Stop print, and free the stopwatch */
|
|
stpwtch_stop (prog);
|
|
stpwtch_print (prog);
|
|
free (prog);
|
|
|
|
exit (0);
|
|
}
|
|
|
|
/* reap a child process, called in response to SIGCLD */
|
|
void
|
|
reapchild (int sig)
|
|
{
|
|
int status;
|
|
int ret = wait (&status);
|
|
sigset (SIGCLD, reapchild);
|
|
}
|
|
|
|
/* reap all child processes prior to exit */
|
|
void
|
|
reapchildren ()
|
|
{
|
|
int status;
|
|
int ret;
|
|
|
|
/* wait for all children to exit */
|
|
for (;;)
|
|
{
|
|
while ((ret = wait (&status)) != (pid_t) - 1)
|
|
fprintf (stderr, "synprog: reap child %x\n", ret);
|
|
if (errno == EINTR)
|
|
continue;
|
|
if (errno == ECHILD)
|
|
return;
|
|
fprintf (stderr, "synprog: unexpected errno from wait() syscall -- %s\n",
|
|
strerror (errno));
|
|
}
|
|
}
|
|
|
|
/* doabort -- force a SEGV */
|
|
int
|
|
doabort (int k)
|
|
{
|
|
char *nullptr = NULL;
|
|
char c;
|
|
|
|
/* Log the event */
|
|
wlog ("start of doabort", NULL);
|
|
|
|
/* and dereference a NULL */
|
|
c = *nullptr;
|
|
|
|
/* this should never be reached */
|
|
return (int) c;
|
|
}
|
|
|
|
/* =============================================================== */
|
|
|
|
/* dousleep -- loop with a usleep */
|
|
int
|
|
dousleep (int k)
|
|
{
|
|
volatile double x;
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of dousleep", NULL);
|
|
do
|
|
{
|
|
x = 0.0;
|
|
for (int j = 0; j < 1000000; j++)
|
|
x = x + 1.0;
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "dousleep", NULL);
|
|
/* this should never be reached */
|
|
return (int) 0;
|
|
}
|
|
|
|
/* =============================================================== */
|
|
/* correlate -- generate CPU use, correlated with profiling clock */
|
|
|
|
static void csig_handler (int);
|
|
|
|
int
|
|
correlate (int k)
|
|
{
|
|
volatile float x; /* temp variable for f.p. calculation */
|
|
struct itimerval tval;
|
|
int retval;
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of correlate", NULL);
|
|
|
|
/* set up the signal handler */
|
|
sigset (SIGALRM, csig_handler);
|
|
|
|
/* set an itimer, to break out of the sleep loop */
|
|
tval.it_value.tv_sec = 0;
|
|
tval.it_value.tv_usec = 10000;
|
|
tval.it_interval.tv_sec = 0;
|
|
tval.it_interval.tv_usec = 10000;
|
|
|
|
retval = setitimer (ITIMER_REAL, &tval, 0);
|
|
if (retval != 0)
|
|
fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
|
|
retval, strerror (errno));
|
|
do
|
|
{
|
|
x = 0.0;
|
|
for (int j = 0; j < 1000000; j++)
|
|
x = x + 1.0;
|
|
sleep (1); /* relying on the timer to break out */
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
/* now disable the itimer */
|
|
tval.it_value.tv_sec = 0;
|
|
tval.it_value.tv_usec = 0;
|
|
tval.it_interval.tv_sec = 0;
|
|
tval.it_interval.tv_usec = 0;
|
|
|
|
retval = setitimer (ITIMER_REAL, &tval, 0);
|
|
if (retval != 0)
|
|
fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
|
|
retval, strerror (errno));
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "correlate", NULL);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
csig_handler (int sig)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* cputime -- loop to use a bunch of user time (f.p.) */
|
|
int
|
|
cputime (int k)
|
|
{
|
|
volatile float x; /* temp variable for f.p. calculation */
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of cputime", NULL);
|
|
do
|
|
{
|
|
x = 0.0;
|
|
for (int j = 0; j < 1000000; j++)
|
|
x = x + 1.0;
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "cputime", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* icputime -- loop to use a bunch of user time (long) */
|
|
int
|
|
icputime (int k)
|
|
{
|
|
volatile long x; /* temp variable for long calculation */
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of icputime", NULL);
|
|
do
|
|
{
|
|
x = 0;
|
|
for (int j = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "icputime", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* hrv -- loop to do lots of gethrvtime calls */
|
|
int
|
|
hrv (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of hrv", NULL);
|
|
do
|
|
{
|
|
for (int j = 0; j < 10000; j++)
|
|
(void) gethrvtime ();
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "hrv", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* =============================================================== */
|
|
|
|
/* ldso -- use up time in ld.so */
|
|
|
|
int
|
|
ldso (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of ldso", NULL);
|
|
do
|
|
{
|
|
for (int j = 0; j < 10000; j++)
|
|
(void) dlsym (RTLD_DEFAULT, "nosuchfoo");
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "ldso", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* masksignals -- debug aid -- call routine to mask SIGPROF and SIGEMT */
|
|
int
|
|
masksignals (int n)
|
|
{
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "masksignals", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* =============================================================== */
|
|
/* muldiv -- loop to do a bunch of integer multiply and divide */
|
|
|
|
volatile int tmp_ival = 0;
|
|
|
|
int
|
|
muldiv (int n)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of muldiv", NULL);
|
|
do
|
|
{
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
for (int j = 0; j < 1000; j++)
|
|
tmp_ival = j * i / (i + 1.0);
|
|
}
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "muldiv", NULL);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* =============================================================== */
|
|
/* underflow -- loop triggering arithmetic underflow */
|
|
volatile float tmp_fval;
|
|
|
|
int
|
|
underflow (int k)
|
|
{
|
|
float x, y;
|
|
long long count = 0;
|
|
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of underflow", NULL);
|
|
do
|
|
{
|
|
x = 1.e-20;
|
|
y = 1.e-20;
|
|
for (int j = 0; j < 50000; j++)
|
|
tmp_fval = x * y;
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "underflow", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* naptime -- spend time in the system sleeping */
|
|
int
|
|
naptime (int k)
|
|
{
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of naptime", NULL);
|
|
if (k == 0)
|
|
{
|
|
k = testtime;
|
|
if (k < 1)
|
|
k = 1;
|
|
}
|
|
for (int i = 0; i < k; i++)
|
|
sleep (1);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "naptime", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* recurse -- loop to show recursion */
|
|
int real_recurse (int, int); /* real routine to do recursion */
|
|
|
|
int
|
|
recurse (int k)
|
|
{
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of recurse", NULL);
|
|
if (k == 0)
|
|
k = 80;
|
|
(void) real_recurse (0, k);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "recurse", NULL);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
recursedeep (int k)
|
|
{
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of recursedeep", NULL);
|
|
if (k == 0)
|
|
k = 500;
|
|
(void) real_recurse (0, k);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "recursedeep", NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int rec_count = 0;
|
|
|
|
int
|
|
real_recurse (int i, int imax)
|
|
{
|
|
if (i == imax)
|
|
{
|
|
volatile float x;
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
do
|
|
{
|
|
x = 0.0;
|
|
for (int j = 0; j < 10000000; j++)
|
|
x = x + 1.0;
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
return rec_count;
|
|
}
|
|
else
|
|
{
|
|
real_recurse (i + 1, imax);
|
|
rec_count++;
|
|
return rec_count;
|
|
}
|
|
}
|
|
|
|
/* gpf -- simple example showing the gprof fallacy */
|
|
float gpf_a (void);
|
|
float gpf_b (void);
|
|
float gpf_work (int);
|
|
|
|
#define MAX_GPF_WORK_COUNT 1000
|
|
|
|
int
|
|
gpf (int k)
|
|
{
|
|
long long count = 0;
|
|
float x = -1.0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of gpf", NULL);
|
|
|
|
do
|
|
{
|
|
x = gpf_a ();
|
|
x += gpf_b ();
|
|
count++;
|
|
if (count == MAX_GPF_WORK_COUNT)
|
|
fprintf (stderr, "Execution error -- %lld iterations of gpf_[ab]; possible compiler bug\n",
|
|
count);
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
if (x < 0.0)
|
|
fprintf (stderr, "Execution error -- x < 0.0; possible compiler bug (x = %f)\n", x);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "gpf - total", NULL);
|
|
return 0;
|
|
}
|
|
|
|
float
|
|
gpf_a ()
|
|
{
|
|
float x = -1.0;
|
|
for (int i = 0; i < 9; i++)
|
|
x += gpf_work (1);
|
|
return x;
|
|
}
|
|
|
|
float
|
|
gpf_b ()
|
|
{
|
|
float x = -1.0;
|
|
x = gpf_work (10);
|
|
return x;
|
|
}
|
|
|
|
float
|
|
gpf_work (int amt)
|
|
{
|
|
volatile float x = 0.0;
|
|
int imax = 4 * amt * amt;
|
|
for (int i = 0; i < imax; i++)
|
|
{
|
|
x = 0.0;
|
|
for (int j = 0; j < 200000; j++)
|
|
x = x + 1.0;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
/* bounce -- example of indirect recursion */
|
|
void bounce_a (int, int);
|
|
void bounce_b (int, int);
|
|
|
|
int
|
|
bounce (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of bounce", NULL);
|
|
if (k == 0)
|
|
k = 20;
|
|
do
|
|
{
|
|
bounce_a (0, k);
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "bounce", NULL);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
bounce_a (int i, int imax)
|
|
{
|
|
if (i == imax)
|
|
{
|
|
volatile float x = 0.0;
|
|
for (int k = 0; k < 8; k++)
|
|
{
|
|
for (int j = 0; j < 2000000; j++)
|
|
x = x + 1.0;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
bounce_b (i, imax);
|
|
}
|
|
|
|
void
|
|
bounce_b (int i, int imax)
|
|
{
|
|
bounce_a (i + 1, imax);
|
|
return;
|
|
}
|
|
|
|
/* =============================================================== */
|
|
|
|
/* sched -- spend time calling sched_yield() */
|
|
|
|
int
|
|
sched (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of sched", NULL);
|
|
if (k == 0)
|
|
{
|
|
k = testtime;
|
|
if (k < 1)
|
|
k = 1;
|
|
}
|
|
do
|
|
{
|
|
for (int i = 0; i < 1000000; i++)
|
|
sched_yield ();
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sched", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* synccall -- spend time calling sync() */
|
|
int
|
|
synccall (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of synccall", NULL);
|
|
if (k == 0)
|
|
{
|
|
k = testtime;
|
|
if (k < 1)
|
|
k = 1;
|
|
}
|
|
do
|
|
{
|
|
sync ();
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld sync() calls\n", count);
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "synccall", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* sigtime -- spend time in a signal handler */
|
|
static void sigtime_handler (int);
|
|
|
|
int
|
|
sigtime (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of sigtime", NULL);
|
|
|
|
/* set up the signal handler */
|
|
sigset (SIGHUP, sigtime_handler);
|
|
do
|
|
{
|
|
kill (getpid (), SIGHUP);
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
sigset (SIGHUP, SIG_DFL);
|
|
fprintf (stderr, " Sent %lld SIGHUP signals\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigtime", NULL);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
sigtime_handler (int sig)
|
|
{
|
|
volatile int x;
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
x = 0;
|
|
for (int j = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* systime -- spend time in a few system calls */
|
|
int
|
|
systime (int k)
|
|
{
|
|
struct timeval ttime;
|
|
int j;
|
|
long long count = 0;
|
|
double t = testtime / 5;
|
|
if (t < 1.0)
|
|
t = 1.0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t rstart = start;
|
|
hrtime_t vstart = getmyvtime ();
|
|
hrtime_t rvstart = vstart;
|
|
|
|
/* Log the event */
|
|
wlog ("start of systime", NULL);
|
|
|
|
/* do gettimeofday calls */
|
|
do
|
|
{
|
|
for (j = 0; j < 30000; j++)
|
|
{
|
|
(void) gettimeofday (&ttime, NULL);
|
|
}
|
|
count++;
|
|
}
|
|
while (start + t * 1e9 > gethrtime ());
|
|
|
|
hrtime_t end = gethrtime ();
|
|
hrtime_t vend = getmyvtime ();
|
|
fprintf (stderr, " Performed %lld while-loop iterations gettimeofday\n", count);
|
|
whrvlog (end - start, vend - vstart, "systime -- 10**6 gettimeofday", NULL);
|
|
|
|
/* do gethrtime calls */
|
|
start = gethrtime ();
|
|
vstart = getmyvtime ();
|
|
count = 0;
|
|
do
|
|
{
|
|
(void) gethrtime ();
|
|
count++;
|
|
}
|
|
while (start + t * 1e9 > gethrtime ());
|
|
|
|
end = gethrtime ();
|
|
vend = getmyvtime ();
|
|
fprintf (stderr, " Performed %lld while-loop iterations gethrtime\n", count);
|
|
whrvlog ((end - start), (vend - vstart), "systime -- 10**6 gethrtime", NULL);
|
|
|
|
/* do pairs of gethrtime calls */
|
|
start = gethrtime ();
|
|
vstart = getmyvtime ();
|
|
|
|
count = 0;
|
|
do
|
|
{
|
|
for (j = 0; j < 30000; j++)
|
|
{
|
|
(void) gethrtime ();
|
|
(void) gethrtime ();
|
|
}
|
|
count++;
|
|
}
|
|
while (start + t * 1e9 > gethrtime ());
|
|
|
|
end = gethrtime ();
|
|
vend = getmyvtime ();
|
|
fprintf (stderr, " Performed %lld while-loop iterations pairs of gethrtime\n",
|
|
count);
|
|
whrvlog (end - start, vend - vstart, "systime -- 10**6 pairs of gethrtime",
|
|
NULL);
|
|
|
|
/* do gethrvtime calls */
|
|
start = gethrtime ();
|
|
vstart = getmyvtime ();
|
|
|
|
count = 0;
|
|
do
|
|
{
|
|
for (j = 0; j < 30000; j++)
|
|
{
|
|
(void) gethrvtime ();
|
|
}
|
|
count++;
|
|
}
|
|
while (start + t * 1e9 > gethrtime ());
|
|
|
|
end = gethrtime ();
|
|
vend = getmyvtime ();
|
|
fprintf (stderr, " Performed %lld while-loop iterations gethrvtime\n", count);
|
|
whrvlog (end - start, vend - vstart, "systime -- 10**6 gethrvtime", NULL);
|
|
|
|
/* do getrusage calls */
|
|
start = gethrtime ();
|
|
vstart = getmyvtime ();
|
|
|
|
count = 0;
|
|
do
|
|
{
|
|
for (j = 0; j < 30000; j++)
|
|
{
|
|
struct rusage rusage;
|
|
(void) getrusage (RUSAGE_SELF, &rusage);
|
|
}
|
|
count++;
|
|
}
|
|
while (start + t * 1e9 > gethrtime ());
|
|
|
|
end = gethrtime ();
|
|
vend = getmyvtime ();
|
|
fprintf (stderr, " Performed %lld while-loop iterations getrusage\n", count);
|
|
whrvlog ((end - start), (vend - vstart), "systime -- 10**6 getrusage", NULL);
|
|
whrvlog ((gethrtime () - rstart), (getmyvtime () - rvstart), "systime", NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* unwindcases -- test various unwind corner cases */
|
|
static void unwindcases_handler (int);
|
|
|
|
int
|
|
unwindcases (int k)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of unwindcases", NULL);
|
|
|
|
/* set up the signal handler */
|
|
sigset (SIGHUP, unwindcases_handler);
|
|
|
|
/* initialize the new signal mask */
|
|
sigset_t new_mask;
|
|
sigset_t old_mask;
|
|
sigfillset (&new_mask);
|
|
sigdelset (&new_mask, SIGHUP);
|
|
|
|
/* block all signals except SIGHUP*/
|
|
sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
|
|
do
|
|
{
|
|
kill (getpid (), SIGHUP);
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
sigprocmask (SIG_SETMASK, &old_mask, NULL);
|
|
sigset (SIGHUP, SIG_DFL);
|
|
fprintf (stderr, " Sent %lld SIGHUP signals\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "unwindcases", NULL);
|
|
return 0;
|
|
}
|
|
|
|
#define unwindcases_memcpy memcpy
|
|
#define unwindcases_memset memset
|
|
#define unwindcases_memnum (4096)
|
|
|
|
static char unwindcases_array[4097];
|
|
static volatile int srcind = 1024;
|
|
|
|
static void
|
|
unwindcases_handler (int sig)
|
|
{
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
for (int j = 0; j < 1000; j++)
|
|
{
|
|
unwindcases_memset ((void*) unwindcases_array, 0, unwindcases_memnum);
|
|
for (int k = 0; k < 10; k++)
|
|
{
|
|
unwindcases_array[k] = unwindcases_array[srcind];
|
|
unwindcases_array[k + srcind / 4] = 0;
|
|
unwindcases_array[k] = unwindcases_array[strlen (unwindcases_array + k) + 1];
|
|
}
|
|
unwindcases_memcpy ((void*) unwindcases_array,
|
|
(void*) (unwindcases_array + 4096 / 2),
|
|
unwindcases_memnum / 2);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* tailcallopt -- call routines that would be tail-call optimized when
|
|
* compiled with optimization
|
|
*/
|
|
void tailcall_a (void);
|
|
void tailcall_b (void);
|
|
void tailcall_c (void);
|
|
|
|
int
|
|
tailcallopt (int n)
|
|
{
|
|
long long count = 0;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of tailcallopt", NULL);
|
|
do
|
|
{
|
|
tailcall_a ();
|
|
count++;
|
|
}
|
|
while (start + testtime * 1e9 > gethrtime ());
|
|
|
|
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "tailcallopt", NULL);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
tailcall_a ()
|
|
{
|
|
volatile float x = 0.0;
|
|
for (int j = 0; j < 4000000; j++)
|
|
x = x + 1.0;
|
|
tailcall_b ();
|
|
}
|
|
|
|
void
|
|
tailcall_b ()
|
|
{
|
|
volatile float x = 0.0;
|
|
for (int j = 0; j < 4000000; j++)
|
|
x = x + 1.0;
|
|
tailcall_c ();
|
|
}
|
|
|
|
void
|
|
tailcall_c ()
|
|
{
|
|
volatile float x = 0.0;
|
|
for (int j = 0; j < 4000000; j++)
|
|
x = x + 1.0;
|
|
}
|
|
|
|
int
|
|
itimer_realprof (int k) /* mess with itimer ITIMER_REALPROF */
|
|
{
|
|
struct itimerval tval;
|
|
int retval;
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* set an itimer */
|
|
if (k != 0)
|
|
{
|
|
wlog ("start of itimer_realprof", NULL);
|
|
tval.it_interval.tv_sec = 1;
|
|
tval.it_interval.tv_usec = 300000;
|
|
tval.it_value = tval.it_interval;
|
|
}
|
|
else
|
|
{
|
|
wlog ("start of itimer_realprof(0)", NULL);
|
|
tval.it_interval.tv_sec = 0;
|
|
tval.it_interval.tv_usec = 0;
|
|
tval.it_value = tval.it_interval;
|
|
}
|
|
retval = setitimer (ITIMER_REALPROF, &tval, 0);
|
|
if (retval != 0)
|
|
fprintf (stderr, "setitimer(ITIMER_REALPROF) got %d returned: %s\n",
|
|
retval, strerror (errno));
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "itimer_realprof",
|
|
NULL);
|
|
return 0;
|
|
}
|
|
|
|
static struct sigaction old_sigprof_handler;
|
|
static void sigprof_handler (int sig);
|
|
static void sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap);
|
|
|
|
int
|
|
sigprof (int k)
|
|
{
|
|
struct sigaction act;
|
|
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of sigprof", NULL);
|
|
|
|
/* query current handler */
|
|
if (sigaction (SIGPROF, NULL, &act) == -1)
|
|
printf ("\tFailed current sigaction query: %s\n", strerror (errno));
|
|
else
|
|
printf ("\tCurrently installed sigaction 0x%p\n", act.sa_sigaction);
|
|
|
|
sigemptyset (&act.sa_mask);
|
|
act.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
act.sa_sigaction = (void(*)(int, siginfo_t*, void*))sigprof_sigaction;
|
|
|
|
if (k != 0)
|
|
{
|
|
/* install with deferral to original handler (if set) */
|
|
if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
|
|
printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
|
|
if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_DFL)
|
|
{
|
|
old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
|
|
printf ("\tReplaced default sigprof handler with 0x%p\n",
|
|
act.sa_sigaction);
|
|
}
|
|
else
|
|
printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
|
|
old_sigprof_handler.sa_sigaction, act.sa_sigaction);
|
|
}
|
|
else
|
|
{
|
|
/* installed without deferral to any original handler */
|
|
old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
|
|
if (sigaction (SIGPROF, &act, NULL) == -1)
|
|
printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
|
|
else
|
|
printf ("\tInstalled sigprof_sigaction 0x%p\n", act.sa_sigaction);
|
|
}
|
|
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprof", NULL);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
sigprofh (int k)
|
|
{
|
|
struct sigaction act;
|
|
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
/* Log the event */
|
|
wlog ("start of sigprofh", NULL);
|
|
|
|
/* query current handler */
|
|
if (sigaction (SIGPROF, NULL, &act) == -1)
|
|
printf ("\tFailed current sigaction query: %s\n", strerror (errno));
|
|
else
|
|
printf ("\tCurrently installed handler 0x%p\n", act.sa_handler);
|
|
|
|
sigemptyset (&act.sa_mask);
|
|
act.sa_flags = SA_RESTART;
|
|
act.sa_handler = sigprof_handler;
|
|
if (k != 0)
|
|
{
|
|
/* install with deferral to original handler (if set) */
|
|
if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
|
|
printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
|
|
if (old_sigprof_handler.sa_handler == SIG_DFL)
|
|
{
|
|
old_sigprof_handler.sa_handler = SIG_IGN;
|
|
printf ("\tReplaced default sigprof handler with 0x%p\n",
|
|
act.sa_handler);
|
|
}
|
|
else
|
|
printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
|
|
old_sigprof_handler.sa_handler, act.sa_handler);
|
|
}
|
|
else
|
|
{
|
|
/* installed without deferral to any original handler */
|
|
old_sigprof_handler.sa_handler = SIG_IGN;
|
|
if (sigaction (SIGPROF, &act, NULL) == -1)
|
|
printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
|
|
else
|
|
printf ("\tInstalled sigprof_handler 0x%p\n", act.sa_handler);
|
|
}
|
|
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprofh", NULL);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
sigprof_handler (int sig)
|
|
{
|
|
int j;
|
|
volatile int x;
|
|
|
|
hrtime_t now = gethrtime ();
|
|
if (old_sigprof_handler.sa_handler == SIG_IGN)
|
|
{
|
|
whrvlog (now, 0, "sigprof_handler (ign)", NULL);
|
|
for (j = 0, x = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
}
|
|
else
|
|
{
|
|
whrvlog (now, 0, "sigprof_handler (fwd)", NULL);
|
|
for (j = 0, x = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
/* forward signal to original handler */
|
|
if (old_sigprof_handler.sa_flags & SA_SIGINFO)
|
|
(old_sigprof_handler.sa_sigaction)(sig, NULL, NULL);
|
|
else
|
|
(old_sigprof_handler.sa_handler)(sig);
|
|
printf ("\tReturned from original sigprof handler!\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap)
|
|
{
|
|
int j;
|
|
volatile int x;
|
|
|
|
hrtime_t now = gethrtime ();
|
|
if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_IGN)
|
|
{
|
|
whrvlog (now, 0, "sigprof_sigaction (ign)", NULL);
|
|
for (j = 0, x = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
}
|
|
else
|
|
{
|
|
whrvlog (now, 0, "sigprof_sigaction (fwd)", NULL);
|
|
for (j = 0, x = 0; j < 1000000; j++)
|
|
x = x + 1;
|
|
/* forward signal to original handler */
|
|
if (old_sigprof_handler.sa_flags & SA_SIGINFO)
|
|
(old_sigprof_handler.sa_sigaction)(sig, sip, uap);
|
|
else
|
|
(old_sigprof_handler.sa_handler)(sig);
|
|
printf ("\tReturned from original sigprof sigaction!\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
Need to consider various signal handler / sigaction scenarios :
|
|
|
|
1. A handler is already installed, and a new handler is being installed.
|
|
(The original handler may be one of the defaults.)
|
|
2. A handler is already installed, and a sigaction is being installed.
|
|
3. A sigaction is already installed, and a new sigaction is being installed.
|
|
4. A sigaction is already installed, and a handler is being installed.
|
|
#endif
|
|
|
|
int
|
|
do_chdir (int k) /* switch to a new working directory */
|
|
{
|
|
char *workdir;
|
|
char *workdir0 = "/tmp";
|
|
char *workdir1 = "/";
|
|
char currworkdir[MAXPATHLEN];
|
|
|
|
hrtime_t start = gethrtime ();
|
|
hrtime_t vstart = getmyvtime ();
|
|
|
|
if (k != 0)
|
|
{
|
|
wlog ("start of do_chdir(X)", NULL);
|
|
workdir = workdir1;
|
|
}
|
|
else
|
|
{
|
|
wlog ("start of do_chdir", NULL);
|
|
workdir = workdir0;
|
|
}
|
|
|
|
if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
|
|
fprintf (stderr, "old getcwd failed: %s\n", strerror (errno));
|
|
else
|
|
printf ("old getcwd returned \"%s\"\n", currworkdir);
|
|
|
|
if (chdir (workdir) != 0)
|
|
fprintf (stderr, "chdir(\"%s\") failed: %s\n", workdir, strerror (errno));
|
|
|
|
if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
|
|
fprintf (stderr, "new getcwd failed: %s\n", strerror (errno));
|
|
else
|
|
printf ("new getcwd returned \"%s\"\n", currworkdir);
|
|
whrvlog (gethrtime () - start, getmyvtime () - vstart, "do_chdir", NULL);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
do_exec (int k) /* do an exec() call */
|
|
{
|
|
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
|
|
if (k >= 0)
|
|
{
|
|
wlog ("about to exec", NULL);
|
|
execl ("./synprog", "synprog", "gpf.cpu.sx", NULL);
|
|
wlog ("exec failed!!!", NULL);
|
|
}
|
|
else
|
|
{
|
|
wlog ("about to execX", NULL);
|
|
execl ("./no-such-file", "no-such-file", "gpf.cpu.sx", NULL);
|
|
wlog ("execX failed (as expected)", NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* preloading libcollector to a setuid executable will fail! */
|
|
const char *cmdX = "/random/crash_n_burn";
|
|
const char *cmd0 = "/bin/uptime";
|
|
const char *cmd1 = "/bin/echo hello world!";
|
|
const char *cmd2 = "/usr/bin/sleep 5";
|
|
const char *cmd3 = "/usr/bin/sleep 5; /bin/echo hello world!";
|
|
const char *cmd4 = "/usr/bin/sleep 2; /bin/echo hello world!; /usr/bin/sleep 2";
|
|
const char *cmd5 = "/bin/date; /bin/sleep 2; /bin/date; /bin/sleep 2; /bin/date";
|
|
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";
|
|
const char *cmd7 = "synprog";
|
|
const char *cmd8 = "synprog icpu.sx 2>&1";
|
|
|
|
int
|
|
do_popen (int k) /* do a popen() call */
|
|
{
|
|
int ret;
|
|
FILE *fd;
|
|
char buf[BUFSIZ];
|
|
const char *mode = "r";
|
|
|
|
/* XXXX popen() will temporarily vfork+exec() a new child */
|
|
/* but there will be no accounting for it, unless it's synprog! */
|
|
sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
|
|
|
|
/* ignore reapchild to catch child here */
|
|
(void) sigset (SIGCHLD, 0);
|
|
if (k >= 0)
|
|
{
|
|
wlog ("about to popen", NULL);
|
|
fd = popen (cmd8, mode);
|
|
}
|
|
else
|
|
{
|
|
wlog ("about to popenX!", NULL);
|
|
fd = popen (cmdX, mode);
|
|
}
|
|
if (fd == NULL)
|
|
printf ("do_popen failed: %s\n", strerror (errno));
|
|
else
|
|
printf ("do_popen succeeded: fileno=%d\n", fileno (fd));
|
|
|
|
/* restore pre-popen environment */
|
|
sprintf (new_name, "_SP_NAME=%s", acct_file);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
|
|
|
|
if (fd != NULL)
|
|
{
|
|
while (fgets (buf, BUFSIZ, fd) != NULL)
|
|
printf ("& %s", buf);
|
|
|
|
if ((ret = pclose (fd)) == -1)
|
|
printf ("do_popen pclose error: %s\n", strerror (errno));
|
|
else
|
|
printf ("do_popen pclose returned %d\n", ret);
|
|
}
|
|
|
|
/* set up to reap any children */
|
|
(void) sigset (SIGCHLD, reapchild);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
do_system (int k) /* do a system() call */
|
|
{
|
|
int ret;
|
|
|
|
/* XXXX system() will temporarily vfork+exec() a new child */
|
|
/* but there will be no accounting for it, unless it's synprog! */
|
|
sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
|
|
|
|
if (k >= 0)
|
|
{
|
|
wlog ("about to system", NULL);
|
|
ret = system (cmd8);
|
|
}
|
|
else
|
|
{
|
|
wlog ("about to systemX!", NULL);
|
|
ret = system (cmd0);
|
|
}
|
|
if (ret < 0)
|
|
printf ("do_system failed: %s\n", strerror (errno));
|
|
else
|
|
printf ("do_system succeeded, ret=%d\n", ret);
|
|
|
|
/* restore pre-system environment */
|
|
sprintf (new_name, "_SP_NAME=%s", acct_file);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
do_forkexec (int k) /* do a fork()+exec() call combo */
|
|
{
|
|
int ret, pid;
|
|
int status = -1;
|
|
char arg0[128], arg1[128];
|
|
arg1[0] = (char) 0;
|
|
|
|
/* ignore reapchild to catch child here */
|
|
(void) sigset (SIGCHLD, 0);
|
|
|
|
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
|
|
if ((pid = fork ()) == 0)
|
|
{
|
|
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
|
|
strcpy (acct_file, child_name);
|
|
acct_init (acct_file);
|
|
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
|
|
if (putenv (new_name))
|
|
{
|
|
fprintf (stderr, "Failed to name fork child! %s\n", strerror (errno));
|
|
}
|
|
(void) execl (arg0, "fork+exec", arg1[0] ? arg1 : NULL, NULL);
|
|
fprintf (stderr, "fork execl failed! %s\n", strerror (errno));
|
|
_exit (127);
|
|
}
|
|
else if (pid == -1)
|
|
fprintf (stderr, "fork failed! %s\n", strerror (errno));
|
|
else
|
|
{
|
|
do
|
|
{
|
|
ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
|
|
}
|
|
while ((ret == -1) && (errno == EINTR));
|
|
|
|
if (ret == -1)
|
|
fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
|
|
#if 0
|
|
else
|
|
{
|
|
if (WIFEXITED (status))
|
|
printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
|
|
if (WIFSTOPPED (status))
|
|
printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
|
|
if (WIFSIGNALED (status))
|
|
printf ("WTERMSIG=%d\n", WTERMSIG (status));
|
|
if (WIFCONTINUED (status))
|
|
printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
|
|
}
|
|
#endif
|
|
if (WIFEXITED (status))
|
|
printf ("do_forkexec succeeded: child exit status=%d\n",
|
|
WEXITSTATUS (status));
|
|
else
|
|
printf ("do_forkexec failed! status=%d\n", status);
|
|
}
|
|
|
|
/* set up to reap any children */
|
|
(void) sigset (SIGCHLD, reapchild);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
do_vforkexec (int k) /* do a vfork()+exec() call combo */
|
|
{
|
|
int ret, pid;
|
|
int status = 1;
|
|
char arg0[128], arg1[128];
|
|
arg1[0] = (char) 0;
|
|
/* ignore reapchild to catch child here */
|
|
(void) sigset (SIGCHLD, 0);
|
|
|
|
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
|
|
|
|
if ((pid = vfork ()) == 0)
|
|
{
|
|
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
|
|
strcpy (acct_file, child_name);
|
|
acct_init (acct_file);
|
|
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
|
|
if (putenv (new_name))
|
|
fprintf (stderr, "Failed to name vfork child! %s\n", strerror (errno));
|
|
(void) execl (arg0, "vfork+exec", arg1[0] ? arg1 : NULL, NULL);
|
|
printf ("vfork execl failed! %s\n", strerror (errno));
|
|
_exit (127);
|
|
}
|
|
else if (pid == -1)
|
|
fprintf (stderr, "vfork failed! %s\n", strerror (errno));
|
|
else
|
|
{
|
|
do
|
|
{
|
|
ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
|
|
}
|
|
while (ret == -1 && errno == EINTR);
|
|
|
|
if (ret == -1)
|
|
fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
|
|
#if 0
|
|
else
|
|
{
|
|
if (WIFEXITED (status))
|
|
printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
|
|
if (WIFSTOPPED (status))
|
|
printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
|
|
if (WIFSIGNALED (status))
|
|
printf ("WTERMSIG=%d\n", WTERMSIG (status));
|
|
if (WIFCONTINUED (status))
|
|
printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
|
|
}
|
|
#endif
|
|
if (WIFEXITED (status))
|
|
printf ("do_vforkexec succeeded: child exit status=%d\n",
|
|
WEXITSTATUS (status));
|
|
else
|
|
printf ("do_vforkexec failed! status=%d\n", status);
|
|
}
|
|
|
|
/* set up to reap any children */
|
|
(void) sigset (SIGCHLD, reapchild);
|
|
return 0;
|
|
}
|