性能计数器实例名称与进程名称

时间:2015-04-28 14:57:54

标签: c# process performancecounter

我正在连接Process类别中的各种效果计数器。我使用以下c#方法来确定获取计数器时要使用的实例名称

private const string _categoryName = "Process";
private const string _processIdCounter = "ID Process";

public static bool TryGetInstanceName(Process process, out string instanceName)
{
    PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
    string[] instanceNames = processCategory.GetInstanceNames();
    foreach (string name in instanceNames)
    {
        using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
        {
            if (process.Id == (int)processIdCounter.RawValue)
            {
                instanceName = name;
                return true;
            }
        }
    }

    instanceName = null;
    return false;
}

现在,我注意到返回的实例名称通常与Process.ProcessName的值相匹配。

实例名称和流程名称如何相关?

我问,因为我想简化例程中的foreach循环,这样我就不必为那些与当前进程不匹配的实例获取ID Process计数器。我设想了一个可能看起来像这样的最终方法:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
    PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
    string[] instanceNames = processCategory.GetInstanceNames();
    foreach (string name in instanceNames)
    {
        if (name /* more or less matches */ process.ProcessName)
        {
            using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
            {
                // ...
            }
        }
    }

    instanceName = null;
    return false;
}

3 个答案:

答案 0 :(得分:9)

看到答案没有到来,我做了一些试验和错误测试并发现了以下行为:

常规流程

对于具有给定名称的第一个常规进程,进程名称似乎与实例名称匹配。对于具有相同名称的后续流程,通过附加#1#2,...来修改实例名称。

令人震惊的是,似乎可以更改与进程关联的实例名称。这似乎发生在数字序列中较早的进程结束时。确定实例名称和获取相关计数器之间存在竞争条件!

服务流程

在服务控制管理器下运行的Windows NT服务的行为方式与常规流程的行为方式相同。如果您在数字序列中较早结束服务进程,则实例名称似乎也会更改。

ASP.NET应用程序

相同的假设适用于IIS下托管的应用程序,但进程名称为w3wp。不同的应用。池肯定会通过启动和停止应用程序获得不同的进程。我确定实例名称在上述相同的情况下以相同的方式更改。

<强>结论

我的结论是实例名称始终进程名称开头,方法可以修改如下:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
    PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
    string[] instanceNames = processCategory.GetInstanceNames();
    foreach (string name in instanceNames)
    {
        if (name.StartsWith(process.ProcessName))
        {
            using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
            {
                if (process.Id == (int)processIdCounter.RawValue)
                {
                    instanceName = name;
                    return true;
                }
            }
        }
    }

    instanceName = null;
    return false;
}

此外,当使用返回的实例名称时,确认存在上述竞争条件至关重要。

(如果没有进一步的输入,我会接受这个作为答案。请随意纠正我。)

答案 1 :(得分:0)

这个解决方案不会更快一点:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
    PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
    string processName = Path.GetFileNameWithoutExtension(process.ProcessName);

    string[] instanceNames = processCategory.GetInstanceNames()
            .Where(inst => inst.StartsWith(processName))
            .ToArray();
    foreach (string name in instanceNames)
    {
            using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
            {
                if (process.Id == (int)processIdCounter.RawValue)
                {
                    instanceName = name;
                    return true;
                }
            }
    }

    instanceName = null;
    return false;
}

(从Rick Strahl's blog复制并修改了一下)。

然而,您需要注意:如果有多个进程具有相同的名称并且其中一个进程退出,则所有进程的命名都会更改:

  

与Windows流程实例名称相关的一件事是,当其中一个进程退出时,它们会动态更改。

     

例如,如果#8铬离开,则#9铬将变为#8铬,而#10>铬将变为#9铬。此时获取先前为chrome#10创建的计数器&gt;的值将引发异常。这个   如果你想监视多个实例,真的很烦人   多个流程,因为它涉及监控流程退出和   重新创建所有计数器(非常难看)。

     

一种方法是改变生成流程实例名称的方式&gt;(参见http://support.microsoft.com/kb/281884)但这有   使用perfmon api影响其他应用程序的可能性。

答案 2 :(得分:0)

另请注意,如果您正在监视同一进程的多个实例,则实例命名在不同类别中不一致。因此,上面给出的解决方案仅适用于从提取pid的同一类别中提取计数器的情况。我确实发现pid在其他一些类别中 - 但不是全部 - 并且没有一致的命名。