From f65b42bee9af5609d39d346395a278db03187212 Mon Sep 17 00:00:00 2001 From: Roman Dementiev Date: Fri, 24 Feb 2017 16:17:10 +0100 Subject: [PATCH] implement SKX support, PCM-IIO, PCM-lspci tools [aaron.cruz@intel.com: PCM-IIO tool] Signed-off-by: Aaron Cruz [patrick.lu@intel.com: SKX support, PCM-IIO tool, PCM-lspci tool] Signed-off-by: Patrick Lu [roman.dementiev@intel.com: SKX support, PCI device DB] Signed-off-by: Roman Dementiev Change-Id: Ibdf3991b418b2a902bd941ebc7cce153de16978c --- Makefile | 2 +- cpucounters.cpp | 629 ++++++++++++++++++++++++++++++++++++------------ cpucounters.h | 276 ++++++++++++++++++--- lspci.h | 216 +++++++++++++++++ pcm-iio.cpp | 604 ++++++++++++++++++++++++++++++++++++++++++++++ pcm-lspci.cpp | 113 +++++++++ pcm-numa.cpp | 9 +- pcm-pcie.cpp | 79 ++++-- pcm-power.cpp | 21 +- types.h | 111 ++++++++- 10 files changed, 1823 insertions(+), 237 deletions(-) create mode 100644 lspci.h create mode 100644 pcm-iio.cpp create mode 100644 pcm-lspci.cpp diff --git a/Makefile b/Makefile index 3465dad2..033d6a80 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # written by Roman Dementiev and Jim Harris # -EXE = pcm-numa.x pcm-power.x pcm.x pcm-sensor.x pcm-msr.x pcm-memory.x pcm-tsx.x pcm-pcie.x pcm-core.x +EXE = pcm.x pcm-numa.x pcm-power.x pcm-sensor.x pcm-msr.x pcm-memory.x pcm-tsx.x pcm-pcie.x pcm-core.x pcm-iio.x pcm-lspci.x all: $(EXE) diff --git a/cpucounters.cpp b/cpucounters.cpp index fa070e61..067a1886 100644 --- a/cpucounters.cpp +++ b/cpucounters.cpp @@ -46,6 +46,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include #include #include +#ifdef __linux__ +#include +#endif #endif #include @@ -606,6 +609,8 @@ void PCM::initCStateSupportTables() case BDX: case KNL: PCM_CSTATE_ARRAY(pkgCStateMsr, PCM_PARAM_PROTECT({0, 0, 0x60D, 0x3F8, 0, 0, 0x3F9, 0x3FA, 0, 0, 0}) ); + case SKX: + PCM_CSTATE_ARRAY(pkgCStateMsr, PCM_PARAM_PROTECT({0, 0, 0x60D, 0, 0, 0, 0x3F9, 0, 0, 0, 0}) ); case HASWELL_ULT: case BROADWELL: case SKL: @@ -653,12 +658,41 @@ void PCM::initCStateSupportTables() PCM_CSTATE_ARRAY(coreCStateMsr, PCM_PARAM_PROTECT({0, 0, 0, 0x3FC, 0, 0, 0x3FD, 0x3FE, 0, 0, 0}) ); case KNL: PCM_CSTATE_ARRAY(coreCStateMsr, PCM_PARAM_PROTECT({0, 0, 0, 0, 0, 0, 0x3FF, 0, 0, 0, 0}) ); + case SKX: + PCM_CSTATE_ARRAY(coreCStateMsr, PCM_PARAM_PROTECT({0, 0, 0, 0, 0, 0, 0x3FD, 0, 0, 0, 0}) ); default: std::cerr << "PCM error: core C-states support array is not initialized. Core C-states metrics will not be shown." << std::endl; PCM_CSTATE_ARRAY(coreCStateMsr, PCM_PARAM_PROTECT({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) ); }; } + +#ifdef __linux__ +int readMaxFromSysFS(const char * path) +{ + FILE * f = fopen(path, "r"); + if (!f) + { + std::cerr << "Can not open "<< path <<" file." << std::endl; + return false; + } + char buffer[1024]; + if(NULL == fgets(buffer, 1024, f)) + { + std::cerr << "Can not read "<< path << "." << std::endl; + return false; + } + fclose(f); + int result = -1; + sscanf(buffer, "0-%d", &result); + if(result == -1) + { + sscanf(buffer, "%d", &result); + } + return result; +} +#endif + bool PCM::discoverSystemTopology() { typedef std::map socketIdMap_type; @@ -831,25 +865,7 @@ bool PCM::discoverSystemTopology() #ifdef __linux__ - FILE * f_presentcpus = fopen("/sys/devices/system/cpu/present", "r"); - if (!f_presentcpus) - { - std::cerr << "Can not open /sys/devices/system/cpu/present file." << std::endl; - return false; - } - char buffer[1024]; - if(NULL == fgets(buffer, 1024, f_presentcpus)) - { - std::cerr << "Can not read /sys/devices/system/cpu/present." << std::endl; - return false; - } - fclose(f_presentcpus); - num_cores = -1; - sscanf(buffer, "0-%d", &num_cores); - if(num_cores == -1) - { - sscanf(buffer, "%d", &num_cores); - } + num_cores = readMaxFromSysFS("/sys/devices/system/cpu/present"); if(num_cores == -1) { std::cerr << "Can not read number of present cores" << std::endl; @@ -869,6 +885,7 @@ bool PCM::discoverSystemTopology() // associated value=socket_id that should be 0 based and sequential std::map found_pkg_ids; topology.resize(num_cores); + char buffer[1024]; while (0 != fgets(buffer, 1024, f_cpuinfo)) { if (strncmp(buffer, "processor", sizeof("processor") - 1) == 0) @@ -1188,6 +1205,7 @@ bool PCM::detectNominalFrequency() || original_cpu_model == ATOM_APOLLO_LAKE || cpu_model == SKL || cpu_model == KNL + || cpu_model == SKX ) ? (100000000ULL) : (133333333ULL); nominal_frequency = ((freq >> 8) & 255) * bus_freq; @@ -1313,6 +1331,7 @@ void PCM::initUncoreObjects() case BDX: case KNL: case HASWELLX: + case SKX: PCU_MSR_PMON_BOX_CTL_ADDR = HSX_PCU_MSR_PMON_BOX_CTL_ADDR; PCU_MSR_PMON_CTRX_ADDR[0] = HSX_PCU_MSR_PMON_CTR0_ADDR; PCU_MSR_PMON_CTRX_ADDR[1] = HSX_PCU_MSR_PMON_CTR1_ADDR; @@ -1326,6 +1345,28 @@ void PCM::initUncoreObjects() PCU_MSR_PMON_CTRX_ADDR[2] = (uint64)0; PCU_MSR_PMON_CTRX_ADDR[3] = (uint64)0; } + // init IIO addresses + std::vector IIO_units; + IIO_units.push_back((int32)IIO_CBDMA); + IIO_units.push_back((int32)IIO_PCIe0); + IIO_units.push_back((int32)IIO_PCIe1); + IIO_units.push_back((int32)IIO_PCIe2); + IIO_units.push_back((int32)IIO_MCP0); + IIO_units.push_back((int32)IIO_MCP1); + if (cpu_model == SKX) + { + for (std::vector::const_iterator iunit = IIO_units.begin(); iunit != IIO_units.end(); ++iunit) + { + const int32 unit = *iunit; + IIO_UNIT_STATUS_ADDR[unit] = SKX_IIO_CBDMA_UNIT_STATUS + SKX_IIO_PM_REG_STEP*unit; + IIO_UNIT_CTL_ADDR[unit] = SKX_IIO_CBDMA_UNIT_CTL + SKX_IIO_PM_REG_STEP*unit; + for(int32 c = 0; c < 4; ++c) + IIO_CTR_ADDR[unit].push_back(SKX_IIO_CBDMA_CTR0 + SKX_IIO_PM_REG_STEP*unit + c); + IIO_CLK_ADDR[unit] = SKX_IIO_CBDMA_CLK + SKX_IIO_PM_REG_STEP*unit; + for (int32 c = 0; c < 4; ++c) + IIO_CTL_ADDR[unit].push_back(SKX_IIO_CBDMA_CTL0 + SKX_IIO_PM_REG_STEP*unit + c); + } + } } #ifdef __linux__ @@ -1406,7 +1447,6 @@ PCM::PCM() : backup_ofile(NULL), run_state(1) { - #ifdef _MSC_VER TCHAR driverPath[1040]; // length for current directory + "\\msr.sys" GetCurrentDirectory(1024, driverPath); @@ -1502,6 +1542,7 @@ bool PCM::isCPUModelSupported(int model_) || model_ == BROADWELL || model_ == KNL || model_ == SKL + || model_ == SKX ); } @@ -1760,7 +1801,7 @@ PCM::ErrorCode PCM::program(const PCM::ProgramMode mode_, const void * parameter coreEventDesc[1].umask_value = ARCH_LLC_REFERENCE_UMASK; core_gen_counter_num_used = 2; - } else if ( SKL == cpu_model ) + } else if (useSkylakeEvents()) { coreEventDesc[0].event_number = SKL_MEM_LOAD_RETIRED_L3_MISS_EVTNR; coreEventDesc[0].umask_value = SKL_MEM_LOAD_RETIRED_L3_MISS_UMASK; @@ -2028,7 +2069,7 @@ void PCM::reportQPISpeed() const if(server_pcicfg_uncore[i].get()) server_pcicfg_uncore[i]->reportQPISpeed(); } } else { - std::cerr << "Max QPI speed: " << max_qpi_speed / (1e9) << " GBytes/second (" << max_qpi_speed / (1e9*double(DATA_BYTES_PER_QPI_CYCLE)) << " GT/second)" << std::endl; + std::cerr << "Max QPI speed: " << max_qpi_speed / (1e9) << " GBytes/second (" << max_qpi_speed / (1e9*getBytesPerLinkTransfer()) << " GT/second)" << std::endl; } } @@ -2444,6 +2485,8 @@ const char * PCM::getUArchCodename(int32 cpu_model_) const return "Broadwell"; case SKL: return "Skylake"; + case SKX: + return "Skylake-SP"; } return "unknown"; } @@ -2890,6 +2933,7 @@ void BasicCounterState::readAndAggregate(std::shared_ptr msr) case PCM::HASWELL: case PCM::BROADWELL: case PCM::SKL: + case PCM::SKX: msr->read(IA32_PMC0, &cL3Miss); msr->read(IA32_PMC1, &cL3UnsharedHit); msr->read(IA32_PMC2, &cL2HitM); @@ -2981,9 +3025,9 @@ PCM::ErrorCode PCM::programServerUncorePowerMetrics(int mc_profile, int pcu_prof case 3: PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x04); // Thermal frequency limit cycles: FREQ_MAX_LIMIT_THERMAL_CYCLES PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x05); // Power frequency limit cycles: FREQ_MAX_POWER_CYCLES - PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x07); // Clipped frequency limit cycles: FREQ_MAX_CURRENT_CYCLES + PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x07); // Clipped frequency limit cycles: FREQ_MAX_CURRENT_CYCLES (not supported on SKX) break; - case 4: + case 4: // not supported on SKX PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x06); // OS frequency limit cycles: FREQ_MAX_OS_CYCLES PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x05); // Power frequency limit cycles: FREQ_MAX_POWER_CYCLES PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x07); // Clipped frequency limit cycles: FREQ_MAX_CURRENT_CYCLES @@ -2997,12 +3041,15 @@ PCM::ErrorCode PCM::programServerUncorePowerMetrics(int mc_profile, int pcu_prof { PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x60) + PCU_MSR_PMON_CTL_EDGE_DET ; // number of frequency transitions PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x60) ; // cycles spent changing frequency: FREQ_TRANS_CYCLES - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x74) + PCU_MSR_PMON_CTL_EDGE_DET ; // number of frequency transitions PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x74) ; // cycles spent changing frequency: FREQ_TRANS_CYCLES - PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x79) + PCU_MSR_PMON_CTL_EDGE_DET ; // number of UFS transitions - PCUCntConf[0] = PCU_MSR_PMON_CTL_EVENT(0x79) ; // UFS transition cyclesss + if(HASWELLX == cpu_model) + { + PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x79) + PCU_MSR_PMON_CTL_EDGE_DET ; // number of UFS transitions + PCUCntConf[0] = PCU_MSR_PMON_CTL_EVENT(0x79) ; // UFS transition cycles + } } else { std::cerr << "ERROR: no frequency transition events defined for CPU model "<< cpu_model << std::endl; @@ -3013,10 +3060,10 @@ PCM::ErrorCode PCM::programServerUncorePowerMetrics(int mc_profile, int pcu_prof { PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x2B) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC2 transitions PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x2D) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC6 transitions - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { - PCUCntConf[0] = PCU_MSR_PMON_CTL_EVENT(0x4E) ; // PC1e residencys - PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x4E) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC1 transitions + PCUCntConf[0] = PCU_MSR_PMON_CTL_EVENT(0x4E) ; // PC1e residenicies (not supported on SKX) + PCUCntConf[1] = PCU_MSR_PMON_CTL_EVENT(0x4E) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC1 transitions (not supported on SKX) PCUCntConf[2] = PCU_MSR_PMON_CTL_EVENT(0x2B) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC2 transitions PCUCntConf[3] = PCU_MSR_PMON_CTL_EVENT(0x2D) + PCU_MSR_PMON_CTL_EDGE_DET ; // PC6 transitions } else @@ -3065,6 +3112,7 @@ PCM::ErrorCode PCM::programServerUncorePowerMetrics(int mc_profile, int pcu_prof case BDX_DE: case BDX: case KNL: + case SKX: PCU_MSR_PMON_BOX_FILTER_ADDR = HSX_PCU_MSR_PMON_BOX_FILTER_ADDR; PCU_MSR_PMON_CTLX_ADDR[0] = HSX_PCU_MSR_PMON_CTL0_ADDR; PCU_MSR_PMON_CTLX_ADDR[1] = HSX_PCU_MSR_PMON_CTL1_ADDR; @@ -3313,13 +3361,13 @@ void PCM::readQPICounters(SystemCounterState & result) MSR[core]->read(R_MSR_PMON_CTR9, &(result.incomingQPIPackets[s][3])); // outgoing idle flits from QPI link 0 - MSR[core]->read(R_MSR_PMON_CTR3, &(result.outgoingQPIIdleFlits[s][0])); + MSR[core]->read(R_MSR_PMON_CTR3, &(result.outgoingQPIFlits[s][0])); // outgoing idle flits from QPI link 1 (yes, from CTR0) - MSR[core]->read(R_MSR_PMON_CTR2, &(result.outgoingQPIIdleFlits[s][1])); + MSR[core]->read(R_MSR_PMON_CTR2, &(result.outgoingQPIFlits[s][1])); // outgoing idle flits from QPI link 2 - MSR[core]->read(R_MSR_PMON_CTR10, &(result.outgoingQPIIdleFlits[s][2])); + MSR[core]->read(R_MSR_PMON_CTR10, &(result.outgoingQPIFlits[s][2])); // outgoing idle flits from QPI link 3 - MSR[core]->read(R_MSR_PMON_CTR11, &(result.outgoingQPIIdleFlits[s][3])); + MSR[core]->read(R_MSR_PMON_CTR11, &(result.outgoingQPIFlits[s][3])); SocketProcessed[s] = true; } @@ -3388,10 +3436,11 @@ void PCM::readQPICounters(SystemCounterState & result) { server_pcicfg_uncore[s]->freezeCounters(); for (uint32 port = 0; port < (uint32)getQPILinksPerSocket(); ++port) - { - result.incomingQPIPackets[s][port] = server_pcicfg_uncore[s]->getIncomingDataFlits(port) / (64/DATA_BYTES_PER_QPI_FLIT); - result.outgoingQPIDataNonDataFlits[s][port] = server_pcicfg_uncore[s]->getOutgoingDataNonDataFlits(port); - } + { + result.incomingQPIPackets[s][port] = uint64(double(server_pcicfg_uncore[s]->getIncomingDataFlits(port)) / (64./getDataBytesPerFlit())); + result.outgoingQPIFlits[s][port] = server_pcicfg_uncore[s]->getOutgoingFlits(port); + result.TxL0Cycles[s][port] = server_pcicfg_uncore[s]->getUPIL0TxCycles(port); + } server_pcicfg_uncore[s]->unfreezeCounters(); } } @@ -3690,6 +3739,9 @@ static const uint32 IMC_DEV_IDS[] = { 0x6fd1, 0x6fd4, 0x6fd5, + 0x2042, + 0x2046, + 0x204a, 0x7840, 0x7841, 0x7842, @@ -3698,9 +3750,14 @@ static const uint32 IMC_DEV_IDS[] = { 0x781f }; -std::vector > ServerPCICFGUncore::socket2bus; +static const uint32 UPI_DEV_IDS[] = { + 0x2058 +}; + +std::vector > ServerPCICFGUncore::socket2iMCbus; +std::vector > ServerPCICFGUncore::socket2UPIbus; -void ServerPCICFGUncore::initSocket2Bus() +void ServerPCICFGUncore::initSocket2Bus(std::vector > & socket2bus, uint32 device, uint32 function, const uint32 DEV_IDS[], uint32 devIdsSize) { if(!socket2bus.empty()) return; @@ -3721,7 +3778,7 @@ void ServerPCICFGUncore::initSocket2Bus() uint32 value = 0; try { - PciHandleType h(mcfg[s].PCISegmentGroupNumber, bus, MCX_CHY_REGISTER_DEV_ADDR[0][0], MCX_CHY_REGISTER_FUNC_ADDR[0][0]); + PciHandleType h(mcfg[s].PCISegmentGroupNumber, bus, device, function); h.read32(0, &value); } catch(...) @@ -3734,10 +3791,10 @@ void ServerPCICFGUncore::initSocket2Bus() if (vendor_id != PCM_INTEL_PCI_VENDOR_ID) continue; - for (uint32 i = 0; i < (uint32)sizeof(IMC_DEV_IDS) / sizeof(IMC_DEV_IDS[0]); ++i) + for (uint32 i = 0; i < devIdsSize; ++i) { // match - if(IMC_DEV_IDS[i] == device_id) + if(DEV_IDS[i] == device_id) { // std::cout << "DEBUG: found bus "<getCPUModel(); + #define PCM_PCICFG_EDC_INIT(controller, clock, arch) \ EDCX_ECLK_REGISTER_DEV_ADDR[controller] = arch##_EDC##controller##_##clock##_REGISTER_DEV_ADDR; \ EDCX_ECLK_REGISTER_FUNC_ADDR[controller] = arch##_EDC##controller##_##clock##_REGISTER_FUNC_ADDR; - const uint32 cpu_model = pcm->getCPUModel(); if(cpu_model == PCM::JAKETOWN || cpu_model == PCM::IVYTOWN) { @@ -3829,6 +3888,17 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : PCM_PCICFG_MC_INIT(1, 2, HSX) PCM_PCICFG_MC_INIT(1, 3, HSX) } + else if(cpu_model == PCM::SKX) + { + PCM_PCICFG_MC_INIT(0, 0, SKX) + PCM_PCICFG_MC_INIT(0, 1, SKX) + PCM_PCICFG_MC_INIT(0, 2, SKX) + PCM_PCICFG_MC_INIT(0, 3, SKX) + PCM_PCICFG_MC_INIT(1, 0, SKX) + PCM_PCICFG_MC_INIT(1, 1, SKX) + PCM_PCICFG_MC_INIT(1, 2, SKX) + PCM_PCICFG_MC_INIT(1, 3, SKX) + } else if(cpu_model == PCM::KNL) { // 2 DDR4 Memory Controllers with 3 channels each @@ -3858,25 +3928,25 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : #undef PCM_PCICFG_MC_INIT #undef PCM_PCICFG_EDC_INIT - initSocket2Bus(); + initSocket2Bus(socket2iMCbus, MCX_CHY_REGISTER_DEV_ADDR[0][0], MCX_CHY_REGISTER_FUNC_ADDR[0][0], IMC_DEV_IDS, (uint32)sizeof(IMC_DEV_IDS) / sizeof(IMC_DEV_IDS[0])); const uint32 total_sockets_ = pcm->getNumSockets(); - if(total_sockets_ == socket2bus.size()) + if(total_sockets_ == socket2iMCbus.size()) { - groupnr = socket2bus[socket_].first; - bus = socket2bus[socket_].second; + groupnr = socket2iMCbus[socket_].first; + iMCbus = socket2iMCbus[socket_].second; } else if(total_sockets_ <= 4) { - bus = getBusFromSocket(socket_); - if(bus < 0) + iMCbus = getBusFromSocket(socket_); + if(iMCbus < 0) { std::cerr << "Cannot find bus for socket "<< socket_ <<" on system with "<< total_sockets_ << " sockets."<< std::endl; throw std::exception(); } else { - std::cerr << "PCM Warning: the bus for socket "<< socket_ <<" on system with "<< total_sockets_ << " sockets could not find via PCI bus scan. Using cpubusno register. Bus = "<< bus << std::endl; + std::cerr << "PCM Warning: the bus for socket "<< socket_ <<" on system with "<< total_sockets_ << " sockets could not find via PCI bus scan. Using cpubusno register. Bus = "<< iMCbus << std::endl; } } else @@ -3888,7 +3958,7 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : { #define PCM_PCICFG_SETUP_MC_HANDLE(controller,channel) \ { \ - PciHandleType * handle = createIntelPerfMonDevice(groupnr, bus, \ + PciHandleType * handle = createIntelPerfMonDevice(groupnr, iMCbus, \ MCX_CHY_REGISTER_DEV_ADDR[controller][channel], MCX_CHY_REGISTER_FUNC_ADDR[controller][channel], true); \ if (handle) imcHandles.push_back(std::shared_ptr(handle)); \ } @@ -3920,7 +3990,7 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : { #define PCM_PCICFG_SETUP_EDC_HANDLE(controller,clock) \ { \ - PciHandleType * handle = createIntelPerfMonDevice(groupnr, bus, \ + PciHandleType * handle = createIntelPerfMonDevice(groupnr, iMCbus, \ EDCX_##clock##_REGISTER_DEV_ADDR[controller], EDCX_##clock##_REGISTER_FUNC_ADDR[controller], true); \ if (handle) edcHandles.push_back(std::shared_ptr(handle)); \ } @@ -3972,6 +4042,12 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : PCM_PCICFG_QPI_INIT(1, HSX); PCM_PCICFG_QPI_INIT(2, HSX); } + else if(cpu_model == PCM::SKX) + { + PCM_PCICFG_QPI_INIT(0, SKX); + PCM_PCICFG_QPI_INIT(1, SKX); + PCM_PCICFG_QPI_INIT(2, SKX); + } else { std::cout << "Error: Uncore PMU for processor with model id "<< cpu_model << " is not supported."<< std::endl; @@ -3980,24 +4056,71 @@ ServerPCICFGUncore::ServerPCICFGUncore(uint32 socket_, PCM * pcm) : #undef PCM_PCICFG_QPI_INIT + if(cpu_model == PCM::SKX) + { + initSocket2Bus(socket2UPIbus, QPI_PORTX_REGISTER_DEV_ADDR[0], QPI_PORTX_REGISTER_FUNC_ADDR[0], UPI_DEV_IDS, (uint32)sizeof(UPI_DEV_IDS) / sizeof(UPI_DEV_IDS[0])); + if(total_sockets_ == socket2UPIbus.size()) + { + UPIbus = socket2UPIbus[socket_].second; + if(groupnr != socket2UPIbus[socket_].first) + { + UPIbus = -1; + std::cerr << "PCM error: mismatching PCICFG group number for UPI and IMC perfmon devices." << std::endl; + } + } + else + { + std::cerr << "PCM error: Did not find UPI perfmon device on every socket in a multisocket system." << std::endl; + } + + LINK_PCI_PMON_BOX_CTL_ADDR = U_L_PCI_PMON_BOX_CTL_ADDR; + + LINK_PCI_PMON_CTL_ADDR[3] = U_L_PCI_PMON_CTL3_ADDR; + LINK_PCI_PMON_CTL_ADDR[2] = U_L_PCI_PMON_CTL2_ADDR; + LINK_PCI_PMON_CTL_ADDR[1] = U_L_PCI_PMON_CTL1_ADDR; + LINK_PCI_PMON_CTL_ADDR[0] = U_L_PCI_PMON_CTL0_ADDR; + + LINK_PCI_PMON_CTR_ADDR[3] = U_L_PCI_PMON_CTR3_ADDR; + LINK_PCI_PMON_CTR_ADDR[2] = U_L_PCI_PMON_CTR2_ADDR; + LINK_PCI_PMON_CTR_ADDR[1] = U_L_PCI_PMON_CTR1_ADDR; + LINK_PCI_PMON_CTR_ADDR[0] = U_L_PCI_PMON_CTR0_ADDR; + } + else + { + UPIbus = iMCbus; + LINK_PCI_PMON_BOX_CTL_ADDR = Q_P_PCI_PMON_BOX_CTL_ADDR; + + LINK_PCI_PMON_CTL_ADDR[3] = Q_P_PCI_PMON_CTL3_ADDR; + LINK_PCI_PMON_CTL_ADDR[2] = Q_P_PCI_PMON_CTL2_ADDR; + LINK_PCI_PMON_CTL_ADDR[1] = Q_P_PCI_PMON_CTL1_ADDR; + LINK_PCI_PMON_CTL_ADDR[0] = Q_P_PCI_PMON_CTL0_ADDR; + + LINK_PCI_PMON_CTR_ADDR[3] = Q_P_PCI_PMON_CTR3_ADDR; + LINK_PCI_PMON_CTR_ADDR[2] = Q_P_PCI_PMON_CTR2_ADDR; + LINK_PCI_PMON_CTR_ADDR[1] = Q_P_PCI_PMON_CTR1_ADDR; + LINK_PCI_PMON_CTR_ADDR[0] = Q_P_PCI_PMON_CTR0_ADDR; + } + try { { - PciHandleType * handle = createIntelPerfMonDevice(groupnr, bus, QPI_PORTX_REGISTER_DEV_ADDR[0], QPI_PORTX_REGISTER_FUNC_ADDR[0], true); + PciHandleType * handle = createIntelPerfMonDevice(groupnr, UPIbus, QPI_PORTX_REGISTER_DEV_ADDR[0], QPI_PORTX_REGISTER_FUNC_ADDR[0], true); if (handle) qpiLLHandles.push_back(std::shared_ptr(handle)); else - std::cerr << "ERROR: QPI LL monitoring device ("<< groupnr<<":"<(handle)); else - std::cerr << "ERROR: QPI LL monitoring device ("<< groupnr<<":"<(handle)); else { @@ -4058,6 +4181,7 @@ void ServerPCICFGUncore::programServerUncoreMemoryMetrics(int rankA, int rankB) case PCM::HASWELLX: case PCM::BDX_DE: case PCM::BDX: + case PCM::SKX: MCCntConfig[0] = MC_CH_PCI_PMON_CTL_EVENT((0xb0 + rankA)) + MC_CH_PCI_PMON_CTL_UMASK(16); // RD_CAS_RANK(rankA) all banks MCCntConfig[1] = MC_CH_PCI_PMON_CTL_EVENT((0xb8 + rankA)) + MC_CH_PCI_PMON_CTL_UMASK(16); // WR_CAS_RANK(rankA) all banks MCCntConfig[2] = MC_CH_PCI_PMON_CTL_EVENT((0xb0 + rankB)) + MC_CH_PCI_PMON_CTL_UMASK(16); // RD_CAS_RANK(rankB) all banks @@ -4101,54 +4225,62 @@ void ServerPCICFGUncore::program() programIMC(MCCntConfig); if(cpu_model == PCM::KNL) programEDC(EDCCntConfig); + const uint32 extra = (cpu_model == PCM::SKX)?U_L_PCI_PMON_BOX_CTL_RSV:Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN; + uint32 event[4]; + if(cpu_model == PCM::SKX) + { + // monitor TxL0_POWER_CYCLES + event[0] = Q_P_PCI_PMON_CTL_EVENT(0x26); + // monitor RxL_FLITS.DATA on counter 1 + event[1] = Q_P_PCI_PMON_CTL_EVENT(0x03) + Q_P_PCI_PMON_CTL_UMASK(0xF); + // monitor TxL_FLITS.IDLE on counter 2 + event[2] = Q_P_PCI_PMON_CTL_EVENT(0x02) + Q_P_PCI_PMON_CTL_UMASK(0x47); + // monitor UPI CLOCKTICKS + event[3] = Q_P_PCI_PMON_CTL_EVENT(0x01); + } + else + { + // monitor DRS data received on counter 0: RxL_FLITS_G1.DRS_DATA + event[0] = Q_P_PCI_PMON_CTL_EVENT(0x02) + Q_P_PCI_PMON_CTL_EVENT_EXT + Q_P_PCI_PMON_CTL_UMASK(8); + // monitor NCB data received on counter 1: RxL_FLITS_G2.NCB_DATA + event[1] = Q_P_PCI_PMON_CTL_EVENT(0x03) + Q_P_PCI_PMON_CTL_EVENT_EXT + Q_P_PCI_PMON_CTL_UMASK(4); + // monitor outgoing data+nondata flits on counter 2: TxL_FLITS_G0.DATA + TxL_FLITS_G0.NON_DATA + event[2] = Q_P_PCI_PMON_CTL_EVENT(0x00) + Q_P_PCI_PMON_CTL_UMASK(6); + // monitor QPI clocks + event[3] = Q_P_PCI_PMON_CTL_EVENT(0x14); // QPI clocks (CLOCKTICKS) + } for (uint32 i = 0; i < (uint32)qpiLLHandles.size(); ++i) { // QPI LL PMU // freeze enable - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra); // freeze - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); #ifdef PCM_UNCORE_PMON_BOX_CHECK_STATUS uint32 val = 0; - qpiLLHandles[i]->read32(Q_P_PCI_PMON_BOX_CTL_ADDR, &val); - if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ)) + qpiLLHandles[i]->read32(LINK_PCI_PMON_BOX_CTL_ADDR, &val); + if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ)) { std::cerr << "ERROR: QPI LL counter programming seems not to work. Q_P" << i << "_PCI_PMON_BOX_CTL=0x" << std::hex << val << std::endl; std::cerr << " Please see BIOS options to enable the export of performance monitoring devices (devices 8 and 9: function 2)." << std::endl; } #endif - // enable counter 0 - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL0_ADDR, Q_P_PCI_PMON_CTL_EN); - - // monitor DRS data received on counter 0: RxL_FLITS_G1.DRS_DATA - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL0_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x02) + Q_P_PCI_PMON_CTL_EVENT_EXT + Q_P_PCI_PMON_CTL_UMASK(8)); - - // enable counter 1 - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL1_ADDR, Q_P_PCI_PMON_CTL_EN); - - // monitor NCB data received on counter 1: RxL_FLITS_G2.NCB_DATA - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL1_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x03) + Q_P_PCI_PMON_CTL_EVENT_EXT + Q_P_PCI_PMON_CTL_UMASK(4)); - - // enable counter 2 - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL2_ADDR, Q_P_PCI_PMON_CTL_EN); - - // monitor outgoing data+nondata flits on counter 2: TxL_FLITS_G0.DATA + TxL_FLITS_G0.NON_DATA - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL2_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x00) + Q_P_PCI_PMON_CTL_UMASK(6)); + for(int cnt = 0; cnt < 4; ++cnt) + { + // enable counter + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[cnt], (event[cnt]?Q_P_PCI_PMON_CTL_EN:0)); - // enable counter 3 - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL3_ADDR, Q_P_PCI_PMON_CTL_EN); - - // monitor QPI clocks - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL3_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x14)); // QPI clocks (CLOCKTICKS) + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[cnt], (event[cnt]?Q_P_PCI_PMON_CTL_EN:0) + event[cnt]); + } // reset counters values - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ + Q_P_PCI_PMON_BOX_CTL_RST_COUNTERS); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ + Q_P_PCI_PMON_BOX_CTL_RST_COUNTERS); // unfreeze counters - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra); } } @@ -4255,54 +4387,66 @@ uint64 ServerPCICFGUncore::getIncomingDataFlits(uint32 port) if (port >= (uint32)qpiLLHandles.size()) return 0; - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR0_ADDR, &drs); - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR1_ADDR, &ncb); + if(cpu_model != PCM::SKX) + { + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[0], &drs); + } + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[1], &ncb); return drs + ncb; } -uint64 ServerPCICFGUncore::getOutgoingDataNonDataFlits(uint32 port) +uint64 ServerPCICFGUncore::getOutgoingFlits(uint32 port) { return getQPILLCounter(port,2); } +uint64 ServerPCICFGUncore::getUPIL0TxCycles(uint32 port) +{ + if(cpu_model == PCM::SKX) + return getQPILLCounter(port,0); + return 0; +} + void ServerPCICFGUncore::program_power_metrics(int mc_profile) { + const uint32 cpu_model = PCM::getInstance()->getCPUModel(); + const uint32 extra = (cpu_model == PCM::SKX)?U_L_PCI_PMON_BOX_CTL_RSV:Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN; for (uint32 i = 0; i < (uint32)qpiLLHandles.size(); ++i) { // QPI LL PMU // freeze enable - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra); // freeze - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); #ifdef PCM_UNCORE_PMON_BOX_CHECK_STATUS uint32 val = 0; - qpiLLHandles[i]->read32(Q_P_PCI_PMON_BOX_CTL_ADDR, &val); - if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ)) + qpiLLHandles[i]->read32(LINK_PCI_PMON_BOX_CTL_ADDR, &val); + if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ)) { std::cerr << "ERROR: QPI LL counter programming seems not to work. Q_P" << i << "_PCI_PMON_BOX_CTL=0x" << std::hex << val << std::endl; std::cerr << " Please see BIOS options to enable the export of performance monitoring devices." << std::endl; } #endif - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL3_ADDR, Q_P_PCI_PMON_CTL_EN); - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL3_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x14)); // QPI clocks (CLOCKTICKS) + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[3], Q_P_PCI_PMON_CTL_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[3], Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT((cpu_model==PCM::SKX ? 0x01 : 0x14))); // QPI/UPI clocks (CLOCKTICKS) + + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[0], Q_P_PCI_PMON_CTL_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[0], Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT((cpu_model == PCM::SKX ? 0x27 : 0x0D))); // L0p Tx Cycles (TxL0P_POWER_CYCLES) + + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[2], Q_P_PCI_PMON_CTL_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_CTL_ADDR[2], Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT((cpu_model == PCM::SKX ? 0x21 : 0x12))); // L1 Cycles (L1_POWER_CYCLES) - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL0_ADDR, Q_P_PCI_PMON_CTL_EN); - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL0_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x0D)); // L0p Tx Cycles (TxL0P_POWER_CYCLES) - - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL2_ADDR, Q_P_PCI_PMON_CTL_EN); - qpiLLHandles[i]->write32(Q_P_PCI_PMON_CTL2_ADDR, Q_P_PCI_PMON_CTL_EN + Q_P_PCI_PMON_CTL_EVENT(0x12)); // L1 Cycles (L1_POWER_CYCLES) - // reset counters values - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ + Q_P_PCI_PMON_BOX_CTL_RST_COUNTERS); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ + Q_P_PCI_PMON_BOX_CTL_RST_COUNTERS); // unfreeze counters - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra); } - + uint32 MCCntConfig[4] = {0,0,0,0}; switch(mc_profile) { @@ -4342,6 +4486,7 @@ void ServerPCICFGUncore::program_power_metrics(int mc_profile) void ServerPCICFGUncore::programIMC(const uint32 * MCCntConfig) { + const uint32 extraIMC = (PCM::getInstance()->getCPUModel() == PCM::SKX)?SKX_MC_CH_PCI_PMON_BOX_CTL_RSV:MC_CH_PCI_PMON_BOX_CTL_FRZ_EN; uint64 MC_CH_PCI_PMON_BOX_CTL_ADDR = 0; uint64 MC_CH_PCI_PMON_FIXED_CTL_ADDR = 0; uint64 MC_CH_PCI_PMON_CTL0_ADDR = 0; @@ -4371,14 +4516,14 @@ void ServerPCICFGUncore::programIMC(const uint32 * MCCntConfig) { // imc PMU // freeze enable - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN); + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC); // freeze - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN + MC_CH_PCI_PMON_BOX_CTL_FRZ); + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC + MC_CH_PCI_PMON_BOX_CTL_FRZ); #ifdef PCM_UNCORE_PMON_BOX_CHECK_STATUS uint32 val = 0; imcHandles[i]->read32(MC_CH_PCI_PMON_BOX_CTL_ADDR, &val); - if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (MC_CH_PCI_PMON_BOX_CTL_FRZ_EN + MC_CH_PCI_PMON_BOX_CTL_FRZ)) + if ((val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) != (extraIMC + MC_CH_PCI_PMON_BOX_CTL_FRZ)) { std::cerr << "ERROR: IMC counter programming seems not to work. MC_CH" << i << "_PCI_PMON_BOX_CTL=0x" << std::hex << val << " " << (val & UNCORE_PMON_BOX_CTL_VALID_BITS_MASK) << std::endl; std::cerr << " Please see BIOS options to enable the export of performance monitoring devices." << std::endl; @@ -4408,10 +4553,10 @@ void ServerPCICFGUncore::programIMC(const uint32 * MCCntConfig) imcHandles[i]->write32(MC_CH_PCI_PMON_CTL3_ADDR, MC_CH_PCI_PMON_CTL_EN + MCCntConfig[3]); // reset counters values - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN + MC_CH_PCI_PMON_BOX_CTL_FRZ + MC_CH_PCI_PMON_BOX_CTL_RST_COUNTERS); + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC + MC_CH_PCI_PMON_BOX_CTL_FRZ + MC_CH_PCI_PMON_BOX_CTL_RST_COUNTERS); // unfreeze counters - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN); + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC); } } @@ -4484,8 +4629,9 @@ void ServerPCICFGUncore::freezeCounters() { uint64 MC_CH_PCI_PMON_BOX_CTL_ADDR = 0; uint64 EDC_CH_PCI_PMON_BOX_CTL_ADDR = 0; - PCM * pcm = PCM::getInstance(); - const uint32 cpu_model = pcm->getCPUModel(); + const uint32 cpu_model = PCM::getInstance()->getCPUModel(); + const uint32 extra = (cpu_model == PCM::SKX)?U_L_PCI_PMON_BOX_CTL_RSV:Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN; + const uint32 extraIMC = (cpu_model == PCM::SKX)?SKX_MC_CH_PCI_PMON_BOX_CTL_RSV:MC_CH_PCI_PMON_BOX_CTL_FRZ_EN; if (cpu_model == PCM::KNL) { MC_CH_PCI_PMON_BOX_CTL_ADDR = KNX_MC_CH_PCI_PMON_BOX_CTL_ADDR; EDC_CH_PCI_PMON_BOX_CTL_ADDR = KNX_EDC_CH_PCI_PMON_BOX_CTL_ADDR; @@ -4494,12 +4640,12 @@ void ServerPCICFGUncore::freezeCounters() } for (size_t i = 0; i < (size_t)qpiLLHandles.size(); ++i) { - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); - } + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra + Q_P_PCI_PMON_BOX_CTL_RST_FRZ); + } for (size_t i = 0; i < (size_t)imcHandles.size(); ++i) { - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN + MC_CH_PCI_PMON_BOX_CTL_FRZ); - } + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC + MC_CH_PCI_PMON_BOX_CTL_FRZ); + } for (size_t i = 0; i < (size_t)edcHandles.size(); ++i) { edcHandles[i]->write32(EDC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN + MC_CH_PCI_PMON_BOX_CTL_FRZ); @@ -4508,10 +4654,11 @@ void ServerPCICFGUncore::freezeCounters() void ServerPCICFGUncore::unfreezeCounters() { + const uint32 cpu_model = PCM::getInstance()->getCPUModel(); + const uint32 extra = (cpu_model == PCM::SKX)?U_L_PCI_PMON_BOX_CTL_RSV:Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN; + const uint32 extraIMC = (cpu_model == PCM::SKX)?SKX_MC_CH_PCI_PMON_BOX_CTL_RSV:MC_CH_PCI_PMON_BOX_CTL_FRZ_EN; uint64 MC_CH_PCI_PMON_BOX_CTL_ADDR = 0; uint64 EDC_CH_PCI_PMON_BOX_CTL_ADDR = 0; - PCM * pcm = PCM::getInstance(); - const uint32 cpu_model = pcm->getCPUModel(); if (cpu_model == PCM::KNL) { MC_CH_PCI_PMON_BOX_CTL_ADDR = KNX_MC_CH_PCI_PMON_BOX_CTL_ADDR; EDC_CH_PCI_PMON_BOX_CTL_ADDR = KNX_EDC_CH_PCI_PMON_BOX_CTL_ADDR; @@ -4521,11 +4668,11 @@ void ServerPCICFGUncore::unfreezeCounters() for (size_t i = 0; i < (size_t)qpiLLHandles.size(); ++i) { - qpiLLHandles[i]->write32(Q_P_PCI_PMON_BOX_CTL_ADDR, Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN); + qpiLLHandles[i]->write32(LINK_PCI_PMON_BOX_CTL_ADDR, extra); } for (size_t i = 0; i < (size_t)imcHandles.size(); ++i) { - imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, MC_CH_PCI_PMON_BOX_CTL_FRZ_EN); + imcHandles[i]->write32(MC_CH_PCI_PMON_BOX_CTL_ADDR, extraIMC); } for (size_t i = 0; i < (size_t)edcHandles.size(); ++i) { @@ -4540,7 +4687,7 @@ uint64 ServerPCICFGUncore::getQPIClocks(uint32 port) if (port >= (uint32)qpiLLHandles.size()) return 0; - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR3_ADDR, &res); + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[3], &res); return res; } @@ -4552,7 +4699,7 @@ uint64 ServerPCICFGUncore::getQPIL0pTxCycles(uint32 port) if (port >= (uint32)qpiLLHandles.size()) return 0; - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR0_ADDR, &res); + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[0], &res); return res; } @@ -4564,7 +4711,7 @@ uint64 ServerPCICFGUncore::getQPIL1Cycles(uint32 port) if (port >= (uint32)qpiLLHandles.size()) return 0; - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR2_ADDR, &res); + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[2], &res); return res; } @@ -4697,23 +4844,9 @@ uint64 ServerPCICFGUncore::getQPILLCounter(uint32 port, uint32 counter) { uint64 result = 0; - if (port < (uint32)qpiLLHandles.size()) + if (port < (uint32)qpiLLHandles.size() && counter < 4) { - switch(counter) - { - case 0: - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR0_ADDR, &result); - break; - case 1: - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR1_ADDR, &result); - break; - case 2: - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR2_ADDR, &result); - break; - case 3: - qpiLLHandles[port]->read64(Q_P_PCI_PMON_CTR3_ADDR, &result); - break; - } + qpiLLHandles[port]->read64(LINK_PCI_PMON_CTR_ADDR[counter], &result); } return result; @@ -4722,7 +4855,7 @@ uint64 ServerPCICFGUncore::getQPILLCounter(uint32 port, uint32 counter) void ServerPCICFGUncore::enableJKTWorkaround(bool enable) { { - PciHandleType reg(groupnr,bus,14,0); + PciHandleType reg(groupnr,iMCbus,14,0); uint32 value = 0; reg.read32(0x84, &value); if(enable) @@ -4732,7 +4865,7 @@ void ServerPCICFGUncore::enableJKTWorkaround(bool enable) reg.write32(0x84, value); } { - PciHandleType reg(groupnr,bus,8,0); + PciHandleType reg(groupnr,iMCbus,8,0); uint32 value = 0; reg.read32(0x80, &value); if(enable) @@ -4742,7 +4875,7 @@ void ServerPCICFGUncore::enableJKTWorkaround(bool enable) reg.write32(0x80, value); } { - PciHandleType reg(groupnr,bus,9,0); + PciHandleType reg(groupnr,iMCbus,9,0); uint32 value = 0; reg.read32(0x80, &value); if(enable) @@ -4753,47 +4886,119 @@ void ServerPCICFGUncore::enableJKTWorkaround(bool enable) } } +#define PCM_MEM_CAPACITY (1024ULL*1024ULL*64ULL) // 64 MByte + +void ServerPCICFGUncore::initMemTest() +{ + #ifdef __linux__ + size_t capacity = PCM_MEM_CAPACITY; + char * buffer = (char *) mmap(NULL, capacity, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (buffer == MAP_FAILED) { + std::cerr << "ERROR: mmap failed"<< std::endl; + return; + } + unsigned long maxNode = (unsigned long)(readMaxFromSysFS("/sys/devices/system/node/online") + 1); + if(maxNode == 0) + { + std::cerr << "ERROR: max node is 0 "<< std::endl; + return; + } + if(maxNode >= 63) maxNode = 63; + const unsigned long nodeMask = (1<((4000000000ULL + ((uint64)value)*800000000ULL)*2ULL); + if(cpumodel != PCM::SKX) + { + PciHandleType reg(groupnr,UPIbus,QPI_PORTX_REGISTER_DEV_ADDR[i],QPI_PORT0_MISC_REGISTER_FUNC_ADDR); + reg.read32(QPI_RATE_STATUS_ADDR, &value); + value &= 7; // extract lower 3 bits + if(value) qpi_speed[i] = static_cast((4000000000ULL + ((uint64)value)*800000000ULL)*2ULL); + } if(qpi_speed[i] == 0ULL) { - std::cerr << "Warning: QPI_RATE_STATUS register is not available on port "<< i <<". Computing QPI speed using a measurement loop." << std::endl; + if(cpumodel != PCM::SKX) + std::cerr << "Warning: QPI_RATE_STATUS register is not available on port "<< i <<". Computing QPI speed using a measurement loop." << std::endl; // compute qpi speed const uint64 timerGranularity = 1000000ULL; // mks PCM * pcm = PCM::getInstance(); + initMemTest(); uint64 startClocks = getQPIClocks((uint32)i); uint64 startTSC = pcm->getTickCount(timerGranularity, core_nr); uint64 endTSC; do { + doMemTest(); endTSC = pcm->getTickCount(timerGranularity, core_nr); } while (endTSC - startTSC < 200000ULL); // spin for 200 ms uint64 endClocks = getQPIClocks((uint32)i); + cleanupMemTest(); - qpi_speed[i] = ((std::max)((endClocks - startClocks) * 16ULL * timerGranularity / (endTSC - startTSC),0ULL)); + qpi_speed[i] = ((std::max)(uint64(double(endClocks - startClocks) * PCM::getBytesPerLinkCycle(cpumodel) * double(timerGranularity) / double(endTSC - startTSC)),0ULL)); if(cpumodel == PCM::HASWELLX || cpumodel == PCM::BDX) /* BDX_DE does not have QPI. */{ qpi_speed[i] /=2; // HSX runs QPI clocks with doubled speed } } } + if(cpumodel == PCM::SKX) + { + // check the speed of link 3 + if(qpi_speed.size() == 3 && qpi_speed[2] == 0) + { + std::cerr << "UPI link 3 is disabled"<< std::endl; + qpi_speed.resize(2); + qpiLLHandles.resize(2); + } + } } if(!qpi_speed.empty()) { @@ -4805,6 +5010,15 @@ uint64 ServerPCICFGUncore::computeQPISpeed(const uint32 core_nr, const int cpumo } } +void ServerPCICFGUncore::reportQPISpeed() const +{ + PCM * m = PCM::getInstance(); + std::cerr.precision(1); + std::cerr << std::fixed; + for (uint32 i = 0; i < (uint32)qpi_speed.size(); ++i) + std::cerr << "Max QPI link " << i << " speed: " << qpi_speed[i] / (1e9) << " GBytes/second (" << qpi_speed[i] / (1e9 * m->getBytesPerLinkTransfer()) << " GT/second)" << std::endl; +} + #ifdef _MSC_VER static DWORD WINAPI WatchDogProc(LPVOID state) #else @@ -4826,7 +5040,7 @@ uint64 PCM::CX_MSR_PMON_CTRY(uint32 Cbo, uint32 Ctr) const { return JKT_C0_MSR_PMON_CTR0 + ((JKTIVT_CBO_MSR_STEP)*Cbo) + Ctr; - } else if(HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if(HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { return HSX_C0_MSR_PMON_CTR0 + ((HSX_CBO_MSR_STEP)*Cbo) + Ctr; } @@ -4839,7 +5053,7 @@ uint64 PCM::CX_MSR_PMON_BOX_FILTER(uint32 Cbo) const { return JKT_C0_MSR_PMON_BOX_FILTER + ((JKTIVT_CBO_MSR_STEP)*Cbo); - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { return HSX_C0_MSR_PMON_BOX_FILTER + ((HSX_CBO_MSR_STEP)*Cbo); } else if (KNL == cpu_model) @@ -4856,7 +5070,7 @@ uint64 PCM::CX_MSR_PMON_BOX_FILTER1(uint32 Cbo) const { return IVT_C0_MSR_PMON_BOX_FILTER1 + ((JKTIVT_CBO_MSR_STEP)*Cbo); - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { return HSX_C0_MSR_PMON_BOX_FILTER1 + ((HSX_CBO_MSR_STEP)*Cbo); } @@ -4869,7 +5083,7 @@ uint64 PCM::CX_MSR_PMON_CTLY(uint32 Cbo, uint32 Ctl) const { return JKT_C0_MSR_PMON_CTL0 + ((JKTIVT_CBO_MSR_STEP)*Cbo) + Ctl; - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { return HSX_C0_MSR_PMON_CTL0 + ((HSX_CBO_MSR_STEP)*Cbo) + Ctl; } @@ -4882,7 +5096,7 @@ uint64 PCM::CX_MSR_PMON_BOX_CTL(uint32 Cbo) const { return JKT_C0_MSR_PMON_BOX_CTL + ((JKTIVT_CBO_MSR_STEP)*Cbo); - } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) + } else if (HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model || SKX == cpu_model) { return HSX_C0_MSR_PMON_BOX_CTL + ((HSX_CBO_MSR_STEP)*Cbo); } else if (KNL == cpu_model) @@ -4916,7 +5130,7 @@ uint32 PCM::getMaxNumOfCBoxes() const return 0; } -void PCM::programCboOpcodeFilter(const uint32 opc, const uint32 cbo, std::shared_ptr msr) +void PCM::programCboOpcodeFilter(const uint32 opc, const uint32 cbo, std::shared_ptr msr, const uint32 nc_) { if(JAKETOWN == cpu_model) { @@ -4925,15 +5139,66 @@ void PCM::programCboOpcodeFilter(const uint32 opc, const uint32 cbo, std::shared } else if(IVYTOWN == cpu_model || HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) { msr->write(CX_MSR_PMON_BOX_FILTER1(cbo), IVTHSX_CBO_MSR_PMON_BOX_FILTER1_OPC(opc)); + } else if(SKX == cpu_model) + { + msr->write(CX_MSR_PMON_BOX_FILTER1(cbo), SKX_CHA_MSR_PMON_BOX_FILTER1_OPC0(opc) + + SKX_CHA_MSR_PMON_BOX_FILTER1_REM(1) + + SKX_CHA_MSR_PMON_BOX_FILTER1_LOC(1) + + SKX_CHA_MSR_PMON_BOX_FILTER1_NM(1) + + SKX_CHA_MSR_PMON_BOX_FILTER1_NOT_NM(1) + + (nc_?SKX_CHA_MSR_PMON_BOX_FILTER1_NC(1):0ULL)); } } -void PCM::programPCIeMissCounters(const PCM::PCIeEventCode event_, const uint32 tid_) +void PCM::programIIOCounters(IIOPMUCNTCTLRegister rawEvents[4], int IIOStack) { - programPCIeCounters(event_,tid_,1); + std::vector IIO_units; + if (IIOStack == -1) + { + IIO_units.push_back((int32)IIO_CBDMA); + IIO_units.push_back((int32)IIO_PCIe0); + IIO_units.push_back((int32)IIO_PCIe1); + IIO_units.push_back((int32)IIO_PCIe2); + IIO_units.push_back((int32)IIO_MCP0); + IIO_units.push_back((int32)IIO_MCP1); + } + else + IIO_units.push_back(IIOStack); + + for (int32 i = 0; (i < num_sockets) && MSR.size(); ++i) + { + uint32 refCore = socketRefCore[i]; + TemporalThreadAffinity tempThreadAffinity(refCore); // speedup trick for Linux + + for (std::vector::const_iterator iunit = IIO_units.begin(); iunit != IIO_units.end(); ++iunit) + { + const int32 unit = *iunit; + MSR[refCore]->write(IIO_UNIT_CTL_ADDR[unit], IIO_MSR_PMON_BOX_CTL_RSV); + // freeze + MSR[refCore]->write(IIO_UNIT_CTL_ADDR[unit], IIO_MSR_PMON_BOX_CTL_RSV + IIO_MSR_PMON_BOX_CTL_FRZ); + + for (int c = 0; c < 4; ++c) + { + MSR[refCore]->write(IIO_CTL_ADDR[unit][c], IIO_MSR_PMON_CTL_EN); + MSR[refCore]->write(IIO_CTL_ADDR[unit][c], IIO_MSR_PMON_CTL_EN | rawEvents[c].value); + } + + // reset counter values + MSR[refCore]->write(IIO_UNIT_CTL_ADDR[unit], IIO_MSR_PMON_BOX_CTL_RSV + IIO_MSR_PMON_BOX_CTL_FRZ + IIO_MSR_PMON_BOX_CTL_RST_COUNTERS); + + // unfreeze counters + MSR[refCore]->write(IIO_UNIT_CTL_ADDR[unit], IIO_MSR_PMON_BOX_CTL_RSV); + + } + } } -void PCM::programPCIeCounters(const PCM::PCIeEventCode event_, const uint32 tid_, const uint32 miss_) +void PCM::programPCIeMissCounters(const PCM::PCIeEventCode event_, const uint32 tid_, const uint32 q_, const uint32 nc_) +{ + programPCIeCounters(event_,tid_,1, q_, nc_); +} + +void PCM::programPCIeCounters(const PCM::PCIeEventCode event_, const uint32 tid_, const uint32 miss_, const uint32 q_, const uint32 nc_) { for (int32 i = 0; (i < num_sockets) && MSR.size(); ++i) { @@ -4957,14 +5222,38 @@ void PCM::programPCIeCounters(const PCM::PCIeEventCode event_, const uint32 tid_ } #endif - programCboOpcodeFilter((uint32)event_, cbo, MSR[refCore]); + programCboOpcodeFilter((uint32)event_, cbo, MSR[refCore], nc_); if((HASWELLX == cpu_model || BDX_DE == cpu_model || BDX == cpu_model) && tid_ != 0) MSR[refCore]->write(CX_MSR_PMON_BOX_FILTER(cbo), tid_); MSR[refCore]->write(CX_MSR_PMON_CTLY(cbo, 0), CBO_MSR_PMON_CTL_EN); // TOR_INSERTS.OPCODE event - MSR[refCore]->write(CX_MSR_PMON_CTLY(cbo, 0), CBO_MSR_PMON_CTL_EN + CBO_MSR_PMON_CTL_EVENT(0x35) + (CBO_MSR_PMON_CTL_UMASK(1) | (miss_?CBO_MSR_PMON_CTL_UMASK(0x3):0ULL)) + (tid_?CBO_MSR_PMON_CTL_TID_EN:0ULL)); + if(SKX == cpu_model) { + uint64 umask = 0; + switch(q_) + { + case PRQ: + umask |= SKX_CHA_TOR_INSERTS_UMASK_PRQ(1); + break; + case IRQ: + umask |= SKX_CHA_TOR_INSERTS_UMASK_IRQ(1); + break; + } + switch(miss_) + { + case 0: + umask |= SKX_CHA_TOR_INSERTS_UMASK_HIT(1); + break; + case 1: + umask |= SKX_CHA_TOR_INSERTS_UMASK_MISS(1); + break; + } + + MSR[refCore]->write(CX_MSR_PMON_CTLY(cbo, 0), CBO_MSR_PMON_CTL_EN + CBO_MSR_PMON_CTL_EVENT(0x35) + CBO_MSR_PMON_CTL_UMASK(umask)); + } + else + MSR[refCore]->write(CX_MSR_PMON_CTLY(cbo, 0), CBO_MSR_PMON_CTL_EN + CBO_MSR_PMON_CTL_EVENT(0x35) + (CBO_MSR_PMON_CTL_UMASK(1) | (miss_?CBO_MSR_PMON_CTL_UMASK(0x3):0ULL)) + (tid_?CBO_MSR_PMON_CTL_TID_EN:0ULL)); // reset counter values MSR[refCore]->write(CX_MSR_PMON_BOX_CTL(cbo), CBO_MSR_PMON_BOX_CTL_FRZ_EN + CBO_MSR_PMON_BOX_CTL_FRZ + CBO_MSR_PMON_BOX_CTL_RST_COUNTERS); @@ -4990,3 +5279,23 @@ PCIeCounterState PCM::getPCIeCounterState(const uint32 socket_) } return result; } + +IIOCounterState PCM::getIIOCounterState(int socket, int IIOStack, int counter) +{ + IIOCounterState result; + uint32 refCore = socketRefCore[socket]; + + MSR[refCore]->read(IIO_CTR_ADDR[IIOStack][counter], &result.data); + + return result; +} + +void PCM::getIIOCounterStates(int socket, int IIOStack, IIOCounterState * result) +{ + uint32 refCore = socketRefCore[socket]; + TemporalThreadAffinity tempThreadAffinity(refCore); // speedup trick for Linux + + for (int c = 0; c < 4; ++c) { + MSR[refCore]->read(IIO_CTR_ADDR[IIOStack][c], &(result[c].data)); + } +} diff --git a/cpucounters.h b/cpucounters.h index 5593ca8b..9e69da81 100644 --- a/cpucounters.h +++ b/cpucounters.h @@ -37,11 +37,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include #include #include +#include #include #ifdef PCM_USE_PERF #include -#include #include #define PCM_PERF_COUNT_HW_REF_CPU_CYCLES (9) #endif @@ -52,6 +52,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include #include #include +#include #include #endif @@ -86,8 +87,9 @@ struct PCM_API TopologyEntry // decribes a core //! Object to access uncore counters in a socket/processor with microarchitecture codename SandyBridge-EP (Jaketown) or Ivytown-EP or Ivytown-EX class ServerPCICFGUncore { - int32 bus; + int32 iMCbus,UPIbus; uint32 groupnr; + int32 cpu_model; std::vector > imcHandles; std::vector > edcHandles; std::vector > qpiLLHandles; @@ -99,9 +101,13 @@ class ServerPCICFGUncore uint32 EDCX_ECLK_REGISTER_FUNC_ADDR[8]; uint32 QPI_PORTX_REGISTER_DEV_ADDR[3]; uint32 QPI_PORTX_REGISTER_FUNC_ADDR[3]; + uint32 LINK_PCI_PMON_BOX_CTL_ADDR; + uint32 LINK_PCI_PMON_CTL_ADDR[4]; + uint32 LINK_PCI_PMON_CTR_ADDR[4]; - static std::vector > socket2bus; - void initSocket2Bus(); + static std::vector > socket2iMCbus; + static std::vector > socket2UPIbus; + void initSocket2Bus(std::vector > & socket2bus, uint32 device, uint32 function, const uint32 DEV_IDS[], uint32 devIdsSize); ServerPCICFGUncore(); // forbidden ServerPCICFGUncore(ServerPCICFGUncore &); // forbidden @@ -109,6 +115,10 @@ class ServerPCICFGUncore PciHandleType * createIntelPerfMonDevice(uint32 groupnr, int32 bus, uint32 dev, uint32 func, bool checkVendor = false); void programIMC(const uint32 * MCCntConfig); void programEDC(const uint32 * EDCCntConfig); + uint64 * memBuffer; + void initMemTest(); + void doMemTest(); + void cleanupMemTest(); public: //! \brief Initialize access data structures @@ -132,9 +142,9 @@ class ServerPCICFGUncore //! \param port QPI port id uint64 getIncomingDataFlits(uint32 port); - //! \brief Get the number of outgoing data and non-data flits from the socket through a port + //! \brief Get the number of outgoing data and non-data or idle flits (depending on the architecture) from the socket through a port //! \param port QPI port id - uint64 getOutgoingDataNonDataFlits(uint32 port); + uint64 getOutgoingFlits(uint32 port); virtual ~ServerPCICFGUncore(); @@ -154,6 +164,9 @@ class ServerPCICFGUncore //! \brief Get number cycles on a QPI port when the link was in a power saving half-lane mode //! \param port QPI port number uint64 getQPIL0pTxCycles(uint32 port); + //! \brief Get number cycles on a UPI port when the link was in a L0 mode (fully active) + //! \param port UPI port number + uint64 getUPIL0TxCycles(uint32 port); //! \brief Get number cycles on a QPI port when the link was in a power saving shutdown mode //! \param port QPI port number uint64 getQPIL1Cycles(uint32 port); @@ -197,13 +210,7 @@ class ServerPCICFGUncore } //! \brief Print QPI Speeds - void reportQPISpeed() const - { - std::cerr.precision(1); - std::cerr << std::fixed; - for (uint32 i = 0; i < (uint32)qpi_speed.size(); ++i) - std::cerr << "Max QPI link " << i << " speed: " << qpi_speed[i] / (1e9) << " GBytes/second (" << qpi_speed[i] / (1e9 * double(DATA_BYTES_PER_QPI_CYCLE)) << " GT/second)" << std::endl; - } + void reportQPISpeed() const; //! \brief Returns the number of detected integrated memory controllers uint32 getNumMC() const { return num_imc; } @@ -215,18 +222,22 @@ class ServerPCICFGUncore size_t getNumEDCChannels() const { return (size_t)edcHandles.size(); } }; -class PCIeCounterState +class SimpleCounterState { - friend uint64 getNumberOfEvents(PCIeCounterState before, PCIeCounterState after); + template + friend uint64 getNumberOfEvents(const T & before, const T & after); friend class PCM; uint64 data; public: - PCIeCounterState() : data(0) + SimpleCounterState() : data(0) { } - virtual ~PCIeCounterState() { } + virtual ~SimpleCounterState() { } }; +typedef SimpleCounterState PCIeCounterState; +typedef SimpleCounterState IIOCounterState; + #ifndef HACK_TO_REMOVE_DUPLICATE_ERROR template class PCM_API std::allocator; template class PCM_API std::vector; @@ -284,6 +295,11 @@ class PCM_API PCM std::vector > MSR; std::vector > server_pcicfg_uncore; uint64 PCU_MSR_PMON_BOX_CTL_ADDR, PCU_MSR_PMON_CTRX_ADDR[4]; + std::map IIO_UNIT_STATUS_ADDR; + std::map IIO_UNIT_CTL_ADDR; + std::map > IIO_CTR_ADDR; + std::map IIO_CLK_ADDR; + std::map > IIO_CTL_ADDR; double joulesPerEnergyUnit; std::vector > energy_status; std::vector > dram_energy_status; @@ -363,6 +379,55 @@ class PCM_API PCM UnknownError }; + enum PerfmonField { + INVALID, /* Use to parse invalid field */ + OPCODE, + EVENT_SELECT, + UMASK, + RESET, + EDGE_DET, + IGNORED, + OVERFLOW_ENABLE, + ENABLE, + INVERT, + THRESH, + CH_MASK, + FC_MASK, + /* Below are not part of perfmon definition */ + H_EVENT_NAME, + V_EVENT_NAME, + MULTIPLIER, + DIVIDER, + COUNTER_INDEX + }; + + enum PCIeWidthMode { + X1, + X4, + X8, + X16, + XFF + }; + + enum { // offsets/enumeration of IIO stacks + IIO_CBDMA = 0, // shared with DMI + IIO_PCIe0 = 1, + IIO_PCIe1 = 2, + IIO_PCIe2 = 3, + IIO_MCP0 = 4, + IIO_MCP1 = 5, + IIO_STACK_COUNT = 6 + }; + + struct SimplePCIeDevInfo + { + enum PCIeWidthMode width; + std::string pciDevName; + std::string busNumber; + + SimplePCIeDevInfo() : width(XFF) { } + }; + /*! \brief Custom Core event description See "Intel 64 and IA-32 Architectures Software Developers Manual Volume 3B: @@ -397,6 +462,15 @@ class PCM_API PCM } }; + struct CustomIIOEventDescription + { + /* We program the same counters to every IIO Stacks */ + std::string eventNames[4]; + IIOPMUCNTCTLRegister eventOpcodes[4]; + int multiplier[4]; //Some IIO event requires transformation to get meaningful output (i.e. DWord to bytes) + int divider[4]; //We usually like to have some kind of divider (i.e. /10e6 ) + }; + private: ProgramMode mode; CustomCoreEventDescription coreEventDesc[4]; @@ -496,7 +570,7 @@ class PCM_API PCM uint64 CX_MSR_PMON_CTLY(uint32 Cbo, uint32 Ctl) const; uint64 CX_MSR_PMON_BOX_CTL(uint32 Cbo) const; uint32 getMaxNumOfCBoxes() const; - void programCboOpcodeFilter(const uint32 opc, const uint32 cbo, std::shared_ptr msr); + void programCboOpcodeFilter(const uint32 opc, const uint32 cbo, std::shared_ptr msr, const uint32 nc_ = 0); public: /*! @@ -756,6 +830,7 @@ class PCM_API PCM BDX = 79, KNL = 87, SKL = 94, + SKX = 85, END_OF_MODEL_LIST = 0x0ffff }; @@ -812,6 +887,7 @@ class PCM_API PCM case HASWELLX: case BDX_DE: case BDX: + case SKX: return (server_pcicfg_uncore.size() && server_pcicfg_uncore[0].get()) ? (server_pcicfg_uncore[0]->getNumQPIPorts()) : 0; } return 0; @@ -833,6 +909,7 @@ class PCM_API PCM case IVYTOWN: case HASWELLX: case BDX_DE: + case SKX: case BDX: case KNL: return (server_pcicfg_uncore.size() && server_pcicfg_uncore[0].get()) ? (server_pcicfg_uncore[0]->getNumMC()) : 0; @@ -856,6 +933,7 @@ class PCM_API PCM case IVYTOWN: case HASWELLX: case BDX_DE: + case SKX: case BDX: case KNL: return (server_pcicfg_uncore.size() && server_pcicfg_uncore[0].get()) ? (server_pcicfg_uncore[0]->getNumMCChannels()) : 0; @@ -896,6 +974,7 @@ class PCM_API PCM case BDX_DE: case BDX: case SKL: + case SKX: return 4; case ATOM: case KNL: @@ -917,6 +996,8 @@ class PCM_API PCM case BDX: case KNL: return 1000000000ULL; // 1 GHz + case SKX: + return 1100000000ULL; // 1.1 GHz } return 0; } @@ -975,6 +1056,21 @@ class PCM_API PCM PRd = 0x187, // Partial Reads (UC) (MMIO Read) WiL = 0x18F, // Write Invalidate Line - partial (MMIO write), PL: Not documented in HSX/IVT ItoM = 0x1C8, // Request Invalidate Line; share the same code for CPU, use tid to filter PCIe only traffic + + SKX_RFO = 0x200, + SKX_CRd = 0x201, + SKX_DRd = 0x202, + SKX_PRd = 0x207, + SKX_WiL = 0x20F, + SKX_RdCur = 0x21E, + SKX_ItoM = 0x248, + }; + + enum ChaPipelineQueue + { + None, + IRQ, + PRQ, }; enum CBoEventTid @@ -986,14 +1082,31 @@ class PCM_API PCM //! \brief Program uncore PCIe monitoring event(s) //! \param event_ a PCIe event to monitor //! \param tid_ tid filter (PCM supports it only on Haswell server) - void programPCIeCounters(const PCIeEventCode event_, const uint32 tid_ = 0, const uint32 miss_ = 0); - void programPCIeMissCounters(const PCIeEventCode event_, const uint32 tid_ = 0); + void programPCIeCounters(const PCIeEventCode event_, const uint32 tid_ = 0, const uint32 miss_ = 0, const uint32 q_ = 0, const uint32 nc_ = 0); + void programPCIeMissCounters(const PCIeEventCode event_, const uint32 tid_ = 0, const uint32 q_ = 0, const uint32 nc_ = 0); //! \brief Get the state of PCIe counter(s) //! \param socket_ socket of the PCIe controller //! \return State of PCIe counter(s) PCIeCounterState getPCIeCounterState(const uint32 socket_); + //! \brief Program uncore IIO events + //! \param rawEvents events to program (raw format) + //! \param IIOStack id of the IIO stack to program (-1 for all, if parameter omitted) + void programIIOCounters(IIOPMUCNTCTLRegister rawEvents[4], int IIOStack = -1); + + //! \brief Get the state of IIO counter + //! \param socket socket of the IIO stack + //! \param IIOStack id of the IIO stack + //! \return State of IIO counter + IIOCounterState getIIOCounterState(int socket, int IIOStack, int counter); + + //! \brief Get the states of the four IIO counters in bulk (faster than four single reads) + //! \param socket socket of the IIO stack + //! \param IIOStack id of the IIO stack + //! \param result states of IIO counters (array of four IIOCounterState elements) + void getIIOCounterStates(int socket, int IIOStack, IIOCounterState * result); + uint64 extractCoreGenCounterValue(uint64 val); uint64 extractCoreFixedCounterValue(uint64 val); uint64 extractUncoreGenCounterValue(uint64 val); @@ -1026,6 +1139,7 @@ class PCM_API PCM || cpu_model == PCM::BDX || cpu_model == PCM::KNL || cpu_model == PCM::SKL + || cpu_model == PCM::SKX ); } @@ -1038,6 +1152,7 @@ class PCM_API PCM || cpu_model == PCM::BDX_DE || cpu_model == PCM::BDX || cpu_model == PCM::KNL + || cpu_model == PCM::SKX ); } @@ -1055,6 +1170,9 @@ class PCM_API PCM || cpu_model == PCM::IVYTOWN || cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX +#ifdef __linux__ + || cpu_model == PCM::SKX +#endif ); } @@ -1065,6 +1183,7 @@ class PCM_API PCM || cpu_model == PCM::WESTMERE_EX || cpu_model == PCM::JAKETOWN || cpu_model == PCM::IVYTOWN + || (cpu_model == PCM::SKX && cpu_stepping > 1) ); } @@ -1097,6 +1216,13 @@ class PCM_API PCM ); } + bool IIOEventsAvailable() const + { + return ( + cpu_model == PCM::SKX + ); + } + bool hasBecktonUncore() const { return ( @@ -1111,6 +1237,7 @@ class PCM_API PCM || cpu_model == PCM::IVYTOWN || cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX_DE + || cpu_model == PCM::SKX || cpu_model == PCM::BDX || cpu_model == PCM::KNL ); @@ -1121,7 +1248,69 @@ class PCM_API PCM bool useSkylakeEvents() const { - return PCM::SKL == cpu_model; + return PCM::SKL == cpu_model || PCM::SKX == cpu_model; + } + + static double getBytesPerFlit(int32 cpu_model_) + { + if(cpu_model_ == PCM::SKX) + { + // 172 bits per UPI flit + return 172./8.; + } + // 8 bytes per QPI flit + return 8.; + } + + double getBytesPerFlit() const + { + return getBytesPerFlit(cpu_model); + } + + static double getDataBytesPerFlit(int32 cpu_model_) + { + if(cpu_model_ == PCM::SKX) + { + // 9 UPI flits to transfer 64 bytes + return 64./9.; + } + // 8 bytes per QPI flit + return 8.; + } + + double getDataBytesPerFlit() const + { + return getDataBytesPerFlit(cpu_model); + } + + static double getFlitsPerLinkCycle(int32 cpu_model_) + { + if(cpu_model_ == PCM::SKX) + { + // 5 UPI flits sent every 6 link cycles + return 5./6.; + } + return 2.; + } + + static double getBytesPerLinkCycle(int32 cpu_model_) + { + return getBytesPerFlit(cpu_model_) * getFlitsPerLinkCycle(cpu_model_); + } + + double getBytesPerLinkCycle() const + { + return getBytesPerLinkCycle(cpu_model); + } + + static double getLinkTransfersPerLinkCycle() + { + return 8.; + } + + double getBytesPerLinkTransfer() const + { + return getBytesPerLinkCycle() / getLinkTransfersPerLinkCycle(); } ~PCM(); @@ -1612,9 +1801,9 @@ class SocketCounterState : public BasicCounterState, public UncoreCounterState class SystemCounterState : public BasicCounterState, public UncoreCounterState { friend class PCM; - std::vector > incomingQPIPackets; - std::vector > outgoingQPIIdleFlits; - std::vector > outgoingQPIDataNonDataFlits; + std::vector > incomingQPIPackets; // each 64 byte + std::vector > outgoingQPIFlits; // idle or data/non-data flits depending on the architecture + std::vector > TxL0Cycles; uint64 uncoreTSC; protected: @@ -1636,10 +1825,10 @@ class SystemCounterState : public BasicCounterState, public UncoreCounterState PCM * m = PCM::getInstance(); incomingQPIPackets.resize(m->getNumSockets(), std::vector((uint32)m->getQPILinksPerSocket(), 0)); - outgoingQPIIdleFlits.resize(m->getNumSockets(), + outgoingQPIFlits.resize(m->getNumSockets(), + std::vector((uint32)m->getQPILinksPerSocket(), 0)); + TxL0Cycles.resize(m->getNumSockets(), std::vector((uint32)m->getQPILinksPerSocket(), 0)); - outgoingQPIDataNonDataFlits.resize(m->getNumSockets(), - std::vector((uint32)m->getQPILinksPerSocket(), 0)); } void accumulateSocketState(const SocketCounterState & o) @@ -2331,23 +2520,35 @@ inline double getOutgoingQPILinkUtilization(uint32 socketNr, uint32 linkNr, cons if (m->hasBecktonUncore()) { - const uint64 b = before.outgoingQPIIdleFlits[socketNr][linkNr]; - const uint64 a = after.outgoingQPIIdleFlits[socketNr][linkNr]; + const uint64 b = before.outgoingQPIFlits[socketNr][linkNr]; // idle flits + const uint64 a = after.outgoingQPIFlits[socketNr][linkNr]; // idle flits // prevent overflows due to counter dissynchronisation const double idle_flits = (double)((a > b) ? (a - b) : 0); const uint64 bTSC = before.uncoreTSC; const uint64 aTSC = after.uncoreTSC; const double tsc = (double)((aTSC > bTSC) ? (aTSC - bTSC) : 0); - if (idle_flits > tsc) return 0.; // prevent oveflows due to potential counter dissynchronization + if (idle_flits >= tsc) return 0.; // prevent oveflows due to potential counter dissynchronization return (1. - (idle_flits / tsc)); } else if (m->hasPCICFGUncore()) { - const uint64 b = before.outgoingQPIDataNonDataFlits[socketNr][linkNr]; - const uint64 a = after.outgoingQPIDataNonDataFlits[socketNr][linkNr]; + const uint64 b = before.outgoingQPIFlits[socketNr][linkNr]; // data + non-data flits or idle (null) flits + const uint64 a = after.outgoingQPIFlits[socketNr][linkNr]; // data + non-data flits or idle (null) flits // prevent overflows due to counter dissynchronisation const double flits = (double)((a > b) ? (a - b) : 0); - const double max_flits = ((double(getInvariantTSC(before, after)) * double(m->getQPILinkSpeed(socketNr, linkNr)) / double(DATA_BYTES_PER_QPI_FLIT)) / double(m->getNominalFrequency())) / double(m->getNumCores()); + const double max_flits = ((double(getInvariantTSC(before, after)) * double(m->getQPILinkSpeed(socketNr, linkNr)) / m->getBytesPerFlit()) / double(m->getNominalFrequency())) / double(m->getNumCores()); + const int cpuModel = m->getCPUModel(); + if(cpuModel == PCM::SKX) + { + const double null_flits = flits/3.; // on SKX the outgoingQPIFlits data field store idle (null) flits + if(null_flits >= max_flits) return 0.; // prevent oveflows due to potential counter dissynchronization + double rawUtil = (1. - (null_flits / max_flits)); + const double fullActiveCycles = double(after.TxL0Cycles[socketNr][linkNr] - before.TxL0Cycles[socketNr][linkNr]); + const double max_cycles = max_flits / double(m->getFlitsPerLinkCycle(cpuModel)); + /* does not take into account L0p half-lane mode. This is only a best-effort approximation + (works best if the link is 100% in the full speed L0 mode).. */ + return rawUtil*(fullActiveCycles/max_cycles); + } if (flits > max_flits) return 1.; // prevent oveflows due to potential counter dissynchronization return (flits / max_flits); } @@ -2491,10 +2692,11 @@ inline double getQPItoMCTrafficRatio(const SystemCounterState & before, const Sy return double(totalQPI) / double(memTraffic); } -//! \brief Returns the raw count of PCIe events -//! \param before PCIe counter state before the experiment -//! \param after PCIe counter state after the experiment -inline uint64 getNumberOfEvents(PCIeCounterState before, PCIeCounterState after) +//! \brief Returns the raw count of events +//! \param before counter state before the experiment +//! \param after counter state after the experiment +template +inline uint64 getNumberOfEvents(const CounterType & before, const CounterType & after) { return after.data - before.data; } diff --git a/lspci.h b/lspci.h new file mode 100644 index 00000000..29312a7d --- /dev/null +++ b/lspci.h @@ -0,0 +1,216 @@ +#ifndef CPUCounters_LSPCI_H +#define CPUCounters_LSPCI_H + +#include +#include +#include "cpucounters.h" +using namespace std; +typedef uint32_t h_id; +typedef uint32_t v_id; +typedef map,uint64_t> ctr_data; +typedef vector stack_content; +typedef vector result_content; + +struct bdf { + uint8_t busno; + uint8_t devno; + uint8_t funcno; +}; + +struct pci { + bool exist = false; + struct bdf bdf; + union { + struct { + uint16_t vendor_id; + uint16_t device_id; + }; + uint32_t offset_0; + }; + int8_t header_type; + union { + struct { + uint8_t primary_bus_number; + uint8_t secondary_bus_number; + uint8_t subordinate_bus_number; + uint8_t junk; + }; + uint32_t offset_18; + }; + union { + struct { + uint16_t link_ctrl; + union { + struct { + uint16_t link_speed : 4; + uint16_t link_width : 6; + uint16_t undefined : 1; + uint16_t link_trained : 1; + }; + uint16_t link_sta; + }; + }; + uint32_t link_info; + }; +}; + +struct counter { + string h_event_name; + string v_event_name; + IIOPMUCNTCTLRegister Opcodes; + int idx; /* Some counters need to be placed in specific index */ + int multiplier; + int divider; + uint32_t h_id; + uint32_t v_id; + vector data; +}; + +struct iio_skx { + struct { + struct { + struct pci root_pci_dev; /* single device represent root port */ + vector child_pci_devs; /* Contain child switch and end-point devices */ + } parts[4]; /* part 0, 1, 2, 3 */ + uint8_t busno; /* holding busno for each IIO stack */ + string stack_name; + vector values; + } stacks[6]; /* iio stack 0, 1, 2, 3, 4, 5 */ + uint32_t socket_id; +}; + +bool operator < (const bdf &l, const bdf &r) { + 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*/ } + } +} + +void probe_pci(struct pci *p) +{ + uint32 value; + struct bdf *bdf = &p->bdf; + if (PciHandleType::exists(bdf->busno, bdf->devno, bdf->funcno)) { + p->exist = true; + PciHandleType h(0, bdf->busno, bdf->devno, bdf->funcno); + h.read32(0x0, &value); //VID:DID + p->offset_0 = value; + h.read32(0xc, &value); + p->header_type = (value >> 16) & 0x7f; + if (p->header_type == 0) { + h.read32(0x4, &value); //Status register + if (value & 0x100000) {//Capability list == true + h.read32(0x34, &value); //Capability pointer + probe_capability_pci_express(p, value); + } + } else if (p->header_type == 1) { + h.read32(0x18, &value); + p->offset_18 = value; + } + } + else + p->exist = false; +} + +/* + first : [vendorID] -> vencor 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"); + std::string line, item; + + if (!in.is_open()) + { + std::cerr << "pci.ids file is not available. Download it from https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids " << endl; + 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) << endl; + pciDB.second[vendorID][deviceID] = line.substr(7); + continue; + } + // vendor + vendorID = stoi(line.substr(0,4),0,16); + pciDB.first[vendorID] = line.substr(6); + } +} + +#endif diff --git a/pcm-iio.cpp b/pcm-iio.cpp new file mode 100644 index 00000000..e6e833bf --- /dev/null +++ b/pcm-iio.cpp @@ -0,0 +1,604 @@ +/* +Copyright (c) 2017, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// written by Patrick Lu +#define HACK_TO_REMOVE_DUPLICATE_ERROR +#include "cpucounters.h" +#ifdef _MSC_VER +#pragma warning(disable : 4996) // for sprintf +#include +#include "../PCM_Win/windriver.h" +#else +#include +#endif +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include "freegetopt/getopt.h" +#endif + +#include "lspci.h" +#include "utils.h" +using namespace std; + +#define PCM_DELAY_DEFAULT 3.0 // in seconds + +const uint8_t max_sockets = 4; +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 " +}; + +map opcodeFieldMap; +//TODO: add description for this nameMap +map>> nameMap; +result_content results(max_sockets, stack_content(6, ctr_data())); + +struct data{ + uint32_t width; + uint64_t value; +}; + +/** + * For debug only + */ +void print_nameMap() { + for (std::map>>::const_iterator iunit = nameMap.begin(); iunit != nameMap.end(); ++iunit) + { + string h_name = iunit->first; + std::pair> value = iunit->second; + uint32_t hid = value.first; + std::map vMap = value.second; + cout << "H name: " << h_name << " id =" << hid << " vMap size:" << vMap.size() << endl; + for (std::map::const_iterator junit = vMap.begin(); junit != vMap.end(); ++junit) + { + string v_name = junit->first; + uint32_t vid = junit->second; + cout << "V name: " << v_name << " id =" << vid << endl; + + } + } +} + + +string a_title (const string &init, const string &name) { + char begin = init[0]; + string row = init; + row += name; + return row + begin; +} + +string a_data (string init, struct data d) { + char begin = init[0]; + string row = init; + string str_d = unit_format(d.value); + row += str_d; + if (str_d.size() > d.width) + throw std::length_error("counter value > event_name length"); + row += string(d.width - str_d.size(), ' '); + return row + begin; +} + +string build_line(string init, string name, bool last_char = true, char this_char = '_') +{ + char begin = init[0]; + string row = init; + row += string(name.size(), this_char); + if (last_char == true) + row += begin; + return row; +} + + +string a_header_footer (string init, string name) +{ + return build_line(init, name); +} + +vector combine_stack_name_and_counter_names(string stack_name) +{ + + vector v; + string *tmp = new string[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 << endl; + } + //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; +} + +vector prepare_data(const vector &values, const vector &headers) +{ + vector v; + uint32_t idx = 0; + for (std::vector::const_iterator iunit = std::next(headers.begin()); iunit != headers.end() && idx < values.size(); ++iunit, idx++) + { + struct data d; + d.width = iunit->size(); + d.value = values[idx]; + v.push_back(d); + } + + return v; +} + +string build_pci_header(const PCIDB & pciDB, uint32_t column_width, struct pci p, int part = -1, uint32_t level = 0) +{ + string s = "|"; + char bdf_buf[8]; + char speed_buf[9]; + char vid_did_buf[10]; + char device_name_buf[128]; + + snprintf(bdf_buf, sizeof(bdf_buf), "%02X:%02X.%1d", 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; + + /* 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; +} + +vector build_display(vector iio_skx_v, vector &ctrs, vector skt_list, vector stack_list, const PCIDB & pciDB) +{ + vector buffer; + vector headers; + vector data; + uint64_t header_width; + string row; + + for (vector::const_iterator skt_unit = skt_list.begin(); skt_unit != skt_list.end(); ++skt_unit) { + buffer.push_back("Socket" + std::to_string(*skt_unit)); + struct iio_skx iio_skx = iio_skx_v[*skt_unit]; + for (vector::const_iterator stack_unit = stack_list.begin(); stack_unit != stack_list.end(); ++stack_unit) { + uint32_t s = *stack_unit; + headers = combine_stack_name_and_counter_names(iio_skx.stacks[s].stack_name); + //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 (vector::iterator cunit = ctrs.begin(); cunit != ctrs.end(); ++cunit) { + v_sort[cunit->v_id][cunit->h_id] = &(*cunit); + } + for (map>::const_iterator vunit = v_sort.begin(); vunit != v_sort.end(); ++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.begin(); hunit != h_array.end(); ++hunit) { + uint32_t hh_id = hunit->first; + uint64_t raw_data = hunit->second->data[0][*skt_unit][s][std::pair(hh_id,vv_id)]; + h_data.push_back(raw_data); + } + data = prepare_data(h_data, headers); + row = "| " + v_name; + row += string(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 (uint32_t p = 0; p < 4; p++) { + vector pp = iio_skx.stacks[s].parts[p].child_pci_devs; + uint8_t level = 1; + for (std::vector::const_iterator iunit = pp.begin(); iunit != pp.end(); ++iunit) + { + row = build_pci_header(pciDB, header_width, *iunit, -1, level); + buffer.push_back(row); + if (iunit->header_type == 1) + level += 1; + } + } + //Print footer + row = std::accumulate(headers.begin(), headers.end(), string(" "), a_header_footer); + buffer.push_back(row); + } + } + return buffer; +} + +void display(const vector &buff) +{ + for (std::vector::const_iterator iunit = buff.begin(); iunit != buff.end(); ++iunit) + std::cout << *iunit << endl; +} + +void discover_pci_tree(const vector & busno, uint8_t socket_id, vector &v_iio_skx) +{ + struct iio_skx iio_skx; + uint32 cpubusno = 0; + + if (PciHandleType::exists((uint32)busno[socket_id], 8, 2)) { + iio_skx.socket_id = socket_id; + PciHandleType h(0, busno[socket_id], 8, 2); + h.read32(0xcc, &cpubusno); // CPUBUSNO register + iio_skx.stacks[0].busno = cpubusno & 0xff; + iio_skx.stacks[1].busno = (cpubusno >> 8) & 0xff; + iio_skx.stacks[2].busno = (cpubusno >> 16) & 0xff; + iio_skx.stacks[3].busno = (cpubusno >> 24) & 0xff; + h.read32(0xd0, &cpubusno); // CPUBUSNO1 register + iio_skx.stacks[4].busno = cpubusno & 0xff; + iio_skx.stacks[5].busno = (cpubusno >> 8) & 0xff; + + for (uint8_t stack = 0; stack < 6; stack++) { + uint8_t busno = iio_skx.stacks[stack].busno; + iio_skx.stacks[stack].stack_name = iio_stack_names[stack]; + //std::cout << "stack" << unsigned(stack) << std::hex << ":0x" << unsigned(busno) << std::dec << ",(" << unsigned(busno) << ")\n"; + for (uint8_t part = 0; part < 3; part++) { + struct pci *pci = &iio_skx.stacks[stack].parts[part].root_pci_dev; + struct bdf *bdf = &pci->bdf; + bdf->busno = busno; + bdf->devno = part; + bdf->funcno = 0; + if (stack != 0 && busno == 0) /* This is a workaround to catch some IIO stack does not exist */ + pci->exist = false; + else + probe_pci(pci); + } + } + for (uint8_t stack = 0; stack < 6; stack++) { + for (uint8_t part = 0; part < 4; part++) { + struct pci p = iio_skx.stacks[stack].parts[part].root_pci_dev; + if (!p.exist) + continue; + for (uint8_t b = p.secondary_bus_number; b <= p.subordinate_bus_number; b++) { /* FIXME: for 0:0.0, we may need to scan from secondary switch down */ + for (uint8_t d = 0; d < 32; d++) { + for (uint8_t f = 0; f < 8; f++) { + struct pci pci; + pci.exist = false; + pci.bdf.busno = b; + pci.bdf.devno = d; + pci.bdf.funcno = f; + probe_pci(&pci); + if (pci.exist) + iio_skx.stacks[stack].parts[part].child_pci_devs.push_back(pci); + } + } + } + } + } + v_iio_skx.push_back(iio_skx); + } +} + +vector load_events(const char* fn) +{ + vector v; + struct counter ctr; + ctr.Opcodes.value = 0; + + std::ifstream in(fn); + std::string line, item; + + if (!in.is_open()) + throw std::invalid_argument("event file is not avaiable. In the future version, we will load a preset"); + + while (std::getline(in, line)) { + /* Ignore anyline with # */ + //TODO: substring until #, if len == 0, skip, else parse normally + if (line.find("#") != std::string::npos) + continue; + /* If line does not have any deliminator, we ignore it as well */ + if (line.find("=") == std::string::npos) + continue; + std::istringstream iss(line); + string h_name, v_name; + while (std::getline(iss, item, ',')) { + std::string key, value; + uint64 numValue; + /* assume the token has the format = */ + key = item.substr(0,item.find("=")); + value = item.substr(item.find("=")+1); + istringstream iss2(value); + iss2 >> setbase(0) >> numValue; + + //cout << "Key:" << key << " Value:" << value << " opcodeFieldMap[key]:" << opcodeFieldMap[key] << endl; + switch(opcodeFieldMap[key]) { + case PCM::H_EVENT_NAME: + h_name = value; + ctr.h_event_name = h_name; + if (nameMap.find(h_name) == nameMap.end()) { + /* It's a new horizontal event name */ + uint32_t next_h_id = nameMap.size(); + std::pair> nameMap_value(next_h_id, std::map()); + nameMap[h_name] = nameMap_value; + } + ctr.h_id = nameMap.size() - 1; + break; + case PCM::V_EVENT_NAME: + { + v_name = value; + ctr.v_event_name = v_name; + //XXX: If h_name comes after v_name, we'll have a problem. + //XXX: It's very weird, I forgot to assign nameMap[h_name] = nameMap_value earlier (:298), but this part still works? + std::map &v_nameMap = nameMap[h_name].second; + if (v_nameMap.find(v_name) == v_nameMap.end()) { + v_nameMap[v_name] = v_nameMap.size() - 1; + } else { + cerr << "Detect duplicated v_name:" << v_name << endl; + exit(EXIT_FAILURE); + } + ctr.v_id = v_nameMap.size() - 1; + break; + } + case PCM::COUNTER_INDEX: + ctr.idx = numValue; + break; + case PCM::OPCODE: + ctr.Opcodes.value = numValue; + break; + case PCM::EVENT_SELECT: + ctr.Opcodes.fields.event_select = numValue; + break; + case PCM::UMASK: + ctr.Opcodes.fields.umask = numValue; + break; + case PCM::RESET: + ctr.Opcodes.fields.reset = numValue; + break; + case PCM::EDGE_DET: + ctr.Opcodes.fields.edge_det = numValue; + break; + case PCM::IGNORED: + ctr.Opcodes.fields.ignored = numValue; + break; + case PCM::OVERFLOW_ENABLE: + ctr.Opcodes.fields.overflow_enable = numValue; + break; + case PCM::ENABLE: + ctr.Opcodes.fields.enable = numValue; + break; + case PCM::INVERT: + ctr.Opcodes.fields.invert = numValue; + break; + case PCM::THRESH: + ctr.Opcodes.fields.thresh = numValue; + break; + case PCM::CH_MASK: + ctr.Opcodes.fields.ch_mask = numValue; + break; + case PCM::FC_MASK: + ctr.Opcodes.fields.fc_mask = numValue; + break; + //TODO: double type for multipler. drop divider variable + case PCM::MULTIPLIER: + ctr.multiplier = numValue; + break; + case PCM::DIVIDER: + ctr.divider = numValue; + break; + case PCM::INVALID: + cerr << "Field in -o file not recognized. The key is: " << key << endl; + exit(EXIT_FAILURE); + break; + } + } + v.push_back(ctr); + //cout << "Finish parsing: " << line << " size:" << v.size() << endl; + cout << line << " " << std::hex << ctr.Opcodes.value << std::dec << endl; + } + + in.close(); + + return v; +} + +result_content get_IIO_Samples(PCM *m, vector iio_skx_v, struct counter ctr, uint32_t delay_ms) +{ + IIOCounterState *before, *after; + IIOPMUCNTCTLRegister rawEvents[4]; + std::vector IIO_units; + IIO_units.push_back((int32)PCM::IIO_CBDMA); + IIO_units.push_back((int32)PCM::IIO_PCIe0); + IIO_units.push_back((int32)PCM::IIO_PCIe1); + IIO_units.push_back((int32)PCM::IIO_PCIe2); + IIO_units.push_back((int32)PCM::IIO_MCP0); + IIO_units.push_back((int32)PCM::IIO_MCP1); + rawEvents[ctr.idx] = ctr.Opcodes; + before = new IIOCounterState[iio_skx_v.size() * IIO_units.size()]; + after = new IIOCounterState[iio_skx_v.size() * IIO_units.size()]; + + m->programIIOCounters(rawEvents, -1); + for (vector::const_iterator socket = iio_skx_v.begin(); socket != iio_skx_v.end(); ++socket) { + for (vector::const_iterator stack = IIO_units.begin(); stack != IIO_units.end(); ++stack) { + uint32_t idx = IIO_units.size()*socket->socket_id + *stack; + before[idx] = m->getIIOCounterState(socket->socket_id, *stack, ctr.idx); + } + } + MySleepMs(delay_ms); + for (vector::const_iterator socket = iio_skx_v.begin(); socket != iio_skx_v.end(); ++socket) { + struct iio_skx iio_skx = *socket; + //iio_skx.stacks[*stack].values.clear(); + for (vector::const_iterator stack = IIO_units.begin(); stack != IIO_units.end(); ++stack) { + uint32_t idx = IIO_units.size()*socket->socket_id + *stack; + after[idx] = m->getIIOCounterState(socket->socket_id, *stack, 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[iio_skx.socket_id][*stack][std::pair(ctr.h_id,ctr.v_id)] = trans_result; + //cout << "skt:" << iio_skx.socket_id << " stack:" << *stack << " h_id:" << ctr.h_id << " v_id:" << ctr.v_id << " res:" << raw_result << " trans:" << trans_result << endl; + } + } + delete[] before; + delete[] after; + return results; +} + +void collect_data(PCM *m, vector iio_skx_v, vector &ctrs) +{ + result_content s; + uint32_t delay_ms = PCM_DELAY_DEFAULT / ctrs.size() * 1000; + //cout << "delay_ms:" << delay_ms << endl; + for (vector::iterator cunit = ctrs.begin(); cunit != ctrs.end(); ++cunit) { + cunit->data.clear(); + s = get_IIO_Samples(m, iio_skx_v, *cunit, delay_ms); + cunit->data.push_back(s); + } +} + +int main(int argc, char * argv[]) +{ + std::cout << "\n Intel(r) Performance Counter Monitor " << INTEL_PCM_VERSION << std::endl; + std::cout << INTEL_PCM_COPYRIGHT << std::endl; + std::cout << "\n This utility measure Skylake-SP IIO information\n\n"; +#define TEST_VAR 1 +#if TEST_VAR == 1 + string ev_file_name = "opCode.txt"; +#endif + vector skt_list; + vector stack_list; + vector iio_skx_v; + vector counters; + vector display_buffer; + PCIDB pciDB; + load_PCIDB(pciDB); + + PCM * m = PCM::getInstance(); + PCM::ErrorCode status = m->program(); + switch (status) + { + case PCM::Success: + break; + case PCM::MSRAccessDenied: + cerr << "Access to Intel(r) Performance Counter Monitor has denied (no MSR or PCI CFG space access)." << endl; + exit(EXIT_FAILURE); + case PCM::PMUBusy: + cerr << "Access to Intel(r) Performance Counter Monitor has denied (Performance Monitoring Unit is occupied by other application). Try to stop the application that uses PMU." << endl; + cerr << "Alternatively you can try to reset PMU configuration at your own risk. Try to reset? (y/n)" << endl; + char yn; + std::cin >> yn; + if ('y' == yn) + { + m->resetPMU(); + cerr << "PMU configuration has been reset. Try to rerun the program again." << endl; + } + exit(EXIT_FAILURE); + default: + cerr << "Access to Intel(r) Performance Counter Monitor has denied (Unknown error)." << endl; + exit(EXIT_FAILURE); + } + + cerr << "\nDetected "<< m->getCPUBrandString() << " \"Intel(r) microarchitecture codename "<getUArchCodename()<<"\""<IIOEventsAvailable())) + { + cerr << "Skylake Server CPU is required for this tool! Program aborted" << endl; + exit(EXIT_FAILURE); + } + if(m->getNumSockets() > max_sockets) + { + cerr << "Only systems with up to "<<(int)max_sockets<<" sockets are supported! Program aborted" << endl; + exit(EXIT_FAILURE); + } + + 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; + + counters = load_events(ev_file_name.c_str()); + //print_nameMap(); + //TODO: Taking from cli + for(uint32 s=0; s < m->getNumSockets();++s) + skt_list.push_back(s); + stack_list.push_back(PCM::IIO_CBDMA); + stack_list.push_back(PCM::IIO_PCIe0); + stack_list.push_back(PCM::IIO_PCIe1); + stack_list.push_back(PCM::IIO_PCIe2); + + vector busno; + + switch(m->getNumSockets()) + { + case 1: + case 2: + { // TODO: do a proper bus scan + vector _{0x0, 0x80}; + busno = _; + } + break; + case 4: + { + vector _{0x0, 0x40, 0x80, 0xc0}; + busno = _; + } + break; + default: + cerr << "Only systems with "<getNumSockets()<<" sockets are not supported! Program aborted" << endl; + exit(EXIT_FAILURE); + } + + for (uint32_t s = 0; s < max_sockets; s++) + discover_pci_tree(busno, s, iio_skx_v); + while (1) { + collect_data(m, iio_skx_v, counters); + display_buffer = build_display(iio_skx_v, counters, skt_list, stack_list, pciDB); + display(display_buffer); + }; +} diff --git a/pcm-lspci.cpp b/pcm-lspci.cpp new file mode 100644 index 00000000..8cb9c55f --- /dev/null +++ b/pcm-lspci.cpp @@ -0,0 +1,113 @@ +/* +Copyright (c) 2017, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// written by Patrick Lu +#define HACK_TO_REMOVE_DUPLICATE_ERROR +#include "cpucounters.h" +#ifdef _MSC_VER +#pragma warning(disable : 4996) // for sprintf +#include +#include "../PCM_Win/windriver.h" +#else +#include +#endif +#include +#include +#include +#ifdef _MSC_VER +#include "freegetopt/getopt.h" +#endif + +#include "lspci.h" +using namespace std; + +void scanBus(int bus, const PCIDB & pciDB) +{ + if(!PciHandleType::exists(bus, 8, 2)) return; + + std::cout << "BUS 0x" << std::hex << bus << std::dec << endl; + + struct iio_skx iio_skx; + + PciHandleType h(0, bus, 8, 2); + uint32 cpubusno = 0; + + h.read32(0xcc, &cpubusno); // CPUBUSNO register + iio_skx.stacks[0].busno = cpubusno & 0xff; + iio_skx.stacks[1].busno = (cpubusno >> 8) & 0xff; + iio_skx.stacks[2].busno = (cpubusno >> 16) & 0xff; + iio_skx.stacks[3].busno = (cpubusno >> 24) & 0xff; + h.read32(0xd0, &cpubusno); // CPUBUSNO1 register + iio_skx.stacks[4].busno = cpubusno & 0xff; + iio_skx.stacks[5].busno = (cpubusno >> 8) & 0xff; + + for (uint8_t stack = 0; stack < 6; stack++) { + uint8_t busno = iio_skx.stacks[stack].busno; + std::cout << "stack" << unsigned(stack) << std::hex << ":0x" << unsigned(busno) << std::dec << ",(" << unsigned(busno) << ")\n"; + for (uint8_t part = 0; part < 3; part++) { + struct pci *pci = &iio_skx.stacks[stack].parts[part].root_pci_dev; + struct bdf *bdf = &pci->bdf; + bdf->busno = busno; + bdf->devno = part; + bdf->funcno = 0; + if (stack != 0 && busno == 0) /* This is a workaround to catch some IIO stack does not exist */ + pci->exist = false; + else + probe_pci(pci); + } + } + for (uint8_t stack = 0; stack < 6; stack++) { + for (uint8_t part = 0; part < 4; part++) { + struct pci p = iio_skx.stacks[stack].parts[part].root_pci_dev; + if (!p.exist) + continue; + for (uint8_t b = p.secondary_bus_number; b <= p.subordinate_bus_number; b++) { /* FIXME: for 0:0.0, we may need to scan from secondary switch down */ + for (uint8_t d = 0; d < 32; d++) { + for (uint8_t f = 0; f < 8; f++) { + struct pci pci; + pci.exist = false; + pci.bdf.busno = b; + pci.bdf.devno = d; + pci.bdf.funcno = f; + probe_pci(&pci); + if (pci.exist) + iio_skx.stacks[stack].parts[part].child_pci_devs.push_back(pci); + } + } + } + } + } + + for (uint8_t stack = 1; stack < 6; stack++) { /* XXX: Maybe there is no point to display all built-in devices on DMI/CBDMA stacks, if so, change stack = 1 */ + for (uint8_t part = 0; part < 4; part++) { + vector v = iio_skx.stacks[stack].parts[part].child_pci_devs; + struct pci pp = iio_skx.stacks[stack].parts[part].root_pci_dev; + if (pp.exist) + print_pci(pp, pciDB); + for (vector::const_iterator iunit = v.begin(); iunit != v.end(); ++iunit) { + struct pci p = *iunit; + if (p.exist) + print_pci(p, pciDB); + } + } + } +} + +int main(int argc, char * argv[]) +{ + PCIDB pciDB; + load_PCIDB(pciDB); + std::cout << "\n Display PCI tree information\n\n"; + for(int bus=0; bus < 256; ++bus) + scanBus(bus, pciDB); +} diff --git a/pcm-numa.cpp b/pcm-numa.cpp index ee73c07f..d531602d 100644 --- a/pcm-numa.cpp +++ b/pcm-numa.cpp @@ -193,8 +193,13 @@ int main(int argc, char * argv[]) conf.OffcoreResponseMsrValue[1] = 0x63f800000 | 0x08FFF; // OFFCORE_RESPONSE.*.REMOTE_DRAM break; case PCM::BDX: - conf.OffcoreResponseMsrValue[0] = 0x0604008FFF; // OFFCORE_RESPONSE.*.LOCAL_DRAM - conf.OffcoreResponseMsrValue[1] = 0x067BC08FFF; // OFFCORE_RESPONSE.*.REMOTE_DRAM + conf.OffcoreResponseMsrValue[0] = 0x0604008FFF; // OFFCORE_RESPONSE.ALL_REQUESTS.L3_MISS.LOCAL_DRAM + conf.OffcoreResponseMsrValue[1] = 0x067BC08FFF; // OFFCORE_RESPONSE.ALL_REQUESTS.L3_MISS.REMOTE_DRAM + break; + case PCM::SKX: + conf.OffcoreResponseMsrValue[0] = 0x3FC0009FFF | (1 << 26); // OFFCORE_RESPONSE.ALL_REQUESTS.L3_MISS_LOCAL_DRAM.ANY_SNOOP + // OFFCORE_RESPONSE.ALL_REQUESTS.L3_MISS_REMOTE_(HOP0,HOP1,HOP2P)_DRAM.ANY_SNOOP + conf.OffcoreResponseMsrValue[1] = 0x3FC0009FFF | (1 << 27) | (1 << 28) | (1 << 29); break; default: cerr << "pcm-numa tool does not support your processor currently." << endl; diff --git a/pcm-pcie.cpp b/pcm-pcie.cpp index 25ef5b01..5bdadbd0 100644 --- a/pcm-pcie.cpp +++ b/pcm-pcie.cpp @@ -71,7 +71,7 @@ uint32 num_events = (sizeof(PCIeEvents_t)/sizeof(uint64)); using namespace std; const uint32 max_sockets = 4; -void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t *sample, const uint32 tid=0); +void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t *sample, const uint32 tid=0, const uint32 q=0, const uint32 nc=0); void print_events() { @@ -301,17 +301,30 @@ int main(int argc, char * argv[]) memset(sample,0,sizeof(sample)); memset(&aggregate_sample,0,sizeof(aggregate_sample)); - if(m->getCPUModel() == PCM::HASWELLX || m->getCPUModel() == PCM::BDX_DE || m->getCPUModel() == PCM::BDX) + if(!(m->getCPUModel() == PCM::JAKETOWN) && !(m->getCPUModel() == PCM::IVYTOWN)) { for(i=0;iPCIeRdCur, delay_ms, sample); - getPCIeEvents(m, m->RFO, delay_ms, sample,m->RFOtid); - getPCIeEvents(m, m->CRd, delay_ms, sample); - getPCIeEvents(m, m->DRd, delay_ms, sample); - getPCIeEvents(m, m->ItoM, delay_ms, sample,m->ItoMtid); - getPCIeEvents(m, m->PRd, delay_ms, sample); - getPCIeEvents(m, m->WiL, delay_ms, sample); + if(m->getCPUModel() == PCM::SKX) + { + getPCIeEvents(m, m->SKX_RdCur, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_RFO, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_CRd, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_DRd, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_ItoM, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_PRd, delay_ms, sample, 0, m->IRQ, 1); + getPCIeEvents(m, m->SKX_WiL, delay_ms, sample, 0, m->IRQ, 1); + } + else + { + getPCIeEvents(m, m->PCIeRdCur, delay_ms, sample); + getPCIeEvents(m, m->RFO, delay_ms, sample,m->RFOtid); + getPCIeEvents(m, m->CRd, delay_ms, sample); + getPCIeEvents(m, m->DRd, delay_ms, sample); + getPCIeEvents(m, m->ItoM, delay_ms, sample,m->ItoMtid); + getPCIeEvents(m, m->PRd, delay_ms, sample); + getPCIeEvents(m, m->WiL, delay_ms, sample); + } } if(csv) @@ -606,17 +619,30 @@ int main(int argc, char * argv[]) memset(sample,0,sizeof(sample)); memset(&aggregate_sample,0,sizeof(aggregate_sample)); - if(m->getCPUModel() == PCM::HASWELLX || m->getCPUModel() == PCM::BDX_DE || m->getCPUModel() == PCM::BDX) + if(!(m->getCPUModel() == PCM::JAKETOWN) && !(m->getCPUModel() == PCM::IVYTOWN)) { for(i=0;iPCIeRdCur, delay_ms, sample); - getPCIeEvents(m, m->RFO, delay_ms, sample,m->RFOtid); - getPCIeEvents(m, m->CRd, delay_ms, sample); - getPCIeEvents(m, m->DRd, delay_ms, sample); - getPCIeEvents(m, m->ItoM, delay_ms, sample,m->ItoMtid); - getPCIeEvents(m, m->PRd, delay_ms, sample); - getPCIeEvents(m, m->WiL, delay_ms, sample); + if(m->getCPUModel() == PCM::SKX) + { + getPCIeEvents(m, m->SKX_RdCur, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_RFO, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_CRd, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_DRd, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_ItoM, delay_ms, sample, 0, m->PRQ); + getPCIeEvents(m, m->SKX_PRd, delay_ms, sample, 0, m->IRQ, 1); + getPCIeEvents(m, m->SKX_WiL, delay_ms, sample, 0, m->IRQ, 1); + } + else + { + getPCIeEvents(m, m->PCIeRdCur, delay_ms, sample); + getPCIeEvents(m, m->RFO, delay_ms, sample,m->RFOtid); + getPCIeEvents(m, m->CRd, delay_ms, sample); + getPCIeEvents(m, m->DRd, delay_ms, sample); + getPCIeEvents(m, m->ItoM, delay_ms, sample,m->ItoMtid); + getPCIeEvents(m, m->PRd, delay_ms, sample); + getPCIeEvents(m, m->WiL, delay_ms, sample); + } } if(csv) @@ -783,7 +809,7 @@ int main(int argc, char * argv[]) exit(EXIT_SUCCESS); } -void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t *sample, const uint32 tid) +void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t *sample, const uint32 tid, const uint32 q, const uint32 nc) { PCIeCounterState * before = new PCIeCounterState[m->getNumSockets()]; PCIeCounterState * after = new PCIeCounterState[m->getNumSockets()]; @@ -791,14 +817,14 @@ void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t PCIeCounterState * after2 = new PCIeCounterState[m->getNumSockets()]; uint32 i; - m->programPCIeCounters(opcode, tid); + m->programPCIeCounters(opcode, tid, 0, q, nc); for(i=0; igetNumSockets(); ++i) before[i] = m->getPCIeCounterState(i); MySleepUs(delay_ms*1000); for(i=0; igetNumSockets(); ++i) after[i] = m->getPCIeCounterState(i); - m->programPCIeMissCounters(opcode, tid); + m->programPCIeMissCounters(opcode, tid, q, nc); for(i=0; igetNumSockets(); ++i) before2[i] = m->getPCIeCounterState(i); MySleepUs(delay_ms*1000); @@ -810,6 +836,7 @@ void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t switch(opcode) { case PCM::PCIeRdCur: + case PCM::SKX_RdCur: sample[i].total.PCIeRdCur += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.PCIeRdCur += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); sample[i].hit.PCIeRdCur += (sample[i].total.PCIeRdCur > sample[i].miss.PCIeRdCur) ? sample[i].total.PCIeRdCur - sample[i].miss.PCIeRdCur : 0; @@ -845,8 +872,9 @@ void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t sample[i].hit.PCIeNSWrF += (sample[i].total.PCIeNSWrF > sample[i].miss.PCIeNSWrF) ? sample[i].total.PCIeNSWrF - sample[i].miss.PCIeNSWrF : 0; aggregate_sample.PCIeNSWrF += sample[i].total.PCIeNSWrF; break; + case PCM::SKX_RFO: case PCM::RFO: - if(tid == PCM::RFOtid) //Use tid to filter only PCIe traffic + if(opcode == PCM::SKX_RFO || tid == PCM::RFOtid) //Use tid to filter only PCIe traffic { sample[i].total.RFO += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.RFO += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); @@ -854,8 +882,9 @@ void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t aggregate_sample.RFO += sample[i].total.RFO; } break; + case PCM::SKX_ItoM: case PCM::ItoM: - if(tid == PCM::ItoMtid) //Use tid to filter only PCIe traffic + if(opcode == PCM::SKX_ItoM || tid == PCM::ItoMtid) //Use tid to filter only PCIe traffic { sample[i].total.ItoM += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.ItoM += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); @@ -863,24 +892,28 @@ void getPCIeEvents(PCM *m, PCM::PCIeEventCode opcode, uint32 delay_ms, sample_t aggregate_sample.ItoM += sample[i].total.ItoM; } break; + case PCM::SKX_WiL: case PCM::WiL: sample[i].total.WiL += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.WiL += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); sample[i].hit.WiL += (sample[i].total.WiL > sample[i].miss.WiL) ? sample[i].total.WiL - sample[i].miss.WiL : 0; aggregate_sample.WiL += sample[i].total.WiL; break; + case PCM::SKX_PRd: case PCM::PRd: sample[i].total.PRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); - sample[i].miss.PRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after[i]); + sample[i].miss.PRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); sample[i].hit.PRd += (sample[i].total.PRd > sample[i].miss.PRd) ? sample[i].total.PRd - sample[i].miss.PRd : 0; aggregate_sample.PRd += sample[i].total.PRd; break; + case PCM::SKX_CRd: case PCM::CRd: sample[i].total.CRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.CRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); sample[i].hit.CRd += (sample[i].total.CRd > sample[i].miss.CRd) ? sample[i].total.CRd - sample[i].miss.CRd : 0; aggregate_sample.CRd += sample[i].total.CRd; break; + case PCM::SKX_DRd: case PCM::DRd: sample[i].total.DRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before[i], after[i]); sample[i].miss.DRd += (sizeof(PCIeEvents_t)/sizeof(uint64)) * getNumberOfEvents(before2[i], after2[i]); diff --git a/pcm-power.cpp b/pcm-power.cpp index 4d9bd167..f321c510 100644 --- a/pcm-power.cpp +++ b/pcm-power.cpp @@ -281,7 +281,7 @@ int main(int argc, char * argv[]) std::cerr << "\nMC counter group: " << imc_profile << std::endl; std::cerr << "PCU counter group: " << pcu_profile << std::endl; if (pcu_profile == 0) { - if (cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX_DE) + if (cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX_DE || cpu_model == PCM::SKX) std::cerr << "Your processor does not support frequency band statistics" << std::endl; else std::cerr << "Freq bands [0/1/2]: " << freq_band[0] * 100 << " MHz; " << freq_band[1] * 100 << " MHz; " << freq_band[2] * 100 << " MHz; " << std::endl; @@ -390,7 +390,7 @@ int main(int argc, char * argv[]) switch (pcu_profile) { case 0: - if (cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX_DE) + if (cpu_model == PCM::HASWELLX || cpu_model == PCM::BDX_DE || cpu_model == PCM::SKX) break; std::cout << "S" << socket << "; PCUClocks: " << getPCUClocks(BeforeState[socket], AfterState[socket]) @@ -403,7 +403,8 @@ int main(int argc, char * argv[]) case 1: std::cout << "S" << socket << "; PCUClocks: " << getPCUClocks(BeforeState[socket], AfterState[socket]) - << "; core C0/C3/C6-state residency: " << getNormalizedPCUCounter(1, BeforeState[socket], AfterState[socket]) + << ((cpu_model == PCM::SKX)?"; core C0_1/C3/C6_7-state residency: ":"; core C0/C3/C6-state residency: ") + << getNormalizedPCUCounter(1, BeforeState[socket], AfterState[socket]) << "; " << getNormalizedPCUCounter(2, BeforeState[socket], AfterState[socket]) << "; " << getNormalizedPCUCounter(3, BeforeState[socket], AfterState[socket]) << "\n"; @@ -422,12 +423,18 @@ int main(int argc, char * argv[]) std::cout << "S" << socket << "; PCUClocks: " << getPCUClocks(BeforeState[socket], AfterState[socket]) << "; Thermal freq limit cycles: " << getNormalizedPCUCounter(1, BeforeState[socket], AfterState[socket]) * 100. << " %" - << "; Power freq limit cycles:" << getNormalizedPCUCounter(2, BeforeState[socket], AfterState[socket]) * 100. << " %" - << "; Clipped freq limit cycles:" << getNormalizedPCUCounter(3, BeforeState[socket], AfterState[socket]) * 100. << " %" - << "\n"; + << "; Power freq limit cycles:" << getNormalizedPCUCounter(2, BeforeState[socket], AfterState[socket]) * 100. << " %"; + if(cpu_model != PCM::SKX) + std::cout << "; Clipped freq limit cycles:" << getNormalizedPCUCounter(3, BeforeState[socket], AfterState[socket]) * 100. << " %"; + std::cout << "\n"; break; case 4: + if(cpu_model == PCM::SKX) + { + std::cout << "This PCU profile is not supported on your processor\n"; + break; + } std::cout << "S" << socket << "; PCUClocks: " << getPCUClocks(BeforeState[socket], AfterState[socket]) << "; OS freq limit cycles: " << getNormalizedPCUCounter(1, BeforeState[socket], AfterState[socket]) * 100. << " %" @@ -452,7 +459,7 @@ int main(int argc, char * argv[]) std::cout << "; PC1e+ residency: " << getNormalizedPCUCounter(0, BeforeState[socket], AfterState[socket], m) * 100. << " %" "; PC1e+ transition count: " << getPCUCounter(1, BeforeState[socket], AfterState[socket]) << " "; - if (cpu_model == PCM::IVYTOWN || cpu_model == PCM::HASWELLX || PCM::BDX_DE == cpu_model) + if (cpu_model == PCM::IVYTOWN || cpu_model == PCM::HASWELLX || PCM::BDX_DE == cpu_model || PCM::SKX == cpu_model) { std::cout << "; PC2 residency: " << getPackageCStateResidency(2, BeforeState[socket], AfterState[socket]) * 100. << " %"; std::cout << "; PC2 transitions: " << getPCUCounter(2, BeforeState[socket], AfterState[socket]) << " "; diff --git a/types.h b/types.h index 05454269..c1fb4169 100644 --- a/types.h +++ b/types.h @@ -475,13 +475,6 @@ struct BecktonUncorePMUCNTCTLRegister #define PCM_INTEL_PCI_VENDOR_ID (0x8086) #define PCM_PCI_VENDOR_ID_OFFSET (0) -// 8 bytes per QPI flit -// 4 QPI cycles per QPI flit - -#define DATA_BYTES_PER_QPI_FLIT (8) -#define QPI_CYCLES_PER_QPI_FLIT (4) -#define DATA_BYTES_PER_QPI_CYCLE (DATA_BYTES_PER_QPI_FLIT / QPI_CYCLES_PER_QPI_FLIT) - // server PCICFG uncore counters #define JKTIVT_MC0_CH0_REGISTER_DEV_ADDR (16) @@ -527,6 +520,25 @@ struct BecktonUncorePMUCNTCTLRegister #define KNL_MC0_CH1_REGISTER_FUNC_ADDR (3) #define KNL_MC0_CH2_REGISTER_FUNC_ADDR (4) +#define SKX_MC0_CH0_REGISTER_DEV_ADDR (10) +#define SKX_MC0_CH1_REGISTER_DEV_ADDR (10) +#define SKX_MC0_CH2_REGISTER_DEV_ADDR (11) +#define SKX_MC0_CH3_REGISTER_DEV_ADDR (-1) //Does not exist +#define SKX_MC0_CH0_REGISTER_FUNC_ADDR (2) +#define SKX_MC0_CH1_REGISTER_FUNC_ADDR (6) +#define SKX_MC0_CH2_REGISTER_FUNC_ADDR (2) +#define SKX_MC0_CH3_REGISTER_FUNC_ADDR (-1) //Does not exist + +#define SKX_MC1_CH0_REGISTER_DEV_ADDR (12) +#define SKX_MC1_CH1_REGISTER_DEV_ADDR (12) +#define SKX_MC1_CH2_REGISTER_DEV_ADDR (13) +#define SKX_MC1_CH3_REGISTER_DEV_ADDR (-1) //Does not exist +#define SKX_MC1_CH0_REGISTER_FUNC_ADDR (2) +#define SKX_MC1_CH1_REGISTER_FUNC_ADDR (6) +#define SKX_MC1_CH2_REGISTER_FUNC_ADDR (2) +#define SKX_MC1_CH3_REGISTER_FUNC_ADDR (-1) //Does not exist + + #define KNL_MC1_CH0_REGISTER_DEV_ADDR (9) #define KNL_MC1_CH1_REGISTER_DEV_ADDR (9) #define KNL_MC1_CH2_REGISTER_DEV_ADDR (9) @@ -617,6 +629,13 @@ struct BecktonUncorePMUCNTCTLRegister #define HSX_QPI_PORT2_REGISTER_DEV_ADDR (10) #define HSX_QPI_PORT2_REGISTER_FUNC_ADDR (2) +#define SKX_QPI_PORT0_REGISTER_DEV_ADDR (14) +#define SKX_QPI_PORT0_REGISTER_FUNC_ADDR (0) +#define SKX_QPI_PORT1_REGISTER_DEV_ADDR (15) +#define SKX_QPI_PORT1_REGISTER_FUNC_ADDR (0) +#define SKX_QPI_PORT2_REGISTER_DEV_ADDR (16) +#define SKX_QPI_PORT2_REGISTER_FUNC_ADDR (0) + #define QPI_PORT0_MISC_REGISTER_FUNC_ADDR (0) #define QPI_PORT1_MISC_REGISTER_FUNC_ADDR (0) #define QPI_PORT2_MISC_REGISTER_FUNC_ADDR (0) @@ -635,6 +654,18 @@ struct BecktonUncorePMUCNTCTLRegister #define QPI_RATE_STATUS_ADDR (0x0D4) +#define U_L_PCI_PMON_BOX_CTL_ADDR (0x378) + +#define U_L_PCI_PMON_CTL3_ADDR (0x368) +#define U_L_PCI_PMON_CTL2_ADDR (0x360) +#define U_L_PCI_PMON_CTL1_ADDR (0x358) +#define U_L_PCI_PMON_CTL0_ADDR (0x350) + +#define U_L_PCI_PMON_CTR3_ADDR (0x330) +#define U_L_PCI_PMON_CTR2_ADDR (0x328) +#define U_L_PCI_PMON_CTR1_ADDR (0x320) +#define U_L_PCI_PMON_CTR0_ADDR (0x318) + #define JKTIVT_PCU_MSR_PMON_CTR3_ADDR (0x0C39) #define JKTIVT_PCU_MSR_PMON_CTR2_ADDR (0x0C38) #define JKTIVT_PCU_MSR_PMON_CTR1_ADDR (0x0C37) @@ -667,6 +698,7 @@ struct BecktonUncorePMUCNTCTLRegister #define MC_CH_PCI_PMON_BOX_CTL_RST_COUNTERS (1 << 1) #define MC_CH_PCI_PMON_BOX_CTL_FRZ (1 << 8) #define MC_CH_PCI_PMON_BOX_CTL_FRZ_EN (1 << 16) +#define SKX_MC_CH_PCI_PMON_BOX_CTL_RSV ((1 << 16) + (1 << 17)) #define UNCORE_PMON_BOX_CTL_VALID_BITS_MASK ((1 << 17) - 1) @@ -686,6 +718,7 @@ struct BecktonUncorePMUCNTCTLRegister #define Q_P_PCI_PMON_BOX_CTL_RST_COUNTERS (1 << 1) #define Q_P_PCI_PMON_BOX_CTL_RST_FRZ (1 << 8) #define Q_P_PCI_PMON_BOX_CTL_RST_FRZ_EN (1 << 16) +#define U_L_PCI_PMON_BOX_CTL_RSV ((1 << 16) + (1 << 17)) #define Q_P_PCI_PMON_CTL_EVENT(x) (x << 0) #define Q_P_PCI_PMON_CTL_UMASK(x) (x << 8) @@ -785,6 +818,70 @@ struct BecktonUncorePMUCNTCTLRegister #define JKT_CBO_MSR_PMON_BOX_FILTER_OPC(x) (x << 23UL) #define IVTHSX_CBO_MSR_PMON_BOX_FILTER1_OPC(x) (x << 20UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_REM(x) (x << 0UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_LOC(x) (x << 1UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_NM(x) (x << 4UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_NOT_NM(x) (x << 5UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_OPC0(x) (x << 9UL) +#define SKX_CHA_MSR_PMON_BOX_FILTER1_NC(x) (x << 30UL) + +#define SKX_CHA_TOR_INSERTS_UMASK_IRQ(x) (x << 0) +#define SKX_CHA_TOR_INSERTS_UMASK_PRQ(x) (x << 2) +#define SKX_CHA_TOR_INSERTS_UMASK_HIT(x) (x << 4) +#define SKX_CHA_TOR_INSERTS_UMASK_MISS(x) (x << 5) + +#define SKX_IIO_CBDMA_UNIT_STATUS (0x0A47) +#define SKX_IIO_CBDMA_UNIT_CTL (0x0A40) +#define SKX_IIO_CBDMA_CTR0 (0x0A41) +#define SKX_IIO_CBDMA_CLK (0x0A45) +#define SKX_IIO_CBDMA_CTL0 (0x0A48) +#define SKX_IIO_PM_REG_STEP (0x0020) + +#define IIO_MSR_PMON_BOX_CTL_RST_CONTROL (1 << 0) +#define IIO_MSR_PMON_BOX_CTL_RST_COUNTERS (1 << 1) +#define IIO_MSR_PMON_BOX_CTL_FRZ (1 << 8) +#define IIO_MSR_PMON_BOX_CTL_RSV ((1 << 16) + (1 << 17)) + +#define IIO_MSR_PMON_CTL_EVENT(x) ((x) << 0) +#define IIO_MSR_PMON_CTL_UMASK(x) ((x) << 8) +#define IIO_MSR_PMON_CTL_RST (1 << 17) +#define IIO_MSR_PMON_CTL_EDGE_DET (1 << 18) +#define IIO_MSR_PMON_CTL_OV_EN (1 << 20) +#define IIO_MSR_PMON_CTL_EN (1 << 22) +#define IIO_MSR_PMON_CTL_INVERT (1 << 23) +#define IIO_MSR_PMON_CTL_THRESH(x) ((x) << 24ULL) +#define IIO_MSR_PMON_CTL_CH_MASK(x) ((x) << 36ULL) +#define IIO_MSR_PMON_CTL_FC_MASK(x) ((x) << 44ULL) + +/* \brief IIO Performance Monitoring Control Register format + + IIOn_MSR_PMON_CTL{3-0} Register- Field Definitions +*/ +struct IIOPMUCNTCTLRegister +{ + union + { + struct + { + uint64 event_select : 8; + uint64 umask : 8; + uint64 reserved1 : 1; + uint64 reset : 1; + uint64 edge_det : 1; + uint64 ignored : 1; + uint64 overflow_enable : 1; + uint64 reserved2 : 1; + uint64 enable : 1; + uint64 invert : 1; + uint64 thresh : 12; + uint64 ch_mask : 8; + uint64 fc_mask : 3; + uint64 reservedX : 17; + } fields; + uint64 value; + }; +}; + #define MSR_PACKAGE_THERM_STATUS (0x01B1) #define MSR_IA32_THERM_STATUS (0x019C) #define PCM_INVALID_THERMAL_HEADROOM ((std::numeric_limits::min)())