pdhutil

package
v0.19.0-rc.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 9, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

Handling of counter strings and translations in windows

Windows counter classes and counter names are localized in Windows. This presents an extra degree of difficulty in reporting performance counters on Windows platforms.

Storage

The strings for the counter classes and counter names are stored in the registry. They are stored in the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib. Beneath that key is a key 009 (for English), and a second key CurrentLanguage which contains the strings for the currently enabled locale. On an en-us locale, the two keys contain the same information.

The strings are stored as a REG_MULTI_SZ, which means it is a "C" language string; in fact, it is a list of NULL terminated strings, with the last element indicated by NULLNULL. For example, the contents might be (shortened for clarity): "1|N|1847|N|2|N|System|N|4|N|Memory|N||N|" (where |N| is NULL)

To find the string for the current locale, in this example "System", first traverse the list of english strings. System has the index "2". Then, find the string with the index "2" in the current language, and Voila.

Duplication

Because each package that reports counters via the performance counter API registers its own strings, strings can be duplicated. For example, the string "Write Bytes/sec" appears 4 times in one sample machine.

In addition, each of those might be translated differently. The translation to the locale "foo" might have one instance "Write Bytes/sec" translated to "FooWrite Bytes/sec", and a second translated to "FooWrite Bytes per second".

This is because the first might be from the "System" package, and the second might be from the "NTDS" package, and the translations were generated separately.

The result of this is that while you use the same English string for two counters

  • \NTDS(*)\Write Bytes/sec
  • \System(*)\Write Bytes/sec

On a "fooish" locale, the counters would be

  • \NTDS(*)\FooWrite Bytes/sec
  • \System(*)\FooWrite Bytes per second

And, there is no way to know in advance which string to use.

Therefore, the (somewhat messy) algorithm in MakeCounterPath() is to look up the string in the string table, and find the counter name that works. Using the "fooish" example above, that means

  1. Look up the index for "Write Bytes/sec". This returns two indices A and B
  2. Retrieve the fooish string for index A, "FooWrite Bytes/sec"
  3. Attempt to create the counter "\System(*)\FooWrite Bytes/sec"
  • this will fail, because that counter doesn't exist (because it's not the correctly translated string)
  1. Attempt to create the counter "\System(*)\FooWrite Bytes per second"
  • This will succeed, because we've found the correct translation of the given English string.

Documentation

Rendered for windows/amd64

Index

Constants

