kperf.PmuOpen

func PmuOpen(collectType C.enum_PmuTaskType, attr PmuAttr) (int, error) 初始化Pmu事件

  • var collecType C.enum_PmuTaskType

    • COUNT PMU计数模式
    • SAMPLE PMU采样模式
    • SPE SPE采样模式
  • type PmuAttr struct

    • EvtList []string 采集的事件列表,事件列表可以通过perf list查询
    • PidList []int 采集的进程id列表
    • CpuList []int 指定的使用cpu核采集列表,默认采集所有逻辑核
    • EvtAttr []EvtAttr 用于对各事件做单独属性定义
      • GroupId 事件分组ID,同组事件需要使用相同数字表示,不同组事件使用不同的数字代表,如果数字为-1,则不参与事件分组
      • Period 如果PmuAttr中useFreq=True则为采样频率,否则为采样间隔
      • ExcludeUser 排除对用户态数据的采集
      • ExcludeKernel 排除对内核态数据的采集
    • SampleRate uint32 采样频率,可通过/proc/sys/kernel/perf_event_max_sample_rate调整最大的采样频率
    • UseFreq bool 是否启用采样频率,如果设置,将可以使用采样频率
    • ExcludeUser bool 排除对用户态数据的采集
    • ExcludeKernel bool 排除对内核态数据的采集
    • SymbolMode C.enum_SymbolMode 符号采集模式 ELF 仅支持ELF数据采集,解析function,不解析行号 ELF_DWARF 既支持ELF数据采集,也支持行号解析
    • CallStack 是否采集调用栈,默认不采集,只取栈顶数据
    • BlockedSample 是否执行blocked Sample采样
    • DataFilter C.enum_SpeFilter
      • TS_ENABLE 使能通用计时器
      • PA_ENABLE 采集物理地址
      • PCT_ENABLE 采集物理地址的事件戳替代虚拟地址
      • JITTER 采样时使用共振防止抖动
      • BRANCH_FILTER 只采集分支数据
      • LOAD_FILTER 只采集已加载数据
      • STORE_FILTER 只采集存储数据
      • SPE_DATA_ALL 以上所有Filter的组合
    • EvFilter C.enum_SpeEventFilter
      • SPE_EVENT_RETIRED instruction retired
      • SPE_EVENT_L1DMISS L1D refill
      • SPE_EVENT_TLB_WALK TLB refill
      • SPE_EVENT_MISPREDICTED mispredict
    • MinLatency 仅收集该latency或者更高的样本数据
    • IncludeNewFork bool 是否支持子线程拆分,仅在COUNTING模式中支持
    • BranchSampleFilter bool
      • 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 []string; 采集cgroup的名称列表
    • EnableUserAccess bool 是否直接读取寄存器,仅支持COUNTING模式
    • EnableBpf bool 是否基于BPF采集,仅支持COUNTING模式
    • EnableHwMetric bool 是否使能hWMetric, 该模式需要两个事件指标配对进行采样
    • EnableOnExec bool 使能enableOnExec,适用于launch模式,在fork之后,未拉起子应用之前PmuOpen,PmuOpen成功之后再去拉起子应用,能规避多线程和短时间应用无数据问题
    • PerThread bool per thread的模式,每个线程会单独开一个perf_event_open,开启时cpu设置为-1,去监测对应事件,但是该模式不会监测新开子进程的该事件,并且只支持sampling采样
  • 返回值是int,error, 如果error不等于nil,则返回的int值为对应采集任务ID

import "libkperf/kperf"
import "fmt"

func main() {
    attr := kperf.PmuAttr{EvtList:[]string{"cycles", "branch-misses"}}
    pd, err := kperf.PmuOpen(kperf.COUNT, attr)
	if err != nil {
		fmt.Printf("kperf pmuopen counting failed, expect err is nil, but is %v", err)
        return
	}
}

kperf.PmuEnable

func PmuEnable(fd int) error 该接口用于开启某个pd的采样能力

  • 返回值为error
  • error != nil,则使能异常
  • error == nil,则使能正常

kperf.PmuDisable

func PmuDisable(fd int) error

  • 返回值为error
  • error != nil,则关闭采集异常
  • error == nil,则关闭采集正常
kperf.PmuEnable(pd)
time.Sleep(time.Second)
kperf.PmuDisable(pd)

kperf.Read

