https://zhuanlan.zhihu.com/p/543218645
perf_event_open
进行挂载。pid 21711 fd 5: prog_id 5 kprobe func __x64_sys_write offset 0
pid 21765 fd 5: prog_id 7 kretprobe func __x64_sys_nanosleep offset 0
pid 21767 fd 5: prog_id 8 tracepoint sys_enter_nanosleep
pid 21800 fd 5: prog_id 9 uprobe filename /home/yhs/a.out offset 1159
linux kerbel中bpftool代码在 tools/bpf/bpftool/perf.c中,具体代码流程为:
do_show---->show_proc---->bpf_task_fd_query---->sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr));
从代码流程可得到bpftool perf可现实的类型有:
raw_tracepoint, tracepoint, kprobe, kretprobe, uprobe, uretprobe
显示的信息方法为遍历/proc目录下的每个pid,然后系统调用sys_bpf查询该pid是否为我们所要找的pid
最直接的当然还是查看相关手册,如下。
(https://man7.org/linux/man-pages/man2/perf_event_open.2.html)
但下面我还是想试着根据自己的理解稍作总结。
perf_event_open()返回一个会被随后系统调用( read(2) , mmap(2) , prctl(2) , fcntl(2) ,等)的文件描述符。对perf_event_open()的一次调用创建一个文件描述符,它运行测量性能信息。每个文件描述符与被检测的一个事件相对应,这些可以同时的被分组一起来检测多个事件。事件可以通过两种方法被激活或者关闭:通过 ioctl(2)和prctl(2)。当一个事件被关闭,它不count或者发生溢出,但它还是存在的并且有它的计算值。事件的发生有两个特点(flavors):计算(counting)和采样(sampled)。一个计算事件被用来统计事件发生的集合数。通常来说,计算事件结果通过一个read(2)调用被收集。一个采样事件周期性的写测量值到一个能通过map(2)被访问的buffer。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>
#define PID_NUM 123
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
int
main(int argc, char **argv)
{
struct perf_event_attr pe;
long long count,cycles,instructions;
double ipc;
int fd;
int i;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE; //这个type也可以有很多种。
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CPU_CYCLES;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
//count cycles;
fd = perf_event_open(&pe, PID_NUM, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long)); //PERF_COUNT_HW_CPU_CYCLES
cycles=count;
//count instructions