View Source
const (

	//
	// Event Descriptors
	//
	PDH_CSTATUS_VALID_DATA                     = 0x0
	PDH_CSTATUS_NEW_DATA                       = 0x1
	PDH_CSTATUS_NO_MACHINE                     = 0x800007D0
	PDH_CSTATUS_NO_INSTANCE                    = 0x800007D1
	PDH_MORE_DATA                              = 0x800007D2
	PDH_CSTATUS_ITEM_NOT_VALIDATED             = 0x800007D3
	PDH_RETRY                                  = 0x800007D4
	PDH_NO_DATA                                = 0x800007D5
	PDH_CALC_NEGATIVE_DENOMINATOR              = 0x800007D6
	PDH_CALC_NEGATIVE_TIMEBASE                 = 0x800007D7
	PDH_CALC_NEGATIVE_VALUE                    = 0x800007D8
	PDH_DIALOG_CANCELLED                       = 0x800007D9
	PDH_END_OF_LOG_FILE                        = 0x800007DA
	PDH_ASYNC_QUERY_TIMEOUT                    = 0x800007DB
	PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE = 0x800007DC
	PDH_UNABLE_MAP_NAME_FILES                  = 0x80000BD5
	PDH_PLA_VALIDATION_WARNING                 = 0x80000BF3
	PDH_CSTATUS_NO_OBJECT                      = 0xC0000BB8
	PDH_CSTATUS_NO_COUNTER                     = 0xC0000BB9
	PDH_CSTATUS_INVALID_DATA                   = 0xC0000BBA
	PDH_MEMORY_ALLOCATION_FAILURE              = 0xC0000BBB
	PDH_INVALID_HANDLE                         = 0xC0000BBC
	PDH_INVALID_ARGUMENT                       = 0xC0000BBD
	PDH_FUNCTION_NOT_FOUND                     = 0xC0000BBE
	PDH_CSTATUS_NO_COUNTERNAME                 = 0xC0000BBF
	PDH_CSTATUS_BAD_COUNTERNAME                = 0xC0000BC0
	PDH_INVALID_BUFFER                         = 0xC0000BC1
	PDH_INSUFFICIENT_BUFFER                    = 0xC0000BC2
	PDH_CANNOT_CONNECT_MACHINE                 = 0xC0000BC3
	PDH_INVALID_PATH                           = 0xC0000BC4
	PDH_INVALID_INSTANCE                       = 0xC0000BC5
	PDH_INVALID_DATA                           = 0xC0000BC6
	PDH_NO_DIALOG_DATA                         = 0xC0000BC7
	PDH_CANNOT_READ_NAME_STRINGS               = 0xC0000BC8
	PDH_LOG_FILE_CREATE_ERROR                  = 0xC0000BC9
	PDH_LOG_FILE_OPEN_ERROR                    = 0xC0000BCA
	PDH_LOG_TYPE_NOT_FOUND                     = 0xC0000BCB
	PDH_NO_MORE_DATA                           = 0xC0000BCC
	PDH_ENTRY_NOT_IN_LOG_FILE                  = 0xC0000BCD
	PDH_DATA_SOURCE_IS_LOG_FILE                = 0xC0000BCE
	PDH_DATA_SOURCE_IS_REAL_TIME               = 0xC0000BCF
	PDH_UNABLE_READ_LOG_HEADER                 = 0xC0000BD0
	PDH_FILE_NOT_FOUND                         = 0xC0000BD1
	PDH_FILE_ALREADY_EXISTS                    = 0xC0000BD2
	PDH_NOT_IMPLEMENTED                        = 0xC0000BD3
	PDH_STRING_NOT_FOUND                       = 0xC0000BD4
	PDH_UNKNOWN_LOG_FORMAT                     = 0xC0000BD6
	PDH_UNKNOWN_LOGSVC_COMMAND                 = 0xC0000BD7
	PDH_LOGSVC_QUERY_NOT_FOUND                 = 0xC0000BD8
	PDH_LOGSVC_NOT_OPENED                      = 0xC0000BD9
	PDH_WBEM_ERROR                             = 0xC0000BDA
	PDH_ACCESS_DENIED                          = 0xC0000BDB
	PDH_LOG_FILE_TOO_SMALL                     = 0xC0000BDC
	PDH_INVALID_DATASOURCE                     = 0xC0000BDD
	PDH_INVALID_SQLDB                          = 0xC0000BDE
	PDH_NO_COUNTERS                            = 0xC0000BDF
	PDH_SQL_ALLOC_FAILED                       = 0xC0000BE0
	PDH_SQL_ALLOCCON_FAILED                    = 0xC0000BE1
	PDH_SQL_EXEC_DIRECT_FAILED                 = 0xC0000BE2
	PDH_SQL_FETCH_FAILED                       = 0xC0000BE3
	PDH_SQL_ROWCOUNT_FAILED                    = 0xC0000BE4
	PDH_SQL_MORE_RESULTS_FAILED                = 0xC0000BE5
	PDH_SQL_CONNECT_FAILED                     = 0xC0000BE6
	PDH_SQL_BIND_FAILED                        = 0xC0000BE7
	PDH_CANNOT_CONNECT_WMI_SERVER              = 0xC0000BE8
	PDH_PLA_COLLECTION_ALREADY_RUNNING         = 0xC0000BE9
	PDH_PLA_ERROR_SCHEDULE_OVERLAP             = 0xC0000BEA
	PDH_PLA_COLLECTION_NOT_FOUND               = 0xC0000BEB
	PDH_PLA_ERROR_SCHEDULE_ELAPSED             = 0xC0000BEC
	PDH_PLA_ERROR_NOSTART                      = 0xC0000BED
	PDH_PLA_ERROR_ALREADY_EXISTS               = 0xC0000BEE
	PDH_PLA_ERROR_TYPE_MISMATCH                = 0xC0000BEF
	PDH_PLA_ERROR_FILEPATH                     = 0xC0000BF0
	PDH_PLA_SERVICE_ERROR                      = 0xC0000BF1
	PDH_PLA_VALIDATION_ERROR                   = 0xC0000BF2
	PDH_PLA_ERROR_NAME_TOO_LONG                = 0xC0000BF4
	PDH_INVALID_SQL_LOG_FORMAT                 = 0xC0000BF5
	PDH_COUNTER_ALREADY_IN_QUERY               = 0xC0000BF6
	PDH_BINARY_LOG_CORRUPT                     = 0xC0000BF7
	PDH_LOG_SAMPLE_TOO_SMALL                   = 0xC0000BF8
	PDH_OS_LATER_VERSION                       = 0xC0000BF9
	PDH_OS_EARLIER_VERSION                     = 0xC0000BFA
	PDH_INCORRECT_APPEND_TIME                  = 0xC0000BFB
	PDH_UNMATCHED_APPEND_COUNTER               = 0xC0000BFC
	PDH_SQL_ALTER_DETAIL_FAILED                = 0xC0000BFD
	PDH_QUERY_PERF_DATA_TIMEOUT                = 0xC0000BFE
	MSG_Publisher_Name                         = 0x90000001
)

