1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-libkperf

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README.md 7.6 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
echodo Отправлено 11.06.2025 09:50 443ab28

libkperf

描述

libkperf是一个轻量级linux性能采集库,它能够让开发者以API的方式执行性能采集,包括pmu采样和符号解析。libkperf把采集数据内存化,使开发者能够在内存中直接处理采集数据,避免了读写perf.data带来的开销。

在什么时候可能会需要libkperf

  • 想要轻量化采集系统和应用的性能数据。
  • 当分析一个高负载的应用,却不想对应用性能有较大影响的时候。
  • 不想管理多个性能分析进程(perf),想获取易于解析的性能数据。
  • 想轻量化地获取cpu的热点。
  • 想分析cache的miss分布和时延。
  • 想要跟踪系统调用函数的耗时。
  • 想获取内存读写带宽。
  • 想获取网络带宽和时延。

支持的CPU架构

  • 鲲鹏

支持的OS

  • openEuler
  • OpenCloudOS
  • TencentOS
  • KylinOS
  • CentOS

Release Notes

v1.3:

  • 支持对系统调用函数的耗时采集。
  • 支持历史分支记录的采集(BRBE)。

v1.2:

  • 支持tracepoint的采集和跟踪。
  • 支持事件分组采集。

v1.1:

  • 提供python的API。

v1.0:

  • 支持采集pmu计数、采样和SPE采样功能。
  • 支持core和uncore事件的采集。
  • 支持符号解析功能。

编译

最低依赖gcc版本:

  • gcc-4.8.5 和 glibc-2.17

最低依赖python版本:

  • python-3.6

编译生成动态库和C的API:

git clone --recurse-submodules https://gitee.com/openeuler/libkperf.git
cd libkperf
bash build.sh install_path=/path/to/install

说明:

  • 如果编译报错提示没有numa.h文件,需要先安装对应的numactl-devel包。
  • 如果编译连接在Found PythonInterp报CMake错误,需要先安装所需的python3-devel包。

如果想要编译调试版本:

bash build.sh install_path=/path/to/install build_type=debug

如果想要编译python包:

bash build.sh install_path=/path/to/install python=true

安装后若需要卸载python库, 可以执行下述命令

python3 -m pip uninstall -y libkperf

想要编译go的包

bash build.sh go=true

执行成功后,需要把go/src/libkperf整个目录拷贝到GOPATH/src/下,GOPATH为用户项目目录

文档

详细文档可以参考docs目录:

Python API文档可以参考docs目录:

Go API文档可以参考GO_API.md:

快速使用

主要有以下几个API:

  • PmuOpen 输入pid、core id和event,打开pmu设备。
  • PmuEnable 开始收集。
  • PmuRead 读取采集数据。
  • PmuDisable 停止收集。
  • PmuClose 关闭pmu设备。

以下是一些示例:

  • 获取进程的pmu计数
#include <iostream>
#include "symbol.h"
#include "pmu.h"
#include "pcerrc.h"

int main() {
    int pidList[1];
    pidList[0] = getpid();
    char *evtList[1];
    evtList[0] = "cycles";
    // 初始化事件列表,指定需要计数的事件cycles。
    PmuAttr attr = {0};
    attr.evtList = evtList;
    attr.numEvt = 1;
    attr.pidList = pidList;
    attr.numPid = 1;
    // 调用PmuOpen,返回pd。pd表示该任务的id。
    int pd = PmuOpen(COUNTING, &attr);
    // 开始采集。
    PmuEnable(pd);
    // 采集1秒。
    sleep(1);
    // 停止采集。
    PmuDisable(pd);
    PmuData *data = NULL;
    // 读取PmuData,它是一个数组,长度是len。
    int len = PmuRead(pd, &data);
    for (int i = 0; i < len; ++i) {
        PmuData *d = &data[i];
        std::cout << "evt=" << d->evt << "count=" << d->count << std::endl;
    }
    // 释放PmuData。
    PmuDataFree(data);
    // 类似fd,当任务结束时调用PmuClose释放资源。
    PmuClose(pd);
}
  • 对进程进行采样
#include <iostream>

#include "symbol.h"
#include "pmu.h"
#include "pcerrc.h"

