【发布时间】:2014-11-20 22:36:39
【问题描述】:
我今天在工作中被要求创建一个工具,供最终用户在遇到“性能问题”时运行。这是对越来越多的关于几台计算机和/或应用程序遇到极端性能问题的报告的反应。由于报告数量众多,我们需要自动收集此数据,以便稍后深入研究数据。
我已经设置了一个后端来收集信息,并且已经在收集大量信息,但是我在收集进程的性能数据时遇到了麻烦。这是我调查的内容:
1) 使用 System.Diagnotics.Process.GetProcesses():
这为我提供了所有正在运行的 proc 的列表,这很好,但这要求应用程序能够明显提升运行,因为每当我想收集 UserProcessorTime 时它都会抛出异常,即使此信息可用于每个非-admin 用户在任务管理器中用于他自己的进程。即使以成熟的管理员用户身份运行,它也会引发异常。
2) 使用性能计数器
性能计数器似乎非常强大,但我在按进程 ID 匹配性能计数器时遇到了麻烦,而且性能计数器似乎主要用于跟踪一段时间内的性能。这不是这里的情况。我们主要是在寻找一种流程失控的模式。
基本上,我们正在寻找的(或多或少)是任务管理器的进程列表中显示的信息的快速快照(进程名称、cpu 周期、私有内存使用情况),而无需应用程序运行提升(进程列表可以限制为用户进程)。这符合我的要求。
编辑:这是我尝试使用的一些代码,抱歉之前没有提供任何代码
这是一个尝试使用性能计数器来获取所有进程的“% Processor Time”和“Working Set - Private”的示例。
PerformanceCounterCategory perfCategory = PerformanceCounterCategory.GetCategories().First(c => c.CategoryName == "Process");
Console.WriteLine("{0} [{1}]", perfCategory.CategoryName, perfCategory.CategoryType);
string[] instanceNames = perfCategory.GetInstanceNames();
if (instanceNames.Length > 0)
{
foreach (string instanceName in instanceNames)
{
Console.WriteLine(" {0}", instanceName);
PerformanceCounter[] counters = perfCategory.GetCounters(instanceName);
foreach (PerformanceCounter counter in counters)
{
if (counter.CounterName == "Working Set - Private")
{
Console.WriteLine(" {0} - {1}", counter.CounterName, counter.RawValue, counter.RawValue / 1024);
}
if (counter.CounterName == "% Processor Time")
{
Console.WriteLine(" {0} - {1}", counter.CounterName, counter.RawValue);
}
}
}
}
“Working Set - Private”的结果是正确的,但对于“% Processor Time”,这些值毫无意义。
这是一个输出示例,如您所见,% Processor Time 结果毫无意义:
WDExpress#1
% Processor Time - 378146424
Working Set - Private - 136257536
taskhost
% Processor Time - 129480830
Working Set - Private - 1835008
svchost
% Processor Time - 2877438445
Working Set - Private - 4096000
IpOverUsbSvc
% Processor Time - 15600100
Working Set - Private - 1236992
vncserver
% Processor Time - 238213527
Working Set - Private - 2555904
chrome#21
% Processor Time - 1652830595
Working Set - Private - 56799232
编辑 2:
Scott 已经提供了大部分答案,但现在我仍然面临以下两个选项的其他问题:
-
快速,不准确,轰炸 CPU
counter.NextValue(); Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
在彼此之后调用 NextValue() 两次可以非常快速地收集数据,但几乎会轰炸我的 CPU(并且结果可能不是最佳的)。
-
准确,非常慢,在 CPU 上很容易
counter.NextValue(); System.Threading.Thread.Sleep(1000); Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
另一种选择是在每次调用 NextValue() 之间使用 Thread.Sleep(),但这会使其非常慢(因为我们可能正在谈论 100 多个进程)
【问题讨论】:
-
你的问题到底是什么?您尝试过的一些代码 sn-ps 怎么样?
-
“我怎样才能快速快照显示在任务管理器的进程列表中的信息(进程名称、cpu 周期、私有内存使用情况),而无需运行提升的应用程序”基本上。我没有提供任何 sn-ps,因为我在编写代码时没有任何问题,我只是不确定要使用哪些组件。我也是在临睡前写的:)
-
使用 WMI 访问进程信息怎么样?比如:codeproject.com/Articles/12138/…
-
您想收集哪些信息?我看到的唯一具体提到的是
UserProcessorTime。在我们告诉您如何收集之前,我们需要知道您想要收集什么。此外,通常“性能快照”确实使用性能计数器,并在几秒到几分钟之间为您提供信息的运行平均值。单个时刻快照没有那么有用。 (例如,如果某个进程敲击了 HDD 的 IO,但每分钟只执行一次,持续 20 秒。如果您的即时快照不在该窗口中,您将看不到它) -
@techvice 我在几个地方读到,使用 WMI 会非常慢(不能引用任何消息来源,我很抱歉)。但我会调查一下。
标签: c# .net performance performancecounter