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
12 changes: 8 additions & 4 deletions IntelPresentMon/CommonUtilities/log/CopyDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

namespace pmon::util::log
{
CopyDriver::CopyDriver(std::shared_ptr<IChannel> pChannel)
CopyDriver::CopyDriver(IChannel* pChannel) noexcept
:
pChannel_{ std::move(pChannel) }
pChannel_{ pChannel }
{}
void CopyDriver::Submit(const Entry& e)
{
pChannel_->Submit(e);
if (pChannel_) {
pChannel_->Submit(e);
}
}
void CopyDriver::Flush()
{
pChannel_->Flush();
if (pChannel_) {
pChannel_->Flush();
}
}
}
4 changes: 2 additions & 2 deletions IntelPresentMon/CommonUtilities/log/CopyDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ namespace pmon::util::log
class CopyDriver : public IDriver
{
public:
CopyDriver(std::shared_ptr<IChannel> pChannel);
explicit CopyDriver(IChannel* pChannel) noexcept;
void Submit(const Entry&) override;
void Flush() override;
private:
std::shared_ptr<IChannel> pChannel_;
IChannel* pChannel_;
};
}
3 changes: 1 addition & 2 deletions IntelPresentMon/Core/source/infra/LogSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ namespace p2c
// connect dll channel and id table to exe, get access to global settings in dll
LoggingSingletons getters;
if (linkMiddlewareLogs) {
getters = pmLinkLogging_(pChan, []() -> IdentificationTable& {
return IdentificationTable::Get_(); });
getters = pmLinkLoggingPtrs_(pChan.get(), IdentificationTable::GetPtr());
}
// set the global policy settings
if (opt.logLevel) {
Expand Down
17 changes: 11 additions & 6 deletions IntelPresentMon/PresentMonAPI2/Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,22 @@ PRESENTMON_API2_EXPORT _CrtMemState pmCreateHeapCheckpoint_();
// log configuration support functions
struct LoggingSingletons
{
std::function<pmon::util::log::GlobalPolicy& ()> getGlobalPolicy;
std::function<pmon::util::log::LineTable& ()> getLineTable;
using GlobalPolicyRefFn = pmon::util::log::GlobalPolicy & (*)();
using LineTableRefFn = pmon::util::log::LineTable & (*)();
GlobalPolicyRefFn getGlobalPolicy = nullptr;
LineTableRefFn getLineTable = nullptr;
operator bool() const noexcept
{
return getGlobalPolicy || getLineTable;
}
Comment thread
planetchili marked this conversation as resolved.
};
// function to connect (subordinate) the dll logging system to the exe one
// replace default channel (nullptr) with a channel that copies entries to pChannel
// optionally hook up an id table to copy entries to as well
// return getters for config singletons in the dll to config from the exe
// Connect (subordinate) the dll logging system to the host module.
// Prefer pmLinkLoggingPtrs_ for all in-repo callers: do not pass shared_ptr or
// std::function across module boundaries (/MT heap). pmLinkLogging_ remains exported
// for older loader/middleware ABI (v2.5.1 mangled name); avoid new call sites.
PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLoggingPtrs_(
pmon::util::log::IChannel* pChannel,
pmon::util::log::IdentificationTable* pExeTable);
PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLogging_(
std::shared_ptr<pmon::util::log::IChannel> pChannel,
std::function<pmon::util::log::IdentificationTable&()> getIdTable);
Expand Down
106 changes: 65 additions & 41 deletions IntelPresentMon/PresentMonAPI2/PresentMonAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,63 +100,87 @@ PRESENTMON_API2_EXPORT _CrtMemState pmCreateHeapCheckpoint_()
return s;
}

PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLogging_(
std::shared_ptr<pmon::util::log::IChannel> pChannel,
std::function<pmon::util::log::IdentificationTable&()> getIdTable)
namespace
{
using namespace util::log;
// set api dll default logging channel to copy to exe logging channel
SetupCopyChannel(std::move(pChannel));
// connecting id tables (dll => exe)
if (pLinkedIdTableSink_) {
IdentificationTable::UnregisterSink(pLinkedIdTableSink_.get());
pLinkedIdTableSink_.reset();
pmon::util::log::GlobalPolicy& GetMiddlewareGlobalPolicy_()
{
return pmon::util::log::GlobalPolicy::Get();
}

pmon::util::log::LineTable& GetMiddlewareLineTable_()
{
return pmon::util::log::LineTable::Get_();
}
if (getIdTable) {
class Sink : public IIdentificationSink
{
public:
Sink(std::function<IdentificationTable& ()> getTable)
:
getTable_{ std::move(getTable) }
{}
void AddThread(uint32_t tid, uint32_t pid, std::string name) override

LoggingSingletons LinkLogging_(pmon::util::log::IChannel* pChannel,
pmon::util::log::IdentificationTable* pExeTable)
{
using namespace pmon::util::log;
SetupCopyChannel(pChannel);
if (pLinkedIdTableSink_) {
IdentificationTable::UnregisterSink(pLinkedIdTableSink_.get());
pLinkedIdTableSink_.reset();
}
if (pExeTable) {
class Sink : public IIdentificationSink
{
getTable_().AddThread_(tid, pid, name);
public:
explicit Sink(IdentificationTable* pTable) noexcept
:
pTable_{ pTable }
{}
void AddThread(uint32_t tid, uint32_t pid, std::string name) override
{
pTable_->AddThread_(tid, pid, name);
}
void AddProcess(uint32_t pid, std::string name) override
{
pTable_->AddProcess_(pid, name);
}
private:
IdentificationTable* pTable_;
};
pLinkedIdTableSink_ = std::make_shared<Sink>(pExeTable);
IdentificationTable::RegisterSink(pLinkedIdTableSink_);
const auto bulk = IdentificationTable::GetBulk();
for (auto& t : bulk.threads) {
pLinkedIdTableSink_->AddThread(t.tid, t.pid, t.name);
}
void AddProcess(uint32_t pid, std::string name) override
{
getTable_().AddProcess_(pid, name);
for (auto& p : bulk.processes) {
pLinkedIdTableSink_->AddProcess(p.pid, p.name);
}
private:
std::function<IdentificationTable& ()> getTable_;
};
pLinkedIdTableSink_ = std::make_shared<Sink>(getIdTable);
IdentificationTable::RegisterSink(pLinkedIdTableSink_);
const auto bulk = IdentificationTable::GetBulk();
for (auto& t : bulk.threads) {
pLinkedIdTableSink_->AddThread(t.tid, t.pid, t.name);
}
for (auto& p : bulk.processes) {
pLinkedIdTableSink_->AddProcess(p.pid, p.name);
}
return {
.getGlobalPolicy = &GetMiddlewareGlobalPolicy_,
.getLineTable = &GetMiddlewareLineTable_,
};
}
// return functions to access the global settings objects
return {
.getGlobalPolicy = []() -> GlobalPolicy& { return GlobalPolicy::Get(); },
.getLineTable = []() -> LineTable& { return LineTable::Get_(); },
};
}

PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLoggingPtrs_(
pmon::util::log::IChannel* pChannel,
pmon::util::log::IdentificationTable* pExeTable)
{
return LinkLogging_(pChannel, pExeTable);
}

PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLogging_(
std::shared_ptr<pmon::util::log::IChannel> pChannel,
std::function<pmon::util::log::IdentificationTable&()> getIdTable)
{
pmon::util::log::IdentificationTable* pExeTable = getIdTable ? &getIdTable() : nullptr;
return LinkLogging_(pChannel.get(), pExeTable);
}

PRESENTMON_API2_EXPORT void pmUnlinkLogging_() noexcept
{
using namespace util::log;
pmquell(FlushEntryPoint())
pmquell(InjectDefaultChannel({}))
if (pLinkedIdTableSink_) {
pmquell(IdentificationTable::UnregisterSink(pLinkedIdTableSink_.get()))
pLinkedIdTableSink_.reset();
}
pmquell(FlushEntryPoint())
pmquell(SeverCopyLoggingBridge())
}

PRESENTMON_API2_EXPORT void pmFlushEntryPoint_() noexcept
Expand Down
21 changes: 21 additions & 0 deletions IntelPresentMon/PresentMonAPI2Loader/Implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ PM_STATUS(*pFunc_pmDiagnosticUnblockWaitingThread_)() = nullptr;
_CrtMemState(*pFunc_pmCreateHeapCheckpoint__)() = nullptr;
LoggingSingletons(*pFunc_pmLinkLogging__)(std::shared_ptr<pmon::util::log::IChannel>,
std::function<pmon::util::log::IdentificationTable&()>) = nullptr;
LoggingSingletons(*pFunc_pmLinkLoggingPtrs__)(pmon::util::log::IChannel*,
pmon::util::log::IdentificationTable*) = nullptr;
void(*pFunc_pmUnlinkLogging__)() = nullptr;
void(*pFunc_pmFlushEntryPoint__)() = nullptr;
void(*pFunc_pmSetupODSLogging__)(PM_DIAGNOSTIC_LEVEL, PM_DIAGNOSTIC_LEVEL, bool) = nullptr;
Expand Down Expand Up @@ -198,6 +200,7 @@ PRESENTMON_API2_EXPORT PM_STATUS LoadLibrary_(bool versionOnly = false)
// internal (optional: older middleware may omit refactored hooks)
RESOLVE_CPP_OPTIONAL(pmCreateHeapCheckpoint_);
RESOLVE_CPP_OPTIONAL(pmLinkLogging_);
RESOLVE_CPP_OPTIONAL(pmLinkLoggingPtrs_);
RESOLVE_CPP_OPTIONAL(pmUnlinkLogging_);
RESOLVE_CPP_OPTIONAL(pmFlushEntryPoint_);
RESOLVE_CPP_OPTIONAL(pmSetupODSLogging_);
Expand Down Expand Up @@ -359,11 +362,29 @@ PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLogging_(std::shared_ptr<pmon::ut
throw LoaderExcept_(status);
}
}
if (pFunc_pmLinkLoggingPtrs__) {
pmon::util::log::IChannel* pChan = pChannel.get();
pmon::util::log::IdentificationTable* pExeTable = getIdTable ? &getIdTable() : nullptr;
return pFunc_pmLinkLoggingPtrs__(pChan, pExeTable);
}
if (!pFunc_pmLinkLogging__) {
return {};
}
return pFunc_pmLinkLogging__(pChannel, std::move(getIdTable));
}
PRESENTMON_API2_EXPORT LoggingSingletons pmLinkLoggingPtrs_(pmon::util::log::IChannel* pChannel,
pmon::util::log::IdentificationTable* pExeTable)
{
if (!middlewareLoadedSuccessfully_) {
if (auto status = LoadLibrary_(); status != PM_STATUS_SUCCESS) {
throw LoaderExcept_(status);
}
}
if (!pFunc_pmLinkLoggingPtrs__) {
return {};
}
return pFunc_pmLinkLoggingPtrs__(pChannel, pExeTable);
}
PRESENTMON_API2_EXPORT void pmUnlinkLogging_() noexcept
{
if (middlewareLoadedSuccessfully_ && pFunc_pmUnlinkLogging__) {
Expand Down
37 changes: 29 additions & 8 deletions IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "../CommonUtilities/win/WinAPI.h"
#include <fstream>
#include "CppUnitTest.h"
#include "FirstFrameWait.h"
#include "Folders.h"
#include "StatusComparison.h"
#include "TestProcess.h"
Expand Down Expand Up @@ -205,11 +204,18 @@ namespace EtlTests

processTracker = pSession->TrackProcess(processId, true, true);

if (!pmon::tests::TryWaitForFirstFrame(
controlPipe_,
processId,
"etl-playback",
std::chrono::seconds(waitTimeSecs))) {
const auto firstFrameDeadline = std::chrono::steady_clock::now() + std::chrono::seconds(waitTimeSecs);
bool gotFirstFrame = false;
while (std::chrono::steady_clock::now() < firstFrameDeadline) {
frameQuery.Consume(processTracker, blobs);
if (blobs.GetNumBlobsPopulated() > 0) {
gotFirstFrame = true;
goldCsvFile.VerifyBlobAgainstCsv(processName, processId, queryElements, blobs, outputCsvFile);
break;
}
std::this_thread::sleep_for(8ms);
}
if (!gotFirstFrame) {
throw CsvException("Timeout waiting to consume first frame");
}

Expand All @@ -228,6 +234,23 @@ namespace EtlTests
goldCsvFile.VerifyBlobAgainstCsv(processName, processId, queryElements, blobs, outputCsvFile);
}
}
// Drain the backpressured playback ring so the service output thread cannot
// block indefinitely during session teardown.
int drainEmptyPollCount = 0;
while (drainEmptyPollCount < pollCount) {
frameQuery.Consume(processTracker, blobs);
if (blobs.GetNumBlobsPopulated() == 0) {
if (++drainEmptyPollCount >= pollCount) {
break;
}
std::this_thread::sleep_for(8ms);
}
else {
drainEmptyPollCount = 0;
goldCsvFile.VerifyBlobAgainstCsv(processName, processId, queryElements, blobs, outputCsvFile);
}
}
processTracker.FlushFrames();
}

TEST_CLASS(GoldEtlCsvTests)
Expand Down Expand Up @@ -278,8 +301,6 @@ namespace EtlTests
});