func PmuRead(fd int) (PmuDataVo, error)

  • type PmuDataVo struct
    • GoData []PmuData
  • type PmuData struct
    • Evt string 事件
    • Ts uint64 Pmu采样时间戳
    • Pid int 进程ID
    • Tid int 线程ID
    • Cpu int CPUID
    • Comm string 运行指令名称
    • Period uint64 采样间隔
    • Count uint64 计数
    • CountPercent float64 计数比值,使能时间/运行时间
    • CpuTopo CpuTopology
      • CoreId 系统核ID
      • NumaId numa ID
      • SocketId socket ID
    • Symbols []sym.Symbol
      • Addr uint64 地址
      • Module string 模块名称
      • SymbolName string 符号名
      • MangleName string mangle后的符号名
      • FileName string dwarf对应文件路径
      • LineNum uint32 行号
      • Offset uint64 地址偏移
      • CodeMapEndAddr uint64 结束地址
      • CodeMapAddr uint64 初始地址
      • FirstLine uin32 首行
      • MntPoint string 挂载点
    • BranchRecords
      • FromAddr uint64 起始地址
      • ToAddr uint64 跳转地址
      • Cycles uint64 执行指令数
      • MisPred uint8 分支目标预测错误
      • Predicted uint8 分支预测正确
    • SpeExt SpeDataExt
      • Pa uint64 物理地址
      • Va uint64 虚拟地址
      • Event uint64 混合事件的比特位
      • Lat uint16 调度操作到执行操作的周期数
      • Source uint16 记录加载或存储操作的数据来源
    • cgroupName cgroup名称
//go 代码示例
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("cpu %v count %v evt %v\n", o.Cpu, o.Count, o.Evt)
}

kperf.PmuClose

func PmuClose(fd int) 接口用于清理该pd所有的对应数据,并移除该pd

kperf.PmuDumpData

func PmuDumpData(dataVo PmuDataVo, filePath string, dumpDwf bool) error

  • dataVo 由kperf.PmuRead读取返回的数据
  • filePath 数据转储的路径
  • dumpDwf 是否写入dwarf数据

kperf.PmuEventList

func PmuEventList(eventType C.enum_PmuEventType) []string 查找所有的事件列表

  • eventType
    • CORE_EVENT 获取core事件列表
    • UNCORE_EVENT 获取uncore事件列表
    • TRACE_EVENT 获取tracepointer事件列表
    • ALL_EVENT 获取所有的事件列表
  • 返回数据为事件列表
import "libkperf/kperf"
import "fmt"

func main() {
    evtList := kperf.PmuEventList(kperf.CORE_EVENT)
	if len(evtList) == 0 {
		fmt.Printf("core event can't be empty\n")
        return
	}
	for _, v := range evtList {
		fmt.Printf("%v\n", v)
	}
}

kperf.PmuTraceOpen

func PmuTraceOpen(traceType C.enum_PmuTraceType, traceAttr PmuTraceAttr) (int, error) 初始化采集系统调用函数能力

  • traceType C.enum_PmuTraceType
    • TRACE_SYS_CALL 采集系统调用函数事件
  • traceAttr PmuTraceAttr
    • Funcs []string 采集的系统调用函数列表,可以查看/usr/include/asm-generic/unistd.h文件,默认为空,表示采集所有系统调用函数
    • PidList []int采集的进程列表,默认为空,表示采集所有进程
    • CpuList []int采集的cpu列表,默认为空,表示采集所有cpu
  • 返回值是int和error,如果error!=nil则采集初始化失败,error==nil则采集初始化成功

以下是kperf.PmuTraceOpen用法:

import "libkperf/kperf"
import "fmt"

func main() {
    traceAttr := kperf.PmuTraceAttr{Funcs:[]string{"read", "write"}}
	taskId, err := kperf.PmuTraceOpen(kperf.TRACE_SYS_CALL, traceAttr)
	if err != nil {
		fmt.Printf("pmu trace open failed, expect err is nil, but is %v\n", err)
        return
	}
}

Kperf.PmuTraceEnable

func PmuTraceEnable(taskId int) error 该接口用于开启某个pd的采样能力

  • 返回值为error
  • error != nil,则使能异常
  • error == nil,则使能正常

kperf.PmuTraceDisable

func PmuTraceDisable(taskId int) error

  • 返回值为error
  • error != nil,则关闭采集异常
  • error == nil,则关闭采集正常
kperf.PmuTraceEnable(pd)
time.Sleep(time.Second)
kperf.PmuTraceDisable(pd)

kperf.PmuTraceRead

