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)
|
|||
|
|
|||
|
|