Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Naming multi-instance performance counters in .NET

Most multiple instance performance counters in Windows seem to automatically(?) have a #n on the end if there's more than one instance with the same name.

For example: if, in Perfmon, you look under the Process category, you'll see:

...
dwm
explorer
explorer#1
...

I have two explorer.exe processes, so the second counter has #1 appended to its name.

When I attempt to do this in a .NET application:

  • I can create the category, and register the instance (using the PerformanceCounterCategory.Create that takes a CounterCreationDataCollection).
  • I can open the counter for write and write to it.

When I open the counter a second time (in another process), it opens the same counter. This means that I have two processes fighting over the counters.

The documentation for PerformanceCounter.InstanceName states that # is not allowed in the name.

So: how do I have multiple-instance performance counters that are actually multiple instance? And where the second (and subsequent) instances get #n appended to the name?

That is: I know that I can put the process ID (e.g.) on the instance name. This works, but has the unfortunate side effect that restarting the process results in a new PID, and Perfmon continues monitoring the old counter.

Update:

I'm creating the category (and counter) as follows:

const string categoryName = "Test App";
const string counterName = "Number of kittens";
string instanceName =
    Path.GetFileNameWithoutExtension(
        Process.GetCurrentProcess().MainModule.FileName);

if (!PerformanceCounterCategory.Exists(categoryName))
{
    var counterCreationDataCollection = new CounterCreationDataCollection
        {
            new CounterCreationData(counterName, "",
                PerformanceCounterType.NumberOfItems32)
        };

    PerformanceCounterCategory.Create(categoryName, "",
        PerformanceCounterCategoryType.MultiInstance,
        counterCreationDataCollection);
}

I'm opening the counter as follows:

PerformanceCounter counter = new PerformanceCounter(
        categoryName, counterName, instanceName, readOnly: false);
like image 798
Roger Lipscombe Avatar asked Jun 07 '10 15:06

Roger Lipscombe


1 Answers

I think your issue is with the fact the .NET is more loose in regards to performance counters, and is actually bypassing the PerfLib Win API.

When using the native PerfLib API, you register categories during setup - and create instances from the process using handles. So with native API there is no straightforward way to share a counter instance. So when two counter instances are accessed with the same name, they actually have different handles and are marked by # appropriately.

In .NET as you simply address a counter and instance by name, you are in danger of cross updates. As .NET takes the name and enumerates(using the WMI) the instances even if they are being used by a different application.

I think that adding the PID* is indeed the smartest solution - as you both have better track-ability and no collision. Regarding the issue with restart creating a new counter, I fail to see the problem; if you allow more than one instance of the process to run at a given time how would you know if this instance was created due to a restart or simply running another executable?

If you do have a dependency of some sort between the processes, you can cleanup stale counters or employ some other logic. While in PerfMon you can watch "*" all instances.

*Or if you have some logic behind the process, which is maintained without regard to restarts - such as a task id of some sort.

like image 56
maximbr Avatar answered Oct 23 '22 03:10

maximbr