拿一台电脑"表演快照"

时间:2014-11-20 22:36:39

标签: c# .net performance performancecounter

我今天在工作中被要求为最终用户创建一个工具,以便他们在遇到性能问题时能够运行#34;。这是对经历极端性能问题的若干计算机和/或应用程序的越来越多的报告的反应。由于报告数量众多,我们需要自动进行此数据收集,因此我们可以在以后深入了解数据。

我已经设置了一个收集信息的后端,并且已经收集了大量信息,但是我在收集流程的性能数据时遇到了麻烦。这就是我所看到的:

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

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

2)使用PerformanceCounter

性能计数器看起来非常强大,但我在按进程ID匹配性能计数器方面遇到了麻烦,看起来性能计数器主要用于跟踪一段时间内的性能。这不是这里的情况。我们主要是在寻找一种过程模式。

基本上,我们正在寻找的(或多或少)是在任务管理器的进程列表中显示的信息的快照(进程名称,cpu周期,私有内存使用情况)并且无需运行提升的应用程序(进程列表可以限制为用户procs)。这符合我的要求。

编辑:这是我尝试使用的一些代码,抱歉没有提供任何早期

这是一个尝试使用性能计数器来获得“处理器时间百分比”的示例。和'工作集 - 私人'适用于所有流程。

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

'工作集 - 私人'的结果现在已经开始了,但是对于处理器时间而言,这些值没有任何意义。

这是一个输出示例,正如您所看到的,%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:

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

  1. 快速,不准确,炸弹CPU

    counter.NextValue();
    Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
    
  2. 在彼此之后调用NextValue()两次非常快速地收集数据,但是几乎轰炸了我的CPU(并且结果可能是次优的)。

    1. 准确,非常慢,很容易在CPU上

      counter.NextValue();
      System.Threading.Thread.Sleep(1000);
      Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
      
    2. 另一个选项是每次调用NextValue()之间的Thread.Sleep(),但这使得它非常慢(因为我们可能正在讨论100多个进程)

1 个答案:

答案 0 :(得分: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());
            }
        }
    }
}