在环形缓冲区中,我们可以只为 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/