Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/cpucounters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/pcm-pcicfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
159 changes: 159 additions & 0 deletions src/pcm-pcie-collector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2026, Intel Corporation
#pragma once

#include "pcm-pcie.h"

#include <condition_variable>
#include <mutex>
#include <thread>
#include <atomic>
#include <vector>
#include <string>
#include <cstdint>
#include <iostream>

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<std::mutex> 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<std::mutex> lk(mu_);
if (skt < snapshot_.size()) return snapshot_[skt];
return {};
}

SocketBW getAggregate() const {
std::lock_guard<std::mutex> lk(mu_);
return aggregate_;
}

std::vector<uint64_t> getRawValues(uint32_t skt) const {
std::lock_guard<std::mutex> lk(mu_);
if (skt < rawValues_.size()) return rawValues_[skt];
return {};
}

std::vector<uint64_t> getRawAggregate() const {
std::lock_guard<std::mutex> lk(mu_);
return rawAggValues_;
}

const std::vector<std::string>& eventNames() const { return eventNames_; }
uint32_t numEvents() const { return static_cast<uint32_t>(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<uint64_t>(eventNames_.size(), 0));
rawAggValues_.resize(eventNames_.size(), 0);
cumSnapshot_.resize(socketCount_);
cumRawValues_.resize(socketCount_, std::vector<uint64_t>(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<uint64_t> 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<std::mutex> lk(mu_);
snapshot_ = cumSnapshot_;
aggregate_ = cumAggregate_;
rawValues_ = cumRawValues_;
rawAggValues_ = rawAgg;
}

std::unique_ptr<IPlatform> platform_;
bool supported_ = false;
uint32_t socketCount_ = 0;
std::vector<std::string> eventNames_;

std::vector<SocketBW> snapshot_;
SocketBW aggregate_;
std::vector<std::vector<uint64_t>> rawValues_;
std::vector<uint64_t> rawAggValues_;

std::vector<SocketBW> cumSnapshot_;
SocketBW cumAggregate_;
std::vector<std::vector<uint64_t>> cumRawValues_;

mutable std::mutex mu_;
std::condition_variable cv_;
std::thread bgThread_;
std::atomic<bool> bgRunning_{false};
};
30 changes: 1 addition & 29 deletions src/pcm-pcie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading
Loading