Merge pull request #10088 from ziglang/std-os-perf

std: add Linux perf syscall bits
This commit is contained in:
Andrew Kelley 2021-11-02 14:52:54 -04:00 committed by GitHub
commit 08dc840247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 372 additions and 10 deletions

View File

@ -1703,8 +1703,6 @@ pub const CLOCK = struct {
/// Max open files per process
/// https://opensource.apple.com/source/xnu/xnu-4903.221.2/bsd/sys/syslimits.h.auto.html
pub const OPEN_MAX = 10240;
pub const RUSAGE_SELF = 0;
pub const RUSAGE_CHILDREN = -1;
pub const rusage = extern struct {
utime: timeval,
@ -1723,6 +1721,9 @@ pub const rusage = extern struct {
nsignals: isize,
nvcsw: isize,
nivcsw: isize,
pub const SELF = 0;
pub const CHILDREN = -1;
};
pub const rlimit_resource = enum(c_int) {

View File

@ -1550,10 +1550,6 @@ pub const rlimit = extern struct {
max: rlim_t,
};
pub const RUSAGE_SELF = 0;
pub const RUSAGE_CHILDREN = -1;
pub const RUSAGE_THREAD = 1;
pub const rusage = extern struct {
utime: timeval,
stime: timeval,
@ -1571,6 +1567,10 @@ pub const rusage = extern struct {
nsignals: isize,
nvcsw: isize,
nivcsw: isize,
pub const SELF = 0;
pub const CHILDREN = -1;
pub const THREAD = 1;
};
pub const SHUT = struct {

View File

@ -6349,3 +6349,87 @@ pub fn madvise(ptr: [*]align(mem.page_size) u8, length: usize, advice: u32) Madv
else => |err| return unexpectedErrno(err),
}
}
pub const PerfEventOpenError = error{
/// Returned if the perf_event_attr size value is too small (smaller
/// than PERF_ATTR_SIZE_VER0), too big (larger than the page size),
/// or larger than the kernel supports and the extra bytes are not
/// zero. When E2BIG is returned, the perf_event_attr size field is
/// overwritten by the kernel to be the size of the structure it was
/// expecting.
TooBig,
/// Returned when the requested event requires CAP_SYS_ADMIN permis
/// sions (or a more permissive perf_event paranoid setting). Some
/// common cases where an unprivileged process may encounter this
/// error: attaching to a process owned by a different user; moni
/// toring all processes on a given CPU (i.e., specifying the pid
/// argument as -1); and not setting exclude_kernel when the para
/// noid setting requires it.
/// Also:
/// Returned on many (but not all) architectures when an unsupported
/// exclude_hv, exclude_idle, exclude_user, or exclude_kernel set
/// ting is specified.
/// It can also happen, as with EACCES, when the requested event re
/// quires CAP_SYS_ADMIN permissions (or a more permissive
/// perf_event paranoid setting). This includes setting a break
/// point on a kernel address, and (since Linux 3.13) setting a ker
/// nel function-trace tracepoint.
PermissionDenied,
/// Returned if another event already has exclusive access to the
/// PMU.
DeviceBusy,
/// Each opened event uses one file descriptor. If a large number
/// of events are opened, the per-process limit on the number of
/// open file descriptors will be reached, and no more events can be
/// created.
ProcessResources,
EventRequiresUnsupportedCpuFeature,
/// Returned if you try to add more breakpoint
/// events than supported by the hardware.
TooManyBreakpoints,
/// Returned if PERF_SAMPLE_STACK_USER is set in sample_type and it
/// is not supported by hardware.
SampleStackNotSupported,
/// Returned if an event requiring a specific hardware feature is
/// requested but there is no hardware support. This includes re
/// questing low-skid events if not supported, branch tracing if it
/// is not available, sampling if no PMU interrupt is available, and
/// branch stacks for software events.
EventNotSupported,
/// Returned if PERF_SAMPLE_CALLCHAIN is requested and sam
/// ple_max_stack is larger than the maximum specified in
/// /proc/sys/kernel/perf_event_max_stack.
SampleMaxStackOverflow,
/// Returned if attempting to attach to a process that does not exist.
ProcessNotFound,
} || UnexpectedError;
pub fn perf_event_open(
attr: *linux.perf_event_attr,
pid: pid_t,
cpu: i32,
group_fd: fd_t,
flags: usize,
) PerfEventOpenError!fd_t {
const rc = system.perf_event_open(attr, pid, cpu, group_fd, flags);
switch (errno(rc)) {
.SUCCESS => return @intCast(fd_t, rc),
.@"2BIG" => return error.TooBig,
.ACCES => return error.PermissionDenied,
.BADF => unreachable, // group_fd file descriptor is not valid.
.BUSY => return error.DeviceBusy,
.FAULT => unreachable, // Segmentation fault.
.INVAL => unreachable, // Bad attr settings.
.INTR => unreachable, // Mixed perf and ftrace handling for a uprobe.
.MFILE => return error.ProcessResources,
.NODEV => return error.EventRequiresUnsupportedCpuFeature,
.NOENT => unreachable, // Invalid type setting.
.NOSPC => return error.TooManyBreakpoints,
.NOSYS => return error.SampleStackNotSupported,
.OPNOTSUPP => return error.EventNotSupported,
.OVERFLOW => return error.SampleMaxStackOverflow,
.PERM => return error.PermissionDenied,
.SRCH => return error.ProcessNotFound,
else => |err| return unexpectedErrno(err),
}
}

View File

@ -1638,6 +1638,23 @@ pub fn fadvise(fd: fd_t, offset: i64, len: i64, advice: usize) usize {
}
}
pub fn perf_event_open(
attr: *perf_event_attr,
pid: pid_t,
cpu: i32,
group_fd: fd_t,
flags: usize,
) usize {
return syscall5(
.perf_event_open,
@ptrToInt(attr),
@bitCast(usize, @as(isize, pid)),
@bitCast(usize, @as(isize, cpu)),
@bitCast(usize, @as(isize, group_fd)),
flags,
);
}
pub const E = switch (native_arch) {
.mips, .mipsel => @import("linux/errno/mips.zig").E,
.sparc, .sparcel, .sparcv9 => @import("linux/errno/sparc.zig").E,
@ -3781,10 +3798,6 @@ pub const MFD_HUGE_1GB = HUGETLB_FLAG_ENCODE_1GB;
pub const MFD_HUGE_2GB = HUGETLB_FLAG_ENCODE_2GB;
pub const MFD_HUGE_16GB = HUGETLB_FLAG_ENCODE_16GB;
pub const RUSAGE_SELF = 0;
pub const RUSAGE_CHILDREN = -1;
pub const RUSAGE_THREAD = 1;
pub const rusage = extern struct {
utime: timeval,
stime: timeval,
@ -3803,6 +3816,10 @@ pub const rusage = extern struct {
nvcsw: isize,
nivcsw: isize,
__reserved: [16]isize = [1]isize{0} ** 16,
pub const SELF = 0;
pub const CHILDREN = -1;
pub const THREAD = 1;
};
pub const cc_t = u8;
@ -4925,3 +4942,263 @@ pub const rtnl_link_stats64 = extern struct {
/// dropped, no handler found
rx_nohandler: u64,
};
pub const perf_event_attr = extern struct {
/// Major type: hardware/software/tracepoint/etc.
type: PERF.TYPE = undefined,
/// Size of the attr structure, for fwd/bwd compat.
size: u32 = @sizeOf(perf_event_attr),
/// Type specific configuration information.
config: u64 = 0,
sample_period_or_freq: u64 = 0,
sample_type: u64 = 0,
read_format: u64 = 0,
flags: packed struct {
/// off by default
disabled: bool = false,
/// children inherit it
inherit: bool = false,
/// must always be on PMU
pinned: bool = false,
/// only group on PMU
exclusive: bool = false,
/// don't count user
exclude_user: bool = false,
/// ditto kernel
exclude_kernel: bool = false,
/// ditto hypervisor
exclude_hv: bool = false,
/// don't count when idle
exclude_idle: bool = false,
/// include mmap data
mmap: bool = false,
/// include comm data
comm: bool = false,
/// use freq, not period
freq: bool = false,
/// per task counts
inherit_stat: bool = false,
/// next exec enables
enable_on_exec: bool = false,
/// trace fork/exit
task: bool = false,
/// wakeup_watermark
watermark: bool = false,
/// precise_ip:
///
/// 0 - SAMPLE_IP can have arbitrary skid
/// 1 - SAMPLE_IP must have constant skid
/// 2 - SAMPLE_IP requested to have 0 skid
/// 3 - SAMPLE_IP must have 0 skid
///
/// See also PERF_RECORD_MISC_EXACT_IP
/// skid constraint
precise_ip: u2 = 0,
/// non-exec mmap data
mmap_data: bool = false,
/// sample_type all events
sample_id_all: bool = false,
/// don't count in host
exclude_host: bool = false,
/// don't count in guest
exclude_guest: bool = false,
/// exclude kernel callchains
exclude_callchain_kernel: bool = false,
/// exclude user callchains
exclude_callchain_user: bool = false,
/// include mmap with inode data
mmap2: bool = false,
/// flag comm events that are due to an exec
comm_exec: bool = false,
/// use @clockid for time fields
use_clockid: bool = false,
/// context switch data
context_switch: bool = false,
/// Write ring buffer from end to beginning
write_backward: bool = false,
/// include namespaces data
namespaces: bool = false,
__reserved_1: u35 = 0,
} = .{},
/// wakeup every n events, or
/// bytes before wakeup
wakeup_events_or_watermark: u32 = 0,
bp_type: u32 = 0,
/// This field is also used for:
/// bp_addr
/// kprobe_func for perf_kprobe
/// uprobe_path for perf_uprobe
config1: u64 = 0,
/// This field is also used for:
/// bp_len
/// kprobe_addr when kprobe_func == null
/// probe_offset for perf_[k,u]probe
config2: u64 = 0,
/// enum perf_branch_sample_type
branch_sample_type: u64 = 0,
/// Defines set of user regs to dump on samples.
/// See asm/perf_regs.h for details.
sample_regs_user: u64 = 0,
/// Defines size of the user stack to dump on samples.
sample_stack_user: u32 = 0,
clockid: i32 = 0,
/// Defines set of regs to dump for each sample
/// state captured on:
/// - precise = 0: PMU interrupt
/// - precise > 0: sampled instruction
///
/// See asm/perf_regs.h for details.
sample_regs_intr: u64 = 0,
/// Wakeup watermark for AUX area
aux_watermark: u32 = 0,
sample_max_stack: u16 = 0,
/// Align to u64
__reserved_2: u16 = 0,
};
pub const PERF = struct {
pub const TYPE = enum(u32) {
HARDWARE,
SOFTWARE,
TRACEPOINT,
HW_CACHE,
RAW,
BREAKPOINT,
MAX,
};
pub const COUNT = struct {
pub const HW = enum(u32) {
CPU_CYCLES,
INSTRUCTIONS,
CACHE_REFERENCES,
CACHE_MISSES,
BRANCH_INSTRUCTIONS,
BRANCH_MISSES,
BUS_CYCLES,
STALLED_CYCLES_FRONTEND,
STALLED_CYCLES_BACKEND,
REF_CPU_CYCLES,
MAX,
pub const CACHE = enum(u32) {
L1D,
L1I,
LL,
DTLB,
ITLB,
BPU,
NODE,
MAX,
pub const OP = enum(u32) {
READ,
WRITE,
PREFETCH,
MAX,
};
pub const RESULT = enum(u32) {
ACCESS,
MISS,
MAX,
};
};
};
pub const SW = enum(u32) {
CPU_CLOCK,
TASK_CLOCK,
PAGE_FAULTS,
CONTEXT_SWITCHES,
CPU_MIGRATIONS,
PAGE_FAULTS_MIN,
PAGE_FAULTS_MAJ,
ALIGNMENT_FAULTS,
EMULATION_FAULTS,
DUMMY,
BPF_OUTPUT,
MAX,
};
};
pub const SAMPLE = struct {
pub const IP = 1;
pub const TID = 2;
pub const TIME = 4;
pub const ADDR = 8;
pub const READ = 16;
pub const CALLCHAIN = 32;
pub const ID = 64;
pub const CPU = 128;
pub const PERIOD = 256;
pub const STREAM_ID = 512;
pub const RAW = 1024;
pub const BRANCH_STACK = 2048;
pub const REGS_USER = 4096;
pub const STACK_USER = 8192;
pub const WEIGHT = 16384;
pub const DATA_SRC = 32768;
pub const IDENTIFIER = 65536;
pub const TRANSACTION = 131072;
pub const REGS_INTR = 262144;
pub const PHYS_ADDR = 524288;
pub const MAX = 1048576;
pub const BRANCH = struct {
pub const USER = 1 << 0;
pub const KERNEL = 1 << 1;
pub const HV = 1 << 2;
pub const ANY = 1 << 3;
pub const ANY_CALL = 1 << 4;
pub const ANY_RETURN = 1 << 5;
pub const IND_CALL = 1 << 6;
pub const ABORT_TX = 1 << 7;
pub const IN_TX = 1 << 8;
pub const NO_TX = 1 << 9;
pub const COND = 1 << 10;
pub const CALL_STACK = 1 << 11;
pub const IND_JUMP = 1 << 12;
pub const CALL = 1 << 13;
pub const NO_FLAGS = 1 << 14;
pub const NO_CYCLES = 1 << 15;
pub const TYPE_SAVE = 1 << 16;
pub const MAX = 1 << 17;
};
};
pub const FLAG = struct {
pub const FD_NO_GROUP = 1 << 0;
pub const FD_OUTPUT = 1 << 1;
pub const PID_CGROUP = 1 << 2;
pub const FD_CLOEXEC = 1 << 3;
};
pub const EVENT_IOC = struct {
pub const ENABLE = 9216;
pub const DISABLE = 9217;
pub const REFRESH = 9218;
pub const RESET = 9219;
pub const PERIOD = 1074275332;
pub const SET_OUTPUT = 9221;
pub const SET_FILTER = 1074275334;
pub const SET_BPF = 1074013192;
pub const PAUSE_OUTPUT = 1074013193;
pub const QUERY_BPF = 3221758986;
pub const MODIFY_ATTRIBUTES = 1074275339;
};
pub const IOC_FLAG_GROUP = 1;
};