即使进程尚未退出,进程的性能计数器实例名称是否也会更改

时间:2012-08-09 14:36:59

标签: c#

我正在使用这个类作为一类测试的基类,这些测试启动一个进程并给它一些输入,并在给它更多输入之前等待它变为空闲。

public abstract class TestProcessLaunchingBase
{
    protected PerformanceCounter PerfCounter { get; set; }

    protected void WaitForProcessIdle()
    {
        while (true)
        {
            float oldValue = PerfCounter.NextValue();

            Thread.Sleep(1000);

            float nextValue = PerfCounter.NextValue();

            if (nextValue == 0)
                break;
        }
    }

    protected void FindSpawnedProcessPerfCounter(int processId)
    {
        PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
        string[] instances = cat.GetInstanceNames();
        foreach (string instance in instances)
        {
            using (PerformanceCounter cnt = new PerformanceCounter("Process", "ID Process", instance, true))
            {
                int val = (int)cnt.RawValue;
                if (val == processId)
                {
                    PerfCounter = new PerformanceCounter("Process", "% Processor Time", instance);
                    break;
                }
            }

        }

        Assert.IsNotNull(PerfCounter, "Failed to perf counter");
    }
}

这些测试偶尔会失败,因为PerfCounter.NextValue()会抛出

  

System.InvalidOperationException   实例'foobar#2'在指定的类别

中不存在

似乎性能计数器的实例名称不是持久性的。

如果有三个foobar进程,则可能有实例名称

  • foobar pid 5331
  • foobar#1 pid 5332
  • foobar#2 pid 5333

似乎 pid 5332 退出 foobar#2 变为 foobar#1

问题:

  1. 这是记录在案的行为吗?你能坚持一个性能指标吗?你每次都要查一查吗?

  2. 或者,是否有一个性能计数器可以为名为 foobar

  3. 的所有进程提供处理器时间

2 个答案:

答案 0 :(得分:9)

我过去已经遇到过这个问题。实例名称的ProcessName#InstanceNumber模式显然是微软的一个不好的选择,你知道为什么:)

所以基本上你有两个选择:

1)每次使用PerformanceCounter方法创建一个新的FindSpawnedProcessPerfCounter个实例。

2)按照KB281884中描述的步骤将模式从ProcessName#InstanceNumber更改为ProcessName_ProcessID

第一个解决方案的问题是每次都需要一些CPU时间来构建一个新实例。

第二种解决方案的问题是注册表修改还会影响同时使用此性能计数器的所有程序。并且它需要在启动您的应用程序之前修改注册表。

您拥有的最后一个选项是根本不使用性能计数器。如果您只对ProcessorTime信息感兴趣,可以使用P / Invoke调用一些Kernel32函数来检索它。

编辑:

Process课程还提供UserProcessorTimePrivilegedProcessorTime (kernel processor time)属性。两者都返回TimeSpan实例(=时间量),因此要检索一定百分比的处理器时间,您必须自己进行一些计算(包括刷新周期和处理器时间)。

答案 1 :(得分:0)

如果必须使用性能计数器,我的方法是在遇到异常时重新创建性能计数器。

当抛出异常时,处理旧的性能计数器,然后使用进程ID为foobar测试的所有实例创建新的性能计数器实例。这里有一个很好的stackoverflow帖子:Performance Counter by Process ID instead of name?

我假设你的语句“启动一个进程并给它一些输入”,你在启动它之后保持进程id。因此,您始终拥有一组要监视的正在运行的测试过程。

使用此技术,只有在遇到异常时才会导致性能下降。

正如@ ken2k已经指出的那样,您可以更改性能计数器的命名约定以保持一致性。根据我的经验,性能计数器有时会因为看似意外的原因而遇到任何数量的异常。因此,即使您确实更改了性能计数器名称,也可以在必要时重新创建性能计数器。