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"
31using namespace Stroika::Foundation::Memory;
33using namespace Stroika::Frameworks;
34using namespace Stroika::Frameworks::SystemPerformance;
35using namespace Stroika::Frameworks::SystemPerformance::Support;
41#pragma comment(lib, "Pdh.lib")
53 : fObjectName_{objectName}
54 , fInstance_{instance}
56#if USE_NOISY_TRACE_IN_THIS_MODULE_
57 Debug::TraceContextBumper ctx{
"Stroika::Frameworks::SystemPerformance::Support::WMICollector::PerInstanceData_::PerInstanceData_"};
59 PDH_STATUS x = ::PdhOpenQuery (NULL, NULL, &fQuery_);
63 counterNames.
Apply ([
this] (
String i) { AddCounter (i); });
66WMICollector::PerInstanceData_::~PerInstanceData_ ()
68#if USE_NOISY_TRACE_IN_THIS_MODULE_
69 Debug::TraceContextBumper ctx{
"Stroika::Frameworks::SystemPerformance::Support::WMICollector::PerInstanceData_::~PerInstanceData_"};
73 ::PdhCloseQuery (fQuery_);
76void WMICollector::PerInstanceData_::AddCounter (
const String& counterName)
78 Require (not fCounters_.ContainsKey (counterName));
79 PDH_HCOUNTER newCounter =
nullptr;
80 PDH_STATUS x = ::PdhAddCounter (fQuery_,
"\\{}({})\\{}"_f(fObjectName_, fInstance_, counterName).As<wstring> ().c_str (), NULL, &newCounter);
82 [[maybe_unused]]
bool isPDH_CSTATUS_NO_OBJECT = (x == PDH_CSTATUS_NO_OBJECT);
83 [[maybe_unused]]
bool isPDH_CSTATUS_NO_COUNTER = (x == PDH_CSTATUS_NO_COUNTER);
86 fCounters_.Add (counterName, newCounter);
89double WMICollector::PerInstanceData_::GetCurrentValue (
const String& counterName)
91 PDH_FMT_COUNTERVALUE counterVal;
92 PDH_HCOUNTER counter = *fCounters_.Lookup (counterName);
93 PDH_STATUS x = ::PdhGetFormattedCounterValue (counter, PDH_FMT_DOUBLE,
nullptr, &counterVal);
95 [[maybe_unused]]
bool isPDH_PDH_INVALID_DATA = (x == PDH_INVALID_DATA);
98 return counterVal.doubleValue;
101optional<double> WMICollector::PerInstanceData_::PeekCurrentValue (
const String& counterName)
103 PDH_FMT_COUNTERVALUE counterVal{};
104 PDH_HCOUNTER counter = *fCounters_.Lookup (counterName);
105 PDH_STATUS x = ::PdhGetFormattedCounterValue (counter, PDH_FMT_DOUBLE,
nullptr, &counterVal);
109 return counterVal.doubleValue;
114 PDH_HCOUNTER counter{*fCounters_.
Lookup (counterName)};
115 DWORD dwBufferSize{};
119 PDH_STATUS status = ::PdhGetFormattedCounterArray (counter, PDH_FMT_DOUBLE, &dwBufferSize, &dwItemCount,
nullptr);
120 if (PDH_MORE_DATA == status) {
121 items.GrowToSize ((dwBufferSize +
sizeof (PDH_FMT_COUNTERVALUE_ITEM) - 1) /
sizeof (PDH_FMT_COUNTERVALUE_ITEM));
123 status = ::PdhGetFormattedCounterArray (counter, PDH_FMT_DOUBLE, &dwBufferSize, &dwItemCount, items.begin ());
125 if (status == PDH_CSTATUS_INVALID_DATA) {
137 [[maybe_unused]]
bool isPDH_PDH_INVALID_DATA = (status == PDH_INVALID_DATA);
142 for (DWORD i = 0; i < dwItemCount; ++i) {
143 result.
Add (items[i].szName, items[i].FmtValue.doubleValue);
153String WMICollector::kWildcardInstance =
"*"sv;
156 : fObjectName_{objectName}
158#if USE_NOISY_TRACE_IN_THIS_MODULE_
161 instances.
Apply ([
this] (
String i) { AddInstance_ (i); });
162 counterName.
Apply ([
this] (
String i) { AddCounter_ (i); });
166 :
WMICollector{from.fObjectName_, from.fInstanceData_.Keys (), from.fCounterNames_}
168#if USE_NOISY_TRACE_IN_THIS_MODULE_
178#if USE_NOISY_TRACE_IN_THIS_MODULE_
182 AssertExternallySynchronizedMutex::ReadContext critSec1{rhs};
183 AssertExternallySynchronizedMutex::WriteContext critSec2{*
this};
184 fInstanceData_.clear ();
185 fObjectName_ = rhs.fObjectName_;
186 rhs.fInstanceData_.Keys ().Apply ([
this] (
String i) { AddInstance_ (i); });
187 rhs.fCounterNames_.Apply ([
this] (
String i) { AddCounter_ (i); });
192void WMICollector::Collect ()
194#if USE_NOISY_TRACE_IN_THIS_MODULE_
197 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
198 fInstanceData_.Apply ([
this] (
KeyValuePair<
String, std::shared_ptr<PerInstanceData_>> i) {
199 PDH_STATUS x = ::PdhCollectQueryData (i.fValue->fQuery_);
201 bool isPDH_PDH_NO_DATA = (x == PDH_NO_DATA);
202 if (not isPDH_PDH_NO_DATA) {
209 fTimeOfLastCollection_ = Time::GetTickCount ();
218 DWORD dwCounterListSize = 0;
219 DWORD dwInstanceListSize = 0;
221 PDH_STATUS pdhStatus = ::PdhEnumObjectItems (
nullptr,
nullptr, fObjectName_.
As<wstring> ().c_str (),
nullptr, &dwCounterListSize,
222 nullptr, &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
223 Assert (pdhStatus == PDH_MORE_DATA);
228 pdhStatus = ::PdhEnumObjectItems (
nullptr,
nullptr, fObjectName_.
As<wstring> ().c_str (), counterBuf.begin (), &dwCounterListSize,
229 instanceBuf.begin (), &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
230 if (pdhStatus != 0) {
235 for (
const TCHAR* p = instanceBuf.begin (); *p !=
'\0'; p += Characters::CString::Length (p) + 1) {
247 DWORD dwCounterListSize = 0;
248 DWORD dwInstanceListSize = 0;
250 PDH_STATUS pdhStatus = ::PdhEnumObjectItems (NULL, NULL, fObjectName_.
As<wstring> ().c_str (),
nullptr, &dwCounterListSize,
nullptr,
251 &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
252 Assert (pdhStatus == PDH_MORE_DATA);
257 pdhStatus = ::PdhEnumObjectItems (NULL, NULL, fObjectName_.
As<wstring> ().c_str (), counterBuf.begin (), &dwCounterListSize,
258 instanceBuf.begin (), &dwInstanceListSize, PERF_DETAIL_WIZARD, 0);
259 if (pdhStatus != 0) {
264 for (
const TCHAR* p = counterBuf.begin (); *p !=
'\0'; p += Characters::CString::Length (p) + 1) {
272#if USE_NOISY_TRACE_IN_THIS_MODULE_
275 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
276 AddCounter_ (counterName);
281#if USE_NOISY_TRACE_IN_THIS_MODULE_
284 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
285 counterNames.
Apply ([
this] (
String i) { AddCounter_ (i); });
290#if USE_NOISY_TRACE_IN_THIS_MODULE_
293 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
294 AddInstance_ (instance);
299#if USE_NOISY_TRACE_IN_THIS_MODULE_
302 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
303 instances.
Apply ([
this] (
String i) { AddInstance_ (i); });
308#if USE_NOISY_TRACE_IN_THIS_MODULE_
311 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
312 if (not fInstanceData_.ContainsKey (instance)) {
313 AddInstance_ (instance);
321#if USE_NOISY_TRACE_IN_THIS_MODULE_
324 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
325 bool anyAdded =
false;
327 if (not fInstanceData_.ContainsKey (i)) {
337#if USE_NOISY_TRACE_IN_THIS_MODULE_
340 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
341 Require (fInstanceData_.ContainsKey (instance));
342 return fInstanceData_.Lookup (instance)->get ()->GetCurrentValue (counterName);
347#if USE_NOISY_TRACE_IN_THIS_MODULE_
350 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
351 Require (fInstanceData_.ContainsKey (instance));
352 return fInstanceData_.Lookup (instance)->get ()->PeekCurrentValue (counterName);
357#if USE_NOISY_TRACE_IN_THIS_MODULE_
360 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
361 Require (fInstanceData_.ContainsKey (WMICollector::kWildcardInstance));
362 return fInstanceData_.Lookup (WMICollector::kWildcardInstance)->get ()->GetCurrentValues (counterName);
365void WMICollector::AddCounter_ (
const String& counterName)
367#if USE_NOISY_TRACE_IN_THIS_MODULE_
371 Require (not fCounterNames_.Contains (counterName));
372 fInstanceData_.Apply (
373 [
this, counterName] (
KeyValuePair<
String, std::shared_ptr<PerInstanceData_>> i) { i.fValue->AddCounter (counterName); });
374 fCounterNames_.Add (counterName);
377void WMICollector::AddInstance_ (
const String& instance)
379#if USE_NOISY_TRACE_IN_THIS_MODULE_
383 Require (not fInstanceData_.ContainsKey (instance));
384 fInstanceData_.Add (instance, MakeSharedPtr<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...