How to liquidise perfmon's guts but still leave the body standing...

| 0 Comments

I'm still working on my performance counter library. I've got parent and child objects working and multiple instances and I have a sample server that publishes performance data using two objects, one for the executable (io threads, sockets and buffers in use, etc) and one for each of the server instances within the executable (connections active, bytes/sec, etc). The per server instance counters have the server executable as a parent and it has some totaled up counters for each instance... In turn there's a _Total instance in the server executable object's instances and that totals all executables... You can run multiple servers and they all just plug themselves in to the system and show their counters. It's nice and provides the functionality that one of my clients might need, which is handy, and exposes functionality that should have been exposed anyway...

Once I got all of the above working on my x64 dev box I decided to try a build on my older 32-bit XP box. Everything was good (once I dealt with the fact that the InterlockedIncrement64() family of functions exist in the headers but not in Kernel32.lib on the 32-bit XP box and so I was getting a run-time failure). However, registering the counters caused perfmon on the XP box to hang, it got to the point where it should display counters and just stopped. This was the problem that I was having with the side by side installation of 32-bit and 64-bit counter dlls on the Vista machine... What was strange was the the calls to OutputDebugString() that I'd put into the performance counter dll's Open() call were working, the dll was being opened, the call to open was returning without error and then, at some point after that, perfmon simply died inside. The shell and GUI remained somewhat responsive for a period of time but there was no monitoring going on.

I shut down my boxes, wandered off to the station to meet Gaelle after her skate and let the problem float around in my head looking for a solution... Sometime later I was just about to drift off to sleep when I realised what the issue was. Calling convention. Way back at the start of the project I'd had some issues with getting the counter dll exports working and had changed the calling convention to explicitly be __cdecl. This worked fine, on x64 (because all of the calling convention compiler modifiers are ignored on x64 and there's only one calling convention!) and looked like it worked back on Win32, well it gave the right entry points... However, a moment's thought (or a quick look at this dummy's guide to win32 calling conventions) will reveal that if the calling code expects a function to use __stdcall and the called code is actually using __cdecl then Bad Things will happen when the stack is cleaned up by both parties... Of course the name mangling is supposed to be different to help protect you from this, but, well...

So, this morning I adjusted the code so that it built as __stdcall, well, WINAPI actually, on both platforms and then used some #pragma magic to rename the exports to the desired names on Win32. The result is that I now have side-by-side performance counters working on x64 and the 32-bit code works on XP! Woo!

Tasks for today include writing a test to prevent the calling convention issue biting me again with this code and then adding multi-language counter and help string support. Once that's done it's pretty much all over bar the refactoring.

Leave a comment