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
14 changes: 12 additions & 2 deletions IntelPresentMon/AppCef/ipm-ui-vue/src/core/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function makeDefaultPreferences(): Preferences {
telemetrySamplingPeriodMs: 100,
etwFlushPeriod: 8,
manualEtwFlush: true,
metricsOffset: 80,
metricsOffset: 150,
metricsWindow: 1000,
overlayPosition: 0,
timeRange: 10,
Expand Down Expand Up @@ -140,7 +140,7 @@ export function makeDefaultPreferences(): Preferences {

export const signature: Signature = {
code: "p2c-cap-pref",
version: "0.20.0",
version: "0.21.0",
};

export interface PreferenceFile {
Expand Down Expand Up @@ -207,6 +207,16 @@ const migrations: Migration[] = [
}
}
},
{
version: '0.21.0',
migrate: (prefs: Preferences) => {
if (prefs.metricsOffset === 80) {
const def = makeDefaultPreferences();
console.info(`Migrating preferences to 0.21.0 (metricsOffset: ${prefs.metricsOffset} => ${def.metricsOffset})`);
prefs.metricsOffset = def.metricsOffset;
}
}
},
];

migrations.sort((a, b) => compareVersions(a.version, b.version));
Expand Down
52 changes: 47 additions & 5 deletions IntelPresentMon/CommonUtilities/IntervalWaiter.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
#include "IntervalWaiter.h"
#include "win/WinAPI.h"
#include <cmath>
#include <thread>

namespace pmon::util
{
IntervalWaiter::IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, double waitBuffer)
IntervalWaiter::IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, Options options)
:
intervalSeconds_{ intervalSeconds },
waiter_{ waitBuffer },
options_{ options },
waiter_{ options.spinBufferSeconds },
timer_{ syncTimestamp }
{}

IntervalWaiter::IntervalWaiter(double intervalSeconds, double waitBuffer)
IntervalWaiter::IntervalWaiter(double intervalSeconds, Options options)
:
intervalSeconds_{ intervalSeconds },
waiter_{ waitBuffer }
options_{ options },
waiter_{ options.spinBufferSeconds }
{}

IntervalWaiter::IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, double waitBuffer)
:
IntervalWaiter{ intervalSeconds, syncTimestamp, Options{
.mechanism = WaitMechanism::HighPrecisionTimer,
.spinBufferSeconds = waitBuffer,
} }
{}

IntervalWaiter::IntervalWaiter(double intervalSeconds, double waitBuffer)
:
IntervalWaiter{ intervalSeconds, Options{
.mechanism = WaitMechanism::HighPrecisionTimer,
.spinBufferSeconds = waitBuffer,
} }
{}

void IntervalWaiter::SetInterval(double intervalSeconds)
Expand All @@ -26,6 +46,16 @@ namespace pmon::util
intervalSeconds_ = double(interval.count()) / 1'000'000'000.;
}

void IntervalWaiter::SetOptions(Options options)
{
options_ = options;
}

IntervalWaiter::Options IntervalWaiter::GetOptions() const
{
return options_;
}

IntervalWaiter::WaitResult IntervalWaiter::Wait()
{
WaitResult res{};
Expand All @@ -43,7 +73,7 @@ namespace pmon::util
return 0.;
}();
if (waitTimeSeconds > 0.) {
res.errorSec = waiter_.Wait(waitTimeSeconds);
res.errorSec = WaitFor(waitTimeSeconds);
}
return res;
}
Expand All @@ -52,4 +82,16 @@ namespace pmon::util
{
return timer_.TimeToTimestamp(targetTime);
}

double IntervalWaiter::WaitFor(double seconds)
{
switch (options_.mechanism) {
case WaitMechanism::HighPrecisionTimer:
return waiter_.WaitWithBuffer(seconds, options_.spinBufferSeconds);
case WaitMechanism::Sleep:
default:
Sleep((DWORD)std::ceil(seconds * 1000.));
return 0.;
}
}
}
21 changes: 19 additions & 2 deletions IntelPresentMon/CommonUtilities/IntervalWaiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

