4#include "Stroika/Frameworks/StroikaPreComp.h"
6#if qStroika_Foundation_Common_Platform_Windows
11#error "WINDOWS REQUIRED FOR THIS MODULE"
15#include "Stroika/Foundation/Characters/FloatConversion.h"
17#include "Stroika/Foundation/Containers/Sequence.h"
30using namespace Stroika::Foundation::Memory;
32using namespace Stroika::Frameworks;
33using namespace Stroika::Frameworks::SystemPerformance;
34using namespace Stroika::Frameworks::SystemPerformance::Support;
40#pragma comment(lib, "Pdh.lib")
52 : fObjectName_{objectName}
53 , fInstance_{instance}
55#if USE_NOISY_TRACE_IN_THIS_MODULE_
56 Debug::TraceContextBumper ctx{
"Stroika::Frameworks::SystemPerformance::Support::WMICollector::PerInstanceData_::PerInstanceData_"};
58 PDH_STATUS x = ::PdhOpenQuery (NULL, NULL, &fQuery_);
62 counterNames.
Apply ([
this] (
String i) { AddCounter (i); });
65WMICollector::PerInstanceData_::~PerInstanceData_ ()
67#if USE_NOISY_TRACE_IN_THIS_MODULE_
68 Debug::TraceContextBumper ctx{
"Stroika::Frameworks::SystemPerformance::Support::WMICollector::PerInstanceData_::~PerInstanceData_"};
72 ::PdhCloseQuery (fQuery_);
75void WMICollector::PerInstanceData_::AddCounter (
const String& counterName)
77 Require (not fCounters_.ContainsKey (counterName));
78 PDH_HCOUNTER newCounter =
nullptr;
79 PDH_STATUS x = ::PdhAddCounter (fQuery_,
"\\{}({})\\{}"_f(fObjectName_, fInstance_, counterName).As<wstring> ().c_str (), NULL, &newCounter);
81 [[maybe_unused]]
bool isPDH_CSTATUS_NO_OBJECT = (x == PDH_CSTATUS_NO_OBJECT);
82 [[maybe_unused]]
bool isPDH_CSTATUS_NO_COUNTER = (x == PDH_CSTATUS_NO_COUNTER);
85 fCounters_.Add (counterName, newCounter);
88double WMICollector::PerInstanceData_::GetCurrentValue (
const String& counterName)
90 PDH_FMT_COUNTERVALUE counterVal;
91 PDH_HCOUNTER counter = *fCounters_.Lookup (counterName);
92 PDH_STATUS x = ::PdhGetFormattedCounterValue (counter, PDH_FMT_DOUBLE,
nullptr, &counterVal);
94 [[maybe_unused]]
bool isPDH_PDH_INVALID_DATA = (x == PDH_INVALID_DATA);
97 return counterVal.doubleValue;
100optional<double> WMICollector::PerInstanceData_::PeekCurrentValue (
const String& counterName)
102 PDH_FMT_COUNTERVALUE counterVal{};
103 PDH_HCOUNTER counter = *fCounters_.Lookup (counterName);
104 PDH_STATUS x = ::PdhGetFormattedCounterValue (counter, PDH_FMT_DOUBLE,
nullptr, &counterVal);
108 return counterVal.doubleValue;
113 PDH_HCOUNTER counter{*fCounters_.
Lookup (counterName)};
114 DWORD dwBufferSize{};
118 PDH_STATUS status = ::PdhGetFormattedCounterArray (counter, PDH_FMT_DOUBLE, &dwBufferSize, &dwItemCount,
nullptr);
119 if (PDH_MORE_DATA == status) {
120 items.GrowToSize ((dwBufferSize +
sizeof (PDH_FMT_COUNTERVALUE_ITEM) - 1) /
sizeof (PDH_FMT_COUNTERVALUE_ITEM));
122 status = ::PdhGetFormattedCounterArray (counter, PDH_FMT_DOUBLE, &dwBufferSize, &dwItemCount, items.begin ());
124 if (status == PDH_CSTATUS_INVALID_DATA) {
136 [[maybe_unused]]
bool isPDH_PDH_INVALID_DATA = (status == PDH_INVALID_DATA);
141 for (DWORD i = 0; i < dwItemCount; ++i) {
142 result.
Add (items[i].szName, items[i].FmtValue.doubleValue);
152String WMICollector::kWildcardInstance =
"*"sv;
155 : fObjectName_{objectName}
157#if USE_NOISY_TRACE_IN_THIS_MODULE_
160 instances.
Apply ([
this] (
String i) { AddInstance_ (i); });
161 counterName.
Apply ([
this] (
String i) { AddCounter_ (i); });
165 :
WMICollector{from.fObjectName_, from.fInstanceData_.Keys (), from.fCounterNames_}
167#if USE_NOISY_TRACE_IN_THIS_MODULE_
177#if USE_NOISY_TRACE_IN_THIS_MODULE_
181 AssertExternallySynchronizedMutex::ReadContext critSec1{rhs};
182 AssertExternallySynchronizedMutex::WriteContext critSec2{*
this};
183 fInstanceData_.clear ();
184 fObjectName_ = rhs.fObjectName_;
185 rhs.fInstanceData_.Keys ().Apply ([
this] (
String i) { AddInstance_ (i); });
186 rhs.fCounterNames_.Apply ([
this] (
String i) { AddCounter_ (i); });
191void WMICollector::Collect ()
193#if USE_NOISY_TRACE_IN_THIS_MODULE_
196 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
197 fInstanceData_.Apply ([
this] (
KeyValuePair<
String, std::shared_ptr<PerInstanceData_>> i) {
198 PDH_STATUS x = ::PdhCollectQueryData (i.fValue->fQuery_);
200 bool isPDH_PDH_NO_DATA = (x == PDH_NO_DATA);
201 if (not isPDH_PDH_NO_DATA) {
208 fTimeOfLastCollection_ = Time::GetTickCount ();
217 DWORD dwCounterListSize = 0;
218 DWORD dwInstanceListSize = 0;
220 PDH_STATUS pdhStatus = ::PdhEnumObjectItems (
nullptr,
nullptr, fObjectName_.
As<wstring> ().c_str (),
nullptr, &dwCounterListSize,
221 nullptr, &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
222 Assert (pdhStatus == PDH_MORE_DATA);
227 pdhStatus = ::PdhEnumObjectItems (
nullptr,
nullptr, fObjectName_.
As<wstring> ().c_str (), counterBuf.begin (), &dwCounterListSize,
228 instanceBuf.begin (), &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
229 if (pdhStatus != 0) {
234 for (
const TCHAR* p = instanceBuf.begin (); *p !=
'\0'; p += Characters::CString::Length (p) + 1) {
246 DWORD dwCounterListSize = 0;
247 DWORD dwInstanceListSize = 0;
249 PDH_STATUS pdhStatus = ::PdhEnumObjectItems (NULL, NULL, fObjectName_.
As<wstring> ().c_str (),
nullptr, &dwCounterListSize,
nullptr,
250 &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
251 Assert (pdhStatus == PDH_MORE_DATA);
256 pdhStatus = ::PdhEnumObjectItems (NULL, NULL, fObjectName_.
As<wstring> ().c_str (), counterBuf.begin (), &dwCounterListSize,
257 instanceBuf.begin (), &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
258 if (pdhStatus != 0) {
263 for (
const TCHAR* p = counterBuf.begin (); *p !=
'\0'; p += Characters::CString::Length (p) + 1) {
271#if USE_NOISY_TRACE_IN_THIS_MODULE_
274 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
275 AddCounter_ (counterName);
280#if USE_NOISY_TRACE_IN_THIS_MODULE_
283 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
284 counterNames.
Apply ([
this] (
String i) { AddCounter_ (i); });
289#if USE_NOISY_TRACE_IN_THIS_MODULE_
292 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
293 AddInstance_ (instance);
298#if USE_NOISY_TRACE_IN_THIS_MODULE_
301 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
302 instances.
Apply ([
this] (
String i) { AddInstance_ (i); });
307#if USE_NOISY_TRACE_IN_THIS_MODULE_
310 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
311 if (not fInstanceData_.ContainsKey (instance)) {
312 AddInstance_ (instance);
320#if USE_NOISY_TRACE_IN_THIS_MODULE_
323 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
324 bool anyAdded =
false;
326 if (not fInstanceData_.ContainsKey (i)) {
336#if USE_NOISY_TRACE_IN_THIS_MODULE_
339 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
340 Require (fInstanceData_.ContainsKey (instance));
341 return fInstanceData_.Lookup (instance)->get ()->GetCurrentValue (counterName);
346#if USE_NOISY_TRACE_IN_THIS_MODULE_
349 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
350 Require (fInstanceData_.ContainsKey (instance));
351 return fInstanceData_.Lookup (instance)->get ()->PeekCurrentValue (counterName);
356#if USE_NOISY_TRACE_IN_THIS_MODULE_
359 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
360 Require (fInstanceData_.ContainsKey (WMICollector::kWildcardInstance));
361 return fInstanceData_.Lookup (WMICollector::kWildcardInstance)->get ()->GetCurrentValues (counterName);
364void WMICollector::AddCounter_ (
const String& counterName)
366#if USE_NOISY_TRACE_IN_THIS_MODULE_
370 Require (not fCounterNames_.Contains (counterName));
371 fInstanceData_.Apply (
372 [
this, counterName] (
KeyValuePair<
String, std::shared_ptr<PerInstanceData_>> i) { i.fValue->AddCounter (counterName); });
373 fCounterNames_.Add (counterName);
376void WMICollector::AddInstance_ (
const String& instance)
378#if USE_NOISY_TRACE_IN_THIS_MODULE_
382 Require (not fInstanceData_.ContainsKey (instance));
383 fInstanceData_.Add (instance, make_shared<PerInstanceData_> (fObjectName_, instance, fCounterNames_));
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromSDKString(const SDKChar *from)
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...