PerformanceCounter creation take a LONG time
Asked Answered
S

2

7

I'm working on a charge balancing system and thus I need to know the charge of each machine. PerformanceCounter seem the way to go, but creating the first one take between 38 and 60 sec. Each subsequent new Counter or 'NextValue' call is nearly instant however.

Here is the code I'm using :

[TestClass]
public class PerfMon
{
    [TestMethod]
    public void SimpleCreationTest()
    {
        Stopwatch Time = new Stopwatch();
        Time.Start();
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds);

        // Create

        PerformanceCounter RAM = new PerformanceCounter("Memory", "Available MBytes");
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => RAM created");

        PerformanceCounter CPU = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => CPU created");

        PerformanceCounter GC = new PerformanceCounter(".NET CLR Memory", "% Time in GC", "_Global_");
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => GC created");

        // Read

        float Value = RAM.NextValue();
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => RAM value is : " + Value);

        Value = CPU.NextValue();
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => CPU value is : " + Value);

        Value = GC.NextValue();
        Debug.WriteLine("Time is : " + Time.ElapsedMilliseconds + " => GC value is : " + Value);
    }
}

Research

PerformanceCounter extremely slow in connecting remote server

Creating a new System.Diagnostics.PerformanceCounter is very slow

I tried using the other constructors and giving a precise 'MachineName' but it doesn't change anything.

Why a call to PerformanceCounter is slow?

http://craigandera.blogspot.fr/2005/06/performancecounter-constructor-horribly_21.html

According to this two threads, the problem seem to be about the fact that performance counters are a shared resource. However I don't understand how I could solve that.

Running Visual Studio in Administrator 'accelerate' the first creation from 38 sec to 26 sec, so it doesn't solve the problem either.


Thanks for your help.

Suburb answered 10/3, 2014 at 10:27 Comment(5)
Try implementing the PerformanceCounter instances via public static variables as shown here msdn.microsoft.com/en-us/library/…Bowdlerize
That's already how my 'real' class work - and how I spotted the problem. Making the PerformanceCounter as 'static public' in the test code above didn't change anything.Suburb
It seems like a network issue coupled with an authentication issue. The NextValue() method documentation does mention about this - To read performance counters, you must have administrative privileges. In Windows Vista, User Account Control (UAC) determines the privileges of a user. If you are a member of the Built-in Administrators group, you are assigned two run-time access tokens: a standard user access token and an administrator access token. By default, you are in the standard user role.Bowdlerize
So ... Being Administrator 'solve' the Authentication issue but not the network issue ? I don't understand why the network would have any role here as I'm requesting the local performance. With the 'No machine name' constructor, the constructor shouldn't even have to look outside the local machine. Anyway, using this : sevenforums.com/tutorials/… I have been able to get the PerformanceCounter creation to 26 sec without launching VS as Administrator. But the 'network issue' still make no sense. This is strange.Suburb
Oh I didn't know that it is running locally. So yes definitely the network issue makes no sense.Bowdlerize
P
3

I tried your code on my machine and I got >2.5 seconds for the constructor of the PerformanceCounter. I was not able to debug the .NET Source Code (I'm running VS2013 Express Edition, Windows 7 64b) but I did a series of experinets:

  1. I called the default constructor of the PerformanceCounter. It executes instantly.
  2. Using perfmon I checked the networking related activity. I saw nothing peculiar.
  3. I monitored the memory footprint. I saw that when calling the first parametrized constructor I add ~2.5MB to the memory footprint of the code.
  4. Using perfmon I checked if there's a spike in the count of used mutex, semaphores and other synchronization objects. Nothing unusual happened.
  5. I tested the code in various times while different number of processes were active. I saw that there is great variation. Sometimes i get 1.4 seconds, sometimes I get 2.7 sometimes I get 5 seconds.
  6. I already opened a GUI monitoring session and ran the code but I saw no gain.

So I believe that there is no setup problem and the the answer is that PerformanceCounter constructor does complex work that takes a lot of time to execute.

All the events being monitored are software events, that can be tracked by the operating system. So I suppose that when a new PerformanceCounter object is created, the OS has to generate the current state of the machine. That possibly means getting information for all processes, and most of all, storing that information into a readable and fast accessible structure. What I observed is that the more active processes I have, the slower the PerformanceCounter is created. Also the more cores you have, probably the more data you have to collect.

In the last link you sent, there's a comment that seems to validate this theory but I suppose the spinlock part was optimized since 2005. Probably the measure of last resort is to debug the .NET source for constructing the PerformanceCounter. However I think that this is just how it's implemented.

What I would do is creating the PerformanceCounter objects I need during the initialization phase of the application.

Pennsylvania answered 22/3, 2015 at 18:40 Comment(2)
tldr; the cost in when creating a PerformanceCounter. Use a cache to re-use the same performance-counter .NET instances.Patric
Furthermore, the cached performance counters don't even need to correspond the original processes (which is another issue for association, but..) and only the InstanceName is relevant. Trying to access a counter for an instance which no longer exists will simply throw an InvalidOperationException: "Instance '..' does not exist in the specified Category."Patric
D
0

This is what fixed it for me:

The performance counters setup time in my application dropped from 2:30 minutes to around 20 seconds by ensuring it was being executed as a 64bit process. The interesting is that I had the performance issue only in a Windows 2012 VM. No problems in Windows 10.

Dispeople answered 25/6, 2018 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.