From 79e44828f4d083b11bcf2d16c8d7afe883f72389 Mon Sep 17 00:00:00 2001 From: glx Date: Thu, 24 Jul 2025 10:59:55 +0800 Subject: [PATCH] Fix bug: cannot read perf.data collected from multithread process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LD_LIBRARY_PATH=./output/lib/ ./pmu_perfdata -e cycles,branch-misses -- /tmp/test 对多线程应用采集多个事件,运行的应用会持续创建线程,在此场景下输出perf.data,用perf script读取会报错bad address。 原因是perf.data会包含PERF_RECORD_FORK。 由于采集时,attr.sample_id_all=1,对于非PERF_RECORD_SAMPLE,会记录额外id信息: struct sample_id { { u32 pid, tid; } /* if PERF_SAMPLE_TID set */ { u64 time; } /* if PERF_SAMPLE_TIME set */ { u64 id; } /* if PERF_SAMPLE_ID set */ { u64 stream_id;} /* if PERF_SAMPLE_STREAM_ID set */ { u32 cpu, res; } /* if PERF_SAMPLE_CPU set */ { u64 id; } /* if PERF_SAMPLE_IDENTIFIER set */ }; 但是PERF_RECORD_FORK写入perf.data的时候并没有带上这些信息,perf script在读取的时候需要通过id来确认PERF_RECORD_FORK属于哪个event(perf_evlist__event2id), 因此读到了错误的id,无法找到对应的event。 修改方法: 在生成perf.data的时候去掉sample_id_all,这样,perf script在读取的时候,对非PERF_RECORD_SAMPLE,不会进入perf_evlist__event2id,绕过该逻辑。 perf.data内的PERF_RECORD_FORK便不会包含时间戳信息,对于编译反馈优化来说暂无影响。 --- docs/Details_Usage.md | 7 ++++++- go/src/libkperf/kperf/kperf.go | 8 ++++---- pmu/dump_perf_data.cpp | 1 - 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/Details_Usage.md b/docs/Details_Usage.md index a4d3c07..99175d8 100644 --- a/docs/Details_Usage.md +++ b/docs/Details_Usage.md @@ -1588,7 +1588,12 @@ func main() { time.Sleep(time.Second) kperf.PmuDisable(pd) dataVo, err := kperf.PmuRead(pd) - file := kperf.PmuBeginWrite("/tmp/test.data", attr) + file, err := kperf.PmuBeginWrite("/tmp/test.data", attr) + if file == nil { + fmt.Printf("failed to write: %v\n", err) + return + } + kperf.PmuWriteData(file, dataVo) kperf.PmuEndWrite(file) } diff --git a/go/src/libkperf/kperf/kperf.go b/go/src/libkperf/kperf/kperf.go index 2d46d6d..38345a9 100644 --- a/go/src/libkperf/kperf/kperf.go +++ b/go/src/libkperf/kperf/kperf.go @@ -1306,16 +1306,16 @@ func (data *PmuData) appendBranchRecords(pmuData C.struct_PmuData) { // It is a simplified perf.data only include basic fields for perf sample, // including id, cpu, tid, pid, addr and branch stack. // It also includes sample like mmap, mmap2, comm, fork. -func PmuBeginWrite(path string, attr PmuAttr) C.PmuFile { +func PmuBeginWrite(path string, attr PmuAttr) (C.PmuFile, error) { cAttr, err := ToCPmuAttr(attr) defer FreePmuAttr(cAttr) if err != 0 { - return nil + return nil, errors.New(C.GoString(C.Perror())) } cFilePath := C.CString(path) file := C.PmuBeginWrite(cFilePath, cAttr) - return file + return file, errors.New(C.GoString(C.Perror())) } // brief Write PmuData list to file. @@ -1334,4 +1334,4 @@ func PmuWriteData(file C.PmuFile, dataVo PmuDataVo) error { // brief End to write file. func PmuEndWrite(file C.PmuFile) { C.PmuEndWrite(file) -} \ No newline at end of file +} diff --git a/pmu/dump_perf_data.cpp b/pmu/dump_perf_data.cpp index 5fdb04c..e6e16fd 100644 --- a/pmu/dump_perf_data.cpp +++ b/pmu/dump_perf_data.cpp @@ -499,7 +499,6 @@ private: attr.sample_type = GetSampleType(); // use attr in 5.10 attr.size = sizeof(perf_event_attr); - attr.sample_id_all = 1; PerfFileAttr fattr = {0}; fattr.attr = attr; // This is the offset of event id. -- Gitee