From bc306ee4c28958e8f518372085f890838c87b5a5 Mon Sep 17 00:00:00 2001 From: Galaxy Date: Wed, 12 Jun 2024 00:45:35 -0700 Subject: [PATCH] Update README and API reference. --- README.en.md | 47 ++++++++++++++++++++++ README.md | 63 ++++++++++++++++++++++++----- include/pmu.h | 108 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 178 insertions(+), 40 deletions(-) diff --git a/README.en.md b/README.en.md index fd417fe..5814b8f 100644 --- a/README.en.md +++ b/README.en.md @@ -66,6 +66,8 @@ All pmu functions are accomplished by the following interfaces: * PmuClose Close pmu device. +Refer to pmu.h for details of interfaces. + Here are some examples: * Get pmu count for a process. ``` @@ -101,6 +103,51 @@ PmuDataFree(data); PmuClose(pd); ``` +* Sample a process +``` +int pidList[1]; +pidList[0] = pid; +char *evtList[1]; +evtList[0] = "cycles"; +// Initialize event list and pid list in PmuAttr. +// There is one event in list, named 'cycles'. +PmuAttr attr = {0}; +attr.evtList = evtList; +attr.numEvt = 1; +attr.pidList = pidList; +attr.numPid = 1; +// Call PmuOpen and pmu descriptor is return. +// is an identity for current task. +// Use SAMPLING for sample task. +int pd = PmuOpen(SAMPLING, &attr); +// Start collection. +PmuEnable(pd); +// Collect for one second. +sleep(1); +// Stop collection. +PmuDisable(pd); +PmuData *data = NULL; +// Read pmu data. You can also read data before PmuDisable. +int len = PmuRead(pd, &data); +for (int i = 0; i < len; ++i) { + // Get an element from array. + PmuData *d = &data[i]; + // Get stack object which is a linked list. + Stack *stack = d->stack; + while (stack) { + // Get symbol object. + if (stack->symbol) { + ... + } + stack = stack->next; + } +} +// To free PmuData, call PmuDataFree. +PmuDataFree(data); +// Like fd, call PmuClose if pd will not be used. +PmuClose(pd); +``` + Python examples: ```python import time diff --git a/README.md b/README.md index c4b274c..ac89a1a 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ python3 -m pip unistall -y libkperf - PmuClose 关闭PMU装置。 +API的详细说明请参考pmu.h。 + 以下是一些示例: - 获取进程的pmu计数。 @@ -81,33 +83,74 @@ int pidList[1]; pidList[0] = pid; char *evtList[1]; evtList[0] = "cycles"; -// Initialize event list and pid list in PmuAttr. -// There is one event in list, named 'cycles'. +// 初始化事件列表,指定需要计数的事件cycles。 PmuAttr attr = {0}; attr.evtList = evtList; attr.numEvt = 1; attr.pidList = pidList; attr.numPid = 1; -// Call PmuOpen and pmu descriptor is return. -// is an identity for current task. +// 调用PmuOpen,返回pd。pd表示该任务的id。 int pd = PmuOpen(COUNTING, &attr); -// Start collection. +// 开始采集。 PmuEnable(pd); -// Collect for one second. +// 采集1秒。 sleep(1); -// Stop collection. +// 停止采集。 PmuDisable(pd); PmuData *data = NULL; -// Read pmu data. You can also read data before PmuDisable. +// 读取PmuData,它是一个数组,长度是len。 int len = PmuRead(pd, &data); for (int i = 0; i < len; ++i) { ... } -// To free PmuData, call PmuDataFree. +// 释放PmuData。 +PmuDataFree(data); +// 类似fd,当任务结束时调用PmuClose释放资源。 +PmuClose(pd); +``` + +- 对进程进行采样 +``` +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; +// 调用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) { + ... + } + stack = stack->next; + } +} +// 释放PmuData。 PmuDataFree(data); -// Like fd, call PmuClose if pd will not be used. +// 类似fd,当任务结束时调用PmuClose释放资源。 PmuClose(pd); ``` + Python 例子: ```python diff --git a/include/pmu.h b/include/pmu.h index 08d75c6..2a08332 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -65,26 +65,60 @@ enum SymbolMode { }; struct PmuAttr { - char** evtList; // event list - unsigned numEvt; // length of event list - int* pidList; // pid list - unsigned numPid; // length of pid list - int* cpuList; // cpu id list - unsigned numCpu; // length of cpu id list + // Event list. + // Refer 'perf list' for details about event names. + // Calling PmuEventList will also return the available event names. + // Both event names like 'cycles' or event ids like 'r11' are allowed. + // For uncore events, event names should be of the form '//'. + // For tracepoints, event names should be of the form ':'. + // For spe sampling, this field should be NULL. + char** evtList; + // Length of event list. + unsigned numEvt; + // Pid list. + // For multi-threaded programs, all threads will be monitored regardless whether threads are created before or after PmuOpen. + // For multi-process programs, only processes created after PmuOpen are monitored. + // For short-lived programs, PmuOpen may fail and return error code. + // To collect system, set pidList to NULL and cpu cores will be monitored according to the field . + int* pidList; + // Length of pid list. + unsigned numPid; + // Core id list. + // If both and are NULL, all processes on all cores will be monitored. + // If is NULL and is not NULL, specified processes on all cores will be monitored. + // if both and are not NULL, specified processes on specified cores will be monitored. + int* cpuList; + // Length of core id list + unsigned numCpu; union { - unsigned period; // sample period - unsigned freq; // sample frequency + // Sample period, only available for SAMPLING and SPE_SAMPLING. + unsigned period; + // Sample frequency, only available for SAMPLING. + unsigned freq; }; + // Use sample frequency or not. + // If set to 1, the previous union will be used as sample frequency, + // otherwise, it will be used as sample period. unsigned useFreq : 1; - unsigned excludeUser : 1; // don't count user - unsigned excludeKernel : 1; // don't count kernel - enum SymbolMode symbolMode; // refer to comments of SymbolMode - unsigned callStack : 1; // collect complete call stack + // Don't count user. + unsigned excludeUser : 1; + // Don't count kernel. + unsigned excludeKernel : 1; + // This indicates how to analyze symbols of samples. + // Refer to comments of SymbolMode. + enum SymbolMode symbolMode; + // This indicates whether to collect whole callchains or only top frame. + unsigned callStack : 1; + // SPE related fields. - enum SpeFilter dataFilter; // spe data filter - enum SpeEventFilter evFilter; // spe event filter - unsigned long minLatency; // collect only samples with latency or higher + + // Spe data filter. Refer to comments of SpeFilter. + enum SpeFilter dataFilter; + // Spe event filter. Refer to comments of SpeEventFilter. + enum SpeEventFilter evFilter; + // Collect only samples with latency or higher. + unsigned long minLatency; }; struct CpuTopology { @@ -113,7 +147,7 @@ enum SPE_EVENTS { struct PmuDataExt { unsigned long pa; // physical address unsigned long va; // virtual address - unsigned long event; // event id + unsigned long event; // event id, which is a bit map of mixed events, event bit is defined in SPE_EVENTS. }; struct PmuData { @@ -125,7 +159,7 @@ struct PmuData { unsigned cpu; // cpu id struct CpuTopology *cpuTopo; // cpu topology const char *comm; // process command - uint64_t period; // number of Samples + uint64_t period; // sample period uint64_t count; // event count. Only available for Counting. struct PmuDataExt *ext; // extension. Only available for Spe. }; @@ -133,15 +167,12 @@ struct PmuData { /** * @brief * Initialize the collection target. - * @param collectType collection typr. - * @param evtList array of event IDs - * @param numEvt length of evtList. - * @param pidList list of PIDs to be collected. Information about subprocess and subthreads of PIDs is collected. If - * the value is NULL, all process/threads are collected - * @param numPid length of pidList. - * @param cpuList CPU ID list. If the value is NULL, all CPUs are collected. - * @param numCpu cpuList length. - * @return int + * On success, a task id is returned which is the unique identity for the task. + * On error, -1 is returned. + * Refer to comments of PmuAttr for details about settings. + * @param collectType task type + * @param attr settings of the current task + * @return task id */ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr); @@ -157,14 +188,20 @@ const char** PmuEventList(enum PmuEventType eventType, unsigned *numEvt); /** * @brief * Enable counting or sampling of task . + * On success, 0 is returned. * On error, -1 is returned. + * @param pd task id + * @return error code */ int PmuEnable(int pd); /** * @brief * Disable counting or sampling of task . + * On success, 0 is returned. * On error, -1 is returned. + * @param pd task id + * @return error code */ int PmuDisable(int pd); @@ -194,9 +231,16 @@ void PmuStop(int pd); /** * @brief - * Collect data. If the value is NULL and the error code is 0, no data is available in the current collection time. If - * the value is NULL and the error code is not 0, an error occurs in the collection process and data cannot be read. - * @param struct PmuData* + * Collect data. + * Pmu data are collected starting from the last PmuEnable or PmuRead. + * That is to say, for COUNTING, counts of all pmu event are reset to zero in PmuRead. + * For SAMPLING and SPE_SAMPLING, samples collected are started from the last PmuEnable or PmuRead. + * On success, length of data array is returned. + * If is NULL and the error code is 0, no data is available in the current collection time. + * If is NULL and the error code is not 0, an error occurs in the collection process and data cannot be read. + * @param pd task id + * @param pmuData pmu data which is a pointer to an array + * @return lenght of pmu data */ int PmuRead(int pd, struct PmuData** pmuData); @@ -208,6 +252,7 @@ int PmuRead(int pd, struct PmuData** pmuData); * On error, -1 is returned. * @param fromData data list which will be copied to <*toData> * @param toData pointer to target data list. If data list <*toData> is NULL, a new list will be created. + * @return length of */ int PmuAppendData(struct PmuData *fromData, struct PmuData **toData); @@ -225,7 +270,10 @@ int PmuAppendData(struct PmuData *fromData, struct PmuData **toData); int PmuDumpData(struct PmuData *pmuData, unsigned len, char *filepath, int dumpDwf); /** - * @brief Close all the file descriptor opened during collecting process + * @brief + * Close task with id . + * After PmuClose is called, all pmu data related to the task become invalid. + * @param pd task id */ void PmuClose(int pd); -- Gitee