Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

win32pdhutil.py 7.4KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. """Utilities for the win32 Performance Data Helper module
  2. Example:
  3. To get a single bit of data:
  4. >>> import win32pdhutil
  5. >>> win32pdhutil.GetPerformanceAttributes("Memory", "Available Bytes")
  6. 6053888
  7. >>> win32pdhutil.FindPerformanceAttributesByName("python", counter="Virtual Bytes")
  8. [22278144]
  9. First example returns data which is not associated with any specific instance.
  10. The second example reads data for a specific instance - hence the list return -
  11. it would return one result for each instance of Python running.
  12. In general, it can be tricky finding exactly the "name" of the data you wish to query.
  13. Although you can use <om win32pdh.EnumObjectItems>(None,None,(eg)"Memory", -1) to do this,
  14. the easiest way is often to simply use PerfMon to find out the names.
  15. """
  16. import time
  17. import win32pdh
  18. error = win32pdh.error
  19. # Handle some localization issues.
  20. # see http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q287/1/59.asp&NoWebContent=1
  21. # Build a map of english_counter_name: counter_id
  22. counter_english_map = {}
  23. def find_pdh_counter_localized_name(english_name, machine_name=None):
  24. if not counter_english_map:
  25. import win32api
  26. import win32con
  27. counter_reg_value = win32api.RegQueryValueEx(
  28. win32con.HKEY_PERFORMANCE_DATA, "Counter 009"
  29. )
  30. counter_list = counter_reg_value[0]
  31. for i in range(0, len(counter_list) - 1, 2):
  32. try:
  33. counter_id = int(counter_list[i])
  34. except ValueError:
  35. continue
  36. counter_english_map[counter_list[i + 1].lower()] = counter_id
  37. return win32pdh.LookupPerfNameByIndex(
  38. machine_name, counter_english_map[english_name.lower()]
  39. )
  40. def GetPerformanceAttributes(
  41. object, counter, instance=None, inum=-1, format=win32pdh.PDH_FMT_LONG, machine=None
  42. ):
  43. # NOTE: Many counters require 2 samples to give accurate results,
  44. # including "% Processor Time" (as by definition, at any instant, a
  45. # thread's CPU usage is either 0 or 100). To read counters like this,
  46. # you should copy this function, but keep the counter open, and call
  47. # CollectQueryData() each time you need to know.
  48. # See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262938
  49. # and http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp
  50. # My older explanation for this was that the "AddCounter" process forced
  51. # the CPU to 100%, but the above makes more sense :)
  52. path = win32pdh.MakeCounterPath((machine, object, instance, None, inum, counter))
  53. hq = win32pdh.OpenQuery()
  54. try:
  55. hc = win32pdh.AddCounter(hq, path)
  56. try:
  57. win32pdh.CollectQueryData(hq)
  58. type, val = win32pdh.GetFormattedCounterValue(hc, format)
  59. return val
  60. finally:
  61. win32pdh.RemoveCounter(hc)
  62. finally:
  63. win32pdh.CloseQuery(hq)
  64. def FindPerformanceAttributesByName(
  65. instanceName,
  66. object=None,
  67. counter=None,
  68. format=win32pdh.PDH_FMT_LONG,
  69. machine=None,
  70. bRefresh=0,
  71. ):
  72. """Find performance attributes by (case insensitive) instance name.
  73. Given a process name, return a list with the requested attributes.
  74. Most useful for returning a tuple of PIDs given a process name.
  75. """
  76. if object is None:
  77. object = find_pdh_counter_localized_name("Process", machine)
  78. if counter is None:
  79. counter = find_pdh_counter_localized_name("ID Process", machine)
  80. if bRefresh: # PDH docs say this is how you do a refresh.
  81. win32pdh.EnumObjects(None, machine, 0, 1)
  82. instanceName = instanceName.lower()
  83. items, instances = win32pdh.EnumObjectItems(None, None, object, -1)
  84. # Track multiple instances.
  85. instance_dict = {}
  86. for instance in instances:
  87. try:
  88. instance_dict[instance] = instance_dict[instance] + 1
  89. except KeyError:
  90. instance_dict[instance] = 0
  91. ret = []
  92. for instance, max_instances in instance_dict.items():
  93. for inum in range(max_instances + 1):
  94. if instance.lower() == instanceName:
  95. ret.append(
  96. GetPerformanceAttributes(
  97. object, counter, instance, inum, format, machine
  98. )
  99. )
  100. return ret
  101. def ShowAllProcesses():
  102. object = find_pdh_counter_localized_name("Process")
  103. items, instances = win32pdh.EnumObjectItems(
  104. None, None, object, win32pdh.PERF_DETAIL_WIZARD
  105. )
  106. # Need to track multiple instances of the same name.
  107. instance_dict = {}
  108. for instance in instances:
  109. try:
  110. instance_dict[instance] = instance_dict[instance] + 1
  111. except KeyError:
  112. instance_dict[instance] = 0
  113. # Bit of a hack to get useful info.
  114. items = [find_pdh_counter_localized_name("ID Process")] + items[:5]
  115. print("Process Name", ",".join(items))
  116. for instance, max_instances in instance_dict.items():
  117. for inum in range(max_instances + 1):
  118. hq = win32pdh.OpenQuery()
  119. hcs = []
  120. for item in items:
  121. path = win32pdh.MakeCounterPath(
  122. (None, object, instance, None, inum, item)
  123. )
  124. hcs.append(win32pdh.AddCounter(hq, path))
  125. win32pdh.CollectQueryData(hq)
  126. # as per http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262938, some "%" based
  127. # counters need two collections
  128. time.sleep(0.01)
  129. win32pdh.CollectQueryData(hq)
  130. print("%-15s\t" % (instance[:15]), end=" ")
  131. for hc in hcs:
  132. type, val = win32pdh.GetFormattedCounterValue(hc, win32pdh.PDH_FMT_LONG)
  133. print("%5d" % (val), end=" ")
  134. win32pdh.RemoveCounter(hc)
  135. print()
  136. win32pdh.CloseQuery(hq)
  137. # NOTE: This BrowseCallback doesn't seem to work on Vista for markh.
  138. # XXX - look at why!?
  139. # Some counters on Vista require elevation, and callback would previously
  140. # clear exceptions without printing them.
  141. def BrowseCallBackDemo(counters):
  142. ## BrowseCounters can now return multiple counter paths
  143. for counter in counters:
  144. (
  145. machine,
  146. object,
  147. instance,
  148. parentInstance,
  149. index,
  150. counterName,
  151. ) = win32pdh.ParseCounterPath(counter)
  152. result = GetPerformanceAttributes(
  153. object, counterName, instance, index, win32pdh.PDH_FMT_DOUBLE, machine
  154. )
  155. print("Value of '%s' is" % counter, result)
  156. print(
  157. "Added '%s' on object '%s' (machine %s), instance %s(%d)-parent of %s"
  158. % (counterName, object, machine, instance, index, parentInstance)
  159. )
  160. return 0
  161. def browse(
  162. callback=BrowseCallBackDemo,
  163. title="Python Browser",
  164. level=win32pdh.PERF_DETAIL_WIZARD,
  165. ):
  166. win32pdh.BrowseCounters(None, 0, callback, level, title, ReturnMultiple=True)
  167. if __name__ == "__main__":
  168. ShowAllProcesses()
  169. # Show how to get a couple of attributes by name.
  170. counter = find_pdh_counter_localized_name("Virtual Bytes")
  171. print(
  172. "Virtual Bytes = ", FindPerformanceAttributesByName("python", counter=counter)
  173. )
  174. print(
  175. "Available Bytes = ",
  176. GetPerformanceAttributes(
  177. find_pdh_counter_localized_name("Memory"),
  178. find_pdh_counter_localized_name("Available Bytes"),
  179. ),
  180. )
  181. # And a browser.
  182. print("Browsing for counters...")
  183. browse()