|
Packit Service |
a1973e |
/* $Id: signal.c,v 1.20 2005/04/08 14:37:55 mikpe Exp $
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* This test program illustrates how performance counter overflow
|
|
Packit Service |
a1973e |
* can be caught and sent to the process as a user-specified signal.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Limitations:
|
|
Packit Service |
a1973e |
* - Requires a 2.4 or newer kernel with local APIC support.
|
|
Packit Service |
a1973e |
* - Requires a CPU with a local APIC (P4, P6, K8, K7).
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Copyright (C) 2001-2004 Mikael Pettersson
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
#define __USE_GNU /* enable symbolic names for gregset_t[] indices */
|
|
Packit Service |
a1973e |
#include <sys/ucontext.h>
|
|
Packit Service |
a1973e |
#include <signal.h>
|
|
Packit Service |
a1973e |
#include <stdio.h>
|
|
Packit Service |
a1973e |
#include <stdlib.h>
|
|
Packit Service |
a1973e |
#include <string.h>
|
|
Packit Service |
a1973e |
#include "libperfctr.h"
|
|
Packit Service |
a1973e |
#include "arch.h"
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static struct vperfctr *vperfctr;
|
|
Packit Service |
a1973e |
static struct perfctr_info info;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void do_open(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
vperfctr = vperfctr_open();
|
|
Packit Service |
a1973e |
if( !vperfctr ) {
|
|
Packit Service |
a1973e |
perror("vperfctr_open");
|
|
Packit Service |
a1973e |
exit(1);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if( vperfctr_info(vperfctr, &info) < 0 ) {
|
|
Packit Service |
a1973e |
perror("vperfctr_info");
|
|
Packit Service |
a1973e |
exit(1);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if( !(info.cpu_features & PERFCTR_FEATURE_PCINT) )
|
|
Packit Service |
a1973e |
printf("PCINT not supported -- expect failure\n");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void on_sigio(int sig, siginfo_t *si, void *puc)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct ucontext *uc;
|
|
Packit Service |
a1973e |
unsigned long pc;
|
|
Packit Service |
a1973e |
unsigned int pmc_mask;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if( sig != SIGIO ) {
|
|
Packit Service |
a1973e |
printf("%s: unexpected signal %d\n", __FUNCTION__, sig);
|
|
Packit Service |
a1973e |
return;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if( si->si_code != SI_PMC_OVF ) {
|
|
Packit Service |
a1973e |
printf("%s: unexpected si_code #%x\n", __FUNCTION__, si->si_code);
|
|
Packit Service |
a1973e |
return;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if( (pmc_mask = si->si_pmc_ovf_mask) == 0 ) {
|
|
Packit Service |
a1973e |
printf("%s: overflow PMCs not identified\n", __FUNCTION__);
|
|
Packit Service |
a1973e |
return;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
uc = puc;
|
|
Packit Service |
a1973e |
pc = ucontext_pc(uc);
|
|
Packit Service |
a1973e |
if( !vperfctr_is_running(vperfctr) ) {
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* My theory is that this happens if a perfctr overflowed
|
|
Packit Service |
a1973e |
* at the very instruction for the VPERFCTR_STOP call.
|
|
Packit Service |
a1973e |
* Signal delivery is delayed until the kernel returns to
|
|
Packit Service |
a1973e |
* user-space, at which time VPERFCTR_STOP will already
|
|
Packit Service |
a1973e |
* have marked the vperfctr as stopped. In this case, we
|
|
Packit Service |
a1973e |
* cannot and must not attempt to IRESUME it.
|
|
Packit Service |
a1973e |
* This can be triggered by counting e.g. BRANCHES and setting
|
|
Packit Service |
a1973e |
* the overflow limit ridiculously low.
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
printf("%s: unexpected overflow from PMC set %#x at pc %#lx\n",
|
|
Packit Service |
a1973e |
__FUNCTION__, pmc_mask, pc);
|
|
Packit Service |
a1973e |
return;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
printf("%s: PMC overflow set %#x at pc %#lx\n", __FUNCTION__, pmc_mask, pc);
|
|
Packit Service |
a1973e |
if( vperfctr_iresume(vperfctr) < 0 ) {
|
|
Packit Service |
a1973e |
perror("vperfctr_iresume");
|
|
Packit Service |
a1973e |
abort();
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void do_sigaction(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct sigaction sa;
|
|
Packit Service |
a1973e |
memset(&sa, 0, sizeof sa);
|
|
Packit Service |
a1973e |
sa.sa_sigaction = on_sigio;
|
|
Packit Service |
a1973e |
sa.sa_flags = SA_SIGINFO;
|
|
Packit Service |
a1973e |
if( sigaction(SIGIO, &sa, NULL) < 0 ) {
|
|
Packit Service |
a1973e |
perror("sigaction");
|
|
Packit Service |
a1973e |
exit(1);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void do_control(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct vperfctr_control control;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
memset(&control, 0, sizeof control);
|
|
Packit Service |
a1973e |
do_setup(&info, &control.cpu_control);
|
|
Packit Service |
a1973e |
control.si_signo = SIGIO;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
printf("Control used:\n");
|
|
Packit Service |
a1973e |
perfctr_cpu_control_print(&control.cpu_control);
|
|
Packit Service |
a1973e |
printf("\n");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if( vperfctr_control(vperfctr, &control) < 0 ) {
|
|
Packit Service |
a1973e |
perror("vperfctr_control");
|
|
Packit Service |
a1973e |
exit(1);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void do_stop(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct sigaction sa;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if( vperfctr_stop(vperfctr) )
|
|
Packit Service |
a1973e |
perror("vperfctr_stop");
|
|
Packit Service |
a1973e |
memset(&sa, 0, sizeof sa);
|
|
Packit Service |
a1973e |
sa.sa_handler = SIG_DFL;
|
|
Packit Service |
a1973e |
if( sigaction(SIGIO, &sa, NULL) < 0 ) {
|
|
Packit Service |
a1973e |
perror("sigaction");
|
|
Packit Service |
a1973e |
exit(1);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define N 150
|
|
Packit Service |
a1973e |
static double v[N], w[N];
|
|
Packit Service |
a1973e |
static double it;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void do_dotprod(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
int i;
|
|
Packit Service |
a1973e |
double sum;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
sum = 0.0;
|
|
Packit Service |
a1973e |
for(i = 0; i < N; ++i)
|
|
Packit Service |
a1973e |
sum += v[i] * w[i];
|
|
Packit Service |
a1973e |
it = sum;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
int main(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
do_sigaction();
|
|
Packit Service |
a1973e |
do_open();
|
|
Packit Service |
a1973e |
do_control();
|
|
Packit Service |
a1973e |
do_dotprod();
|
|
Packit Service |
a1973e |
do_stop();
|
|
Packit Service |
a1973e |
return 0;
|
|
Packit Service |
a1973e |
}
|