1. 综述
2. perf 前端
2.1 是什么
2.2 为什么
3. 事件(event)
3.1 是什么
3.2 事件类型
3.2.1 hardware
3.2.2 software
3.2.3 hw_cache
3.2.4 raw
3.2.5 事件类型与 PMU 的关系
3.3 事件监控模式
4. 前端编程基本范式
4.1 基本 counting 模式编程
4.2 事件组读取
4.3 模型总结
5. 总结
/* 用户自己对 syscall 的封装
*/
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(void) {
struct perf_event_attr pe;
long long count;
int fd;
/* 这里初始化了一个 attr
* 此 attr 是向 perf_event_open 刻画事件属性的关键参数
*/
memset(&pe, 0, sizeof(struct perf_event_attr));
/* type:当前要监控的是一个 hardware 类型事件
* 如前文所述,hardware 类型事件,其本质就是 perf 框架提供了抽象事件编码的硬件事件
*/
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
/* config:指定事件的编码(instruction 事件)
*/
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
/* disable:该事件默认初始是 disabled 模式
*/
pe.disabled = 1;
/* 不监控 kernel(OS)模式下的事件
*/
pe.exclude_kernel = 1;
/* perf_event_open pid 入参是 0
* 表明监控当前 task 的 instruction 事件
* 一个事件在用户态的呈现,就是一个 fd
*/
fd = perf_event_open(&pe, 0, -1, -1, 0);
/* RESET:复位计数值为 0
* ENABLE:enable 此事件(attr 参数中初始此事件是 disabled 的)
* 故而需要显式 enable
*/
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
/* 此 printf 的前后对事件进行了 enable、disable
* 所以,本程序的 instruction,本质上就是此 printf 语句运行期间的 instruction。
*/
printf("Measuring instruction count for this printf\n");
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
/* 读出事件的计数值
*/
read(fd, &count, sizeof(long long));
printf("Used %lld instructions\n", count);
close(fd);
}
struct read_format {
u64 nr; /* The number of events */
u64 values[2];
};
int main(void) {
struct perf_event_attr pe;
struct read_format count;
int group_leader_fd, group_member_fd;
/* 创建一个 hardware 类型的事件,不赘述
*/
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 1;
/* 这里指定采用 PERF_FORMAT_GROUP 读取方式
* 注意,只在 group leader 时需要指定该参数
*/
pe.read_format = PERF_FORMAT_GROUP;
/* 创建 group leader
*/
group_leader_fd = perf_event_open(&pe, 0, -1, -1, 0);
/* 创建一个 raw 类型的事件
* 假设要监控的事件编码:umask = 0x00, event_select = 0x3c
* 实际上此事件就是 UnHalted Core Cycles(也就是 hardware 类型的 PERF_COUNT_HW_CPU_CYCLES)
*/
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_RAW;
pe.size = sizeof(struct perf_event_attr);
/* 注意 raw 类型事件,config 的编码方式
*/
pe.config = (0x00 << 4) | 0x3c;
pe.disabled = 1;
pe.exclude_kernel = 1;
/* 创建 group member,perf_event_open 的 group_fd 参数指定为 group_leader_fd
*/
group_member_fd = perf_event_open(&pe, 0, -1, group_leader_fd, 0);
/* 组模式下,只需要操作 group leader 即可
*/
ioctl(group_leader_fd, PERF_EVENT_IOC_RESET, 0);
ioctl(group_leader_fd, PERF_EVENT_IOC_ENABLE, 0);
printf("Measuring instruction count for this printf\n");
ioctl(group_leader_fd, PERF_EVENT_IOC_DISABLE, 0);
/* 读出事件组的计数值,注意这里入参 count 是一个 struct read_format
*/
read(group_leader_fd, &count, sizeof(count));
/* 只有 count.nr 与当前组成员数(包括 leader、member)匹配,才是合法的数据
*/
if (count.nr == 2)
printf("Used %llu instructions, %llu cycles\n", count.values[0], count.values[1]);
close(group_leader_fd);
close(group_member_fd);
}
加【体系结构与性能优化】群,请扫客服小马微信。