

        Extensible Counter Loading & Unloading Utilities

                Design Specification and Overview



                                                                15 Feb 93
                                                                a-robw
                                                                russbl


Overview
                                   
Device driver developers that wish to provide a performance measuring 
capability in their drivers must have a way to incorporate the names
of the performance counters and counter objects into the registry. Currently
the only methods available are the manual installation of the names into 
the registry or for each developer to devise a scheme to do it program-
matically. Since the "correct" way to do this is poorly documented and diff-
icult to explain, the following utilities will make the installation
and removal of these extensible counters much simpler and less
prone to error and confusion.

Two utilities are provided to the device driver developer.
Examples of their command lines are shown below.


    > LodCtr MyDriver.INI

    > UnLodCtr MyDriver


The installation utility (LodCtr) accepts as it's only argument the
name of the devices counter .INI file (described in detail later in this
document) This utility will enter the counter names and explain text stored
in the .INI file into the corresponding data file and update the necessary 
keys and values for the device driver's performance DLL.

The removal utility UnLodCtr accepts as it's only argument, the 
device driver which is to have its names removed from the data files.

The driver's performance DLL must be written to look up the base
values of the counter names and explain text during initialization for
this to function properly.

.INI file format

The .ini file for the device driver's counters will consist of keys 
and values in a format similar to that of a MS-Windows .INI file (e.g. 
WIN.INI) This will allow a format that is somewhat self-documenting
as well as allow current Win32 utilities to process it and parse the
data (e.g. GetPrivateProfileString). A single file was selected to 
minimize the development and maintenance overhead of adding or modifying
counters and adding foreign language support. The contents of the .INI 
file are described below:


Usage Notes:

The following assumptions are made in the use of counter names and
explain text and should be followed in order to insure predictable and
reliable operation.

    - Index number ranges must not be overlapping between drivers

        The range of index numbers used by an extensible counter 
        must fall between the first and last values (see below).
        (gaps are allowed within the range used). If LodCtr is used
        then this won't be a problem.

    - Names must be assigned to EVEN numbers and Explain text assigned
        to ODD numbers.

        If the convention is followed as shown in the examples below,
        where each item is given an offset of an even number starting 
        from 0, then LodCtr will do the right thing and make this 
        assignment automatically. For this to work, however, the offest 
        values MUST ALWAYS BE EVEN NUMBERS.

    - Manual assignment of counter index values is not recommended.
        
        Failure to follow all the assumptions or manually modifying
        or "hard-coding" index values may result in counter name 
        text corruption or erroneous display of names.

    - Symbol file format must conform to the following:
        
        #define NAME    decimal_number

        The symbol file processor is pretty dumb and can read .H header
        files but will only understand lines that conform to the above
        format. (in line comments after the number are OK) see the
        example below for more information.


// Begin .INI file format

[info]
drivername=<name of device found under the CurrentControlSet\Services key>
symbolfile=<.h file containing symbolic offsets of counters>

[languages] // one key (value optional) for each language supported in file
009=
 .
 .
 .
 .


[text]  // counter & explain text for customer-defined counters
offset_langid_NAME=text
offset_langid_HELP=text

// offset must be a symbolic constant (from symbolfile)
// offset value must be an even number (see code example for why)
// NAME and HELP are literal text and identify counter names or explain text
// langid must be listed as a key under [languages]
// text must be entered on a single line (though it can be a long one)

// end .INI file format


