Skip to content
Open
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
16 changes: 9 additions & 7 deletions IntelPresentMon/Interprocess/source/DataStores.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "DataStores.h"
#include "DataStores.h"
#include "MetricCapabilities.h"
#include "IntrospectionTransfer.h"
#include "IntrospectionDataTypeMapping.h"
Expand Down Expand Up @@ -129,9 +129,11 @@ namespace pmon::ipc
}
}

size_t FrameDataStore::CalculateSegmentBytes(const DataStoreSizingInfo& sizing)
size_t ProcessDataStore::CalculateSegmentBytes(const DataStoreSizingInfo& sizing)
{
const size_t payloadBytes = sizing.ringSamples * sizeof(FrameData);
const size_t framePayloadBytes = sizing.ringSamples * sizeof(FrameData);
const size_t processDataPayloadBytes = sizing.ringSamples * sizeof(ProcessDataSample);
const size_t payloadBytes = framePayloadBytes + processDataPayloadBytes;
size_t scaledBytes =
ScaleBytes_(payloadBytes, kFrameScaleMul_, kFrameScaleDiv_);
if (scaledBytes < payloadBytes + kFixedLeewayBytes_) {
Expand All @@ -140,13 +142,13 @@ namespace pmon::ipc
const size_t leewayBytes = scaledBytes - payloadBytes;
const size_t totalBytes = util::PadToAlignment(scaledBytes, kSegmentAlignmentBytes_);
pmlog_verb(util::log::V::ipc_sto)(std::format(
"ipc frame sizing | ring_samples:{} payload_bytes:{} scaled_bytes:{} fixed_leeway_bytes:{} leeway_bytes:{} alignment:{} total_bytes:{}",
sizing.ringSamples, payloadBytes, scaledBytes, kFixedLeewayBytes_,
"ipc process sizing | ring_samples:{} frame_payload_bytes:{} process_data_payload_bytes:{} payload_bytes:{} scaled_bytes:{} fixed_leeway_bytes:{} leeway_bytes:{} alignment:{} total_bytes:{}",
sizing.ringSamples, framePayloadBytes, processDataPayloadBytes, payloadBytes, scaledBytes, kFixedLeewayBytes_,
leewayBytes, kSegmentAlignmentBytes_, totalBytes));
return totalBytes;
}

StaticMetricValue FrameDataStore::FindStaticMetric(PM_METRIC metric) const
StaticMetricValue ProcessDataStore::FindStaticMetric(PM_METRIC metric) const
{
switch (metric) {
case PM_METRIC_APPLICATION:
Expand All @@ -157,7 +159,7 @@ namespace pmon::ipc
return bookkeeping.startQpc;
default:
throw util::Except<PmStatusError>(PM_STATUS_QUERY_MALFORMED,
"Static metric not handled by frame data store");
"Static metric not handled by process data store");
}
}

Expand Down
22 changes: 16 additions & 6 deletions IntelPresentMon/Interprocess/source/DataStores.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ namespace pmon::ipc
using FrameData = util::metrics::FrameData;
using FrameHistoryRing = HistoryRing<FrameData, &FrameData::presentStartTime>;

// Per-process ETW event samples (not tied to a frame). PSO compile is the first consumer;
// additional metrics add fields here and bindings that read processData.
struct ProcessDataSample
{
double psoCompileDurationMs = 0.;
uint64_t eventCompleteQpc = 0;
};
using ProcessDataHistoryRing = HistoryRing<ProcessDataSample, &ProcessDataSample::eventCompleteQpc>;

class MetricCapabilities;
namespace intro
{
Expand All @@ -32,7 +41,7 @@ namespace pmon::ipc
// Frame + telemetry: ring sample capacity and optional override size.
size_t ringSamples = 0;
std::optional<size_t> overrideBytes;
// Frame-only: backpressure behavior for frame rings.
// Process (target) store: backpressure behavior for frame and process data rings.
bool backpressured = false;
};

Expand All @@ -45,15 +54,16 @@ namespace pmon::ipc
int64_t,
const char*>;

