开发者

Exception: Instance 'Name of instance' does not exist in the specified Category

开发者 https://www.devze.com 2023-03-02 03:29 出处:网络
When I create and use performance counters like this: private readonly PerformanceCounter _cpuPerformanceCounter;

When I create and use performance counters like this:

private readonly PerformanceCounter _cpuPerformanceCounter;
public ProcessViewModel(Process process)
        {

             _cpuPerformanceCounter = new PerformanceCounter("Process", "% Proces开发者_开发知识库sor Time", process.ProcessName, true);
        }

public void Update()
        {
            CPU = (int)_cpuPerformanceCounter.NextValue() / Environment.ProcessorCount; // Exception
        }

... I get an exception Instance 'Name of instance' does not exist in the specified Category and don't understand why.

P.S. Code

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.net>
    <settings>
      <performanceCounters enabled="true"/>
    </settings>
  </system.net>
</configuration>

... included in App.config.


Adding on to previous posts, I have seen processes being formatted like <ProcessName>_<ProcessId> - depending on the OS you are running your app on (Win XP, Win Vista, Win 7, Win 2003 or 2008 Server). In order to have a reliable way to identify your process name for obtaining other performance counters down the road, a function could look like this:

    private string ObtainProcessName()
    {
        string baseProcessName;
        string processName = null;
        int processId;
        bool notFound = true;
        int processOptionsChecked = 0;
        int maxNrOfParallelProcesses = 3 + 1;

        try
        {
            baseProcessName = Process.GetCurrentProcess().ProcessName;
        }
        catch (Exception exception)
        {
            return null;
        }

        try
        {
            processId = Process.GetCurrentProcess().Id;
        }
        catch (Exception exception)
        {
            return null;
        }

        while (notFound)
        {
            processName = baseProcessName;
            if (processOptionsChecked > maxNrOfParallelProcesses)
            {
                break;
            }

            if (1 == processOptionsChecked)
            {
                processName = string.Format("{0}_{1}", baseProcessName, processId);
            }
            else if (processOptionsChecked > 1)
            {
                processName = string.Format("{0}#{1}", baseProcessName, processOptionsChecked - 1);
            }

            try
            {
                PerformanceCounter counter = new PerformanceCounter("Process", "ID Process", processName);
                if (processId == (int)counter.NextValue())
                {
                    notFound = !true;
                }
            }
            catch (Exception)
            {
            }
            processOptionsChecked++;
        }
        return processName;
    }


I think your issue happens when there are more than one process with the same name. What PerfMon does then is append #1, #2, etc to the process name. So that means MyApp.exe executed twice will cause this exception when you try to read the performance monitor for "MyApp". Here's a link to one way of solving this: Read performance counters by pid


Here is my solution for all processes and multiple process instances:

var processes = Process.GetProcesses().GroupBy(g => g.ProcessName);
        List<Tuple<string, PerformanceCounter>> pcList = new List<Tuple<string, PerformanceCounter>>();
        foreach (var pg in processes)
        {
            if (pg.First().ProcessName == "Idle")
                continue;

            if (pg.Count() == 1)
            {
                var process_cpu = new PerformanceCounter(
                           "Process",
                           "% Processor Time",
                           pg.First().ProcessName
                                );
                process_cpu.NextValue();
                pcList.Add(new Tuple<string, PerformanceCounter>(pg.First().ProcessName, process_cpu));
            }
            else
            {
                int id = 1;
                foreach(var p in pg)
                {
                    var process_cpu = new PerformanceCounter(
                           "Process",
                           "% Processor Time",
                           p.ProcessName + "#" + id
                                );
                    process_cpu.NextValue();
                    pcList.Add(new Tuple<string, PerformanceCounter>(p.ProcessName + "#" + id, process_cpu));
                    id++;
                }
            }
        }


The origninal format that used a pid suffix (registry ProcessNameFormat = 1) appears to have changed as of .NET 4.5 (msdn link) to "processame_pid_rid". Thus, the accepted answer as currently written may no longer work for that case.

This solution should still work for the newer formats:

https://weblog.west-wind.com/posts/2014/Sep/27/Capturing-Performance-Counter-Data-for-a-Process-by-Process-Id

However all these matching solutions may be prone to a race condition where the instance name changes due to a process exiting (#9 becomes #8) just after the instance name was determined but before the new PerformanceCounter() was allocated.

It would make much more sense for MS to provide a PerformanceCounter constructor that accepts a Pid (and possibly now RuntimeId?) directly since the instance names can change on the fly.


You can check this code

Use > new PerformanceCounter("Processor Information", "% Processor Time", "_Total");
Instead of> new PerformanceCounter("Processor", "% Processor Time", "_Total");
0

精彩评论

暂无评论...
验证码 换一张
取 消