PDH error codes. Taken from latest PDHMSH.h in Windows SDK

View Source
const (
	PDH_FMT_RAW          = uint32(0x00000010)
	PDH_FMT_ANSI         = uint32(0x00000020)
	PDH_FMT_UNICODE      = uint32(0x00000040)
	PDH_FMT_LONG         = uint32(0x00000100)
	PDH_FMT_DOUBLE       = uint32(0x00000200)
	PDH_FMT_LARGE        = uint32(0x00000400)
	PDH_FMT_NOSCALE      = uint32(0x00001000)
	PDH_FMT_1000         = uint32(0x00002000)
	PDH_FMT_NODATA       = uint32(0x00004000)
	PDH_FMT_NOCAP100     = uint32(0x00008000)
	PERF_DETAIL_COSTLY   = uint32(0x00010000)
	PERF_DETAIL_STANDARD = uint32(0x0000FFFF)
)

dwFormat flag values taken from latest pdh.h in windows sdk

View Source
const (
	CounterAllProcessPctProcessorTime   = `\Process(*)\% Processor Time`
	CounterAllProcessPctUserTime        = `\Process(*)\% User Time`
	CounterAllProcessPctPrivilegedTime  = `\Process(*)\% Privileged Time`
	CounterAllProcessVirtualBytesPeak   = `\Process(*)\Virtual Bytes Peak`
	CounterAllProcessVirtualBytes       = `\Process(*)\Virtual Bytes`
	CounterAllProcessPageFaultsPerSec   = `\Process(*)\Page Faults/sec`
	CounterAllProcessWorkingSetPeak     = `\Process(*)\Working Set Peak`
	CounterAllProcessWorkingSet         = `\Process(*)\Working Set`
	CounterAllProcessPageFileBytesPeak  = `\Process(*)\Page File Bytes Peak`
	CounterAllProcessPageFileBytes      = `\Process(*)\Page File Bytes`
	CounterAllProcessPrivateBytes       = `\Process(*)\Private Bytes`
	CounterAllProcessThreadCount        = `\Process(*)\Thread Count`
	CounterAllProcessPriorityBase       = `\Process(*)\Priority Base`
	CounterAllProcessElapsedTime        = `\Process(*)\Elapsed Time`
	CounterAllProcessPID                = `\Process(*)\ID Process`
	CounterAllProcessParentPID          = `\Process(*)\Creating Process ID`
	CounterAllProcessPoolPagedBytes     = `\Process(*)\Pool Paged Bytes`
	CounterAllProcessPoolNonpagedBytes  = `\Process(*)\Pool Nonpaged Bytes`
	CounterAllProcessHandleCount        = `\Process(*)\Handle Count`
	CounterAllProcessIOReadOpsPerSec    = `\Process(*)\IO Read Operations/sec`
	CounterAllProcessIOWriteOpsPerSec   = `\Process(*)\IO Write Operations/sec`
	CounterAllProcessIODataOpsPerSec    = `\Process(*)\IO Data Operations/sec`
	CounterAllProcessIOOtherOpsPerSec   = `\Process(*)\IO Other Operations/sec`
	CounterAllProcessIOReadBytesPerSec  = `\Process(*)\IO Read Bytes/sec`
	CounterAllProcessIOWriteBytesPerSec = `\Process(*)\IO Write Bytes/sec`
	CounterAllProcessIODataBytesPerSec  = `\Process(*)\IO Data Bytes/sec`
	CounterAllProcessIOOtherBytesPerSec = `\Process(*)\IO Other Bytes/sec`
	CounterAllProcessWorkingSetPrivate  = `\Process(*)\Working Set - Private`
)
View Source
const (
	// taken from winperf.h
	PERF_DETAIL_NOVICE   = 100 // The uninformed can understand it
	PERF_DETAIL_ADVANCED = 200 // For the advanced user
	PERF_DETAIL_EXPERT   = 300 // For the expert user
	PERF_DETAIL_WIZARD   = 400 // For the system designer
)
View Source
const (
	ERROR_SUCCESS = 0
)

