diff --git a/doc/PCM_RAW_README.md b/doc/PCM_RAW_README.md index 4288c368..585e0b35 100644 --- a/doc/PCM_RAW_README.md +++ b/doc/PCM_RAW_README.md @@ -214,6 +214,12 @@ Sample csv output (date,time,event_name,milliseconds_between_samples,TSC_cycles_ ``` The unit can be logical core, memory channel, CHA, etc, depending on the event type. + +Show events available for the processor on the system: +``` +pcm-raw -? +``` + -------------------------------------------------------------------------------- Low-level access to Intel PMT telemetry data -------------------------------------------------------------------------------- diff --git a/doc/WINDOWS_HOWTO.md b/doc/WINDOWS_HOWTO.md index 1ac274ca..d42a8cef 100644 --- a/doc/WINDOWS_HOWTO.md +++ b/doc/WINDOWS_HOWTO.md @@ -4,7 +4,7 @@ _For support of systems with more than _**_64_**_ logical cores you need to comp ## Command-line utility -1. Follow [Compile the windows MSR driver](#compile-the-windows-msr-driver) to compile the windows MSR driver (msr.sys). For Windows 7 and later versions you have to sign the msr.sys driver additionally ([http://msdn.microsoft.com/en-us/library/ms537361(VS.85).aspx](http://msdn.microsoft.com/en-us/library/ms537361(VS.85).aspx)). To enable loading test signed drivers on the system: in administrator cmd console run `bcdedit /set testsigning on` and reboot. +1. Follow [Compile the Windows MSR driver](#compile-the-windows-msr-driver) to compile the Windows MSR driver (msr.sys). For Windows 7 and later versions you have to sign the msr.sys driver additionally ([http://msdn.microsoft.com/en-us/library/ms537361(VS.85).aspx](http://msdn.microsoft.com/en-us/library/ms537361(VS.85).aspx)). To enable loading test-signed drivers on the system: in administrator cmd console run `bcdedit /set testsigning on` and reboot. 2. Build the *pcm.exe* utility: ``` @@ -17,7 +17,7 @@ _For support of systems with more than _**_64_**_ logical cores you need to comp 4. As Administrator copy the msr.sys driver and pcm.exe into the PCM directory 5. Run pcm.exe utility from the PCM directory as Administrator -For Windows 7+ and Windows Server 2008+ R2 the PCM utilities need to be run as administrator: +For Windows 7+ and Windows Server 2008+ R2 the PCM utilities need to be run as Administrator: Alternatively you can achieve the same using the “Properties” Windows menu of the executable (“Privilege level” setting in the “Compatibility” tab): Right mouse click -> Properties -> Compatibility -> Privilege level -> Set “Run this program as an administrator”. @@ -47,13 +47,14 @@ Unhandled Exception: System.NotSupportedException: This method implicitly uses C 8. Start perfmon and find new PCM\* counters -If you do not want or cannot compile the msr.sys driver you might use a third-party open source WinRing0 driver instead. Instructions: +If you do not want or cannot compile the msr.sys driver you might use a third-party open source WinRing0 driver instead (experimental only, for testing environments only). +Instructions: 1. Download the free RealTemp utility package from [http://www.techpowerup.com/realtemp/](http://www.techpowerup.com/realtemp/) or any other free utility that uses the open-source WinRing0 driver (like OpenHardwareMonitor [http://code.google.com/p/open-hardware-monitor/downloads/list](http://code.google.com/p/open-hardware-monitor/downloads/list)). 2. Copy WinRing0.dll, WinRing0.sys, WinRing0x64.dll, WinRing0x64.sys files from there into the PCM.exe binary location, into the PCM-Service.exe location and into c:\windows\system32 3. Run the PCM.exe tool and/or go to step 6 (perfmon utility). -## Compile the windows MSR driver +## Compile the Windows MSR driver 1. Download Visual Studio ([Visual Studio download](https://visualstudio.microsoft.com/downloads/)). When you install Visual Studio, also install related packages: diff --git a/perfmon b/perfmon index 2336912d..59d0e1ff 160000 --- a/perfmon +++ b/perfmon @@ -1 +1 @@ -Subproject commit 2336912dd4f4f8f5313914dc30e4f1e87429ab5b +Subproject commit 59d0e1fff3106c424f6e49eea460ac14220dae76 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e83434cf..4cf1a82a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,12 +8,12 @@ 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 ${PCM_PUGIXML_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-iio-pmu.cpp lspci.cpp ${PCM_PUGIXML_CPP}) if (APPLE) - file(GLOB UNUX_SOURCES dashboard.cpp) + file(GLOB UNIX_SOURCES dashboard.cpp) else() - file(GLOB UNUX_SOURCES dashboard.cpp resctrl.cpp) + file(GLOB UNIX_SOURCES dashboard.cpp resctrl.cpp) endif() if (LINUX) @@ -49,11 +49,11 @@ if(UNIX) # LINUX, FREE_BSD, APPLE list(APPEND PROJECT_NAMES pcm-sensor) # libpcm.a - add_library(PCM_STATIC STATIC ${COMMON_SOURCES} ${UNUX_SOURCES}) + add_library(PCM_STATIC STATIC ${COMMON_SOURCES} ${UNIX_SOURCES}) set_target_properties(PCM_STATIC PROPERTIES OUTPUT_NAME pcm) # libpcm.a with -DPCM_SILENT for Release* - add_library(PCM_STATIC_SILENT STATIC ${COMMON_SOURCES} ${UNUX_SOURCES}) + add_library(PCM_STATIC_SILENT STATIC ${COMMON_SOURCES} ${UNIX_SOURCES}) target_compile_definitions(PCM_STATIC_SILENT PRIVATE $<$:PCM_SILENT> $<$:PCM_SILENT> diff --git a/src/cpucounters.cpp b/src/cpucounters.cpp index 775f124a..54aab939 100644 --- a/src/cpucounters.cpp +++ b/src/cpucounters.cpp @@ -2652,7 +2652,7 @@ void PCM::initUncorePMUsDirect() std::vector > socket2QATbus; std::map rootbusMap; - //Enumurate IDX devices by PCIe bus scan + //Enumerate IDX devices by PCIe bus scan initSocket2Bus(socket2IAAbus, SPR_IDX_IAA_REGISTER_DEV_ADDR, SPR_IDX_IAA_REGISTER_FUNC_ADDR, IAA_DEV_IDS, (uint32)sizeof(IAA_DEV_IDS) / sizeof(IAA_DEV_IDS[0])); initSocket2Bus(socket2DSAbus, SPR_IDX_DSA_REGISTER_DEV_ADDR, SPR_IDX_DSA_REGISTER_FUNC_ADDR, DSA_DEV_IDS, (uint32)sizeof(DSA_DEV_IDS) / sizeof(DSA_DEV_IDS[0])); initSocket2Bus(socket2QATbus, SPR_IDX_QAT_REGISTER_DEV_ADDR, SPR_IDX_QAT_REGISTER_FUNC_ADDR, QAT_DEV_IDS, (uint32)sizeof(QAT_DEV_IDS) / sizeof(QAT_DEV_IDS[0])); @@ -4192,10 +4192,18 @@ PCM::ErrorCode PCM::programCoreCounters(const int i /* core */, if (EXT_CUSTOM_CORE_EVENTS == mode_ && pExtDesc) { - if (pExtDesc->OffcoreResponseMsrValue[0]) // still need to do also if perf API is used due to a bug in perf + if (pExtDesc->OffcoreResponseMsrValue[0]) // still need to do also if perf API is used due to a bug in perf in some kernels + { + DBG(3, "programming offcore response 0x", std::hex , pExtDesc->OffcoreResponseMsrValue[0] , + " into MSR 0x" , MSR_OFFCORE_RSP0 , std::dec , " for core ", i); MSR[i]->write(MSR_OFFCORE_RSP0, pExtDesc->OffcoreResponseMsrValue[0]); + } if (pExtDesc->OffcoreResponseMsrValue[1]) + { + DBG(3, "programming offcore response 0x", std::hex , pExtDesc->OffcoreResponseMsrValue[1] , + " into MSR 0x" , MSR_OFFCORE_RSP1 , std::dec , " for core ", i); MSR[i]->write(MSR_OFFCORE_RSP1, pExtDesc->OffcoreResponseMsrValue[1]); + } if (pExtDesc->LoadLatencyMsrValue != ExtendedCustomCoreEventDescription::invalidMsrValue()) { @@ -4268,9 +4276,19 @@ PCM::ErrorCode PCM::programCoreCounters(const int i /* core */, if (pExtDesc != nullptr) { if (event_select_reg.fields.event_select == getOCREventNr(0, i).first && event_select_reg.fields.umask == getOCREventNr(0, i).second) + { + DBG(3, "writing offcore response 0x", std::hex , pExtDesc->OffcoreResponseMsrValue[0] , + " into perf config1 for core ", std::dec , i, std::hex ," event 0x", event_select_reg.fields.event_select, " umask 0x", event_select_reg.fields.umask , + " on counter ", std::dec , j); e.config1 = pExtDesc->OffcoreResponseMsrValue[0]; + } if (event_select_reg.fields.event_select == getOCREventNr(1, i).first && event_select_reg.fields.umask == getOCREventNr(1, i).second) + { + DBG(3, "writing offcore response 0x", std::hex , pExtDesc->OffcoreResponseMsrValue[1] , + " into perf config1 for core ", std::dec , i, std::hex , " event 0x", event_select_reg.fields.event_select, " umask 0x", event_select_reg.fields.umask , + " on counter ", std::dec , j); e.config1 = pExtDesc->OffcoreResponseMsrValue[1]; + } if (event_select_reg.fields.event_select == LOAD_LATENCY_EVTNR && event_select_reg.fields.umask == LOAD_LATENCY_UMASK) { diff --git a/src/cpucounters.h b/src/cpucounters.h index 18669ec6..deae6eb7 100644 --- a/src/cpucounters.h +++ b/src/cpucounters.h @@ -1666,6 +1666,7 @@ class PCM_API PCM std::pair getOCREventNr(const int event, const unsigned coreID) const { assert (coreID < topology.size()); + const auto eCoreOCREvent = std::make_pair(OFFCORE_RESPONSE_0_EVTNR, event + 1); if (hybrid) { switch (cpu_family_model) @@ -1677,7 +1678,7 @@ class PCM_API PCM case ARL: if (topology[coreID].core_type == TopologyEntry::Atom) { - return std::make_pair(OFFCORE_RESPONSE_0_EVTNR, event + 1); + return eCoreOCREvent; } break; } @@ -1688,6 +1689,7 @@ class PCM_API PCM case SPR: case EMR: case GNR: + case GNR_D: case ADL: // ADL big core (GLC) case RPL: case MTL: @@ -1695,6 +1697,22 @@ class PCM_API PCM case ARL: useGLCOCREvent = true; break; + + case ATOM: + case ATOM_2: + case CENTERTON: + case BAYTRAIL: + case AVOTON: + case CHERRYTRAIL: + case APOLLO_LAKE: + case GEMINI_LAKE: + case DENVERTON: + case SNOWRIDGE: + case ELKHART_LAKE: + case JASPER_LAKE: + case SRF: + case GRR: + return eCoreOCREvent; } switch (event) { diff --git a/src/lspci.cpp b/src/lspci.cpp new file mode 100644 index 00000000..848c357c --- /dev/null +++ b/src/lspci.cpp @@ -0,0 +1,167 @@ +#include "lspci.h" + +namespace pcm { + +const ccr_config ccr::skx_ccrs(44, 0xFFULL); +const ccr_config ccr::icx_ccrs(48, 0xFFFULL); + +bool operator<(const iio_stack& lh, const iio_stack& rh) +{ + return lh.iio_unit_id < rh.iio_unit_id; +} + +bool operator<(const bdf &l, const bdf &r) { + if (l.domainno < r.domainno) + return true; + if (l.domainno > r.domainno) + return false; + if (l.busno < r.busno) + return true; + if (l.busno > r.busno) + return false; + if (l.devno < r.devno) + return true; + if (l.devno > r.devno) + return false; + if (l.funcno < r.funcno) + return true; + if (l.funcno > r.funcno) + return false; + + return false; // bdf == bdf +} + +void probe_capability_pci_express(struct pci *p, uint32_t cap_ptr) +{ + struct cap { + union { + struct { + uint8_t id; + union { + uint8_t next; + uint8_t cap_ptr; + }; + uint16_t junk; + }; + uint32 dw0; + }; + } cap; + uint32 value; + PciHandleType h(0, p->bdf.busno, p->bdf.devno, p->bdf.funcno); + h.read32(cap_ptr, &value); //Capability pointer + cap.dw0 = value; + if (cap.id != 0x10 && cap.next != 0x00) { + probe_capability_pci_express(p, cap.cap_ptr); + } else { + if (cap.id == 0x10) { // We're in PCI express capability structure + h.read32(cap_ptr+0x10, &value); + p->link_info = value; + } else { /*Finish recursive searching but cannot find PCI express capability structure*/ } + } +} + +bool probe_pci(struct pci *p) +{ + uint32 value; + p->exist = false; + struct bdf *bdf = &p->bdf; + if (PciHandleType::exists(bdf->domainno, bdf->busno, bdf->devno, bdf->funcno)) { + PciHandleType h(bdf->domainno, bdf->busno, bdf->devno, bdf->funcno); + // VID:DID + h.read32(0x0, &value); + // Invalid VID::DID + if (value != (std::numeric_limits::max)()) { + p->offset_0 = value; + h.read32(0xc, &value); + p->header_type = (value >> 16) & 0x7f; + if (p->header_type == 0) { + // Status register + h.read32(0x4, &value); + // Capability list == true + if (value & 0x100000) { + // Capability pointer + h.read32(0x34, &value); + probe_capability_pci_express(p, value); + } + } else if (p->header_type == 1) { + h.read32(0x18, &value); + p->offset_18 = value; + } + p->exist = true; + } + } + + return p->exist; +} + +void print_pci(struct pci p, const PCIDB & pciDB) +{ + printf("Parent bridge info:"); + printf("%x:%x.%d [%04x:%04x] %s %s %d P:%x S:%x S:%x ", + p.bdf.busno, p.bdf.devno, p.bdf.funcno, + p.vendor_id, p.device_id, + (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", + (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device", + p.header_type, + p.primary_bus_number, p.secondary_bus_number, p.subordinate_bus_number); + printf("Device info:"); + printf("%x:%x.%d [%04x:%04x] %s %s %d Gen%d x%d\n", + p.bdf.busno, p.bdf.devno, p.bdf.funcno, + p.vendor_id, p.device_id, + (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", + (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device", + p.header_type, + p.link_speed, p.link_width); +} + +void load_PCIDB(PCIDB & pciDB) +{ + std::ifstream in(PCI_IDS_PATH); + std::string line, item; + + if (!in.is_open()) + { +#ifndef _MSC_VER + // On Unix, try PCI_IDS_PATH2 + in.open(PCI_IDS_PATH2); + } + + if (!in.is_open()) + { + // On Unix, try the current directory if the default path failed + in.open("pci.ids"); + } + + if (!in.is_open()) + { +#endif + std::cerr << PCI_IDS_NOT_FOUND << "\n"; + return; + } + + int vendorID = -1; + + while (std::getline(in, line)) { + // Ignore any line starting with # + if (line.size() == 0 || line[0] == '#') + continue; + + if (line[0] == '\t' && line[1] == '\t') + { + // subvendor subdevice subsystem_name + continue; + } + if (line[0] == '\t') + { + int deviceID = stoi(line.substr(1,4),0,16); + //std::cout << vendorID << ";" << vendorName << ";" << deviceID << ";" << line.substr(7) << "\n"; + pciDB.second[vendorID][deviceID] = line.substr(7); + continue; + } + // vendor + vendorID = stoi(line.substr(0,4),0,16); + pciDB.first[vendorID] = line.substr(6); + } +} + +} // Namespace pcm diff --git a/src/lspci.h b/src/lspci.h index 5723621d..23eda0d7 100644 --- a/src/lspci.h +++ b/src/lspci.h @@ -165,9 +165,6 @@ class ccr { static const ccr_config icx_ccrs; }; -const ccr_config ccr::skx_ccrs(44, 0xFFULL); -const ccr_config ccr::icx_ccrs(48, 0xFFFULL); - struct bdf { uint32_t domainno; uint8_t busno; @@ -241,7 +238,10 @@ struct pci { bool hasChildDevices() const { return (child_pci_devs.size() != 0); } bool isIntelDevice() const { return (vendor_id == PCM_INTEL_PCI_VENDOR_ID); } + + bool isIntelDeviceById(uint16_t device_id) const { return (isIntelDevice() && (this->device_id == device_id)); } }; + struct iio_skx { struct { struct { @@ -277,175 +277,28 @@ struct iio_stack { iio_stack() : iio_unit_id(0), stack_name(""), domain(0), busno(0) {} }; -bool operator<(const iio_stack& lh, const iio_stack& rh) -{ - return lh.iio_unit_id < rh.iio_unit_id; -} +bool operator<(const iio_stack& lh, const iio_stack& rh); struct iio_stacks_on_socket { std::vector stacks{}; uint32_t socket_id{}; }; -bool operator<(const bdf &l, const bdf &r) { - if (l.domainno < r.domainno) - return true; - if (l.domainno > r.domainno) - return false; - if (l.busno < r.busno) - return true; - if (l.busno > r.busno) - return false; - if (l.devno < r.devno) - return true; - if (l.devno > r.devno) - return false; - if (l.funcno < r.funcno) - return true; - if (l.funcno > r.funcno) - return false; - - return false; // bdf == bdf -}; +bool operator<(const bdf &l, const bdf &r); -void probe_capability_pci_express(struct pci *p, uint32_t cap_ptr) -{ - struct cap { - union { - struct { - uint8_t id; - union { - uint8_t next; - uint8_t cap_ptr; - }; - uint16_t junk; - }; - uint32 dw0; - }; - } cap; - uint32 value; - PciHandleType h(0, p->bdf.busno, p->bdf.devno, p->bdf.funcno); - h.read32(cap_ptr, &value); //Capability pointer - cap.dw0 = value; - if (cap.id != 0x10 && cap.next != 0x00) { - probe_capability_pci_express(p, cap.cap_ptr); - } else { - if (cap.id == 0x10) { // We're in PCI express capability structure - h.read32(cap_ptr+0x10, &value); - p->link_info = value; - } else { /*Finish recursive searching but cannot find PCI express capability structure*/ } - } -} - -bool probe_pci(struct pci *p) -{ - uint32 value; - p->exist = false; - struct bdf *bdf = &p->bdf; - if (PciHandleType::exists(bdf->domainno, bdf->busno, bdf->devno, bdf->funcno)) { - PciHandleType h(bdf->domainno, bdf->busno, bdf->devno, bdf->funcno); - // VID:DID - h.read32(0x0, &value); - // Invalid VID::DID - if (value != (std::numeric_limits::max)()) { - p->offset_0 = value; - h.read32(0xc, &value); - p->header_type = (value >> 16) & 0x7f; - if (p->header_type == 0) { - // Status register - h.read32(0x4, &value); - // Capability list == true - if (value & 0x100000) { - // Capability pointer - h.read32(0x34, &value); - probe_capability_pci_express(p, value); - } - } else if (p->header_type == 1) { - h.read32(0x18, &value); - p->offset_18 = value; - } - p->exist = true; - } - } +void probe_capability_pci_express(struct pci *p, uint32_t cap_ptr); - return p->exist; -} +bool probe_pci(struct pci *p); /* - first : [vendorID] -> vencor name + first : [vendorID] -> vendor name second : [vendorID][deviceID] -> device name */ typedef std::pair< std::map ,std::map< int, std::map > > PCIDB; -void print_pci(struct pci p, const PCIDB & pciDB) -{ - printf("Parent bridge info:"); - printf("%x:%x.%d [%04x:%04x] %s %s %d P:%x S:%x S:%x ", - p.bdf.busno, p.bdf.devno, p.bdf.funcno, - p.vendor_id, p.device_id, - (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", - (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device", - p.header_type, - p.primary_bus_number, p.secondary_bus_number, p.subordinate_bus_number); - printf("Device info:"); - printf("%x:%x.%d [%04x:%04x] %s %s %d Gen%d x%d\n", - p.bdf.busno, p.bdf.devno, p.bdf.funcno, - p.vendor_id, p.device_id, - (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", - (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device", - p.header_type, - p.link_speed, p.link_width); -} - -void load_PCIDB(PCIDB & pciDB) -{ - std::ifstream in(PCI_IDS_PATH); - std::string line, item; - - if (!in.is_open()) - { -#ifndef _MSC_VER - // On Unix, try PCI_IDS_PATH2 - in.open(PCI_IDS_PATH2); - } - - if (!in.is_open()) - { - // On Unix, try the current directory if the default path failed - in.open("pci.ids"); - } - - if (!in.is_open()) - { -#endif - std::cerr << PCI_IDS_NOT_FOUND << "\n"; - return; - } +void print_pci(struct pci p, const PCIDB & pciDB); - int vendorID = -1; - - while (std::getline(in, line)) { - // Ignore any line starting with # - if (line.size() == 0 || line[0] == '#') - continue; - - if (line[0] == '\t' && line[1] == '\t') - { - // subvendor subdevice subsystem_name - continue; - } - if (line[0] == '\t') - { - int deviceID = stoi(line.substr(1,4),0,16); - //std::cout << vendorID << ";" << vendorName << ";" << deviceID << ";" << line.substr(7) << "\n"; - pciDB.second[vendorID][deviceID] = line.substr(7); - continue; - } - // vendor - vendorID = stoi(line.substr(0,4),0,16); - pciDB.first[vendorID] = line.substr(6); - } -} +void load_PCIDB(PCIDB & pciDB); } // namespace pcm diff --git a/src/pci.h b/src/pci.h index e771534c..b665b597 100644 --- a/src/pci.h +++ b/src/pci.h @@ -141,7 +141,7 @@ inline void forAllIntelDevices(F f, int requestedDevice = -1, int requestedFunct } catch(...) { - // invalid bus:devicei:function + // invalid bus:device:function return; } const uint32 vendor_id = value & 0xffff; diff --git a/src/pcm-iio-pmu.cpp b/src/pcm-iio-pmu.cpp new file mode 100644 index 00000000..cd108fe7 --- /dev/null +++ b/src/pcm-iio-pmu.cpp @@ -0,0 +1,1543 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2017-2022, Intel Corporation + +// written by Patrick Lu, +// Aaron Cruz +// and others + +#include "pcm-iio-pmu.h" + +result_content results; + +vector combine_stack_name_and_counter_names(string stack_name, const map>> &nameMap) +{ + vector v; + vector tmp(nameMap.size()); + v.push_back(stack_name); + for (std::map>>::const_iterator iunit = nameMap.begin(); iunit != nameMap.end(); ++iunit) { + string h_name = iunit->first; + int h_id = (iunit->second).first; + tmp[h_id] = h_name; + //cout << "h_id:" << h_id << " name:" << h_name << "\n"; + } + //XXX: How to simplify and just combine tmp & v? + for (uint32_t i = 0; i < nameMap.size(); i++) { + v.push_back(tmp[i]); + } + return v; +} + +string build_pci_header(const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part, uint32_t level) +{ + string s = "|"; + char bdf_buf[32]; + char speed_buf[10]; + char vid_did_buf[10]; + char device_name_buf[128]; + + snprintf(bdf_buf, sizeof(bdf_buf), "%04X:%02X:%02X.%1d", p.bdf.domainno, p.bdf.busno, p.bdf.devno, p.bdf.funcno); + snprintf(speed_buf, sizeof(speed_buf), "Gen%1d x%-2d", p.link_speed, p.link_width); + snprintf(vid_did_buf, sizeof(vid_did_buf), "%04X:%04X", p.vendor_id, p.device_id); + snprintf(device_name_buf, sizeof(device_name_buf), "%s %s", + (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", + (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device" + ); + s += bdf_buf; + s += '|'; + s += speed_buf; + s += '|'; + s += vid_did_buf; + s += " "; + s += device_name_buf; + + if (!p.parts_no.empty()) { + s += "; Part: "; + for (auto& part : p.parts_no) { + s += std::to_string(part) + ", "; + } + s += "\b\b "; + } + + /* row with data */ + if (part >= 0) { + s.insert(1,"P" + std::to_string(part) + " "); + s += std::string(column_width - (s.size()-1), ' '); + } else { /* row without data, just child pci device */ + s.insert(0, std::string(4*level, ' ')); + } + + return s; +} + +void build_pci_tree(vector &buffer, const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part, uint32_t level) +{ + string row; + for (const auto& child : p.child_pci_devs) { + row = build_pci_header(pciDB, column_width, child, part, level); + buffer.push_back(row); + if (child.hasChildDevices()) + build_pci_tree(buffer, pciDB, column_width, child, part, level + 1); + } +} + +vector build_display(vector& iios, vector& ctrs, const PCIDB& pciDB, + const map>> &nameMap) +{ + vector buffer; + vector headers; + vector data; + uint64_t header_width; + string row; + for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { + buffer.push_back("Socket" + std::to_string(socket->socket_id)); + for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { + auto stack_id = stack->iio_unit_id; + headers = combine_stack_name_and_counter_names(stack->stack_name, nameMap); + //Print first row + row = std::accumulate(headers.begin(), headers.end(), string(" "), a_header_footer); + header_width = row.size(); + buffer.push_back(row); + //Print a_title + row = std::accumulate(headers.begin(), headers.end(), string("|"), a_title); + buffer.push_back(row); + //Print deliminator + row = std::accumulate(headers.begin(), headers.end(), string("|"), a_header_footer); + buffer.push_back(row); + //Print data + std::map> v_sort; + //re-organize data collection to be row wise + for (std::vector::iterator counter = ctrs.begin(); counter != ctrs.end(); ++counter) { + v_sort[counter->v_id][counter->h_id] = &(*counter); + } + for (std::map>::const_iterator vunit = v_sort.cbegin(); vunit != v_sort.cend(); ++vunit) { + map h_array = vunit->second; + uint32_t vv_id = vunit->first; + vector h_data; + string v_name = h_array[0]->v_event_name; + for (map::const_iterator hunit = h_array.cbegin(); hunit != h_array.cend(); ++hunit) { + uint32_t hh_id = hunit->first; + uint64_t raw_data = hunit->second->data[0][socket->socket_id][stack_id][std::pair(hh_id,vv_id)]; + h_data.push_back(raw_data); + } + data = prepare_data(h_data, headers); + row = "| " + v_name; + row += string(abs(int(headers[0].size() - (row.size() - 1))), ' '); + row += std::accumulate(data.begin(), data.end(), string("|"), a_data); + buffer.push_back(row); + } + //Print deliminator + row = std::accumulate(headers.begin(), headers.end(), string("|"), a_header_footer); + buffer.push_back(row); + //Print pcie devices + for (const auto& part : stack->parts) { + uint8_t level = 1; + for (const auto& pci_device : part.child_pci_devs) { + row = build_pci_header(pciDB, (uint32_t)header_width, pci_device, -1, level); + buffer.push_back(row); + if (pci_device.hasChildDevices()) { + build_pci_tree(buffer, pciDB, (uint32_t)header_width, pci_device, -1, level + 1); + } else if (pci_device.header_type == 1) { + level++; + } + } + } + //Print footer + row = std::accumulate(headers.begin(), headers.end(), string(" "), a_header_footer); + buffer.push_back(row); + } + } + return buffer; +} + +std::string get_root_port_dev(const bool show_root_port, int part_id, const pcm::iio_stack *stack) +{ + char tmp[9] = " "; + std::string rp_pci; + + if (!show_root_port) + return rp_pci; + + for (auto part = stack->parts.begin(); part != stack->parts.end(); part = std::next(part)) + { + if (part->part_id == part_id) + { + std::snprintf(tmp, sizeof(tmp), "%02x:%02x.%x", part->root_pci_dev.bdf.busno, + part->root_pci_dev.bdf.devno, part->root_pci_dev.bdf.funcno); + break; + } + } + + rp_pci.append(tmp); + return rp_pci; + +} + +vector build_csv(vector& iios, vector& ctrs, + const bool human_readable, const bool show_root_port, const std::string& csv_delimiter, + const map>> &nameMap) +{ + vector result; + vector current_row; + auto header = combine_stack_name_and_counter_names("Part", nameMap); + header.insert(header.begin(), "Name"); + if (show_root_port) + header.insert(header.begin(), "Root Port"); + header.insert(header.begin(), "Socket"); + auto insertDateTime = [&csv_delimiter](vector & out, CsvOutputType type) { + std::string dateTime; + printDateForCSV(type, csv_delimiter, &dateTime); + // remove last delimiter + dateTime.pop_back(); + out.insert(out.begin(), dateTime); + }; + insertDateTime(header, CsvOutputType::Header2); + result.push_back(build_csv_row(header, csv_delimiter)); + std::map> v_sort; + //re-organize data collection to be row wise + size_t max_name_width = 0; + for (std::vector::iterator counter = ctrs.begin(); counter != ctrs.end(); ++counter) { + v_sort[counter->v_id][counter->h_id] = &(*counter); + max_name_width = (std::max)(max_name_width, counter->v_event_name.size()); + } + + for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { + for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { + const std::string socket_name = "Socket" + std::to_string(socket->socket_id); + + std::string stack_name = stack->stack_name; + if (!human_readable) { + stack_name.erase(stack_name.find_last_not_of(' ') + 1); + } + + const uint32_t stack_id = stack->iio_unit_id; + //Print data + int part_id; + std::map>::const_iterator vunit; + for (vunit = v_sort.cbegin(), part_id = 0; + vunit != v_sort.cend(); ++vunit, ++part_id) { + map h_array = vunit->second; + uint32_t vv_id = vunit->first; + vector h_data; + string v_name = h_array[0]->v_event_name; + if (human_readable) { + v_name += string(max_name_width - (v_name.size()), ' '); + } + + current_row.clear(); + current_row.push_back(socket_name); + if (show_root_port) { + auto pci_dev = get_root_port_dev(show_root_port, part_id, &(*stack)); + current_row.push_back(pci_dev); + } + current_row.push_back(stack_name); + current_row.push_back(v_name); + for (map::const_iterator hunit = h_array.cbegin(); hunit != h_array.cend(); ++hunit) { + uint32_t hh_id = hunit->first; + uint64_t raw_data = hunit->second->data[0][socket->socket_id][stack_id][std::pair(hh_id,vv_id)]; + current_row.push_back(human_readable ? unit_format(raw_data) : std::to_string(raw_data)); + } + insertDateTime(current_row, CsvOutputType::Data); + result.push_back(build_csv_row(current_row, csv_delimiter)); + } + } + } + return result; +} + +void PurleyPlatformMapping::getUboxBusNumbers(std::vector& ubox) +{ + for (uint16_t bus = 0; bus < 256; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci pci_dev; + pci_dev.bdf.busno = (uint8_t)bus; + pci_dev.bdf.devno = device; + pci_dev.bdf.funcno = function; + if (probe_pci(&pci_dev) && pci_dev.isIntelDeviceById(SKX_SOCKETID_UBOX_DID)) { + ubox.push_back(bus); + } + } + } + } +} + +bool PurleyPlatformMapping::pciTreeDiscover(std::vector& iios) +{ + std::vector ubox; + getUboxBusNumbers(ubox); + if (ubox.empty()) { + cerr << "UBOXs were not found! Program aborted" << endl; + return false; + } + + for (uint32_t socket_id = 0; socket_id < socketsCount(); socket_id++) { + if (!PciHandleType::exists(0, ubox[socket_id], SKX_UBOX_DEVICE_NUM, SKX_UBOX_FUNCTION_NUM)) { + cerr << "No access to PCICFG\n" << endl; + return false; + } + uint64 cpubusno = 0; + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = socket_id; + PciHandleType h(0, ubox[socket_id], SKX_UBOX_DEVICE_NUM, SKX_UBOX_FUNCTION_NUM); + h.read64(ROOT_BUSES_OFFSET, &cpubusno); + + iio_on_socket.stacks.reserve(6); + for (int stack_id = 0; stack_id < 6; stack_id++) { + struct iio_stack stack; + stack.iio_unit_id = stack_id; + stack.busno = (uint8_t)(cpubusno >> (stack_id * SKX_BUS_NUM_STRIDE)); + stack.stack_name = skx_iio_stack_names[stack_id]; + for (uint8_t part_id = 0; part_id < 4; part_id++) { + struct iio_bifurcated_part part; + part.part_id = part_id; + struct pci *pci = &part.root_pci_dev; + struct bdf *bdf = &pci->bdf; + bdf->busno = stack.busno; + bdf->devno = part_id; + bdf->funcno = 0; + /* This is a workaround to catch some IIO stack does not exist */ + if (stack_id != 0 && stack.busno == 0) { + pci->exist = false; + } + else if (probe_pci(pci)) { + /* FIXME: for 0:0.0, we may need to scan from secondary switch down; lgtm [cpp/fixme-comment] */ + for (uint8_t bus = pci->secondary_bus_number; bus <= pci->subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev; + child_pci_dev.bdf.busno = bus; + child_pci_dev.bdf.devno = device; + child_pci_dev.bdf.funcno = function; + if (probe_pci(&child_pci_dev)) { + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + } + stack.parts.push_back(part); + } + + iio_on_socket.stacks.push_back(stack); + } + iios.push_back(iio_on_socket); + } + + return true; +} + +bool IPlatformMapping10Nm::getSadIdRootBusMap(uint32_t socket_id, std::map& sad_id_bus_map) +{ + for (uint16_t bus = 0; bus < 256; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci pci_dev; + pci_dev.bdf.busno = (uint8_t)bus; + pci_dev.bdf.devno = device; + pci_dev.bdf.funcno = function; + if (probe_pci(&pci_dev) && pci_dev.isIntelDeviceById(SNR_ICX_MESH2IIO_MMAP_DID)) { + + PciHandleType h(0, bus, device, function); + std::uint32_t sad_ctrl_cfg; + h.read32(SNR_ICX_SAD_CONTROL_CFG_OFFSET, &sad_ctrl_cfg); + if (sad_ctrl_cfg == (std::numeric_limits::max)()) { + cerr << "Could not read SAD_CONTROL_CFG" << endl; + return false; + } + + if ((sad_ctrl_cfg & 0xf) == socket_id) { + uint8_t sid = (sad_ctrl_cfg >> 4) & 0x7; + sad_id_bus_map.insert(std::pair(sid, (uint8_t)bus)); + } + } + } + } + } + + if (sad_id_bus_map.empty()) { + cerr << "Could not find Root Port bus numbers" << endl; + return false; + } + + return true; +} + +bool WhitleyPlatformMapping::pciTreeDiscover(std::vector& iios) +{ + for (uint32_t socket = 0; socket < socketsCount(); socket++) { + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = socket; + std::map sad_id_bus_map; + if (!getSadIdRootBusMap(socket, sad_id_bus_map)) { + return false; + } + + { + struct iio_stack stack; + stack.iio_unit_id = sad_to_pmu_id_mapping.at(ICX_MCP_SAD_ID); + stack.stack_name = iio_stack_names[stack.iio_unit_id]; + iio_on_socket.stacks.push_back(stack); + } + + for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { + int sad_id = sad_id_bus_pair->first; + if (sad_to_pmu_id_mapping.find(sad_id) == + sad_to_pmu_id_mapping.end()) { + cerr << "Unknown SAD ID: " << sad_id << endl; + return false; + } + + if (sad_id == ICX_MCP_SAD_ID) { + continue; + } + + struct iio_stack stack; + int root_bus = sad_id_bus_pair->second; + if (sad_id == ICX_CBDMA_DMI_SAD_ID) { + // There is one DMA Controller on each socket + stack.iio_unit_id = sad_to_pmu_id_mapping.at(sad_id); + stack.busno = root_bus; + stack.stack_name = iio_stack_names[stack.iio_unit_id]; + + // PCH is on socket 0 only + if (socket == 0) { + struct iio_bifurcated_part pch_part; + struct pci *pci = &pch_part.root_pci_dev; + struct bdf *bdf = &pci->bdf; + pch_part.part_id = ICX_PCH_PART_ID; + bdf->busno = root_bus; + bdf->devno = 0x00; + bdf->funcno = 0x00; + if (probe_pci(pci)) { + // Probe child devices only under PCH part. + for (uint8_t bus = pci->secondary_bus_number; bus <= pci->subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev; + child_pci_dev.bdf.busno = bus; + child_pci_dev.bdf.devno = device; + child_pci_dev.bdf.funcno = function; + if (probe_pci(&child_pci_dev)) { + pch_part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(pch_part); + } + } + + struct iio_bifurcated_part part; + part.part_id = ICX_CBDMA_PART_ID; + struct pci *pci = &part.root_pci_dev; + struct bdf *bdf = &pci->bdf; + bdf->busno = root_bus; + bdf->devno = 0x01; + bdf->funcno = 0x00; + if (probe_pci(pci)) + stack.parts.push_back(part); + + iio_on_socket.stacks.push_back(stack); + continue; + } + stack.busno = root_bus; + stack.iio_unit_id = sad_to_pmu_id_mapping.at(sad_id); + stack.stack_name = iio_stack_names[stack.iio_unit_id]; + for (int slot = 2; slot < 6; slot++) { + struct pci pci; + pci.bdf.busno = root_bus; + pci.bdf.devno = slot; + pci.bdf.funcno = 0x00; + if (!probe_pci(&pci)) { + continue; + } + struct iio_bifurcated_part part; + part.part_id = slot - 2; + part.root_pci_dev = pci; + + for (uint8_t bus = pci.secondary_bus_number; bus <= pci.subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev; + child_pci_dev.bdf.busno = bus; + child_pci_dev.bdf.devno = device; + child_pci_dev.bdf.funcno = function; + if (probe_pci(&child_pci_dev)) { + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(part); + } + iio_on_socket.stacks.push_back(stack); + } + std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); + iios.push_back(iio_on_socket); + } + return true; +} + +bool JacobsvillePlatformMapping::JacobsvilleAccelerators(const std::pair& sad_id_bus_pair, struct iio_stack& stack) +{ + uint16_t expected_dev_id; + auto sad_id = sad_id_bus_pair.first; + switch (sad_id) { + case SNR_HQM_SAD_ID: + expected_dev_id = HQM_DID; + break; + case SNR_NIS_SAD_ID: + expected_dev_id = NIS_DID; + break; + case SNR_QAT_SAD_ID: + expected_dev_id = QAT_DID; + break; + default: + return false; + } + stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); + stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; + for (uint16_t bus = sad_id_bus_pair.second; bus < 256; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci pci_dev; + pci_dev.bdf.busno = (uint8_t)bus; + pci_dev.bdf.devno = device; + pci_dev.bdf.funcno = function; + if (probe_pci(&pci_dev)) { + if (expected_dev_id == pci_dev.device_id) { + struct iio_bifurcated_part part; + part.part_id = SNR_ACCELERATOR_PART_ID; + part.root_pci_dev = pci_dev; + stack.busno = (uint8_t)bus; + stack.parts.push_back(part); + return true; + } + } + } + } + } + return false; +} + +bool JacobsvillePlatformMapping::pciTreeDiscover(std::vector& iios) +{ + std::map sad_id_bus_map; + if (!getSadIdRootBusMap(0, sad_id_bus_map)) { + return false; + } + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = 0; + if (sad_id_bus_map.size() != snr_sad_to_pmu_id_mapping.size()) { + cerr << "Found unexpected number of stacks: " << sad_id_bus_map.size() << ", expected: " << snr_sad_to_pmu_id_mapping.size() << endl; + return false; + } + + for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { + int sad_id = sad_id_bus_pair->first; + struct iio_stack stack; + switch (sad_id) { + case SNR_CBDMA_DMI_SAD_ID: + { + int root_bus = sad_id_bus_pair->second; + stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); + stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; + stack.busno = root_bus; + // DMA Controller + struct iio_bifurcated_part part; + part.part_id = 0; + struct pci pci_dev; + pci_dev.bdf.busno = root_bus; + pci_dev.bdf.devno = 0x01; + pci_dev.bdf.funcno = 0x00; + if (probe_pci(&pci_dev)) { + part.root_pci_dev = pci_dev; + stack.parts.push_back(part); + } + + part.part_id = 4; + pci_dev.bdf.busno = root_bus; + pci_dev.bdf.devno = 0x00; + pci_dev.bdf.funcno = 0x00; + if (probe_pci(&pci_dev)) { + for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev; + child_pci_dev.bdf.busno = bus; + child_pci_dev.bdf.devno = device; + child_pci_dev.bdf.funcno = function; + if (probe_pci(&child_pci_dev)) { + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + part.root_pci_dev = pci_dev; + stack.parts.push_back(part); + } + } + break; + case SNR_PCIE_GEN3_SAD_ID: + { + int root_bus = sad_id_bus_pair->second; + stack.busno = root_bus; + stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); + stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; + for (int slot = 4; slot < 8; slot++) { + struct pci pci_dev; + pci_dev.bdf.busno = root_bus; + pci_dev.bdf.devno = slot; + pci_dev.bdf.funcno = 0x00; + if (!probe_pci(&pci_dev)) { + continue; + } + int part_id = 4 + pci_dev.device_id - SNR_ROOT_PORT_A_DID; + if ((part_id < 0) || (part_id > 4)) { + cerr << "Invalid part ID " << part_id << endl; + return false; + } + struct iio_bifurcated_part part; + part.part_id = part_id; + part.root_pci_dev = pci_dev; + for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev; + child_pci_dev.bdf.busno = bus; + child_pci_dev.bdf.devno = device; + child_pci_dev.bdf.funcno = function; + if (probe_pci(&child_pci_dev)) { + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(part); + } + } + break; + case SNR_HQM_SAD_ID: + case SNR_NIS_SAD_ID: + case SNR_QAT_SAD_ID: + JacobsvilleAccelerators(*sad_id_bus_pair, stack); + break; + default: + cerr << "Unknown SAD ID: " << sad_id << endl; + return false; + } + iio_on_socket.stacks.push_back(stack); + } + + std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); + + iios.push_back(iio_on_socket); + + return true; +} + +bool EagleStreamPlatformMapping::setChopValue() +{ + for (uint16_t b = 0; b < 256; b++) { + struct pci pci_dev(0, b, SPR_PCU_CR3_REG_DEVICE, SPR_PCU_CR3_REG_FUNCTION); + if (!(probe_pci(&pci_dev) && pci_dev.isIntelDeviceById(SPR_PCU_CR3_DID))) { + continue; + } + + std::uint32_t capid4; + PciHandleType h(0, b, SPR_PCU_CR3_REG_DEVICE, SPR_PCU_CR3_REG_FUNCTION); + h.read32(SPR_CAPID4_OFFSET, &capid4); + if (capid4 == (std::numeric_limits::max)()) { + std::cerr << "Cannot read PCU RC3 register" << std::endl; + return false; + } + capid4 = SPR_CAPID4_GET_PHYSICAL_CHOP(capid4); + if (capid4 == kXccChop || capid4 == kMccChop) { + m_chop = capid4; + m_es_type = cpuId() == PCM::SPR ? (m_chop == kXccChop ? estype::esSprXcc : estype::esSprMcc) : estype::esEmrXcc; + } + else { + std::cerr << "Unknown chop value " << capid4 << std::endl; + return false; + } + return true; + } + std::cerr << "Cannot find PCU RC3 registers on the system. Device ID is " << std::hex << SPR_PCU_CR3_DID << std::dec << std::endl; + return false; +} + +bool EagleStreamPlatformMapping::getRootBuses(std::map> &root_buses) +{ + bool mapped = true; + for (uint32_t domain = 0; mapped; domain++) { + mapped = false; + for (uint16_t b = 0; b < 256; b++) { + for (uint8_t d = 0; d < 32; d++) { + for (uint8_t f = 0; f < 8; f++) { + struct pci pci_dev(domain, b, d, f); + if (!probe_pci(&pci_dev)) { + break; + } + if (!pci_dev.isIntelDeviceById(SPR_MSM_DEV_ID)) { + continue; + } + + std::uint32_t cpuBusValid; + std::vector cpuBusNo; + int package_id; + + if (get_cpu_bus(domain, b, d, f, cpuBusValid, cpuBusNo, package_id) == false) + { + return false; + } + + const auto& sad_to_pmu_id_mapping = es_sad_to_pmu_id_mapping.at(m_es_type); + for (int cpuBusId = 0; cpuBusId < SPR_MSM_CPUBUSNO_MAX; ++cpuBusId) { + if (!((cpuBusValid >> cpuBusId) & 0x1)) + { + cout << "CPU bus " << cpuBusId << " is disabled on package " << package_id << endl; + continue; + } + if (sad_to_pmu_id_mapping.find(cpuBusId) == sad_to_pmu_id_mapping.end()) + { + cerr << "Cannot map CPU bus " << cpuBusId << " to IO PMU ID" << endl; + continue; + } + int pmuId = sad_to_pmu_id_mapping.at(cpuBusId); + int rootBus = (cpuBusNo[(int)(cpuBusId / 4)] >> ((cpuBusId % 4) * 8)) & 0xff; + root_buses[package_id][pmuId] = bdf(domain, rootBus, 0, 0); + cout << "Mapped CPU bus #" << cpuBusId << " (domain " << domain << " bus " << std::hex << rootBus << std::dec << ") to IO PMU #" + << pmuId << " package " << package_id << endl; + mapped = true; + } + } + } + } + } + return !root_buses.empty(); +} + +bool EagleStreamPlatformMapping::eagleStreamDmiStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + struct iio_stack stack; + stack.iio_unit_id = unit; + stack.stack_name = es_stack_names.at(m_es_type)[unit]; + stack.busno = address.busno; + stack.domain = address.domainno; + struct iio_bifurcated_part pch_part; + struct pci *pci = &pch_part.root_pci_dev; + auto dmi_part_id = SPR_DMI_PART_ID; + pch_part.part_id = dmi_part_id; + pci->bdf = address; + if (!probe_pci(pci)) { + cerr << "Failed to probe DMI Stack: address: " << std::setw(4) << std::setfill('0') << std::hex << address.domainno << + std::setw(2) << std::setfill('0') << ":" << address.busno << ":" << address.devno << + "." << address.funcno << std::dec << endl; + return false; + } + + /* Scan devices behind PCH port only */ + if (!iio_on_socket.socket_id) + probeDeviceRange(pch_part.child_pci_devs, pci->bdf.domainno, pci->secondary_bus_number, pci->subordinate_bus_number); + + pci->parts_no.push_back(dmi_part_id); + + stack.parts.push_back(pch_part); + iio_on_socket.stacks.push_back(stack); + return true; +} + +bool EagleStreamPlatformMapping::eagleStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + /* + * Stacks that manage PCIe 4.0 (device 2,4,6,8) and 5.0 (device 1,3,5,7) Root Ports. + */ + struct iio_stack stack; + stack.domain = address.domainno; + stack.busno = address.busno; + stack.iio_unit_id = unit; + stack.stack_name = es_stack_names.at(m_es_type)[unit]; + for (int slot = 1; slot < 9; ++slot) + { + // Check if port is enabled + struct pci root_pci_dev; + root_pci_dev.bdf = bdf(address.domainno, address.busno, slot, 0x0); + if (probe_pci(&root_pci_dev)) + { + struct iio_bifurcated_part part; + // Bifurcated Root Ports to channel mapping on SPR + part.part_id = slot - 1; + part.root_pci_dev = root_pci_dev; + for (uint8_t b = root_pci_dev.secondary_bus_number; b <= root_pci_dev.subordinate_bus_number; ++b) { + for (uint8_t d = 0; d < 32; ++d) { + for (uint8_t f = 0; f < 8; ++f) { + struct pci child_pci_dev(address.domainno, b, d, f); + if (probe_pci(&child_pci_dev)) { + child_pci_dev.parts_no.push_back(part.part_id); + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(part); + } + } + iio_on_socket.stacks.push_back(stack); + return true; +} + +bool EagleStreamPlatformMapping::eagleStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + struct iio_stack stack; + stack.iio_unit_id = unit; + stack.domain = address.domainno; + stack.busno = address.busno; + + // Channel mappings are checked on B0 stepping + auto rb = address.busno; + const std::vector acceleratorBuses{ rb, rb + 1, rb + 2, rb + 3 }; + stack.stack_name = es_stack_names.at(m_es_type)[unit]; + for (auto& b : acceleratorBuses) { + for (auto d = 0; d < 32; ++d) { + for (auto f = 0; f < 8; ++f) { + struct iio_bifurcated_part part; + struct pci pci_dev(address.domainno, b, d, f); + + if (probe_pci(&pci_dev)) { + if (pci_dev.isIntelDevice()) { + switch (pci_dev.device_id) { + case DSA_DID: + pci_dev.parts_no.push_back(0); + pci_dev.parts_no.push_back(1); + pci_dev.parts_no.push_back(2); + break; + case IAX_DID: + pci_dev.parts_no.push_back(0); + pci_dev.parts_no.push_back(1); + pci_dev.parts_no.push_back(2); + break; + case HQMV2_DID: + pci_dev.parts_no.push_back(isXccPlatform() ? SPR_XCC_HQM_PART_ID : SPR_MCC_HQM_PART_ID); + break; + case QATV2_DID: + pci_dev.parts_no.push_back(isXccPlatform() ? SPR_XCC_QAT_PART_ID : SPR_MCC_QAT_PART_ID); + break; + default: + continue; + } + part.child_pci_devs.push_back(pci_dev); + } + stack.parts.push_back(part); + } + } + } + } + + iio_on_socket.stacks.push_back(stack); + return true; +} + +bool EagleStreamPlatformMapping::isDmiStack(int unit) +{ + const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); + + return stacks_enumeration[esDMI] == unit; +} + +bool EagleStreamPlatformMapping::isPcieStack(int unit) +{ + const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); + + return stacks_enumeration[esPCIe0] == unit || stacks_enumeration[esPCIe1] == unit || + stacks_enumeration[esPCIe2] == unit || stacks_enumeration[esPCIe3] == unit || + stacks_enumeration[esPCIe4] == unit; +} + +bool EagleStreamPlatformMapping::isDinoStack(int unit) +{ + const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); + + return stacks_enumeration[esDINO0] == unit || stacks_enumeration[esDINO1] == unit || + stacks_enumeration[esDINO2] == unit || stacks_enumeration[esDINO3] == unit; +} + +bool EagleStreamPlatformMapping::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + if (isDmiStack(unit)) { + return eagleStreamDmiStackProbe(unit, address, iio_on_socket); + } + else if (isPcieStack(unit)) { + return eagleStreamPciStackProbe(unit, address, iio_on_socket); + } + else if (isDinoStack(unit)) { + return eagleStreamAcceleratorStackProbe(unit, address, iio_on_socket); + } + + return false; +} + +bool EagleStreamPlatformMapping::pciTreeDiscover(std::vector& iios) +{ + if (!setChopValue()) return false; + + std::map> root_buses; + if (!getRootBuses(root_buses)) + { + return false; + } + + for (auto iter = root_buses.cbegin(); iter != root_buses.cend(); ++iter) { + auto rbs_on_socket = iter->second; + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = iter->first; + for (auto rb = rbs_on_socket.cbegin(); rb != rbs_on_socket.cend(); ++rb) { + if (!stackProbe(rb->first, rb->second, iio_on_socket)) { + return false; + } + } + std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); + iios.push_back(iio_on_socket); + } + + return true; +} + +bool LoganvillePlatform::loganvillePchDsaPciStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) +{ + struct iio_stack stack; + stack.busno = root_bus; + stack.iio_unit_id = stack_pmon_id; + stack.stack_name = grr_iio_stack_names[stack_pmon_id]; + + struct iio_bifurcated_part pch_part; + pch_part.part_id = 7; + struct pci* pci_dev = &pch_part.root_pci_dev; + pci_dev->bdf.busno = root_bus; + + if (probe_pci(pci_dev)) { + probeDeviceRange(pch_part.child_pci_devs, pci_dev->bdf.domainno, pci_dev->secondary_bus_number, pci_dev->subordinate_bus_number); + stack.parts.push_back(pch_part); + iio_on_socket.stacks.push_back(stack); + return true; + } + + return false; +} + +bool LoganvillePlatform::loganvilleDlbStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) +{ + struct iio_stack stack; + stack.busno = root_bus; + stack.iio_unit_id = stack_pmon_id; + stack.stack_name = grr_iio_stack_names[stack_pmon_id]; + + struct iio_bifurcated_part dlb_part; + dlb_part.part_id = GRR_DLB_PART_ID; + + for (uint8_t bus = root_bus; bus < 255; bus++) { + struct pci pci_dev(bus, 0x00, 0x00); + if (probe_pci(&pci_dev) && pci_dev.isIntelDeviceById(HQMV25_DID)) { + dlb_part.root_pci_dev = pci_dev; + // Check Virtual RPs for DLB + for (uint8_t device = 0; device < 2; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev(bus, device, function); + if (probe_pci(&child_pci_dev)) { + dlb_part.child_pci_devs.push_back(child_pci_dev); + } + } + } + stack.parts.push_back(dlb_part); + iio_on_socket.stacks.push_back(stack); + return true; + } + } + + return false; +} + +bool LoganvillePlatform::loganvilleNacStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) +{ + struct iio_stack stack; + stack.busno = root_bus; + stack.iio_unit_id = stack_pmon_id; + stack.stack_name = grr_iio_stack_names[stack_pmon_id]; + + // Probe NIS + { + struct iio_bifurcated_part nis_part; + nis_part.part_id = GRR_NIS_PART_ID; + struct pci pci_dev(root_bus, 0x04, 0x00); + if (probe_pci(&pci_dev)) { + nis_part.root_pci_dev = pci_dev; + for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 2; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev(bus, device, function); + if (probe_pci(&child_pci_dev)) { + nis_part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(nis_part); + } + } + + // Probe QAT + { + struct iio_bifurcated_part qat_part; + qat_part.part_id = GRR_QAT_PART_ID; + struct pci pci_dev(root_bus, 0x05, 0x00); + if (probe_pci(&pci_dev)) { + qat_part.root_pci_dev = pci_dev; + for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { + for (uint8_t device = 0; device < 17; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_pci_dev(bus, device, function); + if (probe_pci(&child_pci_dev)) { + qat_part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(qat_part); + } + } + + iio_on_socket.stacks.push_back(stack); + return true; +} + +bool LoganvillePlatform::pciTreeDiscover(std::vector& iios) +{ + std::map sad_id_bus_map; + if (!getSadIdRootBusMap(0, sad_id_bus_map)) { + return false; + } + + if (sad_id_bus_map.size() != grr_sad_to_pmu_id_mapping.size()) { + cerr << "Found unexpected number of stacks: " << sad_id_bus_map.size() << ", expected: " << grr_sad_to_pmu_id_mapping.size() << endl; + return false; + } + + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = 0; + + for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { + if (grr_sad_to_pmu_id_mapping.find(sad_id_bus_pair->first) == grr_sad_to_pmu_id_mapping.end()) { + cerr << "Cannot map SAD ID to PMON ID. Unknown ID: " << sad_id_bus_pair->first << endl; + return false; + } + int stack_pmon_id = grr_sad_to_pmu_id_mapping.at(sad_id_bus_pair->first); + int root_bus = sad_id_bus_pair->second; + switch (stack_pmon_id) { + case GRR_PCH_DSA_GEN4_PMON_ID: + if (!loganvillePchDsaPciStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { + return false; + } + break; + case GRR_DLB_PMON_ID: + if (!loganvilleDlbStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { + return false; + } + break; + case GRR_NIS_QAT_PMON_ID: + if (!loganvilleNacStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { + return false; + } + break; + default: + return false; + } + } + + std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); + + iios.push_back(iio_on_socket); + + return true; +} + +bool Xeon6thNextGenPlatform::getRootBuses(std::map> &root_buses) +{ + bool mapped = true; + for (uint32_t domain = 0; mapped; domain++) { + mapped = false; + for (uint16_t b = 0; b < 256; b++) { + for (uint8_t d = 0; d < 32; d++) { + for (uint8_t f = 0; f < 8; f++) { + struct pci pci_dev(domain, b, d, f); + if (!probe_pci(&pci_dev)) { + break; + } + if (!pci_dev.isIntelDeviceById(SPR_MSM_DEV_ID)) { + continue; + } + + std::uint32_t cpuBusValid; + std::vector cpuBusNo; + int package_id; + + if (!get_cpu_bus(domain, b, d, f, cpuBusValid, cpuBusNo, package_id)) { + return false; + } + + for (int cpuBusId = 0; cpuBusId < SPR_MSM_CPUBUSNO_MAX; ++cpuBusId) { + if (!((cpuBusValid >> cpuBusId) & 0x1)) { + cout << "CPU bus " << cpuBusId << " is disabled on package " << package_id << endl; + continue; + } + int rootBus = (cpuBusNo[(int)(cpuBusId / 4)] >> ((cpuBusId % 4) * 8)) & 0xff; + root_buses[package_id][cpuBusId] = bdf(domain, rootBus, 0, 0); + cout << "Mapped CPU bus #" << cpuBusId << " (domain " << domain << " bus " << std::hex << rootBus << std::dec << ")" + << " package " << package_id << endl; + mapped = true; + } + } + } + } + } + return !root_buses.empty(); +} + +bool Xeon6thNextGenPlatform::pciTreeDiscover(std::vector& iios) +{ + std::map> root_buses; + if (!getRootBuses(root_buses)) + { + return false; + } + + for (auto iter = root_buses.cbegin(); iter != root_buses.cend(); ++iter) { + auto rbs_on_socket = iter->second; + struct iio_stacks_on_socket iio_on_socket; + iio_on_socket.socket_id = iter->first; + for (auto rb = rbs_on_socket.cbegin(); rb != rbs_on_socket.cend(); ++rb) { + if (!stackProbe(rb->first, rb->second, iio_on_socket)) { + return false; + } + } + std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); + iios.push_back(iio_on_socket); + } + + return true; +} + +bool BirchStreamPlatform::birchStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + /* + * All stacks manage PCIe 5.0 Root Ports. Bifurcated Root Ports A-H appear as devices 2-9. + */ + struct iio_stack stack; + stack.domain = address.domainno; + stack.busno = address.busno; + stack.iio_unit_id = srf_sad_to_pmu_id_mapping.at(unit); + stack.stack_name = srf_iio_stack_names[stack.iio_unit_id]; + for (int slot = 2; slot < 9; ++slot) + { + struct pci root_pci_dev; + root_pci_dev.bdf = bdf(address.domainno, address.busno, slot, 0x0); + if (probe_pci(&root_pci_dev)) + { + struct iio_bifurcated_part part; + part.part_id = slot - 2; + part.root_pci_dev = root_pci_dev; + for (uint8_t b = root_pci_dev.secondary_bus_number; b <= root_pci_dev.subordinate_bus_number; ++b) { + for (uint8_t d = 0; d < 32; ++d) { + for (uint8_t f = 0; f < 8; ++f) { + struct pci child_pci_dev(address.domainno, b, d, f); + if (probe_pci(&child_pci_dev)) { + child_pci_dev.parts_no.push_back(part.part_id); + part.child_pci_devs.push_back(child_pci_dev); + } + } + } + } + stack.parts.push_back(part); + } + } + iio_on_socket.stacks.push_back(stack); + return true; +} + +bool BirchStreamPlatform::birchStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + struct iio_stack stack; + stack.iio_unit_id = srf_sad_to_pmu_id_mapping.at(unit); + stack.domain = address.domainno; + stack.busno = address.busno; + stack.stack_name = srf_iio_stack_names[stack.iio_unit_id]; + + /* + * Instance of DSA(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (8, 12, 20, 16), device 1, function 0 + * Instance of IAX(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (8, 12, 20, 16), device 2, function 0 + * Instance of QAT(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (9, 13, 21, 17), device 0, function 0 + * Instance of HQM(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (10, 14, 22, 18), device 0, function 0 + */ + auto process_pci_dev = [](int domainno, int busno, int devno, int part_number, iio_bifurcated_part& part) + { + struct pci pci_dev(domainno, busno, devno, 0); + if (probe_pci(&pci_dev) && pci_dev.isIntelDevice()) { + part.part_id = part_number; + pci_dev.parts_no.push_back(part_number); + part.child_pci_devs.push_back(pci_dev); + return true; + } + return false; + }; + + auto add_pci_part = [&](int domainno, int busno, int devno, int part_number) { + struct iio_bifurcated_part part; + if (process_pci_dev(domainno, busno, devno, part_number, part)) { + stack.parts.push_back(part); + } + }; + + add_pci_part(address.domainno, address.busno, 1, SRF_DSA_IAX_PART_NUMBER); + add_pci_part(address.domainno, address.busno, 2, SRF_DSA_IAX_PART_NUMBER); + + add_pci_part(address.domainno, address.busno + 1, 0, SRF_QAT_PART_NUMBER); + + /* Bus number for HQM is higher on 3 than DSA bus number */ + add_pci_part(address.domainno, address.busno + 3, 0, SRF_HQM_PART_NUMBER); + + if (!stack.parts.empty()) { + iio_on_socket.stacks.push_back(stack); + } + + return true; +} + +bool BirchStreamPlatform::isPcieStack(int unit) +{ + return srf_pcie_stacks.find(unit) != srf_pcie_stacks.end(); +} + +/* + * HC is the name of DINO stacks as we had on SPR + */ +bool BirchStreamPlatform::isRootHcStack(int unit) +{ + return SRF_HC0_SAD_BUS_ID == unit || SRF_HC1_SAD_BUS_ID == unit || + SRF_HC2_SAD_BUS_ID == unit || SRF_HC3_SAD_BUS_ID == unit; +} + +bool BirchStreamPlatform::isPartHcStack(int unit) +{ + return isRootHcStack(unit - 1) || isRootHcStack(unit - 2); +} + +bool BirchStreamPlatform::isUboxStack(int unit) +{ + return SRF_UBOXA_SAD_BUS_ID == unit || SRF_UBOXB_SAD_BUS_ID == unit; +} + +bool BirchStreamPlatform::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + if (isPcieStack(unit)) { + return birchStreamPciStackProbe(unit, address, iio_on_socket); + } + else if (isRootHcStack(unit)) { + return birchStreamAcceleratorStackProbe(unit, address, iio_on_socket); + } + else if (isPartHcStack(unit)) { + cout << "Found a part of HC stack. Stack ID - " << unit << " domain " << address.domainno + << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << ". Don't probe it again." << endl; + return true; + } + else if (isUboxStack(unit)) { + cout << "Found UBOX stack. Stack ID - " << unit << " domain " << address.domainno + << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << endl; + return true; + } + + cout << "Unknown stack ID " << unit << " domain " << address.domainno << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << endl; + + return false; +} + +const std::string generate_stack_str(const int unit) +{ + static const std::string stack_str = "Stack "; + std::stringstream ss; + ss << stack_str << std::setw(2) << unit; + return ss.str(); +} + +bool KasseyvillePlatform::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) +{ + // Skip UBOX buses + if (isUboxStack(unit)) return true; + + // To suppress compilation warning + (void)address; + + struct iio_stack stack; + stack.iio_unit_id = unit; + stack.stack_name = generate_stack_str(unit); + iio_on_socket.stacks.push_back(stack); + return true; +} + +void IPlatformMapping::probeDeviceRange(std::vector &pci_devs, int domain, int secondary, int subordinate) +{ + for (uint8_t bus = secondary; int(bus) <= subordinate; bus++) { + for (uint8_t device = 0; device < 32; device++) { + for (uint8_t function = 0; function < 8; function++) { + struct pci child_dev; + child_dev.bdf.domainno = domain; + child_dev.bdf.busno = bus; + child_dev.bdf.devno = device; + child_dev.bdf.funcno = function; + if (probe_pci(&child_dev)) { + if (secondary < child_dev.secondary_bus_number && subordinate < child_dev.subordinate_bus_number) { + probeDeviceRange(child_dev.child_pci_devs, domain, child_dev.secondary_bus_number, child_dev.subordinate_bus_number); + } + pci_devs.push_back(child_dev); + } + } + } + } +} + +std::unique_ptr IPlatformMapping::getPlatformMapping(int cpu_family_model, uint32_t sockets_count) +{ + switch (cpu_family_model) { + case PCM::SKX: + return std::unique_ptr{new PurleyPlatformMapping(cpu_family_model, sockets_count)}; + case PCM::ICX: + return std::unique_ptr{new WhitleyPlatformMapping(cpu_family_model, sockets_count)}; + case PCM::SNOWRIDGE: + return std::unique_ptr{new JacobsvillePlatformMapping(cpu_family_model, sockets_count)}; + case PCM::SPR: + case PCM::EMR: + return std::unique_ptr{new EagleStreamPlatformMapping(cpu_family_model, sockets_count)}; + case PCM::GRR: + return std::unique_ptr{new LoganvillePlatform(cpu_family_model, sockets_count)}; + case PCM::SRF: + case PCM::GNR: + return std::unique_ptr{new BirchStreamPlatform(cpu_family_model, sockets_count)}; + case PCM::GNR_D: + std::cerr << "Warning: Only initial support (without attribution to PCIe devices) for Graniterapids-D is provided" << std::endl; + return std::unique_ptr{new KasseyvillePlatform(cpu_family_model, sockets_count)}; + default: + return nullptr; + } +} + +ccr* get_ccr(PCM* m, uint64_t& ccr) +{ + switch (m->getCPUFamilyModel()) + { + case PCM::SKX: + return new pcm::ccr(ccr, ccr::ccr_type::skx); + case PCM::ICX: + case PCM::SNOWRIDGE: + case PCM::SPR: + case PCM::EMR: + case PCM::GRR: + case PCM::SRF: + case PCM::GNR: + case PCM::GNR_D: + return new pcm::ccr(ccr, ccr::ccr_type::icx); + default: + cerr << m->getCPUFamilyModelString() << " is not supported! Program aborted" << endl; + exit(EXIT_FAILURE); + } +} + +int iio_evt_parse_handler(evt_cb_type cb_type, void *cb_ctx, counter &base_ctr, std::map &ofm, std::string key, uint64 numValue) +{ + iio_evt_parse_context *context = (iio_evt_parse_context *)cb_ctx; + PCM *m = context->m; + + if (cb_type == EVT_LINE_START) //this event will be called per line(start) + { + context->ctr.ccr = 0; + } + else if (cb_type == EVT_LINE_FIELD) //this event will be called per field of line + { + std::unique_ptr pccr(get_ccr(m, context->ctr.ccr)); + switch (ofm[key]) + { + case PCM::OPCODE: + break; + case PCM::EVENT_SELECT: + pccr->set_event_select(numValue); + break; + case PCM::UMASK: + pccr->set_umask(numValue); + break; + case PCM::RESET: + pccr->set_reset(numValue); + break; + case PCM::EDGE_DET: + pccr->set_edge(numValue); + break; + case PCM::IGNORED: + break; + case PCM::OVERFLOW_ENABLE: + pccr->set_ov_en(numValue); + break; + case PCM::ENABLE: + pccr->set_enable(numValue); + break; + case PCM::INVERT: + pccr->set_invert(numValue); + break; + case PCM::THRESH: + pccr->set_thresh(numValue); + break; + case PCM::CH_MASK: + pccr->set_ch_mask(numValue); + break; + case PCM::FC_MASK: + pccr->set_fc_mask(numValue); + break; + case PCM::INVALID: + default: + std::cerr << "Field in -o file not recognized. The key is: " << key << "\n"; + return -1; + } + } + else if (cb_type == EVT_LINE_COMPLETE) //this event will be called every line(end) + { + context->ctr.h_event_name = base_ctr.h_event_name; + context->ctr.v_event_name = base_ctr.v_event_name; + context->ctr.idx = base_ctr.idx; + context->ctr.multiplier = base_ctr.multiplier; + context->ctr.divider = base_ctr.divider; + context->ctr.h_id = base_ctr.h_id; + context->ctr.v_id = base_ctr.v_id; + DBG(4, "line parse OK, ctrcfg=0x", std::hex, context->ctr.ccr, ", h_event_name=", base_ctr.h_event_name, ", v_event_name=", base_ctr.v_event_name); + DBG(4, ", h_id=0x", std::hex, base_ctr.h_id, ", v_id=0x", std::hex, base_ctr.v_id); + DBG(4, ", idx=0x", std::hex, base_ctr.idx, ", multiplier=0x", std::hex, base_ctr.multiplier, ", divider=0x", std::hex, base_ctr.divider, std::dec, "\n"); + context->ctrs.push_back(context->ctr); + } + + return 0; +} + +result_content get_IIO_Samples(PCM *m, const std::vector& iios, const struct iio_counter & ctr, uint32_t delay_ms) +{ + IIOCounterState *before, *after; + uint64 rawEvents[4] = {0}; + std::unique_ptr pccr(get_ccr(m, const_cast(ctr).ccr)); + rawEvents[ctr.idx] = pccr->get_ccr_value(); + const int stacks_count = (int)m->getMaxNumOfIIOStacks(); + before = new IIOCounterState[iios.size() * stacks_count]; + after = new IIOCounterState[iios.size() * stacks_count]; + + m->programIIOCounters(rawEvents); + for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { + for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { + auto iio_unit_id = stack->iio_unit_id; + uint32_t idx = (uint32_t)stacks_count * socket->socket_id + iio_unit_id; + before[idx] = m->getIIOCounterState(socket->socket_id, iio_unit_id, ctr.idx); + } + } + MySleepMs(delay_ms); + for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { + for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { + auto iio_unit_id = stack->iio_unit_id; + uint32_t idx = (uint32_t)stacks_count * socket->socket_id + iio_unit_id; + after[idx] = m->getIIOCounterState(socket->socket_id, iio_unit_id, ctr.idx); + uint64_t raw_result = getNumberOfEvents(before[idx], after[idx]); + uint64_t trans_result = uint64_t (raw_result * ctr.multiplier / (double) ctr.divider * (1000 / (double) delay_ms)); + results[socket->socket_id][iio_unit_id][std::pair(ctr.h_id,ctr.v_id)] = trans_result; + } + } + deleteAndNullifyArray(before); + deleteAndNullifyArray(after); + return results; +} + +void collect_data(PCM *m, const double delay, vector& iios, vector& ctrs) +{ + const uint32_t delay_ms = uint32_t(delay * 1000 / ctrs.size()); + for (auto counter = ctrs.begin(); counter != ctrs.end(); ++counter) { + counter->data.clear(); + result_content sample = get_IIO_Samples(m, iios, *counter, delay_ms); + counter->data.push_back(sample); + } +} + +void initializeIIOStructure( std::vector& iios ) +{ + PCM * m = PCM::getInstance(); + auto mapping = IPlatformMapping::getPlatformMapping(m->getCPUFamilyModel(), m->getNumSockets()); + if (!mapping) { + cerr << "Failed to discover pci tree: unknown platform" << endl; + exit(EXIT_FAILURE); + } + + if (!mapping->pciTreeDiscover(iios)) { + exit(EXIT_FAILURE); + } +} + +void fillOpcodeFieldMapForPCIeEvents(map& opcodeFieldMap) +{ + opcodeFieldMap["opcode"] = PCM::OPCODE; + opcodeFieldMap["ev_sel"] = PCM::EVENT_SELECT; + opcodeFieldMap["umask"] = PCM::UMASK; + opcodeFieldMap["reset"] = PCM::RESET; + opcodeFieldMap["edge_det"] = PCM::EDGE_DET; + opcodeFieldMap["ignored"] = PCM::IGNORED; + opcodeFieldMap["overflow_enable"] = PCM::OVERFLOW_ENABLE; + opcodeFieldMap["en"] = PCM::ENABLE; + opcodeFieldMap["invert"] = PCM::INVERT; + opcodeFieldMap["thresh"] = PCM::THRESH; + opcodeFieldMap["ch_mask"] = PCM::CH_MASK; + opcodeFieldMap["fc_mask"] = PCM::FC_MASK; + opcodeFieldMap["hname"] =PCM::H_EVENT_NAME; + opcodeFieldMap["vname"] =PCM::V_EVENT_NAME; + opcodeFieldMap["multiplier"] = PCM::MULTIPLIER; + opcodeFieldMap["divider"] = PCM::DIVIDER; + opcodeFieldMap["ctr"] = PCM::COUNTER_INDEX; +} + +void setupPCIeEventContextAndNameMap( iio_evt_parse_context& evt_ctx, PCIeEventNameMap_t& nameMap) +{ + PCM * m = PCM::getInstance(); + + string ev_file_name; + ev_file_name = "opCode-" + std::to_string(m->getCPUFamily()) + "-" + std::to_string(m->getInternalCPUModel()) + ".txt"; + + map opcodeFieldMap; + fillOpcodeFieldMapForPCIeEvents( opcodeFieldMap ); + + evt_ctx.m = m; + evt_ctx.ctrs.clear();//fill the ctrs by evt_handler call back func. + + try + { + load_events(ev_file_name, opcodeFieldMap, iio_evt_parse_handler, (void *)&evt_ctx, nameMap); + } + catch (std::exception & e) + { + std::cerr << "Error info:" << e.what() << "\n"; + std::cerr << "The event configuration file (" << ev_file_name << ") cannot be loaded. Please verify the file. Exiting.\n"; + exit(EXIT_FAILURE); + } + + results.resize(m->getNumSockets(), stack_content(m->getMaxNumOfIIOStacks(), ctr_data())); +} + +bool initializeIIOCounters( std::vector& iios, iio_evt_parse_context& evt_ctx, PCIeEventNameMap_t& nameMap ) +{ + PCM * m = PCM::getInstance(); + if (!m->IIOEventsAvailable()) + { + cerr << "This CPU is not supported by PCM IIO tool! Program aborted\n"; + return false; + } + + initializeIIOStructure( iios ); + + setupPCIeEventContextAndNameMap( evt_ctx, nameMap ); + + return true; +} diff --git a/src/pcm-iio-pmu.h b/src/pcm-iio-pmu.h new file mode 100644 index 00000000..df194c45 --- /dev/null +++ b/src/pcm-iio-pmu.h @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2017-2022, Intel Corporation + +// written by Patrick Lu, +// Aaron Cruz +// and others +#include "cpucounters.h" + +#ifdef _MSC_VER + #include + #include "windows/windriver.h" +#else + #include +#endif + +#include +#include +#include +#include +#include // std::length_error +#include +#include +#include +#include + +#ifdef _MSC_VER + #include "freegetopt/getopt.h" +#endif + +#include "lspci.h" +#include "utils.h" + +using namespace std; +using namespace pcm; + +#define PCM_DELAY_DEFAULT 3.0 // in seconds + +#define QAT_DID 0x18DA +#define NIS_DID 0x18D1 +#define HQM_DID 0x270B + +#define GRR_QAT_VRP_DID 0x5789 // Virtual Root Port to integrated QuickAssist (GRR QAT) +#define GRR_NIS_VRP_DID 0x5788 // VRP to Network Interface and Scheduler (GRR NIS) + +#define ROOT_BUSES_OFFSET 0xCC +#define ROOT_BUSES_OFFSET_2 0xD0 + +#define SKX_SOCKETID_UBOX_DID 0x2014 +#define SKX_UBOX_DEVICE_NUM 0x08 +#define SKX_UBOX_FUNCTION_NUM 0x02 +#define SKX_BUS_NUM_STRIDE 8 +//the below LNID and GID applies to Skylake Server +#define SKX_UNC_SOCKETID_UBOX_LNID_OFFSET 0xC0 +#define SKX_UNC_SOCKETID_UBOX_GID_OFFSET 0xD4 + +static const std::string iio_stack_names[6] = { + "IIO Stack 0 - CBDMA/DMI ", + "IIO Stack 1 - PCIe0 ", + "IIO Stack 2 - PCIe1 ", + "IIO Stack 3 - PCIe2 ", + "IIO Stack 4 - MCP0 ", + "IIO Stack 5 - MCP1 " +}; + +static const std::string skx_iio_stack_names[6] = { + "IIO Stack 0 - CBDMA/DMI ", + "IIO Stack 1 - PCIe0 ", + "IIO Stack 2 - PCIe1 ", + "IIO Stack 3 - PCIe2 ", + "IIO Stack 4 - MCP0 ", + "IIO Stack 5 - MCP1 " +}; + +static const std::string icx_iio_stack_names[6] = { + "IIO Stack 0 - PCIe0 ", + "IIO Stack 1 - PCIe1 ", + "IIO Stack 2 - MCP ", + "IIO Stack 3 - PCIe2 ", + "IIO Stack 4 - PCIe3 ", + "IIO Stack 5 - CBDMA/DMI " +}; + +static const std::string icx_d_iio_stack_names[6] = { + "IIO Stack 0 - MCP ", + "IIO Stack 1 - PCIe0 ", + "IIO Stack 2 - CBDMA/DMI ", + "IIO Stack 3 - PCIe2 ", + "IIO Stack 4 - PCIe3 ", + "IIO Stack 5 - PCIe1 " +}; + +static const std::string snr_iio_stack_names[5] = { + "IIO Stack 0 - QAT ", + "IIO Stack 1 - CBDMA/DMI ", + "IIO Stack 2 - NIS ", + "IIO Stack 3 - HQM ", + "IIO Stack 4 - PCIe " +}; + +#define ICX_CBDMA_DMI_SAD_ID 0 +#define ICX_MCP_SAD_ID 3 + +#define ICX_PCH_PART_ID 0 +#define ICX_CBDMA_PART_ID 3 + +#define SNR_ICX_SAD_CONTROL_CFG_OFFSET 0x3F4 +#define SNR_ICX_MESH2IIO_MMAP_DID 0x09A2 + +#define ICX_VMD_PCI_DEVNO 0x00 +#define ICX_VMD_PCI_FUNCNO 0x05 + +static const std::map icx_sad_to_pmu_id_mapping = { + { ICX_CBDMA_DMI_SAD_ID, 5 }, + { 1, 0 }, + { 2, 1 }, + { ICX_MCP_SAD_ID, 2 }, + { 4, 3 }, + { 5, 4 } +}; + +static const std::map icx_d_sad_to_pmu_id_mapping = { + { ICX_CBDMA_DMI_SAD_ID, 2 }, + { 1, 5 }, + { 2, 1 }, + { ICX_MCP_SAD_ID, 0 }, + { 4, 3 }, + { 5, 4 } +}; + +#define SNR_ACCELERATOR_PART_ID 4 + +#define SNR_ROOT_PORT_A_DID 0x334A + +#define SNR_CBDMA_DMI_SAD_ID 0 +#define SNR_PCIE_GEN3_SAD_ID 1 +#define SNR_HQM_SAD_ID 2 +#define SNR_NIS_SAD_ID 3 +#define SNR_QAT_SAD_ID 4 + +static const std::map snr_sad_to_pmu_id_mapping = { + { SNR_CBDMA_DMI_SAD_ID, 1 }, + { SNR_PCIE_GEN3_SAD_ID, 4 }, + { SNR_HQM_SAD_ID , 3 }, + { SNR_NIS_SAD_ID , 2 }, + { SNR_QAT_SAD_ID , 0 } +}; + +#define HQMV2_DID 0x2710 // Hardware Queue Manager v2 +#define HQMV25_DID 0x2714 // Hardware Queue Manager v2.5 +#define DSA_DID 0x0b25 // Data Streaming Accelerator (DSA) +#define IAX_DID 0x0cfe // In-Memory Database Analytics Accelerator (IAX) +#define QATV2_DID 0x4940 // QuickAssist (CPM) v2 + +#define SPR_DMI_PART_ID 7 +#define SPR_XCC_HQM_PART_ID 5 +#define SPR_MCC_HQM_PART_ID 4 +#define SPR_XCC_QAT_PART_ID 4 +#define SPR_MCC_QAT_PART_ID 5 +#define SPR_SAD_CONTROL_CFG_OFFSET SNR_ICX_SAD_CONTROL_CFG_OFFSET + +#define SPR_PCU_CR3_DID 0x325b +#define SPR_PCU_CR3_REG_DEVICE 0x1e +#define SPR_PCU_CR3_REG_FUNCTION 0x03 +#define SPR_CAPID4_OFFSET 0x94 +#define SPR_CAPID4_GET_PHYSICAL_CHOP(capid4) ((capid4 >> 6) & 3) +#define SPR_PHYSICAL_CHOP_XCC 0b11 +#define SPR_PHYSICAL_CHOP_MCC 0b01 + +#define SPR_XCC_DMI_PMON_ID 1 +#define SPR_XCC_PCIE_GEN5_0_PMON_ID 2 +#define SPR_XCC_PCIE_GEN5_1_PMON_ID 4 +#define SPR_XCC_PCIE_GEN5_2_PMON_ID 6 +#define SPR_XCC_PCIE_GEN5_3_PMON_ID 7 +#define SPR_XCC_PCIE_GEN5_4_PMON_ID 9 +#define SPR_XCC_IDX0_PMON_ID 0 +#define SPR_XCC_IDX1_PMON_ID 3 +#define SPR_XCC_IDX2_PMON_ID 5 +#define SPR_XCC_IDX3_PMON_ID 8 + +const std::map spr_xcc_sad_to_pmu_id_mapping = { + { 0, SPR_XCC_DMI_PMON_ID }, + { 1, SPR_XCC_PCIE_GEN5_0_PMON_ID }, + { 2, SPR_XCC_PCIE_GEN5_1_PMON_ID }, + { 3, SPR_XCC_PCIE_GEN5_2_PMON_ID }, + { 4, SPR_XCC_PCIE_GEN5_3_PMON_ID }, + { 5, SPR_XCC_PCIE_GEN5_4_PMON_ID }, + { 8, SPR_XCC_IDX0_PMON_ID }, + { 9, SPR_XCC_IDX1_PMON_ID }, + { 10, SPR_XCC_IDX2_PMON_ID }, + { 11, SPR_XCC_IDX3_PMON_ID } +}; + +#define SPR_MCC_DMI_PMON_ID 10 +#define SPR_MCC_PCIE_GEN5_0_PMON_ID 0 // assumption +#define SPR_MCC_PCIE_GEN5_1_PMON_ID 1 +#define SPR_MCC_PCIE_GEN5_2_PMON_ID 2 +#define SPR_MCC_PCIE_GEN5_3_PMON_ID 4 // assumption +#define SPR_MCC_PCIE_GEN5_4_PMON_ID 5 +#define SPR_MCC_IDX0_PMON_ID 3 + +const std::map spr_mcc_sad_to_pmu_id_mapping = { + { 0, SPR_MCC_PCIE_GEN5_0_PMON_ID }, + { 1, SPR_MCC_PCIE_GEN5_1_PMON_ID }, + { 2, SPR_MCC_PCIE_GEN5_2_PMON_ID }, + { 3, SPR_MCC_DMI_PMON_ID }, + { 4, SPR_MCC_PCIE_GEN5_3_PMON_ID }, + { 5, SPR_MCC_PCIE_GEN5_4_PMON_ID }, + { 8, SPR_MCC_IDX0_PMON_ID }, +}; + +static const std::string spr_xcc_iio_stack_names[] = { + "IIO Stack 0 - IDX0 ", + "IIO Stack 1 - DMI ", + "IIO Stack 2 - PCIe0 ", + "IIO Stack 3 - IDX1 ", + "IIO Stack 4 - PCIe1 ", + "IIO Stack 5 - IDX2 ", + "IIO Stack 6 - PCIe2 ", + "IIO Stack 7 - PCIe3", + "IIO Stack 8 - IDX3 ", + "IIO Stack 9 - PCIe4", + "IIO Stack 10 - NONE ", + "IIO Stack 11 - NONE ", +}; + +/* + * SPR MCC has 7 I/O stacks but PMON block for DMI has ID number 10. + * And just to follow such enumeration keep Stack 10 for DMI. + */ +static const std::string spr_mcc_iio_stack_names[] = { + "IIO Stack 0 - PCIe0 ", + "IIO Stack 1 - PCIe1 ", + "IIO Stack 2 - PCIe2 ", + "IIO Stack 3 - IDX0 ", + "IIO Stack 4 - PCIe3 ", + "IIO Stack 5 - PCIe4 ", + "IIO Stack 6 - NONE ", + "IIO Stack 7 - NONE ", + "IIO Stack 8 - NONE ", + "IIO Stack 9 - NONE ", + "IIO Stack 10 - DMI ", +}; + +// MS2IOSF stack IDs in CHA notation +#define GRR_PCH_DSA_GEN4_SAD_ID 0 +#define GRR_DLB_SAD_ID 1 +#define GRR_NIS_QAT_SAD_ID 2 + +#define GRR_PCH_DSA_GEN4_PMON_ID 2 +#define GRR_DLB_PMON_ID 1 +#define GRR_NIS_QAT_PMON_ID 0 + +// Stack 0 contains PCH, DSA and CPU PCIe Gen4 Complex +const std::map grr_sad_to_pmu_id_mapping = { + { GRR_PCH_DSA_GEN4_SAD_ID, GRR_PCH_DSA_GEN4_PMON_ID }, + { GRR_DLB_SAD_ID, GRR_DLB_PMON_ID }, + { GRR_NIS_QAT_SAD_ID, GRR_NIS_QAT_PMON_ID }, +}; + +#define GRR_DLB_PART_ID 0 +#define GRR_NIS_PART_ID 0 +#define GRR_QAT_PART_ID 1 + +static const std::string grr_iio_stack_names[3] = { + "IIO Stack 0 - NIS/QAT ", + "IIO Stack 1 - HQM ", + "IIO Stack 2 - PCH/DSA/PCIe " +}; + +#define EMR_DMI_PMON_ID 7 +#define EMR_PCIE_GEN5_0_PMON_ID 1 +#define EMR_PCIE_GEN5_1_PMON_ID 2 +#define EMR_PCIE_GEN5_2_PMON_ID 3 +#define EMR_PCIE_GEN5_3_PMON_ID 8 +#define EMR_PCIE_GEN5_4_PMON_ID 6 +#define EMR_IDX0_PMON_ID 0 +#define EMR_IDX1_PMON_ID 4 +#define EMR_IDX2_PMON_ID 5 +#define EMR_IDX3_PMON_ID 9 + +const std::map emr_sad_to_pmu_id_mapping = { + { 0, EMR_DMI_PMON_ID }, + { 1, EMR_PCIE_GEN5_0_PMON_ID }, + { 2, EMR_PCIE_GEN5_1_PMON_ID }, + { 3, EMR_PCIE_GEN5_2_PMON_ID }, + { 4, EMR_PCIE_GEN5_3_PMON_ID }, + { 5, EMR_PCIE_GEN5_4_PMON_ID }, + { 8, EMR_IDX0_PMON_ID }, + { 9, EMR_IDX1_PMON_ID }, + { 10, EMR_IDX2_PMON_ID }, + { 11, EMR_IDX3_PMON_ID } +}; + +static const std::string emr_iio_stack_names[] = { + "IIO Stack 0 - IDX0 ", + "IIO Stack 1 - PCIe3 ", + "IIO Stack 2 - PCIe0 ", + "IIO Stack 3 - IDX1 ", + "IIO Stack 4 - PCIe1 ", + "IIO Stack 5 - IDX2 ", + "IIO Stack 6 - PCIe2 ", + "IIO Stack 7 - DMI", + "IIO Stack 8 - IDX3 ", + "IIO Stack 9 - PCIe4", + "IIO Stack 10 - NONE ", + "IIO Stack 11 - NONE ", +}; + +enum EagleStreamPlatformStacks +{ + esDMI = 0, + esPCIe0, + esPCIe1, + esPCIe2, + esPCIe3, + esPCIe4, + esDINO0, + esDINO1, + esDINO2, + esDINO3, + esEndOfList +}; + +const std::vector spr_xcc_stacks_enumeration = { + /* esDMI */ SPR_XCC_DMI_PMON_ID, + /* esPCIe0 */ SPR_XCC_PCIE_GEN5_0_PMON_ID, + /* esPCIe1 */ SPR_XCC_PCIE_GEN5_1_PMON_ID, + /* esPCIe2 */ SPR_XCC_PCIE_GEN5_2_PMON_ID, + /* esPCIe3 */ SPR_XCC_PCIE_GEN5_3_PMON_ID, + /* esPCIe4 */ SPR_XCC_PCIE_GEN5_4_PMON_ID, + /* esDINO0 */ SPR_XCC_IDX0_PMON_ID, + /* esDINO1 */ SPR_XCC_IDX1_PMON_ID, + /* esDINO2 */ SPR_XCC_IDX2_PMON_ID, + /* esDINO3 */ SPR_XCC_IDX3_PMON_ID, +}; + +const std::vector spr_mcc_stacks_enumeration = { + /* esDMI */ SPR_MCC_DMI_PMON_ID, + /* esPCIe0 */ SPR_MCC_PCIE_GEN5_0_PMON_ID, + /* esPCIe1 */ SPR_MCC_PCIE_GEN5_1_PMON_ID, + /* esPCIe2 */ SPR_MCC_PCIE_GEN5_2_PMON_ID, + /* esPCIe3 */ SPR_MCC_PCIE_GEN5_3_PMON_ID, + /* esPCIe4 */ SPR_MCC_PCIE_GEN5_4_PMON_ID, + /* esDINO0 */ SPR_MCC_IDX0_PMON_ID, +}; + +const std::vector emr_stacks_enumeration = { + /* esDMI */ EMR_DMI_PMON_ID, + /* esPCIe0 */ EMR_PCIE_GEN5_0_PMON_ID, + /* esPCIe1 */ EMR_PCIE_GEN5_1_PMON_ID, + /* esPCIe2 */ EMR_PCIE_GEN5_2_PMON_ID, + /* esPCIe3 */ EMR_PCIE_GEN5_3_PMON_ID, + /* esPCIe4 */ EMR_PCIE_GEN5_4_PMON_ID, + /* esDINO0 */ EMR_IDX0_PMON_ID, + /* esDINO1 */ EMR_IDX1_PMON_ID, + /* esDINO2 */ EMR_IDX2_PMON_ID, + /* esDINO3 */ EMR_IDX3_PMON_ID, +}; + +enum class EagleStreamSupportedTypes +{ + esInvalid = -1, + esSprXcc, + esSprMcc, + esEmrXcc +}; + +typedef EagleStreamSupportedTypes estype; + +const std::map> es_stacks_enumeration = { + {estype::esSprXcc, spr_xcc_stacks_enumeration}, + {estype::esSprMcc, spr_mcc_stacks_enumeration}, + {estype::esEmrXcc, emr_stacks_enumeration }, +}; + +const std::map es_stack_names = { + {estype::esSprXcc, spr_xcc_iio_stack_names}, + {estype::esSprMcc, spr_mcc_iio_stack_names}, + {estype::esEmrXcc, emr_iio_stack_names }, +}; + +const std::map> es_sad_to_pmu_id_mapping = { + {estype::esSprXcc, spr_xcc_sad_to_pmu_id_mapping}, + {estype::esSprMcc, spr_mcc_sad_to_pmu_id_mapping}, + {estype::esEmrXcc, emr_sad_to_pmu_id_mapping }, +}; + +#define SRF_PE0_PMON_ID 3 +#define SRF_PE1_PMON_ID 4 +#define SRF_PE2_PMON_ID 2 +#define SRF_PE3_PMON_ID 5 +/* + * There are platform configuration when FlexUPI stacks (stacks 5 and 6) are enabled as + * PCIe stack and PCIe ports are disabled (ports 2 and 3) and vice sersa. See details here: + * In these cases the PMON IDs are different. + * So, defines with _FLEX_ are applicable for cases when FlexUPI stacks + * are working as PCIe ports. + */ +#define SRF_PE4_PMON_ID 11 +#define SRF_FLEX_PE4_PMON_ID 13 +#define SRF_PE5_PMON_ID 12 +#define SRF_FLEX_PE5_PMON_ID 10 + +#define SRF_PE6_PMON_ID 0 +#define SRF_PE7_PMON_ID 7 +#define SRF_PE8_PMON_ID 8 +#define SRF_HC0_PMON_ID 1 +#define SRF_HC1_PMON_ID 6 +#define SRF_HC2_PMON_ID 9 +#define SRF_HC3_PMON_ID 14 + +#define SRF_PE0_SAD_BUS_ID 2 +#define SRF_PE1_SAD_BUS_ID 3 +#define SRF_PE2_SAD_BUS_ID 1 +#define SRF_PE3_SAD_BUS_ID 4 +#define SRF_PE4_SAD_BUS_ID 29 +#define SRF_FLEX_PE4_SAD_BUS_ID SRF_PE4_SAD_BUS_ID +#define SRF_PE5_SAD_BUS_ID 26 +#define SRF_FLEX_PE5_SAD_BUS_ID SRF_PE5_SAD_BUS_ID +#define SRF_PE6_SAD_BUS_ID 0 // UPI0 +#define SRF_PE7_SAD_BUS_ID 5 // UPI1 +#define SRF_PE8_SAD_BUS_ID 28 // UPI2 +#define SRF_UBOXA_SAD_BUS_ID 30 +#define SRF_UBOXB_SAD_BUS_ID 31 + +const std::set srf_pcie_stacks({ + SRF_PE0_SAD_BUS_ID, + SRF_PE1_SAD_BUS_ID, + SRF_PE2_SAD_BUS_ID, + SRF_PE3_SAD_BUS_ID, + SRF_PE4_SAD_BUS_ID, + SRF_FLEX_PE4_SAD_BUS_ID, + SRF_PE5_SAD_BUS_ID, + SRF_FLEX_PE5_SAD_BUS_ID, + SRF_PE6_SAD_BUS_ID, + SRF_PE7_SAD_BUS_ID, + SRF_PE8_SAD_BUS_ID, +}); + +#define SRF_HC0_SAD_BUS_ID 8 +#define SRF_HC1_SAD_BUS_ID 12 +#define SRF_HC2_SAD_BUS_ID 20 +#define SRF_HC3_SAD_BUS_ID 16 + +const std::map srf_sad_to_pmu_id_mapping = { + { SRF_PE0_SAD_BUS_ID, SRF_PE0_PMON_ID }, + { SRF_PE1_SAD_BUS_ID, SRF_PE1_PMON_ID }, + { SRF_PE2_SAD_BUS_ID, SRF_PE2_PMON_ID }, + { SRF_PE3_SAD_BUS_ID, SRF_PE3_PMON_ID }, + { SRF_PE4_SAD_BUS_ID, SRF_PE4_PMON_ID }, + { SRF_FLEX_PE4_SAD_BUS_ID, SRF_FLEX_PE4_PMON_ID }, + { SRF_PE5_SAD_BUS_ID, SRF_PE5_PMON_ID }, + { SRF_FLEX_PE5_SAD_BUS_ID, SRF_FLEX_PE5_PMON_ID }, + { SRF_PE6_SAD_BUS_ID, SRF_PE6_PMON_ID }, + { SRF_PE7_SAD_BUS_ID, SRF_PE7_PMON_ID }, + { SRF_PE8_SAD_BUS_ID, SRF_PE8_PMON_ID }, + { SRF_HC0_SAD_BUS_ID, SRF_HC0_PMON_ID }, + { SRF_HC1_SAD_BUS_ID, SRF_HC1_PMON_ID }, + { SRF_HC2_SAD_BUS_ID, SRF_HC2_PMON_ID }, + { SRF_HC3_SAD_BUS_ID, SRF_HC3_PMON_ID }, +}; + +#define SRF_DSA_IAX_PART_NUMBER 0 +#define SRF_HQM_PART_NUMBER 5 +#define SRF_QAT_PART_NUMBER 4 + +static const std::string srf_iio_stack_names[] = { + "IIO Stack 0 - PCIe6 ", // SRF_PE6_PMON_ID 0 + "IIO Stack 1 - HCx0 ", // SRF_HC0_PMON_ID 1 + "IIO Stack 2 - PCIe2 ", // SRF_PE2_PMON_ID 2 + "IIO Stack 3 - PCIe0 ", // SRF_PE0_PMON_ID 3 + "IIO Stack 4 - PCIe1 ", // SRF_PE1_PMON_ID 4 + "IIO Stack 5 - PCIe3 ", // SRF_PE3_PMON_ID 5 + "IIO Stack 6 - HCx1 ", // SRF_HC1_PMON_ID 6 + "IIO Stack 7 - PCIe7 ", // SRF_PE7_PMON_ID 7 + "IIO Stack 8 - PCIe8 ", // SRF_PE8_PMON_ID 8 + "IIO Stack 9 - HCx3 ", // SRF_HC3_PMON_ID 9 + "IIO Stack 10 - Flex PCIe5", // SRF_FLEX_PE5_PMON_ID 10 + "IIO Stack 11 - PCIe4 ", // SRF_PE4_PMON_ID 11 + "IIO Stack 12 - PCIe5 ", // SRF_PE5_PMON_ID 12 + "IIO Stack 13 - Flex PCIe4", // SRF_FLEX_PE4_PMON_ID 13 + "IIO Stack 14 - HCx2 ", // SRF_HC2_PMON_ID 14 +}; + +struct iio_counter : public counter { + std::vector data; +}; + +extern result_content results; + +typedef struct +{ + PCM *m; + iio_counter ctr; + vector ctrs; +} iio_evt_parse_context; + +vector combine_stack_name_and_counter_names(string stack_name, const map>> &nameMap); + +string build_pci_header(const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part = -1, uint32_t level = 0); + +void build_pci_tree(vector &buffer, const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part, uint32_t level = 0); + +vector build_display(vector& iios, vector& ctrs, const PCIDB& pciDB, + const map>> &nameMap); + +std::string get_root_port_dev(const bool show_root_port, int part_id, const pcm::iio_stack *stack); + +vector build_csv(vector& iios, vector& ctrs, + const bool human_readable, const bool show_root_port, const std::string& csv_delimiter, + const map>> &nameMap); + +class IPlatformMapping { +private: + uint32_t m_sockets; + uint32_t m_model; +protected: + void probeDeviceRange(std::vector &child_pci_devs, int domain, int secondary, int subordinate); +public: + IPlatformMapping(int cpu_model, uint32_t sockets_count) : m_sockets(sockets_count), m_model(cpu_model) {} + virtual ~IPlatformMapping() {}; + static std::unique_ptr getPlatformMapping(int cpu_model, uint32_t sockets_count); + virtual bool pciTreeDiscover(std::vector& iios) = 0; + + uint32_t socketsCount() const { return m_sockets; } + uint32_t cpuId() const { return m_model; } +}; + +// Mapping for SkyLake Server. +class PurleyPlatformMapping: public IPlatformMapping { +private: + void getUboxBusNumbers(std::vector& ubox); +public: + PurleyPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} + ~PurleyPlatformMapping() = default; + bool pciTreeDiscover(std::vector& iios) override; +}; + +class IPlatformMapping10Nm: public IPlatformMapping { +private: +public: + IPlatformMapping10Nm(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} + ~IPlatformMapping10Nm() = default; + bool getSadIdRootBusMap(uint32_t socket_id, std::map& sad_id_bus_map); +}; + +// Mapping for IceLake Server. +class WhitleyPlatformMapping: public IPlatformMapping10Nm { +private: + const bool icx_d; + const std::map& sad_to_pmu_id_mapping; + const std::string * iio_stack_names; +public: + WhitleyPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count), + icx_d(PCM::getInstance()->getCPUFamilyModelFromCPUID() == PCM::ICX_D), + sad_to_pmu_id_mapping(icx_d ? icx_d_sad_to_pmu_id_mapping : icx_sad_to_pmu_id_mapping), + iio_stack_names(icx_d ? icx_d_iio_stack_names : icx_iio_stack_names) + { + } + ~WhitleyPlatformMapping() = default; + bool pciTreeDiscover(std::vector& iios) override; +}; + +// Mapping for Snowridge. +class JacobsvillePlatformMapping: public IPlatformMapping10Nm { +private: +public: + JacobsvillePlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count) {} + ~JacobsvillePlatformMapping() = default; + bool pciTreeDiscover(std::vector& iios) override; + bool JacobsvilleAccelerators(const std::pair& sad_id_bus_pair, struct iio_stack& stack); +}; + +class EagleStreamPlatformMapping: public IPlatformMapping +{ +private: + bool getRootBuses(std::map> &root_buses); + bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool eagleStreamDmiStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool eagleStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool eagleStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool isDmiStack(int unit); + bool isPcieStack(int unit); + bool isDinoStack(int unit); + std::uint32_t m_chop; + EagleStreamSupportedTypes m_es_type; +public: + EagleStreamPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count), m_chop(0), m_es_type(estype::esInvalid) {} + ~EagleStreamPlatformMapping() = default; + bool setChopValue(); + bool isXccPlatform() const { return m_chop == kXccChop; } + + const std::uint32_t kXccChop = 0b11; + const std::uint32_t kMccChop = 0b01; + + bool pciTreeDiscover(std::vector& iios) override; +}; + +class LoganvillePlatform: public IPlatformMapping10Nm { +private: + bool loganvillePchDsaPciStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); + bool loganvilleDlbStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); + bool loganvilleNacStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); +public: + LoganvillePlatform(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count) {} + ~LoganvillePlatform() = default; + bool pciTreeDiscover(std::vector& iios) override; +}; + +class Xeon6thNextGenPlatform: public IPlatformMapping { +private: + bool getRootBuses(std::map> &root_buses); +protected: + virtual bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) = 0; +public: + Xeon6thNextGenPlatform(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} + virtual ~Xeon6thNextGenPlatform() = default; + + bool pciTreeDiscover(std::vector& iios) override; +}; + +class BirchStreamPlatform: public Xeon6thNextGenPlatform { +private: + bool isPcieStack(int unit); + bool isRootHcStack(int unit); + bool isPartHcStack(int unit); + bool isUboxStack(int unit); + + bool birchStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool birchStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); +protected: + bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) override; +public: + BirchStreamPlatform(int cpu_model, uint32_t sockets_count) : Xeon6thNextGenPlatform(cpu_model, sockets_count) {} + ~BirchStreamPlatform() = default; +}; + +class KasseyvillePlatform: public Xeon6thNextGenPlatform { +private: + bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); + bool isUboxStack(int unit) + { + return SRF_UBOXA_SAD_BUS_ID == unit || SRF_UBOXB_SAD_BUS_ID == unit; + } +public: + KasseyvillePlatform(int cpu_model, uint32_t sockets_count) : Xeon6thNextGenPlatform(cpu_model, sockets_count) {} + ~KasseyvillePlatform() = default; +}; + +int iio_evt_parse_handler(evt_cb_type cb_type, void *cb_ctx, counter &base_ctr, std::map &ofm, std::string key, uint64 numValue); + +result_content get_IIO_Samples(PCM *m, const std::vector& iios, const struct iio_counter & ctr, uint32_t delay_ms); + +void collect_data(PCM *m, const double delay, vector& iios, vector& ctrs); + +void initializeIIOStructure( std::vector& iios ); + +void fillOpcodeFieldMapForPCIeEvents(map& opcodeFieldMap); + +typedef map>> PCIeEventNameMap_t; + +void setupPCIeEventContextAndNameMap( iio_evt_parse_context& evt_ctx, PCIeEventNameMap_t& nameMap); + +bool initializeIIOCounters( std::vector& iios, iio_evt_parse_context& evt_ctx, PCIeEventNameMap_t& nameMap ); + diff --git a/src/pcm-iio.cpp b/src/pcm-iio.cpp index 381e09d4..e4726bee 100644 --- a/src/pcm-iio.cpp +++ b/src/pcm-iio.cpp @@ -4,2102 +4,8 @@ // written by Patrick Lu, // Aaron Cruz // and others -#include "cpucounters.h" -#ifdef _MSC_VER - #include - #include "windows/windriver.h" -#else - #include -#endif - -#include -#include -#include -#include -#include // std::length_error -#include -#include -#include -#include - -#ifdef _MSC_VER - #include "freegetopt/getopt.h" -#endif - -#include "lspci.h" -#include "utils.h" -using namespace std; -using namespace pcm; - -#define PCM_DELAY_DEFAULT 3.0 // in seconds - -#define QAT_DID 0x18DA -#define NIS_DID 0x18D1 -#define HQM_DID 0x270B - -#define GRR_QAT_VRP_DID 0x5789 // Virtual Root Port to integrated QuickAssist (GRR QAT) -#define GRR_NIS_VRP_DID 0x5788 // VRP to Network Interface and Scheduler (GRR NIS) - -#define ROOT_BUSES_OFFSET 0xCC -#define ROOT_BUSES_OFFSET_2 0xD0 - -#define SKX_SOCKETID_UBOX_DID 0x2014 -#define SKX_UBOX_DEVICE_NUM 0x08 -#define SKX_UBOX_FUNCTION_NUM 0x02 -#define SKX_BUS_NUM_STRIDE 8 -//the below LNID and GID applies to Skylake Server -#define SKX_UNC_SOCKETID_UBOX_LNID_OFFSET 0xC0 -#define SKX_UNC_SOCKETID_UBOX_GID_OFFSET 0xD4 - -static const std::string iio_stack_names[6] = { - "IIO Stack 0 - CBDMA/DMI ", - "IIO Stack 1 - PCIe0 ", - "IIO Stack 2 - PCIe1 ", - "IIO Stack 3 - PCIe2 ", - "IIO Stack 4 - MCP0 ", - "IIO Stack 5 - MCP1 " -}; - -static const std::string skx_iio_stack_names[6] = { - "IIO Stack 0 - CBDMA/DMI ", - "IIO Stack 1 - PCIe0 ", - "IIO Stack 2 - PCIe1 ", - "IIO Stack 3 - PCIe2 ", - "IIO Stack 4 - MCP0 ", - "IIO Stack 5 - MCP1 " -}; - -static const std::string icx_iio_stack_names[6] = { - "IIO Stack 0 - PCIe0 ", - "IIO Stack 1 - PCIe1 ", - "IIO Stack 2 - MCP ", - "IIO Stack 3 - PCIe2 ", - "IIO Stack 4 - PCIe3 ", - "IIO Stack 5 - CBDMA/DMI " -}; - -static const std::string icx_d_iio_stack_names[6] = { - "IIO Stack 0 - MCP ", - "IIO Stack 1 - PCIe0 ", - "IIO Stack 2 - CBDMA/DMI ", - "IIO Stack 3 - PCIe2 ", - "IIO Stack 4 - PCIe3 ", - "IIO Stack 5 - PCIe1 " -}; - -static const std::string snr_iio_stack_names[5] = { - "IIO Stack 0 - QAT ", - "IIO Stack 1 - CBDMA/DMI ", - "IIO Stack 2 - NIS ", - "IIO Stack 3 - HQM ", - "IIO Stack 4 - PCIe " -}; - -#define ICX_CBDMA_DMI_SAD_ID 0 -#define ICX_MCP_SAD_ID 3 - -#define ICX_PCH_PART_ID 0 -#define ICX_CBDMA_PART_ID 3 - -#define SNR_ICX_SAD_CONTROL_CFG_OFFSET 0x3F4 -#define SNR_ICX_MESH2IIO_MMAP_DID 0x09A2 - -#define ICX_VMD_PCI_DEVNO 0x00 -#define ICX_VMD_PCI_FUNCNO 0x05 - -static const std::map icx_sad_to_pmu_id_mapping = { - { ICX_CBDMA_DMI_SAD_ID, 5 }, - { 1, 0 }, - { 2, 1 }, - { ICX_MCP_SAD_ID, 2 }, - { 4, 3 }, - { 5, 4 } -}; - -static const std::map icx_d_sad_to_pmu_id_mapping = { - { ICX_CBDMA_DMI_SAD_ID, 2 }, - { 1, 5 }, - { 2, 1 }, - { ICX_MCP_SAD_ID, 0 }, - { 4, 3 }, - { 5, 4 } -}; - -#define SNR_ACCELERATOR_PART_ID 4 - -#define SNR_ROOT_PORT_A_DID 0x334A - -#define SNR_CBDMA_DMI_SAD_ID 0 -#define SNR_PCIE_GEN3_SAD_ID 1 -#define SNR_HQM_SAD_ID 2 -#define SNR_NIS_SAD_ID 3 -#define SNR_QAT_SAD_ID 4 - -static const std::map snr_sad_to_pmu_id_mapping = { - { SNR_CBDMA_DMI_SAD_ID, 1 }, - { SNR_PCIE_GEN3_SAD_ID, 4 }, - { SNR_HQM_SAD_ID , 3 }, - { SNR_NIS_SAD_ID , 2 }, - { SNR_QAT_SAD_ID , 0 } -}; - -#define HQMV2_DID 0x2710 // Hardware Queue Manager v2 -#define HQMV25_DID 0x2714 // Hardware Queue Manager v2.5 -#define DSA_DID 0x0b25 // Data Streaming Accelerator (DSA) -#define IAX_DID 0x0cfe // In-Memory Database Analytics Accelerator (IAX) -#define QATV2_DID 0x4940 // QuickAssist (CPM) v2 - -#define SPR_DMI_PART_ID 7 -#define SPR_XCC_HQM_PART_ID 5 -#define SPR_MCC_HQM_PART_ID 4 -#define SPR_XCC_QAT_PART_ID 4 -#define SPR_MCC_QAT_PART_ID 5 -#define SPR_SAD_CONTROL_CFG_OFFSET SNR_ICX_SAD_CONTROL_CFG_OFFSET - -#define SPR_PCU_CR3_DID 0x325b -#define SPR_PCU_CR3_REG_DEVICE 0x1e -#define SPR_PCU_CR3_REG_FUNCTION 0x03 -#define SPR_CAPID4_OFFSET 0x94 -#define SPR_CAPID4_GET_PHYSICAL_CHOP(capid4) ((capid4 >> 6) & 3) -#define SPR_PHYSICAL_CHOP_XCC 0b11 -#define SPR_PHYSICAL_CHOP_MCC 0b01 - -#define SPR_XCC_DMI_PMON_ID 1 -#define SPR_XCC_PCIE_GEN5_0_PMON_ID 2 -#define SPR_XCC_PCIE_GEN5_1_PMON_ID 4 -#define SPR_XCC_PCIE_GEN5_2_PMON_ID 6 -#define SPR_XCC_PCIE_GEN5_3_PMON_ID 7 -#define SPR_XCC_PCIE_GEN5_4_PMON_ID 9 -#define SPR_XCC_IDX0_PMON_ID 0 -#define SPR_XCC_IDX1_PMON_ID 3 -#define SPR_XCC_IDX2_PMON_ID 5 -#define SPR_XCC_IDX3_PMON_ID 8 - -const std::map spr_xcc_sad_to_pmu_id_mapping = { - { 0, SPR_XCC_DMI_PMON_ID }, - { 1, SPR_XCC_PCIE_GEN5_0_PMON_ID }, - { 2, SPR_XCC_PCIE_GEN5_1_PMON_ID }, - { 3, SPR_XCC_PCIE_GEN5_2_PMON_ID }, - { 4, SPR_XCC_PCIE_GEN5_3_PMON_ID }, - { 5, SPR_XCC_PCIE_GEN5_4_PMON_ID }, - { 8, SPR_XCC_IDX0_PMON_ID }, - { 9, SPR_XCC_IDX1_PMON_ID }, - { 10, SPR_XCC_IDX2_PMON_ID }, - { 11, SPR_XCC_IDX3_PMON_ID } -}; - -#define SPR_MCC_DMI_PMON_ID 10 -#define SPR_MCC_PCIE_GEN5_0_PMON_ID 0 // assumption -#define SPR_MCC_PCIE_GEN5_1_PMON_ID 1 -#define SPR_MCC_PCIE_GEN5_2_PMON_ID 2 -#define SPR_MCC_PCIE_GEN5_3_PMON_ID 4 // assumption -#define SPR_MCC_PCIE_GEN5_4_PMON_ID 5 -#define SPR_MCC_IDX0_PMON_ID 3 - -const std::map spr_mcc_sad_to_pmu_id_mapping = { - { 0, SPR_MCC_PCIE_GEN5_0_PMON_ID }, - { 1, SPR_MCC_PCIE_GEN5_1_PMON_ID }, - { 2, SPR_MCC_PCIE_GEN5_2_PMON_ID }, - { 3, SPR_MCC_DMI_PMON_ID }, - { 4, SPR_MCC_PCIE_GEN5_3_PMON_ID }, - { 5, SPR_MCC_PCIE_GEN5_4_PMON_ID }, - { 8, SPR_MCC_IDX0_PMON_ID }, -}; - -static const std::string spr_xcc_iio_stack_names[] = { - "IIO Stack 0 - IDX0 ", - "IIO Stack 1 - DMI ", - "IIO Stack 2 - PCIe0 ", - "IIO Stack 3 - IDX1 ", - "IIO Stack 4 - PCIe1 ", - "IIO Stack 5 - IDX2 ", - "IIO Stack 6 - PCIe2 ", - "IIO Stack 7 - PCIe3", - "IIO Stack 8 - IDX3 ", - "IIO Stack 9 - PCIe4", - "IIO Stack 10 - NONE ", - "IIO Stack 11 - NONE ", -}; - -/* - * SPR MCC has 7 I/O stacks but PMON block for DMI has ID number 10. - * And just to follow such enumeration keep Stack 10 for DMI. - */ -static const std::string spr_mcc_iio_stack_names[] = { - "IIO Stack 0 - PCIe0 ", - "IIO Stack 1 - PCIe1 ", - "IIO Stack 2 - PCIe2 ", - "IIO Stack 3 - IDX0 ", - "IIO Stack 4 - PCIe3 ", - "IIO Stack 5 - PCIe4 ", - "IIO Stack 6 - NONE ", - "IIO Stack 7 - NONE ", - "IIO Stack 8 - NONE ", - "IIO Stack 9 - NONE ", - "IIO Stack 10 - DMI ", -}; - -// MS2IOSF stack IDs in CHA notation -#define GRR_PCH_DSA_GEN4_SAD_ID 0 -#define GRR_DLB_SAD_ID 1 -#define GRR_NIS_QAT_SAD_ID 2 - -#define GRR_PCH_DSA_GEN4_PMON_ID 2 -#define GRR_DLB_PMON_ID 1 -#define GRR_NIS_QAT_PMON_ID 0 - -// Stack 0 contains PCH, DSA and CPU PCIe Gen4 Complex -const std::map grr_sad_to_pmu_id_mapping = { - { GRR_PCH_DSA_GEN4_SAD_ID, GRR_PCH_DSA_GEN4_PMON_ID }, - { GRR_DLB_SAD_ID, GRR_DLB_PMON_ID }, - { GRR_NIS_QAT_SAD_ID, GRR_NIS_QAT_PMON_ID }, -}; - -#define GRR_DLB_PART_ID 0 -#define GRR_NIS_PART_ID 0 -#define GRR_QAT_PART_ID 1 - -static const std::string grr_iio_stack_names[3] = { - "IIO Stack 0 - NIS/QAT ", - "IIO Stack 1 - HQM ", - "IIO Stack 2 - PCH/DSA/PCIe " -}; - -#define EMR_DMI_PMON_ID 7 -#define EMR_PCIE_GEN5_0_PMON_ID 1 -#define EMR_PCIE_GEN5_1_PMON_ID 2 -#define EMR_PCIE_GEN5_2_PMON_ID 3 -#define EMR_PCIE_GEN5_3_PMON_ID 8 -#define EMR_PCIE_GEN5_4_PMON_ID 6 -#define EMR_IDX0_PMON_ID 0 -#define EMR_IDX1_PMON_ID 4 -#define EMR_IDX2_PMON_ID 5 -#define EMR_IDX3_PMON_ID 9 - -const std::map emr_sad_to_pmu_id_mapping = { - { 0, EMR_DMI_PMON_ID }, - { 1, EMR_PCIE_GEN5_0_PMON_ID }, - { 2, EMR_PCIE_GEN5_1_PMON_ID }, - { 3, EMR_PCIE_GEN5_2_PMON_ID }, - { 4, EMR_PCIE_GEN5_3_PMON_ID }, - { 5, EMR_PCIE_GEN5_4_PMON_ID }, - { 8, EMR_IDX0_PMON_ID }, - { 9, EMR_IDX1_PMON_ID }, - { 10, EMR_IDX2_PMON_ID }, - { 11, EMR_IDX3_PMON_ID } -}; - -static const std::string emr_iio_stack_names[] = { - "IIO Stack 0 - IDX0 ", - "IIO Stack 1 - PCIe3 ", - "IIO Stack 2 - PCIe0 ", - "IIO Stack 3 - IDX1 ", - "IIO Stack 4 - PCIe1 ", - "IIO Stack 5 - IDX2 ", - "IIO Stack 6 - PCIe2 ", - "IIO Stack 7 - DMI", - "IIO Stack 8 - IDX3 ", - "IIO Stack 9 - PCIe4", - "IIO Stack 10 - NONE ", - "IIO Stack 11 - NONE ", -}; - -enum EagleStreamPlatformStacks -{ - esDMI = 0, - esPCIe0, - esPCIe1, - esPCIe2, - esPCIe3, - esPCIe4, - esDINO0, - esDINO1, - esDINO2, - esDINO3, - esEndOfList -}; - -const std::vector spr_xcc_stacks_enumeration = { - /* esDMI */ SPR_XCC_DMI_PMON_ID, - /* esPCIe0 */ SPR_XCC_PCIE_GEN5_0_PMON_ID, - /* esPCIe1 */ SPR_XCC_PCIE_GEN5_1_PMON_ID, - /* esPCIe2 */ SPR_XCC_PCIE_GEN5_2_PMON_ID, - /* esPCIe3 */ SPR_XCC_PCIE_GEN5_3_PMON_ID, - /* esPCIe4 */ SPR_XCC_PCIE_GEN5_4_PMON_ID, - /* esDINO0 */ SPR_XCC_IDX0_PMON_ID, - /* esDINO1 */ SPR_XCC_IDX1_PMON_ID, - /* esDINO2 */ SPR_XCC_IDX2_PMON_ID, - /* esDINO3 */ SPR_XCC_IDX3_PMON_ID, -}; - -const std::vector spr_mcc_stacks_enumeration = { - /* esDMI */ SPR_MCC_DMI_PMON_ID, - /* esPCIe0 */ SPR_MCC_PCIE_GEN5_0_PMON_ID, - /* esPCIe1 */ SPR_MCC_PCIE_GEN5_1_PMON_ID, - /* esPCIe2 */ SPR_MCC_PCIE_GEN5_2_PMON_ID, - /* esPCIe3 */ SPR_MCC_PCIE_GEN5_3_PMON_ID, - /* esPCIe4 */ SPR_MCC_PCIE_GEN5_4_PMON_ID, - /* esDINO0 */ SPR_MCC_IDX0_PMON_ID, -}; - -const std::vector emr_stacks_enumeration = { - /* esDMI */ EMR_DMI_PMON_ID, - /* esPCIe0 */ EMR_PCIE_GEN5_0_PMON_ID, - /* esPCIe1 */ EMR_PCIE_GEN5_1_PMON_ID, - /* esPCIe2 */ EMR_PCIE_GEN5_2_PMON_ID, - /* esPCIe3 */ EMR_PCIE_GEN5_3_PMON_ID, - /* esPCIe4 */ EMR_PCIE_GEN5_4_PMON_ID, - /* esDINO0 */ EMR_IDX0_PMON_ID, - /* esDINO1 */ EMR_IDX1_PMON_ID, - /* esDINO2 */ EMR_IDX2_PMON_ID, - /* esDINO3 */ EMR_IDX3_PMON_ID, -}; - -enum class EagleStreamSupportedTypes -{ - esInvalid = -1, - esSprXcc, - esSprMcc, - esEmrXcc -}; - -typedef EagleStreamSupportedTypes estype; - -const std::map> es_stacks_enumeration = { - {estype::esSprXcc, spr_xcc_stacks_enumeration}, - {estype::esSprMcc, spr_mcc_stacks_enumeration}, - {estype::esEmrXcc, emr_stacks_enumeration }, -}; - -const std::map es_stack_names = { - {estype::esSprXcc, spr_xcc_iio_stack_names}, - {estype::esSprMcc, spr_mcc_iio_stack_names}, - {estype::esEmrXcc, emr_iio_stack_names }, -}; - -const std::map> es_sad_to_pmu_id_mapping = { - {estype::esSprXcc, spr_xcc_sad_to_pmu_id_mapping}, - {estype::esSprMcc, spr_mcc_sad_to_pmu_id_mapping}, - {estype::esEmrXcc, emr_sad_to_pmu_id_mapping }, -}; - -#define SRF_PE0_PMON_ID 3 -#define SRF_PE1_PMON_ID 4 -#define SRF_PE2_PMON_ID 2 -#define SRF_PE3_PMON_ID 5 -/* - * There are platform configuration when FlexUPI stacks (stacks 5 and 6) are enabled as - * PCIe stack and PCIe ports are disabled (ports 2 and 3) and vice sersa. See details here: - * In these cases the PMON IDs are different. - * So, defines with _FLEX_ are applicable for cases when FlexUPI stacks - * are working as PCIe ports. - */ -#define SRF_PE4_PMON_ID 11 -#define SRF_FLEX_PE4_PMON_ID 13 -#define SRF_PE5_PMON_ID 12 -#define SRF_FLEX_PE5_PMON_ID 10 - -#define SRF_PE6_PMON_ID 0 -#define SRF_PE7_PMON_ID 7 -#define SRF_PE8_PMON_ID 8 -#define SRF_HC0_PMON_ID 1 -#define SRF_HC1_PMON_ID 6 -#define SRF_HC2_PMON_ID 9 -#define SRF_HC3_PMON_ID 14 - -#define SRF_PE0_SAD_BUS_ID 2 -#define SRF_PE1_SAD_BUS_ID 3 -#define SRF_PE2_SAD_BUS_ID 1 -#define SRF_PE3_SAD_BUS_ID 4 -#define SRF_PE4_SAD_BUS_ID 29 -#define SRF_FLEX_PE4_SAD_BUS_ID SRF_PE4_SAD_BUS_ID -#define SRF_PE5_SAD_BUS_ID 26 -#define SRF_FLEX_PE5_SAD_BUS_ID SRF_PE5_SAD_BUS_ID -#define SRF_PE6_SAD_BUS_ID 0 // UPI0 -#define SRF_PE7_SAD_BUS_ID 5 // UPI1 -#define SRF_PE8_SAD_BUS_ID 28 // UPI2 -#define SRF_UBOXA_SAD_BUS_ID 30 -#define SRF_UBOXB_SAD_BUS_ID 31 - -const std::set srf_pcie_stacks({ - SRF_PE0_SAD_BUS_ID, - SRF_PE1_SAD_BUS_ID, - SRF_PE2_SAD_BUS_ID, - SRF_PE3_SAD_BUS_ID, - SRF_PE4_SAD_BUS_ID, - SRF_FLEX_PE4_SAD_BUS_ID, - SRF_PE5_SAD_BUS_ID, - SRF_FLEX_PE5_SAD_BUS_ID, - SRF_PE6_SAD_BUS_ID, - SRF_PE7_SAD_BUS_ID, - SRF_PE8_SAD_BUS_ID, -}); - -#define SRF_HC0_SAD_BUS_ID 8 -#define SRF_HC1_SAD_BUS_ID 12 -#define SRF_HC2_SAD_BUS_ID 20 -#define SRF_HC3_SAD_BUS_ID 16 - -const std::map srf_sad_to_pmu_id_mapping = { - { SRF_PE0_SAD_BUS_ID, SRF_PE0_PMON_ID }, - { SRF_PE1_SAD_BUS_ID, SRF_PE1_PMON_ID }, - { SRF_PE2_SAD_BUS_ID, SRF_PE2_PMON_ID }, - { SRF_PE3_SAD_BUS_ID, SRF_PE3_PMON_ID }, - { SRF_PE4_SAD_BUS_ID, SRF_PE4_PMON_ID }, - { SRF_FLEX_PE4_SAD_BUS_ID, SRF_FLEX_PE4_PMON_ID }, - { SRF_PE5_SAD_BUS_ID, SRF_PE5_PMON_ID }, - { SRF_FLEX_PE5_SAD_BUS_ID, SRF_FLEX_PE5_PMON_ID }, - { SRF_PE6_SAD_BUS_ID, SRF_PE6_PMON_ID }, - { SRF_PE7_SAD_BUS_ID, SRF_PE7_PMON_ID }, - { SRF_PE8_SAD_BUS_ID, SRF_PE8_PMON_ID }, - { SRF_HC0_SAD_BUS_ID, SRF_HC0_PMON_ID }, - { SRF_HC1_SAD_BUS_ID, SRF_HC1_PMON_ID }, - { SRF_HC2_SAD_BUS_ID, SRF_HC2_PMON_ID }, - { SRF_HC3_SAD_BUS_ID, SRF_HC3_PMON_ID }, -}; - -#define SRF_DSA_IAX_PART_NUMBER 0 -#define SRF_HQM_PART_NUMBER 5 -#define SRF_QAT_PART_NUMBER 4 - -static const std::string srf_iio_stack_names[] = { - "IIO Stack 0 - PCIe6 ", // SRF_PE6_PMON_ID 0 - "IIO Stack 1 - HCx0 ", // SRF_HC0_PMON_ID 1 - "IIO Stack 2 - PCIe2 ", // SRF_PE2_PMON_ID 2 - "IIO Stack 3 - PCIe0 ", // SRF_PE0_PMON_ID 3 - "IIO Stack 4 - PCIe1 ", // SRF_PE1_PMON_ID 4 - "IIO Stack 5 - PCIe3 ", // SRF_PE3_PMON_ID 5 - "IIO Stack 6 - HCx1 ", // SRF_HC1_PMON_ID 6 - "IIO Stack 7 - PCIe7 ", // SRF_PE7_PMON_ID 7 - "IIO Stack 8 - PCIe8 ", // SRF_PE8_PMON_ID 8 - "IIO Stack 9 - HCx3 ", // SRF_HC3_PMON_ID 9 - "IIO Stack 10 - Flex PCIe5", // SRF_FLEX_PE5_PMON_ID 10 - "IIO Stack 11 - PCIe4 ", // SRF_PE4_PMON_ID 11 - "IIO Stack 12 - PCIe5 ", // SRF_PE5_PMON_ID 12 - "IIO Stack 13 - Flex PCIe4", // SRF_FLEX_PE4_PMON_ID 13 - "IIO Stack 14 - HCx2 ", // SRF_HC2_PMON_ID 14 -}; - -const std::string generate_stack_str(const int unit) -{ - static const std::string stack_str = "Stack "; - std::stringstream ss; - ss << stack_str << std::setw(2) << unit; - return ss.str(); -} - -struct iio_counter : public counter { - std::vector data; -}; - -result_content results; - -typedef struct -{ - PCM *m; - iio_counter ctr; - vector ctrs; -} iio_evt_parse_context; - -vector combine_stack_name_and_counter_names(string stack_name, const map>> &nameMap) -{ - vector v; - vector tmp(nameMap.size()); - v.push_back(stack_name); - for (std::map>>::const_iterator iunit = nameMap.begin(); iunit != nameMap.end(); ++iunit) { - string h_name = iunit->first; - int h_id = (iunit->second).first; - tmp[h_id] = h_name; - //cout << "h_id:" << h_id << " name:" << h_name << "\n"; - } - //XXX: How to simplify and just combine tmp & v? - for (uint32_t i = 0; i < nameMap.size(); i++) { - v.push_back(tmp[i]); - } - return v; -} - -string build_pci_header(const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part = -1, uint32_t level = 0) -{ - string s = "|"; - char bdf_buf[32]; - char speed_buf[10]; - char vid_did_buf[10]; - char device_name_buf[128]; - - snprintf(bdf_buf, sizeof(bdf_buf), "%04X:%02X:%02X.%1d", p.bdf.domainno, p.bdf.busno, p.bdf.devno, p.bdf.funcno); - snprintf(speed_buf, sizeof(speed_buf), "Gen%1d x%-2d", p.link_speed, p.link_width); - snprintf(vid_did_buf, sizeof(vid_did_buf), "%04X:%04X", p.vendor_id, p.device_id); - snprintf(device_name_buf, sizeof(device_name_buf), "%s %s", - (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor", - (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device" - ); - s += bdf_buf; - s += '|'; - s += speed_buf; - s += '|'; - s += vid_did_buf; - s += " "; - s += device_name_buf; - - if (!p.parts_no.empty()) { - s += "; Part: "; - for (auto& part : p.parts_no) { - s += std::to_string(part) + ", "; - } - s += "\b\b "; - } - - /* row with data */ - if (part >= 0) { - s.insert(1,"P" + std::to_string(part) + " "); - s += std::string(column_width - (s.size()-1), ' '); - } else { /* row without data, just child pci device */ - s.insert(0, std::string(4*level, ' ')); - } - - return s; -} - -void build_pci_tree(vector &buffer, const PCIDB & pciDB, uint32_t column_width, const struct pci &p, int part, uint32_t level = 0) -{ - string row; - for (const auto& child : p.child_pci_devs) { - row = build_pci_header(pciDB, column_width, child, part, level); - buffer.push_back(row); - if (child.hasChildDevices()) - build_pci_tree(buffer, pciDB, column_width, child, part, level + 1); - } -} - -vector build_display(vector& iios, vector& ctrs, const PCIDB& pciDB, - const map>> &nameMap) -{ - vector buffer; - vector headers; - vector data; - uint64_t header_width; - string row; - for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { - buffer.push_back("Socket" + std::to_string(socket->socket_id)); - for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { - auto stack_id = stack->iio_unit_id; - headers = combine_stack_name_and_counter_names(stack->stack_name, nameMap); - //Print first row - row = std::accumulate(headers.begin(), headers.end(), string(" "), a_header_footer); - header_width = row.size(); - buffer.push_back(row); - //Print a_title - row = std::accumulate(headers.begin(), headers.end(), string("|"), a_title); - buffer.push_back(row); - //Print deliminator - row = std::accumulate(headers.begin(), headers.end(), string("|"), a_header_footer); - buffer.push_back(row); - //Print data - std::map> v_sort; - //re-organize data collection to be row wise - for (std::vector::iterator counter = ctrs.begin(); counter != ctrs.end(); ++counter) { - v_sort[counter->v_id][counter->h_id] = &(*counter); - } - for (std::map>::const_iterator vunit = v_sort.cbegin(); vunit != v_sort.cend(); ++vunit) { - map h_array = vunit->second; - uint32_t vv_id = vunit->first; - vector h_data; - string v_name = h_array[0]->v_event_name; - for (map::const_iterator hunit = h_array.cbegin(); hunit != h_array.cend(); ++hunit) { - uint32_t hh_id = hunit->first; - uint64_t raw_data = hunit->second->data[0][socket->socket_id][stack_id][std::pair(hh_id,vv_id)]; - h_data.push_back(raw_data); - } - data = prepare_data(h_data, headers); - row = "| " + v_name; - row += string(abs(int(headers[0].size() - (row.size() - 1))), ' '); - row += std::accumulate(data.begin(), data.end(), string("|"), a_data); - buffer.push_back(row); - } - //Print deliminator - row = std::accumulate(headers.begin(), headers.end(), string("|"), a_header_footer); - buffer.push_back(row); - //Print pcie devices - for (const auto& part : stack->parts) { - uint8_t level = 1; - for (const auto& pci_device : part.child_pci_devs) { - row = build_pci_header(pciDB, (uint32_t)header_width, pci_device, -1, level); - buffer.push_back(row); - if (pci_device.hasChildDevices()) { - build_pci_tree(buffer, pciDB, (uint32_t)header_width, pci_device, -1, level + 1); - } else if (pci_device.header_type == 1) { - level++; - } - } - } - //Print footer - row = std::accumulate(headers.begin(), headers.end(), string(" "), a_header_footer); - buffer.push_back(row); - } - } - return buffer; -} - -std::string get_root_port_dev(const bool show_root_port, int part_id, const pcm::iio_stack *stack) -{ - char tmp[9] = " "; - std::string rp_pci; - - if (!show_root_port) - return rp_pci; - - for (auto part = stack->parts.begin(); part != stack->parts.end(); part = std::next(part)) - { - if (part->part_id == part_id) - { - std::snprintf(tmp, sizeof(tmp), "%02x:%02x.%x", part->root_pci_dev.bdf.busno, - part->root_pci_dev.bdf.devno, part->root_pci_dev.bdf.funcno); - break; - } - } - - rp_pci.append(tmp); - return rp_pci; - -} - -vector build_csv(vector& iios, vector& ctrs, - const bool human_readable, const bool show_root_port, const std::string& csv_delimiter, - const map>> &nameMap) -{ - vector result; - vector current_row; - auto header = combine_stack_name_and_counter_names("Part", nameMap); - header.insert(header.begin(), "Name"); - if (show_root_port) - header.insert(header.begin(), "Root Port"); - header.insert(header.begin(), "Socket"); - auto insertDateTime = [&csv_delimiter](vector & out, CsvOutputType type) { - std::string dateTime; - printDateForCSV(type, csv_delimiter, &dateTime); - // remove last delimiter - dateTime.pop_back(); - out.insert(out.begin(), dateTime); - }; - insertDateTime(header, CsvOutputType::Header2); - result.push_back(build_csv_row(header, csv_delimiter)); - std::map> v_sort; - //re-organize data collection to be row wise - size_t max_name_width = 0; - for (std::vector::iterator counter = ctrs.begin(); counter != ctrs.end(); ++counter) { - v_sort[counter->v_id][counter->h_id] = &(*counter); - max_name_width = (std::max)(max_name_width, counter->v_event_name.size()); - } - - for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { - for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { - const std::string socket_name = "Socket" + std::to_string(socket->socket_id); - - std::string stack_name = stack->stack_name; - if (!human_readable) { - stack_name.erase(stack_name.find_last_not_of(' ') + 1); - } - - const uint32_t stack_id = stack->iio_unit_id; - //Print data - int part_id; - std::map>::const_iterator vunit; - for (vunit = v_sort.cbegin(), part_id = 0; - vunit != v_sort.cend(); ++vunit, ++part_id) { - map h_array = vunit->second; - uint32_t vv_id = vunit->first; - vector h_data; - string v_name = h_array[0]->v_event_name; - if (human_readable) { - v_name += string(max_name_width - (v_name.size()), ' '); - } - - current_row.clear(); - current_row.push_back(socket_name); - if (show_root_port) { - auto pci_dev = get_root_port_dev(show_root_port, part_id, &(*stack)); - current_row.push_back(pci_dev); - } - current_row.push_back(stack_name); - current_row.push_back(v_name); - for (map::const_iterator hunit = h_array.cbegin(); hunit != h_array.cend(); ++hunit) { - uint32_t hh_id = hunit->first; - uint64_t raw_data = hunit->second->data[0][socket->socket_id][stack_id][std::pair(hh_id,vv_id)]; - current_row.push_back(human_readable ? unit_format(raw_data) : std::to_string(raw_data)); - } - insertDateTime(current_row, CsvOutputType::Data); - result.push_back(build_csv_row(current_row, csv_delimiter)); - } - } - } - return result; -} - -class IPlatformMapping { -private: - uint32_t m_sockets; - uint32_t m_model; -protected: - void probeDeviceRange(std::vector &child_pci_devs, int domain, int secondary, int subordinate); -public: - IPlatformMapping(int cpu_model, uint32_t sockets_count) : m_sockets(sockets_count), m_model(cpu_model) {} - virtual ~IPlatformMapping() {}; - static std::unique_ptr getPlatformMapping(int cpu_model, uint32_t sockets_count); - virtual bool pciTreeDiscover(std::vector& iios) = 0; - - uint32_t socketsCount() const { return m_sockets; } - uint32_t cpuId() const { return m_model; } -}; - -void IPlatformMapping::probeDeviceRange(std::vector &pci_devs, int domain, int secondary, int subordinate) -{ - for (uint8_t bus = secondary; int(bus) <= subordinate; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_dev; - child_dev.bdf.domainno = domain; - child_dev.bdf.busno = bus; - child_dev.bdf.devno = device; - child_dev.bdf.funcno = function; - if (probe_pci(&child_dev)) { - if (secondary < child_dev.secondary_bus_number && subordinate < child_dev.subordinate_bus_number) { - probeDeviceRange(child_dev.child_pci_devs, domain, child_dev.secondary_bus_number, child_dev.subordinate_bus_number); - } - pci_devs.push_back(child_dev); - } - } - } - } -} - -// Mapping for SkyLake Server. -class PurleyPlatformMapping: public IPlatformMapping { -private: - void getUboxBusNumbers(std::vector& ubox); -public: - PurleyPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} - ~PurleyPlatformMapping() = default; - bool pciTreeDiscover(std::vector& iios) override; -}; - -void PurleyPlatformMapping::getUboxBusNumbers(std::vector& ubox) -{ - for (uint16_t bus = 0; bus < 256; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci pci_dev; - pci_dev.bdf.busno = (uint8_t)bus; - pci_dev.bdf.devno = device; - pci_dev.bdf.funcno = function; - if (probe_pci(&pci_dev)) { - if (pci_dev.isIntelDevice() && (pci_dev.device_id == SKX_SOCKETID_UBOX_DID)) { - ubox.push_back(bus); - } - } - } - } - } -} - -bool PurleyPlatformMapping::pciTreeDiscover(std::vector& iios) -{ - std::vector ubox; - getUboxBusNumbers(ubox); - if (ubox.empty()) { - cerr << "UBOXs were not found! Program aborted" << endl; - return false; - } - - for (uint32_t socket_id = 0; socket_id < socketsCount(); socket_id++) { - if (!PciHandleType::exists(0, ubox[socket_id], SKX_UBOX_DEVICE_NUM, SKX_UBOX_FUNCTION_NUM)) { - cerr << "No access to PCICFG\n" << endl; - return false; - } - uint64 cpubusno = 0; - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = socket_id; - PciHandleType h(0, ubox[socket_id], SKX_UBOX_DEVICE_NUM, SKX_UBOX_FUNCTION_NUM); - h.read64(ROOT_BUSES_OFFSET, &cpubusno); - - iio_on_socket.stacks.reserve(6); - for (int stack_id = 0; stack_id < 6; stack_id++) { - struct iio_stack stack; - stack.iio_unit_id = stack_id; - stack.busno = (uint8_t)(cpubusno >> (stack_id * SKX_BUS_NUM_STRIDE)); - stack.stack_name = skx_iio_stack_names[stack_id]; - for (uint8_t part_id = 0; part_id < 4; part_id++) { - struct iio_bifurcated_part part; - part.part_id = part_id; - struct pci *pci = &part.root_pci_dev; - struct bdf *bdf = &pci->bdf; - bdf->busno = stack.busno; - bdf->devno = part_id; - bdf->funcno = 0; - /* This is a workaround to catch some IIO stack does not exist */ - if (stack_id != 0 && stack.busno == 0) { - pci->exist = false; - } - else if (probe_pci(pci)) { - /* FIXME: for 0:0.0, we may need to scan from secondary switch down; lgtm [cpp/fixme-comment] */ - for (uint8_t bus = pci->secondary_bus_number; bus <= pci->subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev; - child_pci_dev.bdf.busno = bus; - child_pci_dev.bdf.devno = device; - child_pci_dev.bdf.funcno = function; - if (probe_pci(&child_pci_dev)) { - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - } - stack.parts.push_back(part); - } - - iio_on_socket.stacks.push_back(stack); - } - iios.push_back(iio_on_socket); - } - - return true; -} - -class IPlatformMapping10Nm: public IPlatformMapping { -private: -public: - IPlatformMapping10Nm(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} - ~IPlatformMapping10Nm() = default; - bool getSadIdRootBusMap(uint32_t socket_id, std::map& sad_id_bus_map); -}; - -bool IPlatformMapping10Nm::getSadIdRootBusMap(uint32_t socket_id, std::map& sad_id_bus_map) -{ - for (uint16_t bus = 0; bus < 256; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci pci_dev; - pci_dev.bdf.busno = (uint8_t)bus; - pci_dev.bdf.devno = device; - pci_dev.bdf.funcno = function; - if (probe_pci(&pci_dev) && pci_dev.isIntelDevice() && (pci_dev.device_id == SNR_ICX_MESH2IIO_MMAP_DID)) { - - PciHandleType h(0, bus, device, function); - std::uint32_t sad_ctrl_cfg; - h.read32(SNR_ICX_SAD_CONTROL_CFG_OFFSET, &sad_ctrl_cfg); - if (sad_ctrl_cfg == (std::numeric_limits::max)()) { - cerr << "Could not read SAD_CONTROL_CFG" << endl; - return false; - } - - if ((sad_ctrl_cfg & 0xf) == socket_id) { - uint8_t sid = (sad_ctrl_cfg >> 4) & 0x7; - sad_id_bus_map.insert(std::pair(sid, (uint8_t)bus)); - } - } - } - } - } - - if (sad_id_bus_map.empty()) { - cerr << "Could not find Root Port bus numbers" << endl; - return false; - } - - return true; -} - -// Mapping for IceLake Server. -class WhitleyPlatformMapping: public IPlatformMapping10Nm { -private: - const bool icx_d; - const std::map& sad_to_pmu_id_mapping; - const std::string * iio_stack_names; -public: - WhitleyPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count), - icx_d(PCM::getInstance()->getCPUFamilyModelFromCPUID() == PCM::ICX_D), - sad_to_pmu_id_mapping(icx_d ? icx_d_sad_to_pmu_id_mapping : icx_sad_to_pmu_id_mapping), - iio_stack_names(icx_d ? icx_d_iio_stack_names : icx_iio_stack_names) - { - } - ~WhitleyPlatformMapping() = default; - bool pciTreeDiscover(std::vector& iios) override; -}; - -bool WhitleyPlatformMapping::pciTreeDiscover(std::vector& iios) -{ - for (uint32_t socket = 0; socket < socketsCount(); socket++) { - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = socket; - std::map sad_id_bus_map; - if (!getSadIdRootBusMap(socket, sad_id_bus_map)) { - return false; - } - - { - struct iio_stack stack; - stack.iio_unit_id = sad_to_pmu_id_mapping.at(ICX_MCP_SAD_ID); - stack.stack_name = iio_stack_names[stack.iio_unit_id]; - iio_on_socket.stacks.push_back(stack); - } - - for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { - int sad_id = sad_id_bus_pair->first; - if (sad_to_pmu_id_mapping.find(sad_id) == - sad_to_pmu_id_mapping.end()) { - cerr << "Unknown SAD ID: " << sad_id << endl; - return false; - } - - if (sad_id == ICX_MCP_SAD_ID) { - continue; - } - - struct iio_stack stack; - int root_bus = sad_id_bus_pair->second; - if (sad_id == ICX_CBDMA_DMI_SAD_ID) { - // There is one DMA Controller on each socket - stack.iio_unit_id = sad_to_pmu_id_mapping.at(sad_id); - stack.busno = root_bus; - stack.stack_name = iio_stack_names[stack.iio_unit_id]; - - // PCH is on socket 0 only - if (socket == 0) { - struct iio_bifurcated_part pch_part; - struct pci *pci = &pch_part.root_pci_dev; - struct bdf *bdf = &pci->bdf; - pch_part.part_id = ICX_PCH_PART_ID; - bdf->busno = root_bus; - bdf->devno = 0x00; - bdf->funcno = 0x00; - if (probe_pci(pci)) { - // Probe child devices only under PCH part. - for (uint8_t bus = pci->secondary_bus_number; bus <= pci->subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev; - child_pci_dev.bdf.busno = bus; - child_pci_dev.bdf.devno = device; - child_pci_dev.bdf.funcno = function; - if (probe_pci(&child_pci_dev)) { - pch_part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(pch_part); - } - } - - struct iio_bifurcated_part part; - part.part_id = ICX_CBDMA_PART_ID; - struct pci *pci = &part.root_pci_dev; - struct bdf *bdf = &pci->bdf; - bdf->busno = root_bus; - bdf->devno = 0x01; - bdf->funcno = 0x00; - if (probe_pci(pci)) - stack.parts.push_back(part); - - iio_on_socket.stacks.push_back(stack); - continue; - } - stack.busno = root_bus; - stack.iio_unit_id = sad_to_pmu_id_mapping.at(sad_id); - stack.stack_name = iio_stack_names[stack.iio_unit_id]; - for (int slot = 2; slot < 6; slot++) { - struct pci pci; - pci.bdf.busno = root_bus; - pci.bdf.devno = slot; - pci.bdf.funcno = 0x00; - if (!probe_pci(&pci)) { - continue; - } - struct iio_bifurcated_part part; - part.part_id = slot - 2; - part.root_pci_dev = pci; - - for (uint8_t bus = pci.secondary_bus_number; bus <= pci.subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev; - child_pci_dev.bdf.busno = bus; - child_pci_dev.bdf.devno = device; - child_pci_dev.bdf.funcno = function; - if (probe_pci(&child_pci_dev)) { - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(part); - } - iio_on_socket.stacks.push_back(stack); - } - std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); - iios.push_back(iio_on_socket); - } - return true; -} - -// Mapping for Snowridge. -class JacobsvillePlatformMapping: public IPlatformMapping10Nm { -private: -public: - JacobsvillePlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count) {} - ~JacobsvillePlatformMapping() = default; - bool pciTreeDiscover(std::vector& iios) override; - bool JacobsvilleAccelerators(const std::pair& sad_id_bus_pair, struct iio_stack& stack); -}; - -bool JacobsvillePlatformMapping::JacobsvilleAccelerators(const std::pair& sad_id_bus_pair, struct iio_stack& stack) -{ - uint16_t expected_dev_id; - auto sad_id = sad_id_bus_pair.first; - switch (sad_id) { - case SNR_HQM_SAD_ID: - expected_dev_id = HQM_DID; - break; - case SNR_NIS_SAD_ID: - expected_dev_id = NIS_DID; - break; - case SNR_QAT_SAD_ID: - expected_dev_id = QAT_DID; - break; - default: - return false; - } - stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); - stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; - for (uint16_t bus = sad_id_bus_pair.second; bus < 256; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci pci_dev; - pci_dev.bdf.busno = (uint8_t)bus; - pci_dev.bdf.devno = device; - pci_dev.bdf.funcno = function; - if (probe_pci(&pci_dev)) { - if (expected_dev_id == pci_dev.device_id) { - struct iio_bifurcated_part part; - part.part_id = SNR_ACCELERATOR_PART_ID; - part.root_pci_dev = pci_dev; - stack.busno = (uint8_t)bus; - stack.parts.push_back(part); - return true; - } - } - } - } - } - return false; -} - -bool JacobsvillePlatformMapping::pciTreeDiscover(std::vector& iios) -{ - std::map sad_id_bus_map; - if (!getSadIdRootBusMap(0, sad_id_bus_map)) { - return false; - } - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = 0; - if (sad_id_bus_map.size() != snr_sad_to_pmu_id_mapping.size()) { - cerr << "Found unexpected number of stacks: " << sad_id_bus_map.size() << ", expected: " << snr_sad_to_pmu_id_mapping.size() << endl; - return false; - } - - for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { - int sad_id = sad_id_bus_pair->first; - struct iio_stack stack; - switch (sad_id) { - case SNR_CBDMA_DMI_SAD_ID: - { - int root_bus = sad_id_bus_pair->second; - stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); - stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; - stack.busno = root_bus; - // DMA Controller - struct iio_bifurcated_part part; - part.part_id = 0; - struct pci pci_dev; - pci_dev.bdf.busno = root_bus; - pci_dev.bdf.devno = 0x01; - pci_dev.bdf.funcno = 0x00; - if (probe_pci(&pci_dev)) { - part.root_pci_dev = pci_dev; - stack.parts.push_back(part); - } - - part.part_id = 4; - pci_dev.bdf.busno = root_bus; - pci_dev.bdf.devno = 0x00; - pci_dev.bdf.funcno = 0x00; - if (probe_pci(&pci_dev)) { - for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev; - child_pci_dev.bdf.busno = bus; - child_pci_dev.bdf.devno = device; - child_pci_dev.bdf.funcno = function; - if (probe_pci(&child_pci_dev)) { - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - part.root_pci_dev = pci_dev; - stack.parts.push_back(part); - } - } - break; - case SNR_PCIE_GEN3_SAD_ID: - { - int root_bus = sad_id_bus_pair->second; - stack.busno = root_bus; - stack.iio_unit_id = snr_sad_to_pmu_id_mapping.at(sad_id); - stack.stack_name = snr_iio_stack_names[stack.iio_unit_id]; - for (int slot = 4; slot < 8; slot++) { - struct pci pci_dev; - pci_dev.bdf.busno = root_bus; - pci_dev.bdf.devno = slot; - pci_dev.bdf.funcno = 0x00; - if (!probe_pci(&pci_dev)) { - continue; - } - int part_id = 4 + pci_dev.device_id - SNR_ROOT_PORT_A_DID; - if ((part_id < 0) || (part_id > 4)) { - cerr << "Invalid part ID " << part_id << endl; - return false; - } - struct iio_bifurcated_part part; - part.part_id = part_id; - part.root_pci_dev = pci_dev; - for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev; - child_pci_dev.bdf.busno = bus; - child_pci_dev.bdf.devno = device; - child_pci_dev.bdf.funcno = function; - if (probe_pci(&child_pci_dev)) { - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(part); - } - } - break; - case SNR_HQM_SAD_ID: - case SNR_NIS_SAD_ID: - case SNR_QAT_SAD_ID: - JacobsvilleAccelerators(*sad_id_bus_pair, stack); - break; - default: - cerr << "Unknown SAD ID: " << sad_id << endl; - return false; - } - iio_on_socket.stacks.push_back(stack); - } - - std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); - - iios.push_back(iio_on_socket); - - return true; -} - -class EagleStreamPlatformMapping: public IPlatformMapping -{ -private: - bool getRootBuses(std::map> &root_buses); - bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool eagleStreamDmiStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool eagleStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool eagleStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool isDmiStack(int unit); - bool isPcieStack(int unit); - bool isDinoStack(int unit); - std::uint32_t m_chop; - EagleStreamSupportedTypes m_es_type; -public: - EagleStreamPlatformMapping(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count), m_chop(0), m_es_type(estype::esInvalid) {} - ~EagleStreamPlatformMapping() = default; - bool setChopValue(); - bool isXccPlatform() const { return m_chop == kXccChop; } - - const std::uint32_t kXccChop = 0b11; - const std::uint32_t kMccChop = 0b01; - - bool pciTreeDiscover(std::vector& iios) override; -}; - -bool EagleStreamPlatformMapping::setChopValue() -{ - for (uint16_t b = 0; b < 256; b++) { - struct pci pci_dev(0, b, SPR_PCU_CR3_REG_DEVICE, SPR_PCU_CR3_REG_FUNCTION); - if (!probe_pci(&pci_dev)) { - continue; - } - if (!(pci_dev.isIntelDevice() && (pci_dev.device_id == SPR_PCU_CR3_DID))) { - continue; - } - std::uint32_t capid4; - PciHandleType h(0, b, SPR_PCU_CR3_REG_DEVICE, SPR_PCU_CR3_REG_FUNCTION); - h.read32(SPR_CAPID4_OFFSET, &capid4); - if (capid4 == (std::numeric_limits::max)()) { - std::cerr << "Cannot read PCU RC3 register" << std::endl; - return false; - } - capid4 = SPR_CAPID4_GET_PHYSICAL_CHOP(capid4); - if (capid4 == kXccChop || capid4 == kMccChop) { - m_chop = capid4; - m_es_type = cpuId() == PCM::SPR ? (m_chop == kXccChop ? estype::esSprXcc : estype::esSprMcc) : estype::esEmrXcc; - } - else { - std::cerr << "Unknown chop value " << capid4 << std::endl; - return false; - } - return true; - } - std::cerr << "Cannot find PCU RC3 registers on the system. Device ID is " << std::hex << SPR_PCU_CR3_DID << std::dec << std::endl; - return false; -} - -bool EagleStreamPlatformMapping::getRootBuses(std::map> &root_buses) -{ - bool mapped = true; - for (uint32_t domain = 0; mapped; domain++) { - mapped = false; - for (uint16_t b = 0; b < 256; b++) { - for (uint8_t d = 0; d < 32; d++) { - for (uint8_t f = 0; f < 8; f++) { - struct pci pci_dev(domain, b, d, f); - if (!probe_pci(&pci_dev)) { - break; - } - if (!(pci_dev.isIntelDevice() && (pci_dev.device_id == SPR_MSM_DEV_ID))) { - continue; - } - - std::uint32_t cpuBusValid; - std::vector cpuBusNo; - int package_id; - - if (get_cpu_bus(domain, b, d, f, cpuBusValid, cpuBusNo, package_id) == false) - { - return false; - } - - const auto& sad_to_pmu_id_mapping = es_sad_to_pmu_id_mapping.at(m_es_type); - for (int cpuBusId = 0; cpuBusId < SPR_MSM_CPUBUSNO_MAX; ++cpuBusId) { - if (!((cpuBusValid >> cpuBusId) & 0x1)) - { - cout << "CPU bus " << cpuBusId << " is disabled on package " << package_id << endl; - continue; - } - if (sad_to_pmu_id_mapping.find(cpuBusId) == sad_to_pmu_id_mapping.end()) - { - cerr << "Cannot map CPU bus " << cpuBusId << " to IO PMU ID" << endl; - continue; - } - int pmuId = sad_to_pmu_id_mapping.at(cpuBusId); - int rootBus = (cpuBusNo[(int)(cpuBusId / 4)] >> ((cpuBusId % 4) * 8)) & 0xff; - root_buses[package_id][pmuId] = bdf(domain, rootBus, 0, 0); - cout << "Mapped CPU bus #" << cpuBusId << " (domain " << domain << " bus " << std::hex << rootBus << std::dec << ") to IO PMU #" - << pmuId << " package " << package_id << endl; - mapped = true; - } - } - } - } - } - return !root_buses.empty(); -} - -bool EagleStreamPlatformMapping::eagleStreamDmiStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - struct iio_stack stack; - stack.iio_unit_id = unit; - stack.stack_name = es_stack_names.at(m_es_type)[unit]; - stack.busno = address.busno; - stack.domain = address.domainno; - struct iio_bifurcated_part pch_part; - struct pci *pci = &pch_part.root_pci_dev; - auto dmi_part_id = SPR_DMI_PART_ID; - pch_part.part_id = dmi_part_id; - pci->bdf = address; - if (!probe_pci(pci)) { - cerr << "Failed to probe DMI Stack: address: " << std::setw(4) << std::setfill('0') << std::hex << address.domainno << - std::setw(2) << std::setfill('0') << ":" << address.busno << ":" << address.devno << - "." << address.funcno << std::dec << endl; - return false; - } - - /* Scan devices behind PCH port only */ - if (!iio_on_socket.socket_id) - probeDeviceRange(pch_part.child_pci_devs, pci->bdf.domainno, pci->secondary_bus_number, pci->subordinate_bus_number); - - pci->parts_no.push_back(dmi_part_id); - - stack.parts.push_back(pch_part); - iio_on_socket.stacks.push_back(stack); - return true; -} - -bool EagleStreamPlatformMapping::eagleStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - /* - * Stacks that manage PCIe 4.0 (device 2,4,6,8) and 5.0 (device 1,3,5,7) Root Ports. - */ - struct iio_stack stack; - stack.domain = address.domainno; - stack.busno = address.busno; - stack.iio_unit_id = unit; - stack.stack_name = es_stack_names.at(m_es_type)[unit]; - for (int slot = 1; slot < 9; ++slot) - { - // Check if port is enabled - struct pci root_pci_dev; - root_pci_dev.bdf = bdf(address.domainno, address.busno, slot, 0x0); - if (probe_pci(&root_pci_dev)) - { - struct iio_bifurcated_part part; - // Bifurcated Root Ports to channel mapping on SPR - part.part_id = slot - 1; - part.root_pci_dev = root_pci_dev; - for (uint8_t b = root_pci_dev.secondary_bus_number; b <= root_pci_dev.subordinate_bus_number; ++b) { - for (uint8_t d = 0; d < 32; ++d) { - for (uint8_t f = 0; f < 8; ++f) { - struct pci child_pci_dev(address.domainno, b, d, f); - if (probe_pci(&child_pci_dev)) { - child_pci_dev.parts_no.push_back(part.part_id); - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(part); - } - } - iio_on_socket.stacks.push_back(stack); - return true; -} - -bool EagleStreamPlatformMapping::eagleStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - struct iio_stack stack; - stack.iio_unit_id = unit; - stack.domain = address.domainno; - stack.busno = address.busno; - - // Channel mappings are checked on B0 stepping - auto rb = address.busno; - const std::vector acceleratorBuses{ rb, rb + 1, rb + 2, rb + 3 }; - stack.stack_name = es_stack_names.at(m_es_type)[unit]; - for (auto& b : acceleratorBuses) { - for (auto d = 0; d < 32; ++d) { - for (auto f = 0; f < 8; ++f) { - struct iio_bifurcated_part part; - struct pci pci_dev(address.domainno, b, d, f); - - if (probe_pci(&pci_dev)) { - if (pci_dev.isIntelDevice()) { - switch (pci_dev.device_id) { - case DSA_DID: - pci_dev.parts_no.push_back(0); - pci_dev.parts_no.push_back(1); - pci_dev.parts_no.push_back(2); - break; - case IAX_DID: - pci_dev.parts_no.push_back(0); - pci_dev.parts_no.push_back(1); - pci_dev.parts_no.push_back(2); - break; - case HQMV2_DID: - pci_dev.parts_no.push_back(isXccPlatform() ? SPR_XCC_HQM_PART_ID : SPR_MCC_HQM_PART_ID); - break; - case QATV2_DID: - pci_dev.parts_no.push_back(isXccPlatform() ? SPR_XCC_QAT_PART_ID : SPR_MCC_QAT_PART_ID); - break; - default: - continue; - } - part.child_pci_devs.push_back(pci_dev); - } - stack.parts.push_back(part); - } - } - } - } - - iio_on_socket.stacks.push_back(stack); - return true; -} - -bool EagleStreamPlatformMapping::isDmiStack(int unit) -{ - const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); - - return stacks_enumeration[esDMI] == unit; -} - -bool EagleStreamPlatformMapping::isPcieStack(int unit) -{ - const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); - - return stacks_enumeration[esPCIe0] == unit || stacks_enumeration[esPCIe1] == unit || - stacks_enumeration[esPCIe2] == unit || stacks_enumeration[esPCIe3] == unit || - stacks_enumeration[esPCIe4] == unit; -} - -bool EagleStreamPlatformMapping::isDinoStack(int unit) -{ - const auto& stacks_enumeration = es_stacks_enumeration.at(m_es_type); - - return stacks_enumeration[esDINO0] == unit || stacks_enumeration[esDINO1] == unit || - stacks_enumeration[esDINO2] == unit || stacks_enumeration[esDINO3] == unit; -} - -bool EagleStreamPlatformMapping::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - if (isDmiStack(unit)) { - return eagleStreamDmiStackProbe(unit, address, iio_on_socket); - } - else if (isPcieStack(unit)) { - return eagleStreamPciStackProbe(unit, address, iio_on_socket); - } - else if (isDinoStack(unit)) { - return eagleStreamAcceleratorStackProbe(unit, address, iio_on_socket); - } - - return false; -} - -bool EagleStreamPlatformMapping::pciTreeDiscover(std::vector& iios) -{ - if (!setChopValue()) return false; - - std::map> root_buses; - if (!getRootBuses(root_buses)) - { - return false; - } - - for (auto iter = root_buses.cbegin(); iter != root_buses.cend(); ++iter) { - auto rbs_on_socket = iter->second; - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = iter->first; - for (auto rb = rbs_on_socket.cbegin(); rb != rbs_on_socket.cend(); ++rb) { - if (!stackProbe(rb->first, rb->second, iio_on_socket)) { - return false; - } - } - std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); - iios.push_back(iio_on_socket); - } - - return true; -} - -class LoganvillePlatform: public IPlatformMapping10Nm { -private: - bool loganvillePchDsaPciStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); - bool loganvilleDlbStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); - bool loganvilleNacStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id); -public: - LoganvillePlatform(int cpu_model, uint32_t sockets_count) : IPlatformMapping10Nm(cpu_model, sockets_count) {} - ~LoganvillePlatform() = default; - bool pciTreeDiscover(std::vector& iios) override; -}; - -bool LoganvillePlatform::loganvillePchDsaPciStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) -{ - struct iio_stack stack; - stack.busno = root_bus; - stack.iio_unit_id = stack_pmon_id; - stack.stack_name = grr_iio_stack_names[stack_pmon_id]; - - struct iio_bifurcated_part pch_part; - pch_part.part_id = 7; - struct pci* pci_dev = &pch_part.root_pci_dev; - pci_dev->bdf.busno = root_bus; - - if (probe_pci(pci_dev)) { - probeDeviceRange(pch_part.child_pci_devs, pci_dev->bdf.domainno, pci_dev->secondary_bus_number, pci_dev->subordinate_bus_number); - stack.parts.push_back(pch_part); - iio_on_socket.stacks.push_back(stack); - return true; - } - - return false; -} - -bool LoganvillePlatform::loganvilleDlbStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) -{ - struct iio_stack stack; - stack.busno = root_bus; - stack.iio_unit_id = stack_pmon_id; - stack.stack_name = grr_iio_stack_names[stack_pmon_id]; - - struct iio_bifurcated_part dlb_part; - dlb_part.part_id = GRR_DLB_PART_ID; - - for (uint8_t bus = root_bus; bus < 255; bus++) { - struct pci pci_dev(bus, 0x00, 0x00); - if (probe_pci(&pci_dev)) { - if ((pci_dev.vendor_id == PCM_INTEL_PCI_VENDOR_ID) && (pci_dev.device_id == HQMV25_DID)) { - dlb_part.root_pci_dev = pci_dev; - // Check Virtual RPs for DLB - for (uint8_t device = 0; device < 2; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev(bus, device, function); - if (probe_pci(&child_pci_dev)) { - dlb_part.child_pci_devs.push_back(child_pci_dev); - } - } - } - stack.parts.push_back(dlb_part); - iio_on_socket.stacks.push_back(stack); - return true; - } - } - } - - return false; -} - -bool LoganvillePlatform::loganvilleNacStackProbe(struct iio_stacks_on_socket& iio_on_socket, int root_bus, int stack_pmon_id) -{ - struct iio_stack stack; - stack.busno = root_bus; - stack.iio_unit_id = stack_pmon_id; - stack.stack_name = grr_iio_stack_names[stack_pmon_id]; - - // Probe NIS - { - struct iio_bifurcated_part nis_part; - nis_part.part_id = GRR_NIS_PART_ID; - struct pci pci_dev(root_bus, 0x04, 0x00); - if (probe_pci(&pci_dev)) { - nis_part.root_pci_dev = pci_dev; - for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 2; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev(bus, device, function); - if (probe_pci(&child_pci_dev)) { - nis_part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(nis_part); - } - } - - // Probe QAT - { - struct iio_bifurcated_part qat_part; - qat_part.part_id = GRR_QAT_PART_ID; - struct pci pci_dev(root_bus, 0x05, 0x00); - if (probe_pci(&pci_dev)) { - qat_part.root_pci_dev = pci_dev; - for (uint8_t bus = pci_dev.secondary_bus_number; bus <= pci_dev.subordinate_bus_number; bus++) { - for (uint8_t device = 0; device < 17; device++) { - for (uint8_t function = 0; function < 8; function++) { - struct pci child_pci_dev(bus, device, function); - if (probe_pci(&child_pci_dev)) { - qat_part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(qat_part); - } - } - - iio_on_socket.stacks.push_back(stack); - return true; -} - -bool LoganvillePlatform::pciTreeDiscover(std::vector& iios) -{ - std::map sad_id_bus_map; - if (!getSadIdRootBusMap(0, sad_id_bus_map)) { - return false; - } - - if (sad_id_bus_map.size() != grr_sad_to_pmu_id_mapping.size()) { - cerr << "Found unexpected number of stacks: " << sad_id_bus_map.size() << ", expected: " << grr_sad_to_pmu_id_mapping.size() << endl; - return false; - } - - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = 0; - - for (auto sad_id_bus_pair = sad_id_bus_map.cbegin(); sad_id_bus_pair != sad_id_bus_map.cend(); ++sad_id_bus_pair) { - if (grr_sad_to_pmu_id_mapping.find(sad_id_bus_pair->first) == grr_sad_to_pmu_id_mapping.end()) { - cerr << "Cannot map SAD ID to PMON ID. Unknown ID: " << sad_id_bus_pair->first << endl; - return false; - } - int stack_pmon_id = grr_sad_to_pmu_id_mapping.at(sad_id_bus_pair->first); - int root_bus = sad_id_bus_pair->second; - switch (stack_pmon_id) { - case GRR_PCH_DSA_GEN4_PMON_ID: - if (!loganvillePchDsaPciStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { - return false; - } - break; - case GRR_DLB_PMON_ID: - if (!loganvilleDlbStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { - return false; - } - break; - case GRR_NIS_QAT_PMON_ID: - if (!loganvilleNacStackProbe(iio_on_socket, root_bus, stack_pmon_id)) { - return false; - } - break; - default: - return false; - } - } - - std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); - - iios.push_back(iio_on_socket); - - return true; -} - -class Xeon6thNextGenPlatform: public IPlatformMapping { -private: - bool getRootBuses(std::map> &root_buses); -protected: - virtual bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) = 0; -public: - Xeon6thNextGenPlatform(int cpu_model, uint32_t sockets_count) : IPlatformMapping(cpu_model, sockets_count) {} - virtual ~Xeon6thNextGenPlatform() = default; - - bool pciTreeDiscover(std::vector& iios) override; -}; - -bool Xeon6thNextGenPlatform::getRootBuses(std::map> &root_buses) -{ - bool mapped = true; - for (uint32_t domain = 0; mapped; domain++) { - mapped = false; - for (uint16_t b = 0; b < 256; b++) { - for (uint8_t d = 0; d < 32; d++) { - for (uint8_t f = 0; f < 8; f++) { - struct pci pci_dev(domain, b, d, f); - if (!probe_pci(&pci_dev)) { - break; - } - if (!(pci_dev.isIntelDevice() && (pci_dev.device_id == SPR_MSM_DEV_ID))) { - continue; - } - - std::uint32_t cpuBusValid; - std::vector cpuBusNo; - int package_id; - - if (!get_cpu_bus(domain, b, d, f, cpuBusValid, cpuBusNo, package_id)) { - return false; - } - - for (int cpuBusId = 0; cpuBusId < SPR_MSM_CPUBUSNO_MAX; ++cpuBusId) { - if (!((cpuBusValid >> cpuBusId) & 0x1)) { - cout << "CPU bus " << cpuBusId << " is disabled on package " << package_id << endl; - continue; - } - int rootBus = (cpuBusNo[(int)(cpuBusId / 4)] >> ((cpuBusId % 4) * 8)) & 0xff; - root_buses[package_id][cpuBusId] = bdf(domain, rootBus, 0, 0); - cout << "Mapped CPU bus #" << cpuBusId << " (domain " << domain << " bus " << std::hex << rootBus << std::dec << ")" - << " package " << package_id << endl; - mapped = true; - } - } - } - } - } - return !root_buses.empty(); -} - -bool Xeon6thNextGenPlatform::pciTreeDiscover(std::vector& iios) -{ - std::map> root_buses; - if (!getRootBuses(root_buses)) - { - return false; - } - - for (auto iter = root_buses.cbegin(); iter != root_buses.cend(); ++iter) { - auto rbs_on_socket = iter->second; - struct iio_stacks_on_socket iio_on_socket; - iio_on_socket.socket_id = iter->first; - for (auto rb = rbs_on_socket.cbegin(); rb != rbs_on_socket.cend(); ++rb) { - if (!stackProbe(rb->first, rb->second, iio_on_socket)) { - return false; - } - } - std::sort(iio_on_socket.stacks.begin(), iio_on_socket.stacks.end()); - iios.push_back(iio_on_socket); - } - - return true; -} - -class BirchStreamPlatform: public Xeon6thNextGenPlatform { -private: - bool isPcieStack(int unit); - bool isRootHcStack(int unit); - bool isPartHcStack(int unit); - bool isUboxStack(int unit); - - bool birchStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool birchStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); -protected: - bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) override; -public: - BirchStreamPlatform(int cpu_model, uint32_t sockets_count) : Xeon6thNextGenPlatform(cpu_model, sockets_count) {} - ~BirchStreamPlatform() = default; -}; - -bool BirchStreamPlatform::birchStreamPciStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - /* - * All stacks manage PCIe 5.0 Root Ports. Bifurcated Root Ports A-H appear as devices 2-9. - */ - struct iio_stack stack; - stack.domain = address.domainno; - stack.busno = address.busno; - stack.iio_unit_id = srf_sad_to_pmu_id_mapping.at(unit); - stack.stack_name = srf_iio_stack_names[stack.iio_unit_id]; - for (int slot = 2; slot < 9; ++slot) - { - struct pci root_pci_dev; - root_pci_dev.bdf = bdf(address.domainno, address.busno, slot, 0x0); - if (probe_pci(&root_pci_dev)) - { - struct iio_bifurcated_part part; - part.part_id = slot - 2; - part.root_pci_dev = root_pci_dev; - for (uint8_t b = root_pci_dev.secondary_bus_number; b <= root_pci_dev.subordinate_bus_number; ++b) { - for (uint8_t d = 0; d < 32; ++d) { - for (uint8_t f = 0; f < 8; ++f) { - struct pci child_pci_dev(address.domainno, b, d, f); - if (probe_pci(&child_pci_dev)) { - child_pci_dev.parts_no.push_back(part.part_id); - part.child_pci_devs.push_back(child_pci_dev); - } - } - } - } - stack.parts.push_back(part); - } - } - iio_on_socket.stacks.push_back(stack); - return true; -} - -bool BirchStreamPlatform::birchStreamAcceleratorStackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - struct iio_stack stack; - stack.iio_unit_id = srf_sad_to_pmu_id_mapping.at(unit); - stack.domain = address.domainno; - stack.busno = address.busno; - stack.stack_name = srf_iio_stack_names[stack.iio_unit_id]; - - /* - * Instance of DSA(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (8, 12, 20, 16), device 1, function 0 - * Instance of IAX(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (8, 12, 20, 16), device 2, function 0 - * Instance of QAT(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (9, 13, 21, 17), device 0, function 0 - * Instance of HQM(0, 1, 2, 3) appears as PCIe device with SAD Bus ID (10, 14, 22, 18), device 0, function 0 - */ - auto process_pci_dev = [](int domainno, int busno, int devno, int part_number, iio_bifurcated_part& part) - { - struct pci pci_dev(domainno, busno, devno, 0); - if (probe_pci(&pci_dev) && pci_dev.isIntelDevice()) { - part.part_id = part_number; - pci_dev.parts_no.push_back(part_number); - part.child_pci_devs.push_back(pci_dev); - return true; - } - return false; - }; - - { - struct iio_bifurcated_part part; - if (process_pci_dev(address.domainno, address.busno, 1, SRF_DSA_IAX_PART_NUMBER, part) || - process_pci_dev(address.domainno, address.busno, 2, SRF_DSA_IAX_PART_NUMBER, part)) { - stack.parts.push_back(part); - } - } - - { - struct iio_bifurcated_part part; - if (process_pci_dev(address.domainno, address.busno + 1, 0, SRF_QAT_PART_NUMBER, part)) { - stack.parts.push_back(part); - } - } - - { - /* Bus number for HQM is higher on 3 than DSA bus number */ - struct iio_bifurcated_part part; - if (process_pci_dev(address.domainno, address.busno + 3, 0, SRF_HQM_PART_NUMBER, part)) { - stack.parts.push_back(part); - } - } - - if (!stack.parts.empty()) { - iio_on_socket.stacks.push_back(stack); - } - - return true; -} - -bool BirchStreamPlatform::isPcieStack(int unit) -{ - return srf_pcie_stacks.find(unit) != srf_pcie_stacks.end(); -} - -/* - * HC is the name of DINO stacks as we had on SPR - */ -bool BirchStreamPlatform::isRootHcStack(int unit) -{ - return SRF_HC0_SAD_BUS_ID == unit || SRF_HC1_SAD_BUS_ID == unit || - SRF_HC2_SAD_BUS_ID == unit || SRF_HC3_SAD_BUS_ID == unit; -} - -bool BirchStreamPlatform::isPartHcStack(int unit) -{ - return isRootHcStack(unit - 1) || isRootHcStack(unit - 2); -} - -bool BirchStreamPlatform::isUboxStack(int unit) -{ - return SRF_UBOXA_SAD_BUS_ID == unit || SRF_UBOXB_SAD_BUS_ID == unit; -} - -bool BirchStreamPlatform::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - if (isPcieStack(unit)) { - return birchStreamPciStackProbe(unit, address, iio_on_socket); - } - else if (isRootHcStack(unit)) { - return birchStreamAcceleratorStackProbe(unit, address, iio_on_socket); - } - else if (isPartHcStack(unit)) { - cout << "Found a part of HC stack. Stack ID - " << unit << " domain " << address.domainno - << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << ". Don't probe it again." << endl; - return true; - } - else if (isUboxStack(unit)) { - cout << "Found UBOX stack. Stack ID - " << unit << " domain " << address.domainno - << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << endl; - return true; - } - - cout << "Unknown stack ID " << unit << " domain " << address.domainno << " bus " << std::hex << std::setfill('0') << std::setw(2) << (int)address.busno << std::dec << endl; - - return false; -} - -class KasseyvillePlatform: public Xeon6thNextGenPlatform { -private: - bool stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket); - bool isUboxStack(int unit) - { - return SRF_UBOXA_SAD_BUS_ID == unit || SRF_UBOXB_SAD_BUS_ID == unit; - } -public: - KasseyvillePlatform(int cpu_model, uint32_t sockets_count) : Xeon6thNextGenPlatform(cpu_model, sockets_count) {} - ~KasseyvillePlatform() = default; -}; - -bool KasseyvillePlatform::stackProbe(int unit, const struct bdf &address, struct iio_stacks_on_socket &iio_on_socket) -{ - // Skip UBOX buses - if (isUboxStack(unit)) return true; - - // To suppress compilation warning - (void)address; - - struct iio_stack stack; - stack.iio_unit_id = unit; - stack.stack_name = generate_stack_str(unit); - iio_on_socket.stacks.push_back(stack); - return true; -} - -std::unique_ptr IPlatformMapping::getPlatformMapping(int cpu_family_model, uint32_t sockets_count) -{ - switch (cpu_family_model) { - case PCM::SKX: - return std::unique_ptr{new PurleyPlatformMapping(cpu_family_model, sockets_count)}; - case PCM::ICX: - return std::unique_ptr{new WhitleyPlatformMapping(cpu_family_model, sockets_count)}; - case PCM::SNOWRIDGE: - return std::unique_ptr{new JacobsvillePlatformMapping(cpu_family_model, sockets_count)}; - case PCM::SPR: - case PCM::EMR: - return std::unique_ptr{new EagleStreamPlatformMapping(cpu_family_model, sockets_count)}; - case PCM::GRR: - return std::unique_ptr{new LoganvillePlatform(cpu_family_model, sockets_count)}; - case PCM::SRF: - case PCM::GNR: - return std::unique_ptr{new BirchStreamPlatform(cpu_family_model, sockets_count)}; - case PCM::GNR_D: - std::cerr << "Warning: Only initial support (without attribution to PCIe devices) for Graniterapids-D is provided" << std::endl; - return std::unique_ptr{new KasseyvillePlatform(cpu_family_model, sockets_count)}; - default: - return nullptr; - } -} - -ccr* get_ccr(PCM* m, uint64_t& ccr) -{ - switch (m->getCPUFamilyModel()) - { - case PCM::SKX: - return new pcm::ccr(ccr, ccr::ccr_type::skx); - case PCM::ICX: - case PCM::SNOWRIDGE: - case PCM::SPR: - case PCM::EMR: - case PCM::GRR: - case PCM::SRF: - case PCM::GNR: - case PCM::GNR_D: - return new pcm::ccr(ccr, ccr::ccr_type::icx); - default: - cerr << m->getCPUFamilyModelString() << " is not supported! Program aborted" << endl; - exit(EXIT_FAILURE); - } -} - -int iio_evt_parse_handler(evt_cb_type cb_type, void *cb_ctx, counter &base_ctr, std::map &ofm, std::string key, uint64 numValue) -{ - iio_evt_parse_context *context = (iio_evt_parse_context *)cb_ctx; - PCM *m = context->m; - - if (cb_type == EVT_LINE_START) //this event will be called per line(start) - { - context->ctr.ccr = 0; - } - else if (cb_type == EVT_LINE_FIELD) //this event will be called per field of line - { - std::unique_ptr pccr(get_ccr(m, context->ctr.ccr)); - switch (ofm[key]) - { - case PCM::OPCODE: - break; - case PCM::EVENT_SELECT: - pccr->set_event_select(numValue); - break; - case PCM::UMASK: - pccr->set_umask(numValue); - break; - case PCM::RESET: - pccr->set_reset(numValue); - break; - case PCM::EDGE_DET: - pccr->set_edge(numValue); - break; - case PCM::IGNORED: - break; - case PCM::OVERFLOW_ENABLE: - pccr->set_ov_en(numValue); - break; - case PCM::ENABLE: - pccr->set_enable(numValue); - break; - case PCM::INVERT: - pccr->set_invert(numValue); - break; - case PCM::THRESH: - pccr->set_thresh(numValue); - break; - case PCM::CH_MASK: - pccr->set_ch_mask(numValue); - break; - case PCM::FC_MASK: - pccr->set_fc_mask(numValue); - break; - case PCM::INVALID: - default: - std::cerr << "Field in -o file not recognized. The key is: " << key << "\n"; - return -1; - } - } - else if(cb_type == EVT_LINE_COMPLETE) //this event will be called every line(end) - { - context->ctr.h_event_name = base_ctr.h_event_name; - context->ctr.v_event_name = base_ctr.v_event_name; - context->ctr.idx = base_ctr.idx; - context->ctr.multiplier = base_ctr.multiplier; - context->ctr.divider = base_ctr.divider; - context->ctr.h_id = base_ctr.h_id; - context->ctr.v_id = base_ctr.v_id; - //std::cout << "line parse OK, ctrcfg=0x" << std::hex << context->ctr.ccr << ", h_event_name=" << base_ctr.h_event_name << ", v_event_name=" << base_ctr.v_event_name; - //std::cout << ", h_id=0x" << std::hex << base_ctr.h_id << ", v_id=0x" << std::hex << base_ctr.v_id; - //std::cout << ", idx=0x"<< std::hex << base_ctr.idx << ", multiplier=0x" << std::hex << base_ctr.multiplier << ", divider=0x" << std::hex << base_ctr.divider << std::dec << "\n"; - context->ctrs.push_back(context->ctr); - } - - return 0; -} - -result_content get_IIO_Samples(PCM *m, const std::vector& iios, const struct iio_counter & ctr, uint32_t delay_ms) -{ - IIOCounterState *before, *after; - uint64 rawEvents[4] = {0}; - auto ccrCopy = ctr.ccr; - std::unique_ptr pccr(get_ccr(m, ccrCopy)); - rawEvents[ctr.idx] = pccr->get_ccr_value(); - const int stacks_count = (int)m->getMaxNumOfIIOStacks(); - before = new IIOCounterState[iios.size() * stacks_count]; - after = new IIOCounterState[iios.size() * stacks_count]; - - m->programIIOCounters(rawEvents); - for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { - for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { - auto iio_unit_id = stack->iio_unit_id; - uint32_t idx = (uint32_t)stacks_count * socket->socket_id + iio_unit_id; - before[idx] = m->getIIOCounterState(socket->socket_id, iio_unit_id, ctr.idx); - } - } - MySleepMs(delay_ms); - for (auto socket = iios.cbegin(); socket != iios.cend(); ++socket) { - for (auto stack = socket->stacks.cbegin(); stack != socket->stacks.cend(); ++stack) { - auto iio_unit_id = stack->iio_unit_id; - uint32_t idx = (uint32_t)stacks_count * socket->socket_id + iio_unit_id; - after[idx] = m->getIIOCounterState(socket->socket_id, iio_unit_id, ctr.idx); - uint64_t raw_result = getNumberOfEvents(before[idx], after[idx]); - uint64_t trans_result = uint64_t (raw_result * ctr.multiplier / (double) ctr.divider * (1000 / (double) delay_ms)); - results[socket->socket_id][iio_unit_id][std::pair(ctr.h_id,ctr.v_id)] = trans_result; - } - } - deleteAndNullifyArray(before); - deleteAndNullifyArray(after); - return results; -} - -void collect_data(PCM *m, const double delay, vector& iios, vector& ctrs) -{ - const uint32_t delay_ms = uint32_t(delay * 1000 / ctrs.size()); - for (auto counter = ctrs.begin(); counter != ctrs.end(); ++counter) { - counter->data.clear(); - result_content sample = get_IIO_Samples(m, iios, *counter, delay_ms); - counter->data.push_back(sample); - } -} +#include "pcm-iio-pmu.h" void print_PCIeMapping(const std::vector& iios, const PCIDB & pciDB, std::ostream& stream) { @@ -2172,7 +78,6 @@ int mainThrows(int argc, char * argv[]) string program = string(argv[0]); - vector counters; bool csv = false; bool human_readable = false; bool show_root_port = false; @@ -2181,9 +86,6 @@ int mainThrows(int argc, char * argv[]) double delay = PCM_DELAY_DEFAULT; bool list = false; MainLoop mainLoop; - iio_evt_parse_context evt_ctx; - // Map with metrics names. - map>> nameMap; while (argc > 1) { argv++; @@ -2231,20 +133,6 @@ int mainThrows(int argc, char * argv[]) PCM * m = PCM::getInstance(); - PCIDB pciDB; - load_PCIDB(pciDB); - - auto mapping = IPlatformMapping::getPlatformMapping(m->getCPUFamilyModel(), m->getNumSockets()); - if (!mapping) { - cerr << "Failed to discover pci tree: unknown platform" << endl; - exit(EXIT_FAILURE); - } - - std::vector iios; - if (!mapping->pciTreeDiscover(iios)) { - exit(EXIT_FAILURE); - } - std::ostream* output = &std::cout; std::fstream file_stream; if (!output_file.empty()) { @@ -2252,61 +140,27 @@ int mainThrows(int argc, char * argv[]) output = &file_stream; } - if (list) { - print_PCIeMapping(iios, pciDB, *output); - return 0; - } + std::vector iios; + iio_evt_parse_context evt_ctx; + // Map with metrics names. + PCIeEventNameMap_t nameMap; - string ev_file_name; - if (m->IIOEventsAvailable()) - { - ev_file_name = "opCode-" + std::to_string(m->getCPUFamily()) + "-" + std::to_string(m->getInternalCPUModel()) + ".txt"; - } - else - { - cerr << "This CPU is not supported by PCM IIO tool! Program aborted\n"; + if ( !initializeIIOCounters( iios, evt_ctx, nameMap ) ) exit(EXIT_FAILURE); - } - map opcodeFieldMap; - opcodeFieldMap["opcode"] = PCM::OPCODE; - opcodeFieldMap["ev_sel"] = PCM::EVENT_SELECT; - opcodeFieldMap["umask"] = PCM::UMASK; - opcodeFieldMap["reset"] = PCM::RESET; - opcodeFieldMap["edge_det"] = PCM::EDGE_DET; - opcodeFieldMap["ignored"] = PCM::IGNORED; - opcodeFieldMap["overflow_enable"] = PCM::OVERFLOW_ENABLE; - opcodeFieldMap["en"] = PCM::ENABLE; - opcodeFieldMap["invert"] = PCM::INVERT; - opcodeFieldMap["thresh"] = PCM::THRESH; - opcodeFieldMap["ch_mask"] = PCM::CH_MASK; - opcodeFieldMap["fc_mask"] = PCM::FC_MASK; - opcodeFieldMap["hname"] =PCM::H_EVENT_NAME; - opcodeFieldMap["vname"] =PCM::V_EVENT_NAME; - opcodeFieldMap["multiplier"] = PCM::MULTIPLIER; - opcodeFieldMap["divider"] = PCM::DIVIDER; - opcodeFieldMap["ctr"] = PCM::COUNTER_INDEX; - - evt_ctx.m = m; - evt_ctx.ctrs.clear();//fill the ctrs by evt_handler call back func. + PCIDB pciDB; + load_PCIDB(pciDB); - try - { - load_events(ev_file_name, opcodeFieldMap, iio_evt_parse_handler, (void *)&evt_ctx, nameMap); - } - catch (std::exception & e) - { - std::cerr << "Error info:" << e.what() << "\n"; - std::cerr << "The event configuration file (" << ev_file_name << ") cannot be loaded. Please verify the file. Exiting.\n"; - exit(EXIT_FAILURE); + if (list) { + print_PCIeMapping(iios, pciDB, *output); + return 0; } + #ifdef PCM_DEBUG print_nameMap(nameMap); #endif - results.resize(m->getNumSockets(), stack_content(m->getMaxNumOfIIOStacks(), ctr_data())); - mainLoop([&]() { collect_data(m, delay, iios, evt_ctx.ctrs); diff --git a/src/pcm-pcie.cpp b/src/pcm-pcie.cpp index 79f049d4..ecb5205a 100644 --- a/src/pcm-pcie.cpp +++ b/src/pcm-pcie.cpp @@ -150,7 +150,7 @@ int mainThrows(int argc, char * argv[]) double delay = -1.0; bool csv = false; bool print_bandwidth = false; - bool print_additional_info = false; + bool print_additional_info = false; char * sysCmd = NULL; char ** sysArgv = NULL; MainLoop mainLoop; diff --git a/src/pcm-raw.cpp b/src/pcm-raw.cpp index 9a2df544..80643c03 100644 --- a/src/pcm-raw.cpp +++ b/src/pcm-raw.cpp @@ -767,8 +767,6 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven { DBG(2, "Setting " , registerKeyValue.key , " : " , registerKeyValue.value); simdjson::dom::object fieldDescriptionObj = registerKeyValue.value; - DBG(2, " config: " , uint64_t(fieldDescriptionObj["Config"])); - DBG(2, " Position: " , uint64_t(fieldDescriptionObj["Position"])); const std::string fieldNameStr{ registerKeyValue.key.begin(), registerKeyValue.key.end() }; if (fieldNameStr == "MSRIndex") { @@ -785,8 +783,8 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven const auto MSRIndexes = split(MSRIndexStr, ','); if (offcoreEventIndex >= MSRIndexes.size()) { - std::cerr << "ERROR: too many offcore events specified (max is " << MSRIndexes.size() << "). Ignoring " << fullEventStr << " event\n"; - return AddEventStatus::OK; + std::cerr << "ERROR: too many offcore events specified (max is " << MSRIndexes.size() << "). MSRIndex string:" << MSRIndexStr << " Ignoring " << fullEventStr << " event\n"; + return AddEventStatus::FailedTooManyEvents; } MSRIndexStr = MSRIndexes[offcoreEventIndex]; } @@ -818,21 +816,71 @@ AddEventStatus addEventFromDB(PCM::RawPMUConfigs& curPMUConfigs, string fullEven } else { - std::string fieldValueStr = EventMap::getField(eventStr, fieldNameStr); - - fieldValueStr.erase(std::remove(fieldValueStr.begin(), fieldValueStr.end(), '\"'), fieldValueStr.end()); - if (offcore && fieldNameStr == "EventCode") + auto getFieldValueArray = [&eventStr](const std::string & fieldNameStr) + { + std::string fieldValueStr = EventMap::getField(eventStr, fieldNameStr); + // remove all double quote characters from the fieldValueStr string + fieldValueStr.erase(std::remove(fieldValueStr.begin(), fieldValueStr.end(), '\"'), fieldValueStr.end()); + return split(fieldValueStr, ','); + }; + const auto fieldValueArray = getFieldValueArray(fieldNameStr); + // print all fieldValueArray values + DBG(2, " field " , fieldNameStr , " offcore=" , offcore, " size=" , fieldValueArray.size(), " values:"); + for (const auto& fieldValue : fieldValueArray) + { + DBG(2, "Field value: " , fieldValue, " (" , read_number(fieldValue.c_str()) , ")"); + } + assert(fieldValueArray.size() >= 1); + auto setOffcoreConfig = [&](const std::string & secondField) { - const auto offcoreCodes = split(fieldValueStr,','); + const auto offcoreCodes = fieldValueArray; + std::string fieldValueStr{}; + DBG(2, "offcoreEventIndex: " , offcoreEventIndex); if (offcoreEventIndex >= offcoreCodes.size()) { - std::cerr << "ERROR: too many offcore events specified (max is " << offcoreCodes.size() << "). Ignoring " << fullEventStr << " event\n"; - return AddEventStatus::OK; + const auto adjustedMaxSize = getFieldValueArray(secondField).size(); + if (offcoreEventIndex >= adjustedMaxSize) + { + std::cerr << "ERROR: too many offcore events specified (max is " << adjustedMaxSize << "). " << fieldNameStr << " string: " << EventMap::getField(eventStr, fieldNameStr) + << " for " << fullEventStr << " event\n"; + return AddEventStatus::FailedTooManyEvents; + } + fieldValueStr = offcoreCodes[0]; + } + else + { + fieldValueStr = offcoreCodes[offcoreEventIndex]; + } + assert(!fieldValueStr.empty()); + DBG(2, "Setting field " , fieldNameStr , " value is " , fieldValueStr , " (" , read_number(fieldValueStr.c_str()) , ")"); + setConfig(config, fieldDescriptionObj, read_number(fieldValueStr.c_str()), position); + return AddEventStatus::OK; + }; + if (offcore && fieldNameStr == "EventCode") + { + const auto status = setOffcoreConfig("UMask"); + if (status != AddEventStatus::OK) + { + return status; + } + } else if (offcore && fieldNameStr == "UMask") + { + const auto status = setOffcoreConfig("EventCode"); + if (status != AddEventStatus::OK) + { + return status; + } + } + else + { + if (fieldValueArray.size() > 1) + { + std::cout << "WARNING: multiple field values specified for field " << fieldNameStr << " for event " << fullEventStr << ": " << EventMap::getField(eventStr, fieldNameStr) + << ", choosing the first one...\n"; } - fieldValueStr = offcoreCodes[offcoreEventIndex]; + DBG(2, "Setting field " , fieldNameStr , " value is " , fieldValueArray[0] , " (" , read_number(fieldValueArray[0].c_str()) , ")"); + setConfig(config, fieldDescriptionObj, read_number(fieldValueArray[0].c_str()), position); } - DBG(2, " field " , fieldNameStr , " value is " , fieldValueStr , " (" , read_number(fieldValueStr.c_str()) , ") offcore=" , offcore); - setConfig(config, fieldDescriptionObj, read_number(fieldValueStr.c_str()), position); } } diff --git a/src/pcm-sensor-server.cpp b/src/pcm-sensor-server.cpp index 2c122fec..c2386362 100644 --- a/src/pcm-sensor-server.cpp +++ b/src/pcm-sensor-server.cpp @@ -47,6 +47,8 @@ constexpr unsigned int DEFAULT_HTTPS_PORT = DEFAULT_HTTP_PORT; #include "threadpool.h" +#include "pcm-iio-pmu.h" + using namespace pcm; std::string const HTTP_EOL( "\r\n" ); @@ -3504,11 +3506,11 @@ enum MimeType matchSupportedWithAcceptedMimeTypes( HTTPHeader const& h ) { } } // remove all whitespace from the item - copy.erase( std::remove_if( copy.begin(), copy.end(), isspace ), copy.end() ); + copy.erase( std::remove_if( copy.begin(), copy.end(), ::isspace ), copy.end() ); // compare mimetype with supported ones for ( auto& mimetype : supportedOutputMimeTypes ) { auto str = mimetype.second; - str.erase( std::remove_if( str.begin(), str.end(), isspace ), str.end() ); + str.erase( std::remove_if( str.begin(), str.end(), ::isspace ), str.end() ); DBG( 2, "Comparing mimetype '", copy, "' with known Mimetype '", str, "'" ); if ( str == copy ) { DBG( 2, "Found a match!" ); @@ -3766,20 +3768,18 @@ int mainThrows(int argc, char * argv[]) { unsigned short debug_level = 0; std::string certificateFile; std::string privateKeyFile; - AcceleratorCounterState *accs_; - accs_ = AcceleratorCounterState::getInstance(); + AcceleratorCounterState *accs_ = AcceleratorCounterState::getInstance(); null_stream nullStream; check_and_set_silent(argc, argv, nullStream); - ACCEL_IP accel=ACCEL_NOCONFIG; //default is IAA + ACCEL_IP accel=ACCEL_NOCONFIG; //default is no device bool evtfile = false; std::string specify_evtfile; // ACCEL_DEV_LOC_MAPPING loc_map = SOCKET_MAP; //default is socket mapping MainLoop mainLoop; - std::string ev_file_name; - const char* PPTEnv = std::getenv( "PCMSENSORSERVER_PRINT_TOPOLOGY" ); - if ( PPTEnv ) { - if ( *PPTEnv == '1' ) { + auto PPTEnv = pcm::safe_getenv( "PCMSENSORSERVER_PRINT_TOPOLOGY" ); + if ( ! PPTEnv.empty() ) { + if ( 1 == std::stoi(PPTEnv) ) { printTopology = true; } } else if ( argc > 1 ) { @@ -4031,6 +4031,7 @@ int mainThrows(int argc, char * argv[]) { //TODO: check return value when its implemented pcmInstance->programCXLCM(); + if (pcmInstance->getAccel()!=ACCEL_NOCONFIG) { if (pcmInstance->supportIDXAccelDev() == false) @@ -4043,6 +4044,7 @@ int mainThrows(int argc, char * argv[]) { accs_->programAccelCounters(); } + if ( printTopology ) { TopologyPrinter* tp = new TopologyPrinter(); tp->dispatch( PCM::getInstance()->getSystemTopology() ); @@ -4052,8 +4054,24 @@ int mainThrows(int argc, char * argv[]) { std::cout << line << "\n"; } deleteAndNullify( tp ); - exit( 0 ); + delete pcmInstance; + return( 0 ); } + + std::vector iios; + iio_evt_parse_context evt_ctx; + std::string ev_file_name; + // Map with metrics names. + PCIeEventNameMap_t nameMap; + + // TODO: add check for IIO support before trying to initialize the pmu + if ( !initializeIIOCounters( iios, evt_ctx, nameMap ) ) + { + std::cerr << "Error: IIO is NOT supported with this platform! Program aborted\n"; + exit(EXIT_FAILURE); + } + + // Now that everything is set we can start the http(s) server #if defined (USE_SSL) if ( useSSL ) { if ( port == 0 ) @@ -4072,7 +4090,6 @@ int mainThrows(int argc, char * argv[]) { } else if ( pid > 0 ) { /* Parent, just leave */ DBG( 2, "Child pid: ", pid ); - return 0; } else { /* Error */ DBG( 2, "Error forking. " );