2014-11-20 49 views
2

今天我在工作中被要求创建一个工具,让最终用户在遇到“性能问题”时运行它。这是对越来越多的几台计算机和/或应用程序遇到极端性能问题的报告的反应。由于大量的报告,我们需要这些数据收集自动发生,所以我们可以在以后深入数据。以计算机“性能快照”

我已经设置了一个后端来收集信息,并且已经收集了一堆信息,但是我在收集进程的性能数据时遇到了问题。这是我看着:

1)使用System.Diagnotics.Process.GetProcesses():

这让我所有正在运行的特效,这是很好的一个列表,但是这需要应用程序能够运行显然提升了,因为每当我想要收集UserProcessorTime时它都会抛出异常,即使这些信息对于任务管理器中的每个非管理用户来说都适用于他自己的进程。即使作为成熟的管理员用户运行,它也会引发异常。

2)使用的PerformanceCounter

性能计数器似乎很强大,但我已经遇到了麻烦,通过匹配的进程ID性能计数器,它似乎性能计数器大多用于在一段时间内跟踪性能。情况并非如此。我们主要是在寻找一种进程失控的模式。

基本上,我们正在寻找(或多或少)是在任务管理器的进程列表(进程名称,CPU周期,私有内存使用情况)中显示的信息的快速快照,而且无需应用程序运行提升(进程列表可以限制为用户特效)。这与我所问的是一致的。

编辑:下面是一些代码,我试图用,很抱歉不能提供任何早期

下面是试图使用性能计数器来获得“%处理器时间”和实例“工作集 - 私人”适用于所有流程。

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); 
      } 
     } 
    } 
} 

为“工作集 - 私人”的结果是斑上,但对于“%处理器时间”,这些价值观毫无任何意义。

下面是输出的一个例子,你可以看到,处理器时间百分比结果毫无任何意义:

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:

斯科特已经提供了答案的很大一部分,但我现在仍然面临着其他问题,下面两个选项:

  1. 快速,准确,炸弹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多个进程)

    +0

    而你的问题是什么?如何处理你所尝试的代码片段? – techvice 2014-11-20 22:40:15

    +0

    “我基本上可以如何快速查看任务管理器进程列表中显示的信息(进程名称,cpu周期,专用内存使用情况),而不需要应用程序运行提升”。我没有提供任何代码片断,因为我没有任何编写代码的麻烦,我只是不确定要使用哪些组件。另外我在睡觉之前写下了这个:) – 2014-11-20 22:44:43

    +0

    如何使用WMI访问流程信息?有些是这样的:http://www.codeproject.com/Articles/12138/Process-Information-and-Notifications-using-WMI – techvice 2014-11-20 22:49:33

    回答

    2

    你的处理器时间问题是你不应该使用RawValue就可以了(你真的不应该使用它作为工作集) 。对于处理器时间,您必须带两个样品呼叫NextValue,您会得到第二个样品,您将获得准确的数字。

    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); 
    
         //Go through each processor counter once to get the first value, should just return 0. 
         foreach (PerformanceCounter counter in counters) 
         { 
          if (counter.CounterName == "% Processor Time") 
          { 
           counter.NextValue(); 
          }    
         } 
    
         //You need to wait at least 100ms between samples to get useful values, the longer you wait the better the reading. 
         Thread.Sleep(150); 
    
         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:N1}", counter.CounterName, counter.NextValue()); 
          } 
         } 
        } 
    } 
    
    +0

    谢谢!那样做了。我之前尝试过使用NextValue(),但我认为它会在初始化和第一次调用NextValue()之间进行度量,所以我只用了一次。尽管如此,仍有一些麻烦。在彼此之后两次调用NextValue()以非常快的速度收集数据,但几乎会轰炸我的CPU(并且结果可能不是最佳的)。另一种选择是每次调用NextValue()之间的Thread.Sleep(),但这会使其非常缓慢(因为我们可能在谈论100多个进程) – 2014-11-23 01:57:18

    +0

    对于您编辑的“快速不准确的炸弹CPU”解决方案对于你的问题,你忽略了我在例子中提出的评论:“你需要在样本之间等待至少100ms才能获得有用的值,你等待阅读的时间越长。”如果你没有等待至少100ms,你只会得到0或100从NextValue的结果,请参见[这是我的旧答案](http://stackoverflow.com/questions/8462331/i-need-to-call-accurate-cpu-usage-of-a-single-过程/ 8462977#8462977)了解更多信息。不要每个进程等待一次,读取所有进程一次,等待100毫秒一次,然后再次读取所有进程。 – 2014-11-23 03:04:32

    +0

    好的答案,我从来没有想过只为所有计数器执行一次Thread.Sleep,实际上应该始终如此。不像其他所有其他的例子,在每个柜台都进行了睡眠(我猜是因为问题总是单计数器) – 2015-05-12 16:10:34