func PmuTraceRead(taskId int) (PmuTraceDataVo, error)

  • taskId int kperf.PmuOpen返回的taskId

  • type PmuTraceDataVo struct

    • GoTraceData []PmuTraceData
  • type PmuTraceData struct

    • FuncName string 系统调用函数名
    • ElapsedTime float64 耗时时间
    • StartTs 开始时间戳
    • Pid int 进程id
    • Tid int 线程id
    • Cpu int cpu号
    • Comm string 执行指令名称
traceList, err := kperf.PmuTraceRead(taskId)
if err != nil {
    fmt.Printf("pmu trace read failed, expect err is nil, but is %v\n", err)
    return
}

for _, v := range traceList.GoTraceData {
    fmt.Printf("funcName: %v, elapsedTime: %v ms startTs: %v pid: %v tid: %v, cpu: %v comm: %v\n", v.FuncName, v.ElapsedTime, v.StartTs, v.Pid, v.Tid, v.Cpu, v.Comm)
}

kperf.PmuTraceClose

func PmuTraceClose(taskId int) 该接口用于清理该pd所有对应的数据,并移除该taskId

kperf.PmuSysCallFuncList

func PmuSysCallFuncList() []string 查找所有的系统调用函数列表

import "libkperf/kperf"
import "fmt"

func main() {
    syscallList := kperf.PmuSysCallFuncList()
    if syscallList == nil {
        fmt.Printf("sys call list is empty\n")
    } else {
        for _, funcName := range syscallList {
            fmt.Printf("func name %v\n", funcName)
        }
    }
}

kperf.PmuDeviceBdfList

func PmuDeviceBdfList(bdfType C.enum_PmuBdfType) ([]string, error) 从系统中查找所有的bdf列表

  • bdfType C.enum_PmuBdfType
    • PMU_BDF_TYPE_PCIE PCIE设备对应的bdf
    • PMU_BDF_TYPE_SMMU SMMU设备对应的bdf
import "libkperf/kperf"
import "fmt"

func main() {
   pcieBdfList, err := kperf.PmuDeviceBdfList(kperf.PMU_BDF_TYPE_PCIE)
   if err != nil {
      fmt.Printf("kperf GetDeviceBdfList failed, expect err is nil, but is %v\n", err)
   } 
   for _, v := range pcieBdfList {
      fmt.Printf("bdf is %v\n", v)
   }
}

kperf.PmuDeviceOpen

func PmuDeviceOpen(attr []PmuDeviceAttr) (int, error) 初始化采集uncore事件指标的能力

  • type PmuDeviceAttr struct:
    • 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延时指标有效
  • 返回值是int和error,pd > 0表示初始化成功,pd == -1初始化失败,可通过kperf.error()查看错误信息,以下是一个kperf.device_open的示例
import "libkperf/kperf"
import "fmt"

func main() {
    deviceAttrs := []kperf.PmuDeviceAttr{kperf.PmuDeviceAttr{Metric: kperf.PMU_L3_LAT}}
	fd, err := kperf.PmuDeviceOpen(deviceAttrs)
	if err != nil {
		fmt.Printf("kperf PmuDeviceOpen failed, expect err is nil, but is %v\n", err)
	}
}

kperf.PmuGetDevMetric

func PmuGetDevMetric(dataVo PmuDataVo, deviceAttr []PmuDeviceAttr) (PmuDeviceDataVo, error) 对原始read接口的数据,按照device_attr中给定的指标进行数据聚合接口,返回值是PmuDeviceData

  • type PmuDataVo struct: PmuRead接口返回的原始数据
  • []PmuDeviceAttr: 指定需要聚合的指标参数
  • typ PmuDeviceDataVo struct:
    • GoDeviceData []PmuDeviceData
  • type DdrDataStructure struct { ChannelId uint32 ddr数据的channel编号 DdrNumaId uint32 ddr数据的numa编号 SocketId uint32 ddr数据的socket编号 }
  • type PmuDeviceData struct:
    • Metric C.enum_PmuDeviceMetric 采集的指标
      • Count float64 指标的计数值
      • Mode C.enum_PmuMetricMode 指标的采集类型,按core、按numa、按cluster、按channel还是按bdf号
      • CoreId uint32 数据的core编号
      • NumaId uint32 数据的numa编号
      • ClusterId uint32 簇ID
      • Bdf string 数据的bdf编号
    • Port string 数据的port编号
    • DdrDataStructure ddr相关的统计数据

kperf.DevDataFree

func DevDataFree(devVo PmuDeviceDataVo) 清理PmuDeviceData的指针数据

kperf.PmuGetClusterCore

func PmuGetClusterCore(clusterId uint) ([]uint, error) 查询指定clusterId下对应的core列表

  • clusterId CPU的clusterId编号
  • 返回值:当前clusterId下对应的core列表,出现错误则列表为空,且error不为空
