360 lines
11 KiB
Plaintext
360 lines
11 KiB
Plaintext
|
||
|
||
Extensible Counter Loading & Unloading Utilities
|
||
|
||
Design Specification and Overview
|
||
|
||
|
||
|
||
created: 15 Feb 93
|
||
a-robw
|
||
russbl
|
||
|
||
updated: 16 Nov 95
|
||
a-robw
|
||
|
||
Overview
|
||
|
||
Device driver, service and application developers that wish to provide
|
||
performance measuring capability in their software 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 programmatically. Since the "correct" way to
|
||
do this is poorly documented and difficult to explain, the following
|
||
utilities and library functions are provided to make the installation
|
||
and removal of these extensible counters much simpler and less prone
|
||
to error and confusion.
|
||
|
||
The two command line utilities provided with Windows NT are shown below.
|
||
|
||
> LodCtr MyDriver.INI
|
||
|
||
> UnLodCtr MyDriver
|
||
|
||
|
||
LoadPerf.DLL is provided to the software developer to provide access
|
||
to these same functions (in both Unicode & ANSI formats) from within
|
||
a setup program.
|
||
|
||
LoadPerfCounterTextStrings (
|
||
LPTSTR szCommandLine
|
||
BOOL bQuietModeFlag)
|
||
|
||
UnloadPerfCounterTextStrings (
|
||
LPTSTR szCommandLine,
|
||
BOOL bQuietMode)
|
||
|
||
The contents of the string arguments in the above functions are the
|
||
same as those for the command line.
|
||
|
||
|
||
The installation utility (LodCtr) accepts as an argument the name of
|
||
the device or application's counter .INI file. The format of the .INI
|
||
file is 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 extensible performance counter DLL.
|
||
|
||
The removal utility UnLodCtr accepts as an argument, the name of the
|
||
regsistry key which is to have its names removed from the data files.
|
||
This key is the registry key that the application, service or device
|
||
driver us using under the ...\Services key and has the Performance
|
||
subkey.
|
||
|
||
The extensible performance counter 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 extensible performance counter 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 extensible
|
||
performance 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
|
||
reinstalled.
|
||
|
||
|
||
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)
|
||
|
||
|