diff --git a/.gitmodules b/.gitmodules index 53b7abf1..bcd6dc7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "perfmon"] path = perfmon url = https://github.com/intel/perfmon +[submodule "src/pugixml"] + path = src/pugixml + url = https://github.com/zeux/pugixml.git +[submodule "Intel-PMT"] + path = Intel-PMT + url = https://github.com/intel/Intel-PMT.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 662e5bff..d10d43ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,28 @@ if(PCM_FUZZ) message(STATUS "CMAKE_EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}") endif(PCM_FUZZ) +####################### +# pugixml dependency +####################### + +add_library(PCM_PUGIXML INTERFACE) # interface library for pugixml +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/pugixml/src/pugixml.cpp") + message(STATUS "Local pugixml exists: ${CMAKE_CURRENT_SOURCE_DIR}/src/pugixml/src/pugixml.cpp") + set(PCM_PUGIXML_CPP ${CMAKE_CURRENT_SOURCE_DIR}/src/pugixml/src/pugixml.cpp) + add_compile_definitions(PCM_PUGIXML_AVAILABLE) +else() + message(STATUS "Local pugixml doesn't exist") +# message(WARNING +# " ${CMAKE_CURRENT_SOURCE_DIR}/src/pugixml/src/pugixml.cpp doesn't exist\n" +# " Use `git clone --recursive` flag when cloning pcm repository to clone pugixml submodule as well or\n" +# " update submodule with command 'git submodule update --init --recursive' or\n" +# " run 'git clone https//github.com/zeux/pugixml.git' in 'src' directory to get pugixml library") +endif() + +####################### +# End of pugixml dependency section +####################### + ####################### # Install ####################### diff --git a/Intel-PMT b/Intel-PMT new file mode 160000 index 00000000..76f9e9e5 --- /dev/null +++ b/Intel-PMT @@ -0,0 +1 @@ +Subproject commit 76f9e9e5858399ab59225953932117b31a6fef16 diff --git a/perfmon b/perfmon index d8859e3a..3fc7a87f 160000 --- a/perfmon +++ b/perfmon @@ -1 +1 @@ -Subproject commit d8859e3a5480721a13651cf20a35a1727afcd570 +Subproject commit 3fc7a87fde40817b521dbfb079da85b52a0cc96b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c39770d8..e83434cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,7 @@ set(PROJECT_NAMES pcm pcm-numa pcm-latency pcm-power pcm-msr pcm-memory pcm-tsx set(MINIMUM_OPENSSL_VERSION 1.1.1) -file(GLOB COMMON_SOURCES pcm-accel-common.cpp msr.cpp cpucounters.cpp pci.cpp mmio.cpp tpmi.cpp pmt.cpp bw.cpp utils.cpp topology.cpp debug.cpp threadpool.cpp uncore_pmu_discovery.cpp) +file(GLOB COMMON_SOURCES pcm-accel-common.cpp msr.cpp cpucounters.cpp pci.cpp mmio.cpp tpmi.cpp pmt.cpp bw.cpp utils.cpp topology.cpp debug.cpp threadpool.cpp uncore_pmu_discovery.cpp ${PCM_PUGIXML_CPP}) if (APPLE) file(GLOB UNUX_SOURCES dashboard.cpp) @@ -154,7 +154,7 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSIO endif() if(SIMDJSON_IS_APPLICABLE) - find_package(simdjson QUIET) # Working form Ububtu 22.04 + find_package(simdjson QUIET) # Working form Ubuntu 22.04 if(simdjson_FOUND) message(STATUS "System SIMDJSON is used") target_link_libraries(PCM_SIMDJSON INTERFACE simdjson::simdjson) diff --git a/src/cpucounters.cpp b/src/cpucounters.cpp index 27cfd7d3..ab3299c4 100644 --- a/src/cpucounters.cpp +++ b/src/cpucounters.cpp @@ -2027,7 +2027,7 @@ void PCM::initUncoreObjects() //TPMIHandle::setVerbose(true); try { - if (TPMIHandle::getNumInstances() == (size_t)num_sockets) + if (isServerCPU() && TPMIHandle::getNumInstances() == (size_t)num_sockets) { // std::cerr << "DEBUG: TPMIHandle::getNumInstances(): " << TPMIHandle::getNumInstances() << "\n"; UFSStatus.resize(num_sockets); @@ -3159,7 +3159,10 @@ PCM::PCM() : std::cerr << "\n"; #endif - uncorePMUDiscovery = std::make_shared(); + if (isServerCPU()) + { + uncorePMUDiscovery = std::make_shared(); + } initUncoreObjects(); diff --git a/src/pci.cpp b/src/pci.cpp index d7f485df..89259937 100644 --- a/src/pci.cpp +++ b/src/pci.cpp @@ -145,8 +145,14 @@ int32 PciHandle::read64(uint64 offset, uint64 * value) warnAlignment<4>("PciHandle::read64", false, offset); if (hDriver != INVALID_HANDLE_VALUE) { + if (offset & 7) + { + // this driver supports only 8-byte aligned reads + // use read32 for unaligned reads + uint32* value32Ptr = (uint32*)value; + return read32(offset, value32Ptr) + read32(offset + sizeof(uint32), value32Ptr + 1); + } PCICFG_Request req; - // ULONG64 result; DWORD reslength = 0; req.bus = bus; req.dev = device; diff --git a/src/pcm-iio.cpp b/src/pcm-iio.cpp index 8c77f038..9351e6ff 100644 --- a/src/pcm-iio.cpp +++ b/src/pcm-iio.cpp @@ -2240,7 +2240,7 @@ int mainThrows(int argc, char * argv[]) catch (std::exception & e) { std::cerr << "Error info:" << e.what() << "\n"; - std::cerr << "Event configure file have the problem and cause the program exit, please double check it!\n"; + std::cerr << "The event configuration file (" << ev_file_name << ") cannot be loaded. Please verify the file. Exiting.\n"; exit(EXIT_FAILURE); } diff --git a/src/pcm-raw.cpp b/src/pcm-raw.cpp index a6d4f1f7..84f7d964 100644 --- a/src/pcm-raw.cpp +++ b/src/pcm-raw.cpp @@ -91,6 +91,7 @@ void print_usage(const string & progname) bool verbose = false; double defaultDelay = 1.0; // in seconds +TelemetryDB telemDB; PCM::RawEventConfig initCoreConfig() { @@ -973,6 +974,37 @@ AddEventStatus addEvent(PCM::RawPMUConfigs & curPMUConfigs, string eventStr) } const auto configArray = split(configStr, ','); bool fixed = false; + std::string lookup; + auto pmtAddRecord = [&lookup, &pmuName, &config](const std::vector & records) -> AddEventStatus + { + if (pmuName == "pmt") + { + if (records.empty()) + { + cerr << "ERROR: lookup \"" << lookup << "\" not found in PMT telemetry database\n"; + return AddEventStatus::Failed; + } + if (records.size() > 1) + { + cerr << "ERROR: lookup \"" << lookup << "\" is ambiguous in PMT telemetry database\n\n"; + for (const auto & record : records) + { + cerr << " "; + record.print(cerr); + cerr << "\n"; + } + return AddEventStatus::Failed; + } + config.second = records[0].fullName; + assert(records.size() == 1); + config.first[PCM::PMTEventPosition::UID] = records[0].uid; + config.first[PCM::PMTEventPosition::offset] = records[0].qWordOffset; + config.first[PCM::PMTEventPosition::type] = (records[0].sampleType == "Snapshot") ? PCM::MSRType::Static : PCM::MSRType::Freerun; + config.first[PCM::PMTEventPosition::lsb] = records[0].lsb; + config.first[PCM::PMTEventPosition::msb] = records[0].msb; + } + return AddEventStatus::OK; + }; for (const auto & item : configArray) { if (match(item, "config=", &config.first[0])) @@ -1009,6 +1041,16 @@ AddEventStatus addEvent(PCM::RawPMUConfigs & curPMUConfigs, string eventStr) if (check_for_injections(config.second)) return AddEventStatus::Failed; } + else if (pcm_sscanf(item) >> s_expect("lookup=") >> setw(255) >> lookup) + { + if (pmtAddRecord(telemDB.lookup(lookup)) != AddEventStatus::OK) + return AddEventStatus::Failed; + } + else if (pcm_sscanf(item) >> s_expect("ilookup=") >> setw(255) >> lookup) + { + if (pmtAddRecord(telemDB.ilookup(lookup)) != AddEventStatus::OK) + return AddEventStatus::Failed; + } else if (item == "fixed") { fixed = true; @@ -2343,6 +2385,8 @@ int mainThrows(int argc, char * argv[]) bool reset_pmu = false; PCM* m = PCM::getInstance(); + telemDB.loadFromXML("Intel-PMT"); + parsePID(argc, argv, pid); #ifdef PCM_SIMDJSON_AVAILABLE diff --git a/src/pmt.cpp b/src/pmt.cpp index 9d21a32c..b99f4a5c 100644 --- a/src/pmt.cpp +++ b/src/pmt.cpp @@ -7,6 +7,12 @@ #include #include #include +#include +#include + +#ifdef PCM_PUGIXML_AVAILABLE +#include "pugixml/src/pugixml.hpp" +#endif #ifdef __linux__ #include @@ -79,6 +85,16 @@ class TelemetryArrayLinux : public TelemetryArrayInterface } return t.at(uid).size(); } + static std::vector getUIDs() + { + auto t = getTelemetryFiles(); + std::vector result; + for (auto & guid : t) + { + result.push_back(guid.first); + } + return result; + } virtual ~TelemetryArrayLinux() override { } @@ -124,6 +140,7 @@ class TelemetryArrayDummy : public TelemetryArrayInterface public: TelemetryArrayDummy(const size_t /* uid */, const size_t /* instance */) {}; static size_t numInstances(const size_t /* uid */) { return 0; }; + static std::vector getUIDs() { return std::vector(); }; virtual ~TelemetryArrayDummy() override {}; size_t size() override { return 0;}; // in bytes void load() override {}; @@ -150,6 +167,15 @@ size_t TelemetryArray::numInstances(const size_t uid) #endif } +std::vector TelemetryArray::getUIDs() +{ +#ifdef __linux__ + return TelemetryArrayLinux::getUIDs(); +#else + return TelemetryArrayDummy::getUIDs(); +#endif +} + TelemetryArray::~TelemetryArray() {} size_t TelemetryArray::size() @@ -170,4 +196,116 @@ uint64 TelemetryArray::get(size_t qWordOffset, size_t lsb, size_t msb) return impl->get(qWordOffset, lsb, msb); } + +bool TelemetryDB::loadFromXML(const std::string& pmtXMLPath) +{ +#ifdef PCM_PUGIXML_AVAILABLE + pugi::xml_document doc; + auto result = doc.load_file((pmtXMLPath + "/xml/pmt.xml").c_str()); + + if (!result) + { + std::cerr << "Error: failed to load " << pmtXMLPath << "/xml/pmt.xml" << std::endl; + return false; + } + + constexpr bool debug = false; + + auto guids = TelemetryArray::getUIDs(); + for (pugi::xml_node mapping: doc.child("pmt").child("mappings").children("mapping")) + { + auto guid = read_number(mapping.attribute("guid").value()); + if (std::find(guids.begin(), guids.end(), guid) == guids.end()) + { + // std::cerr << " guid " << std::hex << guid << " not found in telemetry files" << std::endl; + continue; + } + if (debug) std::cout << "Found mapping with guid: " << mapping.attribute("guid").value() << std::endl; + if (debug) std::cout << " Description: " << mapping.child("description").text().as_string() << std::endl; + const auto xmlset = mapping.child("xmlset"); + const auto basedir = xmlset.child("basedir").text().as_string(); + const auto aggregator = xmlset.child("aggregator").text().as_string(); + const auto aggregator_path = pmtXMLPath + "/xml/" + basedir + "/" + aggregator; + if (debug) std::cout << " Aggregator XML path: " << aggregator_path << std::endl; + + pugi::xml_document aggregatorDoc; + auto aggregatorResult = aggregatorDoc.load_file(aggregator_path.c_str()); + if (!aggregatorResult) + { + std::cerr << "Error: failed to load " << aggregator_path << std::endl; + return false; + } + + auto aggregatorNode = aggregatorDoc.child("TELEM:Aggregator"); + const std::string aggregatorName = aggregatorNode.child("TELEM:name").text().as_string(); + if (debug) std::cout << " Agregator name: " << aggregatorName << std::endl; + PMTRecord record; + record.uid = guid; + for (pugi::xml_node sampleGroup: aggregatorNode.children("TELEM:SampleGroup")) + { + const auto sampleID = sampleGroup.attribute("sampleID").as_uint(); + if (debug) std::cout << " SampleID: " << sampleID << std::endl; + record.qWordOffset = sampleID; + for (pugi::xml_node sample: sampleGroup.children("TELC:sample")) + { + const auto name = sample.attribute("name").as_string(); + const std::string sampleSubGroup = sample.child("TELC:sampleSubGroup").text().as_string(); + record.fullName = aggregatorName + "." + sampleSubGroup + "." + name; + record.sampleType = sample.child("TELC:sampleType").text().as_string(); + record.lsb = sample.child("TELC:lsb").text().as_uint(); + record.msb = sample.child("TELC:msb").text().as_uint(); + record.description = sample.child("TELC:description").text().as_string(); + if (debug) std::cout << " "; + if (debug) record.print(std::cout); + records.push_back(record); + } + } + + if (debug) std::cout << std::endl; + } + + return true; +#else + (void)pmtXMLPath; // suppress warning + std::cerr << "INFO: pugixml library is not available" << std::endl; + return false; +#endif +} + +std::vector TelemetryDB::lookup(const std::string & name) +{ + std::vector result; + for (auto & record : records) + { + if (record.fullName.find(name) != std::string::npos) + { + result.push_back(record); + } + } + return result; +} + +std::vector TelemetryDB::ilookup(const std::string & name) +{ + std::vector result; + auto to_lower = [](const std::string & s) -> std::string + { + std::string result; + for (auto c : s) + { + result.push_back(std::tolower(c)); + } + return result; + }; + for (auto & record : records) + { + if (to_lower(record.fullName).find(to_lower(name)) != std::string::npos) + { + result.push_back(record); + } + } + return result; +} + + }; // namespace pcm \ No newline at end of file diff --git a/src/pmt.h b/src/pmt.h index d3ccc8ab..71f28103 100644 --- a/src/pmt.h +++ b/src/pmt.h @@ -5,6 +5,7 @@ #include "types.h" #include +#include namespace pcm { @@ -28,10 +29,37 @@ class TelemetryArray : public TelemetryArrayInterface public: TelemetryArray(const size_t /* uid */, const size_t /* instance */); static size_t numInstances(const size_t /* uid */); + static std::vector getUIDs(); virtual ~TelemetryArray() override; size_t size() override; // in bytes void load() override; uint64 get(size_t qWordOffset, size_t lsb, size_t msb) override; }; +class TelemetryDB +{ +public: + struct PMTRecord + { + size_t uid; + std::string fullName; + std::string sampleType; + size_t qWordOffset; + uint32 lsb; + uint32 msb; + std::string description; + void print(std::ostream & os) const + { + os << "uid: " << uid << " fullName: " << fullName << " description: \"" << description << + "\" sampleType: " << sampleType << " qWordOffset: " << qWordOffset << " lsb: " << lsb << " msb: " << msb << std::endl; + } + }; + std::vector records; + TelemetryDB() = default; + bool loadFromXML(const std::string& pmtXMLPath); + virtual ~TelemetryDB() = default; + std::vector lookup(const std::string & name); + std::vector ilookup(const std::string & name); +}; + } // namespace pcm \ No newline at end of file diff --git a/src/pugixml b/src/pugixml new file mode 160000 index 00000000..06318b08 --- /dev/null +++ b/src/pugixml @@ -0,0 +1 @@ +Subproject commit 06318b084a0c1043516acbdae39fdf617fee474c diff --git a/src/simdjson b/src/simdjson index d4bf0cc7..57699bfe 160000 --- a/src/simdjson +++ b/src/simdjson @@ -1 +1 @@ -Subproject commit d4bf0cc7ec12c30c68cb7ed443895df546390283 +Subproject commit 57699bfed894706798c2cefb4d40cc262127595b