try {
pmLoaderSetPathToMiddlewareDll_("./PresentMonAPI2.dll");
pmSetupODSLogging_(PM_DIAGNOSTIC_LEVEL_DEBUG, PM_DIAGNOSTIC_LEVEL_ERROR, false);
outSession = std::make_unique<pmapi::Session>(controlPipe_);
return true;
}
Expand Down
10 changes: 6 additions & 4 deletions IntelPresentMon/PresentMonAPI2Tests/InterimBroadcasterTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1397,8 +1397,8 @@ namespace InterimBroadcasterTests
// setup query
PM_BEGIN_FIXED_FRAME_QUERY(FQ)
pmapi::FixedQueryElement timestamp{ this, PM_METRIC_CPU_START_QPC };
pmapi::FixedQueryElement timeInPres{ this, PM_METRIC_IN_PRESENT_API };
PM_END_FIXED_QUERY query{ session, 1'000 };
pmapi::FixedQueryElement timeInPres{ this, PM_METRIC_IN_PRESENT_API };
PM_END_FIXED_QUERY query{ session, 350 };

struct Row { uint64_t timestamp; double timeInPresent; };
std::vector<Row> frames;
Expand All @@ -1418,15 +1418,17 @@ namespace InterimBroadcasterTests
};

// verify that backpressure works correctly to ensure no frames are lost
std::this_thread::sleep_for(machine::ScaleWait(400ms));

const auto count1 = consume();
Logger::WriteMessage(std::format("count [{}]\n", count1).c_str());

std::this_thread::sleep_for(machine::ScaleWait(300ms));
std::this_thread::sleep_for(machine::ScaleWait(400ms));

const auto count2 = consume();
Logger::WriteMessage(std::format("count [{}]\n", count2).c_str());

std::this_thread::sleep_for(machine::ScaleWait(500ms));
std::this_thread::sleep_for(machine::ScaleWait(150ms));

const auto count3 = consume();
Logger::WriteMessage(std::format("count [{}]\n", count3).c_str());
Expand Down
Loading