diff --git a/docs/C_C++_API.md b/docs/C_C++_API.md index 5dfe421057458affc2cf70d3f6355f900bd4e13a..933e9774bf008f5c86b5d0716bf252f842b5af64 100644 --- a/docs/C_C++_API.md +++ b/docs/C_C++_API.md @@ -21,6 +21,8 @@ 采集cpu核的个数 * struct EvtAttr *evtAttr 事件分组列表,和evtList搭配使用,同组事件需要使用相同数字表示,不同组事件使用不同的数字代表,如果数字为-1,则不参与事件分组 + * unsigned numGroup + 参与分组的事件个数 * union unsigned period 采样周期,仅支持SAMPLING和SPE_SAMPLING模式 unsigned freq 采样频率,仅支持SAMPLING模式 diff --git a/docs/Details_Usage.md b/docs/Details_Usage.md index c346eef794ccf168f00ebfad5b71fd51b842b194..d78fa4543f68485741d462d48ac363d84aa5ffa1 100644 --- a/docs/Details_Usage.md +++ b/docs/Details_Usage.md @@ -303,6 +303,7 @@ kperf.close(pd) ```go // go代码示例 import "libkperf/kperf" +import "fmt" import "time" func main() { @@ -683,12 +684,14 @@ perf stat -e "{inst_retired,inst_spec,cycles}","{inst_retired,cycles}" // 指定5个事件,因为inst_retired和cycles会重复出现在多个指标中,所以需要重复指定事件。 char *evtList[5] = {"inst_retired", "inst_spec", "cycles", "inst_retired", "cycles"}; -// 指定事件分组编号,前三个事件为一组,后两个事件为一组。 +// 指定事件分组编号,前三个事件为一组,后两个事件为一组。设置groupId=-1表示对应事件不参与分组。 +// 当事件数量numEvt超过指定事件分组数量numGroup时,超过分组数量的事件的groupId默认为-1,即不参与分组。 EvtAttr groupId[5] = {1,1,1,2,2}; PmuAttr attr = {0}; attr.evtList = evtList; attr.numEvt = 5; attr.evtAttr = groupId; +attr.numGroup = 5; int pd = PmuOpen(COUNTING, &attr); PmuEnable(pd); sleep(1); diff --git a/docs/Go_API.md b/docs/Go_API.md index a262b29b6c2d4c1b441cb994c7fc10c6d3ff49e5..33eb0d7948db7100db9bbd0d399ee118eea57a66 100644 --- a/docs/Go_API.md +++ b/docs/Go_API.md @@ -32,6 +32,8 @@ func PmuOpen(collectType C.enum_PmuTaskType, attr PmuAttr) (int, error) ELF_DWARF 既支持ELF数据采集,也支持行号解析 * CallStack 是否采集调用栈,默认不采集,只取栈顶数据 + * BlockedSample + 是否执行blocked Sample采样 * DataFilter C.enum_SpeFilter * TS_ENABLE 使能通用计时器 * PA_ENABLE 采集物理地址 diff --git a/docs/Python_API.md b/docs/Python_API.md index e0f28efe84728bb2cc7d1cbeda71b20a97265edb..942257dfebcac7bcfeea730d0df34562609c587c 100644 --- a/docs/Python_API.md +++ b/docs/Python_API.md @@ -33,6 +33,8 @@ kperf.open(collector_type: kperf.PmuTaskType, pmu_attr: kperf.PmuAttr) RESOLVE_ELF_DWARF = 2 既支持ELF数据采集,也支持行号解析 * callStack 是否采集调用栈,默认不采集,只取栈顶数据 + * blockedSample + 是否执行blocked Sample采样 * dataFilter * SPE_FILTER_NONE = 0 * TS_ENABLE = 1 << 0 使能通用计时器 diff --git a/go/src/libkperf/kperf/kperf.go b/go/src/libkperf/kperf/kperf.go index 049580deac965028cbc8dfef3a51f56457f6814e..b5f8a9b9f7102df9f3b653126c98a86d2df21c53 100644 --- a/go/src/libkperf/kperf/kperf.go +++ b/go/src/libkperf/kperf/kperf.go @@ -537,6 +537,7 @@ func ToCPmuAttr(attr PmuAttr) (*C.struct_PmuAttr, int) { evtAttrList[i] = C.struct_EvtAttr{C.int(groupId)} } cAttr.evtAttr = &evtAttrList[0] + cAttr.numGroup = C.uint32_t(evtAttrLen) } if attr.UseFreq { diff --git a/include/pcerrc.h b/include/pcerrc.h index fbd35225319dd1b46d8ea74489ba886a738b05fe..b1c2736f2dba2716a9d203521c0443f249451bd1 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -117,6 +117,7 @@ extern "C" { #define LIBPERF_ERR_NOT_SUPPORT_PMU_FILE 1070 #define LIBPERF_ERR_INVALID_PMU_FILE 1071 #define LIBPERF_ERR_NOT_SUPPORT_PCIE_PORT 1072 +#define LIBPERF_ERR_INVALID_EVTATTR 1073 #define UNKNOWN_ERROR 9999 diff --git a/include/pmu.h b/include/pmu.h index 1cbff1746859c96669c547bccca1e2e364d3787d..4a3ba2fb752a9a0273311e0dc745584f022bb2d4 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -129,6 +129,9 @@ struct PmuAttr { // the same group id is the a event group. // Note: if the group id value is -1, it indicates that the event is not grouped. struct EvtAttr *evtAttr; + // Length of evtAttr list. + // when numEvt > numGroup, the other events will not set to any group. + unsigned numGroup; union { // Sample period, only available for SAMPLING and SPE_SAMPLING. diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index b230e22c1714bb49ea9a82aecac3081ad3049fc8..2340dd25c86cbcb04e578f691fbf098a023f978b 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -114,6 +114,15 @@ static int CheckEvtList(unsigned numEvt, char** evtList) return SUCCESS; } +static int CheckGroupList(unsigned numGroup, struct EvtAttr *evtAttr) +{ + if (numGroup > 0 && evtAttr == nullptr) { + New(LIBPERF_ERR_INVALID_EVTATTR, "Invalid evtAttr list: numGroup is greater than 0, but evtAttr is null."); + return LIBPERF_ERR_INVALID_EVTATTR; + } + return SUCCESS; +} + static bool InvalidSampleRate(enum PmuTaskType collectType, struct PmuAttr *attr) { // When sampling, sample frequency must be less than or equal to perf_event_max_sample_rate. @@ -267,6 +276,11 @@ static int CheckAttr(enum PmuTaskType collectType, struct PmuAttr *attr) if (err != SUCCESS) { return err; } + err = CheckGroupList(attr->numGroup, attr->evtAttr); + if (err != SUCCESS) { + return err; + } + err = CheckCollectTypeConfig(collectType, attr); if (err != SUCCESS) { return err; @@ -972,9 +986,11 @@ struct PmuTaskAttr* AssignPmuTaskParam(enum PmuTaskType collectType, struct PmuA return taskParam; } for (int i = 0; i < attr->numCgroup; ++i) { + // when the numEvt > numGroup, set groupId=-1 for other events + int groupId = i >= attr->numGroup? -1 : attr->evtAttr[i].groupId; std::string cgroupName(attr->cgroupNameList[i]); for (int j = 0; j < attr->numEvt; ++j) { - struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[j], attr->evtAttr[j].groupId, cgroupName.c_str(), cgroupFds[cgroupName]); + struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[j], groupId, cgroupName.c_str(), cgroupFds[cgroupName]); if (current == nullptr) { return nullptr; } @@ -987,7 +1003,8 @@ struct PmuTaskAttr* AssignPmuTaskParam(enum PmuTaskType collectType, struct PmuA return taskParam; } for (int i = 0; i < attr->numEvt; ++i) { - struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[i], attr->evtAttr[i].groupId, nullptr, -1); + int groupId = i >= attr->numGroup? -1 : attr->evtAttr[i].groupId; + struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[i], groupId, nullptr, -1); if (current == nullptr) { return nullptr; } diff --git a/python/modules/_libkperf/Pmu.py b/python/modules/_libkperf/Pmu.py index e1059a84efbcd089fceedab0e9afb8efcaaabc07..5194dabaec88c6894a58c767ead9dd1e3259d055 100644 --- a/python/modules/_libkperf/Pmu.py +++ b/python/modules/_libkperf/Pmu.py @@ -70,9 +70,10 @@ class CtypesPmuAttr(ctypes.Structure): int* pidList; // pid list unsigned numPid; // length of pid list int* cpuList; // cpu id list - int numCpu; // length of cpu id list + unsigned numCpu; // length of cpu id list struct EvtAttr *evtAttr; // events group id info + unsigned numGroup // length of evtAttr union { unsigned period; // sample period @@ -100,6 +101,7 @@ class CtypesPmuAttr(ctypes.Structure): ('cpuList', ctypes.POINTER(ctypes.c_int)), ('numCpu', ctypes.c_uint), ('evtAttr', ctypes.POINTER(CtypesEvtAttr)), + ('numGroup', ctypes.c_uint), ('sampleRate', SampleRateUnion), ('useFreq', ctypes.c_uint, 1), ('excludeUser', ctypes.c_uint, 1), @@ -168,10 +170,12 @@ class CtypesPmuAttr(ctypes.Structure): self.sampleRate.freq = ctypes.c_uint(sampleRate) if evtAttr: - numEvtAttr = len(evtAttr) - self.evtAttr = (CtypesEvtAttr * numEvtAttr)(*[CtypesEvtAttr(evt) for evt in evtAttr]) + numGroup = len(evtAttr) + self.evtAttr = (CtypesEvtAttr * numGroup)(*[CtypesEvtAttr(evt) for evt in evtAttr]) + self.numGroup = ctypes.c_uint(numGroup) else: self.evtAttr = None + self.numGroup = ctypes.c_uint(0) if cgroupNameList: numCgroup = len(cgroupNameList) @@ -296,18 +300,24 @@ class PmuAttr(object): self.c_pmu_attr.pidList = None self.c_pmu_attr.numPid = ctypes.c_uint(0) + @property + def numGroup(self): + return self.c_pmu_attr.numGroup + @property def evtAttr(self): - return [self.c_pmu_attr.evtAttr[i] for i in range(len(self.c_pmu_attr.evtAttr))] + return [self.c_pmu_attr.evtAttr[i] for i in range(self.numGroup)] @evtAttr.setter def evtAttr(self, evtAttr): if evtAttr: - numEvtAttr = len(evtAttr) - self.c_pmu_attr.evtAttr = (CtypesEvtAttr * numEvtAttr)(*[CtypesEvtAttr(evt) for evt in evtAttr]) + numGroup = len(evtAttr) + self.c_pmu_attr.evtAttr = (CtypesEvtAttr * numGroup)(*[CtypesEvtAttr(evt) for evt in evtAttr]) + self.c_pmu_attr.numGroup = ctypes.c_uint(numGroup) else: self.c_pmu_attr.evtAttr = None - + self.c_pmu_attr.numGroup = ctypes.c_uint(0) + @property def numCpu(self): return self.c_pmu_attr.numCpu diff --git a/python/modules/kperf/perror.py b/python/modules/kperf/perror.py index e0d210cd505d9109f79a8909ed147dd63acd081c..285e5d792e5a0f1326cde3222c40a50875058ed1 100644 --- a/python/modules/kperf/perror.py +++ b/python/modules/kperf/perror.py @@ -116,6 +116,7 @@ class Error: LIBPERF_ERR_NOT_SUPPORT_PMU_FILE = 1070 LIBPERF_ERR_INVALID_PMU_FILE = 1071 LIBPERF_ERR_NOT_SUPPORT_PCIE_PORT = 1072 + LIBPERF_ERR_INVALID_EVTATTR = 1073 UNKNOWN_ERROR = 9999 diff --git a/util/pcerr.cpp b/util/pcerr.cpp index 2e3ad910e83d80c9187d7201a2c155168f158f4c..2252995da002331e2d87eb1b77359a3ea827046a 100644 --- a/util/pcerr.cpp +++ b/util/pcerr.cpp @@ -60,6 +60,7 @@ namespace pcerr { {LIBPERF_ERR_NOT_SUPPORT_PMU_FILE, "writing perf.data is not supported"}, {LIBPERF_ERR_INVALID_PMU_FILE, "invalid pmu file handler"}, {LIBPERF_ERR_OPEN_INVALID_FILE, "failed to open file"}, + {LIBPERF_ERR_INVALID_EVTATTR, "invalid evtAttr list"}, }; static std::unordered_map warnMsgs = { {LIBPERF_WARN_CTXID_LOST, "Some SPE context packets are not found in the traces."},