Exception: Instance 'Name of instance' does not exist in the specified Category
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");
精彩评论