diff --git a/doc/ENVVAR_README.md b/doc/ENVVAR_README.md index af285553..58acfa7a 100644 --- a/doc/ENVVAR_README.md +++ b/doc/ENVVAR_README.md @@ -9,3 +9,5 @@ `PCM_PRINT_TOPOLOGY=1` : print detailed CPU topology `PCM_KEEP_NMI_WATCHDOG=1` : don't disable NMI watchdog (reducing the core metrics set) + +`PCM_NO_MAIN_EXCEPTION_HANDLER=1` : don't catch exceptions in the main function of pcm tools (a debugging option) diff --git a/doc/PCM_RAW_README.md b/doc/PCM_RAW_README.md index 0649c9c2..d01facd2 100644 --- a/doc/PCM_RAW_README.md +++ b/doc/PCM_RAW_README.md @@ -77,6 +77,35 @@ pcicfg/config=0xe20,config1=0x180,config2=0x0,width=32,name=CHANERR_INT ``` From: https://www.intel.la/content/dam/www/public/us/en/documents/datasheets/xeon-e7-v2-datasheet-vol-2.pdf +MMIO Registers: + +``` +mmio/config=,config1=,config2=,config3=[,config4=],width=[,name=] +``` + +The MEMBAR is computed by logically ORing the result of membar_bits1 and membar_bits1 computation described below (PCICFG read + bit extraction and shift). The final MMIO register address = MEMBAR + offset. + +* width: register width in bits (16,32,64) +* dev_id: Intel PCI device id where the membar address registers are located +* membar_bits1: mmioBase register bits to compute membar (base address) + - bits 0-15 : PCICFG register offset to read membar1 bits + - bits 16-23: source position of membar bits in the PCICFG register + - bits 24-31: number of bits + - bits 32-39: destination bit position in the membar +* membar_bits2: mmioBase register bits to compute membar (base address), can be zero if only membar_bits1 is sufficient for locating the register. + - bits 0-15 : PCICFG register offset to read membar2 bits + - bits 16-23: source position of membar bits in the PCICFG register + - bits 24-31: number of bits + - bits 32-39: destination bit position in the membar +* offset: offset of the MMIO register relative to the membar +* static_or_freerun: same syntax as for MSR registers + +Example (Icelake server iMC PMON MMIO register read): + +``` +mmio/config=0x3451,config1=0x22808,config2=1,config3=0x171D0000D0,config4=0x0c0b0000d8,width=64 +``` + -------------------------------------------------------------------------------- Collecting Events By Names From Event Lists (https://github.com/intel/perfmon/) -------------------------------------------------------------------------------- diff --git a/src/PMURegisterDeclarations/GenuineIntel-6-4F-1.json b/src/PMURegisterDeclarations/GenuineIntel-6-4F-1.json index e660ba7a..6901131a 100644 --- a/src/PMURegisterDeclarations/GenuineIntel-6-4F-1.json +++ b/src/PMURegisterDeclarations/GenuineIntel-6-4F-1.json @@ -64,7 +64,11 @@ "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0}, "Filter0": {"Config": 1, "Position": 0, "Width": 64, "DefaultValue": 0}, "TID": {"Config": 1, "Position": 0, "Width": 6, "DefaultValue": 0}, - "Filter1": {"Config": 2, "Position": 0, "Width": 64, "DefaultValue": 59} + "State": {"Config": 1, "Position": 17, "Width": 7, "DefaultValue": 0}, + "Filter1": {"Config": 2, "Position": 0, "Width": 64, "DefaultValue": 59}, + "OPC": {"Config": 2, "Position": 20, "Width": 9, "DefaultValue": 0}, + "NC": {"Config": 2, "Position": 30, "Width": 1, "DefaultValue": 0}, + "ISOC": {"Config": 2, "Position": 31, "Width": 1, "DefaultValue": 0} } }, "imc" : { @@ -75,6 +79,21 @@ "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0} } }, + "ha" : { + "programmable" : { + "EventCode": {"Config": 0, "Position": 0, "Width": 8}, + "UMask": {"Config": 0, "Position": 8, "Width": 8}, + "EdgeDetect": {"Config": 0, "Position": 18, "Width": 1, "DefaultValue": 0}, + "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0} + } + }, + "pcu" : { + "programmable" : { + "EventCode": {"Config": 0, "Position": 0, "Width": 8}, + "UMask": {"Config": 0, "Position": 8, "Width": 8}, + "EdgeDetect": {"Config": 0, "Position": 18, "Width": 1, "DefaultValue": 0} + } + }, "xpi" : { "__comment" : "this is for UPI LL and QPI LL uncore PMUs", "programmable" : { diff --git a/src/PMURegisterDeclarations/GenuineIntel-6-55-4.json b/src/PMURegisterDeclarations/GenuineIntel-6-55-4.json index 6a8626e2..2d39fd49 100644 --- a/src/PMURegisterDeclarations/GenuineIntel-6-55-4.json +++ b/src/PMURegisterDeclarations/GenuineIntel-6-55-4.json @@ -100,6 +100,13 @@ "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0} } }, + "pcu" : { + "programmable" : { + "EventCode": {"Config": 0, "Position": 0, "Width": 8}, + "UMask": {"Config": 0, "Position": 8, "Width": 8}, + "EdgeDetect": {"Config": 0, "Position": 18, "Width": 1, "DefaultValue": 0} + } + }, "irp" : { "programmable" : { "EventCode": {"Config": 0, "Position": 0, "Width": 8}, diff --git a/src/PMURegisterDeclarations/GenuineIntel-6-55-7.json b/src/PMURegisterDeclarations/GenuineIntel-6-55-7.json index 6a8626e2..2d39fd49 100644 --- a/src/PMURegisterDeclarations/GenuineIntel-6-55-7.json +++ b/src/PMURegisterDeclarations/GenuineIntel-6-55-7.json @@ -100,6 +100,13 @@ "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0} } }, + "pcu" : { + "programmable" : { + "EventCode": {"Config": 0, "Position": 0, "Width": 8}, + "UMask": {"Config": 0, "Position": 8, "Width": 8}, + "EdgeDetect": {"Config": 0, "Position": 18, "Width": 1, "DefaultValue": 0} + } + }, "irp" : { "programmable" : { "EventCode": {"Config": 0, "Position": 0, "Width": 8}, diff --git a/src/PMURegisterDeclarations/GenuineIntel-6-55-B.json b/src/PMURegisterDeclarations/GenuineIntel-6-55-B.json index 6a8626e2..2d39fd49 100644 --- a/src/PMURegisterDeclarations/GenuineIntel-6-55-B.json +++ b/src/PMURegisterDeclarations/GenuineIntel-6-55-B.json @@ -100,6 +100,13 @@ "Threshold": {"Config": 0, "Position": 24, "Width": 8, "DefaultValue": 0} } }, + "pcu" : { + "programmable" : { + "EventCode": {"Config": 0, "Position": 0, "Width": 8}, + "UMask": {"Config": 0, "Position": 8, "Width": 8}, + "EdgeDetect": {"Config": 0, "Position": 18, "Width": 1, "DefaultValue": 0} + } + }, "irp" : { "programmable" : { "EventCode": {"Config": 0, "Position": 0, "Width": 8}, diff --git a/src/cpucounters.cpp b/src/cpucounters.cpp index 850ef297..0999998d 100644 --- a/src/cpucounters.cpp +++ b/src/cpucounters.cpp @@ -5435,6 +5435,7 @@ PCM::ErrorCode PCM::program(const RawPMUConfigs& curPMUConfigs_, const bool sile threadMSRConfig = RawPMUConfig{}; packageMSRConfig = RawPMUConfig{}; pcicfgConfig = RawPMUConfig{}; + mmioConfig = RawPMUConfig{}; RawPMUConfigs curPMUConfigs = curPMUConfigs_; constexpr auto globalRegPos = 0ULL; PCM::ExtendedCustomCoreEventDescription conf; @@ -5540,9 +5541,9 @@ PCM::ErrorCode PCM::program(const RawPMUConfigs& curPMUConfigs_, const bool sile { continue; } - if (events.programmable.size() > ServerUncoreCounterState::maxCounters) + if (events.programmable.size() > ServerUncoreCounterState::maxCounters && isRegisterEvent(type) == false) { - std::cerr << "ERROR: trying to program " << events.programmable.size() << " core PMU counters, which exceeds the max num possible (" << ServerUncoreCounterState::maxCounters << ")."; + std::cerr << "ERROR: trying to program " << events.programmable.size() << " uncore PMU counters, which exceeds the max num possible (" << ServerUncoreCounterState::maxCounters << ")."; return PCM::UnknownError; } uint32 events32[ServerUncoreCounterState::maxCounters] = { 0,0,0,0,0,0,0,0 }; @@ -5573,6 +5574,13 @@ PCM::ErrorCode PCM::program(const RawPMUConfigs& curPMUConfigs_, const bool sile uncore->programIMC(events32); } } + else if (type == "ha") + { + for (auto& uncore : serverUncorePMUs) + { + uncore->programHA(events32); + } + } else if (type == "m2m") { for (auto& uncore : serverUncorePMUs) @@ -5649,6 +5657,54 @@ PCM::ErrorCode PCM::program(const RawPMUConfigs& curPMUConfigs_, const bool sile addLocations(pcicfgConfig.programmable); addLocations(pcicfgConfig.fixed); } + else if (type == "mmio") + { + mmioConfig = pmuConfig.second; + auto addLocations = [this](const std::vector& configs) { + for (const auto& c : configs) + { + if (MMIORegisterLocations.find(c.first) == MMIORegisterLocations.end()) + { + // add locations + std::vector locations; + const auto deviceID = c.first[MMIOEventPosition::deviceID]; + forAllIntelDevices([&locations, &deviceID, &c](const uint32 group, const uint32 bus, const uint32 device, const uint32 function, const uint32 device_id) + { + if (deviceID == device_id && PciHandleType::exists(group, bus, device, function)) + { + PciHandleType pciHandle(group, bus, device, function); + auto computeBarOffset = [&pciHandle](uint64 membarBits) -> size_t + { + if (membarBits) + { + const auto destPos = extract_bits(membarBits, 32, 39); + const auto numBits = extract_bits(membarBits, 24, 31); + const auto srcPos = extract_bits(membarBits, 16, 23); + const auto pcicfgOffset = extract_bits(membarBits, 0, 15); + uint32 memBarOffset = 0; + pciHandle.read32(pcicfgOffset, &memBarOffset); + return size_t(extract_bits_ui(memBarOffset, srcPos, srcPos + numBits - 1)) << destPos; + } + return 0; + }; + + size_t memBar = computeBarOffset(c.first[MMIOEventPosition::membar_bits1]) + | computeBarOffset(c.first[MMIOEventPosition::membar_bits2]); + + assert(memBar); + + const size_t addr = memBar + c.first[MMIOEventPosition::offset]; + // MMIORange shared ptr (handle), offset + locations.push_back(MMIORegisterEncoding{ std::make_shared(addr & ~4095ULL, 4096), (uint32) (addr & 4095ULL) }); + } + }); + MMIORegisterLocations[c.first] = locations; + } + } + }; + addLocations(mmioConfig.programmable); + addLocations(mmioConfig.fixed); + } else if (type == "cxlcm") { programCXLCM(events64); @@ -6070,6 +6126,50 @@ void PCM::readPCICFGRegisters(SystemCounterState& systemState) } } +void PCM::readMMIORegisters(SystemCounterState& systemState) +{ + auto read = [this, &systemState](const RawEventConfig& cfg) { + const RawEventEncoding& reEnc = cfg.first; + systemState.MMIOValues[reEnc].clear(); + for (auto& reg : MMIORegisterLocations[reEnc]) + { + const auto width = reEnc[MMIOEventPosition::width]; + auto& h = reg.first; + const auto& offset = reg.second; + if (h.get()) + { + uint64 value = ~0ULL; + uint32 value32 = 0; + switch (width) + { + case 16: + value32 = h->read32(offset); + value = (uint64)extract_bits_ui(value32, 0, 15); + break; + case 32: + value32 = h->read32(offset); + value = (uint64)value32; + break; + case 64: + value = h->read64(offset); + break; + default: + std::cerr << "ERROR: Unsupported width " << width << " for mmio register " << cfg.second << "\n"; + } + systemState.MMIOValues[reEnc].push_back(value); + } + } + }; + for (const auto& cfg : mmioConfig.programmable) + { + read(cfg); + } + for (const auto& cfg : mmioConfig.fixed) + { + read(cfg); + } +} + void PCM::readQPICounters(SystemCounterState & result) { // read QPI counters @@ -6274,6 +6374,7 @@ void PCM::getAllCounterStates(SystemCounterState & systemState, std::vectorgetM2MCounter(controller, cnt); + assert(controller < result.HACounter.size()); + for (uint32 cnt = 0; cnt < ServerUncoreCounterState::maxCounters; ++cnt) + result.HACounter[controller][cnt] = serverUncorePMUs[socket]->getHACounter(controller, cnt); } serverUncorePMUs[socket]->unfreezeCounters(); } @@ -8489,6 +8593,11 @@ uint64 ServerUncorePMUs::getPMUCounter(std::vector & pmu, const uint3 return result; } +uint64 ServerUncorePMUs::getHACounter(uint32 id, uint32 counter) +{ + return getPMUCounter(haPMUs, id, counter); +} + uint64 ServerUncorePMUs::getMCCounter(uint32 channel, uint32 counter) { return getPMUCounter(imcPMUs, channel, counter); @@ -8907,7 +9016,7 @@ uint32 PCM::getMaxNumOfCBoxes() const switch (cpu_model) { case SPR: - { + try { PciHandleType * h = getDeviceHandle(PCM_INTEL_PCI_VENDOR_ID, 0x325b); if (h) { @@ -8919,6 +9028,10 @@ uint32 PCM::getMaxNumOfCBoxes() const delete h; } } + catch (std::exception& e) + { + std::cerr << "Warning: reading the number of CHA from PCICFG register has failed: " << e.what() << "\n"; + } break; case KNL: case SKX: diff --git a/src/cpucounters.h b/src/cpucounters.h index 0da43604..9d89a356 100644 --- a/src/cpucounters.h +++ b/src/cpucounters.h @@ -510,6 +510,10 @@ class ServerUncorePMUs //! \param box box ID/number //! \param counter counter number uint64 getM2MCounter(uint32 box, uint32 counter); + //! \brief Direct read of HA counter + //! \param box box ID/number + //! \param counter counter number + uint64 getHACounter(uint32 box, uint32 counter); //! \brief Freezes event counting void freezeCounters(); @@ -1015,6 +1019,7 @@ class PCM_API PCM void readMSRs(std::shared_ptr msr, const RawPMUConfig & msrConfig, CounterStateType & result); void readQPICounters(SystemCounterState & counterState); void readPCICFGRegisters(SystemCounterState& result); + void readMMIORegisters(SystemCounterState& result); void reportQPISpeed() const; void readCoreCounterConfig(const bool complainAboutMSR = false); void readCPUMicrocodeLevel(); @@ -1323,8 +1328,40 @@ class PCM_API PCM && a[PCICFGEventPosition::width] == b[PCICFGEventPosition::width]; } }; + struct MMIOEventPosition + { + enum constants + { + deviceID = PCICFGEventPosition::deviceID, + offset = PCICFGEventPosition::offset, + type = PCICFGEventPosition::type, + membar_bits1 = 3, + membar_bits2 = 4, + width = PCICFGEventPosition::width + }; + }; + typedef std::pair, uint32> MMIORegisterEncoding; // MMIORange shared ptr, offset + struct MMIORegisterEncodingHash : public PCICFGRegisterEncodingHash + { + std::size_t operator()(const RawEventEncoding& e) const + { + std::size_t h4 = std::hash{}(e[MMIOEventPosition::membar_bits1]); + std::size_t h5 = std::hash{}(e[MMIOEventPosition::membar_bits2]); + return PCICFGRegisterEncodingHash::operator()(e) ^ (h4 << 3ULL) ^ (h5 << 4ULL); + } + }; + struct MMIORegisterEncodingCmp : public PCICFGRegisterEncodingCmp + { + bool operator ()(const RawEventEncoding& a, const RawEventEncoding& b) const + { + return PCICFGRegisterEncodingCmp::operator()(a,b) + && a[MMIOEventPosition::membar_bits1] == b[MMIOEventPosition::membar_bits1] + && a[MMIOEventPosition::membar_bits2] == b[MMIOEventPosition::membar_bits2]; + } + }; private: std::unordered_map, PCICFGRegisterEncodingHash, PCICFGRegisterEncodingCmp> PCICFGRegisterLocations{}; + std::unordered_map, MMIORegisterEncodingHash, MMIORegisterEncodingCmp> MMIORegisterLocations{}; public: TopologyEntry::CoreType getCoreType(const unsigned coreID) const @@ -1589,7 +1626,7 @@ class PCM_API PCM } return false; } - RawPMUConfig threadMSRConfig{}, packageMSRConfig{}, pcicfgConfig{}; + RawPMUConfig threadMSRConfig{}, packageMSRConfig{}, pcicfgConfig{}, mmioConfig{}; public: //! \brief Reads CPU model id @@ -2844,6 +2881,17 @@ uint64 getM2MCounter(uint32 controller, uint32 counter, const CounterStateType & return after.M2MCounter[controller][counter] - before.M2MCounter[controller][counter]; } +/*! \brief Direct read of HA controller PMU counter (counter meaning depends on the programming: power/performance/etc) + \param counter counter number + \param controller controller number + \param before CPU counter state before the experiment + \param after CPU counter state after the experiment +*/ +template +uint64 getHACounter(uint32 controller, uint32 counter, const CounterStateType & before, const CounterStateType & after) +{ + return after.HACounter[controller][counter] - before.HACounter[controller][counter]; +} /*! \brief Direct read of embedded DRAM memory controller counter (counter meaning depends on the programming: power/performance/etc) \param counter counter number @@ -3135,6 +3183,7 @@ class ServerUncoreCounterState : public UncoreCounterState std::array HBMClocks; std::array, maxChannels> MCCounter; // channel X counter std::array, maxControllers> M2MCounter; // M2M/iMC boxes x counter + std::array, maxControllers> HACounter; // HA boxes x counter std::array, maxChannels> EDCCounter; // EDC controller X counter std::array PCUCounter; std::unordered_map freeRunningCounter; @@ -3168,6 +3217,8 @@ class ServerUncoreCounterState : public UncoreCounterState template friend uint64 getM2MCounter(uint32 controller, uint32 counter, const CounterStateType & before, const CounterStateType & after); template + friend uint64 getHACounter(uint32 controller, uint32 counter, const CounterStateType & before, const CounterStateType & after); + template friend uint64 getEDCCounter(uint32 channel, uint32 counter, const CounterStateType & before, const CounterStateType & after); template friend uint64 getPCUCounter(uint32 counter, const CounterStateType & before, const CounterStateType & after); @@ -3199,6 +3250,7 @@ class ServerUncoreCounterState : public UncoreCounterState HBMClocks{{}}, MCCounter{{}}, M2MCounter{{}}, + HACounter{{}}, EDCCounter{{}}, PCUCounter{{}}, PackageThermalHeadroom(0), @@ -3298,12 +3350,14 @@ class SystemCounterState : public SocketCounterState { friend class PCM; friend std::vector getPCICFGEvent(const PCM::RawEventEncoding& eventEnc, const SystemCounterState& before, const SystemCounterState& after); + friend std::vector getMMIOEvent(const PCM::RawEventEncoding& eventEnc, const SystemCounterState& before, const SystemCounterState& after); std::vector > incomingQPIPackets; // each 64 byte std::vector > outgoingQPIFlits; // idle or data/non-data flits depending on the architecture std::vector > TxL0Cycles; uint64 uncoreTSC; std::unordered_map , PCM::PCICFGRegisterEncodingHash, PCM::PCICFGRegisterEncodingCmp> PCICFGValues{}; + std::unordered_map, PCM::MMIORegisterEncodingHash, PCM::MMIORegisterEncodingCmp> MMIOValues{}; protected: void readAndAggregate(std::shared_ptr handle) @@ -4356,6 +4410,12 @@ inline double getLocalMemoryRequestRatio(const CounterStateType & before, const template inline uint64 getNumberOfEvents(const CounterType & before, const CounterType & after) { + // prevent overflows due to counter dissynchronisation + if (after.data < before.data) + { + return 0; + } + return after.data - before.data; } //! \brief Returns average last level cache read+prefetch miss latency in ns @@ -4434,13 +4494,14 @@ inline double getRetiring(const CounterStateType & before, const CounterStateTyp return 0.; } -inline std::vector getPCICFGEvent(const PCM::RawEventEncoding & eventEnc, const SystemCounterState& before, const SystemCounterState& after) +template +inline std::vector getRegisterEvent(const PCM::RawEventEncoding& eventEnc, const ValuesType& beforeValues, const ValuesType& afterValues) { std::vector result{}; - auto beforeIter = before.PCICFGValues.find(eventEnc); - auto afterIter = after.PCICFGValues.find(eventEnc); - if (beforeIter != before.PCICFGValues.end() && - afterIter != after.PCICFGValues.end()) + auto beforeIter = beforeValues.find(eventEnc); + auto afterIter = afterValues.find(eventEnc); + if (beforeIter != beforeValues.end() && + afterIter != afterValues.end()) { const auto& beforeValues = beforeIter->second; const auto& afterValues = afterIter->second; @@ -4462,6 +4523,16 @@ inline std::vector getPCICFGEvent(const PCM::RawEventEncoding & eventEnc return result; } +inline std::vector getPCICFGEvent(const PCM::RawEventEncoding & eventEnc, const SystemCounterState& before, const SystemCounterState& after) +{ + return getRegisterEvent(eventEnc, before.PCICFGValues, after.PCICFGValues); +} + +inline std::vector getMMIOEvent(const PCM::RawEventEncoding& eventEnc, const SystemCounterState& before, const SystemCounterState& after) +{ + return getRegisterEvent(eventEnc, before.MMIOValues, after.MMIOValues); +} + template uint64 getMSREvent(const uint64& index, const PCM::MSRType& type, const CounterStateType& before, const CounterStateType& after) { diff --git a/src/pci.cpp b/src/pci.cpp index b65fac1f..3afcbbfd 100644 --- a/src/pci.cpp +++ b/src/pci.cpp @@ -580,8 +580,10 @@ void PciHandleMM::readMCFG() if (read_bytes == 0) { ::close(mcfg_handle); - std::cerr << "PCM Error: Cannot read MCFG-table\n"; - throw std::exception(); + const auto msg = "PCM Error: Cannot read MCFG-table"; + std::cerr << msg; + std::cerr << "\n"; + throw std::runtime_error(msg); } const unsigned segments = mcfgHeader.nrecords(); @@ -597,8 +599,10 @@ void PciHandleMM::readMCFG() if (read_bytes == 0) { ::close(mcfg_handle); - std::cerr << "PCM Error: Cannot read MCFG-table (2)\n"; - throw std::exception(); + const auto msg = "PCM Error: Cannot read MCFG-table (2)"; + std::cerr << msg; + std::cerr << "\n"; + throw std::runtime_error(msg); } #ifdef PCM_DEBUG std::cout << "PCM Debug: segment " << std::dec << i << " "; diff --git a/src/pcm-raw.cpp b/src/pcm-raw.cpp index d8ba2493..e47fe39a 100644 --- a/src/pcm-raw.cpp +++ b/src/pcm-raw.cpp @@ -132,6 +132,10 @@ enum AddEventStatus bool tooManyEvents(const std::string & pmuName, const int event_pos, const std::string& fullEventStr) { + if (isRegisterEvent(pmuName)) + { + return false; + } PCM* m = PCM::getInstance(); assert(m); const int maxCounters = (pmuName == "core" || pmuName == "atom") ? m->getMaxCustomCoreEvents() : ServerUncoreCounterState::maxCounters; @@ -756,6 +760,8 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven std::regex CounterMaskRegex("c(0x[0-9a-fA-F]+|[[:digit:]]+)"); std::regex UmaskRegex("u(0x[0-9a-fA-F]+|[[:digit:]]+)"); std::regex EdgeDetectRegex("e(0x[0-9a-fA-F]+|[[:digit:]]+)"); + std::regex AnyThreadRegex("amt(0x[0-9a-fA-F]+|[[:digit:]]+)"); + std::regex InvertRegex("i(0x[0-9a-fA-F]+|[[:digit:]]+)"); while (mod != EventTokens.end()) { const auto assignment = split(*mod, '='); @@ -798,6 +804,18 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven const std::string Str{ mod->begin() + 1, mod->end() }; setField("EdgeDetect", read_number(Str.c_str())); } + else if (std::regex_match(mod->c_str(), AnyThreadRegex)) + { + // AnyThread modifier + const std::string Str{ mod->begin() + 1, mod->end() }; + setField("AnyThread", read_number(Str.c_str())); + } + else if (std::regex_match(mod->c_str(), InvertRegex)) + { + // Invert modifier + const std::string Str{ mod->begin() + 1, mod->end() }; + setField("Invert", read_number(Str.c_str())); + } else if (std::regex_match(mod->c_str(), UmaskRegex)) { // UMask modifier @@ -822,6 +840,22 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven { setField("Filter1", read_number(assignment[1].c_str())); } + else if (assignment.size() == 2 && assignment[0] == "opc") + { + setField("OPC", read_number(assignment[1].c_str())); + } + else if (assignment.size() == 2 && assignment[0] == "nc") + { + setField("NC", read_number(assignment[1].c_str())); + } + else if (assignment.size() == 2 && assignment[0] == "isoc") + { + setField("ISOC", read_number(assignment[1].c_str())); + } + else if (assignment.size() == 2 && assignment[0] == "state") + { + setField("State", read_number(assignment[1].c_str())); + } else if (assignment.size() == 2 && assignment[0] == "t") { setField("Threshold", read_number(assignment[1].c_str())); @@ -1179,6 +1213,22 @@ std::string getPCICFGEventString(const PCM::RawEventEncoding & eventEnc, const s return c.str(); } +std::string getMMIOEventString(const PCM::RawEventEncoding& eventEnc, const std::string& type) +{ + std::stringstream c; + c << type << ":0x" << std::hex << + eventEnc[PCM::MMIOEventPosition::deviceID] << + ":0x" << eventEnc[PCM::MMIOEventPosition::offset] << + ":0x" << eventEnc[PCM::MMIOEventPosition::membar_bits1] << + ":0x" << eventEnc[PCM::MMIOEventPosition::membar_bits2] << + ":0x" << eventEnc[PCM::MMIOEventPosition::width] << + ":" << getTypeString(eventEnc[PCM::MMIOEventPosition::type]); + return c.str(); +} + +typedef std::string(*getEventStringFunc)(const PCM::RawEventEncoding& eventEnc, const std::string& type); +typedef std::vector(getEventFunc)(const PCM::RawEventEncoding& eventEnc, const SystemCounterState& before, const SystemCounterState& after); + enum MSRScope { Thread, @@ -1462,28 +1512,12 @@ void printTransposed(const PCM::RawPMUConfigs& curPMUConfigs, is_header_printed = true; } }; - if (type == "core") - { - printCores(pcm::TopologyEntry::Core); - } - else if (type == "atom") - { - printCores(pcm::TopologyEntry::Atom); - } - else if (type == "thread_msr") - { - printMSRRows(MSRScope::Thread); - } - else if (type == "package_msr") - { - printMSRRows(MSRScope::Package); - } - else if (type == "pcicfg") + auto printRegisterRows = [&](getEventStringFunc getEventString, getEventFunc getEvent) { auto printRegister = [&](const PCM::RawEventConfig& event) -> bool { - const std::string name = (event.second.empty()) ? getPCICFGEventString(event.first, type) : event.second; - const auto values = getPCICFGEvent(event.first, SysBeforeState, SysAfterState); + const std::string name = (event.second.empty()) ? getEventString(event.first, type) : event.second; + const auto values = getEvent(event.first, SysBeforeState, SysAfterState); if (is_header && is_header_printed) return false; @@ -1541,6 +1575,30 @@ void printTransposed(const PCM::RawPMUConfigs& curPMUConfigs, break; } } + }; + if (type == "core") + { + printCores(pcm::TopologyEntry::Core); + } + else if (type == "atom") + { + printCores(pcm::TopologyEntry::Atom); + } + else if (type == "thread_msr") + { + printMSRRows(MSRScope::Thread); + } + else if (type == "package_msr") + { + printMSRRows(MSRScope::Package); + } + else if (type == "pcicfg") + { + printRegisterRows(getPCICFGEventString, getPCICFGEvent); + } + else if (type == "mmio") + { + printRegisterRows(getMMIOEventString, getMMIOEvent); } else if (type == "m3upi") { @@ -1560,11 +1618,12 @@ void printTransposed(const PCM::RawPMUConfigs& curPMUConfigs, } else if (type == "imc") { + const std::string fixedEventName = (fixedEvents.empty() == false && fixedEvents[0].second.empty() == false) ? fixedEvents[0].second : "DRAMClocks"; choose(outputType, [&]() { printUncoreRows(nullptr, (uint32) m->getMCChannelsPerSocket(), "CHAN"); }, [&]() { printUncoreRows(nullptr, (uint32) m->getMCChannelsPerSocket(), type); }, [&]() { printUncoreRows([](const uint32 u, const uint32 i, const ServerUncoreCounterState& before, const ServerUncoreCounterState& after) { return getMCCounter(u, i, before, after); }, (uint32)m->getMCChannelsPerSocket(), - "DRAMClocks", [](const uint32 u, const ServerUncoreCounterState& before, const ServerUncoreCounterState& after) { return getDRAMClocks(u, before, after); }); + fixedEventName, [](const uint32 u, const ServerUncoreCounterState& before, const ServerUncoreCounterState& after) { return getDRAMClocks(u, before, after); }); }); } else if (type == "m2m") @@ -1575,6 +1634,14 @@ void printTransposed(const PCM::RawPMUConfigs& curPMUConfigs, [&]() { printUncoreRows([](const uint32 u, const uint32 i, const ServerUncoreCounterState& before, const ServerUncoreCounterState& after) { return getM2MCounter(u, i, before, after); }, (uint32)m->getMCPerSocket(), "MC"); }); } + else if (type == "ha") + { + choose(outputType, + [&]() { printUncoreRows(nullptr, (uint32) m->getMCPerSocket(), "HA"); }, + [&]() { printUncoreRows(nullptr, (uint32) m->getMCPerSocket(), type); }, + [&]() { printUncoreRows([](const uint32 u, const uint32 i, const ServerUncoreCounterState& before, const ServerUncoreCounterState& after) { return getHACounter(u, i, before, after); }, (uint32)m->getMCPerSocket(), "HA"); + }); + } else if (type == "pcu") { choose(outputType, @@ -1738,6 +1805,28 @@ void print(const PCM::RawPMUConfigs& curPMUConfigs, } } }; + auto printRegisters = [&](getEventStringFunc getEventString, getEventFunc getEvent) + { + auto printOneRegister = [&](const PCM::RawEventConfig& event) + { + const auto values = getEvent(event.first, SysBeforeState, SysAfterState); + for (size_t r = 0; r < values.size(); ++r) + { + choose(outputType, + [&r]() { cout << "SYSTEM_" << r << separator; }, + [&]() { if (event.second.empty()) cout << getEventString(event.first, type) << separator; else cout << event.second << separator; }, + [&]() { cout << values[r] << separator; }); + } + }; + for (const auto& event : events) + { + printOneRegister(event); + } + for (const auto& event : fixedEvents) + { + printOneRegister(event); + } + }; if (type == "core") { printCores(pcm::TopologyEntry::Core); @@ -1825,6 +1914,24 @@ void print(const PCM::RawPMUConfigs& curPMUConfigs, } } } + else if (type == "ha") + { + for (uint32 s = 0; s < m->getNumSockets(); ++s) + { + for (uint32 mc = 0; mc < m->getMCPerSocket(); ++mc) + { + int i = 0; + for (auto& event : events) + { + choose(outputType, + [s, mc]() { cout << "SKT" << s << "HA" << mc << separator; }, + [&event, &i]() { if (event.second.empty()) cout << "HAEvent" << i << separator; else cout << event.second << separator; }, + [&]() { cout << getHACounter(mc, i, BeforeUncoreState[s], AfterUncoreState[s]) << separator; }); + ++i; + } + } + } + } else if (type == "pcu") { for (uint32 s = 0; s < m->getNumSockets(); ++s) @@ -1888,25 +1995,11 @@ void print(const PCM::RawPMUConfigs& curPMUConfigs, } else if (type == "pcicfg") { - auto printPCICFG = [&](const PCM::RawEventConfig& event) - { - const auto values = getPCICFGEvent(event.first, SysBeforeState, SysAfterState); - for (size_t r = 0; r < values.size(); ++r) - { - choose(outputType, - [&r]() { cout << "SYSTEM_" << r << separator; }, - [&]() { if (event.second.empty()) cout << getPCICFGEventString(event.first, type) << separator; else cout << event.second << separator; }, - [&]() { cout << values[r] << separator; }); - } - }; - for (const auto& event : events) - { - printPCICFG(event); - } - for (const auto& event : fixedEvents) - { - printPCICFG(event); - } + printRegisters(getPCICFGEventString, getPCICFGEvent); + } + else if (type == "mmio") + { + printRegisters(getMMIOEventString, getMMIOEvent); } else if (type == "ubox") { diff --git a/src/utils.cpp b/src/utils.cpp index b8418c18..5bfe3318 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -838,6 +838,18 @@ std::string dos2unix(std::string in) return in; } +bool isRegisterEvent(const std::string & pmu) +{ + if (pmu == "mmio" + || pmu == "pcicfg" + || pmu == "package_msr" + || pmu == "thread_msr") + { + return true; + } + return false; +} + std::string a_title(const std::string &init, const std::string &name) { char begin = init[0]; std::string row = init; diff --git a/src/utils.h b/src/utils.h index 5c810dbc..e4779467 100644 --- a/src/utils.h +++ b/src/utils.h @@ -29,10 +29,16 @@ #include #include + +namespace pcm { + std::string safe_getenv(const char* env); +} + #define PCM_MAIN_NOTHROW \ int mainThrows(int argc, char * argv[]); \ int main(int argc, char * argv[]) \ { \ + if (pcm::safe_getenv("PCM_NO_MAIN_EXCEPTION_HANDLER") == std::string("1")) return mainThrows(argc, argv); \ try { \ return mainThrows(argc, argv); \ } catch(const std::runtime_error & e) \ @@ -521,8 +527,6 @@ inline uint64 extract_bits(uint64 myin, uint32 beg, uint32 end) return myll; } -std::string safe_getenv(const char* env); - #ifdef _MSC_VER inline HANDLE openMSRDriver() { @@ -574,7 +578,7 @@ typedef enum{ }evt_cb_type; std::string dos2unix(std::string in); - +bool isRegisterEvent(const std::string & pmu); std::string a_title (const std::string &init, const std::string &name); std::string a_data (std::string init, struct data d); std::string a_header_footer(std::string init, std::string name); diff --git a/tests/test.sh b/tests/test.sh index 60f22ec6..e5124075 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -319,6 +319,7 @@ UNC_UPI_TxL0P_POWER_CYCLES UNC_UPI_RxL0P_POWER_CYCLES UNC_UPI_RxL_FLITS.ALL_DATA UNC_UPI_RxL_FLITS.NON_DATA +UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES MSR_EVENT:msr=0x10:type=FREERUN:scope=thread MSR_EVENT:msr=0x10:type=static:scope=thread pcicfg/config=0x2021,config1=4,config2=0,width=32