Я использую raspbian Linux 4.9.78-v7 + на пи 3b.
Я использую perf для проведения некоторых экспериментов с производительностью.
Я пытаюсь использовать PERF_EVENT_IOC_PERIOD
of perf, чтобы изменить период во время выполнения процесса.
Я установил начальный период выборки в структуре данных struct perf_event_attr
.
Я хочу переопределить этот начальный период выборки в атрибуте pe.sample_period
после каждой выборки.
Я использую сигналы для захвата переполнений и определяемый пользователем обработчик для изменения периода с помощью PERF_EVENT_IOC_PERIOD
. Но ioctl(fd, PERF_EVENT_IOC_PERIOD, interval);
не работает. Вместо этого я получаю образцы в начальный период выборки.
Действительно ли PERF_EVENT_IOC_PERIOD
работает.? Есть ли какие-либо предостережения относительно использования PERF_EVENT_IOC_PERIOD
.
Мой пример кода приведен ниже.
#define _GNU_SOURCE 1
#include <asm/unistd.h>
#include <fcntl.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
uint64_t old = 200000;
uint64_t prd[] = {200000, 300000, 500000, 800000, 1000000, 1100000, 1500000, 1700000, 2000000, 2200000, 2400000, 2750000, 2900000, 3000000, 3300000, 3400000, 3550000, 3850000, 4000000};
long perf_event_open(struct perf_event_attr* event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags);
}
static void perf_event_handler(int signum, siginfo_t* info, void* ucontext) {
if(info->si_code != POLL_HUP) {
uint64_t newp = prd[++idx];
uint64_t interval = old - newp;
old = newp;
ioctl(info->si_fd, PERF_EVENT_IOC_PERIOD, interval);
}
}
int main(int argc, char** argv)
{
// Configure signal handler
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = perf_event_handler;
sa.sa_flags = SA_SIGINFO;
// Setup signal handler
if (sigaction(SIGIO, &sa, NULL) < 0) {
fprintf(stderr,"Error setting up signal handler\n");
perror("sigaction");
exit(EXIT_FAILURE);
}
// Configure perf_event_attr struct
struct perf_event_attr pe;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS; // Count retired hardware instructions
pe.disabled = 1; // Event is initially disabled
pe.sample_type = PERF_SAMPLE_IP;
pe.sample_period = 200000;
pe.exclude_kernel = 1; // excluding events that happen in the kernel-space
pe.exclude_hv = 1; // excluding events that happen in the hypervisor
pid_t pid = 0; // measure the current process/thread
int cpu = -1; // measure on any cpu
int group_fd = -1;
unsigned long flags = 0;
int fd = perf_event_open(&pe, pid, cpu, group_fd, flags);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
perror("perf_event_open");
exit(EXIT_FAILURE);
}
//allocate memory for recording perf samples
pages = mmap(NULL, 4096*8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// Setup event handler for overflow signals
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
fcntl(fd, F_SETSIG, SIGIO);
fcntl(fd, F_SETOWN, getpid());
ioctl(fd, PERF_EVENT_IOC_RESET, 0); // Reset event counter to 0
ioctl(fd, PERF_EVENT_IOC_REFRESH, 19); //
// Start monitoring
long loopCount = 1000000;
long c = 0;
long i = 0;
// Some sample payload.
for(i = 0; i < loopCount; i++) {
c += 1;
}
// End monitoring
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); // Disable event
parse_samples(pages); //parse recorded samples
munmap(pages, 4096*8192); //free allocated memory
close(fd);
}
Код основан на предоставленном примере здесь