Todo: 集成多平台 解决因SaiNiu线程抢占资源问题 本地提交测试环境打包 和 正式打包脚本与正式环境打包bat 提交Python32环境包 改进多日志文件生成情况修改打包日志细节
This commit is contained in:
212
Utils/PythonNew32/Lib/site-packages/win32/lib/win32pdhutil.py
Normal file
212
Utils/PythonNew32/Lib/site-packages/win32/lib/win32pdhutil.py
Normal file
@@ -0,0 +1,212 @@
|
||||
"""Utilities for the win32 Performance Data Helper module
|
||||
|
||||
Example:
|
||||
To get a single bit of data:
|
||||
>>> import win32pdhutil
|
||||
>>> win32pdhutil.GetPerformanceAttributes("Memory", "Available Bytes")
|
||||
6053888
|
||||
>>> win32pdhutil.FindPerformanceAttributesByName("python", counter="Virtual Bytes")
|
||||
[22278144]
|
||||
|
||||
First example returns data which is not associated with any specific instance.
|
||||
|
||||
The second example reads data for a specific instance - hence the list return -
|
||||
it would return one result for each instance of Python running.
|
||||
|
||||
In general, it can be tricky finding exactly the "name" of the data you wish to query.
|
||||
Although you can use <om win32pdh.EnumObjectItems>(None,None,(eg)"Memory", -1) to do this,
|
||||
the easiest way is often to simply use PerfMon to find out the names.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
import win32pdh
|
||||
|
||||
error = win32pdh.error # Re-exported alias
|
||||
|
||||
# Handle some localization issues.
|
||||
# see https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/287159
|
||||
# Build a map of english_counter_name: counter_id
|
||||
counter_english_map: dict[str, int] = {}
|
||||
|
||||
|
||||
def find_pdh_counter_localized_name(english_name, machine_name=None):
|
||||
if not counter_english_map:
|
||||
import win32api
|
||||
import win32con
|
||||
|
||||
counter_reg_value = win32api.RegQueryValueEx(
|
||||
win32con.HKEY_PERFORMANCE_DATA, "Counter 009"
|
||||
)
|
||||
counter_list = counter_reg_value[0]
|
||||
for i in range(0, len(counter_list) - 1, 2):
|
||||
try:
|
||||
counter_id = int(counter_list[i])
|
||||
except ValueError:
|
||||
continue
|
||||
counter_english_map[counter_list[i + 1].lower()] = counter_id
|
||||
return win32pdh.LookupPerfNameByIndex(
|
||||
machine_name, counter_english_map[english_name.lower()]
|
||||
)
|
||||
|
||||
|
||||
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 https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/262938
|
||||
# and https://web.archive.org/web/20040926105842/http://msdn.microsoft.com:80/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)
|
||||
type, val = win32pdh.GetFormattedCounterValue(hc, format)
|
||||
return val
|
||||
finally:
|
||||
win32pdh.RemoveCounter(hc)
|
||||
finally:
|
||||
win32pdh.CloseQuery(hq)
|
||||
|
||||
|
||||
def FindPerformanceAttributesByName(
|
||||
instanceName,
|
||||
object=None,
|
||||
counter=None,
|
||||
format=win32pdh.PDH_FMT_LONG,
|
||||
machine=None,
|
||||
bRefresh=0,
|
||||
):
|
||||
"""Find performance attributes by (case insensitive) instance name.
|
||||
|
||||
Given a process name, return a list with the requested attributes.
|
||||
Most useful for returning a tuple of PIDs given a process name.
|
||||
"""
|
||||
if object is None:
|
||||
object = find_pdh_counter_localized_name("Process", machine)
|
||||
if counter is None:
|
||||
counter = find_pdh_counter_localized_name("ID Process", machine)
|
||||
if bRefresh: # PDH docs say this is how you do a refresh.
|
||||
win32pdh.EnumObjects(None, machine, 0, 1)
|
||||
instanceName = instanceName.lower()
|
||||
items, instances = win32pdh.EnumObjectItems(None, None, object, -1)
|
||||
# Track multiple instances.
|
||||
instance_dict = {}
|
||||
for instance in instances:
|
||||
try:
|
||||
instance_dict[instance] += 1
|
||||
except KeyError:
|
||||
instance_dict[instance] = 0
|
||||
|
||||
ret = []
|
||||
for instance, max_instances in instance_dict.items():
|
||||
for inum in range(max_instances + 1):
|
||||
if instance.lower() == instanceName:
|
||||
ret.append(
|
||||
GetPerformanceAttributes(
|
||||
object, counter, instance, inum, format, machine
|
||||
)
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def ShowAllProcesses():
|
||||
object = find_pdh_counter_localized_name("Process")
|
||||
items, instances = win32pdh.EnumObjectItems(
|
||||
None, None, object, win32pdh.PERF_DETAIL_WIZARD
|
||||
)
|
||||
# Need to track multiple instances of the same name.
|
||||
instance_dict = {}
|
||||
for instance in instances:
|
||||
try:
|
||||
instance_dict[instance] += 1
|
||||
except KeyError:
|
||||
instance_dict[instance] = 0
|
||||
|
||||
# Bit of a hack to get useful info.
|
||||
items = [find_pdh_counter_localized_name("ID Process")] + items[:5]
|
||||
print("Process Name", ",".join(items))
|
||||
for instance, max_instances in instance_dict.items():
|
||||
for inum in range(max_instances + 1):
|
||||
hq = win32pdh.OpenQuery()
|
||||
hcs = []
|
||||
for item in items:
|
||||
path = win32pdh.MakeCounterPath(
|
||||
(None, object, instance, None, inum, item)
|
||||
)
|
||||
hcs.append(win32pdh.AddCounter(hq, path))
|
||||
win32pdh.CollectQueryData(hq)
|
||||
# as per https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/262938
|
||||
# some "%" based counters need two collections
|
||||
time.sleep(0.01)
|
||||
win32pdh.CollectQueryData(hq)
|
||||
print("%-15s\t" % (instance[:15]), end=" ")
|
||||
for hc in hcs:
|
||||
type, val = win32pdh.GetFormattedCounterValue(hc, win32pdh.PDH_FMT_LONG)
|
||||
print("%5d" % (val), end=" ")
|
||||
win32pdh.RemoveCounter(hc)
|
||||
print()
|
||||
win32pdh.CloseQuery(hq)
|
||||
|
||||
|
||||
# NOTE: This BrowseCallback doesn't seem to work on Vista for markh.
|
||||
# XXX - look at why!?
|
||||
# Some counters on Vista require elevation, and callback would previously
|
||||
# clear exceptions without printing them.
|
||||
def BrowseCallBackDemo(counters):
|
||||
## BrowseCounters can now return multiple counter paths
|
||||
for counter in counters:
|
||||
(
|
||||
machine,
|
||||
object,
|
||||
instance,
|
||||
parentInstance,
|
||||
index,
|
||||
counterName,
|
||||
) = win32pdh.ParseCounterPath(counter)
|
||||
|
||||
result = GetPerformanceAttributes(
|
||||
object, counterName, instance, index, win32pdh.PDH_FMT_DOUBLE, machine
|
||||
)
|
||||
print("Value of '%s' is" % counter, result)
|
||||
print(
|
||||
"Added '%s' on object '%s' (machine %s), instance %s(%d)-parent of %s"
|
||||
% (counterName, object, machine, instance, index, parentInstance)
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
def browse(
|
||||
callback=BrowseCallBackDemo,
|
||||
title="Python Browser",
|
||||
level=win32pdh.PERF_DETAIL_WIZARD,
|
||||
):
|
||||
win32pdh.BrowseCounters(None, 0, callback, level, title, ReturnMultiple=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ShowAllProcesses()
|
||||
# Show how to get a couple of attributes by name.
|
||||
counter = find_pdh_counter_localized_name("Virtual Bytes")
|
||||
print(
|
||||
"Virtual Bytes = ", FindPerformanceAttributesByName("python", counter=counter)
|
||||
)
|
||||
print(
|
||||
"Available Bytes = ",
|
||||
GetPerformanceAttributes(
|
||||
find_pdh_counter_localized_name("Memory"),
|
||||
find_pdh_counter_localized_name("Available Bytes"),
|
||||
),
|
||||
)
|
||||
# And a browser.
|
||||
print("Browsing for counters...")
|
||||
browse()
|
||||
Reference in New Issue
Block a user