Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
This example introduces
   interrupts and signal handlers
   signal()                -- standard interface to signal handlers
   pmc_sighandler_t        -- pointer to a signal handler
   pmc_catch_signals()     -- install signal handlers
   pmc_restore_signals()   -- reinstall signal handlers

Previous example       -- report generation
Download this example: menu10.c, menu11.c
Return to Main Menu


Compile with gcc -o menu10 -O menu10.c gcc -o menu11 -O `pmc_options` menu11.c -lpmc Try these examples: menu10 menu10 [and type control-C after a few seconds] menu11 -g 0 menu11 -g 1 menu11 -g 1 [and type control-C after a few seconds]
/* menu10: demonstrate use of ANSI C signal handlers */ #include <stdio.h> /* for signal() with BSD behavior, on Linux 2.0.28 but not 2.0.36, * #define __USE_BSD_SIGNAL */ #include <signal.h> /* catch these signals */ static int signals[] = { SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGTERM }; /* cannot catch SIGKILL or SIGSTOP */ /* number of signals being caught */ #define signals_n (sizeof(signals) / sizeof(signals[0])) /* pointer to a signal handler */ typedef void (*sighandler_t)(int); /* pointers to original signal handlers */ static sighandler_t sig[signals_n]; static void signal_handler(int signal_number) { /* print some useful information */ printf("signal %d received\n", signal_number); /* pick one */ /* reset the signal to its default behavior */ /* ANSI C does this automatically */ signal(signal_number, SIG_DFL); /* reset the signal to its previous behavior */ signal(signal_number, sig[signal_number]); /* reset the signal to its current behavior */ /* BSD does this automatically */ signal(signal_number, signal_handler); exit(signal_number); } int main(int argc, char *argv[]) { int i; for (i = 0; i < signals_n; i++) { sig[i] = signal(signals[i], signal_handler); if (sig[i] == SIG_ERR) { char buffer[128]; sprintf(buffer, "%s: signal(%d, signal_handler) failed", argv[0], signals[i]); perror(buffer); exit(1); } } { /* do something */ double j, k = 0, lim = 100000000; for (j = 0; j < lim; j++) { k += j; } } exit(0); }
/* menu11: demonstrate use of ANSI C signal handlers with the PMC library */ #include <pmc_lib.h> /* for signal() with BSD behavior, on Linux 2.0.28 but not 2.0.36, * #define __USE_BSD_SIGNAL */ #include <signal.h> /* catch these signals */ static int signals[] = { SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGTERM }; /* cannot catch SIGKILL or SIGSTOP */ /* number of signals being caught */ #define signals_n (sizeof(signals) / sizeof(signals[0])) /* these are global for use by the signal handler */ pmc_control_t Ctl; int Argc; char ** Argv; static void signal_handler(int signal_number) { /* print some useful information */ printf("signal %d received\n", signal_number); pmc_print_results(Argc, Argv, &Ctl); /* pick one */ /* reset the signal to its default behavior */ /* ANSI C does this automatically */ signal(signal_number, SIG_DFL); /* reset the signal to its previous behavior */ { int s = signal_number; pmc_restore_signals(1, &s); } /* reset the signal to its current behavior */ /* BSD does this automatically */ signal(signal_number, signal_handler); /* force a call to pmc_close() */ exit(signal_number); } int main(int argc, char *argv[]) { pmc_data_t t0, t1; pmc_cycles_t elapsed; int i; Argc = argc; Argv = argv; Ctl = pmc_control_null; pmc_catch_signals(signals_n, signals, signal_handler); if (pmc_getargs(stderr, argv[0], &argc, &argv, &Ctl) == FALSE) { exit(1); } if (pmc_open(0) == FALSE) /* open /dev/pmc */ { exit(1); } for (i = 0; i < Ctl.event_pairs * Ctl.replication; i++) { if (pmc_select(&Ctl.counters[i]) == FALSE) { printf("pmc_select() failed\n"); exit(1); } pmc_read(&t0); { /* do something */ double j, k = 0, lim = 100000000; for (j = 0; j < lim; j++) { k += j; } } pmc_read(&t1); elapsed = pmc_accumulate(&Ctl.counters[i], &t1, &t0); } pmc_close(); /* close /dev/pmc */ pmc_print_results(Argc, Argv, &Ctl); pmc_restore_signals(signals_n, signals); exit(0); }
Synopsis typedef void (*pmc_sighandler_t)(int); /* pointer to a signal handler */ void pmc_catch_signals(int n, int number[], pmc_sighandler_t handler); void pmc_restore_signals(int n, int number[]);
The basic problem is to get some useful information from the program if it is terminated early, usually by control-C. The solution is to write and install a signal handler that will be invoked after some signal is received. The signal handler must call pmc_close() directly, or indirectly through exit(). rabbit, through pmc_run_command(), will catch these signals, for which the default action is to terminate the process: SIGALRM timer signal from alarm(2) SIGHUP hangup on controlling terminal or death of controlling process SIGINT interrupt from keyboard (control-C) SIGQUIT quit from keyboard SIGTERM termination signal SIGUSR1 user-defined signal 1 (used locally at Ames Lab before a shutdown) SIGALRM is used by an interval timer in the parent process for sampling the performance counters. The second group will simply allow a report to be generated by pmc_print_results() before termination. The remaining signals are described in the signal(7) man page. The BSD semantics are used in pmc_lib.h; see signal(2). pmc_catch_signals() takes a list of signals, and associates each with the same signal handler. pmc_restore_signals() can be used with the same list to reinstall the previous signal handler for those signals. If pmc_catch_signals() or pmc_restore_signals() fails to install or reinstall a signal handler, it will quietly skip that one. This is only a matter of convenience, and there is no obligation to use these functions. Remember, any signal handler you write for use with the PMC library should call pmc_close(), or exit().
Man Pages alarm(2), signal(2), signal(7)

Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
Author: Don Heller, dheller@scl.ameslab.gov
Last revised: 2 August 2000