struct FrameDataStore
struct ProcessDataStore
{
FrameDataStore(ShmSegmentManager& segMan, size_t cap, bool backpressured)
ProcessDataStore(ShmSegmentManager& segMan, size_t cap, bool backpressured)
:
frameData{ cap, segMan.get_allocator<FrameData>(), backpressured },
processData{ cap, segMan.get_allocator<ProcessDataSample>(), backpressured },
statics{ .applicationName{ segMan.get_allocator<char>() } }
{}
FrameDataStore(ShmSegmentManager& segMan, const DataStoreSizingInfo& sizing)
: FrameDataStore(segMan, sizing.ringSamples, sizing.backpressured)
ProcessDataStore(ShmSegmentManager& segMan, const DataStoreSizingInfo& sizing)
: ProcessDataStore(segMan, sizing.ringSamples, sizing.backpressured)
{}
// values that never change over the life of a target, available for use with metric queries
// often lazy initialized upon receipt of the first present/frame
Expand All @@ -72,6 +82,7 @@ namespace pmon::ipc
bool isPlayback = false;
} bookkeeping{};
FrameHistoryRing frameData;
ProcessDataHistoryRing processData;

StaticMetricValue FindStaticMetric(PM_METRIC metric) const;

Expand Down Expand Up @@ -133,4 +144,3 @@ namespace pmon::ipc
const DataStoreSizingInfo& sizing,
PM_DEVICE_TYPE deviceType);
}