int main() {
    int pid = getpid();
    int pidList[1];
    pidList[0] = pid;
    char *evtList[1];
    evtList[0] = "cycles";
    // 初始化事件列表,指定需要计数的事件cycles。
    PmuAttr attr = {0};
    attr.evtList = evtList;
    attr.numEvt = 1;
    attr.pidList = pidList;
    attr.numPid = 1;
    attr.symbolMode = RESOLVE_ELF_DWARF;
    attr.callStack = 1;
    attr.freq = 200;
    attr.useFreq = 1;
    // 调用PmuOpen,返回pd。pd表示该任务的id。
    int pd = PmuOpen(SAMPLING, &attr);
    // 开始采集。
    PmuEnable(pd);
    // 采集1秒。
    sleep(1);
    // 停止采集。
    PmuDisable(pd);
    PmuData *data = NULL;
    // 读取PmuData,它是一个数组,长度是len。
    int len = PmuRead(pd, &data);
    for (int i = 0; i < len; ++i) {
        // 获取数组的一个元素。
        PmuData *d = &data[i];
        // 获取调用栈对象,它是一个链表。
        Stack *stack = d->stack;
        while (stack) {
            // 获取符号对象。
            if (stack->symbol) {
                Symbol *data = stack->symbol;
                std::cout << std::hex << data->addr << " " << data->symbolName << "+0x" << data->offset << " "
                          << data->codeMapAddr << " (" << data->module << ")"
                          << " (" << std::dec << data->fileName << ":" << data->lineNum << ")" << std::endl;

            }
            stack = stack->next;
        }
    }
    // 释放PmuData。
    PmuDataFree(data);
    // 类似fd,当任务结束时调用PmuClose释放资源。
    PmuClose(pd);
}
  • Python 例子
import time
from collections import defaultdict
import subprocess

import kperf

def Counting():
    evtList = ["r11", "cycles"]
    pmu_attr = kperf.PmuAttr(evtList=evtList)
    pd = kperf.open(kperf.PmuTaskType.COUNTING, pmu_attr)
    if pd == -1:
        print(kperf.errorno())
        print(kperf.error())

    kperf.enable(pd)

    for _ in range(3):
        time.sleep(1)
        data_iter = kperf.read(pd)
        evtMap = defaultdict(int)
        for data in data_iter.iter:
            evtMap[data.evt] += data.count

        for evt, count in evtMap.items():
            print(f"event: {evt} count: {count}")

    kperf.disable(pd)
    kperf.close(pd)
  • Go 例子
import "libkperf/kperf"
import "fmt"
import "time"

func main() {
  attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF}
	fd, err := kperf.PmuOpen(kperf.COUNT, attr)
	if err != nil {
		fmt.Printf("kperf pmuopen counting failed, expect err is nil, but is %v\n", err)
    return
	}
	kperf.PmuEnable(fd)
	time.Sleep(time.Second)
	kperf.PmuDisable(fd)

	dataVo, err := kperf.PmuRead(fd)
	if err != nil {
		fmt.Printf("kperf pmuread failed, expect err is nil, but is %v\n", err)
    return
	}

	for _, o := range dataVo.GoData {
    fmt.Printf("event: %v count: %v\n", o.Evt, o.Count)
	}
	kperf.PmuDataFree(dataVo)
	kperf.PmuClose(fd)
}

示例代码快速运行参考:

  • 针对C++示例代码: 可以将示例代码放到一个c++源文件的main函数中,并引用此动态库相关的头文件(#include "symbol.h"、#include "pmu.h"、#include "pcerrc.h"),再使用g++编译链接此动态库,生成可执行文件即可运行。

编译指令参考:

g++ -o example example.cpp -I /install_path/include -L /install_path/lib -lkperf -lsym
  • 针对python示例代码: 可以将示例代码放到一个python源文件的main函数中,并导入此动态库相关的头文件包(import kperf、import ksym),在运行此python文件即可。

运行指令参考:

python example.py
  • 针对Go示例代码: 可以直接跳转到 go/src/libkperf_test目录下
go test -v # 全部运行
go test -v -test.run TestCount #指定运行的用例

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/openeuler-libkperf.git
git@api.gitlife.ru:oschina-mirror/openeuler-libkperf.git
oschina-mirror
openeuler-libkperf
openeuler-libkperf
master