|
Packit |
577717 |
/*
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* self_smpl_multi.c - multi-thread self-sampling program
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (c) 2008 Mark W. Krentel
|
|
Packit |
577717 |
* Contributed by Mark W. Krentel <krentel@cs.rice.edu>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
577717 |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
577717 |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
577717 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
577717 |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit |
577717 |
* subject to the following conditions:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit |
577717 |
* copies or substantial portions of the Software.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit |
577717 |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit |
577717 |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
577717 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
577717 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit |
577717 |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* This file is part of libpfm, a performance monitoring support library for
|
|
Packit |
577717 |
* applications on Linux.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Test perfmon overflow without PAPI.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Create a new thread, launch perfmon overflow counters in both
|
|
Packit |
577717 |
* threads, print the number of interrupts per thread and per second,
|
|
Packit |
577717 |
* and look for anomalous interrupts. Look for mismatched thread
|
|
Packit |
577717 |
* ids, bad message type, or failed pfm_restart().
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <sys/time.h>
|
|
Packit |
577717 |
#include <sys/types.h>
|
|
Packit |
577717 |
#include <err.h>
|
|
Packit |
577717 |
#include <errno.h>
|
|
Packit |
577717 |
#include <fcntl.h>
|
|
Packit |
577717 |
#include <pthread.h>
|
|
Packit |
577717 |
#include <signal.h>
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
#include <unistd.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <linux/unistd.h>
|
|
Packit |
577717 |
#include <perfmon/perfmon.h>
|
|
Packit |
577717 |
#include <perfmon/pfmlib.h>
|
|
Packit |
577717 |
#include "detect_pmcs.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PROGRAM_TIME 8
|
|
Packit |
577717 |
#define THRESHOLD 20000000
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int program_time = PROGRAM_TIME;
|
|
Packit |
577717 |
int threshold = THRESHOLD;
|
|
Packit |
577717 |
int signum = SIGIO;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MAX_FD 20
|
|
Packit |
577717 |
|
|
Packit |
577717 |
struct over_args {
|
|
Packit |
577717 |
pfmlib_event_t ev;
|
|
Packit |
577717 |
pfmlib_input_param_t inp;
|
|
Packit |
577717 |
pfmlib_output_param_t outp;
|
|
Packit |
577717 |
pfarg_pmr_t pc[PFMLIB_MAX_PMCS];
|
|
Packit |
577717 |
pfarg_pmd_attr_t pd[PFMLIB_MAX_PMDS];
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
pid_t tid;
|
|
Packit |
577717 |
pthread_t self;
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
struct over_args *fd2ov[MAX_FD];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
long count[MAX_FD];
|
|
Packit |
577717 |
long total[MAX_FD];
|
|
Packit |
577717 |
long iter[MAX_FD];
|
|
Packit |
577717 |
long mismatch[MAX_FD];
|
|
Packit |
577717 |
long bad_msg[MAX_FD];
|
|
Packit |
577717 |
long bad_restart[MAX_FD];
|
|
Packit |
577717 |
long ser_no = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pid_t
|
|
Packit |
577717 |
gettid(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#ifdef SYS_gettid
|
|
Packit |
577717 |
return (pid_t)syscall(SYS_gettid);
|
|
Packit |
577717 |
#elif defined(__NR_gettid)
|
|
Packit |
577717 |
return (pid_t)syscall(__NR_gettid);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
#error "Unable to implement gettid."
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
user_callback(int fd)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
count[fd]++;
|
|
Packit |
577717 |
total[fd]++;
|
|
Packit |
577717 |
ser_no++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
do_cycles(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct timeval start, last, now;
|
|
Packit |
577717 |
double x, sum;
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (fd = 0; fd < MAX_FD; fd++) {
|
|
Packit |
577717 |
if (fd2ov[fd] != NULL &&
|
|
Packit |
577717 |
pthread_equal(fd2ov[fd]->self, pthread_self())) {
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
gettimeofday(&start, NULL);
|
|
Packit |
577717 |
last = start;
|
|
Packit |
577717 |
count[fd] = 0;
|
|
Packit |
577717 |
total[fd] = 0;
|
|
Packit |
577717 |
iter[fd] = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
do {
|
|
Packit |
577717 |
sum = 1.0;
|
|
Packit |
577717 |
for (x = 1.0; x < 250000.0; x += 1.0)
|
|
Packit |
577717 |
sum += x;
|
|
Packit |
577717 |
if (sum < 0.0)
|
|
Packit |
577717 |
printf("==>> SUM IS NEGATIVE !! <<==\n");
|
|
Packit |
577717 |
iter[fd]++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
gettimeofday(&now, NULL);
|
|
Packit |
577717 |
if (now.tv_sec > last.tv_sec) {
|
|
Packit |
577717 |
printf("%ld: fd = %d, count = %4ld, iter = %4ld, rate = %ld/Kiter\n",
|
|
Packit |
577717 |
now.tv_sec - start.tv_sec, fd, count[fd], iter[fd],
|
|
Packit |
577717 |
(1000 * count[fd])/iter[fd]);
|
|
Packit |
577717 |
count[fd] = 0;
|
|
Packit |
577717 |
iter[fd] = 0;
|
|
Packit |
577717 |
last = now;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
} while (now.tv_sec < start.tv_sec + program_time);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define DPRINT(str) \
|
|
Packit |
577717 |
printf("(%s) ser = %ld, fd = %d, tid = %d, self = %p\n", \
|
|
Packit |
577717 |
str, ser_no, fd, tid, (void *)self)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
sigio_handler(int sig, siginfo_t *info, void *context)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
pid_t tid;
|
|
Packit |
577717 |
pthread_t self;
|
|
Packit |
577717 |
struct over_args *ov;
|
|
Packit |
577717 |
pfarg_msg_t msg;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* file descripor is the only reliable source of information
|
|
Packit |
577717 |
* to identify session from which the notification originated
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Depending on scheduling, the signal may not be processed by the
|
|
Packit |
577717 |
* thread which posted it, i.e., the thread which had the nortification
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* POSIX aysnchronous signals cannot be targeted to specific threads
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
fd = info->si_fd;
|
|
Packit |
577717 |
self = pthread_self();
|
|
Packit |
577717 |
tid = gettid();
|
|
Packit |
577717 |
ov = fd2ov[fd];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (fd < 0 || fd >= MAX_FD)
|
|
Packit |
577717 |
errx(1, "bad info.si_fd: %d", fd);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* current thread id may not always match the id associated with
|
|
Packit |
577717 |
* the dfile descriptor
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (tid != ov->tid || !pthread_equal(self, ov->self)) {
|
|
Packit |
577717 |
mismatch[fd]++;
|
|
Packit |
577717 |
DPRINT("bad thread");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_read(fd, 0, PFM_RW_PMD, &ov->pd[1], sizeof(pfarg_pmd_attr_t));
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* extract notification message
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (read(fd, &msg, sizeof(msg)) != sizeof(msg))
|
|
Packit |
577717 |
errx(1, "read from sigio fd failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* cannot be PFM_END_MSG starting with perfmon v2.8
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (msg.type == PFM_MSG_END) {
|
|
Packit |
577717 |
DPRINT("pfm_msg_end");
|
|
Packit |
577717 |
} else if (msg.type != PFM_MSG_OVFL) {
|
|
Packit |
577717 |
bad_msg[fd]++;
|
|
Packit |
577717 |
DPRINT("bad msg type");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
user_callback(fd);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* when session is not that of the current thread, pfm_restart() does
|
|
Packit |
577717 |
* not guarante that upon return monitoring will be resumed. There
|
|
Packit |
577717 |
* may be a delay due to scheduling.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (pfm_set_state(fd, 0, PFM_ST_RESTART) != 0) {
|
|
Packit |
577717 |
bad_restart[fd]++;
|
|
Packit |
577717 |
DPRINT("bad restart");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
overflow_start(struct over_args *ov, char *name)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i, fd, flags;
|
|
Packit |
577717 |
pfarg_sinfo_t sif;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(ov, 0, sizeof(struct over_args));
|
|
Packit |
577717 |
memset(&sif, 0, sizeof(sif));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_get_cycle_event(&ov->ev) != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
errx(1, "pfm_get_cycle_event failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ov->inp.pfp_event_count = 1;
|
|
Packit |
577717 |
ov->inp.pfp_dfl_plm = PFM_PLM3;
|
|
Packit |
577717 |
ov->inp.pfp_flags = 0;
|
|
Packit |
577717 |
ov->inp.pfp_events[0] = ov->ev;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd = pfm_create(0, &sif;;
|
|
Packit |
577717 |
if (fd < 0)
|
|
Packit |
577717 |
errx(1, "pfm_create_session failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd2ov[fd] = ov;
|
|
Packit |
577717 |
ov->fd = fd;
|
|
Packit |
577717 |
ov->tid = gettid();
|
|
Packit |
577717 |
ov->self = pthread_self();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
detect_unavail_pmu_regs(&sif, &ov->inp.pfp_unavail_pmcs, NULL);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_dispatch_events(&ov->inp, NULL, &ov->outp, NULL) != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
errx(1, "pfm_dispatch_events failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (i = 0; i < ov->outp.pfp_pmc_count; i++) {
|
|
Packit |
577717 |
ov->pc[i].reg_num = ov->outp.pfp_pmcs[i].reg_num;
|
|
Packit |
577717 |
ov->pc[i].reg_value = ov->outp.pfp_pmcs[i].reg_value;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
for (i = 0; i < ov->outp.pfp_pmd_count; i++) {
|
|
Packit |
577717 |
ov->pd[i].reg_num = ov->outp.pfp_pmds[i].reg_num;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ov->pd[0].reg_flags |= PFM_REGFL_OVFL_NOTIFY;
|
|
Packit |
577717 |
ov->pd[0].reg_value = - threshold;
|
|
Packit |
577717 |
ov->pd[0].reg_long_reset = - threshold;
|
|
Packit |
577717 |
ov->pd[0].reg_short_reset = - threshold;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_write(fd, 0, PFM_RW_PMC, ov->pc, ov->outp.pfp_pmc_count * sizeof(pfarg_pmr_t)))
|
|
Packit |
577717 |
errx(1, "pfm_write failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_write(fd, 0, PFM_RW_PMD_ATTR, ov->pd, ov->outp.pfp_pmd_count * sizeof(pfarg_pmd_attr_t)))
|
|
Packit |
577717 |
errx(1, "pfm_write(PMD) failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_attach(fd, 0, gettid()) != 0)
|
|
Packit |
577717 |
errx(1, "pfm_attach failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
flags = fcntl(fd, F_GETFL, 0);
|
|
Packit |
577717 |
if (fcntl(fd, F_SETFL, flags | O_ASYNC) < 0)
|
|
Packit |
577717 |
errx(1, "fcntl SETFL failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (fcntl(fd, F_SETOWN, gettid()) < 0)
|
|
Packit |
577717 |
errx(1, "fcntl SETOWN failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (fcntl(fd, F_SETSIG, signum) < 0)
|
|
Packit |
577717 |
errx(1, "fcntl SETSIG failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_set_state(fd, 0, PFM_ST_START))
|
|
Packit |
577717 |
errx(1, "pfm_set_state(start) failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf("launch %s: fd: %d, tid: %d, self: %p\n",
|
|
Packit |
577717 |
name, fd, ov->tid, (void *)ov->self);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
overflow_stop(struct over_args *ov)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (pfm_set_state(ov->fd, 0, PFM_ST_STOP))
|
|
Packit |
577717 |
errx(1, "pfm_set_state(stop) failed");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void *
|
|
Packit |
577717 |
my_thread(void *v)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct over_args ov;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
overflow_start(&ov, "side");
|
|
Packit |
577717 |
do_cycles();
|
|
Packit |
577717 |
overflow_stop(&ov);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return (NULL);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Program args: program_time, threshold, signum.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
main(int argc, char **argv)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pthread_t thr;
|
|
Packit |
577717 |
struct over_args ov;
|
|
Packit |
577717 |
struct sigaction sa;
|
|
Packit |
577717 |
sigset_t set;
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (argc < 2 || sscanf(argv[1], "%d", &program_time) < 1)
|
|
Packit |
577717 |
program_time = PROGRAM_TIME;
|
|
Packit |
577717 |
if (argc < 3 || sscanf(argv[2], "%d", &threshold) < 1)
|
|
Packit |
577717 |
threshold = THRESHOLD;
|
|
Packit |
577717 |
if (argc < 4 || sscanf(argv[3], "%d", &signum) < 1)
|
|
Packit |
577717 |
signum = SIGIO;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf("program_time = %d, threshold = %d, signum = %d\n",
|
|
Packit |
577717 |
program_time, threshold, signum);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (i = 0; i < MAX_FD; i++) {
|
|
Packit |
577717 |
fd2ov[i] = NULL;
|
|
Packit |
577717 |
mismatch[i] = 0;
|
|
Packit |
577717 |
bad_msg[i] = 0;
|
|
Packit |
577717 |
bad_restart[i] = 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(&sa, 0, sizeof(sa));
|
|
Packit |
577717 |
sigemptyset(&set);
|
|
Packit |
577717 |
sa.sa_sigaction = sigio_handler;
|
|
Packit |
577717 |
sa.sa_mask = set;
|
|
Packit |
577717 |
sa.sa_flags = SA_SIGINFO;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (sigaction(signum, &sa, NULL) != 0)
|
|
Packit |
577717 |
errx(1, "sigaction failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_initialize() != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
errx(1, "pfm_initialize failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf("\n");
|
|
Packit |
577717 |
if (pthread_create(&thr, NULL, my_thread, NULL) != 0)
|
|
Packit |
577717 |
errx(1, "pthread_create failed");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
overflow_start(&ov, "main");
|
|
Packit |
577717 |
do_cycles();
|
|
Packit |
577717 |
overflow_stop(&ov);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf("\n");
|
|
Packit |
577717 |
for (i = 0; i < MAX_FD; i++) {
|
|
Packit |
577717 |
if (fd2ov[i] != NULL) {
|
|
Packit |
577717 |
printf("total[%d] = %ld, mismatch[%d] = %ld, "
|
|
Packit |
577717 |
"bad_msg[%d] = %ld, bad_restart[%d] = %ld\n",
|
|
Packit |
577717 |
i, total[i], i, mismatch[i],
|
|
Packit |
577717 |
i, bad_msg[i], i, bad_restart[i]);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return (0);
|
|
Packit |
577717 |
}
|