import "libkperf/kperf"
import "fmt"

func main() {
    clusterId := uint(1)
	coreList, err := kperf.PmuGetClusterCore(clusterId)
	if err != nil {
		fmt.Printf("kperf PmuGetClusterCore failed, expect err is nil, but is %v\n", err)
    return
	}
	for _, v := range coreList {
		fmt.Printf("coreId has:%v\n", v)
	}
}

kperf.PmuGetNumaCore

func PmuGetNumaCore(nodeId uint) ([]uint, error) 查询指定numaId下对应的core列表

  • nodeId numa对应的ID
  • 返回值为对应numaId下的cpu core列表,出现错误则列表为空,且error不为空
import "libkperf/kperf"
import "fmt"

func main() {
    nodeId := uint(0)
	coreList, err := kperf.PmuGetNumaCore(nodeId)
	if err != nil {
		fmt.Printf("kperf PmuGetNumaCore failed, expect err is nil, but is %v\n", err)
    return
	}
	for _, v := range coreList {
		fmt.Printf("coreId has:%v\n", v)
	}
}

kperf.PmuGetCpuFreq

func PmuGetCpuFreq(core uint) (int64, error) 查询当前系统指定core的实时CPU频率

  • core cpu coreId
  • 返回值为int64, 为当前cpu core的实时频率,出现错误频率为-1,且error不为空
import "libkperf/kperf"
import "fmt"

func main() {
    coreId := uint(0)
	freq, err := kperf.PmuGetCpuFreq(coreId)
	if err != nil {
		fmt.Printf("kperf PmuGetCpuFreq failed, expect err is nil, but is %v\n", err)
    return
	}
	fmt.Printf("coreId %v freq is %v\n", coreId, freq)
}

kperf.PmuOpenCpuFreqSampling

func PmuOpenCpuFreqSampling(period uint) (error) 开启cpu频率采集

kperf.PmuCloseCpuFreqSampling

func PmuCloseCpuFreqSampling() 关闭cpu频率采集

kperf.PmuReadCpuFreqDetail

func PmuReadCpuFreqDetail() ([]PmuCpuFreqDetail) 读取开启频率采集到读取时间内的cpu最大频率、最小频率以及平均频率

import "libkperf/kperf"
import "fmt"

func main() {
    err := kperf.PmuOpenCpuFreqSampling(100)
    if err != nil {
		  fmt.Printf("kperf PmuOpenCpuFreqSampling failed, expect err is nil, but is %v\n", err)
	  }

    freqList := kperf.PmuReadCpuFreqDetail()
  	for _, v := range freqList {
	  	fmt.Printf("cpuId=%v, minFreq=%d, maxFreq=%d, avgFreq=%d\n", v.CpuId, v.MinFreq, v.MaxFreq, v.AvgFreq)
	  }

	  kperf.PmuCloseCpuFreqSampling()
}

kperf.ResolvePmuDataSymbol

func ResolvePmuDataSymbol(dataVo PmuDataVo) error 当SymbolMode设置为3或者4时,可通过该接口解析PmuRead返回的PmuData数据中的符号

import "libkperf/kperf"
import "fmt"

func main() {
    attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, CallStack:true, SampleRate: 1000, UseFreq:true}
    fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
    if err != nil {
      fmt.Printf("kperf pmuopen sample 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 {
      if len(o.Symbols) != 0 {
        fmt.Printf("expect symbol data is empty, but is not\n")
      }
    }

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

    for _, o := range dataVo.GoData {
      if len(o.Symbols) == 0 {
        fmt.Printf("expect symbol data is not empty, but is empty\n")
      }
    }
    kperf.PmuDataFree(dataVo)
    kperf.PmuClose(fd)
}

kperf.PmuBeginWrite

用于把性能数据输出为perf.data格式的文件。该函数用于初始化该文件。
目前该文件只支持SAMPLING模式,只支持基本信息的输出,比如id, tid, pid, addr,也包含brbe的数据。

  • path: 文件路径
  • pattr: 采集任务的PmuAttr
  • addIdHdr: 为属于非PERF_RECORD_SAMPLE采样的ID
  • 返回值: 文件句柄,用于下面两个API的调用

kperf.PmuWriteData

把PmuData数组输出到文件里。

  • file: 文件句柄
  • data: 性能数据
  • len: data的长度
  • 返回值: 错误码

kperf.PmuEndWrite

结束文件的写入。在写入结束时必须调用该函数,否则文件可能不完整。

  • file: 文件句柄