diff --git a/include/pcerrc.h b/include/pcerrc.h index 465c25b0ba339584c5adcaaeb73c53856f77e7b8..a081b56f2c2527e1724a0282e6d689e6473e6a14 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -90,6 +90,16 @@ extern "C" { #define LIBPERF_ERR_NOT_SUPPORT_CONFIG_EVENT 1046 #define LIBPERF_ERR_INVALID_BLOCKED_SAMPLE 1047 #define LIBPERF_ERR_NOT_SUPPORT_GROUP_EVENT 1048 +#define LIBPERF_ERR_INVALID_PMU_DEVICES_METRIC 1049 +#define LIBPERF_ERR_INVALID_PMU_DEVICES_BDF 1050 +#define LIBPERF_ERR_OPEN_INVALID_FILE 1051 +#define LIBPERF_ERR_INVALID_BDF_VALUE 1052 +#define LIBPERF_ERR_NOT_SOUUPUT_PCIE_BDF 1053 +#define LIBPERF_ERR_NOT_SOUUPUT_SMMU_BDF 1054 +#define LIBPERF_ERR_INVALID_IOSMMU_DIR 1055 +#define LIBPERF_ERR_INVALID_SMMU_NAME 1056 +#define LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING 1057 +#define LIBPERF_ERR_OPEN_PCI_FILE_FAILD 1058 #define UNKNOWN_ERROR 9999 diff --git a/include/pmu.h b/include/pmu.h index 15962bce19c64540e4d4bc58dab24ef6daf432f4..8cfa520b23c81fd8faba78c76c2adf9350577d41 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -415,6 +415,10 @@ enum PmuDeviceMetric { PMU_L3_REF, // Collect L3 total latency. PMU_L3_LAT, + // Collect PA to ring bandwidth. + PMU_PA2RING_ALL_BW, + // Collect ring to pa bandwidth. + PMU_RING2PA_ALL_BW, // Collect pcie rx bandwidth. PMU_PCIE_RX_MRD_BW, PMU_PCIE_RX_MWR_BW, diff --git a/pmu/pfm/uncore.cpp b/pmu/pfm/uncore.cpp index 75b4200bca51c31ab924926e4586c4ccc2cd5f07..b4312b2c34de97fd32ddca572d3a43daeb5e18f6 100644 --- a/pmu/pfm/uncore.cpp +++ b/pmu/pfm/uncore.cpp @@ -104,9 +104,10 @@ int FillUncoreFields(const char* pmuName, PmuEvt *evt) } evt->type = devType; int cpuMask = GetCpuMask(devName); - if (cpuMask == -1) { - return UNKNOWN_ERROR; - } + // if is armv8 的uncore事件是没有这个cpumask文件 此时默认为-1 暂时不知道这个参数的作用是啥 + // if (cpuMask == -1) { + // return UNKNOWN_ERROR; + // } evt->cpumask = cpuMask; evt->name = pmuName; @@ -360,21 +361,9 @@ struct PmuEvt* GetUncoreRawEvent(const char* pmuName, int collectType) } auto fieldsValues = unCoreRawFieldsValues[(std::string)pmuName]; auto* pmuEvtPtr = new PmuEvt {0}; - if (fieldsValues.find("config") == fieldsValues.end()) { - pmuEvtPtr->config = 0; - } else { - pmuEvtPtr->config = fieldsValues.at("config"); - } - if (fieldsValues.find("config1") == fieldsValues.end()) { - pmuEvtPtr->config1 = 0; - } else { - pmuEvtPtr->config1 = fieldsValues.at("config1"); - } - if (fieldsValues.find("config2") == fieldsValues.end()) { - pmuEvtPtr->config2 = 0; - } else { - pmuEvtPtr->config2 = fieldsValues.at("config2"); - } + pmuEvtPtr->config = fieldsValues.find("config") == fieldsValues.end() ? 0 : fieldsValues.at("config"); + pmuEvtPtr->config1 = fieldsValues.find("config1") == fieldsValues.end() ? 0 : fieldsValues.at("config1"); + pmuEvtPtr->config2 = fieldsValues.find("config2") == fieldsValues.end() ? 0 : fieldsValues.at("config2"); pmuEvtPtr->name = pmuName; pmuEvtPtr->pmuType = UNCORE_RAW_TYPE; diff --git a/pmu/pmu_event_list.cpp b/pmu/pmu_event_list.cpp index b96e500c5b8c891faeb1566a0d04e82fbf4998f7..c85bc529006ca3d35ba478d46b232a5d49f7f4e3 100644 --- a/pmu/pmu_event_list.cpp +++ b/pmu/pmu_event_list.cpp @@ -37,7 +37,7 @@ static const string EVENT_DIR = "/events/"; static std::mutex pmuEventListMtx; -static vector supportDevPrefixs = {"hisi", "smmuv3", "hns3"}; +static vector supportDevPrefixs = {"hisi", "smmuv3", "hns3", "armv8"}; static vector uncoreEventList; static vector traceEventList; diff --git a/pmu/pmu_metric.cpp b/pmu/pmu_metric.cpp index 004a821792836203aeb6e16c29f22d1f5f3fe77c..f1caa7146759a1a5685b541d6723d9290b80ef78 100644 --- a/pmu/pmu_metric.cpp +++ b/pmu/pmu_metric.cpp @@ -12,19 +12,37 @@ * Create: 2025-03-29 * Description: functions for collect metric for L3, DDR, SMMU, PCIE and so on. ******************************************************************************/ -#include "pmu.h" #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" #include "uncore.h" +#include "cpu_map.h" +#include "symbol.h" +#include "pmu.h" #include "pcerrc.h" #include "pcerr.h" using namespace std; using namespace pcerr; +static const string SYS_DEVICES = "/sys/devices/"; +static const string SYS_BUS_PCI_DEVICES = "/sys/bus/pci/devices"; +static const string SYS_IOMMU_DEVICES = "/sys/class/iommu"; +static vector supportedDevicePrefixes = {"hisi", "smmuv3", "hns3", "armv8"}; +static vector uncoreRawDeviceList; +static vector> pciePmuBdfRang; +static unordered_map bdfToSmmuMap; + namespace KUNPENG_PMU { struct UncoreDeviceConfig { string devicePrefix; @@ -35,17 +53,559 @@ namespace KUNPENG_PMU { unsigned splitPosition; }; - static const unordered_map DEVICE_CONFIGS = { - {PmuDeviceMetric::PMU_DDR_READ_BW, {"hisi_sccl", "ddrc", {"0x84"}, "", "", 1}}, - {PmuDeviceMetric::PMU_DDR_WRITE_BW, {"hisi_sccl", "ddrc", {"0x83"}, "", "", 1}}, - {PmuDeviceMetric::PMU_L3_TRAFFIC, {"armv8_pmu", "", {"0x0032"}, "", "", 0}}, - {PmuDeviceMetric::PMU_L3_MISS, {"armv8_pmu", "", {"0x0033"}, "", "", 0}}, - {PmuDeviceMetric::PMU_L3_LAT, {"hisi_sccl", "l3c", {"0x80"}, "", "", 1}}, - {PmuDeviceMetric::PMU_PCIE_RX_MRD_BW, {"hisi_pcie", "core", {"0x0804", "0x10804"}, "", "bdf=", 1}}, - {PmuDeviceMetric::PMU_PCIE_RX_MWR_BW, {"hisi_pcie", "core", {"0x0104", "0x10104"}, "", "bdf=", 1}}, - {PmuDeviceMetric::PMU_PCIE_TX_MRD_BW, {"hisi_pcie", "core", {"0x0405", "0x10405"}, "", "bdf=", 1}}, - {PmuDeviceMetric::PMU_PCIE_TX_MWR_BW, {"hisi_pcie", "core", {"0x0105", "0x10105"}, "", "bdf=", 1}}, - {PmuDeviceMetric::PMU_SMMU_TRAN, {"smmuv3_pmcg", "", {"0x1"}, "filter_enable=1", "filter_stream_id=", 2}}}; + using PMU_METRIC_PAIR = std::pair; + using UNCORE_METRIC_MAP = std::unordered_map&>; + namespace METRIC_CONFIG { + PMU_METRIC_PAIR DDR_READ_BW_A = { + PmuDeviceMetric::PMU_DDR_READ_BW, + { + "hisi_sccl", + "ddrc", + {"0x1"}, + "", + "", + 1 + } + }; + + PMU_METRIC_PAIR DDR_WRITE_BW_A = { + PmuDeviceMetric::PMU_DDR_WRITE_BW, + { + "hisi_sccl", + "ddrc", + {"0x0"}, + "", + "", + 1 + } + }; + + PMU_METRIC_PAIR DDR_READ_BW_B = { + PmuDeviceMetric::PMU_DDR_READ_BW, + { + "hisi_sccl", + "ddrc", + {"0x84"}, + "", + "", + 1 + } + }; + + PMU_METRIC_PAIR DDR_WRITE_BW_B = { + PmuDeviceMetric::PMU_DDR_WRITE_BW, + { + "hisi_sccl", + "ddrc", + {"0x83"}, + "", + "", + 1 + } + }; + + PMU_METRIC_PAIR L3_TRAFFIC = { + PmuDeviceMetric::PMU_L3_TRAFFIC, + { + "armv8_pmu", + "", + {"0x0032"}, + "", + "", + 0 + } + }; + + PMU_METRIC_PAIR L3_MISS = { + PmuDeviceMetric::PMU_L3_MISS, + { + "armv8_pmu", + "", + {"0x0033"}, + "", + "", + 0 + } + }; + + PMU_METRIC_PAIR L3_REF = { + PmuDeviceMetric::PMU_L3_REF, + { + "armv8_pmu", + "", + {"0x0032"}, + "", + "", + 0 + } + }; + + PMU_METRIC_PAIR L3_LAT = { + PmuDeviceMetric::PMU_L3_LAT, + { + "armv8_pmu", + "", + {"0x80"}, + "", + "", + 0 + } + }; + + PMU_METRIC_PAIR PA2RING_ALL_BW = { + PmuDeviceMetric::PMU_PA2RING_ALL_BW, + { + "hisi_sicl", + "_pa", + {"0x60", "0x61", "0x62", "0x63"}, + "", + "", + 1 + } + }; + + PMU_METRIC_PAIR RING2PA_ALL_BW = { + PmuDeviceMetric::PMU_RING2PA_ALL_BW, + { + "hisi_sicl", + "_pa", + {"0x40", "0x41", "0x42", "0x43"}, + "", + "", + 1 + } + + }; + + PMU_METRIC_PAIR PCIE_RX_MRD_BW = { + PmuDeviceMetric::PMU_PCIE_RX_MRD_BW, + { + "hisi_pcie", + "core", + {"0x0804", "0x10804"}, + "", + "bdf=", + 1 + } + }; + + PMU_METRIC_PAIR PCIE_RX_MWR_BW = { + PmuDeviceMetric::PMU_PCIE_RX_MWR_BW, + { + "hisi_pcie", + "core", + {"0x0104", "0x10104"}, + "", + "bdf=", + 1 + } + }; + + PMU_METRIC_PAIR PCIE_TX_MRD_BW = { + PmuDeviceMetric::PMU_PCIE_TX_MRD_BW, + { + "hisi_pcie", + "core", + {"0x0405", "0x10405"}, + "", + "bdf=", + 1 + } + }; + + PMU_METRIC_PAIR PCIE_TX_MWR_BW = { + PmuDeviceMetric::PMU_PCIE_TX_MWR_BW, + { + "hisi_pcie", + "core", + {"0x0105", "0x10105"}, + "", + "bdf=", + 1 + } + }; + + PMU_METRIC_PAIR SMMU_TRAN = { + PmuDeviceMetric::PMU_SMMU_TRAN, + { + "smmuv3_pmcg", + "", + {"0x1"}, + "filter_enable=1", + "filter_stream_id=", + 2 + } + }; + } + + static const unordered_map HIP_A_UNCORE_METRIC_MAP { + METRIC_CONFIG::DDR_READ_BW_A, + METRIC_CONFIG::DDR_WRITE_BW_A, + METRIC_CONFIG::L3_TRAFFIC, + METRIC_CONFIG::L3_MISS, + METRIC_CONFIG::L3_REF, + METRIC_CONFIG::SMMU_TRAN, + }; + + static const unordered_map HIP_B_UNCORE_METRIC_MAP { + METRIC_CONFIG::DDR_READ_BW_B, + METRIC_CONFIG::DDR_WRITE_BW_B, + METRIC_CONFIG::L3_TRAFFIC, + METRIC_CONFIG::L3_MISS, + METRIC_CONFIG::L3_REF, + METRIC_CONFIG::L3_LAT, + METRIC_CONFIG::PA2RING_ALL_BW, + METRIC_CONFIG::RING2PA_ALL_BW, + METRIC_CONFIG::PCIE_RX_MRD_BW, + METRIC_CONFIG::PCIE_RX_MWR_BW, + METRIC_CONFIG::PCIE_TX_MRD_BW, + METRIC_CONFIG::PCIE_TX_MWR_BW, + METRIC_CONFIG::SMMU_TRAN, + }; + + const UNCORE_METRIC_MAP UNCORE_METRIC_CONFIG_MAP = { + {CHIP_TYPE::HIPA, HIP_A_UNCORE_METRIC_MAP}, + {CHIP_TYPE::HIPB, HIP_B_UNCORE_METRIC_MAP}, + }; + + static const unordered_map GetDeviceMtricConfig() + { + return UNCORE_METRIC_CONFIG_MAP.at(GetCpuType()); + } + + static int QueryUncoreRawDevices() + { + if (!uncoreRawDeviceList.empty()) { + return SUCCESS; + } + if (!ExistPath(SYS_DEVICES) || !IsDirectory(SYS_DEVICES)) { + New(LIBPERF_ERR_QUERY_EVENT_LIST_FAILED, "Query uncore evtlist falied!"); + return LIBPERF_ERR_QUERY_EVENT_LIST_FAILED; + } + vector entries = ListDirectoryEntries(SYS_DEVICES); + for (const auto& entry : entries) { + for (auto devPrefix : supportedDevicePrefixes) { + if (entry.find(devPrefix) == 0) { + uncoreRawDeviceList.emplace_back(entry); + break; + } + } + } + return SUCCESS; + } + + static int QueryBdfToSmmuMapping() + { + if (!bdfToSmmuMap.empty()) { + return SUCCESS; + } + if (!ExistPath(SYS_IOMMU_DEVICES) || !IsDirectory(SYS_IOMMU_DEVICES)) { + cerr << "Directory does not exist or is not a directory: " << SYS_IOMMU_DEVICES << endl; + SetCustomErr(LIBPERF_ERR_INVALID_IOSMMU_DIR, "Directory does not exist or is not a directory: " + SYS_IOMMU_DEVICES); + return LIBPERF_ERR_INVALID_IOSMMU_DIR; + } + vector entries = ListDirectoryEntries(SYS_IOMMU_DEVICES); + for (const auto& entry : entries) { + string devicesPath = SYS_IOMMU_DEVICES + "/" + entry + "/devices"; + if (!ExistPath(devicesPath) || !IsDirectory(devicesPath)) { + SetCustomErr(LIBPERF_ERR_INVALID_IOSMMU_DIR, "Directory does not exist or is not a directory: " + devicesPath); + return LIBPERF_ERR_INVALID_IOSMMU_DIR; + } + vector bdfEntries = ListDirectoryEntries(devicesPath); + for (const auto& bdfEntry : bdfEntries) { + if (IsDirectory(devicesPath + "/" + bdfEntry)) { + string bdfStr = bdfEntry; + if (bdfStr.find("0000:") != string::npos) { + string bdfValue = bdfStr.substr(bdfStr.find("0000:") + strlen("0000:")); + bdfToSmmuMap[bdfValue] = entry; + } + } + } + } + return SUCCESS; + } + + static int ConvertBdfStringToValue(const string& bdfStr, uint16_t& bdfValue) + { + vector busDeviceFunction = SplitStringByDelimiter(bdfStr, ':'); + vector deviceFunction = SplitStringByDelimiter(busDeviceFunction[1], '.'); + if (busDeviceFunction.size() != 2 || deviceFunction.size() != 2) { + New(LIBPERF_ERR_INVALID_BDF_VALUE, "bdf value is invalid, shoubld be like 00:00.0"); + return LIBPERF_ERR_INVALID_BDF_VALUE; + } + uint16_t bus = 0; + uint16_t device = 0; + uint16_t function = 0; + try { + bus = static_cast(stoul(busDeviceFunction[0], nullptr, 16)); + device = static_cast(stoul(deviceFunction[0], nullptr, 16)); + function = static_cast(stoul(deviceFunction[1], nullptr, 16)); + } catch (const std::invalid_argument& e) { + New(LIBPERF_ERR_INVALID_BDF_VALUE, "bdf value is invalid, shoubld be like 00:00.0"); + return LIBPERF_ERR_INVALID_BDF_VALUE; + } + if (bus > 0xFF || device > 0x1F || function > 0x7) { + New(LIBPERF_ERR_INVALID_BDF_VALUE, "bdf value is invalid, shoubld be like 00:00.0"); + return LIBPERF_ERR_INVALID_BDF_VALUE; + } + bdfValue = (static_cast(bus) << 8) | (static_cast(device) << 3) | function; + return SUCCESS; + } + + // convert smmu name to smmu pmu key. example: smmu3.0x0000000100100000 -> 100120 + static int ConvertSmmuToDeviceAddress(const string& smmuDeviceName, string& smmuPmuKey) + { + const string prefix = "smmu3.0x"; + const uint64_t PMU_OFFSET = 0x20000; + size_t pos = smmuDeviceName.find(prefix); + string hexAddressStr = smmuDeviceName.substr(prefix.length()); + uint64_t physicalBaseAddress = 0; + try { + physicalBaseAddress = stoul(hexAddressStr, nullptr, 16); + } catch (const std::invalid_argument& e) { + SetCustomErr(LIBPERF_ERR_INVALID_SMMU_NAME, "invalid smmu device name"); + return LIBPERF_ERR_INVALID_SMMU_NAME; + } + uint64_t pmuPhysicalAddress = physicalBaseAddress + PMU_OFFSET; + uint64_t pmuSuffix = pmuPhysicalAddress >> 12; + std::stringstream result; + result << hex << uppercase << pmuSuffix; + smmuPmuKey = result.str(); + return SUCCESS; + } + + static int FindSmmuDeviceByBdf(std::unordered_map>& classifiedDevices, const string& bdf, string& smmuPmuName) + { + auto it = bdfToSmmuMap.find(bdf); + if (it == bdfToSmmuMap.end()) { + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_SMMU_BDF, "BDF Value " + bdf + " not found in any SMMU Directory."); + return LIBPERF_ERR_NOT_SOUUPUT_SMMU_BDF; + } + string smmuPmuKey = ""; + int err = ConvertSmmuToDeviceAddress(it->second, smmuPmuKey); + if (err != SUCCESS) { + return err; + } + const auto smmu = classifiedDevices.find(smmuPmuKey); + if (smmu == classifiedDevices.end()) { + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_SMMU_BDF, "BDF Value " + bdf + " not manage in any SMMU Directory."); + return LIBPERF_ERR_NOT_SOUUPUT_SMMU_BDF; + } + smmuPmuName = smmu->second.front(); + return SUCCESS; + } + + static int QueryPcieBdfRanges() + { + if (!pciePmuBdfRang.empty()) { + return SUCCESS; + } + if (!ExistPath(SYS_DEVICES) || !IsDirectory(SYS_DEVICES)) { + cerr << "PCI devices directory not found: " << SYS_DEVICES << endl; + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_PCIE_BDF, "PCI devices directory not found: " + SYS_DEVICES); + return LIBPERF_ERR_NOT_SOUUPUT_PCIE_BDF; + } + vector entries = ListDirectoryEntries(SYS_DEVICES); + for (const auto& entry : entries) { + if (entry.find("pcie") != string::npos) { + string bdfBusPath = SYS_DEVICES + "/" + entry + "/bus"; + string bdfMinPath = SYS_DEVICES + "/" + entry + "/bdf_min"; + string bdfMaxPath = SYS_DEVICES + "/" + entry + "/bdf_max"; + if (!ExistPath(bdfBusPath) || !ExistPath(bdfMinPath) || !ExistPath(bdfMaxPath)) { + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING, "pcie pmu bdfMin or bdfMax file is empty"); + return LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING; + } + string bdfBusStr = ReadFileContent(bdfBusPath); + string bdfMinStr = ReadFileContent(bdfMinPath); + string bdfMaxStr = ReadFileContent(bdfMaxPath); + if (bdfBusStr.empty() || bdfMinStr.empty() || bdfMaxStr.empty()) { + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING, "pcie pmu bdfMin or bdfMax file is empty"); + return LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING; + } + uint16_t bus = 0; + uint16_t bdfMin = 0; + uint16_t bdfMax = 0; + try { + bus = stoul(bdfBusStr, nullptr, 16); + bdfMin = stoul(bdfMinStr, nullptr, 16); + bdfMax = stoul(bdfMaxStr, nullptr, 16); + } catch (const std::exception& e) { + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING, "pcie pmu bdfMin or bdfMax file is invalid"); + return LIBPERF_ERR_NOT_SOUUPUT_PCIE_COUNTING; + } + if (bus == 0) { + continue; // skip the invalid pcie pmu device + } + pciePmuBdfRang.emplace_back(entry, bdfMin, bdfMax); + + } + } + return SUCCESS; + } + + static int FindPcieDeviceByBdf(const string& bdf, string& pciePmuName) + { + uint16_t userBdf = 0; + int err = ConvertBdfStringToValue(bdf, userBdf); + if (err != SUCCESS) { + return err; + } + for (const auto& [deviceName, bdfMin, bdfMax] : pciePmuBdfRang) { + if (userBdf >= bdfMin && userBdf <= bdfMax) { + pciePmuName = deviceName; + return SUCCESS; + } + } + SetCustomErr(LIBPERF_ERR_NOT_SOUUPUT_PCIE_BDF, "bdf value " + bdf + " is not managed by any PCIe Device."); + return LIBPERF_ERR_NOT_SOUUPUT_PCIE_BDF; + } + + static bool ValidateBdfValue(const string& bdf) + { + if (!ExistPath(SYS_BUS_PCI_DEVICES) || !IsDirectory(SYS_BUS_PCI_DEVICES)) { + New(LIBPERF_ERR_OPEN_PCI_FILE_FAILD, SYS_BUS_PCI_DEVICES + " is not exist."); + return false; + } + unordered_set validBdfSet; + vector entries = ListDirectoryEntries(SYS_BUS_PCI_DEVICES); + for (const auto& entry : entries) { + if (entry.size() > 5 && entry.substr(0, 5) == "0000:") { + validBdfSet.insert(entry.substr(5)); + } + } + if (validBdfSet.find(bdf) == validBdfSet.end()) { + New(LIBPERF_ERR_OPEN_PCI_FILE_FAILD, SYS_BUS_PCI_DEVICES + " is not exist this bdf number."); + return false; + } + return true; + } + + static std::unordered_map> ClassifyDevicesByPrefix(const string& devicePrefix, + const string& subDeviceName, unsigned splitPos) + { + std::unordered_map> classifiedDevices; + for (const auto& device : uncoreRawDeviceList) { + if (device.find(devicePrefix) != string::npos && device.find(subDeviceName) != string::npos) { + if (splitPos == 0) { + classifiedDevices[device].push_back(device); + continue; + } + vector splitParts = SplitStringByDelimiter(device, '_'); + if (splitParts.size() > splitPos) { + classifiedDevices[splitParts[splitPos]].push_back(device); + } + } + } + return classifiedDevices; + } + + static vector GenerateEventStrings(std::unordered_map> classifiedDevices, + const vector& events, const string& extraConfig, const string& bdfParameter, const string& bdf) + { + vector eventList; + if (!bdf.empty()) { + for (const auto& evt : events) { + string device = ""; + if (bdfParameter == "bdf=") { + int err = FindPcieDeviceByBdf(bdf, device); + if (err != SUCCESS) { + return {}; + } + } else { + int err = FindSmmuDeviceByBdf(classifiedDevices, bdf, device); + if (err != SUCCESS) { + return {}; + } + } + string eventString = device + "/config=" + evt; + if (!extraConfig.empty()) eventString += "," + extraConfig; + if (!bdfParameter.empty() && !bdf.empty()) { + stringstream bdfValue; + uint16_t userBdf = 0; + ConvertBdfStringToValue(bdf, userBdf); + bdfValue << "0x" << hex << userBdf; + eventString += "," + bdfParameter + bdfValue.str(); + } + eventString += "/"; + eventList.push_back(eventString); + } + return eventList; + } + for (const auto& [key, devices] : classifiedDevices) { + for (const auto& evt : events) { + for (const auto& device : devices) { + string eventString = device + "/config=" + evt + "/"; + eventList.push_back(eventString); + } + } + } + return eventList; + } + + static vector GenerateEventList(struct PmuDeviceAttr& deviceAttr) + { + const auto& deviceConfig = GetDeviceMtricConfig(); + const auto& config = deviceConfig.at(deviceAttr.metric); + string bdf = ""; + if (deviceAttr.bdf != nullptr) { + if (!ValidateBdfValue(deviceAttr.bdf)) { + return {}; + } + int err = QueryPcieBdfRanges(); + if (err != SUCCESS) { + return {}; + } + err = QueryBdfToSmmuMapping(); + if (err != SUCCESS) { + return {}; + } + bdf = deviceAttr.bdf; + } + int err = QueryUncoreRawDevices(); + if (err != SUCCESS) { + return {}; + } + auto classifiedDevices = ClassifyDevicesByPrefix(config.devicePrefix, config.subDeviceName, config.splitPosition); + return GenerateEventStrings(classifiedDevices, config.events, config.extraConfig, config.bdfParameter, bdf); + } + + static int CheckDeviceMetricEnum(struct PmuDeviceAttr *attr, unsigned len) + { + for (int i = 0; i < len; ++i) { + const auto & metricConfig = GetDeviceMtricConfig(); + if (metricConfig.find(attr[i].metric) == metricConfig.end()) { + New(LIBPERF_ERR_INVALID_PMU_DEVICES_METRIC, "for this platform this metric is invalid value for PmuDeviceMetric!"); + return LIBPERF_ERR_INVALID_PMU_DEVICES_METRIC; + } + } + return SUCCESS; + } + + static int CheckBdf(struct PmuDeviceAttr *attr, unsigned len) + { + for (int i = 0; i < len; ++i) { + if (attr[i].metric >= PMU_PCIE_RX_MRD_BW && attr[i].bdf == nullptr) { + New(LIBPERF_ERR_INVALID_PMU_DEVICES_BDF, "When collecting pcie or smmu metric, bdf value can not is nullptr!"); + return LIBPERF_ERR_INVALID_PMU_DEVICES_BDF; + } + } + return SUCCESS; + } + + static int CheckPmuDeviceAttr(struct PmuDeviceAttr *attr, unsigned len) + { + int err = CheckDeviceMetricEnum(attr, len); + if (!err) { + return err; + } + + err = CheckBdf(attr, len); + if (!err) { + return err; + } + + return SUCCESS; + } struct InnerDeviceData { enum PmuDeviceMetric metric; @@ -136,8 +696,9 @@ namespace KUNPENG_PMU { int PcieBWAggregate(const PmuDeviceMetric metric, const vector &rawData, vector &devData) { - auto findConfig = DEVICE_CONFIGS.find(metric); - if (findConfig == DEVICE_CONFIGS.end()) { + const auto& deviceConfig = GetDeviceMtricConfig(); + const auto& findConfig = deviceConfig.find(metric); + if (findConfig == deviceConfig.end()) { return SUCCESS; } auto &evts = findConfig->second.events; @@ -227,8 +788,9 @@ namespace KUNPENG_PMU { static bool IsMetricEvent(const string &devName, const string &evtName, const PmuDeviceAttr &devAttr) { - auto findDevConfig = DEVICE_CONFIGS.find(devAttr.metric); - if (findDevConfig == DEVICE_CONFIGS.end()) { + const auto& deviceConfig = GetDeviceMtricConfig(); + auto findDevConfig = deviceConfig.find(devAttr.metric); + if (findDevConfig == deviceConfig.end()) { return false; } @@ -299,6 +861,32 @@ namespace KUNPENG_PMU { using namespace KUNPENG_PMU; +int PmuDeviceOpen(struct PmuDeviceAttr *attr, unsigned len) +{ + if (CheckPmuDeviceAttr(attr, len) != SUCCESS) { + return -1; + } + vector configEvtList; + for (int i = 0; i < len; ++i) { + vector temp = GenerateEventList(attr[i]); + if (temp.empty()) { + return -1; + } + configEvtList.insert(configEvtList.end(), temp.begin(), temp.end()); + } + + vector evts; + for (auto& evt : configEvtList) { + evts.push_back(const_cast(evt.c_str())); + } + + PmuAttr attrConfig = {0}; + attrConfig.evtList = evts.data(); + attrConfig.numEvt = evts.size(); + int pd = PmuOpen(COUNTING, &attrConfig); + return pd; +} + int PmuGetDevMetric(struct PmuData *pmuData, unsigned len, struct PmuDeviceAttr *attr, unsigned attrLen, struct PmuDeviceData **data) @@ -344,4 +932,6 @@ void DevDataFree(struct PmuDeviceData *data) deviceDataMap.erase(data); } New(SUCCESS); -} \ No newline at end of file +} + + diff --git a/python/modules/CMakeLists.txt b/python/modules/CMakeLists.txt index 40b53a1fbbda7046d5dfff508d8bdde32fe47bef..8f898fc225d644d0cb6bf18f2c69a466ae90e2f5 100644 --- a/python/modules/CMakeLists.txt +++ b/python/modules/CMakeLists.txt @@ -22,7 +22,7 @@ configure_file( ) add_custom_target(${PROJECT_NAME} ALL - COMMAND ${PYTHON_EXECUTABLE} setup.py install + COMMAND ${PYTHON_EXECUTABLE} setup.py install --user WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/util/common.cpp b/util/common.cpp index ddf361352f64c7e6fae812d88fbd90f69f19ef62..21cacd127b366cebba4fde82c5641b63474fb4f3 100644 --- a/util/common.cpp +++ b/util/common.cpp @@ -14,12 +14,18 @@ ******************************************************************************/ #include +#include +#include +#include +#include #include #include +#include #include #include #include #include "pcerrc.h" +#include "pcerr.h" #include "common.h" bool IsValidIp(unsigned long ip) { @@ -48,7 +54,43 @@ bool IsValidPath(const std::string& filePath) return true; } -int RaiseNumFd(unsigned long numFd) +bool IsDirectory(const std::string& path) +{ + struct stat statbuf; + return stat(path.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode); +} + +std::vector ListDirectoryEntries(const std::string& dirPath) +{ + std::vector entries; + DIR* dir = opendir(dirPath.c_str()); + if (!dir) { + pcerr::SetCustomErr(LIBPERF_ERR_OPEN_INVALID_FILE, "Failed to open directory: " + dirPath); + return entries; + } + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + entries.push_back(entry->d_name); + } + closedir(dir); + return entries; +} + +std::string ReadFileContent(const std::string& filePath) +{ + std::ifstream file(filePath); + if (!file.is_open()) { + pcerr::SetCustomErr(LIBPERF_ERR_OPEN_INVALID_FILE, "Failed to open File: " + filePath); + return ""; + } + std::string content; + std::getline(file, content); + file.close(); + return content; +} + +int RaiseNumFd(uint64_t numFd) { unsigned long extra = 50; unsigned long setNumFd = extra + numFd; @@ -76,14 +118,25 @@ int RaiseNumFd(unsigned long numFd) } bool ExistPath(const std::string &filePath) { - struct stat st{}; - if(stat(filePath.c_str(), &st) != 0) { - return false; + struct stat statbuf{}; + return stat(filePath.c_str(), &statbuf) == 0; +} + +std::vector SplitStringByDelimiter(const std::string& str, char delimiter) +{ + std::vector parts; + std::stringstream ss(str); + std::string part; + while (std::getline(ss, part, delimiter)) { + if (!part.empty()) { + parts.push_back(part); + } } - return true; + return parts; } -std::string GetTraceEventDir() { +std::string GetTraceEventDir() +{ if (ExistPath(TRACE_EVENT_PATH)) { return TRACE_EVENT_PATH; } diff --git a/util/common.h b/util/common.h index 5e5d0aaa39be1f5d71915492f2132a9f0149604f..4ffd0c8e4cef5f193a60733916afcae753a66175 100644 --- a/util/common.h +++ b/util/common.h @@ -17,6 +17,7 @@ #define LIBKPROF_COMMON_H #include #include +#include const std::string TRACE_EVENT_PATH = "/sys/kernel/tracing/events/"; const std::string TRACE_DEBUG_EVENT_PATH = "/sys/kernel/debug/tracing/events/"; @@ -24,6 +25,11 @@ const std::string TRACE_DEBUG_EVENT_PATH = "/sys/kernel/debug/tracing/events/"; bool IsValidIp(unsigned long ip); std::string GetRealPath(const std::string filePath); bool IsValidPath(const std::string& filePath); +bool IsDirectory(const std::string& path); +bool FileExists(const std::string& path); +std::vector ListDirectoryEntries(const std::string& dirPath); +std::string ReadFileContent(const std::string& filePath); +std::vector SplitStringByDelimiter(const std::string& str, char delimiter); int RaiseNumFd(uint64_t numFd); bool ExistPath(const std::string& filePath); std::string GetTraceEventDir();