You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取Linux Perf的perf script二进制转文本功能并实现跨平台?

解决方案:提取Perf的perf.data转文本功能并实现跨平台

核心思路

perf script的核心是解析perf.data二进制文件并格式化输出,和性能分析的实时采样、内核交互部分完全解耦,所以确实可以剥离出独立的跨平台模块。关键是梳理依赖链,砍掉Linux特有且非必需的部分。


步骤1:梳理核心依赖与可剥离模块

从builtin-script.c的依赖入手,把无关模块全部砍掉:

  • 必需模块:
    • libperfdata:负责perf.data文件的读写和事件遍历
    • libtraceevent:解析perf事件的格式定义
    • libsymbol:可选,如果你需要将事件中的地址解析为函数名(只需要原始事件数据可跳过)
    • 格式化输出逻辑:builtin-script.c里的print_event等输出函数
  • 可剥离的Linux特有模块:
    • 所有和实时性能采样相关的代码(比如perf record的依赖)
    • 依赖/proc文件系统的内核符号解析逻辑(不需要内核符号化可直接删掉)
    • 依赖<sys/syscall.h>、<sys/mman.h>等Linux系统头文件的主动系统调用(比如内存映射可换成标准文件IO)

步骤2:替换Linux特有的依赖实现

针对必须保留但Linux特有的部分,做跨平台兼容:

  • 内存映射替代:perf默认用mmap映射perf.data提升效率,跨平台可换成标准C的fopen+fread逐块读取,性能稍降但完全跨平台。
  • 系统调用号依赖:perf.data里记录的是已捕获的事件,不需要主动调用系统调用,所以<sys/syscall.h>相关定义只需要保留事件格式里的常量(比如事件类型)即可。
  • 符号解析跨平台:如果需要符号化,不要用Linux特有的/proc/kcore,改用跨平台的符号解析库,比如libdw(elfutils的一部分,支持多平台)或者libbfd(GNU binutils的库)。

步骤3:构建最小化编译单元

  1. 从Perf源码中复制以下目录到你的项目:
    • tools/perf/lib/perfdata/
    • tools/perf/lib/traceevent/
    • tools/perf/lib/symbol/(可选)
    • tools/perf/include/(头文件)
    • builtin-script.c及相关输出格式化代码
  2. 编写简化的入口函数,模拟cmd_script的核心逻辑:
    #include "builtin-script.h"
    #include "perfdata.h"
    
    int main(int argc, char **argv) {
        // 只保留必要参数:perf.data路径、输出文件路径
        struct script_opts opts = {
            .input_name = "./perf.data",
            .output_name = "./perf_script_output.txt",
            // 关闭所有性能分析相关选项
            .sample_time = false,
            .sample_cpu = false,
            // 根据需要开启格式化选项
        };
        return cmd_script(argc, argv, &opts);
    }
    
  3. 用CMake/Makefile做条件编译:
    • 用#ifdef __linux__包裹Linux特有的残留代码
    • 链接时只包含必需的库,排除Perf的其他builtin模块(比如builtin-record.o、builtin-top.o等)

备选方案:封装子进程调用(快速实现)

如果剥离源码太耗时,也可以在代码中调用perf script命令作为子进程,通过管道捕获输出:

#include <iostream>
#include <cstdio>
#include <string>

std::string perf_data_to_text(const std::string& perf_data_path) {
    std::string cmd = "perf script -i " + perf_data_path;
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) return "";

    char buffer[128];
    std::string result;
    while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
        result += buffer;
    }
    pclose(pipe);
    return result;
}

缺点是依赖目标平台安装了Perf工具,无法做到完全跨平台,但实现成本极低。

内容的提问来源于stack exchange,提问作者Jing Herng Loo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:04:51