|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* self_smpl_multi.c - multi-thread self-sampling program
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Copyright (c) 2009 Google, Inc
|
|
Packit Service |
a1973e |
* Modified by Stephane Eranian <eranian@gmail.com>
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Based on:
|
|
Packit Service |
a1973e |
* Copyright (c) 2008 Mark W. Krentel
|
|
Packit Service |
a1973e |
* Contributed by Mark W. Krentel <krentel@cs.rice.edu>
|
|
Packit Service |
a1973e |
* Modified by Stephane Eranian <eranian@gmail.com>
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit Service |
a1973e |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit Service |
a1973e |
* in the Software without restriction, including without limitation the rights
|
|
Packit Service |
a1973e |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit Service |
a1973e |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit Service |
a1973e |
* subject to the following conditions:
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit Service |
a1973e |
* copies or substantial portions of the Software.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit Service |
a1973e |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit Service |
a1973e |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit Service |
a1973e |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit Service |
a1973e |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit Service |
a1973e |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* This file is part of libpfm, a performance monitoring support library for
|
|
Packit Service |
a1973e |
* applications on Linux.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Test perfmon overflow without PAPI.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Create a new thread, launch perfmon overflow counters in both
|
|
Packit Service |
a1973e |
* threads, print the number of interrupts per thread and per second,
|
|
Packit Service |
a1973e |
* and look for anomalous interrupts. Look for mismatched thread
|
|
Packit Service |
a1973e |
* ids, bad message type, or failed pfm_restart().
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* self_smpl_multi is a test program to stress signal delivery in the context
|
|
Packit Service |
a1973e |
* of a multi-threaded self-sampling program which is common with PAPI and HPC.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* There is an issue with existing (as of 2.6.30) kernel which do not provide
|
|
Packit Service |
a1973e |
* a reliable way of having the signal delivered to the thread in which the
|
|
Packit Service |
a1973e |
* counter overflow occurred. This is problematic for many self-monitoring
|
|
Packit Service |
a1973e |
* program.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* This program demonstrates the issue by tracking the number of times
|
|
Packit Service |
a1973e |
* the signal goes to the wrong thread. The bad behavior is exacerbated
|
|
Packit Service |
a1973e |
* if the monitored threads, themselves, already use signals. Here we
|
|
Packit Service |
a1973e |
* use SIGLARM.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Note that kernel developers have been made aware of this problem and
|
|
Packit Service |
a1973e |
* a fix has been proposed. It introduces a new F_SETOWN_EX command to
|
|
Packit Service |
a1973e |
* fcntl().
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
#include <sys/time.h>
|
|
Packit Service |
a1973e |
#include <sys/types.h>
|
|
Packit Service |
a1973e |
#include <err.h>
|
|
Packit Service |
a1973e |
#include <errno.h>
|
|
Packit Service |
a1973e |
#include <fcntl.h>
|
|
Packit Service |
a1973e |
#include <pthread.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 <unistd.h>
|
|
Packit Service |
a1973e |
#include <getopt.h>
|
|
Packit Service |
a1973e |
#include <sys/ioctl.h>
|
|
Packit Service |
a1973e |
#include <sys/mman.h>
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#include "perf_util.h"
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define PROGRAM_TIME 8
|
|
Packit Service |
a1973e |
#define THRESHOLD 20000000
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int program_time = PROGRAM_TIME;
|
|
Packit Service |
a1973e |
static int threshold = THRESHOLD;
|
|
Packit Service |
a1973e |
static int signum = SIGIO;
|
|
Packit Service |
a1973e |
static pthread_barrier_t barrier;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int buffer_pages = 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define MAX_THR 128
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* the following definitions come
|
|
Packit Service |
a1973e |
* from the F_SETOWN_EX patch from Peter Zijlstra
|
|
Packit Service |
a1973e |
* Check out: http://lkml.org/lkml/2009/8/4/128
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
#ifndef F_SETOWN_EX
|
|
Packit Service |
a1973e |
#define F_SETOWN_EX 15
|
|
Packit Service |
a1973e |
#define F_GETOWN_EX 16
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define F_OWNER_TID 0
|
|
Packit Service |
a1973e |
#define F_OWNER_PID 1
|
|
Packit Service |
a1973e |
#define F_OWNER_PGRP 2
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
struct f_owner_ex {
|
|
Packit Service |
a1973e |
int type;
|
|
Packit Service |
a1973e |
pid_t pid;
|
|
Packit Service |
a1973e |
};
|
|
Packit Service |
a1973e |
#endif
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
struct over_args {
|
|
Packit Service |
a1973e |
int fd;
|
|
Packit Service |
a1973e |
pid_t tid;
|
|
Packit Service |
a1973e |
int id;
|
|
Packit Service |
a1973e |
perf_event_desc_t *fds;
|
|
Packit Service |
a1973e |
};
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
struct over_args fd2ov[MAX_THR];
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
long count[MAX_THR];
|
|
Packit Service |
a1973e |
long total[MAX_THR];
|
|
Packit Service |
a1973e |
long iter[MAX_THR];
|
|
Packit Service |
a1973e |
long mismatch[MAX_THR];
|
|
Packit Service |
a1973e |
long bad_msg[MAX_THR];
|
|
Packit Service |
a1973e |
long bad_restart[MAX_THR];
|
|
Packit Service |
a1973e |
int fown;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static __thread int myid; /* TLS */
|
|
Packit Service |
a1973e |
static __thread perf_event_desc_t *fds; /* TLS */
|
|
Packit Service |
a1973e |
static __thread int num_fds; /* TLS */
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pid_t
|
|
Packit Service |
a1973e |
gettid(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
return (pid_t)syscall(__NR_gettid);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
user_callback(int m)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
count[m]++;
|
|
Packit Service |
a1973e |
total[m]++;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
do_cycles(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct timeval start, last, now;
|
|
Packit Service |
a1973e |
unsigned long x, sum;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
gettimeofday(&start, NULL);
|
|
Packit Service |
a1973e |
last = start;
|
|
Packit Service |
a1973e |
count[myid] = 0;
|
|
Packit Service |
a1973e |
total[myid] = 0;
|
|
Packit Service |
a1973e |
iter[myid] = 0;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
do {
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
sum = 1;
|
|
Packit Service |
a1973e |
for (x = 1; x < 250000; x++) {
|
|
Packit Service |
a1973e |
/* signal pending to private queue because of
|
|
Packit Service |
a1973e |
* pthread_kill(), i.e., tkill()
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if ((x % 5000) == 0)
|
|
Packit Service |
a1973e |
pthread_kill(pthread_self(), SIGUSR1);
|
|
Packit Service |
a1973e |
sum += x;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
iter[myid]++;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
gettimeofday(&now, NULL);
|
|
Packit Service |
a1973e |
if (now.tv_sec > last.tv_sec) {
|
|
Packit Service |
a1973e |
printf("%ld: myid = %3d, fd = %3d, count = %4ld, iter = %4ld, rate = %ld/Kiter\n",
|
|
Packit Service |
a1973e |
(long)(now.tv_sec - start.tv_sec),
|
|
Packit Service |
a1973e |
myid,
|
|
Packit Service |
a1973e |
fd2ov[myid].fd,
|
|
Packit Service |
a1973e |
count[myid], iter[myid],
|
|
Packit Service |
a1973e |
(1000 * count[myid])/iter[myid]);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
count[myid] = 0;
|
|
Packit Service |
a1973e |
iter[myid] = 0;
|
|
Packit Service |
a1973e |
last = now;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
} while (now.tv_sec < start.tv_sec + program_time);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define DPRINT(str) \
|
|
Packit Service |
a1973e |
printf("(%s) si->fd = %d, ov->self = 0x%lx, self = 0x%lx\n", \
|
|
Packit Service |
a1973e |
str, fd, (unsigned long)ov->self, (unsigned long)self)
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
sigusr1_handler(int sig, siginfo_t *info, void *context)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* a signal handler cannot safely invoke printf()
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
sigio_handler(int sig, siginfo_t *info, void *context)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
perf_event_desc_t *fdx;
|
|
Packit Service |
a1973e |
struct perf_event_header ehdr;
|
|
Packit Service |
a1973e |
struct over_args *ov;
|
|
Packit Service |
a1973e |
int fd, i, ret;
|
|
Packit Service |
a1973e |
pid_t tid;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* positive si_code indicate kernel generated signal
|
|
Packit Service |
a1973e |
* which is normal for SIGIO
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (info->si_code < 0)
|
|
Packit Service |
a1973e |
errx(1, "signal not generated by kernel");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* SIGPOLL = SIGIO
|
|
Packit Service |
a1973e |
* expect POLL_HUP instead of POLL_IN because we are
|
|
Packit Service |
a1973e |
* in one-shot mode (IOC_REFRESH)
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (info->si_code != POLL_HUP)
|
|
Packit Service |
a1973e |
errx(1, "signal not generated by SIGIO: %d", info->si_code);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fd = info->si_fd;
|
|
Packit Service |
a1973e |
tid = gettid();
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for(i=0; i < MAX_THR; i++)
|
|
Packit Service |
a1973e |
if (fd2ov[i].fd == fd)
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (i == MAX_THR)
|
|
Packit Service |
a1973e |
errx(1, "bad info.si_fd: %d", fd);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ov = &fd2ov[i];
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* current thread id may not always match the id
|
|
Packit Service |
a1973e |
* associated with the file descriptor
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* We need to use the other's thread fds info
|
|
Packit Service |
a1973e |
* otherwise, it is going to get stuck with no
|
|
Packit Service |
a1973e |
* more samples generated
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (tid != ov->tid) {
|
|
Packit Service |
a1973e |
mismatch[myid]++;
|
|
Packit Service |
a1973e |
fdx = ov->fds;
|
|
Packit Service |
a1973e |
} else {
|
|
Packit Service |
a1973e |
fdx = fds;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* read sample header
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
ret = perf_read_buffer(fdx+0, &ehdr, sizeof(ehdr));
|
|
Packit Service |
a1973e |
if (ret) {
|
|
Packit Service |
a1973e |
errx(1, "cannot read event header");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* message we do not handle
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (ehdr.type != PERF_RECORD_SAMPLE) {
|
|
Packit Service |
a1973e |
bad_msg[myid]++;
|
|
Packit Service |
a1973e |
goto skip;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
user_callback(myid);
|
|
Packit Service |
a1973e |
skip:
|
|
Packit Service |
a1973e |
/* mark sample as consumed */
|
|
Packit Service |
a1973e |
perf_skip_buffer(fdx+0, ehdr.size);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* re-arm period, next notification after wakeup_events
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
ret = ioctl(fd, PERF_EVENT_IOC_REFRESH, 1);
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "cannot refresh");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
overflow_start(char *name)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct f_owner_ex fown_ex;
|
|
Packit Service |
a1973e |
struct over_args *ov;
|
|
Packit Service |
a1973e |
size_t pgsz;
|
|
Packit Service |
a1973e |
int ret, fd, flags;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fds = NULL;
|
|
Packit Service |
a1973e |
num_fds = 0;
|
|
Packit Service |
a1973e |
ret = perf_setup_list_events("cycles", &fds, &num_fds);
|
|
Packit Service |
a1973e |
if (ret || !num_fds)
|
|
Packit Service |
a1973e |
errx(1, "cannot monitor event");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pgsz = sysconf(_SC_PAGESIZE);
|
|
Packit Service |
a1973e |
ov = &fd2ov[myid];
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* do not enable now */
|
|
Packit Service |
a1973e |
fds[0].hw.disabled = 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* notify after 1 sample */
|
|
Packit Service |
a1973e |
fds[0].hw.wakeup_events = 1;
|
|
Packit Service |
a1973e |
fds[0].hw.sample_type = PERF_SAMPLE_IP;
|
|
Packit Service |
a1973e |
fds[0].hw.sample_period = threshold;
|
|
Packit Service |
a1973e |
fds[0].hw.read_format = 0;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fds[0].fd = fd = perf_event_open(&fds[0].hw, gettid(), -1, -1, 0);
|
|
Packit Service |
a1973e |
if (fd == -1)
|
|
Packit Service |
a1973e |
err(1, "cannot attach event %s", fds[0].name);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ov->fd = fd;
|
|
Packit Service |
a1973e |
ov->tid = gettid();
|
|
Packit Service |
a1973e |
ov->id = myid;
|
|
Packit Service |
a1973e |
ov->fds = fds;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
flags = fcntl(fd, F_GETFL, 0);
|
|
Packit Service |
a1973e |
if (fcntl(fd, F_SETFL, flags | O_ASYNC) < 0)
|
|
Packit Service |
a1973e |
err(1, "fcntl SETFL failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fown_ex.type = F_OWNER_TID;
|
|
Packit Service |
a1973e |
fown_ex.pid = gettid();
|
|
Packit Service |
a1973e |
ret = fcntl(fd,
|
|
Packit Service |
a1973e |
(fown ? F_SETOWN_EX : F_SETOWN),
|
|
Packit Service |
a1973e |
(fown ? (unsigned long)&fown_ex: (unsigned long)gettid()));
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "fcntl SETOWN failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (fcntl(fd, F_SETSIG, signum) < 0)
|
|
Packit Service |
a1973e |
err(1, "fcntl SETSIG failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fds[0].buf = mmap(NULL, (buffer_pages + 1)* pgsz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
|
Packit Service |
a1973e |
if (fds[0].buf == MAP_FAILED)
|
|
Packit Service |
a1973e |
err(1, "cannot mmap buffer");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
fds[0].pgmsk = (buffer_pages * pgsz) - 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
printf("launch %s: fd: %d, tid: %d\n", name, fd, ov->tid);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* activate event for wakeup_events (samples)
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
ret = ioctl(fd, PERF_EVENT_IOC_REFRESH , 1);
|
|
Packit Service |
a1973e |
if (ret == -1)
|
|
Packit Service |
a1973e |
err(1, "cannot refresh");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
void
|
|
Packit Service |
a1973e |
overflow_stop(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
int ret;
|
|
Packit Service |
a1973e |
ret = ioctl(fd2ov[myid].fd, PERF_EVENT_IOC_DISABLE, 0);
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "cannot stop");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
void *
|
|
Packit Service |
a1973e |
my_thread(void *v)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
int retval = 0;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
myid = (unsigned long)v;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pthread_barrier_wait(&barrier);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
overflow_start("side");
|
|
Packit Service |
a1973e |
do_cycles();
|
|
Packit Service |
a1973e |
overflow_stop();
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
perf_free_fds(fds, num_fds);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pthread_exit((void *)&retval);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
usage(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
printf("self_smpl_multi [-t secs] [-p period] [-s signal] [-f] [-n threads]\n"
|
|
Packit Service |
a1973e |
"-t secs: duration of the run in seconds\n"
|
|
Packit Service |
a1973e |
"-p period: sampling period in CPU cycles\n"
|
|
Packit Service |
a1973e |
"-s signal: signal to use (default: SIGIO)\n"
|
|
Packit Service |
a1973e |
"-n thread: number of threads to create (default: 1)\n"
|
|
Packit Service |
a1973e |
"-f : use F_SETOWN_EX for correct delivery of signal to thread (default: off)\n");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* Program args: program_time, threshold, signum.
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
int
|
|
Packit Service |
a1973e |
main(int argc, char **argv)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
struct sigaction sa;
|
|
Packit Service |
a1973e |
pthread_t allthr[MAX_THR];
|
|
Packit Service |
a1973e |
sigset_t set, old, new;
|
|
Packit Service |
a1973e |
int i, ret, max_thr = 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
while ((i=getopt(argc, argv, "t:p:s:fhn:")) != EOF) {
|
|
Packit Service |
a1973e |
switch(i) {
|
|
Packit Service |
a1973e |
case 'h':
|
|
Packit Service |
a1973e |
usage();
|
|
Packit Service |
a1973e |
return 0;
|
|
Packit Service |
a1973e |
case 't':
|
|
Packit Service |
a1973e |
program_time = atoi(optarg);
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
case 'p':
|
|
Packit Service |
a1973e |
threshold = atoi(optarg);
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
case 's':
|
|
Packit Service |
a1973e |
signum = atoi(optarg);
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
case 'f':
|
|
Packit Service |
a1973e |
fown = 1;
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
case 'n':
|
|
Packit Service |
a1973e |
max_thr = atoi(optarg);
|
|
Packit Service |
a1973e |
if (max_thr >= MAX_THR)
|
|
Packit Service |
a1973e |
errx(1, "no more than %d threads", MAX_THR);
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
default:
|
|
Packit Service |
a1973e |
errx(1, "invalid option");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
printf("program_time = %d, threshold = %d, signum = %d fcntl(%s), threads = %d\n",
|
|
Packit Service |
a1973e |
program_time, threshold, signum,
|
|
Packit Service |
a1973e |
fown ? "F_SETOWN_EX" : "F_SETOWN",
|
|
Packit Service |
a1973e |
max_thr);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for (i = 0; i < MAX_THR; i++) {
|
|
Packit Service |
a1973e |
mismatch[i] = 0;
|
|
Packit Service |
a1973e |
bad_msg[i] = 0;
|
|
Packit Service |
a1973e |
bad_restart[i] = 0;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
memset(&sa, 0, sizeof(sa));
|
|
Packit Service |
a1973e |
sigemptyset(&set);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
sa.sa_sigaction = sigusr1_handler;
|
|
Packit Service |
a1973e |
sa.sa_mask = set;
|
|
Packit Service |
a1973e |
sa.sa_flags = SA_SIGINFO;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (sigaction(SIGUSR1, &sa, NULL) != 0)
|
|
Packit Service |
a1973e |
errx(1, "sigaction failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
memset(&sa, 0, sizeof(sa));
|
|
Packit Service |
a1973e |
sigemptyset(&set);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
sa.sa_sigaction = sigio_handler;
|
|
Packit Service |
a1973e |
sa.sa_mask = set;
|
|
Packit Service |
a1973e |
sa.sa_flags = SA_SIGINFO;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (sigaction(signum, &sa, NULL) != 0)
|
|
Packit Service |
a1973e |
errx(1, "sigaction failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (pfm_initialize() != PFM_SUCCESS)
|
|
Packit Service |
a1973e |
errx(1, "pfm_initialize failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* +1 because main thread is also using the barrier
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
pthread_barrier_init(&barrier, 0, max_thr+1);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for(i=0; i < max_thr; i++) {
|
|
Packit Service |
a1973e |
ret = pthread_create(allthr+i, NULL, my_thread, (void *)(unsigned long)i);
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "pthread_create failed");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
myid = i;
|
|
Packit Service |
a1973e |
sigemptyset(&set);
|
|
Packit Service |
a1973e |
sigemptyset(&new;;
|
|
Packit Service |
a1973e |
sigaddset(&set, SIGIO);
|
|
Packit Service |
a1973e |
sigaddset(&new, SIGIO);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (pthread_sigmask(SIG_BLOCK, &set, NULL))
|
|
Packit Service |
a1973e |
err(1, "cannot mask SIGIO in main thread");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ret = sigprocmask(SIG_SETMASK, NULL, &old;;
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "sigprocmask failed");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (sigismember(&old, SIGIO)) {
|
|
Packit Service |
a1973e |
warnx("program started with SIGIO masked, unmasking it now\n");
|
|
Packit Service |
a1973e |
ret = sigprocmask(SIG_UNBLOCK, &new, NULL);
|
|
Packit Service |
a1973e |
if (ret)
|
|
Packit Service |
a1973e |
err(1, "sigprocmask failed");
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pthread_barrier_wait(&barrier);
|
|
Packit Service |
a1973e |
printf("\n\n");
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for (i = 0; i < max_thr; i++) {
|
|
Packit Service |
a1973e |
pthread_join(allthr[i], NULL);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
printf("\n\n");
|
|
Packit Service |
a1973e |
for (i = 0; i < max_thr; i++) {
|
|
Packit Service |
a1973e |
printf("myid = %3d, fd = %3d, total = %4ld, mismatch = %ld, "
|
|
Packit Service |
a1973e |
"bad_msg = %ld, bad_restart = %ld\n",
|
|
Packit Service |
a1973e |
fd2ov[i].id, fd2ov[i].fd, total[i], mismatch[i],
|
|
Packit Service |
a1973e |
bad_msg[i], bad_restart[i]);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
/* free libpfm resources cleanly */
|
|
Packit Service |
a1973e |
pfm_terminate();
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
return (0);
|
|
Packit Service |
a1973e |
}
|