Skip to content

perf event

#include <linux/perf_event.h> /* Definition of PERF_* constants */
#include <linux/hw_breakpoint.h> /* Definition of HW_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
int syscall(SYS_perf_event_open, struct perf_event_attr *attr,
pid_t pid, int cpu, int group_fd, unsigned long flags);
  • perf_event_open은 성능 모니터링을 설정하기 위한 시스템 콜이다.

  • perf_event_open()는 성능 정보를 측정할 수 있는 파일 디스크립터(FD)를 반환한다. 각 FD는 측정되는 하나의 이벤트를 의미한다.

  • 각 이벤트는 ioctl(2)prctl(2)를 통해 활성화, 비활성화될 수 있다. 이벤트가 비활성화되면 측정을 멈추지만 카운트 값은 그대로 유지한다.

  • 이벤트는 카운팅(counting) 타입과 샘플링(sampled) 타입 두 형태로 제공된다.

    • 카운팅 이벤트는 발생하는 이벤트의 총 수를 세기 위해 사용된다. 카운팅 이벤트 결과는 일반적으로 read(2) 호출로 수집된다.
    • 샘플링 이벤트는 측정값을 주기적으로 버퍼에 기록하고, mmap(2)를 통해 버퍼에 액세스할 수 있다.

Arguments

pid와 cpu

  • pid 인자로 측정할 프로세스를 지정할 수 있다.
    • pid == 0: 현재 프로세스를 측정
    • pid > 0: 해당 pid의 프로세스를 측정
    • pid == -1: 모든 프로세스 측정
      CAP_PERFMON, CAP_SYS_ADMIN 권한을 가지고 있거나 /proc/sys/kernel/perf_event_paranoid 값이 1 이하인 경우에만 실행할 수 있다.
  • cpu 인자로 측정할 CPU를 지정할 수 있다.
    • cpu >= 0: 지정된 CPU를 측정
    • cpu == -1: 모든 CPU에서 이벤트 측정
  • pid와 cpu 인자 두 개가 모두 -1인 경우 에러가 발생한다.

group_fd

  • 이벤트 그룹을 생성할 수 있도록 하는 인자이다.
  • 이벤트 그룹에서는 하나의 이벤트가 그룹의 리더가 된다. roup_fd를 -1로 지정해서 리더를 먼저 생성할 수 있고, 나머지 그룹 구성원을 생성할 때는 그룹 리더의 fd를 group_fd로 지정한다. (단일 이벤트는 멤버가 1명뿐인 그룹으로 간주된다.)
  • 이벤트 그룹은 CPU에 하나의 단위로 스케줄링된다. 멤버 이벤트의 값이 동일한 명령어에 대한 이벤트를 계산했기 때문에 서로 의미 있게 비교, 추가, 계산할 수 있다는 것을 의미한다.

flags

  • flag 인자는 다음 중 하나의 값을 가진다.

  • PERF_FLAG_FD_CLOEXEC
    이 flag는 생성된 이벤트 FD가 execve(2)를 통해 닫히도록 한다. (이걸 close-on-exec라고 부른다.) fcntl(2)로도 설정할 수 있지만, 다른 스레드가 fork(2) execve(2)를 호출해서 생길 수 있는 경합 가능성을 피하기 위해 유용하다.

  • PERF_FLAG_FD_NO_GROUP
    이 flag는 group_fd 인자를 무시하도록 한다.

  • PERF_FLAG_FD_OUTPUT (Linux 2.6.35부터 에러 발생)
    이벤트 수집 결과가 group_fd에 지정된 이벤트의 mmap 버퍼에 같이 저장되도록 한다.

  • PERF_FLAG_PID_CGROUP (Linux 2.6.39부터 사용 가능)
    컨테이너별 시스템 전역 모니터링을 활성화한다. 이 모드에서 이벤트는 스레드가 지정된 컨테이너(cgroup)에 속할 경우에만 측정된다.
    cgroup은 cgroupfs 파일 시스템의 디렉터리에서 열린 FD를 통해 식별된다. 예를 들어 모니터링할 컨트롤 그룹이 test이고, cgroupfs가 /dev/cgroup에 마운트되어 있다면 /dev/cgroup/test에서 열린 FD를 pid 매개변수로 전달해야 한다.
    cgroup 모니터링은 시스템 전체 이벤트에만 사용할 수 있으며 추가 권한이 필요할 수 있다.

