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