Windows PerfMon与对应WMI类性能计数器数值不一致的解决问询
性能计数器WMI与PerfMon数值不一致的解决方法
核心原因
PerfMon默认展示的是指定采样间隔内的平均值,而WMI直接返回的Win32_PerfFormattedData_*类数值或瞬时查询的原始值,采样逻辑和PerfMon不同,导致数值波动大。要得到和PerfMon一致的结果,必须用原始性能计数器类(Win32_PerfRawData_*)手动计算时间间隔内的平均值。
解决思路
PerfMon的计算逻辑是多次采样原始累计值,通过时间差和数值差计算平均速率/百分比。我们需要复刻这个逻辑:
- 两次查询原始WMI类的累计计数器值和时间戳
- 计算两个采样点的数值差与时间差
- 根据计数器类型套用对应公式得到平均值
示例脚本(以CPU用户时间为例)
以下脚本模拟PerfMon的采样逻辑,计算和它一致的平均CPU用户时间:
# 配置目标计数器的原始WMI类和属性 $targetClass = "Win32_PerfRawData_PerfOS_Processor" $counterName = "PercentUserTime" $timestampName = "Timestamp_Sys100NS" $filter = "Name='_Total'" # 针对总CPU,若要单个核心可修改Name值 # 第一次采样(获取初始累计值和时间戳) $sampleInitial = Get-WmiObject -Class $targetClass -Filter $filter $valInitial = $sampleInitial.$counterName $timeInitial = $sampleInitial.$timestampName # 等待采样间隔(和PerfMon默认一致,设为1秒) Start-Sleep -Seconds 1 # 第二次采样(获取结束累计值和时间戳) $sampleFinal = Get-WmiObject -Class $targetClass -Filter $filter $valFinal = $sampleFinal.$counterName $timeFinal = $sampleFinal.$timestampName # 处理32位累计值溢出问题(累计值达到最大值后会归零) if ($valFinal -lt $valInitial) { $valDiff = $valFinal + [uint32]::MaxValue - $valInitial + 1 } else { $valDiff = $valFinal - $valInitial } $timeDiff = $timeFinal - $timeInitial # 计算平均百分比(CPU类计数器公式:(数值差/时间差)*100) $average = ($valDiff / $timeDiff) * 100 # 输出结果(保留2位小数) Write-Host "平均CPU用户时间: $($average.ToString('N2'))%"
关键注意事项
- 计数器类型适配:不同计数器的计算公式不同:
- 百分比类(如CPU、内存使用率):
(数值差/时间差)*100 - 速率类(如磁盘IOPS、网络吞吐量):
数值差/(时间差/10000000)(时间差单位为100纳秒,转换为秒需除以1e7)
- 百分比类(如CPU、内存使用率):
- 采样间隔匹配:PerfMon默认采样间隔为1秒,可根据需求调整
Start-Sleep的时长,或多次采样取平均进一步稳定结果 - 远程集群适配:在集群环境下,只需添加
-ComputerName和-Credential参数即可远程查询:$sampleInitial = Get-WmiObject -Class $targetClass -Filter $filter -ComputerName "ClusterNode01" -Credential $cred - WMI类对应关系:可通过PerfMon的计数器属性查看对应的原始WMI类,或用
Get-Counter -ListSet *找到计数器对应的RawData类
内容的提问来源于stack exchange,提问作者Qxlkdr
相关产品推荐
相关产品推荐

