Search code examples
pythonwinapipywin32

How can I get win32pdhutil to query a performance counter with a slash?


I'm trying to query Windows Performance Counters using win32pdhutil from the pywin32 package in Python, but I run into an error whenever the counter name has a slash.

For example, this code works fine:

import win32pdhutil

query = win32pdhutil.GetPerformanceAttributes("Memory", "Available Bytes")

But this code fails:

import win32pdhutil

query = win32pdhutil.GetPerformanceAttributes("Memory", "Cache Faults/sec")

The error message is:

Traceback (most recent call last):
  File "<path>\Python\Python38-32\lib\site-packages\win32\lib\win32pdhutil.py", line 61, in GetPerformanceAttributes
    type, val = win32pdh.GetFormattedCounterValue(hc, format)
pywintypes.error: (-1073738810, 'GetFormattedCounterValue', 'The data is not valid.')

I've tried a number of different counters and only run into this issue when there is a slash in the counter name.

My original code uses win32pdh.AddCounter and win32pdh.CollectQueryData with the same issue, but the example above demonstrates it in a single line.

I found a similar thread here, without an obvious solution.


Solution

  • You need to wait for "cache faults/sec" to collect enough data, Here is an c++ sample on msdn for Performance Counters api:

    Browsing Performance Counters

    And in python, if I hard code(just for test) in GetPerformanceAttributes function in win32pdhutil.py as below:

    def GetPerformanceAttributes(object, counter, instance = None, inum=-1,
                                 format = win32pdh.PDH_FMT_LONG, machine=None):
        # NOTE: Many counters require 2 samples to give accurate results,
        # including "% Processor Time" (as by definition, at any instant, a
        # thread's CPU usage is either 0 or 100).  To read counters like this,
        # you should copy this function, but keep the counter open, and call
        # CollectQueryData() each time you need to know.
        # See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262938
        # and http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp
        # My older explanation for this was that the "AddCounter" process forced
        # the CPU to 100%, but the above makes more sense :)
        path = win32pdh.MakeCounterPath( (machine,object,instance, None, inum,counter) )
        hq = win32pdh.OpenQuery()
        try:
            hc = win32pdh.AddCounter(hq, path)
            try:
                win32pdh.CollectQueryData(hq)
                time.sleep(1)
                win32pdh.CollectQueryData(hq)
                type, val = win32pdh.GetFormattedCounterValue(hc, format)
                return val
            finally:
                win32pdh.RemoveCounter(hc)
        finally:
            win32pdh.CloseQuery(hq)
    

    Then "Cache Faults/sec" works for me, you could try to customize your own m_GetFormattedCounterValue function, and then give the collector enough time to collect data like the sample above.