package libkperf_test
import "testing"
import "time"
import "os"
import "fmt"
import "libkperf/kperf"
func TestCount(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF}
fd, err := kperf.PmuOpen(kperf.COUNT, attr)
if err != nil {
t.Fatalf("kperf pmuopen counting failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("================================Get Counting data success================================")
t.Logf("count base info comm=%v, evt=%v, pid=%v, tid=%v, coreId=%v, numaId=%v, sockedId=%v", o.Comm, o.Evt, o.Pid, o.Tid, o.CpuTopo.CoreId, o.CpuTopo.NumaId, o.CpuTopo.SocketId)
t.Logf("count info count=%v, countPercent=%v", o.Count, o.CountPercent)
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestUserAccessCount(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF, PidList:[]int{0}, CpuList:[]int{-1}, EnableUserAccess:true}
fd, err := kperf.PmuOpen(kperf.COUNT, attr)
if err != nil {
t.Fatalf("kperf pmuopen counting failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for i, n := 0, 3; i < n; i++ {
j := 0;
for k := 0; k < 1000000000; k++ {
j = j + 1
}
dataVo, err = kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("================================Get Counting data success================================")
t.Logf("count base info comm=%v, evt=%v, pid=%v, tid=%v, coreId=%v, numaId=%v, sockedId=%v", o.Comm, o.Evt, o.Pid, o.Tid, o.CpuTopo.CoreId, o.CpuTopo.NumaId, o.CpuTopo.SocketId)
t.Logf("count info count=%v, countPercent=%v", o.Count, o.CountPercent)
}
kperf.PmuDataFree(dataVo)
}
kperf.PmuDisable(fd)
kperf.PmuClose(fd)
}
func TestSample(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF_DWARF, CallStack:true, SampleRate: 1000, UseFreq:true}
fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
if err != nil {
t.Fatalf("kperf pmuopen sample failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("================================Get Sampling data success================================")
t.Logf("sample base info comm=%v, evt=%v, pid=%v, tid=%v, coreId=%v, numaId=%v, sockedId=%v", o.Comm, o.Evt, o.Pid, o.Tid, o.CpuTopo.CoreId, o.CpuTopo.NumaId, o.CpuTopo.SocketId)
t.Logf("sample info count=%v", o.Period)
for _, s := range o.Symbols {
t.Logf("symbol info module=%v, symbolName=%v, mangleName=%v, addr=%#x, lineNum=%v fileName=%v", s.Module, s.SymbolName, s.MangleName, s.Addr, s.LineNum, s.FileName)
}
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestSpe(t *testing.T) {
attr := kperf.PmuAttr{MinLatency:0x40, CallStack: true, SymbolMode: kperf.ELF_DWARF, SampleRate: 1000, DataFilter: kperf.SPE_DATA_ALL, EvFilter: kperf.SPE_EVENT_RETIRED}
fd, err := kperf.PmuOpen(kperf.SPE, attr)
if err != nil {
t.Fatalf("kperf pmuopen spe failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("================================Get Spe data success================================")
t.Logf("spe base info comm=%v, evt=%v, pid=%v, tid=%v, coreId=%v, numaId=%v, sockedId=%v", o.Comm, o.Evt, o.Pid, o.Tid, o.CpuTopo.CoreId, o.CpuTopo.NumaId, o.CpuTopo.SocketId)
t.Logf("spe ext info pa=%v, va=%v, event=%v, latency=%v, source=%v", o.SpeExt.Pa, o.SpeExt.Va, o.SpeExt.Event, o.SpeExt.Lat, o.SpeExt.Source)
for _, s := range o.Symbols {
t.Logf("symbol info module=%v, symbolName=%v, mangleName=%v, addr=%#x, lineNum=%v fileName=%v", s.Module, s.SymbolName, s.MangleName, s.Addr, s.LineNum, s.FileName)
}
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestGetEvtList(t *testing.T) {
evtList := kperf.PmuEventList(kperf.CORE_EVENT)
if len(evtList) == 0 {
t.Fatalf("core event can't be empty")
}
t.Logf("Get Core event list success!")
for _, v := range evtList {
t.Logf("%v", v)
}
}
func TestDumpData(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF_DWARF, CallStack:true, SampleRate: 1000, UseFreq:true}
fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
if err != nil {
t.Fatalf("kperf pmuopen sample failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
wd, err := os.Getwd()
if err != nil {
t.Fatalf("get pwd dir failed, expect err is nil, but is %v", err)
}
dumpFilePath := wd + "/dump.txt"
dumpErr := kperf.PmuDumpData(dataVo, dumpFilePath, true)
if dumpErr != nil {
t.Fatalf("pmu dump data failed, expect err is nil, but is %v", dumpErr)
}
t.Logf("dump data to %v success!", dumpFilePath)
}
func TestSysCallTrace(t *testing.T) {
syscallList := kperf.PmuSysCallFuncList()
if syscallList == nil {
t.Fatalf("sys call list is empty")
} else {
for _, funcName := range syscallList {
t.Logf("func name %v", funcName)
}
}
traceAttr := kperf.PmuTraceAttr{Funcs:[]string{"clone", "futex", "clock_gettime"}}
taskId, err := kperf.PmuTraceOpen(kperf.TRACE_SYS_CALL, traceAttr)
if err != nil {
t.Fatalf("pmu trace open failed, expect err is nil, but is %v", err)
}
kperf.PmuTraceEnable(taskId)
time.Sleep(time.Second)
kperf.PmuTraceDisable(taskId)
traceList, err := kperf.PmuTraceRead(taskId)
if err != nil {
t.Fatalf("pmu trace read failed, expect err is nil, but is %v", err)
}
t.Logf("==========================pmu get trace data success==========================")
for _, v := range traceList.GoTraceData {
t.Logf("comm=%v, func=%v, elapsedTime=%v, startTs=%v, pid=%v, tid=%v, cpu=%v", v.Comm, v.FuncName, v.ElapsedTime, v.StartTs, v.Pid, v.Tid, v.Cpu)
}
kperf.PmuTraceFree(traceList)
kperf.PmuTraceClose(taskId)
}
func TestSysCallTraceWithCallStack(t *testing.T) {
traceAttr := kperf.PmuTraceAttr{Funcs:[]string{"clock_gettime"}, CallStack:true, SymbolMode: kperf.ELF}
taskId, err := kperf.PmuTraceOpen(kperf.TRACE_SYS_CALL, traceAttr)
if err != nil {
t.Fatalf("pmu trace open with call stack failed, expect err is nil, but is %v", err)
}
kperf.PmuTraceEnable(taskId)
time.Sleep(time.Second)
kperf.PmuTraceDisable(taskId)
traceList, err := kperf.PmuTraceRead(taskId)
if err != nil {
t.Fatalf("pmu trace read failed, expect err is nil, but is %v", err)
}
t.Logf("==========================pmu get trace data with call stack success==========================")
hasValidStack := false
for _, v := range traceList.GoTraceData {
t.Logf("comm=%v, func=%v, elapsedTime=%v, startTs=%v, pid=%v, tid=%v, cpu=%v", v.Comm, v.FuncName, v.ElapsedTime, v.StartTs, v.Pid, v.Tid, v.Cpu)
if len(v.Symbols) > 0 {
hasValidStack = true
t.Logf("Call stack depth: %d", len(v.Symbols))
for _, s := range v.Symbols {
t.Logf("symbol info module=%v, symbolName=%v, addr=%#x", s.Module, s.SymbolName, s.Addr)
if s.Addr == 0 {
t.Errorf("symbol address should not be 0")
}
if s.Module == "" {
t.Errorf("symbol module should not be empty")
}
}
}
}
if !hasValidStack {
t.Fatalf("no trace data has valid call stack")
}
kperf.PmuTraceFree(traceList)
kperf.PmuTraceClose(taskId)
}
func TestSysCallTraceWithDwarfSymbol(t *testing.T) {
traceAttr := kperf.PmuTraceAttr{Funcs:[]string{"clock_gettime"}, CallStack:true, SymbolMode: kperf.ELF_DWARF}
taskId, err := kperf.PmuTraceOpen(kperf.TRACE_SYS_CALL, traceAttr)
if err != nil {
t.Fatalf("pmu trace open with dwarf symbol failed, expect err is nil, but is %v", err)
}
kperf.PmuTraceEnable(taskId)
time.Sleep(time.Second)
kperf.PmuTraceDisable(taskId)
traceList, err := kperf.PmuTraceRead(taskId)
if err != nil {
t.Fatalf("pmu trace read failed, expect err is nil, but is %v", err)
}
t.Logf("==========================pmu get trace data with dwarf symbol success==========================")
hasValidStack := false
for _, v := range traceList.GoTraceData {
t.Logf("comm=%v, func=%v, elapsedTime=%v, startTs=%v, pid=%v, tid=%v, cpu=%v", v.Comm, v.FuncName, v.ElapsedTime, v.StartTs, v.Pid, v.Tid, v.Cpu)
if len(v.Symbols) > 0 {
hasValidStack = true
t.Logf("Call stack depth: %d", len(v.Symbols))
for _, s := range v.Symbols {
t.Logf("symbol info module=%v, symbolName=%v, addr=%#x, lineNum=%v, fileName=%v", s.Module, s.SymbolName, s.Addr, s.LineNum, s.FileName)
if s.Addr == 0 {
t.Errorf("symbol address should not be 0")
}
if s.Module == "" {
t.Errorf("symbol module should not be empty")
}
}
}
}
if !hasValidStack {
t.Fatalf("no trace data has valid call stack")
}
kperf.PmuTraceFree(traceList)
kperf.PmuTraceClose(taskId)
}
func TestBrbe(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF_DWARF, CallStack:true, SampleRate: 1000, UseFreq:true, BranchSampleFilter: kperf.KPERF_SAMPLE_BRANCH_ANY}
fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
if err != nil {
t.Fatalf("kperf pmuopen sample failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("================================Get Sampling data success================================")
t.Logf("sample base info comm=%v, evt=%v, pid=%v, tid=%v, coreId=%v, numaId=%v, sockedId=%v", o.Comm, o.Evt, o.Pid, o.Tid, o.CpuTopo.CoreId, o.CpuTopo.NumaId, o.CpuTopo.SocketId)
t.Logf("sample info count=%v", o.Period)
for _, s := range o.Symbols {
t.Logf("symbol info module=%v, symbolName=%v, mangleName=%v, addr=%#x, lineNum=%v fileName=%v", s.Module, s.SymbolName, s.MangleName, s.Addr, s.LineNum, s.FileName)
}
for _, b := range o.BranchRecords {
t.Logf("branch record info fromAddr=%#x, toAddr=%#x cycles=%v mispred=%v predicted=%v", b.FromAddr, b.ToAddr, b.Cycles, b.MisPred, b.Predicted)
}
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestGetDeviceBdfList(t *testing.T) {
pcieBdfList, err := kperf.PmuDeviceBdfList(kperf.PMU_BDF_TYPE_PCIE)
if err != nil {
t.Fatalf("kperf GetDeviceBdfList failed, expect err is nil, but is %v", err)
}
t.Log("Get PCIE bdf list success!")
for _, v := range pcieBdfList {
t.Logf("bdf is %v", v)
}
smmuBdfList, err := kperf.PmuDeviceBdfList(kperf.PMU_BDF_TYPE_SMMU)
if err != nil {
t.Fatalf("kperf GetDeviceBdfList failed, expect err is nil, but is %v", err)
}
t.Log("Get SMMU bdf list success!")
for _, v := range smmuBdfList {
t.Logf("bdf is %v", v)
}
}
func TestGetCpuFreq(t *testing.T) {
coreId := uint(6)
freq, err := kperf.PmuGetCpuFreq(coreId)
if err != nil {
t.Fatalf("kperf PmuGetCpuFreq failed, expect err is nil, but is %v", err)
}
t.Logf("coreId %v freq is %v", coreId, freq)
}
func TestGetMetric(t *testing.T) {
deviceAttrs := []kperf.PmuDeviceAttr{kperf.PmuDeviceAttr{Metric: kperf.PMU_L3_LAT}}
fd, err := kperf.PmuDeviceOpen(deviceAttrs)
if err != nil {
t.Fatalf("kperf PmuDeviceOpen failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
t.Logf("================================Get device data success================================")
deivceDataVo, err := kperf.PmuGetDevMetric(dataVo, deviceAttrs)
if err != nil {
t.Fatalf("kperf PmuGetDevMetric failed, expect err is nil, but is %v", err)
}
for _, v := range deivceDataVo.GoDeviceData {
t.Logf("get device data count=%v coreId=%v, numaId=%v bdf=%v clusterId=%v", v.Count, v.CoreId, v.NumaId, v.Bdf, v.ClusterId)
}
kperf.DevDataFree(deivceDataVo)
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestPmuGetClusterCore(t *testing.T) {
clusterId := uint(1)
coreList, err := kperf.PmuGetClusterCore(clusterId)
if err != nil {
t.Fatalf("kperf PmuGetClusterCore failed, expect err is nil, but is %v", err)
}
for _, v := range coreList {
t.Logf("coreId has:%v", v)
}
}
func TestPmuGetNumaCore(t *testing.T) {
nodeId := uint(0)
coreList, err := kperf.PmuGetNumaCore(nodeId)
if err != nil {
t.Fatalf("kperf PmuGetNumaCore failed, expect err is nil, but is %v", err)
}
for _, v := range coreList {
t.Logf("coreId has:%v", v)
}
}
func TestPmuGetCpuFreqDetail(t *testing.T) {
err := kperf.PmuOpenCpuFreqSampling(100)
if err != nil {
t.Fatalf("kperf PmuOpenCpuFreqSampling failed, expect err is nil, but is %v", err)
}
freqList := kperf.PmuReadCpuFreqDetail()
for _, v := range freqList {
t.Logf("cpuId=%v, minFreq=%d, maxFreq=%d, avgFreq=%d", v.CpuId, v.MinFreq, v.MaxFreq, v.AvgFreq)
}
kperf.PmuCloseCpuFreqSampling()
}
func TestResolvePmuDataSymbol(t *testing.T) {
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, CallStack:true, SampleRate: 1000, UseFreq:true, SymbolMode: kperf.DELAY_DWARF}
fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
if err != nil {
t.Fatalf("kperf pmuopen sample failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
if len(o.Symbols) != 0 {
t.Fatalf("expect symbol data is empty, but is not")
}
}
parseErr := kperf.ResolvePmuDataSymbol(dataVo)
if parseErr != nil {
t.Fatalf("kperf ResolvePmuDataSymbol failed, expect err is nil, but is %v", parseErr)
}
for _, o := range dataVo.GoData {
if len(o.Symbols) == 0 {
t.Fatalf("expect symbol data is not empty, but is empty")
}
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestCgroupNameList(t *testing.T) {
cgroupV2File := "/sys/fs/cgroup/cgroup.controllers"
_, err := os.Stat(cgroupV2File)
groupPath := "/sys/fs/cgroup"
if os.IsNotExist(err) {
groupPath += "/perf_event/testGocgroup"
} else {
groupPath += "/testGocgroup"
}
_, statErr := os.Stat(groupPath)
if statErr != nil {
err := os.Mkdir(groupPath, 0755)
if err != nil {
t.Fatalf("failed to mkdir groupPath named %s, err is %v", groupPath, err)
}
}
cgroupProcPath := groupPath + "/cgroup.procs"
procFile, procOpenErr := os.OpenFile(cgroupProcPath, os.O_RDWR | os.O_CREATE|os.O_TRUNC, 0644)
if procOpenErr != nil {
t.Fatalf("failed to open file %v, err is %v", cgroupProcPath, procOpenErr)
}
defer procFile.Close()
pid := os.Getpid()
contentStr := fmt.Sprintf("%d\n", pid)
_, writeErr := procFile.WriteString(contentStr)
if writeErr != nil {
t.Fatalf("failed to write pidinfo, err is %v", writeErr)
}
attr := kperf.PmuAttr{EvtList:[]string{"cycles"}, SymbolMode:kperf.ELF_DWARF, CallStack:true, SampleRate: 1000, UseFreq:true, CgroupNameList:[]string{"testGocgroup"}}
fd, err := kperf.PmuOpen(kperf.SAMPLE, attr)
if err != nil {
t.Fatalf("kperf pmuopen sample failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(fd)
time.Sleep(time.Second)
kperf.PmuDisable(fd)
dataVo, err := kperf.PmuRead(fd)
if err != nil {
t.Fatalf("kperf pmuread failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
if "testGocgroup" != o.CgroupName {
t.Fatalf("kperf pmuread cgroupName err")
}
}
kperf.PmuDataFree(dataVo)
kperf.PmuClose(fd)
}
func TestHwMetric(t *testing.T) {
metric := kperf.PMU_HWM_CPI | kperf.PMU_HWM_L3_CACHE_MISS
attr := kperf.PmuHwMetricAttr{Metric:metric, BasePeriodList:[]uint32{1000000, 100000}, ThresholdList:[]float64{0.8, 0.2}}
pd, err := kperf.PmuOpenWithHwMetric(attr)
if err != nil {
t.Fatalf("kperf PmuOpenWithHwMetric failed, expect err is nil, but is %v", err)
}
kperf.PmuEnable(pd)
time.Sleep(time.Second)
kperf.PmuDisable(pd)
dataVo, err := kperf.PmuRead(pd)
if err != nil {
t.Fatalf("kperf PmuRead failed, expect err is nil, but is %v", err)
}
for _, o := range dataVo.GoData {
t.Logf("sample base info comm=%v,pid=%v,tid=%v,evt=%v, period=%v,hw_metric=1", o.Comm,o.Pid,o.Tid,o.Evt, o.Period)
}
}