kperf.open
kperf.open(collector_type: kperf.PmuTaskType, pmu_attr: kperf.PmuAttr) 初始化Pmu事件
-
class PmuTaskType
- COUNTING PMU计数模式
- SAMPLING PMU采样模式
- SPE_SAMPLING SPE采样模式
-
class PmuAttr
- evtList 采集的事件列表,事件列表可以通过perf list查询
- pidList 采集的进程id列表
- cpuList 指定的使用cpu核采集列表,默认采集所有逻辑核
- evtAttr
用于对各事件做单独属性定义
- groupId 事件分组ID,同组事件需要使用相同数字表示,不同组事件使用不同的数字代表,如果数字为-1,则不参与事件分组
- period 如果PmuAttr中useFreq=True则为采样频率,否则为采样间隔
- excludeUser 排除对用户态数据的采集
- excludeKernel 排除对内核态数据的采集
- sampleRate 采样频率,可通过/proc/sys/kernel/perf_event_max_sample_rate调整最大的采样频率
- useFreq 是否启用采样频率,如果设置,将可以使用采样频率
- excludeUser 排除对用户态数据的采集
- excludeKernel 排除对内核态数据的采集
- symbolMode 符号采集模式 NO_SYMBOL_RESOLVE = 0 不支持符号采集 RESOLVE_ELF = 1 仅支持ELF数据采集,解析function,不解析行号 RESOLVE_ELF_DWARF = 2 既支持ELF数据采集,也支持行号解析
- callStack 是否采集调用栈,默认不采集,只取栈顶数据
- blockedSample 是否执行blocked Sample采样
- dataFilter
- SPE_FILTER_NONE = 0
- TS_ENABLE = 1 << 0 使能通用计时器
- PA_ENABLE = 1 << 1 采集物理地址
- PCT_ENABLE = 1 << 2 采集物理地址的事件戳替代虚拟地址
- JITTER = 1 << 16 采样时使用共振防止抖动
- BRANCH_FILTER = 1 << 32 只采集分支数据
- LOAD_FILTER = 1 << 33 只采集已加载数据
- STORE_FILTER = 1 << 34 只采集存储数据
- SPE_DATA_ALL = TS_ENABLE | PA_ENABLE | PCT_ENABLE | JITTER | BRANCH_FILTER | LOAD_FILTER | STORE_FILTER
- evFilter
- SPE_EVENT_NONE = 0
- SPE_EVENT_RETIRED = 0x2 # instruction retired
- SPE_EVENT_L1DMISS = 0x8 # L1D refill
- SPE_EVENT_TLB_WALK = 0x20 # TLB refill
- SPE_EVENT_MISPREDICTED = 0x80 # mispredict
- minLatency 仅收集该latency或者更高的样本数据
- includeNewFork 是否支持子线程拆分,仅在COUNTING模式中支持
- branchSampleFilter
- KPERF_NO_BRANCH_SAMPLE = 0 不采集branch sample stack数据
- KPERF_SAMPLE_BRANCH_USER = 1 << 0 分支目标位于用户空间
- KPERF_SAMPLE_BRANCH_KERNEL = 1 << 1 分支目标位于内核空间
- KPERF_SAMPLE_BRANCH_HV = 1 << 2 分支目标位于虚拟机管理程序中
- KPERF_SAMPLE_BRANCH_ANY = 1 << 3 任意分支目标
- KPERF_SAMPLE_BRANCH_ANY_CALL = 1 << 4 任意调用分支(包括直接调用,间接调用和远程调用)
- KPERF_SAMPLE_BRANCH_ANY_RETURN = 1 << 5 任意返回分支
- KPERF_SAMPLE_BRANCH_IND_CALL = 1 << 6 间接调用分支
- KPERF_SAMPLE_BRANCH_ABORT_TX = 1 << 7 事物性内存中止
- KPERF_SAMPLE_BRANCH_IN_TX = 1 << 8 事物内存分支
- KPERF_SAMPLE_BRANCH_NO_TX = 1 << 9 分支不在事物性内存事物中
- KPERF_SAMPLE_BRANCH_COND = 1 << 10 条件分支
- KPERF_SAMPLE_BRANCH_CALL_STACK = 1 << 11 调用栈分支
- KPERF_SAMPLE_BRANCH_IND_JUMP = 1 << 12 跳跃分支
- KPERF_SAMPLE_BRANCH_CALL = 1 << 13 调用分支
- KPERF_SAMPLE_BRANCH_NO_FLAGES = 1 << 14 无标志
- KPERF_SAMPLE_BRANCH_NO_CYCLES = 1 << 15 无循环
- KPERF_SAMPLE_BRANCH_TYPE_SAVE = 1 << 16 存储分支类型 branch_sample_type对应的比特值,使用方式 branchSampleMode = kperf.BranchSampleFilter.KPERF_SAMPLE_BRANCH_ANY | kperf.BranchSampleFilter.KPERF_SAMPLE_BRANCH_USER pmu_attr = kperf.PmuAttr(sampleRate=1000, useFreq=True, pidList=pidList, evtList=evtList, branchSampleFilter=branchSampleMode) 仅支持SAMPLING模式, 其中KPERF_SAMPLE_BRANCH_USER, KPERF_SAMPLE_BRANCH_KERNEL, KPERF_SAMPLE_BRANCH_HV使用时必须搭配KPERF_SAMPLE_BRANCH_ANY或者KPERF_SAMPLE_BRANCH_ANY之后的值一起使用
- cgroupNameList; 采集cgroup的名称列表
- numCgroup; 采集cgroup的个数
- enableUserAccess 是否直接读取寄存器,仅支持COUNTING模式
- enableBpf 是否基于BPF采集,仅支持COUNTING模式
- enableHwMetric 是否使能hWMetric, 该模式需要两个事件指标配对进行采样
- enableOnExec 使能enableOnExec,适用于launch模式,在fork之后,未拉起子应用之前PmuOpen,PmuOpen成功之后再去拉起子应用,能规避多线程和短时间应用无数据问题
- perThread per thread的模式,每个线程会单独开一个perf_event_open,开启时cpu设置为-1,去监测对应事件,但是该模式不会监测新开子进程的该事件,并且只支持sampling采样
-
返回值是int值 fd > 0 成功初始化 fd == -1 初始化失败,可通过 kperf.error()查看错误信息 以下是kperf.open的一个示例:
# python代码示例
import kperf
import ksym
import time
evtList = ["cycles", "branch-misses"]
pmu_attr = kperf.PmuAttr(evtList=evtList)
pd = kperf.open(kperf.PmuTaskType.COUNTING, pmu_attr)
if pd == -1:
print(kperf.error())
exit(1)
kperf.enable
kperf.enable(pd: int) 该接口用于开启某个pd的采样能力 pd为kperf.open返回值 返回值为int 如果返回值>0,则使能异常 如果返回值=0, 则使能正常
kperf.disable
kperf.disable(pd: int) 该接口用于关闭某个pd的采样 pd为kperf.open返回值 返回值为int 如果返回值>0,则关闭采集异常 如果返回值=0, 则关闭采集正常 一般kperf.enable和kperf.disable搭配使用,以下为示例,相当于采集1s的数据:
kperf.enable(pd)
time.sleep(1)
kperf.disable(pd)
kperf.read
kperf.read(pd: int) 读取pd采样的数据 pd为kperf.open返回值 返回值为PmuData
- class PmuData
- len 数据长度
- iter 返回Iterator[ImplPmuData]
- free 将当前PmuData数据清理
- class ImplPmuData
- stack: Stack=None
- symbol
- addr 地址
- module 模块名称
- symbolName 符号名
- mangleName mangle后的符号名
- fileName dwarf文件路径
- lineNum 行号
- offset 地址偏移
- codeMapEndAddr 结束地址
- codeMapAddr 初始地址
- firstLine 首行
- mntPoint 挂载点
- next 下一个stack
- prev 前一个stack
- symbol
- evt: 事件
- ts: Pmu采集时间戳
- pid: 进程ID
- tid: 线程ID
- cpu: cpu核
- cpuTopo:
- coreId 系统核ID
- numaId numaID
- socketId socketId
- comm: 执行指令名称
- period: 采样间隔
- count: 计数
- countPercent: 计数比值,使能时间/运行时间
- ext: SPE独特数据
- pa 物理地址
- va 虚拟地址
- event 事件ID
- lat 调度操作到执行操作的周期数
- source 记录加载或存储操作的数据来源
- branchRecords brbe数据
- iter brbe数据迭代器
- len brbe数据长度
- rawData: tracepointer数据指针,搭配kperf.get_field和Kperf.get_field_exp使用
- cgroupName cgroup名称
- stack: Stack=None
以下为kperf.read示例
# python代码示例
pmu_data = kperf.read(pd)
for data in pmu_data.iter:
print(f"cpu {data.cpu} count {data.count} evt {data.evt}")
kperf.close
kperf.close(pd: int) 该接口用于清理该pd所有的对应数据,并移除该pd
kperf.dump
dump(pmuData: PmuData, filepath: str, dump_dwf: int)
- pmuData 由kperf.read返回的PmuData数据
- filePath 数据落盘写入路径
- dump_dwf 是否写入dwarf数据
kperf.get_field
get_field(pmu_data: ImplPmuData, field_name: str, value: c_void_p)
获取tracepointer format某个字段数据,format数据可通过/sys/kernel/tracing/events/或者/sys/kernel/debug/tracing/events/进行查找
- pmu_data: ImplePmuData 详细见kperf.read返回数据说明
- field_name 字段名称
- value 字段属性指针
以下为kperf.get_field示例
import kperf
import ksym
import time
from ctypes import *
evtList = ["sched:sched_switch"]
pmu_attr = kperf.PmuAttr(
evtList=evtList
)
pd = kperf.open(kperf.PmuTaskType.SAMPLING, pmu_attr)
kperf.enable(pd)
time.sleep(1) # 采集时间为1s
kperf.disable(pd)
pmu_data = kperf.read(pd)
for data in pmu_data.iter:
next_comm = create_string_buffer(128) #该长度可适当减少,但最好设置比最终获取的长度大,否则最终将无法获取对应结果。
kperf.get_field(data, "next_comm", next_comm)
next_comm = next_comm.value.decode("utf-8")
prev_pid = c_uint(0)
kperf.get_field(data, "prev_pid", pointer(prev_pid))
print(f"next_comm={next_comm};prev_pid={prev_pid.value}")
kperf.get_field_exp
get_field_exp(pmu_data: ImplPmuData, field_name: str) 获取某个字段属性说明
- pmu_data: ImplePmuData 详细见kperf.read返回数据说明
- field_name 字段名称 返回数据
- class SampleRawField
- fieldName 属性名称
- fieldStr 符号单位
- offset 偏移字节数
- size 数据大小
- isSigned 有无符号
field = kperf.get_field_exp(data, "name")
print("field_str={} field_name={} size={} offset={} isSigned={}"
.format(field.field_name, field.field_str, field.size, field.offset, field.is_signed))
kperf.event_list
event_list(event_type: PmuEventType) 查找所有的事件列表
- class PmuEventType:
- CORE_EVENT = 0 获取core事件列表
- UNCORE_EVENT = 1 获取uncore事件列表
- TRACE_EVENT = 2 获取tracepointer事件列表
- ALL_EVENT = 3 获取所有的事件列表
- 返回数据 Iterator[str],可通过for循环遍历该单元
以下为kperf.event_list示例
# python代码示例
for evt in kperf.event_list(kperf.PmuEventType.CORE_EVENT):
print(f"event name: {evt}")
kperf.trace_open
kperf.trace_open(trace_type: kperf.PmuTraceType, pmu_trace_attr: kperf.PmuTraceAttr) # 初始化采集系统调用函数能力
- class PmuTraceType:
- TRACE_SYS_CALL = 0 采集系统调用函数事件
- class PmuTraceAttr:
- funcs:采集的系统调用函数列表,可以查看/usr/include/asm-generic/unistd.h文件,默认为空,表示采集所有系统调用函数
- pidList:采集的进程列表,默认为空,表示采集所有进程
- cpuList:采集的cpu列表,默认为空,表示采集所有cpu
- 返回值是int类型的, pd > 0 表示打开成功, pd == -1 初始化失败,可通过kperf.error()查看错误信息,调用样例类似kperf.open()
以下是kperf.trace_open的一个示例:
# python代码示例
import kperf
import time
funcs = ["read", "write"]
pmu_trace_attr = kperf.PmuTraceAttr(funcs=funcs)
pd = kperf.trace_open(kperf.PmuTraceType.TRACE_SYS_CALL, pmu_trace_attr)
if pd == -1:
print(kperf.error())
exit(1)
kperf.trace_enable、kperf.trace_disable
调用逻辑类似kperf.enable、kperf.disable,用于配置采集启动和结束的时刻,两个调用之间的时间即是采集的时间段
kperf.trace_read
kperf.trace_read(pd: int) pd为kperf.trace_open返回值 返回值是PmuTraceData
- class PmuTraceData:
- len: 数据长度
- iter: 返回iterator[lmplPmuTraceData]
- free: 释放当前PmuTraceData数据
- class lmplPmuTraceData:
- funcs: 系统调用函数名
- startTs: 耗时起始时刻
- elapsedTime: 耗时时间
- pid: 进程id
- tid: 线程id
- cpu: cpu号
- comm: 执行指令名称 以下为kperf.trace_read示例
pmu_trace_data = kperf.trace_read(pd)
for pmu_trace in pmu_trace_data.iter:
print("funcs: %s, elapsedTime: %d, pid: %d, tid: %d, cpu: %d, comm: %s" % (pmu_trace.funcs, pmu_trace.elapsedTime, pmu_trace.pid, pmu_trace.tid, pmu_trace.cpu, pmu_trace.comm))
kperf.trace_close
kperf.trace_close(pd: int): 该接口用于清理该pd所有对应的数据,并移除该pd
kperf.sys_call_func_list
kperf.sys_call_func_list(): 查找所有的系统调用函数列表
- 返回数据 iterator[str], 可通过for循环遍历该单元
以下为kperf.sys_call_func_list示例
# python代码示例
for func_name in kperf.sys_call_func_list():
print(f"syscall function name: {func_name}")
kperf.device_open
kperf.device_open(dev_attr: List[PmuDeviceAttr]) 初始化采集uncore事件指标的能力
- class PmuDeviceAttr:
- metric: 指定需要采集的指标
- PMU_DDR_READ_BW 采集每个channel的ddrc的读带宽,单位:Bytes
- PMU_DDR_WRITE_BW 采集每个channel的ddrc的写带宽,单位:Bytes
- PMU_L3_TRAFFIC 采集每个core的L3的访问字节数,单位:Bytes
- PMU_L3_MISS 采集每个core的L3的miss数量,单位:count
- PMU_L3_REF 采集每个core的L3的总访问数量,单位:count
- PMU_L3_LAT 采集每个cluster的L3的总时延,单位:cycles
- PMU_PCIE_RX_MRD_BW 采集pcie设备的rx方向上的读带宽,单位:Bytes/us
- PMU_PCIE_RX_MWR_BW 采集pcie设备的rx方向上的写带宽,单位:Bytes/us
- PMU_PCIE_TX_MRD_BW 采集pcie设备的tx方向上的读带宽,单位:Bytes/us
- PMU_PCIE_TX_MWR_BW 采集pcie设备的tx方向上的读带宽,单位:Bytes/us
- PMU_PCIE_RX_MRD_LAT 采集pcie设备的rx方向上的读延时,单位:ns
- PMU_PCIE_RX_MWR_LAT 采集pcie设备的rx方向上的写延时,单位:ns
- PMU_PCIE_TX_MRD_LAT 采集pcie设备的tx方向上的读延时,单位:ns
- PMU_SMMU_TRAN 采集指定smmu设备的地址转换次数,单位:count
- PMU_HHA_CROSS_NUMA 采集每个numa的跨numa访问HHA的操作比例
- PMU_HHA_CROSS_SOCKET 采集每个numa的跨socket访问HHA的操作比例
- bdf: 指定需要采集设备的bdf号,只对pcie带宽和smmu指标有效
- port: 指定需要采集设备的port号,只对pcie延时指标有效
- metric: 指定需要采集的指标
- 返回值是int类型,pd > 0表示初始化成功,pd == -1初始化失败,可通过kperf.error()查看错误信息,以下是一个kperf.device_open的示例
# python代码示例
import kperf
import time
dev_attr = [
kperf.PmuDeviceAttr(metric=kperf.PmuDeviceMetric.PMU_L3_TRAFFIC)
]
pd = kperf.device_open(dev_attr)
if pd == -1:
print(kperf.error())
exit(1)
kperf.get_device_metric
kperf.get_device_metric(pmu_data: PmuData, device_attr: List[PmuDeviceAttr]) 对原始read接口的数据,按照device_attr中给定的指标进行数据聚合接口,返回值是PmuDeviceData
- class PmuData: read接口返回的原始数据
- clase PmuDeviceAttr: 指定需要聚合的指标参数
- class PmuDeviceData:
- len: 数据长度
- iter: 返回iterator[ImplPmuDeviceData]
- free: 释放当前PmuDeviceData
- class DdrDataStructure:
- channelId: ddr数据的channel编号
- ddrNumaId: ddr数据的numa编号
- socketId: ddr数据的socket编号
- class ImplPmuDeviceData:
- metric: 采集的指标
- count:指标的计数值
- mode: 指标的采集类型,按core、按numa、按cluster、按channel还是按bdf号
- union:
- coreId: 数据的core编号
- numaId: 数据的numa编号
- cluster: 簇ID
- bdf: 数据的bdf编号
- port: 数据的port编号
- DdrDataStructure: ddr相关的统计数据
kperf.device_bdf_list
kperf.device_bdf_list(bdf_type: PmuBdfType): 查找当前系统pcie指标中有效的bdf列表和smmu指标中的有效bdf列表
- class PmuBdfType: PMU_BDF_TYPE_PCIE: pcie指标类型 PMU_BDF_TYPE_SMMU: smmu指标类型
- 返回数据iterator[str],可通过for循环遍历该单元 以下是kperf.device_bdf_list示例
# python代码示例
bdf_type = kperf.PmuBdfType.PMU_BDF_TYPE_SMMU
bdf_list = kperf.device_bdf_list(bdf_type)
print(bdf_list)
kperf.get_cpu_freq
kperf.get_cpu_freq(core: int): 查询当前系统指定core的实时CPU频率
- core: CPU的core编号
- 返回值:指定core的实时频率,单位: Hz
# python代码示例
core = 6
cpu6_freq = kperf.get_cpu_freq(core)
kperf.get_cluster_core
kperf.get_cluster_core(clusterId: int): 查询指定clusterId下对应的core列表
- clusterId: CPU的clusterId编号
- 返回值:当前clusterId下对应的core列表,出现错误则列表为空
# python代码示例
clusterId = 1
cluster_cores = kperf.get_cluster_core(clusterId)
kperf.get_numa_core
kperf.get_numa_core(numaId: int): 查询指定numaId下对应的core列表
- numaId: CPU的numaId编号
- 返回值:当前numaId下对应的core列表,出现错误则列表为空
# python代码示例
numaId = 1
numa_cores = kperf.get_numa_core(numaId)
kperf.open_cpu_freq_sampling
def open_cpu_freq_sampling(period: int) 开启cpu频率采集
kperf.close_cpu_freq_sampling
def close_cpu_freq_sampling() 关闭cpu频率采集
kperf.read_cpu_freq_detail
def read_cpu_freq_detail() -> CpuFreqDetail 读取开启频率采集到读取时间内的cpu最大频率、最小频率以及平均频率
#python代码示例
import kperf
import time
err = kperf.open_cpu_freq_sampling(100)
if err != 0:
print(f"error number: {kperf.errorno()} error message: {kperf.error()}")
exit(1)
dataList = kperf.read_cpu_freq_detail()
for item in dataList.iter:
print(f"cpuId={item.cpuId} minFreq={item.minFreq} maxFreq={item.maxFreq} avgFreq={item.avgFreq}")
kperf.close_cpu_freq_sampling()
kperf.resolvePmuDataSymbol
def resolvePmuDataSymbol(pmuData: PmuData) -> int: 当SymbolMode设置为3或者4时,可通过该接口解析read返回的PmuData数据中的符号
#python代码示例
import kperf
import time
event_name = "cycles"
pmu_attr = kperf.PmuAttr(
evtList=[event_name],
sampleRate=1000,
callStack=True,
useFreq=True,
symMode=kperf.RESOLVE_DELAY_ELF,
)
fd = kperf.open(kperf.PmuTaskType.SAMPLING, pmu_attr)
if fd == -1:
print(f"error number: {kperf.errorno()} error message: {kperf.error()}")
exit(1)
kperf.enable(fd)
time.sleep(1)
kperf.disable(fd)
pmu_data = kperf.read(fd)
err = kperf.resolvePmuDataSymbol(pmu_data)
if err != 0:
print(f"error number: {kperf.errorno()} error message: {kperf.error()}")
exit(1)
kperf.close(fd)
kperf.begin_write
用于把性能数据输出为perf.data格式的文件。该函数用于初始化该文件。
目前该文件只支持SAMPLING模式,只支持基本信息的输出,比如id, tid, pid, addr,也包含brbe的数据。
- path: 文件路径
- pattr: 采集任务的PmuAttr
- 返回值: 文件句柄,用于下面两个API的调用
kperf.write_data
把PmuData数组输出到文件里。
- file: 文件句柄
- data: 性能数据
- len: data的长度
- 返回值: 错误码
kperf.end_write
结束文件的写入。在写入结束时必须调用该函数,否则文件可能不完整。
- file: 文件句柄