perf_event_attr

perf_event_attr 구조체로 되어있는 인자는 생성될 이벤트에 대한 구체적인 정보를 전달하기 위해 사용한다.

struct perf_event_attr {
__u32 type; /* Type of event */
__u32 size; /* Size of attribute structure */
__u64 config; /* Type-specific configuration */
union {
__u64 sample_period; /* Period of sampling */
__u64 sample_freq; /* Frequency of sampling */
};
__u64 sample_type; /* Specifies values included in sample */
__u64 read_format; /* Specifies values returned in read */
__u64 disabled : 1, /* off by default */
inherit : 1, /* children inherit it */
pinned : 1, /* must always be on PMU */
exclusive : 1, /* only group on PMU */
exclude_user : 1, /* don't count user */
exclude_kernel : 1, /* don't count kernel */
exclude_hv : 1, /* don't count hypervisor */
exclude_idle : 1, /* don't count when idle */
mmap : 1, /* include mmap data */
comm : 1, /* include comm data */
freq : 1, /* use freq, not period */
inherit_stat : 1, /* per task counts */
enable_on_exec : 1, /* next exec enables */
task : 1, /* trace fork/exit */
watermark : 1, /* wakeup_watermark */
precise_ip : 2, /* skid constraint */
mmap_data : 1, /* non-exec mmap data */
sample_id_all : 1, /* sample_type all events */
exclude_host : 1, /* don't count in host */
exclude_guest : 1, /* don't count in guest */
exclude_callchain_kernel : 1, /* exclude kernel callchains */
exclude_callchain_user : 1, /* exclude user callchains */
mmap2 : 1, /* include mmap with inode data */
comm_exec : 1, /* flag comm events that are due to exec */
use_clockid : 1, /* use clockid for time fields */
context_switch : 1, /* context switch data */
write_backward : 1, /* Write ring buffer from end to beginning */
namespaces : 1, /* include namespaces data */
ksymbol : 1, /* include ksymbol events */
bpf_event : 1, /* include bpf events */
aux_output : 1, /* generate AUX records instead of events */
cgroup : 1, /* include cgroup events */
text_poke : 1, /* include text poke events */
build_id : 1, /* use build id in mmap2 events */
inherit_thread : 1, /* children only inherit */
/* if cloned with CLONE_THREAD */
remove_on_exec : 1, /* event is removed from task on exec */
sigtrap : 1, /* send synchronous SIGTRAP on event */
__reserved_1 : 26;
union {
__u32 wakeup_events; /* wakeup every n events */
__u32 wakeup_watermark; /* bytes before wakeup */
};
__u32 bp_type; /* breakpoint type */
union {
__u64 bp_addr; /* breakpoint address */
__u64 kprobe_func; /* for perf_kprobe */
__u64 uprobe_path; /* for perf_uprobe */
__u64 config1; /* extension of config */
};
union {
__u64 bp_len; /* breakpoint length */
__u64 kprobe_addr; /* with kprobe_func == NULL */
__u64 probe_offset; /* for perf_[k,u]probe */
__u64 config2; /* extension of config1 */
};
__u64 branch_sample_type; /* enum perf_branch_sample_type */
__u64 sample_regs_user; /* user regs to dump on samples */
__u32 sample_stack_user; /* size of stack to dump on
samples */
__s32 clockid; /* clock to use for time fields */
__u64 sample_regs_intr; /* regs to dump on samples */
__u32 aux_watermark; /* aux bytes before wakeup */
__u16 sample_max_stack; /* max frames in callchain */
__u16 __reserved_2; /* align to u64 */
__u32 aux_sample_size; /* max aux sample size */
__u32 __reserved_3; /* align to u64 */
__u64 sig_data; /* user data for sigtrap */
};