76 changes: 38 additions & 38 deletions IntelPresentMon/Interprocess/source/Interprocess.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "../../CommonUtilities/win/WinAPI.h"
#include "../../CommonUtilities/win/WinAPI.h"
#include "Interprocess.h"
#include "IntrospectionTransfer.h"
#include "IntrospectionPopulators.h"
Expand Down Expand Up @@ -161,72 +161,72 @@ namespace pmon::ipc
return namer_;
}
// data store access
std::shared_ptr<OwnedDataSegment<FrameDataStore>>
CreateOrGetFrameDataSegment(uint32_t pid, bool backpressured) override
std::shared_ptr<OwnedDataSegment<ProcessDataStore>>
CreateOrGetProcessDataSegment(uint32_t pid, bool backpressured) override
{
// resolve out existing or new weak ptr, try and lock
auto& pWeak = frameShmWeaks_[pid];
auto& pWeak = processShmWeaks_[pid];
auto pFrameData = pWeak.lock();
if (!pFrameData) {
// if weak ptr was new (or expired), lock will not work and we need to construct
// make a frame data store as shared ptr
const auto segmentName = namer_.MakeFrameName(pid);
const auto segmentName = namer_.MakeProcessName(pid);
const DataStoreSizingInfo sizing{
.ringSamples = frameRingSamples_,
.backpressured = backpressured,
};
pFrameData = std::shared_ptr<OwnedDataSegment<FrameDataStore>>(
new OwnedDataSegment<FrameDataStore>(
pFrameData = std::shared_ptr<OwnedDataSegment<ProcessDataStore>>(
new OwnedDataSegment<ProcessDataStore>(
segmentName,
sizing,
static_cast<const bip::permissions&>(Permissions_{ Permissions_::kReadOnly })),
[pid, segmentName](OwnedDataSegment<FrameDataStore>* pSegment) {
pmlog_dbg("Frame data segment destroyed")
[pid, segmentName](OwnedDataSegment<ProcessDataStore>* pSegment) {
pmlog_dbg("Process data segment destroyed")
.pmwatch(pid)
.pmwatch(segmentName);
delete pSegment;
});
// store a weak reference
pWeak = pFrameData;
pmlog_dbg("Frame data segment created")
pmlog_dbg("Process data segment created")
.pmwatch(pid)
.pmwatch(segmentName)
.pmwatch(backpressured);
}
// remove stale elements to keep map lean
for (auto it = frameShmWeaks_.begin(); it != frameShmWeaks_.end(); ) {
for (auto it = processShmWeaks_.begin(); it != processShmWeaks_.end(); ) {
if (it->second.expired()) {
const auto segmentName = namer_.MakeFrameName(it->first);
pmlog_dbg("Frame data segment released")
const auto segmentName = namer_.MakeProcessName(it->first);
pmlog_dbg("Process data segment released")
.pmwatch(it->first)
.pmwatch(segmentName);
it = frameShmWeaks_.erase(it);
it = processShmWeaks_.erase(it);
}
else {
++it;
}
}
return pFrameData;
}
std::shared_ptr<OwnedDataSegment<FrameDataStore>>
GetFrameDataSegment(uint32_t pid) override
std::shared_ptr<OwnedDataSegment<ProcessDataStore>>
GetProcessDataSegment(uint32_t pid) override
{
if (auto i = frameShmWeaks_.find(pid); i != frameShmWeaks_.end()) {
if (auto i = processShmWeaks_.find(pid); i != processShmWeaks_.end()) {
if (auto pSegment = i->second.lock()) {
return pSegment;
}
// if weak ptr has expired, garbage collect from the map
const auto segmentName = namer_.MakeFrameName(pid);
pmlog_dbg("Frame data segment released")
const auto segmentName = namer_.MakeProcessName(pid);
pmlog_dbg("Process data segment released")
.pmwatch(pid)
.pmwatch(segmentName);
frameShmWeaks_.erase(i);
processShmWeaks_.erase(i);
}
return {};
}
std::vector<uint32_t> GetFramePids() const override
std::vector<uint32_t> GetProcessDataPids() const override
{
return frameShmWeaks_ | vi::filter([](auto&& p) {return !p.second.expired(); }) |
return processShmWeaks_ | vi::filter([](auto&& p) {return !p.second.expired(); }) |
vi::keys | rn::to<std::vector>();
}
GpuDataStore& GetGpuDataStore(uint32_t deviceId) override
Expand Down Expand Up @@ -305,7 +305,7 @@ namespace pmon::ipc
bool introCpuComplete_ = false;

std::optional<OwnedDataSegment<SystemDataStore>> systemShm_;
std::unordered_map<uint32_t, std::weak_ptr<OwnedDataSegment<FrameDataStore>>> frameShmWeaks_;
std::unordered_map<uint32_t, std::weak_ptr<OwnedDataSegment<ProcessDataStore>>> processShmWeaks_;
std::unordered_map<uint32_t, OwnedDataSegment<GpuDataStore>> gpuShms_;
};

Expand Down Expand Up @@ -352,39 +352,39 @@ namespace pmon::ipc
// responsibility to track this resource
return root.ApiClone(blockAllocator);
}
void OpenFrameDataStore(uint32_t pid) override
void OpenProcessDataStore(uint32_t pid) override
{
// If already open, nothing to do
if (frameShms_.find(pid) != frameShms_.end()) {
if (processShms_.find(pid) != processShms_.end()) {
return;
}

const auto segName = namer_.MakeFrameName(pid);
frameShms_.emplace(
const auto segName = namer_.MakeProcessName(pid);
processShms_.emplace(
std::piecewise_construct,
std::forward_as_tuple(pid),
std::forward_as_tuple(segName)
);
pmlog_dbg("Frame data segment opened")
pmlog_dbg("Process data segment opened")
.pmwatch(pid)
.pmwatch(segName);
}
void CloseFrameDataStore(uint32_t pid) override
void CloseProcessDataStore(uint32_t pid) override
{
if (auto it = frameShms_.find(pid); it != frameShms_.end()) {
const auto segName = namer_.MakeFrameName(pid);
pmlog_dbg("Frame data segment closed")
if (auto it = processShms_.find(pid); it != processShms_.end()) {
const auto segName = namer_.MakeProcessName(pid);
pmlog_dbg("Process data segment closed")
.pmwatch(pid)
.pmwatch(segName);
frameShms_.erase(it);
processShms_.erase(it);
}
}
// data store access
const FrameDataStore& GetFrameDataStore(uint32_t pid) const override
const ProcessDataStore& GetProcessDataStore(uint32_t pid) const override
{
const auto it = frameShms_.find(pid);
if (it == frameShms_.end()) {
throw std::runtime_error{ "Frame data segment not open for this PID" };
const auto it = processShms_.find(pid);
if (it == processShms_.end()) {
throw std::runtime_error{ "Process data segment not open for this PID" };
}
return it->second.GetStore();
}
Expand Down Expand Up @@ -432,7 +432,7 @@ namespace pmon::ipc

std::optional<ViewedDataSegment<SystemDataStore>> systemShm_;
std::unordered_map<uint32_t, ViewedDataSegment<GpuDataStore>> gpuShms_;
std::unordered_map<uint32_t, ViewedDataSegment<FrameDataStore>> frameShms_;
std::unordered_map<uint32_t, ViewedDataSegment<ProcessDataStore>> processShms_;
};
}

Expand Down
14 changes: 7 additions & 7 deletions IntelPresentMon/Interprocess/source/Interprocess.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <optional>
#include <string>
#include <memory>
Expand Down Expand Up @@ -27,9 +27,9 @@ namespace pmon::ipc
virtual const ShmNamer& GetNamer() const = 0;

// data store access
virtual std::shared_ptr<OwnedDataSegment<FrameDataStore>> CreateOrGetFrameDataSegment(uint32_t pid, bool backpressured) = 0;
virtual std::shared_ptr<OwnedDataSegment<FrameDataStore>> GetFrameDataSegment(uint32_t pid) = 0;
virtual std::vector<uint32_t> GetFramePids() const = 0;
virtual std::shared_ptr<OwnedDataSegment<ProcessDataStore>> CreateOrGetProcessDataSegment(uint32_t pid, bool backpressured) = 0;
virtual std::shared_ptr<OwnedDataSegment<ProcessDataStore>> GetProcessDataSegment(uint32_t pid) = 0;
virtual std::vector<uint32_t> GetProcessDataPids() const = 0;
virtual GpuDataStore& GetGpuDataStore(uint32_t deviceId) = 0;
virtual SystemDataStore& GetSystemDataStore() = 0;
};
Expand All @@ -43,11 +43,11 @@ namespace pmon::ipc
// data store access
// not const because of the backpressure case
// TODO: consider more separation of backpressure and broadcast cases
virtual const FrameDataStore& GetFrameDataStore(uint32_t pid) const = 0;
virtual const ProcessDataStore& GetProcessDataStore(uint32_t pid) const = 0;
virtual const GpuDataStore& GetGpuDataStore(uint32_t deviceId) const = 0;
virtual const SystemDataStore& GetSystemDataStore() const = 0;
virtual void OpenFrameDataStore(uint32_t pid) = 0;
virtual void CloseFrameDataStore(uint32_t pid) = 0;
virtual void OpenProcessDataStore(uint32_t pid) = 0;
virtual void CloseProcessDataStore(uint32_t pid) = 0;
};

std::unique_ptr<ServiceComms> MakeServiceComms(std::string prefix,
Expand Down
6 changes: 3 additions & 3 deletions IntelPresentMon/Interprocess/source/OwnedDataSegment.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "SharedMemoryTypes.h"
#include "DataStores.h"
#include "../../CommonUtilities/log/Log.h"
Expand All @@ -21,8 +21,8 @@ namespace pmon::ipc
nullptr, perms },
pData_{ MakeStore_(sizing) }
{
if constexpr (std::is_same_v<T, FrameDataStore>) {
pmlog_dbg("Shm segment populated (Frame)")
if constexpr (std::is_same_v<T, ProcessDataStore>) {
pmlog_dbg("Shm segment populated (Process)")
.pmwatch(segmentName)
.pmwatch(GetBytesTotal())
.pmwatch(GetBytesUsed())
Expand Down
3 changes: 1 addition & 2 deletions IntelPresentMon/Interprocess/source/ShmNamer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#pragma once
#include "ShmNamer.h"
#include <format>
#include <random>
Expand Down Expand Up @@ -26,7 +25,7 @@ namespace pmon::ipc
{
return std::format("{}_{}_gpu_{}", prefix_, salt_, deviceId);
}
std::string ShmNamer::MakeFrameName(uint32_t pid) const
std::string ShmNamer::MakeProcessName(uint32_t pid) const
{
return std::format("{}_{}_tgt_{}", prefix_, salt_, pid);
}
Expand Down
4 changes: 2 additions & 2 deletions IntelPresentMon/Interprocess/source/ShmNamer.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <string>
#include <optional>

Expand All @@ -14,7 +14,7 @@ namespace pmon::ipc
std::string MakeIntrospectionReadyName() const;
std::string MakeSystemName() const;
std::string MakeGpuName(uint32_t deviceId) const;
std::string MakeFrameName(uint32_t pid) const;
std::string MakeProcessName(uint32_t pid) const;
const std::string& GetSalt() const;
const std::string& GetPrefix() const;
private:
Expand Down
2 changes: 1 addition & 1 deletion IntelPresentMon/Interprocess/source/metadata/EnumUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
X_(UNIT, KILOHERTZ, "Kilohertz", "kHz", "Frequency in thousands of cycles per second") \
X_(UNIT, MEGAHERTZ, "Megahertz", "MHz", "Frequency in millions of cycles per second") \
X_(UNIT, GIGAHERTZ, "Gigahertz", "GHz", "Frequency in billions of cycles per second") \
X_(UNIT, CELSIUS, "Degrees Celsius", (const char*)u8"�C", "Temperature in degrees Celsius") \
X_(UNIT, CELSIUS, "Degrees Celsius", (const char*)u8"�C", "Temperature in degrees Celsius") \
X_(UNIT, RPM, "Revolutions per Minute", "RPM", "Angular speed in revolutions per minute") \
X_(UNIT, BITS_PER_SECOND, "Bits per Second", "bps", "Bandwidth / data throughput in bits per second") \
X_(UNIT, KILOBITS_PER_SECOND, "Kilobits per Second", "kbps", "Bandwidth / data throughput in kilobits per second") \
Expand Down
3 changes: 3 additions & 0 deletions IntelPresentMon/Interprocess/source/metadata/MetricList.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,7 @@
X_(PM_METRIC_BETWEEN_APP_START, PM_METRIC_TYPE_FRAME_EVENT, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_VOID, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
X_(PM_METRIC_FLIP_DELAY, PM_METRIC_TYPE_FRAME_EVENT, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_VOID, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
X_(PM_METRIC_SESSION_START_QPC, PM_METRIC_TYPE_STATIC, PM_UNIT_QPC, PM_DATA_TYPE_UINT64, PM_DATA_TYPE_UINT64, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NONE) \
X_(PM_METRIC_D3D12_PSO_COMPILE_COUNT, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_HERTZ, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_AVG) \
X_(PM_METRIC_D3D12_PSO_COMPILE_TIME, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_AVG) \
X_(PM_METRIC_D3D12_PSO_COMPILE_BUSY_PERCENT, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_PERCENT, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_AVG) \
X_(PM_METRIC_COUNT_, PM_METRIC_TYPE_STATIC, PM_UNIT_DIMENSIONLESS, PM_DATA_TYPE_VOID, PM_DATA_TYPE_VOID, PM_ENUM_NULL_ENUM, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NONE)
3 changes: 3 additions & 0 deletions IntelPresentMon/PresentMonAPI2/PresentMonAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ extern "C" {
PM_METRIC_PROCESS_ID,
PM_METRIC_SESSION_START_QPC,
PM_METRIC_CPU_CORE_TEMPERATURE,
PM_METRIC_D3D12_PSO_COMPILE_COUNT,
PM_METRIC_D3D12_PSO_COMPILE_TIME,
PM_METRIC_D3D12_PSO_COMPILE_BUSY_PERCENT,
PM_METRIC_COUNT_, // sentry to mark end of metric list; not an actual query metric
};

Expand Down
4 changes: 2 additions & 2 deletions IntelPresentMon/PresentMonAPI2Tests/EtlLoggerTests.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2022-2023 Intel Corporation
// Copyright (C) 2022-2023 Intel Corporation
// SPDX-License-Identifier: MIT
#include "../CommonUtilities/win/WinAPI.h"
#include "CppUnitTest.h"
Expand Down Expand Up @@ -53,7 +53,7 @@ namespace EtlLoggerTests
// verify initial status
const auto status = fixture_.service->QueryStatus();
Assert::AreEqual(0ull, status.trackedPids.size());
Assert::AreEqual(0ull, status.frameStorePids.size());
Assert::AreEqual(0ull, status.processStorePids.size());
Assert::AreEqual(16u, status.telemetryPeriodMs);
Assert::IsFalse((bool)status.etwFlushPeriodMs);
}
Expand Down
Loading