c++ - 如何从 perf_event_open 中的环形缓冲区中检索 PERF_RECORD_SWITCH 的调用链?

标签 c++ profiling perf

在环形缓冲区中,我们可以只为 PERF_RECORD_SAMPLE 检索调用链,还是也可以为其他记录类型检索调用链?

perf_event_open 的手册页仅明确说明调用链可用于 PERF_RECORD_SAMPLE。我特别感兴趣的是获取 PERF_RECORD_SWITCH 的调用链,以获取程序上下文切换时的堆栈跟踪。我尝试了一种从缓冲区读取调用链的方法,但看到返回的地址,它看起来不正确。

size_t index = mapping->data_tail; //mapping is the pointer to the ring buffer

uintptr_t base = reinterpret_cast<uintptr_t>(mapping) + PageSize;
size_t start_index = index % DataSize;
size_t end_index = start_index + sizeof(struct perf_event_header);

memcpy(buf, reinterpret_cast<void*>(base + start_index), sizeof(struct perf_event_header));

struct perf_event_header* header = reinterpret_cast<struct perf_event_header*>(buf);

uintptr_t p = reinterpret_cast<uintptr_t>(header) + sizeof(struct perf_event_header)

// Only sampling PERF_SAMPLE_CALLCHAIN
uint64_t* base = reinterpret_cast<uint64_t*>(p);
uint64_t size = *base; // Should be callchain size
base++;

for (int i = 0; i < size; i++) {
    cout << *base << endl; // prints the addresses in the callchain stack
}

我使用此代码段得到的输出的 2 个主要问题是: 1. 所有 PERF_RECORD_SWITCH 都有相同的调用链。这应该是极不可能的。 2. 多次运行的输出不一致。调用链大小从 0(大部分)到 4、6、16 不等,有时是一个非常大(未定义)的数字。

最佳答案

调用链仅适用于 PERF_RECORD_SAMPLE事件。

读取不同记录类型时,应遵循struct来自 perf_event_open 的定义而不是仅仅尝试通过指针访问各个字段,即

struct perf_record_switch {
    struct perf_event_header header;
    struct sample_id sample_id;
};

然后转换整个事件reinterpret_cast<struct perf_record_switch*>(header)

具体而言,示例类型的布局高度依赖于配置,并且可能包含多个动态大小的数组,这会阻止使用静态结构。

从技术上讲,您可以使用 sched:sched_switch 从切换事件中收集调用链跟踪点采样事件。这导致 PERF_RECORD_SAMPLE事件。但是,您可能并不总能看到有用的信息,而主要是内核中的调度详细信息。

关于c++ - 如何从 perf_event_open 中的环形缓冲区中检索 PERF_RECORD_SWITCH 的调用链?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57799620/

相关文章:

c++ - Mac 中的通知窗口。有或没有 Qt

用于基准测试目的的 C# 编译器优化

C++ 线程函数说明

c++ - ActiveMQ主从故障转移丢失消息

运行gprof后计算MIPS?

qt - 是否有任何特定于 Qt 的分析器?

linux - 我可以获得用户空间中断或有关 PMC 溢出的其他指示吗

linux - 计算条件跳转

linux - 为什么 Linux 性能计数器中的指令数是不确定的

c++ - `xxxx' : looks like a function definition, 但是没有参数列表;跳过明显的 body