From db9d77cf23b4e5c92852543e2b46131d53e06770 Mon Sep 17 00:00:00 2001 From: Junyi Ye <294572668@qq.com> Date: Mon, 22 Apr 2024 12:46:43 +0800 Subject: [PATCH 1/4] pfm support for uncore events and pmu event query interface --- CMakeLists.txt | 2 +- Common.cmake | 17 ++++++++++ README.en.md | 65 ++++++++++++++++++++++++++++++++++----- build.sh | 3 +- include/pcerrc.h | 3 ++ include/pmu.h | 24 +++++++++++++++ pmu/CMakeLists.txt | 2 +- pmu/pfm/pfm.cpp | 30 +++++++++++++++--- pmu/pfm/pfm_event.h | 1 + pmu/pfm/uncore.cpp | 2 +- pmu/pmu.cpp | 60 ++++++++++++++++++++++++++++++++++++ pmu/pmu_list.cpp | 11 ++++--- pmu/pmu_list.h | 15 ++++++++- pmu/sample_process.cpp | 1 + symbol/CMakeLists.txt | 2 +- symbol/symbol_resolve.cpp | 8 +++-- 16 files changed, 222 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52c7be2..761fc49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,4 +35,4 @@ include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake) add_subdirectory(symbol) add_subdirectory(pmu) -set(CMAKE_EXPORT_COMPILE_COMMANDS True) \ No newline at end of file +set(CMAKE_EXPORT_COMPILE_COMMANDS True) diff --git a/Common.cmake b/Common.cmake index 030dac1..2aac046 100644 --- a/Common.cmake +++ b/Common.cmake @@ -32,3 +32,20 @@ add_library(dwarf_static STATIC IMPORTED) set_property(TARGET dwarf_static PROPERTY IMPORTED_LOCATION ${THIRD_PARTY}/local/elfin-parser/libdwarf++.a) include_directories(${THIRD_PARTY}/elfin-parser/dwarf) include_directories(${THIRD_PARTY}/elfin-parser/elf) + +find_library(gtest_main_path libgtest_main.a /usr/local/lib64 /usr/local/lib) +if (${gtest_main_path} STREQUAL "gtest_main_path-NOTFOUND") + message (STATUS "required gtest_main library but not found!") +else() + message (STATUS "gtest_main library found in ${gtest_main_path}") +endif() +add_library(gtest_main STATIC IMPORTED) +set_property(TARGET gtest_main PROPERTY IMPORTED_LOCATION ${gtest_main_path}) +find_library(gtest_path libgtest.a /usr/local/lib64 /usr/local/lib) +if (${gtest_path} STREQUAL "gtest_path-NOTFOUND") + message (STATUS "required gtest library but not found!") +else() + message (STATUS "gtest library found in ${gtest_path}") +endif() +add_library(gtest STATIC IMPORTED) +set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${gtest_path}) diff --git a/README.en.md b/README.en.md index 408cd64..f9ee122 100644 --- a/README.en.md +++ b/README.en.md @@ -4,19 +4,70 @@ Implement a low overhead pmu collection library, providing abstract interfaces for counting, sampling and symbol resolve. #### Software Architecture -Software architecture description +This repo includes two modules: pmu collections and symbol resolve. + +Pmu collection module is developed on syscall perf_event_open to enable kernel pmu counting and sampling, using -thread or per-core mode depending on user input. +Pmu data packets are read from ring buffer and are parsed to different structure for counting, sampling and spe sampling. +For sampling, symbols are resolved according to ips or pc from data packet. Each symbol contains symbol name, address, source file path and line number if possible. + +Symbol resolve module is developed on elfin-parser, a library for parsing elf and dwarf. The module manages all symbol data in well-designed data structures for fast query. #### Installation +Run bash script: -1. xxxx -2. xxxx -3. xxxx +```sh +sh build.sh +``` +Headers and libraries will be installed to ./output directory. #### Instructions +All pmu functions are accomplished by the following interfaces: +* PmuOpen + Input pid, core id and event and Open pmu device. +* PmuEnable + Start collection. +* PmuRead + Read pmu data and a list is returned. +* PmuDisable + Stop collection. +* PmuClose + Close pmu device. + +Here are some examples: +* Get pmu count for 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. +int pd = PmuOpen(COUNTING, &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) { + ... +} +// To free PmuData, call PmuDataFree. +PmuDataFree(data); +// Like fd, call PmuClose if pd will not be used. +PmuClose(pd); +``` -1. xxxx -2. xxxx -3. xxxx #### Contribution diff --git a/build.sh b/build.sh index 0d56a7d..ae8924a 100644 --- a/build.sh +++ b/build.sh @@ -73,4 +73,5 @@ main() { build_libprof } -main $@ \ No newline at end of file +main $@ + diff --git a/include/pcerrc.h b/include/pcerrc.h index bcdf187..abaf10f 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -70,6 +70,9 @@ extern "C" { #define LIBPERF_ERR_FAILED_PMU_DISABLE 1026 #define LIBPERF_ERR_FAILED_PMU_RESET 1027 #define LIBPERF_ERR_NOT_OPENED 1028 +#define LIBPERF_ERR_QUERY_EVENT_TYPE_INVALID 1029 +#define LIBPERF_ERR_QUERY_EVENT_LIST_FAILED 1030 +#define LIBPERF_ERR_FOLDER_PATH_INACCESSIBLE 1031 #define UNKNOWN_ERROR 9999 diff --git a/include/pmu.h b/include/pmu.h index 99b1580..1f97d36 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -28,6 +28,13 @@ enum PmuTaskType { MAX_TASK_TYPE }; +enum PmuEventType { + CORE_EVENT, + UNCORE_EVENT, + TRACE_EVENT, + ALL_EVENT +}; + enum AggregateType { PER_SYSTEM, PER_CORE, @@ -121,6 +128,23 @@ struct PmuData { */ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr); +/** + * @brief + * Query all available event from system. + * @param eventType type of event chosen by user + * @param numEvt length of event list + * @return event list + */ +const char** PmuEventList(enum PmuEventType eventType, unsigned *numEvt); + +/** + * @brief + * Free eventList pointer. + * @param eventList event list + * @param numEvt length of event list + */ +void PmuEventListFree(const char** eventList, unsigned *numEvt); + /** * @brief * Enable counting or sampling of task . diff --git a/pmu/CMakeLists.txt b/pmu/CMakeLists.txt index d344009..189e43e 100644 --- a/pmu/CMakeLists.txt +++ b/pmu/CMakeLists.txt @@ -33,6 +33,6 @@ include_directories(${PMU_DECODER_DIR}) ADD_LIBRARY(kperf SHARED ${PMU_SRC} ${UTIL_SRC} ${PFM_SRC} ${PMU_DECODER_SRC}) target_link_libraries(kperf numa sym) target_compile_options(kperf PRIVATE -fPIC) -install(TARGETS kperf DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +install(TARGETS kperf DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) file(GLOB HEADER_FILES ${PROJECT_TOP_DIR}/include/*.h) install(FILES ${HEADER_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) diff --git a/pmu/pfm/pfm.cpp b/pmu/pfm/pfm.cpp index 1f8ea3f..4b46838 100644 --- a/pmu/pfm/pfm.cpp +++ b/pmu/pfm/pfm.cpp @@ -40,6 +40,25 @@ using namespace KUNPENG_PMU; static constexpr int MAX_STRING_LEN = 2048; static CHIP_TYPE g_chipType = UNDEFINED_TYPE; +static struct PmuEvt* GetRawEvent(const char* pmuName, int collectType) +{ + // check raw event name like 'r11' or 'r60ea' is valid or not + const char *numStr = pmuName + 1; + char *endPtr; + __u64 config = strtol(numStr, &endPtr, 16); + if (*endPtr != '\0') { + return nullptr; + } + struct PmuEvt* pmuEvtPtr = new PmuEvt; + pmuEvtPtr->config = config; + pmuEvtPtr->name = pmuName; + pmuEvtPtr->type = PERF_TYPE_RAW; + pmuEvtPtr->pmuType = CORE_TYPE; + pmuEvtPtr->collectType = collectType; + pmuEvtPtr->cpumask = -1; + return std::move(pmuEvtPtr); +} + static struct PmuEvt* ConstructPmuEvtFromCore(KUNPENG_PMU::CoreConfig config, int collectType) { struct PmuEvt* pmuEvtPtr = new PmuEvt; @@ -87,6 +106,7 @@ static int GetSpeType(void) using EvtRetriever = std::function; static const std::unordered_map EvtMap{ + {KUNPENG_PMU::RAW_TYPE, GetRawEvent}, {KUNPENG_PMU::CORE_TYPE, GetCoreEvent}, {KUNPENG_PMU::UNCORE_TYPE, GetUncoreEvent}, {KUNPENG_PMU::TRACE_TYPE, GetKernelTraceEvent}, @@ -94,6 +114,10 @@ static const std::unordered_map EvtMap{ static int GetEventType(const char *pmuName, string &evtName) { + if (pmuName[0] == 'r') { + evtName = pmuName; + return RAW_TYPE; + } auto coreMap = CORE_EVENT_MAP.at(g_chipType); auto findCoreEvent = coreMap.find(pmuName); if (findCoreEvent != coreMap.end()) { @@ -148,7 +172,7 @@ struct PmuEvt* PfmGetPmuEvent(const char* pmuName, int collectType) struct PmuEvt* PfmGetSpeEvent( unsigned long dataFilter, unsigned long eventFilter, unsigned long minLatency, int collectType) { - PmuEvt* evt = new PmuEvt{0}; + auto* evt = new PmuEvt{0}; evt->collectType = collectType; int type = GetSpeType(); if (type == -1) { @@ -165,7 +189,5 @@ struct PmuEvt* PfmGetSpeEvent( void PmuEvtFree(PmuEvt *evt) { - if (evt != nullptr) { - delete evt; - } + delete evt; } diff --git a/pmu/pfm/pfm_event.h b/pmu/pfm/pfm_event.h index b416baf..aaca4a6 100644 --- a/pmu/pfm/pfm_event.h +++ b/pmu/pfm/pfm_event.h @@ -22,6 +22,7 @@ namespace KUNPENG_PMU { enum PMU_TYPE { + RAW_TYPE, CORE_TYPE, UNCORE_TYPE, TRACE_TYPE, diff --git a/pmu/pfm/uncore.cpp b/pmu/pfm/uncore.cpp index 16257f3..382802d 100644 --- a/pmu/pfm/uncore.cpp +++ b/pmu/pfm/uncore.cpp @@ -76,7 +76,7 @@ static int64_t GetUncoreEventConfig(const char* pmuName) } string configStr; evtIn >> configStr; - auto findEq = configStr.find("="); + auto findEq = configStr.find('='); if (findEq == string::npos) { return -1; } diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index a88470f..2f05b57 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include "common.h" #include "pfm.h" #include "pfm_event.h" #include "pmu_event.h" @@ -33,6 +35,7 @@ using namespace std; static unordered_map runningStatus; static SafeHandler pdMutex; +static const int NINE = 9; struct PmuTaskAttr* AssignPmuTaskParam(PmuTaskType collectType, struct PmuAttr *attr); @@ -118,6 +121,54 @@ static int CheckAttr(enum PmuTaskType collectType, struct PmuAttr *attr) return SUCCESS; } +void AppendChildEvents(char* evt, unordered_map& eventSplitMap) +{ + string strName(evt); + auto findSlash = strName.find('/'); + string devName = strName.substr(0, findSlash); + string evtName = strName.substr(devName.size(), strName.size() - devName.size() + 1); + for (int i = 0; i <= NINE; i++) { + string typePath = "/sys/devices/"; + string childName = devName; + typePath += devName + to_string(i) + "/type"; + string realPath = GetRealPath(typePath); + childName += to_string(i) + evtName; + if (IsValidPath(realPath)) { + eventSplitMap.emplace(childName, evt); + } + } +} + +static void SplitUncoreEvent(struct PmuAttr *attr, unordered_map &eventSplitMap) +{ + char** evtList = attr->evtList; + unsigned size = attr->numEvt; + int newSize = 0; + for (int i = 0; i < size; ++i) { + char* evt = evtList[i]; + char* slashPos = std::strchr(evt, '/'); + if (slashPos != nullptr && slashPos != evt) { + char* prevChar = slashPos - 1; + if (!std::isdigit(*prevChar)) { + // 添加子事件 + AppendChildEvents(evt, eventSplitMap); + continue; + } + } + eventSplitMap.emplace(evt, evt); + newSize++; + } +} + +static unsigned GenerateSplitList(unordered_map& eventSplitMap, vector &newEvtlist) +{ + // append child event + for (auto& event : eventSplitMap) { + newEvtlist.push_back(const_cast(event.first.c_str())); + } + return newEvtlist.size(); +} + static bool PdValid(const int &pd) { return PmuList::GetInstance()->IsPdAlive(pd); @@ -143,6 +194,12 @@ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr) if (err != SUCCESS) { return -1; } + unordered_map eventSplitMap; + SplitUncoreEvent(attr, eventSplitMap); + auto previousEventList = make_pair(attr->numEvt, attr->evtList); + vector newEvtlist; + attr->numEvt = GenerateSplitList(eventSplitMap, newEvtlist); + attr->evtList = newEvtlist.data(); auto pTaskAttr = AssignPmuTaskParam(collectType, attr); if (pTaskAttr == nullptr) { @@ -161,6 +218,9 @@ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr) PmuList::GetInstance()->Close(pd); pd = -1; } + // store eventList provided by user and the mapping relationship between the user eventList and the split + // eventList into buff + KUNPENG_PMU::PmuList::GetInstance()->StoreSplitData(pd, previousEventList, eventSplitMap); New(err); return pd; } catch (std::bad_alloc&) { diff --git a/pmu/pmu_list.cpp b/pmu/pmu_list.cpp index 691ecfb..42a4382 100644 --- a/pmu/pmu_list.cpp +++ b/pmu/pmu_list.cpp @@ -73,13 +73,18 @@ namespace KUNPENG_PMU { if (err != SUCCESS) { return err; } - fdNum += cpuTopoList.size(); + procTopoList.size(); + fdNum += cpuTopoList.size() + procTopoList.size(); std::shared_ptr evtList = std::make_shared(cpuTopoList, procTopoList, pmuTaskAttrHead->pmuEvt); InsertEvtList(pd, evtList); pmuTaskAttrHead = pmuTaskAttrHead->next; } + auto err = CheckRlimit(fdNum); + if (err != SUCCESS) { + return err; + } + for (auto evtList : GetEvtList(pd)) { auto err = evtList->Init(); if (err != SUCCESS) { @@ -91,10 +96,6 @@ namespace KUNPENG_PMU { } } - auto err = CheckRlimit(fdNum); - if (err != SUCCESS) { - return err; - } return SUCCESS; } diff --git a/pmu/pmu_list.h b/pmu/pmu_list.h index 67b8bd2..90f588b 100644 --- a/pmu/pmu_list.h +++ b/pmu/pmu_list.h @@ -66,6 +66,8 @@ public: int NewPd(); int GetHistoryData(const int pd, std::vector& pmuData); + void StoreSplitData(unsigned pd, std::pair previousEventList, + std::unordered_map eventSplitMap); private: using ProcPtr = std::shared_ptr; @@ -86,6 +88,7 @@ private: void InsertEvtList(const unsigned pd, std::shared_ptr evtList); std::vector>& GetEvtList(const unsigned pd); void EraseEvtList(const unsigned pd); + void EraseParentEventMap(); EventData& GetDataList(const unsigned pd); void EraseDataList(const unsigned pd); @@ -108,10 +111,12 @@ private: int PrepareProcTopoList(PmuTaskAttr* pmuTaskAttrHead, std::vector& procTopoList) const; int CheckRlimit(const unsigned fdNum); static void AggregateData(const std::vector& evData, std::vector& newEvData); + void AggregateUncoreData(const unsigned pd, const std::vector &evData, std::vector &newEvData); std::vector& GetPreviousData(const unsigned pd); static std::mutex pmuListMtx; static std::mutex dataListMtx; + static std::mutex dataParentMtx; std::unordered_map>> pmuList; // Key: pd // Value: PmuData List. @@ -121,7 +126,15 @@ private: // Value: PmuData vector for raw pointer. // PmuData is stored here after user call . std::unordered_map userDataList; - + // Key1: pd + // Key2: parent event + // Value: child event name list + // parent event name is stored here before user call to aggregate event. + std::unordered_map> parentEventMap; + // Key: pd + // Value: previous event list and its length + // previous event list is stored here before user call to aggregate event. + std::unordered_map> previousEventMap; // Key: pd // Value: epoll fd std::unordered_map epollList; diff --git a/pmu/sample_process.cpp b/pmu/sample_process.cpp index 79a20e7..56a92a4 100644 --- a/pmu/sample_process.cpp +++ b/pmu/sample_process.cpp @@ -33,6 +33,7 @@ static constexpr int MAX_DATA_SIZE = 8192; void KUNPENG_PMU::PerfMmapConsume(PerfMmap &map) { + __u64 prev = map.prev; struct perf_event_mmap_page *base = (struct perf_event_mmap_page *)map.base; PerfRingbufferSmpStoreRelease(&base->data_tail, prev); diff --git a/symbol/CMakeLists.txt b/symbol/CMakeLists.txt index e17614b..920d59e 100644 --- a/symbol/CMakeLists.txt +++ b/symbol/CMakeLists.txt @@ -17,5 +17,5 @@ include_directories(${INCLUDE_DIR}) message(${THIRD_PARTY}/elfin-parser/elf) ADD_LIBRARY(sym SHARED ${SYMBOL_SRC}) target_link_libraries(sym elf_static dwarf_static pthread) -install(TARGETS sym DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +install(TARGETS sym DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) install(FILES ${SYMBOL_FILE_DIR}/symbol.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include) diff --git a/symbol/symbol_resolve.cpp b/symbol/symbol_resolve.cpp index 9cb0089..fd6dc66 100644 --- a/symbol/symbol_resolve.cpp +++ b/symbol/symbol_resolve.cpp @@ -463,7 +463,9 @@ void MyDwarf::FindLine(unsigned long addr, struct DwarfEntry &entry) for (auto &range : rangeList) { if (range.IsInLineTable(addr)) { range.FindLine(addr, entry); - return; + if (entry.find) { + return; + } } } } @@ -488,7 +490,9 @@ void MyDwarf::LoadDwarf(unsigned long addr, DwarfEntry& entry) loadNum++; if (range.IsInLineTable(addr)) { range.FindLine(addr, entry); - return; + if (entry.find) { + return; + } } } hasLoad = true; -- Gitee From 885104a805a48f99c7f90e24d337ee6c4e91e906 Mon Sep 17 00:00:00 2001 From: Junyi Ye <294572668@qq.com> Date: Mon, 22 Apr 2024 12:52:06 +0800 Subject: [PATCH 2/4] pfm support for uncore events and pmu event query interface --- include/pcerrc.h | 3 +++ include/pmu.h | 24 ++++++++++++++++++ pmu/pfm/pfm.cpp | 30 ++++++++++++++++++++--- pmu/pfm/pfm_event.h | 1 + pmu/pfm/uncore.cpp | 2 +- pmu/pmu.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++ pmu/pmu_list.h | 15 +++++++++++- 7 files changed, 129 insertions(+), 6 deletions(-) diff --git a/include/pcerrc.h b/include/pcerrc.h index bcdf187..abaf10f 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -70,6 +70,9 @@ extern "C" { #define LIBPERF_ERR_FAILED_PMU_DISABLE 1026 #define LIBPERF_ERR_FAILED_PMU_RESET 1027 #define LIBPERF_ERR_NOT_OPENED 1028 +#define LIBPERF_ERR_QUERY_EVENT_TYPE_INVALID 1029 +#define LIBPERF_ERR_QUERY_EVENT_LIST_FAILED 1030 +#define LIBPERF_ERR_FOLDER_PATH_INACCESSIBLE 1031 #define UNKNOWN_ERROR 9999 diff --git a/include/pmu.h b/include/pmu.h index 99b1580..1f97d36 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -28,6 +28,13 @@ enum PmuTaskType { MAX_TASK_TYPE }; +enum PmuEventType { + CORE_EVENT, + UNCORE_EVENT, + TRACE_EVENT, + ALL_EVENT +}; + enum AggregateType { PER_SYSTEM, PER_CORE, @@ -121,6 +128,23 @@ struct PmuData { */ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr); +/** + * @brief + * Query all available event from system. + * @param eventType type of event chosen by user + * @param numEvt length of event list + * @return event list + */ +const char** PmuEventList(enum PmuEventType eventType, unsigned *numEvt); + +/** + * @brief + * Free eventList pointer. + * @param eventList event list + * @param numEvt length of event list + */ +void PmuEventListFree(const char** eventList, unsigned *numEvt); + /** * @brief * Enable counting or sampling of task . diff --git a/pmu/pfm/pfm.cpp b/pmu/pfm/pfm.cpp index 1f8ea3f..4b46838 100644 --- a/pmu/pfm/pfm.cpp +++ b/pmu/pfm/pfm.cpp @@ -40,6 +40,25 @@ using namespace KUNPENG_PMU; static constexpr int MAX_STRING_LEN = 2048; static CHIP_TYPE g_chipType = UNDEFINED_TYPE; +static struct PmuEvt* GetRawEvent(const char* pmuName, int collectType) +{ + // check raw event name like 'r11' or 'r60ea' is valid or not + const char *numStr = pmuName + 1; + char *endPtr; + __u64 config = strtol(numStr, &endPtr, 16); + if (*endPtr != '\0') { + return nullptr; + } + struct PmuEvt* pmuEvtPtr = new PmuEvt; + pmuEvtPtr->config = config; + pmuEvtPtr->name = pmuName; + pmuEvtPtr->type = PERF_TYPE_RAW; + pmuEvtPtr->pmuType = CORE_TYPE; + pmuEvtPtr->collectType = collectType; + pmuEvtPtr->cpumask = -1; + return std::move(pmuEvtPtr); +} + static struct PmuEvt* ConstructPmuEvtFromCore(KUNPENG_PMU::CoreConfig config, int collectType) { struct PmuEvt* pmuEvtPtr = new PmuEvt; @@ -87,6 +106,7 @@ static int GetSpeType(void) using EvtRetriever = std::function; static const std::unordered_map EvtMap{ + {KUNPENG_PMU::RAW_TYPE, GetRawEvent}, {KUNPENG_PMU::CORE_TYPE, GetCoreEvent}, {KUNPENG_PMU::UNCORE_TYPE, GetUncoreEvent}, {KUNPENG_PMU::TRACE_TYPE, GetKernelTraceEvent}, @@ -94,6 +114,10 @@ static const std::unordered_map EvtMap{ static int GetEventType(const char *pmuName, string &evtName) { + if (pmuName[0] == 'r') { + evtName = pmuName; + return RAW_TYPE; + } auto coreMap = CORE_EVENT_MAP.at(g_chipType); auto findCoreEvent = coreMap.find(pmuName); if (findCoreEvent != coreMap.end()) { @@ -148,7 +172,7 @@ struct PmuEvt* PfmGetPmuEvent(const char* pmuName, int collectType) struct PmuEvt* PfmGetSpeEvent( unsigned long dataFilter, unsigned long eventFilter, unsigned long minLatency, int collectType) { - PmuEvt* evt = new PmuEvt{0}; + auto* evt = new PmuEvt{0}; evt->collectType = collectType; int type = GetSpeType(); if (type == -1) { @@ -165,7 +189,5 @@ struct PmuEvt* PfmGetSpeEvent( void PmuEvtFree(PmuEvt *evt) { - if (evt != nullptr) { - delete evt; - } + delete evt; } diff --git a/pmu/pfm/pfm_event.h b/pmu/pfm/pfm_event.h index b416baf..aaca4a6 100644 --- a/pmu/pfm/pfm_event.h +++ b/pmu/pfm/pfm_event.h @@ -22,6 +22,7 @@ namespace KUNPENG_PMU { enum PMU_TYPE { + RAW_TYPE, CORE_TYPE, UNCORE_TYPE, TRACE_TYPE, diff --git a/pmu/pfm/uncore.cpp b/pmu/pfm/uncore.cpp index 16257f3..382802d 100644 --- a/pmu/pfm/uncore.cpp +++ b/pmu/pfm/uncore.cpp @@ -76,7 +76,7 @@ static int64_t GetUncoreEventConfig(const char* pmuName) } string configStr; evtIn >> configStr; - auto findEq = configStr.find("="); + auto findEq = configStr.find('='); if (findEq == string::npos) { return -1; } diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index a88470f..2f05b57 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include "common.h" #include "pfm.h" #include "pfm_event.h" #include "pmu_event.h" @@ -33,6 +35,7 @@ using namespace std; static unordered_map runningStatus; static SafeHandler pdMutex; +static const int NINE = 9; struct PmuTaskAttr* AssignPmuTaskParam(PmuTaskType collectType, struct PmuAttr *attr); @@ -118,6 +121,54 @@ static int CheckAttr(enum PmuTaskType collectType, struct PmuAttr *attr) return SUCCESS; } +void AppendChildEvents(char* evt, unordered_map& eventSplitMap) +{ + string strName(evt); + auto findSlash = strName.find('/'); + string devName = strName.substr(0, findSlash); + string evtName = strName.substr(devName.size(), strName.size() - devName.size() + 1); + for (int i = 0; i <= NINE; i++) { + string typePath = "/sys/devices/"; + string childName = devName; + typePath += devName + to_string(i) + "/type"; + string realPath = GetRealPath(typePath); + childName += to_string(i) + evtName; + if (IsValidPath(realPath)) { + eventSplitMap.emplace(childName, evt); + } + } +} + +static void SplitUncoreEvent(struct PmuAttr *attr, unordered_map &eventSplitMap) +{ + char** evtList = attr->evtList; + unsigned size = attr->numEvt; + int newSize = 0; + for (int i = 0; i < size; ++i) { + char* evt = evtList[i]; + char* slashPos = std::strchr(evt, '/'); + if (slashPos != nullptr && slashPos != evt) { + char* prevChar = slashPos - 1; + if (!std::isdigit(*prevChar)) { + // 添加子事件 + AppendChildEvents(evt, eventSplitMap); + continue; + } + } + eventSplitMap.emplace(evt, evt); + newSize++; + } +} + +static unsigned GenerateSplitList(unordered_map& eventSplitMap, vector &newEvtlist) +{ + // append child event + for (auto& event : eventSplitMap) { + newEvtlist.push_back(const_cast(event.first.c_str())); + } + return newEvtlist.size(); +} + static bool PdValid(const int &pd) { return PmuList::GetInstance()->IsPdAlive(pd); @@ -143,6 +194,12 @@ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr) if (err != SUCCESS) { return -1; } + unordered_map eventSplitMap; + SplitUncoreEvent(attr, eventSplitMap); + auto previousEventList = make_pair(attr->numEvt, attr->evtList); + vector newEvtlist; + attr->numEvt = GenerateSplitList(eventSplitMap, newEvtlist); + attr->evtList = newEvtlist.data(); auto pTaskAttr = AssignPmuTaskParam(collectType, attr); if (pTaskAttr == nullptr) { @@ -161,6 +218,9 @@ int PmuOpen(enum PmuTaskType collectType, struct PmuAttr *attr) PmuList::GetInstance()->Close(pd); pd = -1; } + // store eventList provided by user and the mapping relationship between the user eventList and the split + // eventList into buff + KUNPENG_PMU::PmuList::GetInstance()->StoreSplitData(pd, previousEventList, eventSplitMap); New(err); return pd; } catch (std::bad_alloc&) { diff --git a/pmu/pmu_list.h b/pmu/pmu_list.h index 67b8bd2..90f588b 100644 --- a/pmu/pmu_list.h +++ b/pmu/pmu_list.h @@ -66,6 +66,8 @@ public: int NewPd(); int GetHistoryData(const int pd, std::vector& pmuData); + void StoreSplitData(unsigned pd, std::pair previousEventList, + std::unordered_map eventSplitMap); private: using ProcPtr = std::shared_ptr; @@ -86,6 +88,7 @@ private: void InsertEvtList(const unsigned pd, std::shared_ptr evtList); std::vector>& GetEvtList(const unsigned pd); void EraseEvtList(const unsigned pd); + void EraseParentEventMap(); EventData& GetDataList(const unsigned pd); void EraseDataList(const unsigned pd); @@ -108,10 +111,12 @@ private: int PrepareProcTopoList(PmuTaskAttr* pmuTaskAttrHead, std::vector& procTopoList) const; int CheckRlimit(const unsigned fdNum); static void AggregateData(const std::vector& evData, std::vector& newEvData); + void AggregateUncoreData(const unsigned pd, const std::vector &evData, std::vector &newEvData); std::vector& GetPreviousData(const unsigned pd); static std::mutex pmuListMtx; static std::mutex dataListMtx; + static std::mutex dataParentMtx; std::unordered_map>> pmuList; // Key: pd // Value: PmuData List. @@ -121,7 +126,15 @@ private: // Value: PmuData vector for raw pointer. // PmuData is stored here after user call . std::unordered_map userDataList; - + // Key1: pd + // Key2: parent event + // Value: child event name list + // parent event name is stored here before user call to aggregate event. + std::unordered_map> parentEventMap; + // Key: pd + // Value: previous event list and its length + // previous event list is stored here before user call to aggregate event. + std::unordered_map> previousEventMap; // Key: pd // Value: epoll fd std::unordered_map epollList; -- Gitee From b0e5ee42d933b20379d0a0fe8cad496a53530c0b Mon Sep 17 00:00:00 2001 From: Junyi Ye <294572668@qq.com> Date: Mon, 22 Apr 2024 14:18:47 +0800 Subject: [PATCH 3/4] pfm support for uncore events and pmu event query interface --- pmu/pmu_list.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/pmu/pmu_list.cpp b/pmu/pmu_list.cpp index 42a4382..127c212 100644 --- a/pmu/pmu_list.cpp +++ b/pmu/pmu_list.cpp @@ -32,6 +32,7 @@ namespace KUNPENG_PMU { // Initializing pmu list singleton instance and global lock std::mutex PmuList::pmuListMtx; std::mutex PmuList::dataListMtx; + std::mutex PmuList::dataParentMtx; int PmuList::CheckRlimit(const unsigned fdNum) { @@ -210,6 +211,14 @@ namespace KUNPENG_PMU { return SUCCESS; } + void PmuList::StoreSplitData(const unsigned pd, pair previousEventList, + unordered_map eventSplitMap) + { + lock_guard lg(dataParentMtx); + parentEventMap.emplace(pd, move(eventSplitMap)); + previousEventMap.emplace(pd, move(previousEventList)); + } + void PmuList::Close(const int pd) { auto evtList = GetEvtList(pd); @@ -220,6 +229,7 @@ namespace KUNPENG_PMU { EraseDataList(pd); RemoveEpollFd(pd); EraseSpeCpu(pd); + EraseParentEventMap() SymResolverDestroy(); } @@ -305,6 +315,17 @@ namespace KUNPENG_PMU { pmuList.erase(pd); } + void PmuList::EraseParentEventMap() + { + lock_guard lg(dataParentMtx); + for (auto& pair : parentEventMap) { + auto& innerMap = pair.second; + innerMap.clear(); + } + parentEventMap.clear(); + previousEventMap.clear(); + } + PmuList::EventData& PmuList::GetDataList(const unsigned pd) { lock_guard lg(dataListMtx); @@ -370,15 +391,7 @@ namespace KUNPENG_PMU { auto& evData = dataList[pd]; auto pData = evData.data.data(); if (GetTaskType(pd) == COUNTING) { - std::vector newPmuData; - AggregateData(evData.data, newPmuData); - EventData newEvData = { - .pd = pd, - .collectType = COUNTING, - .data = newPmuData, - }; - - auto inserted = userDataList.emplace(newEvData.data.data(), move(newEvData)); + auto inserted = userDataList.emplace(pData, move(evData)); dataList.erase(pd); return inserted.first->second.data; } else { -- Gitee From bb9979090c0af57c231b66cdf461596f240f452e Mon Sep 17 00:00:00 2001 From: Junyi Ye <294572668@qq.com> Date: Mon, 22 Apr 2024 14:34:03 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pmu/pmu_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmu/pmu_list.cpp b/pmu/pmu_list.cpp index 127c212..4ac2fa9 100644 --- a/pmu/pmu_list.cpp +++ b/pmu/pmu_list.cpp @@ -229,7 +229,7 @@ namespace KUNPENG_PMU { EraseDataList(pd); RemoveEpollFd(pd); EraseSpeCpu(pd); - EraseParentEventMap() + EraseParentEventMap(); SymResolverDestroy(); } -- Gitee