Performance Anxiety
One of the hardest parts of .Net programming is the problem of objects with explicit lifecycles. Performance Counters are a perfect example of such an object: there are severe penalties to the application if a performance counter's lifecycle isn't handled correctly. The lifecycle is as follows:
- Installation - installation is tricky because it generally requires administrative priveleges, at least for the act of creating a counter category. Many applications will attempt to create performance counter category when the counter is used, but this is incorrect; for example, in ASP.NET applications, the application by default runs under an account without sufficient privelege to do this. The answer is to build an installer class for the counters.
- Use - On top of that, there's a development issue involved - if you invoke a performance counter that's not installed, the application will throw an exception. It's a pain for developers to have to install a library that they're developing just to keep the performance counters happy. It would be nice to be able to separate these concerns - code that uses performance counters should operate if the counters aren't installed. #if DEBUG can solve this for you, but that creates a separate headache. Really, the performance counter code should just be there - it will operate if the counters are installed, otherwise, it will just be ignored.
- Instantiation - performance counters have a pretty significant penalty for instantiation and disposal. I wrote a short program that compares 3 methods of performance logging: 100,000 iterations using:
- a new PerformanceCounter instance for each iteration (including disposing of the instance)
- re-using a PerformanceCounter instance for each iteration.
- writing to a log4net FileAppender on each instance.
- Performance counters have instances - generally the global instance plus an instance per application that's logging performance counters. If you want to track instances, you need to updatethe global instance as well as the specific instance that you're working with.
- Disposal - counters must be disposed of; otherwise over time the counters will start yielding the "Custom counters file view is out of memory" error. You can slow this down, but increasing the size of the paging file isn't a way around a Dispose() bug, so this setting is really only a way to increase memory available if you legitimately need to create an enormous number of counters.
These are the overarching concerns that you have to manage, all the while remembering that you want to measure performance, but this is not the primary goal of your application - the instrumentation should be as unobtrusive as possible.