Variables

This section is empty.

Functions

func AddCounterInstance

func AddCounterInstance(clss, inst string)

AddCounterInstance adds a specific instance to the table of available instances

func PdhAddCounter

func PdhAddCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32

PdhAddCounter adds the specified counter to the query

Parameters hQuery [in] Handle to the query to which you want to add the counter. This handle is returned by the PdhOpenQuery function.

szFullCounterPath [in] Null-terminated string that contains the counter path. For details on the format of a counter path, see Specifying a Counter Path. The maximum length of a counter path is PDH_MAX_COUNTER_PATH.

dwUserData [in] User-defined value. This value becomes part of the counter information. To retrieve this value later, call the PdhGetCounterInfo function and access the dwUserData member of the PDH_COUNTER_INFO structure.

phCounter [out] Handle to the counter that was added to the query. You may need to reference this handle in subsequent calls.

func PdhAddEnglishCounter

func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32

PdhAddEnglishCounter adds the specified counter to the query

Parameters hQuery [in] Handle to the query to which you want to add the counter. This handle is returned by the PdhOpenQuery function. szFullCounterPath [in] Null-terminated string that contains the counter path. For details on the format of a counter path, see Specifying a Counter Path. The maximum length of a counter path is PDH_MAX_COUNTER_PATH. dwUserData [in] User-defined value. This value becomes part of the counter information. To retrieve this value later, call the PdhGetCounterInfo function and access the dwUserData member of the PDH_COUNTER_INFO structure. phCounter [out] Handle to the counter that was added to the query. You may need to reference this handle in subsequent calls.

func PdhCloseQuery

func PdhCloseQuery(hQuery PDH_HQUERY) uint32

PdhCloseQuery Closes all counters contained in the specified query, closes all handles related to the query, and frees all memory associated with the query.

func PdhCollectQueryData

func PdhCollectQueryData(hQuery PDH_HQUERY) uint32
PdhCollectQueryData
  Collects the current raw data value for all counters in the specified query and updates the status code of each counter.

Parameters hQuery [in, out] Handle of the query for which you want to collect data. The PdhOpenQuery function returns this handle.

