15

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

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 进程,它们可能具有实例名称

  • foob​​ar pid 5331
  • foob​​ar #1 pid 5332
  • foob​​ar #2 pid 5333

似乎pid 5332 exits foobar #2变成foobar #1

问题:

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

  2. 或者,是否有一个性能计数器可以为所有名为foobar的进程提供处理器时间

4

2 回答 2

9

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

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

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

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

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

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

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

编辑:

该类Process还提供UserProcessorTimePrivilegedProcessorTime(内核处理器时间) 属性。两者都返回一个TimeSpan实例(=时间量),因此要检索处理器时间的百分比,您必须自己进行一些计算(涉及刷新周期和处理器时间)。

于 2012-08-13T17:22:38.290 回答
0

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

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

我假设您的声明“启动一个进程并给它一些输入”,您在启动它后保留了进程 ID。所以你总是有一个你想要监控的正在运行的测试进程的集合。

使用这种技术,您只会在遇到异常时招致性能损失。

As @ken2k already pointed out, you can change the naming convention of the performance counters for consistency. In my experience performance counters can encounter any number exceptions sometimes for seemingly unexpected reasons. So even if you do change the performance counters name, it might be nice to be able to re-create your performance counters if necessary.

于 2012-08-20T16:10:17.787 回答