$RodHat_
Syscall reference · Tracing

perf_event_open(2)

Open a file descriptor for a hardware or software performance counter.

Since
Linux 2.6.31check your kernel →
glibc
none (use syscall(2))
System
Linux
Man page
perf_event_open(2)

Synopsis

#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <unistd.h>

/* no glibc wrapper; call via syscall(2) */
int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
                    int group_fd, unsigned long flags);

Rod's take

perf stat calls perf_event_open(2). Call it yourself when you need counters inline without a subprocess or perf.data file. Use group_fd to atomic-read multiple counters from the same scheduling window. Always request PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING and scale accordingly when the kernel multiplexes more events than the PMU has physical registers. Set disabled=1 and gate with ioctl(PERF_EVENT_IOC_ENABLE/DISABLE) to control the measurement window precisely.

Flags and arguments that matter

NameWhat it does
PERF_TYPE_HARDWARECPU PMU counter; config is one of PERF_COUNT_HW_* (cycles, instructions, cache-misses, branch-misses, etc.).
PERF_TYPE_SOFTWAREKernel counter; config is one of PERF_COUNT_SW_* (cpu-clock, page-faults, context-switches, etc.).
PERF_TYPE_RAWVendor-specific PMU event code; config is the raw event selector from the CPU architecture manual.
PERF_FORMAT_GROUPRead all group members atomically in one read(2) call on the leader fd.
PERF_FORMAT_TOTAL_TIME_ENABLED / PERF_FORMAT_TOTAL_TIME_RUNNINGInclude nanoseconds the counter was enabled vs. actually running; divide to detect PMU multiplexing.
PERF_FLAG_FD_CLOEXECLinux 3.14Set O_CLOEXEC on the returned fd.
CAP_PERFMONLinux 5.8Required for system-wide (pid=-1) access; replaces CAP_SYS_ADMIN for perf in Linux 5.8.

Errors you will actually hit

errnoMeaning
EACCESperf_event_paranoid is too restrictive for the requested scope without the required capability.
EINVALInvalid event type or config, or pid=-1 and cpu=-1 simultaneously.
EMFILEToo many open file descriptors; each event costs one fd.

Example

#include <linux/perf_event.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>

struct perf_event_attr attr = {
    .type = PERF_TYPE_HARDWARE,
    .size = sizeof(attr),
    .config = PERF_COUNT_HW_INSTRUCTIONS,
    .disabled = 1,
    .exclude_kernel = 1,
};
int fd = syscall(SYS_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
/* ... work ... */
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
uint64_t count;
read(fd, &count, sizeof(count));

Trimmed from the full walkthrough in perf_event_open(2): hardware counters without the wrapper.

BSD equivalent

FreeBSD: hwpmc(4) and pmc(3)/pmcstat(8). Allocate via pmc_allocate(3), attach to a process, read via pmc_read(3). No group-atomic read. pmcstat -S instructions -p $pid is the closest equivalent.

The long version, from the console

Sources

  1. perf_event_open(2), man7.org
  2. perf security and access control, kernel.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.