각 필드에 대한 자세한 설명은 다음과 같다.

  • type: 추적할 이벤트의 타입을 나타낸다. 상세한 이벤트는 config 인자의 값으로 결정된다. 타입은 아래 값 중 하나이다.

    • PERF_TYPE_HARDWARE: 커널에서 제공하는 제네럴한 하드웨어 이벤트 중 하나를 나타낸다.
    • PERF_TYPE_SOFTWARE: kernel의 software로 정의된 이벤트를 나타낸다.
    • PERF_TYPE_TRACEPOINT: kernel의 tracepoint 인프라에서 제공되는 tracepoint를 나타낸다.
    • PERF_TYPE_HW_CACHE: 하드웨어 캐시 이벤트를 나타낸다. config 필드 정의에서 설명되는 특수 인코딩을 가지고 있다.
    • PERF_TYPE_RAW: config 필드에서 명시되는 raw 구현을 나타낸다.
    • PERF_TYPE_BREAKPOINT: CPU로부터 제공되는 hardware breakpoint를 나타낸다. breakpoint의 주소로부터 읽기/쓰기 뿐만 아니라 명령어 주소 실행 또한 가능하다.
    • kprobeuprobe: 이 두가지의 동적 PMU는 perf_event_open로 생성된 FD에 대해서 kprobe/uprobe를 생성하고 등록한다.
  • size: perf_event_attr 구조체의 크기 값을 넣어주면 된다. sizeof(struct perf_event_attr)를 사용하여 구할 수 있다.

  • config: 타입 필드와 함께 원하는 이벤트를 지정한다. config1, config2 필드는 이벤트를 지정하기 위해 64비트만으로는 충분하지 않은 경우 사용된다. 이 필드들의 인코딩은 이벤트에 따라 다르다.

  • kprobe_func, uprobe_path, kprobe_addr, probe_offset: kprobe/uprobe 타입을 쓰는 경우 그에 대한

  • sample_period, sample_freq: 샘플링 주기를 지정하기 위해 사용한다. 샘플링 기간 또는 주기를 지정할 수 있다.

  • sample_type: 샘플링 할 데이터의 타입을 지정한다.
    PERF_SAMPLE_IP, PERF_SAMPLE_TID, PERF_SAMPLE_TIME, PERF_SAMPLE_ADDR, PERF_SAMPLE_READ, PERF_SAMPLE_CALLCHAIN, PERF_SAMPLE_ID, PERF_SAMPLE_CPU, PERF_SAMPLE_STACK_USER, PERF_SAMPLE_PHYS_ADDR 등이 있다.

  • inherit: 해당 작업의 하위 작업의 이벤트도 함께 카운트할지 여부를 지정한다. 기존 하위 작업에는 적용되지 않고 새로운 하위 작업에만 적용된다.

  • pinned: 카운터를 한 CPU에서 실행되도록 할지 여부를 지정한다. 하드웨어 카운터, 그룹 리더에만 적용된다. 카운터가 고정된 CPU에 놓일 수 없는 경우(예: 하드웨어 카운터가 충분하지 않거나 다른 이벤트와의 충돌이 있는 경우), 카운터는 ‘에러’ 상태가 되어 파일의 끝(즉, read(2)가 0을 반환)을 반환하며, 나중에 카운터가 활성화되거나 비활성화될 때까지 이 상태가 유지된다.

  • exclusive: 이 카운터 그룹이 CPU에 있을 때 CPU의 카운터를 사용하는 유일한 그룹이도록 강제할지 여부를 지정한다. 이 기능을 사용하면 다른 하드웨어 카운터를 방해하지 않도록 도와주는 PMU 기능을 사용하도록 할 수 있다.


참고