namespace pmon::util
{
enum class WaitMechanism
{
Sleep,
HighPrecisionTimer,
};

class IntervalWaiter
{
public:
Expand All @@ -16,21 +22,32 @@ namespace pmon::util
double targetSec;
double errorSec;
};
struct Options
{
WaitMechanism mechanism = WaitMechanism::Sleep;
double spinBufferSeconds = 0.;
};
// functions
IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, double waitBuffer = PrecisionWaiter::standardWaitBuffer);
IntervalWaiter(double intervalSeconds, double waitBuffer = PrecisionWaiter::standardWaitBuffer);
IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, Options options = {});
IntervalWaiter(double intervalSeconds, Options options = {});
IntervalWaiter(double intervalSeconds, int64_t syncTimestamp, double waitBuffer);
IntervalWaiter(double intervalSeconds, double waitBuffer);
IntervalWaiter(const IntervalWaiter&) = delete;
IntervalWaiter & operator=(const IntervalWaiter&) = delete;
IntervalWaiter(IntervalWaiter&&) = delete;
IntervalWaiter & operator=(IntervalWaiter&&) = delete;
~IntervalWaiter() = default;
void SetInterval(double intervalSeconds);
void SetInterval(std::chrono::nanoseconds interval);
void SetOptions(Options options);
Options GetOptions() const;
WaitResult Wait();
int64_t TargetTimeToTimestamp(double targetTime) const;
private:
double WaitFor(double seconds);
double intervalSeconds_;
double lastTargetTime_ = 0.;
Options options_;
PrecisionWaiter waiter_;
QpcTimer timer_;
};
Expand Down
6 changes: 5 additions & 1 deletion IntelPresentMon/CommonUtilities/PrecisionWaiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "win/WinAPI.h"
#include "Exception.h"
#include "PrecisionWaiter.h"
#include <algorithm>


namespace pmon::util
Expand Down Expand Up @@ -38,10 +39,13 @@ namespace pmon::util
// mark the start time of the wait if we're doing buffer with precision spin
if (buffer > 0.) {
qpcTimer_.Mark();
if (seconds <= buffer) {
return qpcTimer_.SpinWaitUntil(seconds);
}
}
// wait slightly (buffer seconds) shorter than required to compensate for overwait error
const LARGE_INTEGER waitTime100ns{
.QuadPart = -LONGLONG(double(seconds - defaultWaitBuffer_) * 10'000'000.)
.QuadPart = -LONGLONG(std::max(seconds - buffer, 0.) * 10'000'000.)
};
// set the timer deadline
if (!SetWaitableTimerEx(
Expand Down
10 changes: 6 additions & 4 deletions IntelPresentMon/Core/source/kernel/MetricPackMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "DataFetchPack.h"
#include "../pmon/MetricFetcherFactory.h"
#include "../pmon/DynamicQuery.h"
#include "../pmon/Timekeeper.h"
#include "../infra/Logging.h"
#include "OverlaySpec.h"
#include <CommonUtilities\Hash.h>
Expand Down Expand Up @@ -100,13 +101,14 @@ namespace p2c::kern
}
usageMap_[qmet].text = true;
}
void Populate(const pmapi::ProcessTracker& tracker, double timestamp)
void Populate(const pmapi::ProcessTracker& tracker, uint64_t timestamp)
{
// if query is empty, don't do anything (empty loadout)
if (pQuery_) {
pQuery_->Poll(tracker);
pQuery_->PollWithTimestamp(tracker, timestamp);
const auto time = pmon::Timekeeper::RelativeToEpoch((int64_t)timestamp);
for (auto&& [qmet, pPack] : metricPackMap_) {
pPack.Populate(timestamp);
pPack.Populate(time);
}
}
}
Expand All @@ -129,4 +131,4 @@ namespace p2c::kern
// i.e. which ones can carry over, differentiates between graph and readout
std::unordered_map<QualifiedMetric, MetricUsage_> usageMap_;
};
}
}
7 changes: 4 additions & 3 deletions IntelPresentMon/Core/source/kernel/Overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ namespace p2c::kern
}
}