The .ini file must be loaded into the registry before the devices extensible
counter DLL is initialized (e.g. during or immediately after the driver is
loaded for the first time. Once the counter names are loaded, however, they
will remain until they are removed or NT is re-installed.


Following is an example of how the various components of an extensible 
counter would incorporate the definitions of the .INI file and the use
of the LodCtr and UnLodCtr utilities.  This example has one object and
two counters.

// begin devdef.H file

// legal constant definitions

#define OBJECT_1    0
#define DEVICE_COUNTER_1    2
#define DEVICE_COUNTER_2    4


// end devdef.H file

// BEGIN: Object & Counter structure initialization file

// defines static structures used to build the perf data that is returned
// by the extensible counter routines

#include "devdef.h"
        
MY_DEVICE_CTR_DEFINITION MyDeviceCtrDefinition = {

    {   sizeof(MY_DEVICE_CTR_DEFINITION) + SIZE_OF_CTR_DATA,
        sizeof(MY_DEVICE_CTR_DEFINITION),
        sizeof(PERF_OBJECT_TYPE),
        OBJECT_1,
        0,
        OBJECT_1,
        0,
        PERF_DETAIL_ADVANCED,
        (sizeof(MY_DEVICE_CTR_DEFINITION-sizeof(PERF_OBJECT_TYPE))/
        sizeof(PERF_COUNTER_DEFINITION),
        1,
        0,
        0
    },
    {   sizeof(PERF_COUNTER_DEFINITION),
        DEVICE_COUNTER_1,
        0,
        DEVICE_COUNTER_1,
        0,
        0,
        PERF_DETAIL_ADVANCED, 
        PERF_COUNTER_COUNTER, 
        sizeof(DWORD),
        DEVICE_COUNTER_1_DATA_OFFSET
    },
    {   sizeof(PERF_COUNTER_DEFINITION),
        DEVICE_COUNTER_2,
        0,
        DEVICE_COUNTER_2,
        0,
        0,
        PERF_DETAIL_ADVANCED,
        PERF_COUNTER_COUNTER,
        sizeof(DWORD),
        DEVICE_COUNTER_2_DATA_OFFSET,
    }
};

// END: Object & Counter structure initialization file

// begin .INI file example
[info]
drivername=DriverName
symbolfile=devdef.h

[languages] 
009=English
00C=OtherLanguage

[text]  
OBJECT_1_009_NAME=Device Name
OBJECT_1_009_HELP=Displays performance statistics on Device Name
OBJECT_1_00C_NAME=Device Name in other language
OBJECT_1_00C_HELP=Displays performance of Device Name in other language

DEVICE_COUNTER_1_009_NAME=Counter A
DEVICE_COUNTER_1_009_HELP=Displays the current value of Counter A
DEVICE_COUNTER_1_00C_NAME=Counter A in other language
DEVICE_COUNTER_1_00C_HELP=Displays the value of Counter A in other language

DEVICE_COUNTER_2_009_NAME=Counter B
DEVICE_COUNTER_2_009_HELP=Displays the current rate of Devices B
DEVICE_COUNTER_2_00C_NAME=Counter B in other language
DEVICE_COUNTER_2_00C_HELP=Displays the rate of Device B in other language

// end .INI file


OpenPerformanceData ( ... args ... ) 
{

        .
        .
        .

    // execute this code before accessing or passing any perf. data
    // objects.

    status = RegOpenKeyEx (
        HKEY_LOCAL_MACHINE,
        "\\System\\CurrentControlSet\\Service\\DriverName\\Performance",
        NULL,
        SAM, 
        &hKeyDriverPerf);

    size = sizeof (DWORD);
    Status = RegQueryValueEx (
                hKeyDriverPerf, 
                "First Counter"
                0L,
                &type,
                (LPBYTE)&dwFirstCounter,
                &size);

    size = sizeof (DWORD);
    Status = RegQueryValueEx(
                hKeyDriverPerf, 
                "First Help"
                0L,
                &type,
                (LPBYTE)&dwFirstHelp,
                &size);

    //
    //  NOTE: the initialization program could also retrieve
    //      LastCounter and LastHelp if they wanted to do 
    //      bounds checking on the new number. e.g.
    //
    //      counter->CounterNameTitleIndex += dwFirstCounter;
    //      if (counter->CounterNameTitleIndex > dwLastCounter) {
    //          LogErrorToEventLog (INDEX_OUT_OF_BOUNDS);
    //      }

    For each counter object {
        Object->ObjectNameTitleIndex += dwFirstCounter;
        Object->ObjectHelpTitleIndex += dwFirstHelp;

        for each counter definition in the object {
            counter->CounterNameTitleIndex += dwFirstCounter;
            counter->CounterHelpTitleIndex += dwFirstHelp;

        }
    }

    RegCloseKey (hKeyDriverPerf);
        .
        .
        .

}


When LodCtr has loaded the contents of the .INI file the following 
registry keys will have been updated.  The ":" indicates a Value of
a Key; other symbols are keys in the registry.

MACHINE
    SYSTEM
        CurrentControlSet
            Services
                <devicename>
                    Performance
                        :First Counter (updated to show current value)
                        :First Help    (updated to show current value)
                        :Last Counter  (updated to show current value)
                        :Last Help     (updated to show current value)
                
MACHINE
    SOFTWARE
        Microsoft
            Windows NT
                CurrentVersion
                    Perflib            
                        :Last Counter (updated to show current value)
                        :Last Help    (updated to show current value)  



After UnLodCtr is run to remove a driver's counters from the data file,
the following changes to the registry will take place

MACHINE
    SYSTEM
        CurrentControlSet
            Services
                <devicename>
                    Performance
                        :First Counter     (value deleted)
                        :First Help        (value deleted)
                        :Last Counter      (value deleted)
                        :Last Help         (value deleted)
                
MACHINE
    SOFTWARE
        Microsoft
            Windows NT
                CurrentVersion
                    Perflib            
                        :Last Counter (updated to show current value)
                        :Last Help    (updated to show current value)  

