Documentation ¶
Overview ¶
Go bindings for the HKEY_PERFORMANCE_DATA perflib / Performance Counters interface.
Overview ¶
HKEY_PERFORMANCE_DATA is a low-level alternative to the higher-level PDH library and WMI. It operates on blocks of counters and only returns raw values without calculating rates or formatting them, which is exactly what you want for, say, a Prometheus exporter (not so much for a GUI like Windows Performance Monitor).
Its overhead is much lower than the high-level libraries.
It operates on the same set of perflib providers as PDH and WMI. See this document for more details on the relationship between the different libraries: https://msdn.microsoft.com/en-us/library/windows/desktop/aa371643(v=vs.85).aspx
Example C++ source code: https://msdn.microsoft.com/de-de/library/windows/desktop/aa372138(v=vs.85).aspx
For now, the API is not stable and is probably going to change in future perflib_exporter releases. If you want to use this library, send the author an email so we can discuss your requirements and stabilize the API.
Names ¶
Counter names and help texts are resolved by looking up an index in a name table. Since Microsoft loves internalization, both names and help texts can be requested any locally available language.
The library automatically loads the name tables and resolves all identifiers in English ("Name" and "HelpText" struct members). You can manually resolve identifiers in a different language by using the NameTable API.
Performance Counters intro ¶
Windows has a system-wide performance counter mechanism. Most performance counters are stored as actual counters, not gauges (with some exceptions). There's additional metadata which defines how the counter should be presented to the user (for example, as a calculated rate). This library disregards all of the display metadata.
At the top level, there's a number of performance counter objects. Each object has counter definitions, which contain the metadata for a particular counter, and either zero or multiple instances. We hide the fact that there are objects with no instances, and simply return a single null instance.
There's one counter per counter definition and instance (or the object itself, if there are no instances).
Behind the scenes, every perflib DLL provides one or more objects. Perflib has a registry where DLLs are dynamically registered and unregistered. Some third party applications like VMWare provide their own counters, but this is, sadly, a rare occurrence.
Different Windows releases have different numbers of counters.
Objects and counters are identified by well-known indices.
Here's an example object with one instance:
4320 WSMan Quota Statistics [7 counters, 1 instance(s)] `-- "WinRMService" `-- Total Requests/Second [4322] = 59 `-- User Quota Violations/Second [4324] = 0 `-- System Quota Violations/Second [4326] = 0 `-- Active Shells [4328] = 0 `-- Active Operations [4330] = 0 `-- Active Users [4332] = 0 `-- Process ID [4334] = 928
All "per second" metrics are counters, the rest are gauges.
Another example, with no instance:
4600 Network QoS Policy [6 counters, 1 instance(s)] `-- (default) `-- Packets transmitted [4602] = 1744 `-- Packets transmitted/sec [4604] = 4852 `-- Bytes transmitted [4606] = 4853 `-- Bytes transmitted/sec [4608] = 180388626632 `-- Packets dropped [4610] = 0 `-- Packets dropped/sec [4612] = 0
You can access the same values using PowerShell's Get-Counter cmdlet or the Performance Monitor.
> Get-Counter '\WSMan Quota Statistics(WinRMService)\Process ID' Timestamp CounterSamples --------- -------------- 1/28/2018 10:18:00 PM \\DEV\wsman quota statistics(winrmservice)\process id : 928 > (Get-Counter '\Process(Idle)\% Processor Time').CounterSamples[0] | Format-List * [..detailed output...]
Data for some of the objects is also available through WMI:
> Get-CimInstance Win32_PerfRawData_Counters_WSManQuotaStatistics Name : WinRMService [...] ActiveOperations : 0 ActiveShells : 0 ActiveUsers : 0 ProcessID : 928 SystemQuotaViolationsPerSecond : 0 TotalRequestsPerSecond : 59 UserQuotaViolationsPerSecond : 0
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SortObjects ¶
func SortObjects(p []*PerfObject)
Sort slice of objects by index. This is useful for displaying a human-readable list or dump, but unnecessary otherwise.
Types ¶
type NameTable ¶
type NameTable struct {
// contains filtered or unexported fields
}
var CounterNameTable NameTable
var HelpNameTable NameTable
func QueryNameTable ¶
Query a perflib name table from the registry. Specify the type and the language code (i.e. "Counter 009" or "Help 009") for English language.
func (*NameTable) LookupIndex ¶
func (*NameTable) LookupString ¶
type PerfCounter ¶
type PerfCounter struct { Value int64 Def *PerfCounterDef SecondValue int64 }
type PerfCounterDef ¶
type PerfCounterDef struct { Name string NameIndex uint HelpText string HelpTextIndex uint // For debugging - subject to removal. CounterType is a perflib // implementation detail (see perflib.h) and should not be used outside // of this package. We export it so we can show it on /dump. CounterType uint32 // PERF_TYPE_COUNTER (otherwise, it's a gauge) IsCounter bool // PERF_COUNTER_BASE (base value of a multi-value fraction) IsBaseValue bool // PERF_TIMER_100NS IsNanosecondCounter bool HasSecondValue bool // contains filtered or unexported fields }
type PerfInstance ¶
type PerfInstance struct { // *not* resolved using a name table Name string Counters []*PerfCounter // contains filtered or unexported fields }
Each object can have multiple instances. For example, In case the object has no instances, we return one single PerfInstance with an empty name.
type PerfObject ¶
type PerfObject struct { Name string // Same index you pass to QueryPerformanceData NameIndex uint HelpText string HelpTextIndex uint Instances []*PerfInstance CounterDefs []*PerfCounterDef Frequency int64 // contains filtered or unexported fields }
Top-level performance object (like "Process").
func QueryPerformanceData ¶
func QueryPerformanceData(query string) ([]*PerfObject, error)
Query all performance counters that match a given query.
The query can be any of the following:
- "Global" (all performance counters except those Windows marked as costly)
- "Costly" (only the costly ones)
- One or more object indices, separated by spaces ("238 2 5")
Many objects have dependencies - if you query one of them, you often get back more than you asked for.
Example ¶
objects, err := QueryPerformanceData("2") if err != nil { panic(err) } for _, object := range objects { fmt.Printf("%d %s [%d counters, %d instances]\n", object.NameIndex, object.Name, len(object.CounterDefs), len(object.Instances)) for _, instance := range object.Instances { if !((instance.Name == "_Total") || (instance.Name == "")) { continue } if instance.Name == "" { fmt.Println("No instance.", instance.Name) } else { fmt.Println("Instance:", instance.Name) } for _, counter := range instance.Counters { fmt.Printf(" -> %s %d\n", counter.Def.Name, counter.Def.NameIndex) } } }
Output: