Performance counter rewrite almost complete

| 0 Comments
Around a week ago I started looking at rewriting my performance counter library so that it worked on Vista. That work is almost complete and I'm at the stage where the new library does everything the old one did but there's a list of 'nice to have' new items that I haven't completed yet. The work was reasonably easy once I got into it. I wasted an afternoon or so trying to understand the original code that I'd hacked a little way back in 2000 and eventually gave up and went to the documentation (and the book from whence the original code came). It's not that the original code was bad in any way, indeed it was clever and tight and worked well, it's just that it was a little obtuse. I'm not convinced that my new code is any less obtuse but at least I've split the code into several classes which just do one thing rather than having a single class with parts of it that are compiled out depending on whether you're building the application that logs data or the dll that collects it... I also wrote the whole thing in a test driven manner, which means I have tests for all of it, which is nice and will make the next step, refactoring it a little, easier.

My new design has, at its core, a "data block" class which manages the shared memory and associated interprocess locking that's needed to communicate between the application(s) that are logging and the dll that's collecting. This is where the first of the improvements comes in; the old code always allowed multiple instances of a performance object but they weren't especially easy to manage. The new code makes this much easier. It's now possible for applications to dynamically add and remove counter instances and for multiple applications to connect to different instances of the same counter set. This means that there'll soon be an example server that logs performance information per server instance within a server process and across server processes - which a client currently requires.

The next class is a schema class. This allows you to define your performance objects and replaces the macros and clever compile time construction of the performance objects that the old code allowed. There are some TODO's for the schema class, I'd like to be able to save the structure to a resource in the exe and dll so that you dont need to explicitly build the schema in code in both of them (it's not so terrible to do so, you simply include your custom schema class in each project) but it would make the collection dll's slightly smaller and more efficient if they didn't need to pull in the STL just because of the schema.

Then we have a monitoring class for use by the application, this provides access to the performance objects, instances and their counters. I'm pleased that this class basically just helps you map from the schema to the correct memory blobs in the data block so that actually incrementing a counter is still simply a case of doing an InterlockedIncrement() on a block of shared memory.

Then there's a collector class which is used by the collection dll. This works with the data block to format and return the performance data in the correct way. It doesn't need to do a great deal as most of the data is formatted in the right way in the data block anyway...

Finally there's an installer class that takes a schema and writes out the appropriate registry entries and calls the appropriate APIs to register your counter DLL. This uses a 'file exporter' that takes the schema and writes out an appropriately formatted .h and .ini file into a temporary directory and so that we can call LoadPerfCounterTextStrings(). The installer makes it easy for us to load localised strings for the counter names and help, so there's an open TODO item on the schema class to support this.

I'd like to be able to say that since I wrote all of the code in a test driven manner that when I came to install a performance counter DLL and look at the results in perfmon it just worked. It didn't. The tests made sure that the code did what I understood the spec to be. My understanding was slightly flawed in places and so I needed to do some debugging to get the counters to work. The debugging was pretty easy since the resulting changes were supported by the tests that I had. As I brought my understanding of the spec in line with what the spec actually said and adjusted my tests to suit it was easy to then adjust the code so that the tests passed again. So, next on the list is an example server to show off the mutliple instances stuff and then one that uses multiple languages in the counters.

My only currently outstanding "strangeness" is how to install the 64bit and 32bit counter dlls so that I can run a 64bit version of perfmon locally and a 32bit version remotely... Putting the dlls in System32 and SysWOW64 doesn't seem to be enough...

Leave a comment