Reading the Processor Load

  • Thread starter Thread starter Alain Dekker
  • Start date Start date
A

Alain Dekker

Hi,

I have a working C++ program reading the ProcessorLoad but there are a few
problems which I need some advise on, please. The code I am using is given
at the bottom of this post. Here are my problems:

* The entire process of getting the load (top->bottom) takes about 1000ms.
This is *very* slow. Is this just a limitation of WMI or have I programmed
it inefficiently or is there a better way?
* Much more importantly, the code below is LEAKING MEMORY! If I put "return
byLoad;" right at the top of the function, there is no memory leak. Where is
the leak coming from, I can't work it out!

Here's the code and thanks in advance,
Alain

// Function: ReadProcessorLoad()
BYTE byLoad = 0;

// Frustratingly, every time you need to read from WMI, it appears you must
redo the
// entire WQL (SQL-like) query!

// Initialize the COM library on the current thread
HRESULT hr = S_OK;
if (!m_bComInitialised)
hr = CoInitialize(NULL);

bool bGoodToGo = true;

// Open the overall WMI service provider
if (bGoodToGo && m_pIWbemLocator)
{
BSTR bstrNamespace = SysAllocString(L"root\\cimv2");
hr = m_pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, NULL, 0,
NULL, NULL, &m_pWbemServices);
if (hr != S_OK)
bGoodToGo = false;

SysFreeString(bstrNamespace);
}

// Open the WMI class object
if (bGoodToGo && m_pWbemServices)
{
BSTR bstrQuery = SysAllocString(L"Select * from Win32_Processor");
BSTR bstrQL = SysAllocString(L"WQL");
hr = m_pWbemServices->ExecQuery(bstrQL, bstrQuery,
WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &m_pEnumObject);
if (hr != S_OK)
bGoodToGo = false;

SysFreeString(bstrQuery);
SysFreeString(bstrQL);
}

// Reset the object
if (bGoodToGo && m_pEnumObject)
{
hr = m_pEnumObject->Reset();
if (hr != S_OK)
bGoodToGo = false;
}

// Enumerate the object (make sure it has methods and data)
if (bGoodToGo && m_pEnumObject)
{
ULONG uCount = 1, uReturned;
hr = m_pEnumObject->Next(WBEM_INFINITE, uCount, &m_pClassObject,
&uReturned);
if (hr != S_OK)
bGoodToGo = false;
}

// Read the processor load
if (bGoodToGo && m_pClassObject)
{
BSTR bstrClassProp = SysAllocString(L"LoadPercentage");
HRESULT hr = m_pClassObject->Get(bstrClassProp, 0, &m_vData, 0, 0);
if (SUCCEEDED(hr))
{
// Convert BSTR to ANSI
_bstr_t bstrData = &m_vData;
char* strData = (char*)bstrData;

// Get data
byLoad = atoi(strData);
}

SysFreeString(bstrClassProp);
}

return byLoad;
 
Alain said:
Hi,

I have a working C++ program reading the ProcessorLoad but there are a few
problems which I need some advise on, please. The code I am using is given
at the bottom of this post. Here are my problems:

* The entire process of getting the load (top->bottom) takes about 1000ms.
This is *very* slow. Is this just a limitation of WMI or have I programmed
it inefficiently or is there a better way?
* Much more importantly, the code below is LEAKING MEMORY! If I put "return
byLoad;" right at the top of the function, there is no memory leak. Where is
the leak coming from, I can't work it out!

Here's the code and thanks in advance,
Alain

// Function: ReadProcessorLoad()
BYTE byLoad = 0;

// Frustratingly, every time you need to read from WMI, it appears you must
redo the
// entire WQL (SQL-like) query!

// Initialize the COM library on the current thread
HRESULT hr = S_OK;
if (!m_bComInitialised)
hr = CoInitialize(NULL);

bool bGoodToGo = true;

// Open the overall WMI service provider
if (bGoodToGo && m_pIWbemLocator)
{
BSTR bstrNamespace = SysAllocString(L"root\\cimv2");
hr = m_pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, NULL, 0,
NULL, NULL, &m_pWbemServices);
if (hr != S_OK)
bGoodToGo = false;

SysFreeString(bstrNamespace);
}

// Open the WMI class object
if (bGoodToGo && m_pWbemServices)
{
BSTR bstrQuery = SysAllocString(L"Select * from Win32_Processor");
BSTR bstrQL = SysAllocString(L"WQL");
hr = m_pWbemServices->ExecQuery(bstrQL, bstrQuery,
WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &m_pEnumObject);
if (hr != S_OK)
bGoodToGo = false;

SysFreeString(bstrQuery);
SysFreeString(bstrQL);
}

// Reset the object
if (bGoodToGo && m_pEnumObject)
{
hr = m_pEnumObject->Reset();
if (hr != S_OK)
bGoodToGo = false;
}

// Enumerate the object (make sure it has methods and data)
if (bGoodToGo && m_pEnumObject)
{
ULONG uCount = 1, uReturned;
hr = m_pEnumObject->Next(WBEM_INFINITE, uCount, &m_pClassObject,
&uReturned);
if (hr != S_OK)
bGoodToGo = false;
}

// Read the processor load
if (bGoodToGo && m_pClassObject)
{
BSTR bstrClassProp = SysAllocString(L"LoadPercentage");
HRESULT hr = m_pClassObject->Get(bstrClassProp, 0, &m_vData, 0, 0);
if (SUCCEEDED(hr))
{
// Convert BSTR to ANSI
_bstr_t bstrData = &m_vData;
char* strData = (char*)bstrData;

// Get data
byLoad = atoi(strData);
}

SysFreeString(bstrClassProp);
}

return byLoad;

These are some newsgroups that mention WMI in the name.

microsoft.public.dotnet.framework.wmi
microsoft.public.win32.programmer.wmi
mcirosoft.public.windowsxp.wmi
microsoft.public.wmi.programmer

I'd probably use a packet sniffer, like Wireshark, take a
snapshot of the packets sent and received, examine their
time stamps, and reconstruct what is happening.

In client-server architectures, the "discovery" phase can be
separated from the repetitive part ("query"). Perhaps by
caching any expensive "discovery" stuff for later use,
the query can be made faster. And if the info cached is
invalid (as detected by a timeout on a query), executing
the discovery phase again can be used to refresh it.

HTH,
Paul (who is not a programmer :-) )
 
Thanks Paul, I've cross-posted to those other newsgroups. This is not TCP/IP
or ethernet programming so a packet sniffer will not, to my knowledge, help
here. Something strange is happening with the memory allocation that I do
not understand!

Regards,
Alain
 
Maybe this can be done with the Performance helper lib
or directly retrieving performance counters.
This WMI query code creates more CPU load than it measures...
--pa
 
Back
Top