diff --git a/IntelPresentMon/AppCef/Web/src/App.vue b/IntelPresentMon/AppCef/Web/src/App.vue index 35e460b78..03681316c 100644 --- a/IntelPresentMon/AppCef/Web/src/App.vue +++ b/IntelPresentMon/AppCef/Web/src/App.vue @@ -225,18 +225,20 @@ export default Vue.extend({ widget.metrics = widget.metrics.filter(widgetMetric => { const metric = Introspection.metrics.find(m => m.id === widgetMetric.metric.metricId); if (metric === undefined || metric.availableDeviceIds.length === 0) { - // If the metric is undefined, this widgetMetric will be removed, so return false + // If the metric is undefined, this widgetMetric will be dropped return false; } // If the metric is found, set up the deviceId and desiredUnitId as needed widgetMetric.metric.deviceId = 0; // establish universal device id // Check whether metric is a gpu metric, then we need non-universal device id if (!metric.availableDeviceIds.includes(0)) { - // Set device to selected adapter, falling back to first available device if necessary - if (this.pref.adapterId !== null && metric.availableDeviceIds.includes(this.pref.adapterId)) { - widgetMetric.metric.deviceId = this.pref.adapterId; - } else { - widgetMetric.metric.deviceId = metric.availableDeviceIds[0]; + // if no specific adapter id set, assume adapter id = 1 is active + const adapterId = this.pref.adapterId !== null ? this.pref.adapterId : 1; + // Set adapter id for this query element to the active one if available + if (metric.availableDeviceIds.includes(adapterId)) { + widgetMetric.metric.deviceId = adapterId; + } else { // if active adapter id is not available drop this widgetMetric + return false; } } // Fill out the unit diff --git a/IntelPresentMon/AppCef/source/NanoCefBrowserClient.cpp b/IntelPresentMon/AppCef/source/NanoCefBrowserClient.cpp index 8946669f5..bc08c9f28 100644 --- a/IntelPresentMon/AppCef/source/NanoCefBrowserClient.cpp +++ b/IntelPresentMon/AppCef/source/NanoCefBrowserClient.cpp @@ -122,7 +122,7 @@ namespace p2c::client::cef return pContextMenuHandler; } -#define xjs_pmlog_(lvl) ((PMLOG_BUILD_LEVEL < lvl) || (::pmon::util::log::GlobalPolicy::Get().GetLogLevel() < lvl)) \ +#define xjs_pmlog_(lvl) ((PMLOG_BUILD_LEVEL_ < lvl) || (::pmon::util::log::GlobalPolicy::Get().GetLogLevel() < lvl)) \ ? (void)0 : (void)::pmon::util::log::EntryBuilder{ lvl, source.ToString(), {}, line } \ .to(::pmon::util::log::GetDefaultChannel()).no_trace().note(message.ToString()) diff --git a/IntelPresentMon/AppCef/source/util/AsyncEndpointManager.cpp b/IntelPresentMon/AppCef/source/util/AsyncEndpointManager.cpp index 5a4488c13..216787a3d 100644 --- a/IntelPresentMon/AppCef/source/util/AsyncEndpointManager.cpp +++ b/IntelPresentMon/AppCef/source/util/AsyncEndpointManager.cpp @@ -31,6 +31,14 @@ namespace p2c::client::util ); lck.unlock(); + if constexpr (v::v8async) { + pmlog_verb(v::v8async)(std::format("Async call {{{}}} from V8 to endpoint [{}] with payload:\n{}", + uid, key, Traverse(V8ToCefValue(*pObj)).Dump())); + } + else { + pmlog_dbg(std::format("Async call {{{}}} from V8 to endpoint [{}]", uid, key)); + } + switch (pEndpoint->GetEnvironment()) { case AsyncEndpoint::Environment::BrowserProcess: @@ -86,6 +94,15 @@ namespace p2c::client::util if (auto i = invocations.find(uid); i != std::end(invocations)) { auto invocation = std::move(i->second); + + if constexpr (v::v8async) { + pmlog_verb(v::v8async)(std::format("Async call {{{}}} resolved with payload:\n{}", + uid, Traverse(pArgs).Dump())); + } + else { + pmlog_verb(v::v8async)(std::format("Async call {{{}}} resolved", uid)); + } + invocations.erase(i); lck.unlock(); diff --git a/IntelPresentMon/AppCef/source/util/CefValues.cpp b/IntelPresentMon/AppCef/source/util/CefValues.cpp index 8be4b2193..d5956db84 100644 --- a/IntelPresentMon/AppCef/source/util/CefValues.cpp +++ b/IntelPresentMon/AppCef/source/util/CefValues.cpp @@ -5,6 +5,8 @@ namespace p2c::client::util { + using namespace std::literals; + CefRefPtr V8ToCefValue(CefV8Value& v8) { auto v = CefValue::Create(); @@ -130,7 +132,7 @@ namespace p2c::client::util return { std::move(pVal) }; } - std::wstring CefValueTraverser::AsWString() + std::wstring CefValueTraverser::AsWString() const { using str::ToWide; if (pCefValue->GetType() == CefValueType::VTYPE_STRING) @@ -141,7 +143,7 @@ namespace p2c::client::util throw Except(); } - std::string CefValueTraverser::AsString() + std::string CefValueTraverser::AsString() const { using str::ToWide; if (pCefValue->GetType() == CefValueType::VTYPE_STRING) @@ -203,17 +205,102 @@ namespace p2c::client::util return std::move(pCefValue); } - size_t CefValueTraverser::GetArrayLength() + bool CefValueTraverser::IsAggregate() const + { + const auto type = pCefValue->GetType(); + return type == CefValueType::VTYPE_LIST || type == CefValueType::VTYPE_DICTIONARY; + } + + std::string CefValueTraverser::Dump(int initial, int increment) const { - if (pCefValue->GetType() == CefValueType::VTYPE_LIST) + return Dump_(initial, increment, false); + } + + std::string CefValueTraverser::Dump_(int depth, int increment, bool labeled) const + { + std::ostringstream oss; + if (!labeled) { + oss << std::string(depth * increment, ' '); + } + switch (pCefValue->GetType()) { + case CefValueType::VTYPE_BOOL: + oss << (bool(*this) ? "true"s : "false"s) + " "; + break; + case CefValueType::VTYPE_INT: + oss << std::to_string(int(*this)) + " "; + break; + case CefValueType::VTYPE_DOUBLE: + oss << std::to_string(double(*this)) + " "; + break; + case CefValueType::VTYPE_STRING: + oss << AsString() + " "; + break; + case CefValueType::VTYPE_BINARY: + oss << "# "s + std::to_string(pCefValue->GetBinary()->GetSize()) + " bytes # "; + break; + case CefValueType::VTYPE_DICTIONARY: + { + depth++; + const std::string istr(increment * depth, ' '); + const auto pDict = pCefValue->GetDictionary(); + CefDictionaryValue::KeyList keys; + pDict->GetKeys(keys); + if (keys.size() == 0) { + oss << "{}"; + } + else { + oss << "{\n"; + for (auto& key : keys) { + oss << istr << "\"" << key << "\": " << Traverse(pDict->GetValue(key)) + .Dump_(depth, increment, true) << "\n"; + } + oss << std::string(increment * (depth - 1), ' ') << "}"; + } + break; + } + case CefValueType::VTYPE_LIST: { + depth++; + const std::string istr(increment * depth, ' '); + const auto pList = pCefValue->GetList(); + const auto size = pList->GetSize(); + if (size == 0) { + oss << "[]"; + } + else { + oss << "[\n"; + for (int i = 0; i < pList->GetSize(); i++) { + oss << istr << i << ": " << Traverse(pList->GetValue(i)) + .Dump_(depth, increment, true) << "\n"; + } + oss << std::string(increment * (depth - 1), ' ') << "]"; + } + break; + } + case CefValueType::VTYPE_NULL: + oss << ""s; + break; + default: + oss << "<@UNKNOWN@>"; + break; + } + return oss.str(); + } + + + size_t CefValueTraverser::GetLength() const + { + if (pCefValue->GetType() == CefValueType::VTYPE_LIST) { return pCefValue->GetList()->GetSize(); } - pmlog_error(std::format("Failed getting array length of CefValue type {}", CefValueTypeToString(pCefValue->GetType()))); + else if (pCefValue->GetType() == CefValueType::VTYPE_DICTIONARY) { + return pCefValue->GetDictionary()->GetSize(); + } + pmlog_error(std::format("Failed getting length of non-Array non-Dict CefValue type {}", CefValueTypeToString(pCefValue->GetType()))); throw Except(); } - bool CefValueTraverser::IsNull() + bool CefValueTraverser::IsNull() const { return pCefValue->GetType() == CefValueType::VTYPE_NULL; } diff --git a/IntelPresentMon/AppCef/source/util/CefValues.h b/IntelPresentMon/AppCef/source/util/CefValues.h index 85b739cf6..b90b79ab4 100644 --- a/IntelPresentMon/AppCef/source/util/CefValues.h +++ b/IntelPresentMon/AppCef/source/util/CefValues.h @@ -171,10 +171,10 @@ namespace p2c::client::util { public: CefValueTraverser(CefRefPtr pCefValue) : pCefValue{ std::move(pCefValue) } {} - std::wstring AsWString(); - std::string AsString(); + std::wstring AsWString() const; + std::string AsString() const; template - operator T() + operator T() const { using str::ToWide; if constexpr (std::is_same_v) @@ -215,7 +215,7 @@ namespace p2c::client::util template std::vector ToVector() { - const auto size = GetArrayLength(); + const auto size = GetLength(); std::vector container; container.reserve(size); for (size_t i = 0; i < size; i++) { @@ -232,9 +232,9 @@ namespace p2c::client::util return container; } template - std::vector PluckAs(const char* key) + std::vector PluckAs(const char* key) const { - const auto size = GetArrayLength(); + const auto size = GetLength(); std::vector container; container.reserve(size); for (size_t i = 0; i < size; i++) { @@ -246,9 +246,14 @@ namespace p2c::client::util CefValueTraverser operator[](size_t index); CefRefPtr AsCefValue() const &; CefRefPtr AsCefValue() &&; - size_t GetArrayLength(); - bool IsNull(); + size_t GetLength() const; + bool IsNull() const; + bool IsAggregate() const; + std::string Dump(int initial = 1, int increment = 3) const; private: + // functions + std::string Dump_(int depth, int increment, bool labeled) const; + // data CefRefPtr pCefValue; }; diff --git a/IntelPresentMon/AppCef/source/util/MakeOverlaySpec.cpp b/IntelPresentMon/AppCef/source/util/MakeOverlaySpec.cpp index a0d2005e9..4ab94be08 100644 --- a/IntelPresentMon/AppCef/source/util/MakeOverlaySpec.cpp +++ b/IntelPresentMon/AppCef/source/util/MakeOverlaySpec.cpp @@ -252,7 +252,7 @@ namespace p2c::client::util // populate widgets into spec file { auto widgets = traversedSpec["widgets"].AsCefValue(); - const auto widgetCount = Traverse(widgets).GetArrayLength(); + const auto widgetCount = Traverse(widgets).GetLength(); for (size_t i = 0; i < widgetCount; i++) { auto widget = Traverse(widgets)[i].AsCefValue(); @@ -266,7 +266,7 @@ namespace p2c::client::util auto type = lay::EnumRegistry::ToEnum(Traverse(vGraph)["graphType"]["name"].AsWString()); // create the metric specs for each line etc. in widget std::vector graphMetricSpecs; - for (size_t i = 0; i < widgetMetrics.GetArrayLength(); i++) { + for (size_t i = 0; i < widgetMetrics.GetLength(); i++) { auto widgetMetric = Traverse(widgetMetrics)[i]; const gfx::lay::AxisAffinity axis = widgetMetric["axisAffinity"]; auto qualifiedMetric = widgetMetric["metric"]; @@ -352,7 +352,7 @@ namespace p2c::client::util // why is this hardcoded using index 0? sheets.back()->InsertRaw(at::make::Color(ColorFromV8(widgetMetrics[0ull]["lineColor"]))); - const auto widgetMetricCount = widgetMetrics.GetArrayLength(); + const auto widgetMetricCount = widgetMetrics.GetLength(); bool hasRightAxis = false; for (size_t iWidgetMetric = 0; iWidgetMetric < widgetMetricCount; iWidgetMetric++) { auto widgetMetric = widgetMetrics[iWidgetMetric]; @@ -405,7 +405,7 @@ namespace p2c::client::util auto& vReadout = widget; auto& sheets = pSpec->sheets; const auto tag = std::format("r{}", i); - if (Traverse(vReadout)["metrics"].GetArrayLength() > 1) { + if (Traverse(vReadout)["metrics"].GetLength() > 1) { pmlog_warn("Too many metricIds for readout widget"); } auto qualifiedMetric = Traverse(vReadout)["metrics"][0ull]["metric"]; diff --git a/IntelPresentMon/CommonUtilities/log/HrLogger.cpp b/IntelPresentMon/CommonUtilities/log/HrLogger.cpp index ca2367fbe..02af63eec 100644 --- a/IntelPresentMon/CommonUtilities/log/HrLogger.cpp +++ b/IntelPresentMon/CommonUtilities/log/HrLogger.cpp @@ -13,7 +13,7 @@ namespace pmon::util::log void HrLogger::operator<<(uint32_t hr) const { if (FAILED(hr)) { - if ((PMLOG_BUILD_LEVEL >= Level::Error) || (GlobalPolicy::Get().GetLogLevel() >= Level::Error)) { + if ((PMLOG_BUILD_LEVEL_ >= Level::Error) || (GlobalPolicy::Get().GetLogLevel() >= Level::Error)) { EntryBuilder{ Level::Error, sourceFile_, sourceFunctionName_, sourceLine_ }.hr(hr); } throw Except("failed hr check"); diff --git a/IntelPresentMon/CommonUtilities/log/Log.h b/IntelPresentMon/CommonUtilities/log/Log.h index dfb8ef6dc..ee6fd5777 100644 --- a/IntelPresentMon/CommonUtilities/log/Log.h +++ b/IntelPresentMon/CommonUtilities/log/Log.h @@ -21,15 +21,19 @@ namespace pmon::util::log struct Voidifier_ { template void operator&(T&&) const {} }; } -#ifndef PMLOG_BUILD_LEVEL +#ifdef PMLOG_BUILD_LEVEL +#define PMLOG_BUILD_LEVEL_ ::pmon::util::log::Level::##PMLOG_BUILD_LEVEL +#endif + +#ifndef PMLOG_BUILD_LEVEL_ #ifndef NDEBUG -#define PMLOG_BUILD_LEVEL ::pmon::util::log::Level::Debug +#define PMLOG_BUILD_LEVEL_ ::pmon::util::log::Level::Debug #else -#define PMLOG_BUILD_LEVEL ::pmon::util::log::Level::Info +#define PMLOG_BUILD_LEVEL_ ::pmon::util::log::Level::Info #endif #endif -#define pmlog_(lvl) ((PMLOG_BUILD_LEVEL < lvl) || (::pmon::util::log::GlobalPolicy::Get().GetLogLevel() < lvl)) \ +#define pmlog_(lvl) ((PMLOG_BUILD_LEVEL_ < lvl) || (::pmon::util::log::GlobalPolicy::Get().GetLogLevel() < lvl)) \ ? (void)0 : ::pmon::util::log::Voidifier_{} & ::pmon::util::log::EntryBuilder{ lvl, __FILE__, __FUNCTION__, __LINE__ } \ .subsys(::pmon::util::log::GlobalPolicy::Get().GetSubsystem()) \ .to(::pmon::util::log::GetDefaultChannel()) diff --git a/IntelPresentMon/CommonUtilities/log/TimePoint.cpp b/IntelPresentMon/CommonUtilities/log/TimePoint.cpp index 49227b85f..a93a69f6a 100644 --- a/IntelPresentMon/CommonUtilities/log/TimePoint.cpp +++ b/IntelPresentMon/CommonUtilities/log/TimePoint.cpp @@ -5,7 +5,7 @@ namespace pmon::util::log { TimePoint::TimePoint() noexcept { - if constexpr (PMLOG_BUILD_LEVEL >= Level::Performance) { + if constexpr (PMLOG_BUILD_LEVEL_ >= Level::Performance) { value = std::chrono::high_resolution_clock::now(); } else { diff --git a/IntelPresentMon/Core/source/infra/Logging.h b/IntelPresentMon/Core/source/infra/Logging.h index 89ddc7469..00bc58625 100644 --- a/IntelPresentMon/Core/source/infra/Logging.h +++ b/IntelPresentMon/Core/source/infra/Logging.h @@ -1,6 +1,10 @@ #pragma once + +// #define PMLOG_BUILD_LEVEL Verbose +// #define VVV_METRIC #include + namespace p2c::v { #ifndef VVV_WINDOW // system that tracks overlay target process ancestry and windows spawning therein @@ -23,4 +27,14 @@ namespace p2c::v #else inline constexpr bool overlay = true; #endif +#ifndef VVV_METRIC // system for parsing QualifiedMetric lists and building queries, fetchers, and data packs + inline constexpr bool metric = false; +#else + inline constexpr bool metric = true; +#endif +#ifndef VVV_V8ASYNC // system for async calls and signals between V8 and C++ + inline constexpr bool v8async = false; +#else + inline constexpr bool v8async = true; +#endif } \ No newline at end of file diff --git a/IntelPresentMon/Core/source/kernel/MetricPackMapper.h b/IntelPresentMon/Core/source/kernel/MetricPackMapper.h index bcac52d72..df9ea012d 100644 --- a/IntelPresentMon/Core/source/kernel/MetricPackMapper.h +++ b/IntelPresentMon/Core/source/kernel/MetricPackMapper.h @@ -2,6 +2,7 @@ #include "DataFetchPack.h" #include "../pmon/MetricFetcherFactory.h" #include "../pmon/DynamicQuery.h" +#include "../infra/Logging.h" #include "OverlaySpec.h" #include #include @@ -61,6 +62,9 @@ namespace p2c::kern usageMap_.clear(); // build vector of qmet const auto qualifiedMetrics = metricPackMap_ | vi::keys | rn::to(); + pmlog_verb(v::metric)("Metrics for query build:\n" + [&] { return qualifiedMetrics | + vi::transform([](auto& q) {return " " + q.Dump(); }) | + vi::join_with('\n') | rn::to(); }()); // build fetchers / query auto buildResult = factory.Build(pid, winSizeMs, metricOffsetMs, qualifiedMetrics); // fill fetchers into map @@ -78,9 +82,11 @@ namespace p2c::kern auto& pPack = metricPackMap_[qmet]; if (!pPack.graphData) { pPack.graphData = std::make_shared(timeWindow); + pmlog_verb(v::metric)(std::format("AddGraph[new]> {}", qmet.Dump())); } else if (pPack.graphData->GetWindowSize() != timeWindow) { pPack.graphData->Resize(timeWindow); + pmlog_verb(v::metric)(std::format("AddGraph[resize]> {}", qmet.Dump())); } usageMap_[qmet].graph = true; } @@ -89,6 +95,7 @@ namespace p2c::kern auto& pPack = metricPackMap_[qmet]; if (!pPack.textData) { pPack.textData = std::make_shared(); + pmlog_verb(v::metric)(std::format("AddReadout[new]> {}", qmet.Dump())); } usageMap_[qmet].text = true; } diff --git a/IntelPresentMon/Core/source/kernel/OverlaySpec.h b/IntelPresentMon/Core/source/kernel/OverlaySpec.h index a90873cd7..c354951e7 100644 --- a/IntelPresentMon/Core/source/kernel/OverlaySpec.h +++ b/IntelPresentMon/Core/source/kernel/OverlaySpec.h @@ -32,6 +32,11 @@ namespace p2c::kern deviceId == rhs.deviceId; // TODO: cosider what to do about unitId here } + std::string Dump() const + { + return std::format("QMet> metId:{} staId:{} arrIdx:{} devId:{} untId:{}", + metricId, statId, arrayIndex, deviceId, unitId); + } }; struct GraphMetricSpec