hyperv: fix misnamed root partition metrics, counter types and units (#2720)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-15 17:58:31 +00:00
committed by GitHub
parent 8fe85c143b
commit 55275e7db1
9 changed files with 368 additions and 87 deletions
+11
View File
@@ -213,6 +213,17 @@ Renamed:
| 0.31 | 0.32 | Note | | 0.31 | 0.32 | Note |
|------------------------------------------------------|----------------------------------------------------------------|------------------------------------| |------------------------------------------------------|----------------------------------------------------------------|------------------------------------|
| `windows_hyperv_virtual_storage_device_throughput` | `windows_hyperv_virtual_storage_device_throughput_total` | Now a counter, use `rate()` | | `windows_hyperv_virtual_storage_device_throughput` | `windows_hyperv_virtual_storage_device_throughput_total` | Now a counter, use `rate()` |
| `windows_hyperv_virtual_storage_device_normalized_throughput` | `windows_hyperv_virtual_storage_device_normalized_throughput_total` | Now a counter, use `rate()` |
| `windows_hyperv_io_quota_replenishment_rate` | `windows_hyperv_virtual_storage_device_io_quota_replenishment_total` | Now a counter, use `rate()` |
| `windows_hyperv_root_partition_preferred_numa_node_index` | `windows_hyperv_root_partition_gpa_pages` | Same value; the old name was wrong |
| `windows_hyperv_root_partition_physical_pages_allocated` | `windows_hyperv_root_partition_skipped_timer_ticks_total` | Same value; the old name was wrong, now a counter |
| `windows_hyperv_root_partition_device_interrupt_throttle_events` | `windows_hyperv_root_partition_device_interrupt_throttle_events_total` | Now a counter |
| `windows_hyperv_root_partition_io_tlb_flush_cost` | `windows_hyperv_root_partition_io_tlb_flush_seconds_total` | Same value, cumulative seconds, now a counter. Divide its rate by `rate(windows_hyperv_root_partition_io_tlb_flushes_total)` for the average time per flush |
| `windows_hyperv_root_partition_io_tlb_flush` | `windows_hyperv_root_partition_io_tlb_flushes_total` | Same value |
| `windows_hyperv_root_partition_gpa_space_modifications` | `windows_hyperv_root_partition_gpa_space_modifications_total` | Same value |
| `windows_hyperv_root_partition_virtual_tlb_flush_entries` | `windows_hyperv_root_partition_virtual_tlb_flush_entries_total` | Same value |
| `windows_hyperv_hypervisor_virtual_processor_cpu_wait_time_per_dispatch_total` | `windows_hyperv_hypervisor_virtual_processor_cpu_wait_seconds_total` | Same value, cumulative seconds. Divide its rate by `rate(windows_hyperv_hypervisor_virtual_processor_dispatches_total)` for the average wait per dispatch |
| `windows_hyperv_hypervisor_root_virtual_cpu_wait_time_per_dispatch_total` | `windows_hyperv_hypervisor_root_virtual_processor_cpu_wait_seconds_total` | Same value, cumulative seconds. Divide its rate by `rate(windows_hyperv_hypervisor_root_virtual_processor_dispatches_total)` for the average wait per dispatch |
| `windows_filetime_mtime_timestamp_seconds` | `windows_file_mtime_timestamp_seconds` | See [filetime](#filetime-collector-removed) | | `windows_filetime_mtime_timestamp_seconds` | `windows_file_mtime_timestamp_seconds` | See [filetime](#filetime-collector-removed) |
| `windows_memory_commit_limit` | `windows_memory_commit_limit_bytes` | Unit suffix added, same value | | `windows_memory_commit_limit` | `windows_memory_commit_limit_bytes` | Unit suffix added, same value |
| `windows_memory_pool_paged_allocs_total` | `windows_memory_pool_paged_allocs` | Now a gauge, query it without `rate()` | | `windows_memory_pool_paged_allocs_total` | `windows_memory_pool_paged_allocs` | Now a gauge, query it without `rate()` |
+24 -22
View File
@@ -157,20 +157,20 @@ Multiply by the number of threads per core to get the ratio per **physical** cor
| `windows_hyperv_root_partition_device_dma_errors` | An indicator of illegal DMA requests generated by all devices assigned to the partition | gauge | None | | `windows_hyperv_root_partition_device_dma_errors` | An indicator of illegal DMA requests generated by all devices assigned to the partition | gauge | None |
| `windows_hyperv_root_partition_device_interrupt_errors` | An indicator of illegal interrupt requests generated by all devices assigned to the partition | gauge | None | | `windows_hyperv_root_partition_device_interrupt_errors` | An indicator of illegal interrupt requests generated by all devices assigned to the partition | gauge | None |
| `windows_hyperv_root_partition_device_interrupt_mappings` | The number of device interrupt mappings used by the partition | gauge | None | | `windows_hyperv_root_partition_device_interrupt_mappings` | The number of device interrupt mappings used by the partition | gauge | None |
| `windows_hyperv_root_partition_device_interrupt_throttle_events` | The number of times an interrupt from a device assigned to the partition was temporarily throttled because the device was generating too many interrupts | gauge | None | | `windows_hyperv_root_partition_device_interrupt_throttle_events_total` | The number of times an interrupt from a device assigned to the partition was temporarily throttled because the device was generating too many interrupts | counter | None |
| `windows_hyperv_root_partition_preferred_numa_node_index` | The number of pages present in the GPA space of the partition (zero for root partition) | gauge | None | | `windows_hyperv_root_partition_gpa_pages` | The number of pages present in the GPA space of the partition (zero for root partition) | gauge | None |
| `windows_hyperv_root_partition_gpa_space_modifications` | The rate of modifications to the GPA space of the partition | counter | None | | `windows_hyperv_root_partition_gpa_space_modifications_total` | The number of modifications to the GPA space of the partition | counter | None |
| `windows_hyperv_root_partition_io_tlb_flush_cost` | The average time (in nanoseconds) spent processing an I/O TLB flush | gauge | None | | `windows_hyperv_root_partition_io_tlb_flush_seconds_total` | The time spent processing I/O TLB flushes. Divide its rate by the rate of `windows_hyperv_root_partition_io_tlb_flushes_total` for the average time per flush | counter | None |
| `windows_hyperv_root_partition_io_tlb_flush` | The rate of flushes of I/O TLBs of the partition | counter | None | | `windows_hyperv_root_partition_io_tlb_flushes_total` | The number of flushes of I/O TLBs of the partition | counter | None |
| `windows_hyperv_root_partition_recommended_virtual_tlb_size` | The recommended number of pages to be deposited for the virtual TLB | gauge | None | | `windows_hyperv_root_partition_recommended_virtual_tlb_size` | The recommended number of pages to be deposited for the virtual TLB | gauge | None |
| `windows_hyperv_root_partition_physical_pages_allocated` | The number of timer interrupts skipped for the partition | gauge | None | | `windows_hyperv_root_partition_skipped_timer_ticks_total` | The number of timer interrupts skipped for the partition | counter | None |
| `windows_hyperv_root_partition_1G_device_pages` | The number of 1G pages present in the device space of the partition | gauge | None | | `windows_hyperv_root_partition_1G_device_pages` | The number of 1G pages present in the device space of the partition | gauge | None |
| `windows_hyperv_root_partition_1G_gpa_pages` | The number of 1G pages present in the GPA space of the partition | gauge | None | | `windows_hyperv_root_partition_1G_gpa_pages` | The number of 1G pages present in the GPA space of the partition | gauge | None |
| `windows_hyperv_root_partition_2M_device_pages` | The number of 2M pages present in the device space of the partition | gauge | None | | `windows_hyperv_root_partition_2M_device_pages` | The number of 2M pages present in the device space of the partition | gauge | None |
| `windows_hyperv_root_partition_2M_gpa_pages` | The number of 2M pages present in the GPA space of the partition | gauge | None | | `windows_hyperv_root_partition_2M_gpa_pages` | The number of 2M pages present in the GPA space of the partition | gauge | None |
| `windows_hyperv_root_partition_4K_device_pages` | The number of 4K pages present in the device space of the partition | gauge | None | | `windows_hyperv_root_partition_4K_device_pages` | The number of 4K pages present in the device space of the partition | gauge | None |
| `windows_hyperv_root_partition_4K_gpa_pages` | The number of 4K pages present in the GPA space of the partition | gauge | None | | `windows_hyperv_root_partition_4K_gpa_pages` | The number of 4K pages present in the GPA space of the partition | gauge | None |
| `windows_hyperv_root_partition_virtual_tlb_flush_entries` | The rate of flushes of the entire virtual TLB | counter | None | | `windows_hyperv_root_partition_virtual_tlb_flush_entries_total` | The number of flushes of the entire virtual TLB | counter | None |
| `windows_hyperv_root_partition_virtual_tlb_pages` | The number of pages used by the virtual TLB of the partition | gauge | None | | `windows_hyperv_root_partition_virtual_tlb_pages` | The number of pages used by the virtual TLB of the partition | gauge | None |
@@ -178,9 +178,10 @@ Multiply by the number of threads per core to get the ratio per **physical** cor
| Name | Description | Type | Labels | | Name | Description | Type | Labels |
|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|---------|----------------| |---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|---------|----------------|
| `windows_hyperv_hypervisor_root_virtual_processor_time_total` | Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote) | counter | `core`,`state` | | `windows_hyperv_hypervisor_root_virtual_processor_time_total` | Time in seconds that processor spent in different modes (`state`: `guest_run`, `hypervisor`, `remote`) | counter | `core`,`state` |
| `windows_hyperv_hypervisor_root_virtual_processor_total_run_time_total` | Time that processor spent | counter | `core` | | `windows_hyperv_hypervisor_root_virtual_processor_total_run_time_total` | Time in seconds that processor spent running | counter | `core` |
| `windows_hyperv_hypervisor_root_virtual_cpu_wait_time_per_dispatch_total` | The average time (in nanoseconds) spent waiting for a virtual processor to be dispatched onto a logical processor | counter | `core` | | `windows_hyperv_hypervisor_root_virtual_processor_cpu_wait_seconds_total` | The time spent waiting for a virtual processor to be dispatched onto a logical processor. Divide its rate by the rate of `windows_hyperv_hypervisor_root_virtual_processor_dispatches_total` for the average wait per dispatch | counter | `core` |
| `windows_hyperv_hypervisor_root_virtual_processor_dispatches_total` | The number of times the virtual processor was dispatched onto a logical processor | counter | `core` |
### Hyper-V Legacy Network Adapter ### Hyper-V Legacy Network Adapter
@@ -271,11 +272,12 @@ Example alert:
| Name | Description | Type | Labels | | Name | Description | Type | Labels |
|--------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|---------|-----------------------| |--------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|---------|-----------------------|
| `windows_hyperv_hypervisor_virtual_processor_mode_time_total` | Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote) | counter | `vm`, `core`, `state` | | `windows_hyperv_hypervisor_virtual_processor_mode_time_total` | Time in seconds that processor spent in different modes (`state`: `hypervisor`, `guest`, `remote`) | counter | `vm`, `core`, `state` |
| `windows_hyperv_hypervisor_virtual_processor_run_time_total` | Time that processor spent | counter | `vm`, `core` | | `windows_hyperv_hypervisor_virtual_processor_run_time_total` | Time in seconds that processor spent running | counter | `vm`, `core` |
| `windows_hyperv_hypervisor_virtual_processor_cpu_wait_time_per_dispatch_total` | The average time (in nanoseconds) spent waiting for a virtual processor to be dispatched onto a logical processor. | counter | `vm`, `core` | | `windows_hyperv_hypervisor_virtual_processor_cpu_wait_seconds_total` | The time spent waiting for a virtual processor to be dispatched onto a logical processor. Divide its rate by the rate of `windows_hyperv_hypervisor_virtual_processor_dispatches_total` for the average wait per dispatch | counter | `vm`, `core` |
| `windows_hyperv_hypervisor_virtual_processor_time_total` | **Deprecated:** use `windows_hyperv_hypervisor_virtual_processor_mode_time_total`. Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote) | counter | `vm`, `core`, `state` | | `windows_hyperv_hypervisor_virtual_processor_dispatches_total` | The number of times the virtual processor was dispatched onto a logical processor | counter | `vm`, `core` |
| `windows_hyperv_hypervisor_virtual_processor_total_run_time_total` | **Deprecated:** use `windows_hyperv_hypervisor_virtual_processor_run_time_total`. Time that processor spent | counter | `vm`, `core` | | `windows_hyperv_hypervisor_virtual_processor_time_total` | **Deprecated:** use `windows_hyperv_hypervisor_virtual_processor_mode_time_total`. Time in seconds that processor spent in different modes (`state`: `hypervisor`, `guest`, `remote`) | counter | `vm`, `core`, `state` |
| `windows_hyperv_hypervisor_virtual_processor_total_run_time_total` | **Deprecated:** use `windows_hyperv_hypervisor_virtual_processor_run_time_total`. Time in seconds that processor spent running | counter | `vm`, `core` |
### Hyper-V Virtual Network Adapter ### Hyper-V Virtual Network Adapter
@@ -355,12 +357,12 @@ Example alert:
| `windows_hyperv_virtual_storage_device_operations_written_total` | Represents the total number of write operations that have occurred on this virtual device. | counter | `device` | | `windows_hyperv_virtual_storage_device_operations_written_total` | Represents the total number of write operations that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_io_latency_seconds_total` | Represents the total IO transfer latency for this virtual device. | counter | `device` | | `windows_hyperv_virtual_storage_device_io_latency_seconds_total` | Represents the total IO transfer latency for this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` | | `windows_hyperv_virtual_storage_device_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_throughput_total` | Represents the total number of 8KB IO transfers completed by this virtual device. | counter | `device` | | `windows_hyperv_virtual_storage_device_throughput_total` | Represents the total number of IO transfers completed by this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_normalized_throughput` | Represents the average number of IO transfers completed by this virtual device. | gauge | `device` | | `windows_hyperv_virtual_storage_device_normalized_throughput_total` | Represents the total number of IO transfers completed by this virtual device, normalized to 8KB transfers. | counter | `device` |
| `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total` | Represents the total IO transfer latency on the underlying storage subsystem for this virtual device. | counter | `device` | | `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total` | Represents the total IO transfer latency on the underlying storage subsystem for this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_lower_queue_length` | **Deprecated:** use `rate(windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total)`. Cumulative queue length in 100ns ticks, see below. | gauge | `device` | | `windows_hyperv_virtual_storage_device_lower_queue_length` | **Deprecated:** use `rate(windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total)`. Cumulative queue length in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_lower_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` | | `windows_hyperv_virtual_storage_device_lower_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_io_quota_replenishment_rate` | Represents the IO quota replenishment rate for this virtual device. | gauge | `device` | | `windows_hyperv_virtual_storage_device_io_quota_replenishment_total` | Represents the IO quota replenishment counter for this virtual device. Use `rate()` for the replenishment rate. | counter | `device` |
#### Deprecated latency and queue length metrics #### Deprecated latency and queue length metrics
@@ -493,19 +495,19 @@ _This collector does not yet have explained examples, we would appreciate your h
## Useful queries ## Useful queries
Percent of physical CPU resources used per VM (on instance "localhost") Percent of physical CPU resources used per VM (on instance "localhost")
``` ```
(sum (rate(windows_hyperv_hypervisor_virtual_processor_mode_time_total{state="hypervisor",instance="localhost"}[1m]))) / ignoring(state,vm) group_left max (windows_cpu_logical_processor{instance="localhost"}) / 100000 sum by (vm) (rate(windows_hyperv_hypervisor_virtual_processor_run_time_total{instance="localhost"}[1m])) / ignoring(vm) group_left max (windows_cpu_logical_processor{instance="localhost"}) * 100
``` ```
Percent of physical CPU resources used by all VMs (on all monitored hosts) Percent of physical CPU resources used by all VMs (on all monitored hosts)
``` ```
(sum by (instance)(rate(windows_hyperv_hypervisor_virtual_processor_run_time_total{}[1m]))) / max by (instance)(windows_cpu_logical_processor{}) / 100000 (sum by (instance)(rate(windows_hyperv_hypervisor_virtual_processor_run_time_total{}[1m]))) / max by (instance)(windows_cpu_logical_processor{}) * 100
``` ```
Percent of physical CPU resources by the hosts themselves (on all monitored hosts) Percent of physical CPU resources by the hosts themselves (on all monitored hosts)
``` ```
(sum by (instance)(rate(windows_hyperv_hypervisor_root_virtual_processor_total_run_time_total{}[1m]))) / sum by (instance)(windows_cpu_logical_processor{}) / 100000 (sum by (instance)(rate(windows_hyperv_hypervisor_root_virtual_processor_total_run_time_total{}[1m]))) / sum by (instance)(windows_cpu_logical_processor{}) * 100
``` ```
Percent of physical CPU resources by the hypervisor (on all monitored hosts) Percent of physical CPU resources by the hypervisor (on all monitored hosts)
``` ```
(sum by (instance)(rate(windows_hyperv_hypervisor_logical_processor_time_total{}[1m]))) / sum by (instance)(windows_cpu_logical_processor{}) / 100000 (sum by (instance)(rate(windows_hyperv_hypervisor_logical_processor_time_total{state="hypervisor"}[1m]))) / sum by (instance)(windows_cpu_logical_processor{}) * 100
``` ```
## Alerting examples ## Alerting examples
+19 -5
View File
@@ -19,11 +19,17 @@ memory) on a host with 12 logical processors.
`% Total Run Time` is about `% Guest Run Time` + `% Hypervisor Run Time`. `% Total Run Time` is about `% Guest Run Time` + `% Hypervisor Run Time`.
The help text of `CPU Wait Time Per Dispatch` and `I/O TLB Flush Cost` says The help text of `CPU Wait Time Per Dispatch` and `I/O TLB Flush Cost` says
"average time (in nanoseconds)", but the raw value is cumulative 100 ns "average time (in nanoseconds)", but the raw value is cumulative 100 ns
ticks. ticks. `internal/pdh` already scales `PERF_PRECISION_100NS_TIMER` to
seconds, so do not scale again. Publish both as `_seconds_total` counters
next to their operation count (`Logical Processor Dispatches/sec`,
`I/O TLB Flushes/sec`), so the average is a ratio of the two rates.
- The virtual processor `state` label is `hypervisor`, `guest`, `remote` for
VMs and `guest_run`, `hypervisor`, `remote` for root VPs. There is no idle
state.
- `Hyper-V Hypervisor Root Partition` is read for the instance `Root` only. - `Hyper-V Hypervisor Root Partition` is read for the instance `Root` only.
All its non-`/sec` counters are `PERF_COUNTER_LARGE_RAWCOUNT`. Page counts All its non-`/sec` counters are `PERF_COUNTER_LARGE_RAWCOUNT`. Page counts
and sizes are gauges; by the help text `Skipped Timer Ticks` and and sizes are gauges; by the help text `Skipped Timer Ticks` and
`Device Interrupt Throttle Events` count events. `Device Interrupt Throttle Events` count events, so they are counters.
- Dynamic Memory: memory counters are in MB (`Physical Memory` and - Dynamic Memory: memory counters are in MB (`Physical Memory` and
`Guest Visible Physical Memory` are 2048 for the 2 GiB VM). `Added Memory` `Guest Visible Physical Memory` are 2048 for the 2 GiB VM). `Added Memory`
and `Removed Memory` are cumulative MB, `Memory Add/Remove Operations` are and `Removed Memory` are cumulative MB, `Memory Add/Remove Operations` are
@@ -52,7 +58,9 @@ memory) on a host with 12 logical processors.
`Read Count` + `Write Count` (6 + 4). `Read Count` + `Write Count` (6 + 4).
- `Throughput` (`PERF_COUNTER_COUNTER`) counts IO transfers. - `Throughput` (`PERF_COUNTER_COUNTER`) counts IO transfers.
`Normalized Throughput` (`PERF_COUNTER_BULK_COUNT`) counts 8 KB IO `Normalized Throughput` (`PERF_COUNTER_BULK_COUNT`) counts 8 KB IO
transfers by its help text. Both raw values are cumulative. transfers by its help text. Both raw values are cumulative, as is
`Io Quota Replenishment Rate` (`PERF_COUNTER_BULK_COUNT`); publish them
as counters.
- `Read Count`, `Write Count` and `Error Count` are - `Read Count`, `Write Count` and `Error Count` are
`PERF_COUNTER_RAWCOUNT` but cumulative ("total number of ..."). `PERF_COUNTER_RAWCOUNT` but cumulative ("total number of ...").
- `Hyper-V Virtual Switch` and `Hyper-V Virtual Network Adapter`: all - `Hyper-V Virtual Switch` and `Hyper-V Virtual Network Adapter`: all
@@ -81,6 +89,10 @@ memory) on a host with 12 logical processors.
the one VM. the one VM.
- The `wmi_health`, `virtual_hard_disk` and host VM processor metrics do not - The `wmi_health`, `virtual_hard_disk` and host VM processor metrics do not
come from PDH, so the table below does not cover them. come from PDH, so the table below does not cover them.
- To test emitted metrics without Hyper-V, build the descriptors with the
`build...Descriptors` helpers, fill the `perfDataObject...` slice (or a
`pdhtypes.Collector` fixture) and gather through a registry, as in
`hyperv_metric_types_internal_test.go`.
## Counter reference ## Counter reference
@@ -252,10 +264,11 @@ Counters the collector reads:
| `% Remote Run Time` | `PERF_PRECISION_100NS_TIMER` | 0 | | | `% Remote Run Time` | `PERF_PRECISION_100NS_TIMER` | 0 | |
| `% Total Run Time` | `PERF_PRECISION_100NS_TIMER` | 10411471300 | | | `% Total Run Time` | `PERF_PRECISION_100NS_TIMER` | 10411471300 | |
| `CPU Wait Time Per Dispatch` | `PERF_PRECISION_100NS_TIMER` | 290865977 | | | `CPU Wait Time Per Dispatch` | `PERF_PRECISION_100NS_TIMER` | 290865977 | |
| `Logical Processor Dispatches/sec` | `PERF_COUNTER_BULK_COUNT` | 3171435 | |
Not read by the collector: Not read by the collector:
- `PERF_COUNTER_BULK_COUNT`: `Address Domain Flushes/sec`, `Address Space Evictions/sec`, `Address Space Flushes/sec`, `Address Space Switches/sec`, `APIC EOI Accesses/sec`, `APIC IPIs Sent/sec`, `APIC MMIO Accesses/sec`, `APIC Self IPIs Sent/sec`, `APIC TPR Accesses/sec`, `Bus Lock Acquisitions/sec`, `Control Register Accesses Forwarded/sec`, `Control Register Accesses/sec`, `CPPC Request Context Switches/sec`, `CPU Group Hypercalls/sec`, `CPUID Instructions Forwarded/sec`, `CPUID Instructions/sec`, `Debug Register Accesses Forwarded/sec`, `Debug Register Accesses/sec`, `Deposit Hypercalls/sec`, `Device Domain Hypercalls/sec`, `Emulated Instructions Forwarded/sec`, `Emulated Instructions/sec`, `Event Log Hypercalls/sec`, `Extended Hypercall Intercept Messages/sec`, `Extended Hypercalls/sec`, `External Interrupts Forwarded/sec`, `External Interrupts/sec`, `Flush Physical Address List Hypercalls/sec`, `Flush Physical Address Space Hypercalls/sec`, `GIF Instruction Emulation Intercepts/sec`, `Global GVA Range Flushes/sec`, `Global I/O TLB Flushes/sec`, `GPA Space Hypercalls/sec`, `Guest Page Table Maps/sec`, `Hardware Interrupts/sec`, `HLT Instructions Forwarded/sec`, `HLT Instructions/sec`, `Hypercalls Forwarded/sec`, `Hypercalls/sec`, `InvEpt All Context Emulation Intercepts/sec`, `InvEpt Single Context Emulation Intercepts/sec`, `InvVpid All Context Emulation Intercepts/sec`, `InvVpid Single Address Emulation Intercepts/sec`, `InvVpid Single Context Emulation Intercepts/sec`, `IO Instructions Forwarded/sec`, `IO Instructions/sec`, `IO Intercept Messages/sec`, `IOMMU Hypercalls/sec`, `Large Page TLB Fills/sec`, `Local Flushed GVA Ranges/sec`, `Local I/O TLB Flushes/sec`, `Logical Processor Dispatches/sec`, `Logical Processor Hypercalls/sec`, `Logical Processor Migrations/sec`, `Long Spin Wait Hypercalls/sec`, `MBEC Nested Page Table Switches/sec`, `Memory Intercept Messages/sec`, `MSR Accesses Forwarded/sec`, `MSR Accesses/sec`, `MWAIT Instructions Forwarded/sec`, `MWAIT Instructions/sec`, `Nested Page Fault Intercepts/sec`, `Nested SLAT Hard Page Faults/sec`, `Nested SLAT Soft Page Faults/sec`, `Nested TLB Page Table Evictions/sec`, `Nested TLB Page Table Reclamations/sec`, `Nested VM Entries/sec`, `Other Hypercalls/sec`, `Other Intercepts Forwarded/sec`, `Other Intercepts/sec`, `Other Messages/sec`, `Other Reflected Guest Exceptions/sec`, `Page Fault Intercepts Forwarded/sec`, `Page Fault Intercepts/sec`, `Page Invalidations Forwarded/sec`, `Page Invalidations/sec`, `Page Scans/sec`, `Page Table Allocations/sec`, `Page Table Evictions/sec`, `Page Table Reclamations/sec`, `Page Table Resets/sec`, `Page Table Validations/sec`, `Page Table Write Intercepts/sec`, `Pending Interrupts Forwarded/sec`, `Pending Interrupts/sec`, `Performance Monitoring Interrupts/sec`, `Performance Monitoring IPT MSR Accesses/sec`, `Performance Monitoring LBR MSR Accesses/sec`, `Performance Monitoring vPMU MSR Accesses/sec`, `Posted Interrupt Notifications/sec`, `Posted Interrupt Scans/sec`, `RDPMC Instructions/sec`, `Reflected Guest Page Faults/sec`, `Small Page TLB Fills/sec`, `SVM Hypercalls/sec`, `Synthetic Interrupt Hypercalls/sec`, `Synthetic Interrupts/sec`, `Total Intercepts/sec`, `Total Messages/sec`, `Total Virtualization Instructions Emulated/sec`, `Virtual Interrupt Hypercalls/sec`, `Virtual Interrupts/sec`, `Virtual MMU Hypercalls/sec`, `Virtual Processor Hypercalls/sec`, `VMCLEAR Emulation Intercepts/sec`, `VMLOAD Emulation Intercepts/sec`, `VMPTRLD Emulation Intercepts/sec`, `VMPTRST Emulation Intercepts/sec`, `VMREAD Emulation Intercepts/sec`, `VMSAVE Emulation Intercepts/sec`, `VMWRITE Emulation Intercepts/sec`, `VMXOFF Emulation Intercepts/sec`, `VMXON Emulation Intercepts/sec`, `VSM Hypercalls/sec`, `VTL1 Dispatches/sec`, `VTL2 Dispatches/sec` - `PERF_COUNTER_BULK_COUNT`: `Address Domain Flushes/sec`, `Address Space Evictions/sec`, `Address Space Flushes/sec`, `Address Space Switches/sec`, `APIC EOI Accesses/sec`, `APIC IPIs Sent/sec`, `APIC MMIO Accesses/sec`, `APIC Self IPIs Sent/sec`, `APIC TPR Accesses/sec`, `Bus Lock Acquisitions/sec`, `Control Register Accesses Forwarded/sec`, `Control Register Accesses/sec`, `CPPC Request Context Switches/sec`, `CPU Group Hypercalls/sec`, `CPUID Instructions Forwarded/sec`, `CPUID Instructions/sec`, `Debug Register Accesses Forwarded/sec`, `Debug Register Accesses/sec`, `Deposit Hypercalls/sec`, `Device Domain Hypercalls/sec`, `Emulated Instructions Forwarded/sec`, `Emulated Instructions/sec`, `Event Log Hypercalls/sec`, `Extended Hypercall Intercept Messages/sec`, `Extended Hypercalls/sec`, `External Interrupts Forwarded/sec`, `External Interrupts/sec`, `Flush Physical Address List Hypercalls/sec`, `Flush Physical Address Space Hypercalls/sec`, `GIF Instruction Emulation Intercepts/sec`, `Global GVA Range Flushes/sec`, `Global I/O TLB Flushes/sec`, `GPA Space Hypercalls/sec`, `Guest Page Table Maps/sec`, `Hardware Interrupts/sec`, `HLT Instructions Forwarded/sec`, `HLT Instructions/sec`, `Hypercalls Forwarded/sec`, `Hypercalls/sec`, `InvEpt All Context Emulation Intercepts/sec`, `InvEpt Single Context Emulation Intercepts/sec`, `InvVpid All Context Emulation Intercepts/sec`, `InvVpid Single Address Emulation Intercepts/sec`, `InvVpid Single Context Emulation Intercepts/sec`, `IO Instructions Forwarded/sec`, `IO Instructions/sec`, `IO Intercept Messages/sec`, `IOMMU Hypercalls/sec`, `Large Page TLB Fills/sec`, `Local Flushed GVA Ranges/sec`, `Local I/O TLB Flushes/sec`, `Logical Processor Hypercalls/sec`, `Logical Processor Migrations/sec`, `Long Spin Wait Hypercalls/sec`, `MBEC Nested Page Table Switches/sec`, `Memory Intercept Messages/sec`, `MSR Accesses Forwarded/sec`, `MSR Accesses/sec`, `MWAIT Instructions Forwarded/sec`, `MWAIT Instructions/sec`, `Nested Page Fault Intercepts/sec`, `Nested SLAT Hard Page Faults/sec`, `Nested SLAT Soft Page Faults/sec`, `Nested TLB Page Table Evictions/sec`, `Nested TLB Page Table Reclamations/sec`, `Nested VM Entries/sec`, `Other Hypercalls/sec`, `Other Intercepts Forwarded/sec`, `Other Intercepts/sec`, `Other Messages/sec`, `Other Reflected Guest Exceptions/sec`, `Page Fault Intercepts Forwarded/sec`, `Page Fault Intercepts/sec`, `Page Invalidations Forwarded/sec`, `Page Invalidations/sec`, `Page Scans/sec`, `Page Table Allocations/sec`, `Page Table Evictions/sec`, `Page Table Reclamations/sec`, `Page Table Resets/sec`, `Page Table Validations/sec`, `Page Table Write Intercepts/sec`, `Pending Interrupts Forwarded/sec`, `Pending Interrupts/sec`, `Performance Monitoring Interrupts/sec`, `Performance Monitoring IPT MSR Accesses/sec`, `Performance Monitoring LBR MSR Accesses/sec`, `Performance Monitoring vPMU MSR Accesses/sec`, `Posted Interrupt Notifications/sec`, `Posted Interrupt Scans/sec`, `RDPMC Instructions/sec`, `Reflected Guest Page Faults/sec`, `Small Page TLB Fills/sec`, `SVM Hypercalls/sec`, `Synthetic Interrupt Hypercalls/sec`, `Synthetic Interrupts/sec`, `Total Intercepts/sec`, `Total Messages/sec`, `Total Virtualization Instructions Emulated/sec`, `Virtual Interrupt Hypercalls/sec`, `Virtual Interrupts/sec`, `Virtual MMU Hypercalls/sec`, `Virtual Processor Hypercalls/sec`, `VMCLEAR Emulation Intercepts/sec`, `VMLOAD Emulation Intercepts/sec`, `VMPTRLD Emulation Intercepts/sec`, `VMPTRST Emulation Intercepts/sec`, `VMREAD Emulation Intercepts/sec`, `VMSAVE Emulation Intercepts/sec`, `VMWRITE Emulation Intercepts/sec`, `VMXOFF Emulation Intercepts/sec`, `VMXON Emulation Intercepts/sec`, `VSM Hypercalls/sec`, `VTL1 Dispatches/sec`, `VTL2 Dispatches/sec`
- `PERF_COUNTER_LARGE_RAWCOUNT`: `Scheduling Priority` - `PERF_COUNTER_LARGE_RAWCOUNT`: `Scheduling Priority`
- `PERF_PRECISION_100NS_TIMER`: `% Guest-Relative Utilization`, `% Total Core Run Time`, `% VTL1 Run Time`, `% VTL2 Run Time`, `Control Register Accesses Cost`, `Control Register Accesses Forwarding Cost`, `CPU Contention Time Per Dispatch`, `CPU Wake Up Time Per Dispatch`, `CPUID Instructions Cost`, `CPUID Instructions Forwarding Cost`, `Debug Register Accesses Cost`, `Debug Register Accesses Forwarding Cost`, `Emulated Instructions Cost`, `Emulated Instructions Forwarding Cost`, `External Interrupts Cost`, `GIF Instruction Emulation Cost`, `Global I/O TLB Flush Cost`, `HLT Instructions Cost`, `HLT Instructions Forwarding Cost`, `Hypercalls Cost`, `Hypercalls Forwarding Cost`, `InvEpt All Context Instruction Emulation Cost`, `InvEpt Single Context Instruction Emulation Cost`, `InvVpid All Context Instruction Emulation Cost`, `InvVpid Single Address Instruction Emulation Cost`, `InvVpid Single Context Instruction Emulation Cost`, `IO Instructions Cost`, `IO Instructions Forwarding Cost`, `Local I/O TLB Flush Cost`, `MSR Accesses Cost`, `MSR Accesses Forwarding Cost`, `MWAIT Instructions Cost`, `MWAIT Instructions Forwarding Cost`, `Nested Page Fault Intercepts Cost`, `Nested SLAT Hard Page Faults Cost`, `Nested SLAT Soft Page Faults Cost`, `Nested VM Entries Cost`, `Other Intercepts Cost`, `Other Intercepts Forwarding Cost`, `Page Fault Intercepts Cost`, `Page Fault Intercepts Forwarding Cost`, `Page Invalidations Cost`, `Page Invalidations Forwarding Cost`, `Pending Interrupts Cost`, `Pending Interrupts Forwarding Cost`, `RDPMC Instructions Cost`, `Total Intercepts Cost`, `Total Virtualization Instructions Emulation Cost`, `VMCLEAR Instruction Emulation Cost`, `VMLOAD Instruction Emulation Cost`, `VMPTRLD Instruction Emulation Cost`, `VMPTRST Instruction Emulation Cost`, `VMREAD Instruction Emulation Cost`, `VMSAVE Instruction Emulation Cost`, `VMWRITE Instruction Emulation Cost`, `VMXOFF Instruction Emulation Cost`, `VMXON Instruction Emulation Cost`, `VTL1 Average Run Time`, `VTL2 Average Run Time` - `PERF_PRECISION_100NS_TIMER`: `% Guest-Relative Utilization`, `% Total Core Run Time`, `% VTL1 Run Time`, `% VTL2 Run Time`, `Control Register Accesses Cost`, `Control Register Accesses Forwarding Cost`, `CPU Contention Time Per Dispatch`, `CPU Wake Up Time Per Dispatch`, `CPUID Instructions Cost`, `CPUID Instructions Forwarding Cost`, `Debug Register Accesses Cost`, `Debug Register Accesses Forwarding Cost`, `Emulated Instructions Cost`, `Emulated Instructions Forwarding Cost`, `External Interrupts Cost`, `GIF Instruction Emulation Cost`, `Global I/O TLB Flush Cost`, `HLT Instructions Cost`, `HLT Instructions Forwarding Cost`, `Hypercalls Cost`, `Hypercalls Forwarding Cost`, `InvEpt All Context Instruction Emulation Cost`, `InvEpt Single Context Instruction Emulation Cost`, `InvVpid All Context Instruction Emulation Cost`, `InvVpid Single Address Instruction Emulation Cost`, `InvVpid Single Context Instruction Emulation Cost`, `IO Instructions Cost`, `IO Instructions Forwarding Cost`, `Local I/O TLB Flush Cost`, `MSR Accesses Cost`, `MSR Accesses Forwarding Cost`, `MWAIT Instructions Cost`, `MWAIT Instructions Forwarding Cost`, `Nested Page Fault Intercepts Cost`, `Nested SLAT Hard Page Faults Cost`, `Nested SLAT Soft Page Faults Cost`, `Nested VM Entries Cost`, `Other Intercepts Cost`, `Other Intercepts Forwarding Cost`, `Page Fault Intercepts Cost`, `Page Fault Intercepts Forwarding Cost`, `Page Invalidations Cost`, `Page Invalidations Forwarding Cost`, `Pending Interrupts Cost`, `Pending Interrupts Forwarding Cost`, `RDPMC Instructions Cost`, `Total Intercepts Cost`, `Total Virtualization Instructions Emulation Cost`, `VMCLEAR Instruction Emulation Cost`, `VMLOAD Instruction Emulation Cost`, `VMPTRLD Instruction Emulation Cost`, `VMPTRST Instruction Emulation Cost`, `VMREAD Instruction Emulation Cost`, `VMSAVE Instruction Emulation Cost`, `VMWRITE Instruction Emulation Cost`, `VMXOFF Instruction Emulation Cost`, `VMXON Instruction Emulation Cost`, `VTL1 Average Run Time`, `VTL2 Average Run Time`
@@ -272,10 +285,11 @@ Counters the collector reads:
| `% Remote Run Time` | `PERF_PRECISION_100NS_TIMER` | 0 | | | `% Remote Run Time` | `PERF_PRECISION_100NS_TIMER` | 0 | |
| `% Total Run Time` | `PERF_PRECISION_100NS_TIMER` | 3180787877 | | | `% Total Run Time` | `PERF_PRECISION_100NS_TIMER` | 3180787877 | |
| `CPU Wait Time Per Dispatch` | `PERF_PRECISION_100NS_TIMER` | 1217187193 | | | `CPU Wait Time Per Dispatch` | `PERF_PRECISION_100NS_TIMER` | 1217187193 | |
| `Logical Processor Dispatches/sec` | `PERF_COUNTER_BULK_COUNT` | 2007559 | |
Not read by the collector: Not read by the collector:
- `PERF_COUNTER_BULK_COUNT`: `Address Domain Flushes/sec`, `Address Space Evictions/sec`, `Address Space Flushes/sec`, `Address Space Switches/sec`, `APIC EOI Accesses/sec`, `APIC IPIs Sent/sec`, `APIC MMIO Accesses/sec`, `APIC Self IPIs Sent/sec`, `APIC TPR Accesses/sec`, `Bus Lock Acquisitions/sec`, `Control Register Accesses Forwarded/sec`, `Control Register Accesses/sec`, `CPPC Request Context Switches/sec`, `CPU Group Hypercalls/sec`, `CPUID Instructions Forwarded/sec`, `CPUID Instructions/sec`, `Debug Register Accesses Forwarded/sec`, `Debug Register Accesses/sec`, `Deposit Hypercalls/sec`, `Device Domain Hypercalls/sec`, `Emulated Instructions Forwarded/sec`, `Emulated Instructions/sec`, `Event Log Hypercalls/sec`, `Extended Hypercall Intercept Messages/sec`, `Extended Hypercalls/sec`, `External Interrupts Forwarded/sec`, `External Interrupts/sec`, `Flush Physical Address List Hypercalls/sec`, `Flush Physical Address Space Hypercalls/sec`, `GIF Instruction Emulation Intercepts/sec`, `Global GVA Range Flushes/sec`, `Global I/O TLB Flushes/sec`, `GPA Space Hypercalls/sec`, `Guest Page Table Maps/sec`, `Hardware Interrupts/sec`, `HLT Instructions Forwarded/sec`, `HLT Instructions/sec`, `Hypercalls Forwarded/sec`, `Hypercalls/sec`, `InvEpt All Context Emulation Intercepts/sec`, `InvEpt Single Context Emulation Intercepts/sec`, `InvVpid All Context Emulation Intercepts/sec`, `InvVpid Single Address Emulation Intercepts/sec`, `InvVpid Single Context Emulation Intercepts/sec`, `IO Instructions Forwarded/sec`, `IO Instructions/sec`, `IO Intercept Messages/sec`, `IOMMU Hypercalls/sec`, `Large Page TLB Fills/sec`, `Local Flushed GVA Ranges/sec`, `Local I/O TLB Flushes/sec`, `Logical Processor Dispatches/sec`, `Logical Processor Hypercalls/sec`, `Logical Processor Migrations/sec`, `Long Spin Wait Hypercalls/sec`, `MBEC Nested Page Table Switches/sec`, `Memory Intercept Messages/sec`, `MSR Accesses Forwarded/sec`, `MSR Accesses/sec`, `MWAIT Instructions Forwarded/sec`, `MWAIT Instructions/sec`, `Nested Page Fault Intercepts/sec`, `Nested SLAT Hard Page Faults/sec`, `Nested SLAT Soft Page Faults/sec`, `Nested TLB Page Table Evictions/sec`, `Nested TLB Page Table Reclamations/sec`, `Nested VM Entries/sec`, `Other Hypercalls/sec`, `Other Intercepts Forwarded/sec`, `Other Intercepts/sec`, `Other Messages/sec`, `Other Reflected Guest Exceptions/sec`, `Page Fault Intercepts Forwarded/sec`, `Page Fault Intercepts/sec`, `Page Invalidations Forwarded/sec`, `Page Invalidations/sec`, `Page Scans/sec`, `Page Table Allocations/sec`, `Page Table Evictions/sec`, `Page Table Reclamations/sec`, `Page Table Resets/sec`, `Page Table Validations/sec`, `Page Table Write Intercepts/sec`, `Pending Interrupts Forwarded/sec`, `Pending Interrupts/sec`, `Performance Monitoring Interrupts/sec`, `Performance Monitoring IPT MSR Accesses/sec`, `Performance Monitoring LBR MSR Accesses/sec`, `Performance Monitoring vPMU MSR Accesses/sec`, `Posted Interrupt Notifications/sec`, `Posted Interrupt Scans/sec`, `RDPMC Instructions/sec`, `Reflected Guest Page Faults/sec`, `Small Page TLB Fills/sec`, `SVM Hypercalls/sec`, `Synthetic Interrupt Hypercalls/sec`, `Synthetic Interrupts/sec`, `Total Intercepts/sec`, `Total Messages/sec`, `Total Virtualization Instructions Emulated/sec`, `Virtual Interrupt Hypercalls/sec`, `Virtual Interrupts/sec`, `Virtual MMU Hypercalls/sec`, `Virtual Processor Hypercalls/sec`, `VMCLEAR Emulation Intercepts/sec`, `VMLOAD Emulation Intercepts/sec`, `VMPTRLD Emulation Intercepts/sec`, `VMPTRST Emulation Intercepts/sec`, `VMREAD Emulation Intercepts/sec`, `VMSAVE Emulation Intercepts/sec`, `VMWRITE Emulation Intercepts/sec`, `VMXOFF Emulation Intercepts/sec`, `VMXON Emulation Intercepts/sec`, `VSM Hypercalls/sec`, `VTL1 Dispatches/sec`, `VTL2 Dispatches/sec` - `PERF_COUNTER_BULK_COUNT`: `Address Domain Flushes/sec`, `Address Space Evictions/sec`, `Address Space Flushes/sec`, `Address Space Switches/sec`, `APIC EOI Accesses/sec`, `APIC IPIs Sent/sec`, `APIC MMIO Accesses/sec`, `APIC Self IPIs Sent/sec`, `APIC TPR Accesses/sec`, `Bus Lock Acquisitions/sec`, `Control Register Accesses Forwarded/sec`, `Control Register Accesses/sec`, `CPPC Request Context Switches/sec`, `CPU Group Hypercalls/sec`, `CPUID Instructions Forwarded/sec`, `CPUID Instructions/sec`, `Debug Register Accesses Forwarded/sec`, `Debug Register Accesses/sec`, `Deposit Hypercalls/sec`, `Device Domain Hypercalls/sec`, `Emulated Instructions Forwarded/sec`, `Emulated Instructions/sec`, `Event Log Hypercalls/sec`, `Extended Hypercall Intercept Messages/sec`, `Extended Hypercalls/sec`, `External Interrupts Forwarded/sec`, `External Interrupts/sec`, `Flush Physical Address List Hypercalls/sec`, `Flush Physical Address Space Hypercalls/sec`, `GIF Instruction Emulation Intercepts/sec`, `Global GVA Range Flushes/sec`, `Global I/O TLB Flushes/sec`, `GPA Space Hypercalls/sec`, `Guest Page Table Maps/sec`, `Hardware Interrupts/sec`, `HLT Instructions Forwarded/sec`, `HLT Instructions/sec`, `Hypercalls Forwarded/sec`, `Hypercalls/sec`, `InvEpt All Context Emulation Intercepts/sec`, `InvEpt Single Context Emulation Intercepts/sec`, `InvVpid All Context Emulation Intercepts/sec`, `InvVpid Single Address Emulation Intercepts/sec`, `InvVpid Single Context Emulation Intercepts/sec`, `IO Instructions Forwarded/sec`, `IO Instructions/sec`, `IO Intercept Messages/sec`, `IOMMU Hypercalls/sec`, `Large Page TLB Fills/sec`, `Local Flushed GVA Ranges/sec`, `Local I/O TLB Flushes/sec`, `Logical Processor Hypercalls/sec`, `Logical Processor Migrations/sec`, `Long Spin Wait Hypercalls/sec`, `MBEC Nested Page Table Switches/sec`, `Memory Intercept Messages/sec`, `MSR Accesses Forwarded/sec`, `MSR Accesses/sec`, `MWAIT Instructions Forwarded/sec`, `MWAIT Instructions/sec`, `Nested Page Fault Intercepts/sec`, `Nested SLAT Hard Page Faults/sec`, `Nested SLAT Soft Page Faults/sec`, `Nested TLB Page Table Evictions/sec`, `Nested TLB Page Table Reclamations/sec`, `Nested VM Entries/sec`, `Other Hypercalls/sec`, `Other Intercepts Forwarded/sec`, `Other Intercepts/sec`, `Other Messages/sec`, `Other Reflected Guest Exceptions/sec`, `Page Fault Intercepts Forwarded/sec`, `Page Fault Intercepts/sec`, `Page Invalidations Forwarded/sec`, `Page Invalidations/sec`, `Page Scans/sec`, `Page Table Allocations/sec`, `Page Table Evictions/sec`, `Page Table Reclamations/sec`, `Page Table Resets/sec`, `Page Table Validations/sec`, `Page Table Write Intercepts/sec`, `Pending Interrupts Forwarded/sec`, `Pending Interrupts/sec`, `Performance Monitoring Interrupts/sec`, `Performance Monitoring IPT MSR Accesses/sec`, `Performance Monitoring LBR MSR Accesses/sec`, `Performance Monitoring vPMU MSR Accesses/sec`, `Posted Interrupt Notifications/sec`, `Posted Interrupt Scans/sec`, `RDPMC Instructions/sec`, `Reflected Guest Page Faults/sec`, `Small Page TLB Fills/sec`, `SVM Hypercalls/sec`, `Synthetic Interrupt Hypercalls/sec`, `Synthetic Interrupts/sec`, `Total Intercepts/sec`, `Total Messages/sec`, `Total Virtualization Instructions Emulated/sec`, `Virtual Interrupt Hypercalls/sec`, `Virtual Interrupts/sec`, `Virtual MMU Hypercalls/sec`, `Virtual Processor Hypercalls/sec`, `VMCLEAR Emulation Intercepts/sec`, `VMLOAD Emulation Intercepts/sec`, `VMPTRLD Emulation Intercepts/sec`, `VMPTRST Emulation Intercepts/sec`, `VMREAD Emulation Intercepts/sec`, `VMSAVE Emulation Intercepts/sec`, `VMWRITE Emulation Intercepts/sec`, `VMXOFF Emulation Intercepts/sec`, `VMXON Emulation Intercepts/sec`, `VSM Hypercalls/sec`, `VTL1 Dispatches/sec`, `VTL2 Dispatches/sec`
- `PERF_COUNTER_LARGE_RAWCOUNT`: `Scheduling Priority` - `PERF_COUNTER_LARGE_RAWCOUNT`: `Scheduling Priority`
- `PERF_PRECISION_100NS_TIMER`: `% Guest-Relative Utilization`, `% Total Core Run Time`, `% VTL1 Run Time`, `% VTL2 Run Time`, `Control Register Accesses Cost`, `Control Register Accesses Forwarding Cost`, `CPU Contention Time Per Dispatch`, `CPU Wake Up Time Per Dispatch`, `CPUID Instructions Cost`, `CPUID Instructions Forwarding Cost`, `Debug Register Accesses Cost`, `Debug Register Accesses Forwarding Cost`, `Emulated Instructions Cost`, `Emulated Instructions Forwarding Cost`, `External Interrupts Cost`, `GIF Instruction Emulation Cost`, `Global I/O TLB Flush Cost`, `HLT Instructions Cost`, `HLT Instructions Forwarding Cost`, `Hypercalls Cost`, `Hypercalls Forwarding Cost`, `InvEpt All Context Instruction Emulation Cost`, `InvEpt Single Context Instruction Emulation Cost`, `InvVpid All Context Instruction Emulation Cost`, `InvVpid Single Address Instruction Emulation Cost`, `InvVpid Single Context Instruction Emulation Cost`, `IO Instructions Cost`, `IO Instructions Forwarding Cost`, `Local I/O TLB Flush Cost`, `MSR Accesses Cost`, `MSR Accesses Forwarding Cost`, `MWAIT Instructions Cost`, `MWAIT Instructions Forwarding Cost`, `Nested Page Fault Intercepts Cost`, `Nested SLAT Hard Page Faults Cost`, `Nested SLAT Soft Page Faults Cost`, `Nested VM Entries Cost`, `Other Intercepts Cost`, `Other Intercepts Forwarding Cost`, `Page Fault Intercepts Cost`, `Page Fault Intercepts Forwarding Cost`, `Page Invalidations Cost`, `Page Invalidations Forwarding Cost`, `Pending Interrupts Cost`, `Pending Interrupts Forwarding Cost`, `RDPMC Instructions Cost`, `Total Intercepts Cost`, `Total Virtualization Instructions Emulation Cost`, `VMCLEAR Instruction Emulation Cost`, `VMLOAD Instruction Emulation Cost`, `VMPTRLD Instruction Emulation Cost`, `VMPTRST Instruction Emulation Cost`, `VMREAD Instruction Emulation Cost`, `VMSAVE Instruction Emulation Cost`, `VMWRITE Instruction Emulation Cost`, `VMXOFF Instruction Emulation Cost`, `VMXON Instruction Emulation Cost`, `VTL1 Average Run Time`, `VTL2 Average Run Time` - `PERF_PRECISION_100NS_TIMER`: `% Guest-Relative Utilization`, `% Total Core Run Time`, `% VTL1 Run Time`, `% VTL2 Run Time`, `Control Register Accesses Cost`, `Control Register Accesses Forwarding Cost`, `CPU Contention Time Per Dispatch`, `CPU Wake Up Time Per Dispatch`, `CPUID Instructions Cost`, `CPUID Instructions Forwarding Cost`, `Debug Register Accesses Cost`, `Debug Register Accesses Forwarding Cost`, `Emulated Instructions Cost`, `Emulated Instructions Forwarding Cost`, `External Interrupts Cost`, `GIF Instruction Emulation Cost`, `Global I/O TLB Flush Cost`, `HLT Instructions Cost`, `HLT Instructions Forwarding Cost`, `Hypercalls Cost`, `Hypercalls Forwarding Cost`, `InvEpt All Context Instruction Emulation Cost`, `InvEpt Single Context Instruction Emulation Cost`, `InvVpid All Context Instruction Emulation Cost`, `InvVpid Single Address Instruction Emulation Cost`, `InvVpid Single Context Instruction Emulation Cost`, `IO Instructions Cost`, `IO Instructions Forwarding Cost`, `Local I/O TLB Flush Cost`, `MSR Accesses Cost`, `MSR Accesses Forwarding Cost`, `MWAIT Instructions Cost`, `MWAIT Instructions Forwarding Cost`, `Nested Page Fault Intercepts Cost`, `Nested SLAT Hard Page Faults Cost`, `Nested SLAT Soft Page Faults Cost`, `Nested VM Entries Cost`, `Other Intercepts Cost`, `Other Intercepts Forwarding Cost`, `Page Fault Intercepts Cost`, `Page Fault Intercepts Forwarding Cost`, `Page Invalidations Cost`, `Page Invalidations Forwarding Cost`, `Pending Interrupts Cost`, `Pending Interrupts Forwarding Cost`, `RDPMC Instructions Cost`, `Total Intercepts Cost`, `Total Virtualization Instructions Emulation Cost`, `VMCLEAR Instruction Emulation Cost`, `VMLOAD Instruction Emulation Cost`, `VMPTRLD Instruction Emulation Cost`, `VMPTRST Instruction Emulation Cost`, `VMREAD Instruction Emulation Cost`, `VMSAVE Instruction Emulation Cost`, `VMWRITE Instruction Emulation Cost`, `VMXOFF Instruction Emulation Cost`, `VMXON Instruction Emulation Cost`, `VTL1 Average Run Time`, `VTL2 Average Run Time`
@@ -55,7 +55,7 @@ func (c *Collector) buildDynamicMemoryBalancer() error {
// https://learn.microsoft.com/en-us/archive/blogs/chrisavis/monitoring-dynamic-memory-in-windows-server-hyper-v-2012 // https://learn.microsoft.com/en-us/archive/blogs/chrisavis/monitoring-dynamic-memory-in-windows-server-hyper-v-2012
c.perfDataCollectorDynamicMemoryBalancer, err = pdh.NewCollector[perfDataCounterValuesDynamicMemoryBalancer](c.logger, pdh.CounterTypeRaw, "Hyper-V Dynamic Memory Balancer", pdh.InstancesAll) c.perfDataCollectorDynamicMemoryBalancer, err = pdh.NewCollector[perfDataCounterValuesDynamicMemoryBalancer](c.logger, pdh.CounterTypeRaw, "Hyper-V Dynamic Memory Balancer", pdh.InstancesAll)
if err != nil { if err != nil {
return fmt.Errorf("failed to create Hyper-V Virtual Machine Health Summary collector: %w", err) return fmt.Errorf("failed to create Hyper-V Dynamic Memory Balancer collector: %w", err)
} }
c.vmDynamicMemoryBalancerAvailableMemory = prometheus.NewDesc( c.vmDynamicMemoryBalancerAvailableMemory = prometheus.NewDesc(
@@ -65,18 +65,20 @@ type perfDataCounterValuesHypervisorRootPartition struct {
HypervisorRootPartitionDeviceInterruptThrottleEvents float64 `perfdata:"Device Interrupt Throttle Events"` HypervisorRootPartitionDeviceInterruptThrottleEvents float64 `perfdata:"Device Interrupt Throttle Events"`
HypervisorRootPartitionGPAPages float64 `perfdata:"GPA Pages"` HypervisorRootPartitionGPAPages float64 `perfdata:"GPA Pages"`
HypervisorRootPartitionGPASpaceModifications float64 `perfdata:"GPA Space Modifications/sec"` HypervisorRootPartitionGPASpaceModifications float64 `perfdata:"GPA Space Modifications/sec"`
HypervisorRootPartitionIOTLBFlushCost float64 `perfdata:"I/O TLB Flush Cost"` // PERF_PRECISION_100NS_TIMER: the raw value is the cumulative flush time, which pdh
HypervisorRootPartitionIOTLBFlushes float64 `perfdata:"I/O TLB Flushes/sec"` // scales to seconds. The Windows help text calls it an average in nanoseconds.
HypervisorRootPartitionRecommendedVirtualTLBSize float64 `perfdata:"Recommended Virtual TLB Size"` HypervisorRootPartitionIOTLBFlushCost float64 `perfdata:"I/O TLB Flush Cost"`
HypervisorRootPartitionSkippedTimerTicks float64 `perfdata:"Skipped Timer Ticks"` HypervisorRootPartitionIOTLBFlushes float64 `perfdata:"I/O TLB Flushes/sec"`
HypervisorRootPartition1GDevicePages float64 `perfdata:"1G device pages"` HypervisorRootPartitionRecommendedVirtualTLBSize float64 `perfdata:"Recommended Virtual TLB Size"`
HypervisorRootPartition1GGPAPages float64 `perfdata:"1G GPA pages"` HypervisorRootPartitionSkippedTimerTicks float64 `perfdata:"Skipped Timer Ticks"`
HypervisorRootPartition2MDevicePages float64 `perfdata:"2M device pages"` HypervisorRootPartition1GDevicePages float64 `perfdata:"1G device pages"`
HypervisorRootPartition2MGPAPages float64 `perfdata:"2M GPA pages"` HypervisorRootPartition1GGPAPages float64 `perfdata:"1G GPA pages"`
HypervisorRootPartition4KDevicePages float64 `perfdata:"4K device pages"` HypervisorRootPartition2MDevicePages float64 `perfdata:"2M device pages"`
HypervisorRootPartition4KGPAPages float64 `perfdata:"4K GPA pages"` HypervisorRootPartition2MGPAPages float64 `perfdata:"2M GPA pages"`
HypervisorRootPartitionVirtualTLBFlushEntries float64 `perfdata:"Virtual TLB Flush Entires/sec"` HypervisorRootPartition4KDevicePages float64 `perfdata:"4K device pages"`
HypervisorRootPartitionVirtualTLBPages float64 `perfdata:"Virtual TLB Pages"` HypervisorRootPartition4KGPAPages float64 `perfdata:"4K GPA pages"`
HypervisorRootPartitionVirtualTLBFlushEntries float64 `perfdata:"Virtual TLB Flush Entires/sec"`
HypervisorRootPartitionVirtualTLBPages float64 `perfdata:"Virtual TLB Pages"`
} }
func (c *Collector) buildHypervisorRootPartition() error { func (c *Collector) buildHypervisorRootPartition() error {
@@ -130,32 +132,32 @@ func (c *Collector) buildHypervisorRootPartitionDescriptors() {
nil, nil,
) )
c.hypervisorRootPartitionDeviceInterruptThrottleEvents = prometheus.NewDesc( c.hypervisorRootPartitionDeviceInterruptThrottleEvents = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_device_interrupt_throttle_events"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_device_interrupt_throttle_events_total"),
"The number of times an interrupt from a device assigned to the partition was temporarily throttled because the device was generating too many interrupts", "The number of times an interrupt from a device assigned to the partition was temporarily throttled because the device was generating too many interrupts",
nil, nil,
nil, nil,
) )
c.hypervisorRootPartitionGPAPages = prometheus.NewDesc( c.hypervisorRootPartitionGPAPages = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_preferred_numa_node_index"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_gpa_pages"),
"The number of pages present in the GPA space of the partition (zero for root partition)", "The number of pages present in the GPA space of the partition (zero for root partition)",
nil, nil,
nil, nil,
) )
c.hypervisorRootPartitionGPASpaceModifications = prometheus.NewDesc( c.hypervisorRootPartitionGPASpaceModifications = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_gpa_space_modifications"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_gpa_space_modifications_total"),
"The rate of modifications to the GPA space of the partition", "The number of modifications to the GPA space of the partition",
nil, nil,
nil, nil,
) )
c.hypervisorRootPartitionIOTLBFlushCost = prometheus.NewDesc( c.hypervisorRootPartitionIOTLBFlushCost = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_io_tlb_flush_cost"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_io_tlb_flush_seconds_total"),
"The average time (in nanoseconds) spent processing an I/O TLB flush", "The time spent processing I/O TLB flushes. Divide its rate by the rate of windows_hyperv_root_partition_io_tlb_flushes_total for the average time per flush",
nil, nil,
nil, nil,
) )
c.hypervisorRootPartitionIOTLBFlushes = prometheus.NewDesc( c.hypervisorRootPartitionIOTLBFlushes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_io_tlb_flush"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_io_tlb_flushes_total"),
"The rate of flushes of I/O TLBs of the partition", "The number of flushes of I/O TLBs of the partition",
nil, nil,
nil, nil,
) )
@@ -166,7 +168,7 @@ func (c *Collector) buildHypervisorRootPartitionDescriptors() {
nil, nil,
) )
c.hypervisorRootPartitionSkippedTimerTicks = prometheus.NewDesc( c.hypervisorRootPartitionSkippedTimerTicks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_physical_pages_allocated"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_skipped_timer_ticks_total"),
"The number of timer interrupts skipped for the partition", "The number of timer interrupts skipped for the partition",
nil, nil,
nil, nil,
@@ -208,8 +210,8 @@ func (c *Collector) buildHypervisorRootPartitionDescriptors() {
nil, nil,
) )
c.hypervisorRootPartitionVirtualTLBFlushEntries = prometheus.NewDesc( c.hypervisorRootPartitionVirtualTLBFlushEntries = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "root_partition_virtual_tlb_flush_entries"), prometheus.BuildFQName(types.Namespace, Name, "root_partition_virtual_tlb_flush_entries_total"),
"The rate of flushes of the entire virtual TLB", "The number of flushes of the entire virtual TLB",
nil, nil,
nil, nil,
) )
@@ -265,7 +267,7 @@ func (c *Collector) collectHypervisorRootPartition(ch chan<- prometheus.Metric,
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.hypervisorRootPartitionDeviceInterruptThrottleEvents, c.hypervisorRootPartitionDeviceInterruptThrottleEvents,
prometheus.GaugeValue, prometheus.CounterValue,
c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceInterruptThrottleEvents, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceInterruptThrottleEvents,
) )
@@ -283,7 +285,7 @@ func (c *Collector) collectHypervisorRootPartition(ch chan<- prometheus.Metric,
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.hypervisorRootPartitionIOTLBFlushCost, c.hypervisorRootPartitionIOTLBFlushCost,
prometheus.GaugeValue, prometheus.CounterValue,
c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionIOTLBFlushCost, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionIOTLBFlushCost,
) )
@@ -301,7 +303,7 @@ func (c *Collector) collectHypervisorRootPartition(ch chan<- prometheus.Metric,
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.hypervisorRootPartitionSkippedTimerTicks, c.hypervisorRootPartitionSkippedTimerTicks,
prometheus.GaugeValue, prometheus.CounterValue,
c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionSkippedTimerTicks, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionSkippedTimerTicks,
) )
@@ -36,19 +36,24 @@ type collectorHypervisorRootVirtualProcessor struct {
// \Hyper-V Hypervisor Root Virtual Processor(*)\% Hypervisor Run Time // \Hyper-V Hypervisor Root Virtual Processor(*)\% Hypervisor Run Time
// \Hyper-V Hypervisor Root Virtual Processor(*)\% Remote Run Time // \Hyper-V Hypervisor Root Virtual Processor(*)\% Remote Run Time
// \Hyper-V Hypervisor Root Virtual Processor(*)\% Total Run Time // \Hyper-V Hypervisor Root Virtual Processor(*)\% Total Run Time
hypervisorRootVirtualProcessorTimeTotal *prometheus.Desc hypervisorRootVirtualProcessorTimeTotal *prometheus.Desc
hypervisorRootVirtualProcessorTotalRunTimeTotal *prometheus.Desc hypervisorRootVirtualProcessorTotalRunTimeTotal *prometheus.Desc
hypervisorRootVirtualProcessorCPUWaitTimePerDispatch *prometheus.Desc // \Hyper-V Hypervisor Root Virtual Processor(*)\CPU Wait Time Per Dispatch hypervisorRootVirtualProcessorCPUWaitSeconds *prometheus.Desc // \Hyper-V Hypervisor Root Virtual Processor(*)\CPU Wait Time Per Dispatch
hypervisorRootVirtualProcessorDispatches *prometheus.Desc // \Hyper-V Hypervisor Root Virtual Processor(*)\Logical Processor Dispatches/sec
} }
type perfDataCounterValuesHypervisorRootVirtualProcessor struct { type perfDataCounterValuesHypervisorRootVirtualProcessor struct {
Name string Name string
// The run time counters and CPU Wait Time Per Dispatch are PERF_PRECISION_100NS_TIMER.
// Their raw values are cumulative times, which pdh scales to seconds. Despite its name
// and help text, CPU Wait Time Per Dispatch is the total wait time, not an average.
HypervisorRootVirtualProcessorGuestRunTimePercent float64 `perfdata:"% Guest Run Time"` HypervisorRootVirtualProcessorGuestRunTimePercent float64 `perfdata:"% Guest Run Time"`
HypervisorRootVirtualProcessorHypervisorRunTimePercent float64 `perfdata:"% Hypervisor Run Time"` HypervisorRootVirtualProcessorHypervisorRunTimePercent float64 `perfdata:"% Hypervisor Run Time"`
HypervisorRootVirtualProcessorTotalRunTimePercent float64 `perfdata:"% Total Run Time"` HypervisorRootVirtualProcessorTotalRunTimePercent float64 `perfdata:"% Total Run Time"`
HypervisorRootVirtualProcessorRemoteRunTimePercent float64 `perfdata:"% Remote Run Time"` HypervisorRootVirtualProcessorRemoteRunTimePercent float64 `perfdata:"% Remote Run Time"`
HypervisorRootVirtualProcessorCPUWaitTimePerDispatch float64 `perfdata:"CPU Wait Time Per Dispatch"` HypervisorRootVirtualProcessorCPUWaitTimePerDispatch float64 `perfdata:"CPU Wait Time Per Dispatch"`
HypervisorRootVirtualProcessorDispatches float64 `perfdata:"Logical Processor Dispatches/sec"`
} }
func (c *Collector) buildHypervisorRootVirtualProcessor() error { func (c *Collector) buildHypervisorRootVirtualProcessor() error {
@@ -59,28 +64,40 @@ func (c *Collector) buildHypervisorRootVirtualProcessor() error {
return fmt.Errorf("failed to create Hyper-V Hypervisor Root Virtual Processor collector: %w", err) return fmt.Errorf("failed to create Hyper-V Hypervisor Root Virtual Processor collector: %w", err)
} }
c.buildHypervisorRootVirtualProcessorDescriptors()
return nil
}
func (c *Collector) buildHypervisorRootVirtualProcessorDescriptors() {
c.hypervisorRootVirtualProcessorTimeTotal = prometheus.NewDesc( c.hypervisorRootVirtualProcessorTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_time_total"),
"Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote)", "Time in seconds that processor spent in different modes (guest_run, hypervisor, remote)",
[]string{"core", "state"}, []string{"core", "state"},
nil, nil,
) )
c.hypervisorRootVirtualProcessorTotalRunTimeTotal = prometheus.NewDesc( c.hypervisorRootVirtualProcessorTotalRunTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_total_run_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_total_run_time_total"),
"Time that processor spent", "Time in seconds that processor spent running",
[]string{"core"}, []string{"core"},
nil, nil,
) )
c.hypervisorRootVirtualProcessorCPUWaitTimePerDispatch = prometheus.NewDesc( c.hypervisorRootVirtualProcessorCPUWaitSeconds = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_cpu_wait_time_per_dispatch_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_cpu_wait_seconds_total"),
"The average time (in nanoseconds) spent waiting for a virtual processor to be dispatched onto a logical processor.", "The time spent waiting for a virtual processor to be dispatched onto a logical processor. "+
"Divide its rate by the rate of windows_hyperv_hypervisor_root_virtual_processor_dispatches_total for the average wait per dispatch.",
[]string{"core"}, []string{"core"},
nil, nil,
) )
return nil c.hypervisorRootVirtualProcessorDispatches = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_root_virtual_processor_dispatches_total"),
"The number of times the virtual processor was dispatched onto a logical processor.",
[]string{"core"},
nil,
)
} }
func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error {
@@ -89,8 +106,12 @@ func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.M
return fmt.Errorf("failed to collect Hyper-V Hypervisor Root Virtual Processor metrics: %w", err) return fmt.Errorf("failed to collect Hyper-V Hypervisor Root Virtual Processor metrics: %w", err)
} }
return c.publishHypervisorRootVirtualProcessor(ch, scrape)
}
func (c *Collector) publishHypervisorRootVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error {
for _, data := range c.perfDataObjectHypervisorRootVirtualProcessor { for _, data := range c.perfDataObjectHypervisorRootVirtualProcessor {
// The name format is Hv LP <core id> // The name format is Root VP <core id>
parts := strings.Split(data.Name, " ") parts := strings.Split(data.Name, " ")
if len(parts) != 3 { if len(parts) != 3 {
return fmt.Errorf("unexpected Hyper-V Hypervisor Root Virtual Processor name format: %s", data.Name) return fmt.Errorf("unexpected Hyper-V Hypervisor Root Virtual Processor name format: %s", data.Name)
@@ -127,11 +148,18 @@ func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.M
) )
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.hypervisorRootVirtualProcessorCPUWaitTimePerDispatch, c.hypervisorRootVirtualProcessorCPUWaitSeconds,
prometheus.CounterValue, prometheus.CounterValue,
data.HypervisorRootVirtualProcessorCPUWaitTimePerDispatch, data.HypervisorRootVirtualProcessorCPUWaitTimePerDispatch,
coreID, coreID,
) )
ch <- scrape.MustNewConstMetric(
c.hypervisorRootVirtualProcessorDispatches,
prometheus.CounterValue,
data.HypervisorRootVirtualProcessorDispatches,
coreID,
)
} }
return nil return nil
@@ -39,17 +39,22 @@ type collectorHypervisorVirtualProcessor struct {
hypervisorVirtualProcessorModeTimeTotal *prometheus.Desc // New name for better clarity hypervisorVirtualProcessorModeTimeTotal *prometheus.Desc // New name for better clarity
hypervisorVirtualProcessorTotalRunTimeTotal *prometheus.Desc // \Hyper-V Hypervisor Virtual Processor(*)\% Total Run Time hypervisorVirtualProcessorTotalRunTimeTotal *prometheus.Desc // \Hyper-V Hypervisor Virtual Processor(*)\% Total Run Time
hypervisorVirtualProcessorRunTimeTotal *prometheus.Desc // New name for better clarity hypervisorVirtualProcessorRunTimeTotal *prometheus.Desc // New name for better clarity
hypervisorVirtualProcessorContextSwitches *prometheus.Desc // \Hyper-V Hypervisor Virtual Processor(*)\CPU Wait Time Per Dispatch hypervisorVirtualProcessorCPUWaitSeconds *prometheus.Desc // \Hyper-V Hypervisor Virtual Processor(*)\CPU Wait Time Per Dispatch
hypervisorVirtualProcessorDispatches *prometheus.Desc // \Hyper-V Hypervisor Virtual Processor(*)\Logical Processor Dispatches/sec
} }
type perfDataCounterValuesHypervisorVirtualProcessor struct { type perfDataCounterValuesHypervisorVirtualProcessor struct {
Name string Name string
// The run time counters and CPU Wait Time Per Dispatch are PERF_PRECISION_100NS_TIMER.
// Their raw values are cumulative times, which pdh scales to seconds. Despite its name
// and help text, CPU Wait Time Per Dispatch is the total wait time, not an average.
HypervisorVirtualProcessorGuestRunTimePercent float64 `perfdata:"% Guest Run Time"` HypervisorVirtualProcessorGuestRunTimePercent float64 `perfdata:"% Guest Run Time"`
HypervisorVirtualProcessorHypervisorRunTimePercent float64 `perfdata:"% Hypervisor Run Time"` HypervisorVirtualProcessorHypervisorRunTimePercent float64 `perfdata:"% Hypervisor Run Time"`
HypervisorVirtualProcessorTotalRunTimePercent float64 `perfdata:"% Total Run Time"` HypervisorVirtualProcessorTotalRunTimePercent float64 `perfdata:"% Total Run Time"`
HypervisorVirtualProcessorRemoteRunTimePercent float64 `perfdata:"% Remote Run Time"` HypervisorVirtualProcessorRemoteRunTimePercent float64 `perfdata:"% Remote Run Time"`
HypervisorVirtualProcessorCPUWaitTimePerDispatch float64 `perfdata:"CPU Wait Time Per Dispatch"` HypervisorVirtualProcessorCPUWaitTimePerDispatch float64 `perfdata:"CPU Wait Time Per Dispatch"`
HypervisorVirtualProcessorDispatches float64 `perfdata:"Logical Processor Dispatches/sec"`
} }
func (c *Collector) buildHypervisorVirtualProcessor() error { func (c *Collector) buildHypervisorVirtualProcessor() error {
@@ -60,42 +65,53 @@ func (c *Collector) buildHypervisorVirtualProcessor() error {
return fmt.Errorf("failed to create Hyper-V Hypervisor Virtual Processor collector: %w", err) return fmt.Errorf("failed to create Hyper-V Hypervisor Virtual Processor collector: %w", err)
} }
c.buildHypervisorVirtualProcessorDescriptors()
return nil
}
func (c *Collector) buildHypervisorVirtualProcessorDescriptors() {
c.hypervisorVirtualProcessorTimeTotal = prometheus.NewDesc( c.hypervisorVirtualProcessorTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_time_total"),
"DEPRECATED: use hypervisor_virtual_processor_mode_time_total. Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote)", "DEPRECATED: use hypervisor_virtual_processor_mode_time_total. Time in seconds that processor spent in different modes (hypervisor, guest, remote)",
[]string{"vm", "core", "state"}, []string{"vm", "core", "state"},
nil, nil,
) )
// New metric with better name for clarity, old one is kept for backward compatibility // New metric with better name for clarity, old one is kept for backward compatibility
c.hypervisorVirtualProcessorModeTimeTotal = prometheus.NewDesc( c.hypervisorVirtualProcessorModeTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_mode_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_mode_time_total"),
"Time that processor spent in different modes (hypervisor, guest_run, guest_idle, remote)", "Time in seconds that processor spent in different modes (hypervisor, guest, remote)",
[]string{"vm", "core", "state"}, []string{"vm", "core", "state"},
nil, nil,
) )
// end same metric // end same metric
c.hypervisorVirtualProcessorTotalRunTimeTotal = prometheus.NewDesc( c.hypervisorVirtualProcessorTotalRunTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_total_run_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_total_run_time_total"),
"DEPRECATED: use hypervisor_virtual_processor_run_time_total. Time that processor spent", "DEPRECATED: use hypervisor_virtual_processor_run_time_total. Time in seconds that processor spent running",
[]string{"vm", "core"}, []string{"vm", "core"},
nil, nil,
) )
// New metric with better name for clarity, old one is kept for backward compatibility // New metric with better name for clarity, old one is kept for backward compatibility
c.hypervisorVirtualProcessorRunTimeTotal = prometheus.NewDesc( c.hypervisorVirtualProcessorRunTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_run_time_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_run_time_total"),
"Time that processor spent", "Time in seconds that processor spent running",
[]string{"vm", "core"}, []string{"vm", "core"},
nil, nil,
) )
// end same metric // end same metric
c.hypervisorVirtualProcessorContextSwitches = prometheus.NewDesc( c.hypervisorVirtualProcessorCPUWaitSeconds = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_cpu_wait_time_per_dispatch_total"), prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_cpu_wait_seconds_total"),
"The average time (in nanoseconds) spent waiting for a virtual processor to be dispatched onto a logical processor.", "The time spent waiting for a virtual processor to be dispatched onto a logical processor. "+
"Divide its rate by the rate of windows_hyperv_hypervisor_virtual_processor_dispatches_total for the average wait per dispatch.",
[]string{"vm", "core"},
nil,
)
c.hypervisorVirtualProcessorDispatches = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "hypervisor_virtual_processor_dispatches_total"),
"The number of times the virtual processor was dispatched onto a logical processor.",
[]string{"vm", "core"}, []string{"vm", "core"},
nil, nil,
) )
return nil
} }
func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error {
@@ -104,6 +120,10 @@ func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metri
return fmt.Errorf("failed to collect Hyper-V Hypervisor Virtual Processor metrics: %w", err) return fmt.Errorf("failed to collect Hyper-V Hypervisor Virtual Processor metrics: %w", err)
} }
return c.publishHypervisorVirtualProcessor(ch, scrape)
}
func (c *Collector) publishHypervisorVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error {
for _, data := range c.perfDataObjectHypervisorVirtualProcessor { for _, data := range c.perfDataObjectHypervisorVirtualProcessor {
// The name format is <VM Name>:Hv VP <vcore id> // The name format is <VM Name>:Hv VP <vcore id>
parts := strings.Split(data.Name, ":") parts := strings.Split(data.Name, ":")
@@ -176,11 +196,18 @@ func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metri
) )
// end same metric // end same metric
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.hypervisorVirtualProcessorContextSwitches, c.hypervisorVirtualProcessorCPUWaitSeconds,
prometheus.CounterValue, prometheus.CounterValue,
data.HypervisorVirtualProcessorCPUWaitTimePerDispatch, data.HypervisorVirtualProcessorCPUWaitTimePerDispatch,
vmName, coreID, vmName, coreID,
) )
ch <- scrape.MustNewConstMetric(
c.hypervisorVirtualProcessorDispatches,
prometheus.CounterValue,
data.HypervisorVirtualProcessorDispatches,
vmName, coreID,
)
} }
return nil return nil
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build windows
package hyperv
import (
"testing"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/require"
)
// publishCollector adapts a publish function to prometheus.Collector, so the test
// checks the metrics as a registry gathers them.
type publishCollector func(ch chan<- prometheus.Metric) error
func (publishCollector) Describe(chan<- *prometheus.Desc) {}
func (p publishCollector) Collect(ch chan<- prometheus.Metric) {
if err := p(ch); err != nil {
panic(err)
}
}
type gatheredSample struct {
metricType dto.MetricType
value float64
}
func gatherSamples(t *testing.T, publish publishCollector) map[string]gatheredSample {
t.Helper()
registry := prometheus.NewPedanticRegistry()
require.NoError(t, registry.Register(publish))
families, err := registry.Gather()
require.NoError(t, err)
samples := make(map[string]gatheredSample, len(families))
for _, family := range families {
metric := family.GetMetric()[0]
sample := gatheredSample{metricType: family.GetType()}
switch family.GetType() {
case dto.MetricType_COUNTER:
sample.value = metric.GetCounter().GetValue()
case dto.MetricType_GAUGE:
sample.value = metric.GetGauge().GetValue()
default:
t.Fatalf("unexpected metric type %s for %s", family.GetType(), family.GetName())
}
samples[family.GetName()] = sample
}
return samples
}
func requireSample(t *testing.T, samples map[string]gatheredSample, name string, metricType dto.MetricType, value float64) {
t.Helper()
sample, ok := samples[name]
require.Truef(t, ok, "metric %s not published", name)
require.Equalf(t, metricType, sample.metricType, "type of %s", name)
require.InDeltaf(t, value, sample.value, 1e-9, "value of %s", name)
}
type rootPartitionFixture struct{}
func (rootPartitionFixture) Collect(dst *[]perfDataCounterValuesHypervisorRootPartition) error {
*dst = []perfDataCounterValuesHypervisorRootPartition{{
HypervisorRootPartitionGPAPages: 11,
HypervisorRootPartitionSkippedTimerTicks: 22,
HypervisorRootPartitionDeviceInterruptThrottleEvents: 33,
HypervisorRootPartitionIOTLBFlushCost: 0.5,
HypervisorRootPartitionIOTLBFlushes: 44,
HypervisorRootPartitionGPASpaceModifications: 55,
HypervisorRootPartitionVirtualTLBFlushEntries: 66,
}}
return nil
}
func (rootPartitionFixture) Close() {}
func TestRootPartitionMetricNamesAndTypes(t *testing.T) {
t.Parallel()
c := New(nil)
c.buildHypervisorRootPartitionDescriptors()
c.perfDataCollectorHypervisorRootPartition = rootPartitionFixture{}
samples := gatherSamples(t, func(ch chan<- prometheus.Metric) error {
return c.collectHypervisorRootPartition(ch, nil)
})
requireSample(t, samples, "windows_hyperv_root_partition_gpa_pages", dto.MetricType_GAUGE, 11)
requireSample(t, samples, "windows_hyperv_root_partition_skipped_timer_ticks_total", dto.MetricType_COUNTER, 22)
requireSample(t, samples, "windows_hyperv_root_partition_device_interrupt_throttle_events_total", dto.MetricType_COUNTER, 33)
requireSample(t, samples, "windows_hyperv_root_partition_io_tlb_flush_seconds_total", dto.MetricType_COUNTER, 0.5)
requireSample(t, samples, "windows_hyperv_root_partition_io_tlb_flushes_total", dto.MetricType_COUNTER, 44)
requireSample(t, samples, "windows_hyperv_root_partition_gpa_space_modifications_total", dto.MetricType_COUNTER, 55)
requireSample(t, samples, "windows_hyperv_root_partition_virtual_tlb_flush_entries_total", dto.MetricType_COUNTER, 66)
for _, removed := range []string{
"windows_hyperv_root_partition_preferred_numa_node_index",
"windows_hyperv_root_partition_physical_pages_allocated",
"windows_hyperv_root_partition_io_tlb_flush_cost",
} {
require.NotContains(t, samples, removed)
}
}
func TestVirtualProcessorCPUWaitMetrics(t *testing.T) {
t.Parallel()
c := New(nil)
c.buildHypervisorVirtualProcessorDescriptors()
c.buildHypervisorRootVirtualProcessorDescriptors()
// pdh has already scaled the 100ns timers to seconds.
c.perfDataObjectHypervisorVirtualProcessor = []perfDataCounterValuesHypervisorVirtualProcessor{{
Name: "vm1:Hv VP 0",
HypervisorVirtualProcessorCPUWaitTimePerDispatch: 39.13,
HypervisorVirtualProcessorDispatches: 1086776,
}}
c.perfDataObjectHypervisorRootVirtualProcessor = []perfDataCounterValuesHypervisorRootVirtualProcessor{{
Name: "Root VP 0",
HypervisorRootVirtualProcessorCPUWaitTimePerDispatch: 9.98,
HypervisorRootVirtualProcessorDispatches: 1082841,
}}
samples := gatherSamples(t, func(ch chan<- prometheus.Metric) error {
if err := c.publishHypervisorVirtualProcessor(ch, nil); err != nil {
return err
}
return c.publishHypervisorRootVirtualProcessor(ch, nil)
})
requireSample(t, samples, "windows_hyperv_hypervisor_virtual_processor_cpu_wait_seconds_total", dto.MetricType_COUNTER, 39.13)
requireSample(t, samples, "windows_hyperv_hypervisor_virtual_processor_dispatches_total", dto.MetricType_COUNTER, 1086776)
requireSample(t, samples, "windows_hyperv_hypervisor_root_virtual_processor_cpu_wait_seconds_total", dto.MetricType_COUNTER, 9.98)
requireSample(t, samples, "windows_hyperv_hypervisor_root_virtual_processor_dispatches_total", dto.MetricType_COUNTER, 1082841)
require.NotContains(t, samples, "windows_hyperv_hypervisor_virtual_processor_cpu_wait_time_per_dispatch_total")
require.NotContains(t, samples, "windows_hyperv_hypervisor_root_virtual_cpu_wait_time_per_dispatch_total")
}
func TestVirtualStorageDeviceCounterTypes(t *testing.T) {
t.Parallel()
c := New(nil)
c.buildVirtualStorageDeviceDescriptors()
c.perfDataObjectVirtualStorageDevice = []perfDataCounterValuesVirtualStorageDevice{{
Name: "ubuntu.vhdx",
VirtualStorageDeviceThroughput: 22336,
VirtualStorageDeviceNormalizedThroughput: 36413,
VirtualStorageDeviceIOQuotaReplenishmentRate: 7,
}}
samples := gatherSamples(t, func(ch chan<- prometheus.Metric) error {
c.publishVirtualStorageDevice(ch, nil)
return nil
})
requireSample(t, samples, "windows_hyperv_virtual_storage_device_throughput_total", dto.MetricType_COUNTER, 22336)
requireSample(t, samples, "windows_hyperv_virtual_storage_device_normalized_throughput_total", dto.MetricType_COUNTER, 36413)
requireSample(t, samples, "windows_hyperv_virtual_storage_device_io_quota_replenishment_total", dto.MetricType_COUNTER, 7)
require.NotContains(t, samples, "windows_hyperv_virtual_storage_device_normalized_throughput")
require.NotContains(t, samples, "windows_hyperv_io_quota_replenishment_rate")
}
@@ -72,6 +72,12 @@ func (c *Collector) buildVirtualStorageDevice() error {
return fmt.Errorf("failed to create Hyper-V Virtual Storage Device collector: %w", err) return fmt.Errorf("failed to create Hyper-V Virtual Storage Device collector: %w", err)
} }
c.buildVirtualStorageDeviceDescriptors()
return nil
}
func (c *Collector) buildVirtualStorageDeviceDescriptors() {
c.virtualStorageDeviceErrorCount = prometheus.NewDesc( c.virtualStorageDeviceErrorCount = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_error_count_total"), prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_error_count_total"),
"Represents the total number of errors that have occurred on this virtual device.", "Represents the total number of errors that have occurred on this virtual device.",
@@ -118,13 +124,13 @@ func (c *Collector) buildVirtualStorageDevice() error {
) )
c.virtualStorageDeviceThroughput = prometheus.NewDesc( c.virtualStorageDeviceThroughput = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_throughput_total"), prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_throughput_total"),
"Represents the total number of 8KB IO transfers completed by this virtual device.", "Represents the total number of IO transfers completed by this virtual device.",
[]string{"device"}, []string{"device"},
nil, nil,
) )
c.virtualStorageDeviceNormalizedThroughput = prometheus.NewDesc( c.virtualStorageDeviceNormalizedThroughput = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_normalized_throughput"), prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_normalized_throughput_total"),
"Represents the average number of IO transfers completed by this virtual device.", "Represents the total number of IO transfers completed by this virtual device, normalized to 8KB transfers.",
[]string{"device"}, []string{"device"},
nil, nil,
) )
@@ -157,13 +163,11 @@ func (c *Collector) buildVirtualStorageDevice() error {
nil, nil,
) )
c.virtualStorageDeviceIOQuotaReplenishmentRate = prometheus.NewDesc( c.virtualStorageDeviceIOQuotaReplenishmentRate = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "io_quota_replenishment_rate"), prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_io_quota_replenishment_total"),
"Represents the IO quota replenishment rate for this virtual device.", "Represents the IO quota replenishment counter for this virtual device. Use rate() for the replenishment rate.",
[]string{"device"}, []string{"device"},
nil, nil,
) )
return nil
} }
func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error {
@@ -172,6 +176,12 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scr
return fmt.Errorf("failed to collect Hyper-V Virtual Storage Device metrics: %w", err) return fmt.Errorf("failed to collect Hyper-V Virtual Storage Device metrics: %w", err)
} }
c.publishVirtualStorageDevice(ch, scrape)
return nil
}
func (c *Collector) publishVirtualStorageDevice(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) {
for _, data := range c.perfDataObjectVirtualStorageDevice { for _, data := range c.perfDataObjectVirtualStorageDevice {
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.virtualStorageDeviceErrorCount, c.virtualStorageDeviceErrorCount,
@@ -231,7 +241,7 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scr
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.virtualStorageDeviceNormalizedThroughput, c.virtualStorageDeviceNormalizedThroughput,
prometheus.GaugeValue, prometheus.CounterValue,
data.VirtualStorageDeviceNormalizedThroughput, data.VirtualStorageDeviceNormalizedThroughput,
data.Name, data.Name,
) )
@@ -252,7 +262,7 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scr
ch <- scrape.MustNewConstMetric( ch <- scrape.MustNewConstMetric(
c.virtualStorageDeviceIOQuotaReplenishmentRate, c.virtualStorageDeviceIOQuotaReplenishmentRate,
prometheus.GaugeValue, prometheus.CounterValue,
data.VirtualStorageDeviceIOQuotaReplenishmentRate, data.VirtualStorageDeviceIOQuotaReplenishmentRate,
data.Name, data.Name,
) )
@@ -273,6 +283,4 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scr
data.Name, data.Name,
) )
} }
return nil
} }