void Overlay::UpdateGraphData_(double timestamp)
void Overlay::UpdateGraphData_(uint64_t timestamp)
{
if (!IsTargetLive()) {
pmlog_dbg("Target found dead")
Expand Down Expand Up @@ -429,12 +429,13 @@ namespace p2c::kern
{
const auto wait = scheduler_.GetNextWait();
samplingWaiter.SetInterval(wait);
samplingWaiter.Wait();
const auto waitResult = samplingWaiter.Wait();
const auto targetTimestamp = samplingWaiter.TargetTimeToTimestamp(waitResult.targetSec);
Comment on lines +432 to +433
pmon::Timekeeper::LockNow();

if (scheduler_.AtPoll() && !IsHidden_()) {
pmlog_mark mkPoll;
UpdateGraphData_(pmon::Timekeeper::GetLockedNow());
UpdateGraphData_((uint64_t)targetTimestamp);
pmlog_perf(clog::p::overlay)("Data update time").mark(mkPoll);
}
if (scheduler_.AtRender()) {
Expand Down
2 changes: 1 addition & 1 deletion IntelPresentMon/Core/source/kernel/Overlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace p2c::kern
private:
// functions
void AdjustOverlaySituation_(OverlaySpec::OverlayPosition position);
void UpdateGraphData_(double timestamp);
void UpdateGraphData_(uint64_t timestamp);
void Render_();
void UpdateCaptureStatusText_();
void UpdateDataSets_();
Expand Down
12 changes: 11 additions & 1 deletion IntelPresentMon/Core/source/pmon/DynamicQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,21 @@ namespace p2c::pmon
}
}

void DynamicQuery::PollWithTimestamp(const pmapi::ProcessTracker& tracker, uint64_t nowTimestamp)
{
if (query) {
query.PollWithTimestamp(tracker, blobs, nowTimestamp);
}
else {
pmlog_warn("Polling empty dynamic query");
}
}

const uint8_t* DynamicQuery::GetBlobData() const
{
if (blobs.GetNumBlobsPopulated() == 0) {
return nullptr;
}
return blobs.GetFirst();
}
}
}
3 changes: 2 additions & 1 deletion IntelPresentMon/Core/source/pmon/DynamicQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ namespace p2c::pmon
public:
DynamicQuery(pmapi::Session& session, double winSizeMs, double metricOffsetMs, std::span<const kern::QualifiedMetric> qmet);
void Poll(const pmapi::ProcessTracker& tracker);
void PollWithTimestamp(const pmapi::ProcessTracker& tracker, uint64_t nowTimestamp);
const uint8_t* GetBlobData() const;
std::vector<PM_QUERY_ELEMENT> ExtractElements();
private:
pmapi::DynamicQuery query;
std::vector<PM_QUERY_ELEMENT> elements;
pmapi::BlobContainer blobs;
};
}
}
3 changes: 2 additions & 1 deletion IntelPresentMon/PresentMonAPI2/PresentMonAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,12 @@ extern "C" {
PRESENTMON_API2_EXPORT PM_STATUS pmFreeIntrospectionRoot(const PM_INTROSPECTION_ROOT* pRoot);
// sets the rate at which hardware telemetry (including CPU) is polled
PRESENTMON_API2_EXPORT PM_STATUS pmSetTelemetryPollingPeriod(PM_SESSION_HANDLE handle, uint32_t reserved, uint32_t timeMs);
#define PM_TELEMETRY_PERIOD_MIN 4
#define PM_TELEMETRY_PERIOD_MIN 50
#define PM_TELEMETRY_PERIOD_MAX 5000
// sets the rate at which ETW event buffers are flushed, affecting the delay of frame data reported by PresentMon
// a value of zero indicates to use current service setting (default or value requested by other client)
PRESENTMON_API2_EXPORT PM_STATUS pmSetEtwFlushPeriod(PM_SESSION_HANDLE handle, uint32_t periodMs);
#define PM_ETW_FLUSH_PERIOD_MIN 8
#define PM_ETW_FLUSH_PERIOD_MAX 1000
// flush any buffered frame event data for the specified process on this session
PRESENTMON_API2_EXPORT PM_STATUS pmFlushFrames(PM_SESSION_HANDLE handle, uint32_t processId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ namespace InterimBroadcasterTests
auto pMetricMap = pmapi::EnumMap::GetKeyMap(PM_ENUM_METRIC);

// set telemetry period so we have a known baseline
client.DispatchSync(svc::acts::SetTelemetryPeriod::Params{ .telemetrySamplePeriodMs = 40 });
client.DispatchSync(svc::acts::SetTelemetryPeriod::Params{ .telemetrySamplePeriodMs = 50 });

// get the store containing adapter telemetry
auto& sys = pComms->GetSystemDataStore();
Expand Down Expand Up @@ -625,7 +625,7 @@ namespace InterimBroadcasterTests
auto pMetricMap = pmapi::EnumMap::GetKeyMap(PM_ENUM_METRIC);

// set telemetry period so we have a known baseline
client.DispatchSync(svc::acts::SetTelemetryPeriod::Params{ .telemetrySamplePeriodMs = 40 });
client.DispatchSync(svc::acts::SetTelemetryPeriod::Params{ .telemetrySamplePeriodMs = 50 });

// target gpu device 1 (hardcoded for test)
const uint32_t TargetDeviceID = 1;
Expand Down
Loading