首先我们看一下对应的perf_header
struct perf_event_header {
__u32 type;
__u16 misc;
__u16 size;
};
-
type (
__u32
): 表示 perf 事件的类型。每种类型的事件都有其特定的值,例如PERF_RECORD_SAMPLE
表示采样事件,PERF_RECORD_LOST
表示丢失事件等。 -
misc (
__u16
): 包含一些额外的信息。例如,它可以指示事件发生时的 CPU 模式(用户模式、内核模式等),这可以通过PERF_RECORD_MISC_CPUMODE_MASK
来获取。 -
size (
__u16
): 表示 perf 事件记录的总大小(以字节为单位)。这个大小包括了struct perf_event_header
本身以及后续的事件特定数据。
这个结构体是 perf 事件数据格式的核心部分,每个 perf 事件记录都以它作为开始。在处理 perf 事件时,用户空间程序首先读取这个头部,然后根据 type
字段确定后续数据的格式,并使用 size
字段来确定整个记录的长度。
介绍完这个定义,我们继续看下面的定义:
//普通的事件
typedef struct event {
struct perf_event_header hdr;
uint32_t size;
uint64_t type;
uint8_t data[0];
} __attribute__((packed)) event_t;
//丢失的事件
struct lost_event {
struct perf_event_header hdr;
uint64_t id;
uint64_t lost;
};
PERF_RECORD_LOST 是 Linux perf 事件系统中的一种事件类型,用于通知用户空间程序有 perf 事件数据丢失。这通常发生在 perf 事件缓冲区(ring buffer)被内核填充得太快,而用户空间程序未能及时读取数据时。
下面我们看一下关于事件处理的函数:
typedef struct evhandler {
TAILQ_ENTRY(evhandler) node;
uint64_t type;
//提供函数的结构
void *priv;
//回调函数
int (*handle)(event_t *ev, void *priv);
} evhandler_t;
一个自定义结构体,表示一个事件处理器。它包含了一个用于链表的 node(使用 sys/queue.h 中的 TAILQ_ENTRY 宏),一个 type 字段用于标识事件类型,一个 priv 字段用于存储私有数据,以及一个 handle 函数指针,该函数用于处理事件。
一个事件队列(event queue),它通常用于 perf 事件监控系统中。这个结构体定义了以下成员:
struct evqueue {
int fd;
struct perf_event_mmap_page *mem;
void *buf;
};
fd (int)
: 这是 perf 事件的文件描述符(file descriptor),用于与 perf 事件进行交互,如读取和写入。mem (struct perf_event_mmap_page *)
: 指向 perf_event_mmap_page 结构体的指针,该结构体定义了 perf 事件的内存映射页。这个内存映射页用于访问 perf 事件的数据,通常包含数据头(data_head 和 data_tail)以及实际的事件数据。buf (void *)
: 一个通用指针,用作缓冲区,以存储从 perf 事件读取的数据。这个缓冲区可能用于临时存储事件数据,以便进一步处理。
evpipe_t 结构体定义了整个事件管道的状态,包括一个 BPF 映射文件描述符 mapfd,CPU 数量 ncpus,一个指向 pollfd 数组的指针用于 poll 调用,以及一个指向 evqueue 数组的指针 q。
typedef struct evpipe {
int mapfd;
uint32_t ncpus;
struct pollfd *poll;
struct evqueue *q;
} evpipe_t;