diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 8d25bb15..25135f3e 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -49,4 +49,6 @@ jobs: uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: PCMforWindows - path: build/bin/**/* + path: | + build/bin/**/* + third-party-software.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 73f81465..a353345d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,7 @@ if(UNIX) # APPLE, LINUX, FREE_BSD message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") install(DIRECTORY "perfmon" DESTINATION ${CMAKE_INSTALL_DATADIR}/pcm) + install(FILES "third-party-software.txt" DESTINATION ${CMAKE_INSTALL_DATADIR}/pcm) endif(UNIX) diff --git a/appveyor.yml b/appveyor.yml index 64fb18f4..09df9eeb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,7 +18,7 @@ build_script: - msbuild src\WinMSRDriver\MSR.vcxproj /m /t:Build /p:Configuration=Release /p:Platform=x64 after_build: -- cmd: 7z a pcm-all.zip %APPVEYOR_BUILD_FOLDER%\build\bin\Release\*.exe %APPVEYOR_BUILD_FOLDER%\build\bin\Release\*.dll %APPVEYOR_BUILD_FOLDER%\build\src\Release\*.lib %APPVEYOR_BUILD_FOLDER%\build\src\Release\*.exp %APPVEYOR_BUILD_FOLDER%\src\windows\PCM-Service.exe.config %APPVEYOR_BUILD_FOLDER%\src\WinMSRDriver\x64\Release\MSR\msr.* +- cmd: 7z a pcm-all.zip %APPVEYOR_BUILD_FOLDER%\build\bin\Release\*.exe %APPVEYOR_BUILD_FOLDER%\build\bin\Release\*.dll %APPVEYOR_BUILD_FOLDER%\build\src\Release\*.lib %APPVEYOR_BUILD_FOLDER%\build\src\Release\*.exp %APPVEYOR_BUILD_FOLDER%\src\windows\PCM-Service.exe.config %APPVEYOR_BUILD_FOLDER%\src\WinMSRDriver\x64\Release\MSR\msr.* %APPVEYOR_BUILD_FOLDER%\third-party-software.txt artifacts: - path: pcm-all.zip name: pcm-all diff --git a/doc/WINDOWS_HOWTO.md b/doc/WINDOWS_HOWTO.md index b4afc769..fa03c819 100644 --- a/doc/WINDOWS_HOWTO.md +++ b/doc/WINDOWS_HOWTO.md @@ -14,7 +14,7 @@ _For support of systems with more than _**_64_**_ logical cores you need to comp alternatively you can perform `cmake -B build`, open *PCM.sln* form *build* folder in and build required project in Visual Studio. .exe and .dll files will be located in *build\bin\Release* folder 3. As Administrator create PCM directory in Windows "Program Files" directory (e.g. `C:\Program Files (x86)\PCM\`) -4. As Administrator copy the msr.sys driver and pcm.exe into the PCM directory +4. As Administrator copy the msr.sys driver into `c:\windows\system32` and pcm.exe into the PCM directory 5. Run pcm.exe utility from the PCM directory as Administrator For Windows 7+ and Windows Server 2008+ R2 the PCM utilities need to be run as Administrator: @@ -51,7 +51,7 @@ If you do not want or cannot compile the msr.sys driver you might use a third-pa Instructions: 1. Download the free RealTemp utility package from [http://www.techpowerup.com/realtemp/](http://www.techpowerup.com/realtemp/) or any other free utility that uses the open-source WinRing0 driver (like OpenHardwareMonitor [http://code.google.com/p/open-hardware-monitor/downloads/list](http://code.google.com/p/open-hardware-monitor/downloads/list)). -2. Copy WinRing0.dll, WinRing0.sys, WinRing0x64.dll, WinRing0x64.sys files from there into the PCM.exe binary location, into the PCM-Service.exe location and into c:\windows\system32 +2. Copy WinRing0.dll, WinRing0.sys, WinRing0x64.dll, WinRing0x64.sys files from there into c:\windows\system32 3. Run the PCM.exe tool and/or go to step 6 (perfmon utility). ## Compile the Windows MSR driver @@ -122,7 +122,7 @@ Starting from this release, **pcm-sensor-server** is now supported on Windows. T ### Running pcm-sensor-server on Windows -1. Create a directory for PCM in a protected location (e.g., `C:\Program Files\PCM\` or `C:\Program Files (x86)\PCM\`). Copy `msr.sys` and `pcm-sensor-server.exe` to this directory. **Important:** Do not place PCM binaries in user-writable directories (e.g., Downloads, Desktop, `C:\Users\Public\`) to prevent DLL planting attacks. +1. Create a directory for PCM in a protected location (e.g., `C:\Program Files\PCM\` or `C:\Program Files (x86)\PCM\`). Copy `pcm-sensor-server.exe` to this directory and `msr.sys` to `c:\windows\system32`. If using WinPmem for memory bandwidth statistics, also copy `winpmem_x64.sys` (or `winpmem_x86.sys`) to `c:\windows\system32`. **Important:** Do not place PCM binaries or drivers in user-writable directories (e.g., Downloads, Desktop, `C:\Users\Public\`) to prevent driver planting attacks. 2. Run as Administrator (required for MSR access): ``` diff --git a/src/cpucounters.cpp b/src/cpucounters.cpp index c1039ab6..cc1a3d4d 100644 --- a/src/cpucounters.cpp +++ b/src/cpucounters.cpp @@ -3279,7 +3279,7 @@ PCM::PCM() : #endif #ifdef _MSC_VER // WARNING: This driver code (msr.sys) is only for testing purposes, not for production use - Driver drv(Driver::msrLocalPath()); + Driver drv(Driver::msrSystemPath()); // drv.stop(); // restart driver (usually not needed) if (!drv.start()) { diff --git a/src/cpucounters.h b/src/cpucounters.h index 4091ec75..fc6c9a33 100644 --- a/src/cpucounters.h +++ b/src/cpucounters.h @@ -2074,6 +2074,11 @@ class PCM_API PCM //! \return socket identifier int32 getSocketId(uint32 core_id) const { return (int32)topology[core_id].socket_id; } + //! \brief Determines die of given processor ID within a socket + //! \param os_id processor identifier + //! \return die identifier + int32 getDieId(uint32 os_id) const { return (int32)topology[os_id].die_id; } + //! \brief Maps NUMA node ID to CPU socket ID //! \param numa_node_id NUMA node identifier //! \return socket identifier, or -1 if mapping is not available or numa_node_id is invalid diff --git a/src/mmio.cpp b/src/mmio.cpp index ee112d9f..46a5a2a6 100644 --- a/src/mmio.cpp +++ b/src/mmio.cpp @@ -38,7 +38,12 @@ class PCMPmem : public WinPmem { SYSTEM_INFO sys_info; SecureZeroMemory(&sys_info, sizeof(sys_info)); - GetCurrentDirectory(MAX_PATH - 10, driver_filename); + // Use System32 directory to avoid untrusted search path vulnerability + if (!GetSystemDirectory(driver_filename, MAX_PATH - 10)) + { + std::wcerr << "Failed to get System32 directory path.\n"; + return -1; + } GetNativeSystemInfo(&sys_info); switch (sys_info.wProcessorArchitecture) @@ -47,7 +52,7 @@ class PCMPmem : public WinPmem { _tcscat_s(driver_filename, MAX_PATH, TEXT("\\winpmem_x64.sys")); if (GetFileAttributes(driver_filename) == INVALID_FILE_ATTRIBUTES) { - std::cerr << "ERROR: winpmem_x64.sys not found in current directory. Download it from https://github.com/Velocidex/WinPmem/blob/f044f340dd05658d026b0f293cdfa92876159872/kernel/binaries/winpmem_x64.sys .\n"; + std::cerr << "ERROR: winpmem_x64.sys not found in System32 directory. Download it from https://github.com/Velocidex/WinPmem/blob/f044f340dd05658d026b0f293cdfa92876159872/kernel/binaries/winpmem_x64.sys .\n"; std::cerr << "ERROR: Memory bandwidth statistics will not be available.\n"; } break; @@ -55,7 +60,7 @@ class PCMPmem : public WinPmem { _tcscat_s(driver_filename, MAX_PATH, TEXT("\\winpmem_x86.sys")); if (GetFileAttributes(driver_filename) == INVALID_FILE_ATTRIBUTES) { - std::cerr << "ERROR: winpmem_x86.sys not found in current directory. Download it from https://github.com/Velocidex/WinPmem/blob/f044f340dd05658d026b0f293cdfa92876159872/kernel/binaries/winpmem_x86.sys .\n"; + std::cerr << "ERROR: winpmem_x86.sys not found in System32 directory. Download it from https://github.com/Velocidex/WinPmem/blob/f044f340dd05658d026b0f293cdfa92876159872/kernel/binaries/winpmem_x86.sys .\n"; std::cerr << "ERROR: Memory bandwidth statistics will not be available.\n"; } break; diff --git a/src/pcm-memory.cpp b/src/pcm-memory.cpp index 1f4030d1..bddb0d8f 100644 --- a/src/pcm-memory.cpp +++ b/src/pcm-memory.cpp @@ -1512,7 +1512,7 @@ int mainThrows(int argc, char * argv[]) } else if (check_argument_equals(*argv, {"--installDriver"})) { - Driver tmpDrvObject = Driver(Driver::msrLocalPath()); + Driver tmpDrvObject = Driver(Driver::msrSystemPath()); if (!tmpDrvObject.start()) { tcerr << "Can not access CPU counters\n"; diff --git a/src/pcm-msr.cpp b/src/pcm-msr.cpp index 761b4de3..b6ddc659 100644 --- a/src/pcm-msr.cpp +++ b/src/pcm-msr.cpp @@ -123,7 +123,7 @@ int mainThrows(int argc, char * argv[]) SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // WARNING: This driver code (msr.sys) is only for testing purposes, not for production use - Driver drv = Driver(Driver::msrLocalPath()); + Driver drv = Driver(Driver::msrSystemPath()); // drv.stop(); // restart driver (usually not needed) if (!drv.start()) { diff --git a/src/pcm-pcicfg.cpp b/src/pcm-pcicfg.cpp index 25da0b18..a14b1eaa 100644 --- a/src/pcm-pcicfg.cpp +++ b/src/pcm-pcicfg.cpp @@ -116,7 +116,7 @@ int mainThrows(int argc, char * argv[]) SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // WARNING: This driver code (msr.sys) is only for testing purposes, not for production use - Driver drv = Driver(Driver::msrLocalPath()); + Driver drv = Driver(Driver::msrSystemPath()); // drv.stop(); // restart driver (usually not needed) if (!drv.start()) { @@ -137,7 +137,7 @@ int mainThrows(int argc, char * argv[]) } // List all PCI devices - forAllDevices([&dec, &verbosity, &pciDB](const uint32 group, const uint32 bus, const uint32 device, const uint32 function, const uint32 device_id) + forAllDevices([&dec, &verbosity, &pciDB](const uint32 group, const uint32 bus, const uint32 device, const uint32 function, const uint32 /* device_id */) { if (PciHandleType::exists(group, bus, device, function) == false) { diff --git a/src/pcm-pcie-collector.h b/src/pcm-pcie-collector.h new file mode 100644 index 00000000..bb0acab6 --- /dev/null +++ b/src/pcm-pcie-collector.h @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2026, Intel Corporation +#pragma once + +#include "pcm-pcie.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +class PCIeCollector { +public: + struct SocketBW { + uint64_t readBytes = 0; + uint64_t writeBytes = 0; + }; + + static PCIeCollector* getInstance() { + static PCIeCollector instance; + return instance.supported_ ? &instance : nullptr; + } + + PCIeCollector(PCIeCollector const &) = delete; + PCIeCollector& operator=(PCIeCollector const &) = delete; + PCIeCollector(PCIeCollector &&) = delete; + PCIeCollector& operator=(PCIeCollector &&) = delete; + + static constexpr uint32_t kDefaultIntervalMs = 2000; + + void startBackground(uint32_t intervalMs = kDefaultIntervalMs) { + bool expected = false; + if (!bgRunning_.compare_exchange_strong(expected, true)) return; + bgThread_ = std::thread([this, intervalMs]() { + while (bgRunning_.load()) { + collect(); + std::unique_lock lk(mu_); + cv_.wait_for(lk, std::chrono::milliseconds(intervalMs), + [this] { return !bgRunning_.load(); }); + } + }); + } + + void stop() { + bool expected = true; + if (!bgRunning_.compare_exchange_strong(expected, false)) return; + cv_.notify_one(); + if (bgThread_.joinable()) bgThread_.join(); + } + + ~PCIeCollector() { stop(); } + + uint32_t socketCount() const { return socketCount_; } + + SocketBW getSocket(uint32_t skt) const { + std::lock_guard lk(mu_); + if (skt < snapshot_.size()) return snapshot_[skt]; + return {}; + } + + SocketBW getAggregate() const { + std::lock_guard lk(mu_); + return aggregate_; + } + + std::vector getRawValues(uint32_t skt) const { + std::lock_guard lk(mu_); + if (skt < rawValues_.size()) return rawValues_[skt]; + return {}; + } + + std::vector getRawAggregate() const { + std::lock_guard lk(mu_); + return rawAggValues_; + } + + const std::vector& eventNames() const { return eventNames_; } + uint32_t numEvents() const { return static_cast(eventNames_.size()); } + bool isSupported() const { return supported_; } + +private: + PCIeCollector() { + try { + PCM* pcm = PCM::getInstance(); + static constexpr uint32_t kPmonMultiplier = 1000; + platform_.reset(IPlatform::getPlatform(pcm, false, true, false, kPmonMultiplier)); + if (platform_) { + supported_ = true; + socketCount_ = pcm->getNumSockets(); + const auto& names = platform_->getEventNames(); + eventNames_.assign(names.begin(), names.end()); + snapshot_.resize(socketCount_); + rawValues_.resize(socketCount_, std::vector(eventNames_.size(), 0)); + rawAggValues_.resize(eventNames_.size(), 0); + cumSnapshot_.resize(socketCount_); + cumRawValues_.resize(socketCount_, std::vector(eventNames_.size(), 0)); + } + } catch (const std::exception& e) { + std::cerr << "PCIeCollector: " << e.what() << " (PCIe metrics disabled)\n"; + supported_ = false; + } + } + + void collect() { + if (!platform_ || !bgRunning_.load()) return; + platform_->cleanup(); + platform_->getEvents(); + + SocketBW aggDelta{0, 0}; + const uint32_t nEvt = numEvents(); + + for (uint32_t s = 0; s < socketCount_; ++s) { + uint64_t dr = platform_->getReadBw(s, IPlatform::TOTAL); + uint64_t dw = platform_->getWriteBw(s, IPlatform::TOTAL); + cumSnapshot_[s].readBytes += dr; + cumSnapshot_[s].writeBytes += dw; + aggDelta.readBytes += dr; + aggDelta.writeBytes += dw; + for (uint32_t i = 0; i < nEvt; ++i) + cumRawValues_[s][i] += platform_->event(s, IPlatform::TOTAL, i); + } + cumAggregate_.readBytes += aggDelta.readBytes; + cumAggregate_.writeBytes += aggDelta.writeBytes; + + std::vector rawAgg(nEvt, 0); + for (uint32_t s = 0; s < socketCount_; ++s) + for (uint32_t i = 0; i < nEvt; ++i) + rawAgg[i] += cumRawValues_[s][i]; + + std::lock_guard lk(mu_); + snapshot_ = cumSnapshot_; + aggregate_ = cumAggregate_; + rawValues_ = cumRawValues_; + rawAggValues_ = rawAgg; + } + + std::unique_ptr platform_; + bool supported_ = false; + uint32_t socketCount_ = 0; + std::vector eventNames_; + + std::vector snapshot_; + SocketBW aggregate_; + std::vector> rawValues_; + std::vector rawAggValues_; + + std::vector cumSnapshot_; + SocketBW cumAggregate_; + std::vector> cumRawValues_; + + mutable std::mutex mu_; + std::condition_variable cv_; + std::thread bgThread_; + std::atomic bgRunning_{false}; +}; diff --git a/src/pcm-pcie.cpp b/src/pcm-pcie.cpp index aa92204e..97726488 100644 --- a/src/pcm-pcie.cpp +++ b/src/pcm-pcie.cpp @@ -93,35 +93,7 @@ void print_usage(const string & progname) cout << "\n"; } -IPlatform *IPlatform::getPlatform(PCM *m, bool csv, bool print_bandwidth, bool print_additional_info, uint32 delay) -{ - switch (m->getCPUFamilyModel()) { - case PCM::GNR: - case PCM::GNR_D: - case PCM::SRF: - return new BirchStreamPlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::GRR: - return new LoganvillePlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::SPR: - case PCM::EMR: - return new EagleStreamPlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::ICX: - case PCM::SNOWRIDGE: - return new WhitleyPlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::SKX: - return new PurleyPlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::BDX_DE: - case PCM::BDX: - case PCM::KNL: - case PCM::HASWELLX: - return new GrantleyPlatform(m, csv, print_bandwidth, print_additional_info, delay); - case PCM::IVYTOWN: - case PCM::JAKETOWN: - return new BromolowPlatform(m, csv, print_bandwidth, print_additional_info, delay); - default: - return NULL; - } -} +// getPlatform() is defined inline in pcm-pcie.h. PCM_MAIN_NOTHROW; diff --git a/src/pcm-pcie.h b/src/pcm-pcie.h index f9055024..7f3f09e1 100644 --- a/src/pcm-pcie.h +++ b/src/pcm-pcie.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,17 @@ class IPlatform bool verbose, uint32 delay); virtual ~IPlatform() { } + enum eventFilter {TOTAL, MISS, HIT, fltLast}; + + // Data-access interface for external consumers (e.g. PCIeCollector). + virtual uint64 getReadBw(uint socket, eventFilter filter) = 0; + virtual uint64 getWriteBw(uint socket, eventFilter filter) = 0; + virtual uint64 getReadBw() = 0; + virtual uint64 getWriteBw() = 0; + virtual uint64 event(uint socket, eventFilter filter, uint idx) = 0; + virtual const vector& getEventNames() const = 0; + virtual uint numEvents() const = 0; + protected: PCM *m_pcm; bool m_csv; @@ -61,8 +73,6 @@ class IPlatform bool m_verbose; uint m_socketCount; - enum eventFilter {TOTAL, MISS, HIT, fltLast}; - vector filterNames, bwNames; }; @@ -72,8 +82,7 @@ void IPlatform::init() if (m_pcm->getMaxNumOfUncorePMUs(PCM::CBO_PMU_ID) == 0) // CHAs (CBoxes) PMUs are not available { - cerr << "Your processor/system does not support CHA PCIe performance counters. Program aborted\n"; - exit(EXIT_FAILURE); + throw std::runtime_error("CHA PCIe performance counters not supported on this processor"); } if (m_pcm->isMaxNumOfCBoxesBasedOnCoreCount() && m_pcm->isSomeCoreOfflined()) @@ -88,8 +97,7 @@ void IPlatform::init() pcm-pcie does not support such systems because the bandwidth can't be computed correctly. */ - cerr << "Core offlining is not supported on your processor. Program aborted\n"; - exit(EXIT_FAILURE); + throw std::runtime_error("CHA PCIe counters unavailable: core offlining not supported on this processor"); } } @@ -161,13 +169,11 @@ class LegacyPlatform: public IPlatform } }; + const vector& getEventNames() const override { return eventNames; } + uint numEvents() const override { return (uint)eventNames.size(); } + protected: vector> eventSample; - virtual uint64 getReadBw(uint socket, eventFilter filter) = 0; - virtual uint64 getWriteBw(uint socket, eventFilter filter) = 0; - virtual uint64 getReadBw() = 0; - virtual uint64 getWriteBw() = 0; - virtual uint64 event(uint socket, eventFilter filter, uint idx) = 0; }; void LegacyPlatform::cleanup() @@ -400,11 +406,11 @@ class BirchStreamPlatform: public LegacyPlatform eventLast }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 BirchStreamPlatform::event(uint socket, eventFilter filter, uint idx) @@ -531,11 +537,11 @@ class LoganvillePlatform: public LegacyPlatform eventLast }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 LoganvillePlatform::event(uint socket, eventFilter filter, uint idx) @@ -661,11 +667,11 @@ class EagleStreamPlatform: public LegacyPlatform eventLast }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 EagleStreamPlatform::event(uint socket, eventFilter filter, uint idx) @@ -786,11 +792,11 @@ class WhitleyPlatform: public LegacyPlatform eventLast }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 WhitleyPlatform::event(uint socket, eventFilter filter, uint idx) @@ -922,11 +928,11 @@ class PurleyPlatform: public LegacyPlatform WiL_hit, }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 PurleyPlatform::event(uint socket, eventFilter filter, uint idx) @@ -1034,11 +1040,11 @@ class GrantleyPlatform: public LegacyPlatform WiL_total, }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 GrantleyPlatform::event(uint socket, eventFilter filter, uint idx) @@ -1143,11 +1149,11 @@ class BromolowPlatform: public LegacyPlatform PCIeNSWrF_total, }; - virtual uint64 getReadBw(uint socket, eventFilter filter); - virtual uint64 getWriteBw(uint socket, eventFilter filter); - virtual uint64 getReadBw(); - virtual uint64 getWriteBw(); - virtual uint64 event(uint socket, eventFilter filter, uint idx); + uint64 getReadBw(uint socket, eventFilter filter) override; + uint64 getWriteBw(uint socket, eventFilter filter) override; + uint64 getReadBw() override; + uint64 getWriteBw() override; + uint64 event(uint socket, eventFilter filter, uint idx) override; }; uint64 BromolowPlatform::event(uint socket, eventFilter filter, uint idx) @@ -1201,3 +1207,36 @@ uint64 BromolowPlatform::getWriteBw() event(socket, TOTAL, PCIeNSWrF)); return (writeBw * 64ULL); } + +inline IPlatform *IPlatform::getPlatform(PCM *m, bool csv, bool bandwidth, + bool verbose, uint32 delay) +{ + switch (m->getCPUFamilyModel()) { + case PCM::GNR: + case PCM::GNR_D: + case PCM::SRF: + return new BirchStreamPlatform(m, csv, bandwidth, verbose, delay); + case PCM::GRR: + return new LoganvillePlatform(m, csv, bandwidth, verbose, delay); + case PCM::SPR: + case PCM::EMR: + return new EagleStreamPlatform(m, csv, bandwidth, verbose, delay); + case PCM::ICX: + case PCM::SNOWRIDGE: + return new WhitleyPlatform(m, csv, bandwidth, verbose, delay); + case PCM::SKX: + return new PurleyPlatform(m, csv, bandwidth, verbose, delay); + case PCM::BDX_DE: + case PCM::BDX: + case PCM::KNL: + case PCM::HASWELLX: + return new GrantleyPlatform(m, csv, bandwidth, verbose, delay); + case PCM::IVYTOWN: + case PCM::JAKETOWN: + return new BromolowPlatform(m, csv, bandwidth, verbose, delay); + default: + return nullptr; + } +} + + diff --git a/src/pcm-sensor-server.cpp b/src/pcm-sensor-server.cpp index 838a87f7..9e83a268 100644 --- a/src/pcm-sensor-server.cpp +++ b/src/pcm-sensor-server.cpp @@ -68,10 +68,14 @@ typedef int socket_t; #include #include +#include +#include +#include #include "threadpool.h" #include "pcm-iio-pmu.h" +#include "pcm-pcie-collector.h" using namespace pcm; @@ -323,21 +327,21 @@ class JSONPrinter : Visitor CoreCounterState ccs; if ( nullptr == ag.get() ) return ccs; - return std::move( ag->coreCounterStates()[tid] ); + return ag->coreCounterStates()[tid]; } SocketCounterState const getSocketCounter( std::shared_ptr ag, uint32 sid ) const { SocketCounterState socs; if ( nullptr == ag.get() ) return socs; - return std::move( ag->socketCounterStates()[sid] ); + return ag->socketCounterStates()[sid]; } SystemCounterState getSystemCounter( std::shared_ptr ag ) const { SystemCounterState sycs; if ( nullptr == ag.get() ) return sycs; - return std::move( ag->systemCounterState() ); + return ag->systemCounterState(); } @@ -410,6 +414,10 @@ class JSONPrinter : Visitor endObject( JSONPrinter::LineEndAction::DelimiterAndNewLine, END_OBJECT ); startObject( "Uncore Aggregate", BEGIN_OBJECT ); printUncoreCounterState( before, after ); + endObject( JSONPrinter::LineEndAction::DelimiterAndNewLine, END_OBJECT ); + + startObject( "PCIe Bandwidth", BEGIN_OBJECT ); + printPCIeCounterState(); endObject( JSONPrinter::LineEndAction::NewLineOnly, END_OBJECT ); endObject( JSONPrinter::LineEndAction::NewLineOnly, END_OBJECT ); @@ -533,6 +541,31 @@ class JSONPrinter : Visitor endObject( JSONPrinter::NewLineOnly, END_OBJECT ); } + void printPCIeCounterState() { + PCIeCollector* col = PCIeCollector::getInstance(); + if (!col) return; + + const auto& names = col->eventNames(); + for (uint32 skt = 0; skt < col->socketCount(); ++skt) { + auto bw = col->getSocket(skt); + auto raw = col->getRawValues(skt); + startObject( std::string("PCIe Counters Socket ") + std::to_string(skt), BEGIN_OBJECT ); + printCounter( "PCIe Read Bytes", bw.readBytes ); + printCounter( "PCIe Write Bytes", bw.writeBytes ); + for (uint32_t i = 0; i < raw.size(); ++i) + printCounter( std::string("PCIe ") + names[i], raw[i] ); + endObject( JSONPrinter::DelimiterAndNewLine, END_OBJECT ); + } + auto agg = col->getAggregate(); + auto rawAgg = col->getRawAggregate(); + startObject( "PCIe Counters Aggregate", BEGIN_OBJECT ); + printCounter( "PCIe Read Bytes", agg.readBytes ); + printCounter( "PCIe Write Bytes", agg.writeBytes ); + for (uint32_t i = 0; i < rawAgg.size(); ++i) + printCounter( std::string("PCIe ") + names[i], rawAgg[i] ); + endObject( JSONPrinter::NewLineOnly, END_OBJECT ); + } + void printAccelCounterState( SystemCounterState const& before, SystemCounterState const& after ) { AcceleratorCounterState* accs_ = AcceleratorCounterState::getInstance(); uint32 devs = accs_->getNumOfAccelDevs(); @@ -654,21 +687,21 @@ class PrometheusPrinter : Visitor CoreCounterState ccs; if ( nullptr == ag.get() ) return ccs; - return std::move( ag->coreCounterStates()[tid] ); + return ag->coreCounterStates()[tid]; } SocketCounterState const getSocketCounter( std::shared_ptr ag, uint32 sid ) const { SocketCounterState socs; if ( nullptr == ag.get() ) return socs; - return std::move( ag->socketCounterStates()[sid] ); + return ag->socketCounterStates()[sid]; } SystemCounterState getSystemCounter( std::shared_ptr ag ) const { SystemCounterState sycs; if ( nullptr == ag.get() ) return sycs; - return std::move( ag->systemCounterState() ); + return ag->systemCounterState(); } virtual void dispatch( HyperThread* ht ) override { @@ -724,6 +757,8 @@ class PrometheusPrinter : Visitor printBasicCounterState ( before, after ); printComment( "Uncore Counters Aggregate System" ); printUncoreCounterState( before, after ); + printComment( "PCIe Bandwidth Counters" ); + printPCIeCounterState(); removeFromHierarchy(); // aggregate=system } @@ -829,6 +864,34 @@ class PrometheusPrinter : Visitor removeFromHierarchy(); } + void printPCIeCounterState() { + PCIeCollector* col = PCIeCollector::getInstance(); + if (!col) return; + + addToHierarchy( "source=\"uncore\"" ); + + const auto& names = col->eventNames(); + for (uint32 skt = 0; skt < col->socketCount(); ++skt) { + auto bw = col->getSocket(skt); + auto raw = col->getRawValues(skt); + addToHierarchy( std::string("socket=\"") + std::to_string(skt) + "\"" ); + printCounter( "PCIe Read Bytes", bw.readBytes ); + printCounter( "PCIe Write Bytes", bw.writeBytes ); + for (uint32_t i = 0; i < raw.size(); ++i) + printCounter( std::string("PCIe ") + names[i], raw[i] ); + removeFromHierarchy(); + } + + auto agg = col->getAggregate(); + auto rawAgg = col->getRawAggregate(); + printCounter( "PCIe Read Bytes", agg.readBytes ); + printCounter( "PCIe Write Bytes", agg.writeBytes ); + for (uint32_t i = 0; i < rawAgg.size(); ++i) + printCounter( std::string("PCIe ") + names[i], rawAgg[i] ); + + removeFromHierarchy(); + } + void printAccelCounterState( SystemCounterState const& before, SystemCounterState const& after ) { addToHierarchy( "source=\"accel\"" ); @@ -4347,6 +4410,15 @@ int mainThrows(int argc, char * argv[]) { // exit(EXIT_FAILURE); // } + // PCIe bandwidth collection + PCIeCollector* pcieCol = PCIeCollector::getInstance(); + if (pcieCol) { + std::cerr << "PCIe bandwidth collector: supported, starting background thread\n"; + pcieCol->startBackground(2000); + } else { + std::cerr << "PCIe bandwidth collector: not supported on this platform\n"; + } + // Now that everything is set we can start the http(s) server #if defined (USE_SSL) if ( useSSL ) { @@ -4364,6 +4436,9 @@ int mainThrows(int argc, char * argv[]) { std::cerr << "Starting plain HTTP server on http://" << displayAddr << ":" << port << "/\n"; startHTTPServer( listenAddress, port, useIPv4 ); } + + if (pcieCol) pcieCol->stop(); + delete pcmInstance; } else if ( pid > 0 ) { /* Parent, just leave */ diff --git a/src/pcm-tpmi.cpp b/src/pcm-tpmi.cpp index daf53460..1b4f2898 100644 --- a/src/pcm-tpmi.cpp +++ b/src/pcm-tpmi.cpp @@ -99,7 +99,7 @@ int mainThrows(int argc, char * argv[]) SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // WARNING: This driver code (msr.sys) is only for testing purposes, not for production use - Driver drv = Driver(Driver::msrLocalPath()); + Driver drv = Driver(Driver::msrSystemPath()); // drv.stop(); // restart driver (usually not needed) if (!drv.start()) { diff --git a/src/pcm.cpp b/src/pcm.cpp index 95bd948e..5ba29042 100644 --- a/src/pcm.cpp +++ b/src/pcm.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "cpucounters.h" #include "utils.h" @@ -89,6 +90,7 @@ void print_help(const string & prog_name) cout << " -yc | --yescores | /yc => enable specific cores to output\n"; cout << " -ns | --nosockets | /ns => hide socket related output\n"; cout << " -nsys | --nosystem | /nsys => hide system related output\n"; + cout << " --die => show aggregated core metrics per die\n"; cout << " --color => use ASCII colors\n"; cout << " --no-color => don't use ASCII colors\n"; cout << " -csv[=file.csv] | /csv[=file.csv] => output compact CSV format to screen or\n" @@ -171,7 +173,8 @@ void print_output(PCM * m, const bool show_partial_core_output, const bool show_socket_output, const bool show_system_output, - const int metricVersion + const int metricVersion, + const bool show_die_output = false ) { cout << "\n"; @@ -301,6 +304,28 @@ void print_output(PCM * m, cout << resetColor(); } } + if (show_die_output) + { + // aggregate core metrics per (socket, die) pair + std::map, CoreCounterState> die_cstates1, die_cstates2; + for (uint32 i = 0; i < m->getNumCores(); ++i) + { + if (m->isCoreOnline(i) == false) + continue; + auto key = std::make_pair(m->getSocketId(i), m->getDieId(i)); + die_cstates1[key] += cstates1[i]; + die_cstates2[key] += cstates2[i]; + } + cout << longDiv; + for (const auto & entry : die_cstates1) + { + const auto & key = entry.first; + cout << " SKT " << setw(4) << (std::to_string(key.first) + "." + std::to_string(key.second)); + print_basic_metrics(m, die_cstates1[key], die_cstates2[key], metricVersion); + print_other_metrics(m, die_cstates1[key], die_cstates2[key]); + cout << resetColor(); + } + } if (show_socket_output) { if (!(m->getNumSockets() == 1 && (m->isAtom() || cpu_family_model == PCM::KNL))) @@ -725,7 +750,8 @@ void print_csv_header(PCM * m, const bool show_core_output, const bool show_partial_core_output, const bool show_socket_output, - const bool show_system_output + const bool show_system_output, + const bool show_die_output = false ) { // print first header line @@ -880,6 +906,30 @@ void print_csv_header(PCM * m, } } + if (show_die_output) + { + // build sorted list of (socket, die) pairs for first header line + std::map, bool> die_map; + for (uint32 i = 0; i < m->getNumCores(); ++i) + { + if (m->isCoreOnline(i)) + die_map[std::make_pair(m->getSocketId(i), m->getDieId(i))] = true; + } + for (const auto & entry : die_map) + { + header = "SKT" + std::to_string(entry.first.first) + "." + std::to_string(entry.first.second); + print_basic_metrics_csv_semicolons(m, header); + if (m->L3CacheOccupancyMetricAvailable()) + print_csv_header_helper(header); + if (m->CoreLocalMemoryBWMetricAvailable()) + print_csv_header_helper(header); + if (m->CoreRemoteMemoryBWMetricAvailable()) + print_csv_header_helper(header); + print_csv_header_helper(header); // TEMP + print_csv_header_helper(header, 7); // INST,ACYC,TIME(ticks),PhysIPC,PhysIPC%,INSTnom,INSTnom% + } + } + if (show_core_output) { for (uint32 i = 0; i < m->getNumCores(); ++i) @@ -1059,6 +1109,29 @@ void print_csv_header(PCM * m, } } + if (show_die_output) + { + // second header line for die-level columns + std::map, bool> die_map; + for (uint32 i = 0; i < m->getNumCores(); ++i) + { + if (m->isCoreOnline(i)) + die_map[std::make_pair(m->getSocketId(i), m->getDieId(i))] = true; + } + for (size_t d = 0; d < die_map.size(); ++d) + { + print_basic_metrics_csv_header(m); + if (m->L3CacheOccupancyMetricAvailable()) + cout << "L3OCC,"; + if (m->CoreLocalMemoryBWMetricAvailable()) + cout << "LMB,"; + if (m->CoreRemoteMemoryBWMetricAvailable()) + cout << "RMB,"; + cout << "TEMP,"; + cout << "INST,ACYC,TIME(ticks),PhysIPC,PhysIPC%,INSTnom,INSTnom%,"; + } + } + if (show_core_output) { for (uint32 i = 0; i < m->getNumCores(); ++i) @@ -1151,7 +1224,8 @@ void print_csv(PCM * m, const bool show_core_output, const bool show_partial_core_output, const bool show_socket_output, - const bool show_system_output + const bool show_system_output, + const bool show_die_output = false ) { cout << "\n"; @@ -1324,6 +1398,35 @@ void print_csv(PCM * m, } } + if (show_die_output) + { + // aggregate core metrics per (socket, die) pair + std::map, CoreCounterState> die_cstates1, die_cstates2; + for (uint32 i = 0; i < m->getNumCores(); ++i) + { + if (m->isCoreOnline(i) == false) + continue; + auto key = std::make_pair(m->getSocketId(i), m->getDieId(i)); + die_cstates1[key] += cstates1[i]; + die_cstates2[key] += cstates2[i]; + } + for (const auto & entry : die_cstates1) + { + const auto & key = entry.first; + print_basic_metrics_csv(m, die_cstates1[key], die_cstates2[key], false); + print_other_metrics_csv(m, die_cstates1[key], die_cstates2[key]); + cout << ',' << temp_format(die_cstates2[key].getThermalHeadroom()) << ','; + + cout << float_format(getInstructionsRetired(die_cstates1[key], die_cstates2[key])) << "," + << float_format(getCycles(die_cstates1[key], die_cstates2[key])) << "," + << float_format(getInvariantTSC(cstates1[0], cstates2[0])) << "," + << getCoreIPC(die_cstates1[key], die_cstates2[key]) << "," + << 100. * (getCoreIPC(die_cstates1[key], die_cstates2[key]) / double(m->getMaxIPC())) << "," + << getTotalExecUsage(die_cstates1[key], die_cstates2[key]) << "," + << 100. * (getTotalExecUsage(die_cstates1[key], die_cstates2[key]) / double(m->getMaxIPC())) << ","; + } + } + if (show_core_output) { for (uint32 i = 0; i < m->getNumCores(); ++i) @@ -1388,6 +1491,7 @@ int mainThrows(int argc, char * argv[]) bool show_partial_core_output = false; bool show_socket_output = true; bool show_system_output = true; + bool show_die_output = false; bool csv_output = false; bool reset_pmu = false; bool disable_JKT_workaround = false; // as per http://software.intel.com/en-us/articles/performance-impact-when-sampling-certain-llc-events-on-snb-ep-with-vtune @@ -1472,6 +1576,11 @@ int mainThrows(int argc, char * argv[]) show_system_output = false; continue; } + else if (check_argument_equals(*argv, {"--die"})) + { + show_die_output = true; + continue; + } else if (check_argument_equals(*argv, {"--color"})) { setColorEnabled(); @@ -1540,7 +1649,7 @@ int mainThrows(int argc, char * argv[]) } else if (check_argument_equals(*argv, {"--installDriver"})) { - Driver tmpDrvObject = Driver(Driver::msrLocalPath()); + Driver tmpDrvObject = Driver(Driver::msrSystemPath()); if (!tmpDrvObject.start()) { tcerr << "Can not access CPU counters\n"; @@ -1613,7 +1722,7 @@ int mainThrows(int argc, char * argv[]) // cerr << "DEBUG: Delay: " << delay << " seconds. Blocked: " << m->isBlocked() << "\n"; if (csv_output) { - print_csv_header(m, ycores, show_core_output, show_partial_core_output, show_socket_output, show_system_output); + print_csv_header(m, ycores, show_core_output, show_partial_core_output, show_socket_output, show_system_output, show_die_output); } m->getAllCounterStates(sstate1, sktstate1, cstates1); @@ -1632,11 +1741,11 @@ int mainThrows(int argc, char * argv[]) if (csv_output) print_csv(m, cstates1, cstates2, sktstate1, sktstate2, ycores, sstate1, sstate2, - show_core_output, show_partial_core_output, show_socket_output, show_system_output); + show_core_output, show_partial_core_output, show_socket_output, show_system_output, show_die_output); else print_output(m, cstates1, cstates2, sktstate1, sktstate2, ycores, sstate1, sstate2, cpu_family_model, show_core_output, show_partial_core_output, show_socket_output, show_system_output, - metricVersion); + metricVersion, show_die_output); std::swap(sstate1, sstate2); std::swap(sktstate1, sktstate2); diff --git a/src/windows/windriver.h b/src/windows/windriver.h index 1e162fc4..d79bca91 100644 --- a/src/windows/windriver.h +++ b/src/windows/windriver.h @@ -33,22 +33,17 @@ class Driver SERVICE_STATUS ss{}; public: - static tstring msrLocalPath() + // Use System32 directory to avoid untrusted search path vulnerability + static tstring msrSystemPath() { tstring driverPath; - DWORD driverPathLen = 1; - DWORD gcdReturn = 0; - - do { - if (0 != gcdReturn) - { - driverPathLen = gcdReturn; - } - driverPath.resize(driverPathLen); - gcdReturn = GetCurrentDirectory(driverPathLen, &driverPath[0]); - } while (0 != gcdReturn && driverPathLen < gcdReturn); - - removeNullTerminator(driverPath); + driverPath.resize(MAX_PATH); + UINT len = GetSystemDirectory(&driverPath[0], MAX_PATH); + if (len == 0 || len >= MAX_PATH) + { + return TEXT("c:\\windows\\system32\\msr.sys"); + } + driverPath.resize(len); return driverPath + TEXT("\\msr.sys"); } @@ -228,7 +223,7 @@ class Driver } removeNullTerminator(regRead); - + return ERROR_SUCCESS == regRes ? regRead : defaultValue; } diff --git a/tests/pcm-fuzz.cpp b/tests/pcm-fuzz.cpp index 941bbbed..44e12bbd 100644 --- a/tests/pcm-fuzz.cpp +++ b/tests/pcm-fuzz.cpp @@ -8,7 +8,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { size_t size_int = size / sizeof(int); - const auto ints_used = 7; + const auto ints_used = 8; if (size_int < ints_used) { return 0; @@ -65,17 +65,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bool show_socket_output = data_int[pos++] % 2; bool show_system_output = data_int[pos++] % 2; bool show_core_output = data_int[pos++] % 2; + bool show_die_output = data_int[pos++] % 2; assert(pos == ints_used); m->getAllCounterStates(sstate1, sktstate1, cstates1); m->getAllCounterStates(sstate2, sktstate2, cstates2); if (csv_output) print_csv(m, cstates1, cstates2, sktstate1, sktstate2, ycores, sstate1, sstate2, - show_core_output, show_partial_core_output, show_socket_output, show_system_output); + show_core_output, show_partial_core_output, show_socket_output, show_system_output, show_die_output); else print_output(m, cstates1, cstates2, sktstate1, sktstate2, ycores, sstate1, sstate2, cpu_family_model, show_core_output, show_partial_core_output, show_socket_output, show_system_output, - metricVersion); + metricVersion, show_die_output); return 0; } diff --git a/third-party-software.txt b/third-party-software.txt new file mode 100644 index 00000000..8863b0ad --- /dev/null +++ b/third-party-software.txt @@ -0,0 +1,416 @@ +This file contains the list of third-party software included in or with the Intel software and their required +license, copyright statement, permission notice, disclaimers, or other terms. This third-party software is +governed by the separate license terms listed in this file, and this notice file must accompany any distribution +or release (including binary installers and other release artifacts) of the Intel software. +============================== +1. Free Getopt + Copyright (c)2002-2003 Mark K. Kim + All rights reserved. + +BSD 3-Clause License + +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 original author of this software 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. +============================== +2. Intel-PMT + Intel Performance Monitoring Tooling ("Intel-PMT") is referenced by this repository as a Git submodule. + The Intel-PMT source code and binaries are not distributed as part of this Intel software. + When obtaining or using Intel-PMT, please refer to the Intel-PMT repository or distribution for the + applicable license terms, notices, and other conditions. +============================== +3. GoogleTest + Copyright 2008, Google Inc. + All rights reserved. + +BSD 3-Clause License + +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 Google Inc. 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. +============================== +4. Intel perfmon + Copyright (c) 2021, Intel Corporation + All rights reserved. + +BSD 3-Clause License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 HOLDER 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. +============================== +5. pugixml + Copyright (c) 2006-2025 Arseny Kapoulkine + +MIT License + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +============================== +6. simdjson + Copyright 2018-2024 The simdjson authors + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by the Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding any notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS +============================== +7. WinPmem + Copyright 2012 Michael Cohen + +Licensed under the Apache License, Version 2.0. +The full text of the Apache License 2.0 is provided under the +simdjson component section above. +============================== +8. WinRing0 + Copyright (c) 2007-2009 OpenLibSys.org. All rights reserved. + +Modified BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +============================== +9. GCC libgcc (Runtime Library) + Copyright (C) Free Software Foundation, Inc. + +This library is licensed under the terms of the GNU General Public License, +version 3 ("GPLv3"), together with the GCC Runtime Library Exception. +The full text of GPLv3 is available at https://www.gnu.org/licenses/gpl-3.0.html. + +GCC Runtime Library Exception, Version 3.1 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +This GCC Runtime Library Exception ("Exception") is an additional +permission under section 7 of the GNU General Public License, version 3 +("GPLv3"). It applies to a given file (the "Runtime Library") that bears +a notice placed by the copyright holder of the file stating that the +file is governed by GPLv3 along with this Exception. + +When you use GCC to compile a program, GCC may combine portions of +certain GCC header files and runtime libraries with the compiled program. +The purpose of this Exception is to allow compilation of non-GPL +(including proprietary) programs to use, in this way, the header files +and runtime libraries covered by this Exception. + +0. Definitions. + +A file is an "Independent Module" if it either requires the Runtime +Library for execution after a Coverage Compilation, or makes use of +an interface provided by the Runtime Library, but is not otherwise +based on the Runtime Library. + +"GCC" means a version of the GNU Compiler Collection, with or without +modifications, governed by version 3 (or a specified later version) of +the GNU General Public License (GPL) with the option of using any +subsequent versions published by the FSF. + +"GPL-compatible Software" is software whose conditions of propagation, +modification and use would permit combination with GCC in accord with +the license of GCC. + +"Target Code" refers to output from any compiler for a real or virtual +target processor architecture, in executable form or suitable for input +to an assembler, loader, linker and/or execution phase. Notwithstanding +that, Target Code does not include data in any format that is used as a +compiler intermediate representation, or used for producing a compiler +intermediate representation. + +An "Eligible Compilation Process" is a compilation using GCC, alone or +with other GPL-compatible software, or if the output of the compilation +is an Object file, using all or part of the Runtime Library. + +"Output" refers to the result of the Eligible Compilation Process. + +1. Grant of Additional Permission. + +You have permission to propagate a work of Target Code formed by +combining the Runtime Library with Independent Modules, even if such +propagation would otherwise violate the terms of GPLv3, provided that +all Target Code was generated by Eligible Compilation Processes. You +may then convey such a combination under terms of your choice, +consistent with the licensing of the Independent Modules. + +2. No Weakening of GCC Copyleft. + +The availability of this Exception does not imply any general +presumption that third-party software is unaffected by the copyleft +requirements of the license of GCC. +============================== +Other names and brands may be claimed as the property of others.