mik*_*see 3 c# windows performance performancecounter query-performance
我试图实现一个性能监视工具,我想监视内存和CPU等基本内容.
我试图通过使用性能计数器这样做,因为我相信这是在C#中查询进程性能的"正确"方法,这是一些示例代码:
class Program
{
static void Main(string[] args)
{
while (true)
{
var pcs = Process.GetProcesses()
.Select(p => new PerformanceCounter("Process", "Working Set - Private", p.ProcessName));
var sw = Stopwatch.StartNew();
foreach (var pc in pcs)
pc.NextValue();
Console.WriteLine($"Time taken to read {pcs.Count()} performance counters: {sw.ElapsedMilliseconds}ms");
Thread.Sleep(1000);
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以很明显〜在我的系统上查询进程大约12.5毫秒是不可接受的慢.它应该如何完成?
我已经在这篇文章中提到了一个相关问题:性能计数器读取访问速度非常慢 - 任务管理器如何做到这一点?
但我意识到我在那篇文章中并不够具体,并且问了错误的问题.我真的想知道我怎么能用性能计数器做我想做的事情,或者根本不可能做到这一点?
编辑1:
我正在运行Windows 10 Pro 1607 - Build 14393.479
Han*_*ant 11
当你对机器上所有正在运行的进程执行某些操作时,Windows有点臭名昭着.但这太过分了.在PerformanceCounter状态下有一些东西腐烂了,我从这个问题得到了第一个提示.您可以通过更改Console.WriteLine()调用在您自己的测试程序中轻松查看的内容:
Console.Write($"Time taken to read {pcs.Count()} performance counters:");
Console.WriteLine($"{sw.ElapsedMilliseconds}ms, {GC.CollectionCount(2)} collections");
Run Code Online (Sandbox Code Playgroud)
我机器上的输出:
Time taken to read 124 performance counters: 1633ms, 15 collections
Time taken to read 124 performance counters: 923ms, 30 collections
Time taken to read 124 performance counters: 928ms, 45 collections
Time taken to read 124 performance counters: 934ms, 59 collections
Time taken to read 124 performance counters: 922ms, 74 collections
Time taken to read 124 performance counters: 925ms, 89 collections
...etc
Run Code Online (Sandbox Code Playgroud)
或者换句话说,对于每次调用PerformanceCounter.NextValue()的~8次调用的完整垃圾收集.哎哟.是的,这会让你的计划陷入困境.
说得客气一点,这是非常奇怪的行为.我在PerformanceCounter类本身找不到任何好的提示,代码看起来非常无辜.很难看到很多非托管代码(C:\ Windows\Microsoft.NET\Framework\v4.0.30319\PerfCounter.dll),但查看其依赖关系并不能提供令人信服的证据证明它是负责.在v2.0.50727和v4.0.30319运行时版本上都会发生这种情况,因此V4.x中的一个不幸的黑客攻击并不容易解释它.它不是8的很好的倍数所以一个强制终结器运行的简单计数器不容易解释它.它不是本机性能计数器,使用WMI查询它不会触发任何集合.它不是特定于内存计数器,查询,例如,"线程计数"也是如此.可能与Windows版本有关,我的是Win10版本1607(不能轻易测试另一个版本).
微软需要参与其中.我链接的问题的作者似乎已经为它创建了一个错误反馈报告,我添加了这个Q + A作为支持证据.留意反馈报告,投票给它,希望他们会开始关注.或者,如果您不想等待,请直接与Microsoft支持部门联系.
同时,您可以继续使用System.Management命名空间.WMI Code Creator实用程序非常便于自动生成代码:
...
using System.Management; // Project > Add Reference required
public static void QueryWorkingset() {
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT Name, WorkingSetPrivate FROM Win32_PerfRawData_PerfProc_Process");
foreach (ManagementObject queryObj in searcher.Get()) {
Console.WriteLine("{0}: {1}", queryObj["Name"], queryObj["WorkingSetPrivate"]);
}
}
Run Code Online (Sandbox Code Playgroud)
仍然没有速度恶魔,在我的机器上每个进程大约需要1.0毫秒.但是不像PerformanceCounter那样烧掉100%的核心,也没有强制收集.