func PdhOpenQuery

func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY) uint32

PdhOpenQuery Creates a new query that is used to manage the collection of performance data.

Parameters szDataSource [in] Null-terminated string that specifies the name of the log file from which to retrieve performance data. If NULL, performance data is collected from a real-time data source.

dwUserData [in] User-defined value to associate with this query. To retrieve the user data later, call PdhGetCounterInfo and access the dwQueryUserData member of PDH_COUNTER_INFO.

phQuery [out] Handle to the query. You use this handle in subsequent calls.

func PdhRemoveCounter

func PdhRemoveCounter(hCounter PDH_HCOUNTER) uint32

PdhRemoveCounter removes a counter from a query

func RemoveCounterInstance

func RemoveCounterInstance(clss, inst string)

RemoveCounterInstance removes a specific instance from the table of available instances

func SetQueryReturnValue

func SetQueryReturnValue(counter string, val float64)

SetQueryReturnValue provides an entry point for tests to set expected values for a given counter

func SetupTesting

func SetupTesting(counterstringsfile, countersfile string)

SetupTesting initializes the PDH libarary with the mock functions rather than the real thing

Types

type AvailableCounters

type AvailableCounters struct {
	// contains filtered or unexported fields
}

AvailableCounters houses the mocked version of the available counters & instances

func ReadCounters

func ReadCounters(fn string) (AvailableCounters, error)

ReadCounters reads the available PDH counters from a static text file

type CounterInstanceVerify

type CounterInstanceVerify func(string) bool

CounterInstanceVerify is a callback function called by GetCounterSet for each instance of the counter. Implementation should return true if that instance should be included, false otherwise

type CounterStrings

type CounterStrings struct {
	// contains filtered or unexported fields
}

CounterStrings houses the mocked version of the registry-based counter strings database

func ReadCounterStrings

func ReadCounterStrings(fn string) (CounterStrings, error)

ReadCounterStrings reads the counter strings from the provided file

type ErrPdhInvalidInstance

type ErrPdhInvalidInstance struct {
	// contains filtered or unexported fields
}

func NewErrPdhInvalidInstance

func NewErrPdhInvalidInstance(message string) *ErrPdhInvalidInstance

func (*ErrPdhInvalidInstance) Error

func (e *ErrPdhInvalidInstance) Error() string

type PDH_FMT_COUNTERVALUE_DOUBLE

type PDH_FMT_COUNTERVALUE_DOUBLE struct {
	CStatus     uint32
	DoubleValue float64
}

Union specialization for double values

type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE

type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct {
	// contains filtered or unexported fields
}

PDH_FMT_COUNTERVALUE_ITEM_DOUBLE structure contains the instance name and formatted value of a PDH_FMT_COUNTERVALUE_DOUBLE counter.

type PDH_FMT_COUNTERVALUE_ITEM_LARGE

type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct {
	// contains filtered or unexported fields
}

PDH_FMT_COUNTERVALUE_ITEM_LARGE structure contains the instance name and formatted value of a PDH_FMT_COUNTERVALUE_LARGE counter.

type PDH_FMT_COUNTERVALUE_ITEM_LONG

type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
	// contains filtered or unexported fields
}

PDH_FMT_COUNTERVALUE_ITEM_LONG structure contains the instance name and formatted value of a PDH_FMT_COUNTERVALUE_LONG counter.

type PDH_FMT_COUNTERVALUE_LARGE

type PDH_FMT_COUNTERVALUE_LARGE struct {
	CStatus    uint32
	LargeValue int64
}

Union specialization for 64 bit integer values

type PDH_FMT_COUNTERVALUE_LONG

type PDH_FMT_COUNTERVALUE_LONG struct {
	CStatus uint32

	LongValue int32
	// contains filtered or unexported fields
}

Union specialization for long values

type PDH_HCOUNTER

type PDH_HCOUNTER windows.Handle

type PDH_HQUERY

type PDH_HQUERY windows.Handle

type PdhCounterSet

type PdhCounterSet struct {
	// contains filtered or unexported fields
}

PdhCounterSet is the object which represents a pdh counter set.

func (*PdhCounterSet) Close

func (p *PdhCounterSet) Close()

Close closes the query handle, freeing the underlying windows resources.

func (*PdhCounterSet) Initialize

func (p *PdhCounterSet) Initialize(className string) error

Initialize initializes a counter set object

func (*PdhCounterSet) MakeCounterPath

func (p *PdhCounterSet) MakeCounterPath(machine, counterName, instanceName string, counters []string) (string, error)

MakeCounterPath creates a counter path from the counter instance and counter name. Tries all available translated counter indexes from the english name

type PdhCounterValue

type PdhCounterValue struct {
	Double float64
	Large  int64
	Long   int32
}

PdhCounterValue represents a counter value

type PdhFormatter

type PdhFormatter struct {
	// contains filtered or unexported fields
}

PdhFormatter implements a formatter for PDH performance counters

func (*PdhFormatter) Enum

func (f *PdhFormatter) Enum(counterName string, hCounter PDH_HCOUNTER, format uint32, ignoreInstances []string, fn ValueEnumFunc) error

Enum enumerates performance counter values for a wildcard instance counter (e.g. `\Process(*)\% Processor Time`)

type PdhMultiInstanceCounterSet

type PdhMultiInstanceCounterSet struct {
	PdhCounterSet
	// contains filtered or unexported fields
}

PdhMultiInstanceCounterSet is a specialization for a multiple instance counter

func GetMultiInstanceCounter

func GetMultiInstanceCounter(className, counterName string, requestedInstances *[]string, verifyfn CounterInstanceVerify) (*PdhMultiInstanceCounterSet, error)

GetMultiInstanceCounter returns a multi-instance counter object for the given counter class TODO: Replace usages of this with a function similar to GetUnlocalizedCounter for multi-instance counters, that uses PdhAddEnglishCounter

func (*PdhMultiInstanceCounterSet) GetAllValues

func (p *PdhMultiInstanceCounterSet) GetAllValues() (values map[string]float64, err error)

GetAllValues returns the data associated with each instance in a query.

func (*PdhMultiInstanceCounterSet) MakeInstanceList

func (p *PdhMultiInstanceCounterSet) MakeInstanceList() error

MakeInstanceList walks the list of available instances, and adds new instances that have appeared since the last check run

func (*PdhMultiInstanceCounterSet) RemoveInvalidInstance

func (p *PdhMultiInstanceCounterSet) RemoveInvalidInstance(badInstance string)

RemoveInvalidInstance removes an instance from the counter that is no longer valid

type PdhSingleInstanceCounterSet

type PdhSingleInstanceCounterSet struct {
	PdhCounterSet
	// contains filtered or unexported fields
}

PdhSingleInstanceCounterSet is a specialization for single instance counters

func GetSingleInstanceCounter

func GetSingleInstanceCounter(className, counterName string) (*PdhSingleInstanceCounterSet, error)

GetSingleInstanceCounter returns a single instance counter object for the given counter class TODO: Replace usages of this with GetUnlocalizedCounter using an empty string as instance

func GetUnlocalizedCounter

func GetUnlocalizedCounter(className, counterName, instance string) (PdhSingleInstanceCounterSet, error)

GetUnlocalizedCounter wraps the PdhAddEnglishCounter call that takes unlocalized counter names (as opposed to the other functions which use PdhAddCounter)

func (*PdhSingleInstanceCounterSet) GetValue

func (p *PdhSingleInstanceCounterSet) GetValue() (val float64, err error)

GetValue returns the data associated with a single-value counter

type ValueEnumFunc

type ValueEnumFunc func(s string, v PdhCounterValue)

ValueEnumFunc implements a callback for counter enumeration

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL