feat(inputs.intel_powerstat): Extract business logic to external library (#14363)

This commit is contained in:
Gabriele Galiero Casay 2023-12-07 17:56:17 +01:00 committed by GitHub
parent 57fbc73814
commit 5d598321bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 8289 additions and 3370 deletions

View File

@ -201,6 +201,7 @@ following works:
- github.com/influxdata/toml [MIT License](https://github.com/influxdata/toml/blob/master/LICENSE)
- github.com/influxdata/wlog [MIT License](https://github.com/influxdata/wlog/blob/master/LICENSE)
- github.com/intel/iaevents [Apache License 2.0](https://github.com/intel/iaevents/blob/main/LICENSE)
- github.com/intel/powertelemetry [Apache License 2.0](https://github.com/intel/powertelemetry/blob/main/LICENSE)
- github.com/jackc/chunkreader [MIT License](https://github.com/jackc/chunkreader/blob/master/LICENSE)
- github.com/jackc/pgconn [MIT License](https://github.com/jackc/pgconn/blob/master/LICENSE)
- github.com/jackc/pgio [MIT License](https://github.com/jackc/pgio/blob/master/LICENSE)
@ -220,6 +221,7 @@ following works:
- github.com/jeremywohl/flatten [MIT License](https://github.com/jeremywohl/flatten/blob/master/LICENSE)
- github.com/jhump/protoreflect [Apache License 2.0](https://github.com/jhump/protoreflect/blob/master/LICENSE)
- github.com/jmespath/go-jmespath [Apache License 2.0](https://github.com/jmespath/go-jmespath/blob/master/LICENSE)
- github.com/jmhodges/clock [MIT Licence](https://github.com/jmhodges/clock/blob/main/LICENSE)
- github.com/josharian/intern [MIT License](https://github.com/josharian/intern/blob/master/LICENSE.md)
- github.com/josharian/native [MIT License](https://github.com/josharian/native/blob/main/license)
- github.com/jpillora/backoff [MIT License](https://github.com/jpillora/backoff/blob/master/LICENSE)

6
go.mod
View File

@ -112,6 +112,7 @@ require (
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65
github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8
github.com/intel/iaevents v1.1.0
github.com/intel/powertelemetry v1.0.0
github.com/jackc/pgconn v1.14.1
github.com/jackc/pgio v1.0.0
github.com/jackc/pgtype v1.14.0
@ -363,6 +364,7 @@ require (
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jmhodges/clock v1.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
@ -374,7 +376,7 @@ require (
github.com/kr/fs v0.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165 // indirect
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@ -418,7 +420,7 @@ require (
github.com/pkg/sftp v1.13.5 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff // indirect

12
go.sum
View File

@ -1535,6 +1535,8 @@ github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8 h1:W2IgzRCb0L9VzMu
github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8/go.mod h1:/2NMgWB1DHM1ti/gqhOlg+LJeBVk6FqR5aVGYY0hlwI=
github.com/intel/iaevents v1.1.0 h1:FzxMBfXk/apG2EUXUCfaq3gUQ+q+TgZ1HNMjjUILUGE=
github.com/intel/iaevents v1.1.0/go.mod h1:CyUUzXw0lHRCsmyyF7Pwco9Y7NiTNQUUlcJ7RJAazKs=
github.com/intel/powertelemetry v1.0.0 h1:9MP7OjNSqPPok1GCMRcVvToAcIJ4HvuNgt9rq7shnfk=
github.com/intel/powertelemetry v1.0.0/go.mod h1:0/EKcFml0Imic4Mva8QzsZhT/L0nc3Y+MbT9IU0y1FA=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@ -1610,6 +1612,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=
github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@ -1721,8 +1725,8 @@ github.com/loov/hrtime v1.0.3/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd
github.com/loov/hrtime/hrplot v1.0.2/go.mod h1:9t65xYn4d42ntjv40Wt5lbU72/VC5S0zGDgjC8kD5BU=
github.com/loov/plot v0.0.0-20200413101321-e09a6f01d2f5/go.mod h1:gSrhfSMoiPGG0CZ9E66kXjaHxFw0fzJhooyicOnz5z4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE=
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lxc/lxd v0.0.0-20220920163450-e9b4b514106a h1:VCh69Giyzh/1qPZHC62ysQvFGI93vEQkFNo7iApvlzM=
github.com/lxc/lxd v0.0.0-20220920163450-e9b4b514106a/go.mod h1:Y+Ny8KSylQRtfyOxVN0Cha/jAfd2l1AlHiDulGP+GQk=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
@ -2003,8 +2007,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus-community/pro-bing v0.3.0 h1:SFT6gHqXwbItEDJhTkzPWVqU6CLEtqEfNAPp47RUON4=
github.com/prometheus-community/pro-bing v0.3.0/go.mod h1:p9dLb9zdmv+eLxWfCT6jESWuDrS+YzpPkQBgysQF8a0=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=

View File

@ -27,15 +27,15 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
# Intel PowerStat plugin enables monitoring of platform metrics (power, TDP)
# and per-CPU metrics like temperature, power and utilization. Please see the
# plugin readme for details on software and hardware compatability.
# This plugin ONLY supports Linux
# This plugin ONLY supports Linux.
[[inputs.intel_powerstat]]
## The user can choose which package metrics are monitored by the plugin with
## the package_metrics setting:
## - The default, will collect "current_power_consumption",
## "current_dram_power_consumption" and "thermal_design_power"
## - Leaving this setting empty means no package metrics will be collected
## "current_dram_power_consumption" and "thermal_design_power".
## - Leaving this setting empty means no package metrics will be collected.
## - Finally, a user can specify individual metrics to capture from the
## supported options list
## supported options list.
## Supported options:
## "current_power_consumption", "current_dram_power_consumption",
## "thermal_design_power", "max_turbo_frequency", "uncore_frequency",
@ -48,13 +48,49 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## by the plugin.
## Supported options:
## "cpu_frequency", "cpu_c0_state_residency", "cpu_c1_state_residency",
## "cpu_c6_state_residency", "cpu_busy_cycles", "cpu_temperature",
## "cpu_busy_frequency"
## ATTENTION: cpu_busy_cycles is DEPRECATED - use cpu_c0_state_residency
## "cpu_c3_state_residency", "cpu_c6_state_residency", "cpu_c7_state_residency",
## "cpu_temperature", "cpu_busy_frequency", "cpu_c0_substate_c01",
## "cpu_c0_substate_c02", "cpu_c0_substate_c0_wait"
# cpu_metrics = []
## Optionally the user can choose for which CPUs metrics configured in cpu_metrics array should be gathered.
## Can't be combined with excluded_cpus.
## Empty or missing array means CPU metrics are gathered for all CPUs.
## e.g. ["0-3", "4,5,6"] or ["1-3,4"]
# included_cpus = []
## Optionally the user can choose which CPUs should be excluded from gathering metrics configured in cpu_metrics array.
## Can't be combined with included_cpus.
## Empty or missing array means CPU metrics are gathered for all CPUs.
## e.g. ["0-3", "4,5,6"] or ["1-3,4"]
# excluded_cpus = []
## Filesystem location of JSON file that contains PMU event definitions.
## Mandatory only for perf-related metrics (cpu_c0_substate_c01, cpu_c0_substate_c02, cpu_c0_substate_c0_wait).
# event_definitions = ""
## The user can set the timeout duration for MSR reading.
## Enabling this timeout can be useful in situations where, on heavily loaded systems,
## the code waits too long for a kernel response to MSR read requests.
## 0 disables the timeout (default).
# msr_read_timeout = "0ms"
```
## Example: Configuration with no per-CPU telemetry
### Configuration notes
1. The configuration of `included_cpus` or `excluded_cpus` may affect the ability to collect `package_metrics`.
Some of them (`max_turbo_frequency`, `cpu_base_frequency`, and `uncore_frequency`) need to read data
from exactly one processor for each package. If `included_cpus` or `excluded_cpus` exclude all processors
from the package, reading the mentioned metrics for that package will not be possible.
2. `event_definitions` JSON file for specific architecture can be found at [perfmon](https://github.com/intel/perfmon).
A script to download the event definition that is appropriate for current environment (`event_download.py`) is
available at [pmu-tools](https://github.com/andikleen/pmu-tools).
For perf-related metrics supported by this plugin, an event definition JSON file
with events for the `core` is required.
For example: `sapphirerapids_core.json` or `GenuineIntel-6-8F-core.json`.
### Example: Configuration with no per-CPU telemetry
This configuration allows getting default processor package specific metrics,
no per-CPU metrics are collected:
@ -64,7 +100,7 @@ no per-CPU metrics are collected:
cpu_metrics = []
```
## Example: Configuration with no per-CPU telemetry - equivalent case
### Example: Configuration with no per-CPU telemetry - equivalent case
This configuration allows getting default processor package specific metrics,
no per-CPU metrics are collected:
@ -73,268 +109,276 @@ no per-CPU metrics are collected:
[[inputs.intel_powerstat]]
```
## Example: Configuration for CPU Temperature and CPU Frequency
### Example: Configuration for CPU Temperature and CPU Frequency
This configuration allows getting default processor package specific metrics,
plus subset of per-CPU metrics (CPU Temperature and CPU Frequency):
plus subset of per-CPU metrics (CPU Temperature and CPU Frequency) which will be
gathered only for `cpu_id = 0`:
```toml
[[inputs.intel_powerstat]]
cpu_metrics = ["cpu_frequency", "cpu_temperature"]
included_cpus = ["0"]
```
## Example: Configuration for CPU Temperature and CPU Frequency without default package metrics
### Example: Configuration for CPU Temperature and CPU Frequency without default package metrics
This configuration allows getting only a subset of per-CPU metrics (CPU
Temperature and CPU Frequency):
This configuration allows getting only a subset of per-CPU metrics
(CPU Temperature and CPU Frequency) which will be gathered for
all `cpus` except `cpu_id = ["1-3"]`:
```toml
[[inputs.intel_powerstat]]
package_metrics = []
cpu_metrics = ["cpu_frequency", "cpu_temperature"]
excluded_cpus = ["1-3"]
```
## Example: Configuration with all available metrics
### Example: Configuration with all available metrics
This configuration allows getting all processor package specific metrics and
all per-CPU metrics:
```toml
[[inputs.intel_powerstat]]
package_metrics = ["current_power_consumption", "current_dram_power_consumption", "thermal_design_power", "max_turbo_frequency", "uncore_frequency"]
cpu_metrics = ["cpu_frequency", "cpu_busy_frequency", "cpu_temperature", "cpu_c0_state_residency", "cpu_c1_state_residency", "cpu_c6_state_residency"]
package_metrics = ["current_power_consumption", "current_dram_power_consumption", "thermal_design_power", "max_turbo_frequency", "uncore_frequency", "cpu_base_frequency"]
cpu_metrics = ["cpu_frequency", "cpu_c0_state_residency", "cpu_c1_state_residency", "cpu_c3_state_residency", "cpu_c6_state_residency", "cpu_c7_state_residency", "cpu_temperature", "cpu_busy_frequency", "cpu_c0_substate_c01", "cpu_c0_substate_c02", "cpu_c0_substate_c0_wait"]
event_definitions = "/home/telegraf/.cache/pmu-events/GenuineIntel-6-8F-core.json"
```
## SW Dependencies
Plugin is based on Linux Kernel modules that expose specific metrics over
### Kernel modules
Plugin is mostly based on Linux Kernel modules that expose specific metrics over
`sysfs` or `devfs` interfaces. The following dependencies are expected by
plugin:
- _intel-rapl_ module which exposes Intel Runtime Power Limiting metrics over
- `intel-rapl` kernel module which exposes Intel Runtime Power Limiting metrics over
`sysfs` (`/sys/devices/virtual/powercap/intel-rapl`),
- _msr_ kernel module that provides access to processor model specific
- `msr` kernel module that provides access to processor model specific
registers over `devfs` (`/dev/cpu/cpu%d/msr`),
- _cpufreq_ kernel module - which exposes per-CPU Frequency over `sysfs`
(`/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq`).
- _intel-uncore-frequency_ module exposes Intel uncore frequency metrics
over `sysfs` (`/sys/devices/system/cpu/intel_uncore_frequency`),
- `cpufreq` kernel module - which exposes per-CPU Frequency over `sysfs`
(`/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq`),
- `intel-uncore-frequency` kernel module exposes Intel uncore frequency metrics
over `sysfs` (`/sys/devices/system/cpu/intel_uncore_frequency`).
Minimum kernel version required is 3.13 to satisfy most of requirements,
for `uncore_frequency` metrics `intel-uncore-frequency` module is required
(available since kernel 5.6).
Please make sure that kernel modules are loaded and running (cpufreq is
integrated in kernel). Modules might have to be manually enabled by using
`modprobe`. Depending on the kernel version, run commands:
Make sure that required kernel modules are loaded and running.
Modules might have to be manually enabled by using `modprobe`.
Depending on the kernel version, run commands:
```sh
# kernel 5.x.x:
# rapl modules:
## kernel < 4.0
sudo modprobe intel_rapl
## kernel >= 4.0
sudo modprobe rapl
sudo modprobe msr
sudo modprobe intel_rapl_common
sudo modprobe intel_rapl_msr
# also for kernel >= 5.6.0
sudo modprobe intel-uncore-frequency
# kernel 4.x.x:
# msr module:
sudo modprobe msr
sudo modprobe intel_rapl
# cpufreq module:
### integrated in kernel
# intel-uncore-frequency module:
## only for kernel >= 5.6.0
sudo modprobe intel-uncore-frequency
```
**Telegraf with Intel PowerStat plugin enabled may require root access to read
model specific registers (MSRs)** to retrieve data for calculation of most
critical per-CPU specific metrics:
### Kernel's perf interface
- `cpu_busy_frequency_mhz`
- `cpu_temperature_celsius`
- `cpu_c0_state_residency_percent`
- `cpu_c1_state_residency_percent`
- `cpu_c6_state_residency_percent`
For perf-related metrics, when Telegraf is not running as root,
the following capability should be added to the Telegraf executable:
and to retrieve data for calculation per-package specific metric:
```sh
sudo setcap cap_sys_admin+ep <path_to_telegraf_binary>
```
- `max_turbo_frequency_mhz`
- `uncore_frequency_mhz_cur`
- `cpu_base_frequency_mhz`
Alternatively, `/proc/sys/kernel/perf_event_paranoid` has to be set to
value less than 1.
To expose other Intel PowerStat metrics root access may or may not be required
Depending on environment and configuration (number of monitored CPUs
and number of enabled metrics), it might be required to increase
the limit on the number of open file descriptors allowed.
This can be done for example by using `ulimit -n` command.
### Dependencies of metrics on system configuration
Details of these dependencies are discussed above:
| Configuration option | Type | Dependency |
|-------------------------------------------------------------------------------------|-------------------|------------------------------------------------|
| `current_power_consumption` | `package_metrics` | `rapl` kernel module(s) |
| `current_dram_power_consumption` | `package_metrics` | `rapl` kernel module(s) |
| `thermal_design_power` | `package_metrics` | `rapl` kernel module(s) |
| `max_turbo_frequency` | `package_metrics` | `msr` kernel module |
| `uncore_frequency` | `package_metrics` | `intel-uncore-frequency`/`msr` kernel modules* |
| `cpu_base_frequency` | `package_metrics` | `msr` kernel module |
| `cpu_frequency` | `cpu_metrics` | `cpufreq` kernel module |
| `cpu_c0_state_residency` | `cpu_metrics` | `msr` kernel module |
| `cpu_c1_state_residency` | `cpu_metrics` | `msr` kernel module |
| `cpu_c3_state_residency` | `cpu_metrics` | `msr` kernel module |
| `cpu_c6_state_residency` | `cpu_metrics` | `msr` kernel module |
| `cpu_c7_state_residency` | `cpu_metrics` | `msr` kernel module |
| `cpu_busy_cycles` (**DEPRECATED** - superseded by `cpu_c0_state_residency_percent`) | `cpu_metrics` | `msr` kernel module |
| `cpu_temperature` | `cpu_metrics` | `msr` kernel module |
| `cpu_busy_frequency` | `cpu_metrics` | `msr` kernel module |
| `cpu_c0_substate_c01` | `cpu_metrics` | kernel's `perf` interface |
| `cpu_c0_substate_c02` | `cpu_metrics` | kernel's `perf` interface |
| `cpu_c0_substate_c0_wait` | `cpu_metrics` | kernel's `perf` interface |
*for all metrics enabled by the configuration option `uncore_frequency`,
starting from kernel version 5.18, only the `intel-uncore-frequency` module
is required. For older kernel versions, the metric `uncore_frequency_mhz_cur`
requires the `msr` module to be enabled.
### Root privileges
**Telegraf with Intel PowerStat plugin enabled may require
root privileges to read all the metrics**
(depending on OS type or configuration).
Alternatively, the following capabilities can be added to
the Telegraf executable:
```sh
#without perf-related metrics:
sudo setcap cap_sys_rawio,cap_dac_read_search+ep <path_to_telegraf_binary>
#with perf-related metrics:
sudo setcap cap_sys_rawio,cap_dac_read_search,cap_sys_admin+ep <path_to_telegraf_binary>
```
## HW Dependencies
Specific metrics require certain processor features to be present, otherwise
Intel PowerStat plugin won't be able to read them. When using Linux Kernel based
OS, user can detect supported processor features reading `/proc/cpuinfo` file.
Intel PowerStat plugin won't be able to read them. The user can detect supported
processor features by reading `/proc/cpuinfo` file.
Plugin assumes crucial properties are the same for all CPU cores in the system.
The following processor properties are examined in more detail in this section:
processor _cpu family_, _model_ and _flags_. The following processor properties
are required by the plugin:
- Processor _cpu family_ must be Intel (0x6) - since data used by the plugin
assumes Intel specific model specific registers for all features
The following `processor` properties are examined in more detail
in this section:
- `vendor_id`
- `cpu family`
- `model`
- `flags`
The following processor properties are required by the plugin:
- Processor `vendor_id` must be `GenuineIntel` and `cpu family` must be `6` -
since data used by the plugin are Intel-specific.
- The following processor flags shall be present:
- "_msr_" shall be present for plugin to read platform data from processor
- `msr` shall be present for plugin to read platform data from processor
model specific registers and collect the following metrics:
_powerstat\_core.cpu\_temperature_, _powerstat\_core.cpu\_busy\_frequency_,
_powerstat\_core.cpu\_c0\_state\_residency_,
_powerstat\_core.cpu\_c1\_state\_residency_,
_powerstat\_core.cpu\_c6\_state\_residency_
- "_aperfmperf_" shall be present to collect the following metrics:
_powerstat\_core.cpu\_busy\_frequency_,
_powerstat\_core.cpu\_c0\_state\_residency_,
_powerstat\_core.cpu\_c1\_state\_residency_
- "_dts_" shall be present to collect _powerstat\_core.cpu\_temperature_
- Processor _Model number_ must be one of the following values for plugin to
read _powerstat\_core.cpu\_c1\_state\_residency_ /
_powerstat\_core.cpu\_c6\_state\_residency_ and
_powerstat\_package.cpu\_base\_frequency_ metrics:
| Model number | Processor name |
|--------------|---------------------------------|
| 0x37 | Intel Atom® Bay Trail |
| 0x4D | Intel Atom® Avaton |
| 0x5C | Intel Atom® Apollo Lake |
| 0x5F | Intel Atom® Denverton |
| 0x7A | Intel Atom® Goldmont |
| 0x4C | Intel Atom® Airmont |
| 0x86 | Intel Atom® Jacobsville |
| 0x96 | Intel Atom® Elkhart Lake |
| 0x9C | Intel Atom® Jasper Lake |
| 0x1A | Intel Nehalem-EP |
| 0x1E | Intel Nehalem |
| 0x1F | Intel Nehalem-G |
| 0x2E | Intel Nehalem-EX |
| 0x25 | Intel Westmere |
| 0x2C | Intel Westmere-EP |
| 0x2F | Intel Westmere-EX |
| 0x2A | Intel Sandybridge |
| 0x2D | Intel Sandybridge-X |
| 0x3A | Intel Ivybridge |
| 0x3E | Intel Ivybridge-X |
| 0x4E | Intel Atom® Silvermont-MID |
| 0x5E | Intel Skylake |
| 0x55 | Intel Skylake-X |
| 0x8E | Intel KabyLake-L |
| 0x9E | Intel KabyLake |
| 0x6A | Intel IceLake-X |
| 0x6C | Intel IceLake-D |
| 0x7D | Intel IceLake |
| 0x7E | Intel IceLake-L |
| 0x9D | Intel IceLake-NNPI |
| 0x3C | Intel Haswell |
| 0x3F | Intel Haswell-X |
| 0x45 | Intel Haswell-L |
| 0x46 | Intel Haswell-G |
| 0x3D | Intel Broadwell |
| 0x47 | Intel Broadwell-G |
| 0x4F | Intel Broadwell-X |
| 0x56 | Intel Broadwell-D |
| 0x66 | Intel CannonLake-L |
| 0x57 | Intel Xeon® PHI Knights Landing |
| 0x85 | Intel Xeon® PHI Knights Mill |
| 0xA5 | Intel CometLake |
| 0xA6 | Intel CometLake-L |
| 0x8A | Intel Lakefield |
| 0x8F | Intel Sapphire Rapids X |
| 0x8C | Intel TigerLake-L |
| 0x8D | Intel TigerLake |
| 0xA7 | Intel RocketLake |
| 0x97 | Intel AlderLake |
| 0x9A | Intel AlderLake-L |
| 0xBE | Intel AlderLake-N |
| 0xB7 | Intel RaptorLake |
| 0xBA | Intel RaptorLake-P |
| 0xBF | Intel RaptorLake-S |
| 0xAC | Intel MeteorLake |
| 0xAA | Intel MeteorLake-L |
### uncore frequency
Note that only certain processors support the uncore frequency module as well:
| Model number | Processor name |
|--------------|---------------------------------|
| 0x55 | Intel Skylake-X |
| 0x6A | Intel IceLake-X |
| 0x6C | Intel IceLake-D |
| 0x47 | Intel Broadwell-G |
| 0x4F | Intel Broadwell-X |
| 0x56 | Intel Broadwell-D |
| 0x8F | Intel Sapphire Rapids X |
| 0xCF | Intel Emerald Rapids X |
- `cpu_c0_state_residency`
- `cpu_c1_state_residency`
- `cpu_c3_state_residency`
- `cpu_c6_state_residency`
- `cpu_c7_state_residency`
- `cpu_busy_cycles` (**DEPRECATED** - superseded by `cpu_c0_state_residency_percent`)
- `cpu_busy_frequency`
- `cpu_temperature`
- `cpu_base_frequency`
- `max_turbo_frequency`
- `uncore_frequency` (for kernel < 5.18)
- `aperfmperf` shall be present to collect the following metrics:
- `cpu_c0_state_residency`
- `cpu_c1_state_residency`
- `cpu_busy_cycles` (**DEPRECATED** - superseded by `cpu_c0_state_residency_percent`)
- `cpu_busy_frequency`
- `dts` shall be present to collect:
- `cpu_temperature`
- Please consult the table of [supported CPU models](#supported-cpu-models) to see which metrics are supported by your `model`. The following metrics exist:
- `cpu_c1_state_residency`
- `cpu_c3_state_residency`
- `cpu_c6_state_residency`
- `cpu_c7_state_residency`
- `cpu_temperature`
- `cpu_base_frequency`
- `uncore_frequency`
## Metrics
All metrics collected by Intel PowerStat plugin are collected in fixed
intervals. Metrics that reports processor C-state residency or power are
calculated over elapsed intervals. When starting to measure metrics, plugin
skips first iteration of metrics if they are based on deltas with previous
value.
calculated over elapsed intervals.
**The following measurements are supported by Intel PowerStat plugin:**
- powerstat_core
- `powerstat_core`
- The following tags are returned by plugin with
`powerstat_core` measurements:
- The following Tags are returned by plugin with powerstat_core measurements:
| Tag | Description |
|--------------|--------------------------------|
| `package_id` | ID of platform package/socket. |
| `core_id` | ID of physical processor core. |
| `cpu_id` | ID of logical processor core. |
| Tag | Description |
|--------------|-------------------------------|
| `package_id` | ID of platform package/socket |
| `core_id` | ID of physical processor core |
| `cpu_id` | ID of logical processor core |
Measurement `powerstat_core` metrics are collected per-CPU (`cpu_id` is the key)
while `core_id` and `package_id` tags are additional topology information.
Measurement powerstat_core metrics are collected per-CPU (cpu_id is the key)
while core_id and package_id tags are additional topology information.
- Available metrics for `powerstat_core` measurement:
- Available metrics for powerstat_core measurement
| Metric name (field) | Description | Units |
|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| `cpu_frequency_mhz` | Current operational frequency of CPU Core. | MHz |
| `cpu_busy_frequency_mhz` | CPU Core Busy Frequency measured as frequency adjusted to CPU Core busy cycles. | MHz |
| `cpu_temperature_celsius` | Current temperature of CPU Core. | Celsius degrees |
| `cpu_c0_state_residency_percent` | Percentage of time that CPU Core spent in C0 Core residency state. | % |
| `cpu_c1_state_residency_percent` | Percentage of time that CPU Core spent in C1 Core residency state. | % |
| `cpu_c3_state_residency_percent` | Percentage of time that CPU Core spent in C3 Core residency state. | % |
| `cpu_c6_state_residency_percent` | Percentage of time that CPU Core spent in C6 Core residency state. | % |
| `cpu_c7_state_residency_percent` | Percentage of time that CPU Core spent in C7 Core residency state. | % |
| `cpu_c0_substate_c01_percent` | Percentage of time that CPU Core spent in C0.1 substate out of the total time in the C0 state. | % |
| `cpu_c0_substate_c02_percent` | Percentage of time that CPU Core spent in C0.2 substate out of the total time in the C0 state. | % |
| `cpu_c0_substate_c0_wait_percent` | Percentage of time that CPU Core spent in C0_Wait substate out of the total time in the C0 state. | % |
| `cpu_busy_cycles_percent` | (**DEPRECATED** - superseded by cpu_c0_state_residency_percent) CPU Core Busy cycles as a ratio of Cycles spent in C0 state residency to all cycles executed by CPU Core. | % |
| Metric name (field) | Description | Units |
|---------------------|-------------|-------|
| `cpu_frequency_mhz` | Current operational frequency of CPU Core | MHz |
| `cpu_busy_frequency_mhz` | CPU Core Busy Frequency measured as frequency adjusted to CPU Core busy cycles | MHz |
| `cpu_temperature_celsius` | Current temperature of CPU Core | Celsius degrees |
| `cpu_c0_state_residency_percent` | Percentage of time that CPU Core spent in C0 Core residency state | % |
| `cpu_c1_state_residency_percent` | Percentage of time that CPU Core spent in C1 Core residency state | % |
| `cpu_c6_state_residency_percent` | Percentage of time that CPU Core spent in C6 Core residency state | % |
| `cpu_busy_cycles_percent` | (**DEPRECATED** - superseded by cpu_c0_state_residency_percent) CPU Core Busy cycles as a ratio of Cycles spent in C0 state residency to all cycles executed by CPU Core | % |
- `powerstat_package`
- The following tags are returned by plugin with `powerstat_package` measurements:
- powerstat_package
- The following Tags are returned by plugin with powerstat_package measurements:
| Tag | Description |
|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `package_id` | ID of platform package/socket. |
| `active_cores` | Specific tag for `max_turbo_frequency_mhz` metric. The maximum number of activated cores for reachable turbo frequency. |
| `hybrid` | Specific tag for `max_turbo_frequency_mhz` metric. Available only for hybrid processors. Will be set to `primary` for primary cores of a hybrid architecture, and to `secondary` for secondary cores of a hybrid architecture. |
| `die` | Specific tag for all `uncore_frequency` metrics. Id of die. |
| `type` | Specific tag for all `uncore_frequency` metrics. Type of uncore frequency (`current` or `initial`). |
| Tag | Description |
|-----|-------------|
| `package_id` | ID of platform package/socket |
| `active_cores`| Specific tag for `max_turbo_frequency_mhz` metric. The maximum number of activated cores for reachable turbo frequency
| `die`| Specific tag for all `uncore_frequency` metrics. Id of die
| `type`| Specific tag for all `uncore_frequency` metrics. Type of uncore frequency (current or initial)
Measurement `powerstat_package` metrics are collected per processor package
`package_id` tag indicates which package metric refers to.
Measurement powerstat_package metrics are collected per processor package
_package_id_ tag indicates which package metric refers to.
- Available metrics for powerstat_package measurement
- Available metrics for `powerstat_package` measurement:
| Metric name (field) | Description | Units |
|-----|-------------|-----|
| `thermal_design_power_watts` | Maximum Thermal Design Power (TDP) available for processor package | Watts |
| `current_power_consumption_watts` | Current power consumption of processor package | Watts |
| `current_dram_power_consumption_watts` | Current power consumption of processor package DRAM subsystem | Watts |
| `max_turbo_frequency_mhz`| Maximum reachable turbo frequency for number of cores active | MHz
| `uncore_frequency_limit_mhz_min`| Minimum uncore frequency limit for die in processor package | MHz
| `uncore_frequency_limit_mhz_max`| Maximum uncore frequency limit for die in processor package | MHz
| `uncore_frequency_mhz_cur`| Current uncore frequency for die in processor package. Available only with tag `current`. Since this value is not yet available from `intel-uncore-frequency` module it needs to be accessed via MSR. In case of lack of loaded msr, only `uncore_frequency_limit_mhz_min` and `uncore_frequency_limit_mhz_max` metrics will be collected | MHz
| `cpu_base_frequency_mhz`| CPU Base Frequency (maximum non-turbo frequency) for the processor package | MHz
| Metric name (field) | Description | Units |
|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|
| `thermal_design_power_watts` | Maximum Thermal Design Power (TDP) available for processor package. | Watts |
| `current_power_consumption_watts` | Current power consumption of processor package. | Watts |
| `current_dram_power_consumption_watts` | Current power consumption of processor package DRAM subsystem. | Watts |
| `max_turbo_frequency_mhz` | Maximum reachable turbo frequency for number of cores active. | MHz |
| `uncore_frequency_limit_mhz_min` | Minimum uncore frequency limit for die in processor package. | MHz |
| `uncore_frequency_limit_mhz_max` | Maximum uncore frequency limit for die in processor package. | MHz |
| `uncore_frequency_mhz_cur` | Current uncore frequency for die in processor package. Available only with tag `current`. This value is available from `intel-uncore-frequency` module for kernel >= 5.18. For older kernel versions it needs to be accessed via MSR. In case of lack of loaded `msr`, only `uncore_frequency_limit_mhz_min` and `uncore_frequency_limit_mhz_max` metrics will be collected. | MHz |
| `cpu_base_frequency_mhz` | CPU Base Frequency (maximum non-turbo frequency) for the processor package. | MHz |
### Known issues
From linux kernel version v5.4.77 with [this kernel change][19f6d91b] resources
like `/sys/class/powercap/intel-rapl*/*/energy_uj` are readable only by root for
security reasons, so this plugin needs root privileges to work properly.
Starting from Linux kernel version v5.4.77, due to
[this kernel change][19f6d91b], resources such as
`/sys/devices/virtual/powercap/intel-rapl//*/energy_uj`
can only be accessed by the root user for security reasons.
Therefore, this plugin requires root privileges to gather
`rapl` metrics correctly.
If such strict security restrictions are not relevant, reading permissions to
files in `/sys/devices/virtual/powercap/intel-rapl/` directory can be manually
changed for example with `chmod` command with custom parameters. For example to
give all users permission to all files in `intel-rapl` directory:
If such strict security restrictions are not relevant, reading permissions for
files in the `/sys/devices/virtual/powercap/intel-rapl/` directory can be
manually altered, for example, using the chmod command with custom parameters.
For instance, read and execute permissions for all files in the
intel-rapl directory can be granted to all users using:
```bash
sudo chmod -R a+rx /sys/devices/virtual/powercap/intel-rapl/
@ -355,8 +399,82 @@ powerstat_package,die=0,host=ubuntu,package_id=0,type=initial uncore_frequency_l
powerstat_package,die=0,host=ubuntu,package_id=0,type=current uncore_frequency_mhz_cur=800i,uncore_frequency_limit_mhz_min=800,uncore_frequency_limit_mhz_max=2400 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_frequency_mhz=1200.29 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_temperature_celsius=34i 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c6_state_residency_percent=92.52 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c1_state_residency_percent=6.68 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_state_residency_percent=0.8 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c1_state_residency_percent=6.68 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c3_state_residency_percent=0 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c6_state_residency_percent=92.52 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c7_state_residency_percent=0 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_busy_frequency_mhz=1213.24 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c01_percent=0 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c02_percent=5.68 1606494744000000000
powerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c0_wait_percent=43.74 1606494744000000000
```
## Supported CPU models
| Model number | Processor name | `cpu_c1_state_residency`<br/>`cpu_c6_state_residency`<br/>`cpu_temperature`<br/>`cpu_base_frequency` | `cpu_c3_state_residency` | `cpu_c7_state_residency` | `uncore_frequency` |
|--------------|---------------------------------|:----------------------------------------------------------------------------------------------------:|:------------------------:|:------------------------:|:------------------:|
| 0x1E | Intel Nehalem | ✓ | ✓ | | |
| 0x1F | Intel Nehalem-G | ✓ | ✓ | | |
| 0x1A | Intel Nehalem-EP | ✓ | ✓ | | |
| 0x2E | Intel Nehalem-EX | ✓ | ✓ | | |
| 0x25 | Intel Westmere | ✓ | ✓ | | |
| 0x2C | Intel Westmere-EP | ✓ | ✓ | | |
| 0x2F | Intel Westmere-EX | ✓ | ✓ | | |
| 0x2A | Intel Sandybridge | ✓ | ✓ | ✓ | |
| 0x2D | Intel Sandybridge-X | ✓ | ✓ | ✓ | |
| 0x3A | Intel Ivybridge | ✓ | ✓ | ✓ | |
| 0x3E | Intel Ivybridge-X | ✓ | ✓ | ✓ | |
| 0x3C | Intel Haswell | ✓ | ✓ | ✓ | |
| 0x3F | Intel Haswell-X | ✓ | ✓ | ✓ | |
| 0x45 | Intel Haswell-L | ✓ | ✓ | ✓ | |
| 0x46 | Intel Haswell-G | ✓ | ✓ | ✓ | |
| 0x3D | Intel Broadwell | ✓ | ✓ | ✓ | |
| 0x47 | Intel Broadwell-G | ✓ | ✓ | ✓ | ✓ |
| 0x4F | Intel Broadwell-X | ✓ | ✓ | | ✓ |
| 0x56 | Intel Broadwell-D | ✓ | ✓ | | ✓ |
| 0x4E | Intel Skylake-L | ✓ | ✓ | ✓ | |
| 0x5E | Intel Skylake | ✓ | ✓ | ✓ | |
| 0x55 | Intel Skylake-X | ✓ | | | ✓ |
| 0x8E | Intel KabyLake-L | ✓ | ✓ | ✓ | |
| 0x9E | Intel KabyLake | ✓ | ✓ | ✓ | |
| 0xA5 | Intel CometLake | ✓ | ✓ | ✓ | |
| 0xA6 | Intel CometLake-L | ✓ | ✓ | ✓ | |
| 0x66 | Intel CannonLake-L | ✓ | | ✓ | |
| 0x6A | Intel IceLake-X | ✓ | | | ✓ |
| 0x6C | Intel IceLake-D | ✓ | | | ✓ |
| 0x7D | Intel IceLake | ✓ | | | |
| 0x7E | Intel IceLake-L | ✓ | | ✓ | |
| 0x9D | Intel IceLake-NNPI | ✓ | | ✓ | |
| 0xA7 | Intel RocketLake | ✓ | | ✓ | |
| 0x8C | Intel TigerLake-L | ✓ | | ✓ | |
| 0x8D | Intel TigerLake | ✓ | | ✓ | |
| 0x8F | Intel Sapphire Rapids X | ✓ | | | ✓ |
| 0xCF | Intel Emerald Rapids X | ✓ | | | ✓ |
| 0xAD | Intel Granite Rapids X | ✓ | | | |
| 0x8A | Intel Lakefield | ✓ | | ✓ | |
| 0x97 | Intel AlderLake | ✓ | | ✓ | ✓ |
| 0x9A | Intel AlderLake-L | ✓ | | ✓ | ✓ |
| 0xB7 | Intel RaptorLake | ✓ | | ✓ | ✓ |
| 0xBA | Intel RaptorLake-P | ✓ | | ✓ | ✓ |
| 0xBF | Intel RaptorLake-S | ✓ | | ✓ | ✓ |
| 0xAC | Intel MeteorLake | ✓ | | ✓ | ✓ |
| 0xAA | Intel MeteorLake-L | ✓ | | ✓ | ✓ |
| 0xC6 | Intel ArrowLake | ✓ | | ✓ | |
| 0xBD | Intel LunarLake | ✓ | | ✓ | |
| 0x37 | Intel Atom® Bay Trail | ✓ | | | |
| 0x4D | Intel Atom® Avaton | ✓ | | | |
| 0x4A | Intel Atom® Merrifield | ✓ | | | |
| 0x5A | Intel Atom® Moorefield | ✓ | | | |
| 0x4C | Intel Atom® Airmont | ✓ | ✓ | | |
| 0x5C | Intel Atom® Apollo Lake | ✓ | ✓ | ✓ | |
| 0x5F | Intel Atom® Denverton | ✓ | | | |
| 0x7A | Intel Atom® Goldmont | ✓ | ✓ | ✓ | |
| 0x86 | Intel Atom® Jacobsville | ✓ | | | |
| 0x96 | Intel Atom® Elkhart Lake | ✓ | | ✓ | |
| 0x9C | Intel Atom® Jasper Lake | ✓ | | ✓ | |
| 0xBE | Intel AlderLake-N | ✓ | | ✓ | |
| 0xAF | Intel Sierra Forest | ✓ | | | |
| 0xB6 | Intel Grand Ridge | ✓ | | | |
| 0x57 | Intel Xeon® PHI Knights Landing | ✓ | | | |
| 0x85 | Intel Xeon® PHI Knights Mill | ✓ | | | |

View File

@ -1,39 +0,0 @@
//go:build linux
package intel_powerstat
type msrData struct {
mperf uint64
aperf uint64
timeStampCounter uint64
c3 uint64
c6 uint64
c7 uint64
throttleTemp int64
temp int64
mperfDelta uint64
aperfDelta uint64
timeStampCounterDelta uint64
c3Delta uint64
c6Delta uint64
c7Delta uint64
readDate int64
}
type raplData struct {
dramCurrentEnergy float64
socketCurrentEnergy float64
socketEnergy float64
dramEnergy float64
readDate int64
}
type cpuInfo struct {
physicalID string
coreID string
cpuID string
vendorID string
cpuFamily string
model string
flags string
}

View File

@ -0,0 +1,139 @@
//go:build linux && amd64
package intel_powerstat
import (
ptel "github.com/intel/powertelemetry"
)
// topologyFetcher fetches topology information of the host.
type topologyFetcher interface {
// GetMsrCPUIDs returns a slice with available CPU IDs of the host for which msr will access to.
GetMsrCPUIDs() []int
// GetPerfCPUIDs returns a slice with available CPU IDs of the host for which perf will access to.
GetPerfCPUIDs() []int
// GetPackageIDs returns a slice with available package IDs of the host.
GetPackageIDs() []int
// GetCPUPackageID returns the package ID of the host corresponding to the given CPU ID.
GetCPUPackageID(cpuID int) (int, error)
// GetCPUCoreID returns the core ID of the host corresponding to the given CPU ID.
GetCPUCoreID(cpuID int) (int, error)
// GetPackageDieIDs returns the die IDs of the host corresponding to the given package ID.
GetPackageDieIDs(packageID int) ([]int, error)
}
// cpuFreqFetcher fetches supported CPU-related metrics relying on core frequency.
type cpuFreqFetcher interface {
// GetCPUFrequency returns the current frequency value of a given CPU ID, in MHz.
GetCPUFrequency(cpuID int) (float64, error)
}
// cpuMsrFetcher fetches supported CPU-related metrics relying on msr registers.
type cpuMsrFetcher interface {
// GetCPUTemperature returns the temperature value of a given CPU ID, in degrees Celsius.
GetCPUTemperature(cpuID int) (uint64, error)
// UpdatePerCPUMetrics reads multiple MSR offsets needed to get metric values that are time sensitive.
// Below are the list of methods that need the update to be performed beforehand.
UpdatePerCPUMetrics(cpuID int) error
// GetCPUC0StateResidency returns the C0 state residency value of a given CPU ID, as a percentage.
GetCPUC0StateResidency(cpuID int) (float64, error)
// GetCPUC1StateResidency returns the C1 state residency value of a given CPU ID, as a percentage.
GetCPUC1StateResidency(cpuID int) (float64, error)
// GetCPUC3StateResidency returns the C3 state residency value of a given CPU ID, as a percentage.
GetCPUC3StateResidency(cpuID int) (float64, error)
// GetCPUC6StateResidency returns the C6 state residency value of a given CPU ID, as a percentage.
GetCPUC6StateResidency(cpuID int) (float64, error)
// GetCPUC7StateResidency returns the C7 state residency value of a given CPU ID, as a percentage.
GetCPUC7StateResidency(cpuID int) (float64, error)
// GetCPUBusyFrequencyMhz returns the busy frequency value of a given CPU ID, in MHz.
GetCPUBusyFrequencyMhz(cpuID int) (float64, error)
}
// cpuPerfFetcher fetches supported CPU-related metrics relying on perf events.
type cpuPerfFetcher interface {
// ReadPerfEvents reads values of perf events needed to get C0X state residency metrics.
// Below getter methods that need this operation to be performed previously.
ReadPerfEvents() error
// DeactivatePerfEvents deactivates perf events. It closes file descriptors used to get perf event values.
DeactivatePerfEvents() error
// GetCPUC0SubstateC01Percent takes a CPU ID and returns a value indicating the percentage of time
// the processor spent in its C0.1 substate out of the total time in the C0 state.
// C0.1 is characterized by a light-weight slower wakeup time but more power-saving optimized state.
GetCPUC0SubstateC01Percent(cpuID int) (float64, error)
// GetCPUC0SubstateC02Percent takes a CPU ID and returns a value indicating the percentage of time
// the processor spent in its C0.2 substate out of the total time in the C0 state.
// C0.2 is characterized by a light-weight faster wakeup time but less power saving optimized state.
GetCPUC0SubstateC02Percent(cpuID int) (float64, error)
// GetCPUC0SubstateC0WaitPercent takes a CPU ID and returns a value indicating the percentage of time
// the processor spent in its C0_Wait substate out of the total time in the C0 state.
// CPU is in C0_Wait substate when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.
GetCPUC0SubstateC0WaitPercent(cpuID int) (float64, error)
}
// packageRaplFetcher fetches supported package related metrics relying on rapl.
type packageRaplFetcher interface {
// GetCurrentPackagePowerConsumptionWatts returns the current package power consumption value of a given package ID, in watts.
GetCurrentPackagePowerConsumptionWatts(packageID int) (float64, error)
// GetCurrentDramPowerConsumptionWatts returns the current dram power consumption value of a given package ID, in watts.
GetCurrentDramPowerConsumptionWatts(packageID int) (float64, error)
// GetPackageThermalDesignPowerWatts returns the thermal power design value of a given package ID, in watts.
GetPackageThermalDesignPowerWatts(packageID int) (float64, error)
}
// packageUncoreFreqFetcher fetches supported package related metrics relying on uncore frequency.
type packageUncoreFreqFetcher interface {
// GetInitialUncoreFrequencyMin returns the minimum initial uncore frequency value of a given package ID, in MHz.
GetInitialUncoreFrequencyMin(packageID, dieID int) (float64, error)
// GetInitialUncoreFrequencyMax returns the maximum initial uncore frequency value of a given package ID, in MHz.
GetInitialUncoreFrequencyMax(packageID, dieID int) (float64, error)
// GetCustomizedUncoreFrequencyMin returns the minimum custom uncore frequency value of a given package ID, in MHz.
GetCustomizedUncoreFrequencyMin(packageID, dieID int) (float64, error)
// GetCustomizedUncoreFrequencyMax returns the maximum custom uncore frequency value of a given package ID, in MHz.
GetCustomizedUncoreFrequencyMax(packageID, dieID int) (float64, error)
// GetCurrentUncoreFrequency returns the current uncore frequency value of a given package ID, in MHz.
GetCurrentUncoreFrequency(packageID, dieID int) (float64, error)
}
// packageMsrFetcher fetches supported package related metrics relying on msr registers.
type packageMsrFetcher interface {
// GetCPUBaseFrequency returns the CPU base frequency value of a given package ID, in MHz.
GetCPUBaseFrequency(packageID int) (uint64, error)
// GetMaxTurboFreqList returns a list of max turbo frequencies and related active cores of a given package ID.
GetMaxTurboFreqList(packageID int) ([]ptel.MaxTurboFreq, error)
}
// metricFetcher fetches metrics supported by this plugin.
type metricFetcher interface {
topologyFetcher
cpuFreqFetcher
cpuMsrFetcher
cpuPerfFetcher
packageRaplFetcher
packageUncoreFreqFetcher
packageMsrFetcher
}

View File

@ -1,172 +0,0 @@
//go:build linux
package intel_powerstat
import (
"bufio"
"encoding/binary"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
)
// fileService is responsible for handling operations on files.
type fileService interface {
getCPUInfoStats() (map[string]*cpuInfo, error)
getStringsMatchingPatternOnPath(path string) ([]string, error)
readFile(path string) ([]byte, error)
readFileToFloat64(reader io.Reader) (float64, int64, error)
readFileAtOffsetToUint64(reader io.ReaderAt, offset int64) (uint64, error)
}
type fileServiceImpl struct {
}
// getCPUInfoStats retrieves basic information about CPU from /proc/cpuinfo.
func (fs *fileServiceImpl) getCPUInfoStats() (map[string]*cpuInfo, error) {
path := "/proc/cpuinfo"
cpuInfoFile, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("error while reading %q: %w", path, err)
}
defer cpuInfoFile.Close()
scanner := bufio.NewScanner(cpuInfoFile)
processorRegexp := regexp.MustCompile(`^processor\t+:\s([0-9]+)\n*$`)
physicalIDRegexp := regexp.MustCompile(`^physical id\t+:\s([0-9]+)\n*$`)
coreIDRegexp := regexp.MustCompile(`^core id\t+:\s([0-9]+)\n*$`)
vendorIDRegexp := regexp.MustCompile(`^vendor_id\t+:\s([a-zA-Z]+)\n*$`)
cpuFamilyRegexp := regexp.MustCompile(`^cpu\sfamily\t+:\s([0-9]+)\n*$`)
modelRegexp := regexp.MustCompile(`^model\t+:\s([0-9]+)\n*$`)
flagsRegexp := regexp.MustCompile(`^flags\t+:\s(.+)\n*$`)
stats := make(map[string]*cpuInfo)
currentInfo := &cpuInfo{}
for scanner.Scan() {
line := scanner.Text()
processorRes := processorRegexp.FindStringSubmatch(line)
if len(processorRes) > 1 {
currentInfo = &cpuInfo{
cpuID: processorRes[1],
}
}
vendorIDRes := vendorIDRegexp.FindStringSubmatch(line)
if len(vendorIDRes) > 1 {
currentInfo.vendorID = vendorIDRes[1]
}
physicalIDRes := physicalIDRegexp.FindStringSubmatch(line)
if len(physicalIDRes) > 1 {
currentInfo.physicalID = physicalIDRes[1]
}
coreIDRes := coreIDRegexp.FindStringSubmatch(line)
if len(coreIDRes) > 1 {
currentInfo.coreID = coreIDRes[1]
}
cpuFamilyRes := cpuFamilyRegexp.FindStringSubmatch(line)
if len(cpuFamilyRes) > 1 {
currentInfo.cpuFamily = cpuFamilyRes[1]
}
modelRes := modelRegexp.FindStringSubmatch(line)
if len(modelRes) > 1 {
currentInfo.model = modelRes[1]
}
flagsRes := flagsRegexp.FindStringSubmatch(line)
if len(flagsRes) > 1 {
currentInfo.flags = flagsRes[1]
// Flags is the last value we have to acquire, so currentInfo is added to map.
stats[currentInfo.cpuID] = currentInfo
}
}
return stats, nil
}
// getStringsMatchingPatternOnPath looks for filenames and directory names on path matching given regexp.
// It ignores file system errors such as I/O errors reading directories. The only possible returned error
// is ErrBadPattern, when pattern is malformed.
func (fs *fileServiceImpl) getStringsMatchingPatternOnPath(path string) ([]string, error) {
return filepath.Glob(path)
}
// readFile reads file on path and return string content.
func (fs *fileServiceImpl) readFile(path string) ([]byte, error) {
out, err := os.ReadFile(path)
if err != nil {
return make([]byte, 0), err
}
return out, nil
}
// readFileToFloat64 reads file on path and tries to parse content to float64.
func (fs *fileServiceImpl) readFileToFloat64(reader io.Reader) (float64, int64, error) {
read, err := io.ReadAll(reader)
if err != nil {
return 0, 0, err
}
readDate := time.Now().UnixNano()
// Remove new line character
trimmedString := strings.TrimRight(string(read), "\n")
// Parse result to float64
parsedValue, err := strconv.ParseFloat(trimmedString, 64)
if err != nil {
return 0, 0, fmt.Errorf("error parsing string to float for %s", trimmedString)
}
return parsedValue, readDate, nil
}
// readFileAtOffsetToUint64 reads 8 bytes from passed file at given offset.
func (fs *fileServiceImpl) readFileAtOffsetToUint64(reader io.ReaderAt, offset int64) (uint64, error) {
buffer := make([]byte, 8)
if offset == 0 {
return 0, fmt.Errorf("file offset %d should not be 0", offset)
}
_, err := reader.ReadAt(buffer, offset)
if err != nil {
return 0, fmt.Errorf("error on reading file at offset %d: %w", offset, err)
}
return binary.LittleEndian.Uint64(buffer), nil
}
func newFileService() *fileServiceImpl {
return &fileServiceImpl{}
}
func checkFile(path string) error {
if path == "" {
return fmt.Errorf("empty path given")
}
lInfo, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("file %q doesn't exist", path)
}
return fmt.Errorf("cannot obtain file info of %q: %w", path, err)
}
mode := lInfo.Mode()
if mode&os.ModeSymlink != 0 {
return fmt.Errorf("file %q is a symlink", path)
}
return nil
}

View File

@ -1,149 +0,0 @@
//go:build linux
// Code generated by mockery v2.12.3. DO NOT EDIT.
package intel_powerstat
import (
io "io"
mock "github.com/stretchr/testify/mock"
)
// mockFileService is an autogenerated mock type for the mockFileService type
type mockFileService struct {
mock.Mock
}
// getCPUInfoStats provides a mock function with given fields:
func (_m *mockFileService) getCPUInfoStats() (map[string]*cpuInfo, error) {
ret := _m.Called()
var r0 map[string]*cpuInfo
if rf, ok := ret.Get(0).(func() map[string]*cpuInfo); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string]*cpuInfo)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// getStringsMatchingPatternOnPath provides a mock function with given fields: path
func (_m *mockFileService) getStringsMatchingPatternOnPath(path string) ([]string, error) {
ret := _m.Called(path)
var r0 []string
if rf, ok := ret.Get(0).(func(string) []string); ok {
r0 = rf(path)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// readFile provides a mock function with given fields: path
func (_m *mockFileService) readFile(path string) ([]byte, error) {
ret := _m.Called(path)
var r0 []byte
if rf, ok := ret.Get(0).(func(string) []byte); ok {
r0 = rf(path)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// readFileAtOffsetToUint64 provides a mock function with given fields: reader, offset
func (_m *mockFileService) readFileAtOffsetToUint64(reader io.ReaderAt, offset int64) (uint64, error) {
ret := _m.Called(reader, offset)
var r0 uint64
if rf, ok := ret.Get(0).(func(io.ReaderAt, int64) uint64); ok {
r0 = rf(reader, offset)
} else {
r0 = ret.Get(0).(uint64)
}
var r1 error
if rf, ok := ret.Get(1).(func(io.ReaderAt, int64) error); ok {
r1 = rf(reader, offset)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// readFileToFloat64 provides a mock function with given fields: reader
func (_m *mockFileService) readFileToFloat64(reader io.Reader) (float64, int64, error) {
ret := _m.Called(reader)
var r0 float64
if rf, ok := ret.Get(0).(func(io.Reader) float64); ok {
r0 = rf(reader)
} else {
r0 = ret.Get(0).(float64)
}
var r1 int64
if rf, ok := ret.Get(1).(func(io.Reader) int64); ok {
r1 = rf(reader)
} else {
r1 = ret.Get(1).(int64)
}
var r2 error
if rf, ok := ret.Get(2).(func(io.Reader) error); ok {
r2 = rf(reader)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
type newmockFileServiceT interface {
mock.TestingT
Cleanup(func())
}
// newmockFileService creates a new instance of mockFileService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newmockFileService(t newmockFileServiceT) *mockFileService {
mock := &mockFileService{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
//go:generate ../../../tools/readme_config_includer/generator
//go:build !linux
//go:build !linux || !amd64
package intel_powerstat
@ -21,6 +21,7 @@ func (i *IntelPowerstat) Init() error {
i.Log.Warn("current platform is not supported")
return nil
}
func (*IntelPowerstat) SampleConfig() string { return sampleConfig }
func (*IntelPowerstat) Gather(_ telegraf.Accumulator) error { return nil }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,322 @@
//go:build linux && amd64
package intel_powerstat
import (
"errors"
"fmt"
"math"
"strconv"
ptel "github.com/intel/powertelemetry"
"github.com/influxdata/telegraf"
)
// cpuMetricType is an enum type to identify core metrics.
type cpuMetricType int
// cpuMetricType enum defines supported core metrics.
const (
// metric relying on cpuFreq
cpuFrequency cpuMetricType = iota
// metric relying on msr
cpuTemperature
// metrics relying on msr with storage
cpuC0StateResidency
cpuC1StateResidency
cpuC3StateResidency
cpuC6StateResidency
cpuC7StateResidency
cpuBusyCycles // alias of cpuC0StateResidency
cpuBusyFrequency
// metrics relying on perf
cpuC0SubstateC01Percent
cpuC0SubstateC02Percent
cpuC0SubstateC0WaitPercent
)
// Helper method to return a string representation of a core metric.
func (m cpuMetricType) String() string {
switch m {
case cpuFrequency:
return "cpu_frequency"
case cpuTemperature:
return "cpu_temperature"
case cpuBusyFrequency:
return "cpu_busy_frequency"
case cpuC0StateResidency:
return "cpu_c0_state_residency"
case cpuC1StateResidency:
return "cpu_c1_state_residency"
case cpuC3StateResidency:
return "cpu_c3_state_residency"
case cpuC6StateResidency:
return "cpu_c6_state_residency"
case cpuC7StateResidency:
return "cpu_c7_state_residency"
case cpuBusyCycles:
return "cpu_busy_cycles"
case cpuC0SubstateC01Percent:
return "cpu_c0_substate_c01"
case cpuC0SubstateC02Percent:
return "cpu_c0_substate_c02"
case cpuC0SubstateC0WaitPercent:
return "cpu_c0_substate_c0_wait"
}
return ""
}
// UnmarshalText parses the cpu metric from the TOML config file
func (m *cpuMetricType) UnmarshalText(data []byte) (err error) {
parsedMetric, err := cpuMetricTypeFromString(string(data))
if err != nil {
return err
}
*m = parsedMetric
return nil
}
func cpuMetricTypeFromString(metric string) (cpuMetricType, error) {
switch metric {
case "cpu_frequency":
return cpuFrequency, nil
case "cpu_temperature":
return cpuTemperature, nil
case "cpu_busy_frequency":
return cpuBusyFrequency, nil
case "cpu_c0_state_residency":
return cpuC0StateResidency, nil
case "cpu_c1_state_residency":
return cpuC1StateResidency, nil
case "cpu_c3_state_residency":
return cpuC3StateResidency, nil
case "cpu_c6_state_residency":
return cpuC6StateResidency, nil
case "cpu_c7_state_residency":
return cpuC7StateResidency, nil
case "cpu_busy_cycles":
return cpuBusyCycles, nil
case "cpu_c0_substate_c01":
return cpuC0SubstateC01Percent, nil
case "cpu_c0_substate_c02":
return cpuC0SubstateC02Percent, nil
case "cpu_c0_substate_c0_wait":
return cpuC0SubstateC0WaitPercent, nil
}
return -1, fmt.Errorf("invalid cpu metric specified: %q", metric)
}
// packageMetricType is an enum type to identify package metrics.
type packageMetricType int
// packageMetricType enum defines supported package metrics.
const (
// metrics relying on rapl
packageCurrentPowerConsumption packageMetricType = iota
packageCurrentDramPowerConsumption
packageThermalDesignPower
// metrics relying on msr
packageCPUBaseFrequency
// hybrid metric relying on uncoreFreq as a primary mechanism and on msr as fallback mechanism.
packageUncoreFrequency
// metrics relying on msr
packageTurboLimit
)
// Helper method to return a string representation of a package metric.
func (m packageMetricType) String() string {
switch m {
case packageCurrentPowerConsumption:
return "current_power_consumption"
case packageCurrentDramPowerConsumption:
return "current_dram_power_consumption"
case packageThermalDesignPower:
return "thermal_design_power"
case packageCPUBaseFrequency:
return "cpu_base_frequency"
case packageUncoreFrequency:
return "uncore_frequency"
case packageTurboLimit:
return "max_turbo_frequency"
}
return ""
}
// UnmarshalText parses the package metric from the TOML config file
func (m *packageMetricType) UnmarshalText(data []byte) (err error) {
parsedMetric, err := packageMetricTypeFromString(string(data))
if err != nil {
return err
}
*m = parsedMetric
return nil
}
func packageMetricTypeFromString(metric string) (packageMetricType, error) {
switch metric {
case "current_power_consumption":
return packageCurrentPowerConsumption, nil
case "current_dram_power_consumption":
return packageCurrentDramPowerConsumption, nil
case "thermal_design_power":
return packageThermalDesignPower, nil
case "cpu_base_frequency":
return packageCPUBaseFrequency, nil
case "uncore_frequency":
return packageUncoreFrequency, nil
case "max_turbo_frequency":
return packageTurboLimit, nil
}
return -1, fmt.Errorf("invalid package metric specified: %q", metric)
}
// numeric is a type constraint definition.
type numeric interface {
float64 | uint64
}
// metricInfoProvider provides measurement name, fields, and tags needed by the accumulator to add a metric.
type metricInfoProvider interface {
// measurement returns a string with the name of measurement.
measurement() string
// fields returns a map of string keys with metric name and metric values.
fields() (map[string]interface{}, error)
// tags returns a map of string key and string value to add additional metric-specific information.
tags() map[string]string
// name returns the name of a metric.
name() string
}
// addMetric takes a metricInfoProvider interface and adds metric information to an accumulator.
func addMetric(acc telegraf.Accumulator, m metricInfoProvider, logOnceMap map[string]struct{}) {
fields, err := m.fields()
if err == nil {
acc.AddGauge(
m.measurement(),
fields,
m.tags(),
)
return
}
// Always add to the accumulator errors not related to module not initialized.
var moduleErr *ptel.ModuleNotInitializedError
if !errors.As(err, &moduleErr) {
acc.AddError(err)
return
}
// Add only once module not initialized error related to module and metric name.
logErrorOnce(
acc,
logOnceMap,
fmt.Sprintf("%s_%s", moduleErr.Name, m.name()),
fmt.Errorf("failed to get %q: %w", m.name(), moduleErr),
)
}
// metricCommon has metric information common to different types.
type metricCommon struct {
metric interface{}
units string
}
func (m *metricCommon) name() string {
switch m.metric.(type) {
case cpuMetricType:
return m.metric.(cpuMetricType).String()
case packageMetricType:
return m.metric.(packageMetricType).String()
default:
return ""
}
}
func (m *metricCommon) measurement() string {
switch m.metric.(type) {
case cpuMetricType:
return "powerstat_core"
case packageMetricType:
return "powerstat_package"
default:
return ""
}
}
// cpuMetric is a generic type that has the information to identify a CPU-related metric,
// as well as function to retrieve its value at any time. Implements metricAdder interface.
type cpuMetric[T numeric] struct {
metricCommon
cpuID int
coreID int
packageID int
fetchFn func(cpuID int) (T, error)
}
func (m *cpuMetric[T]) fields() (map[string]interface{}, error) {
val, err := m.fetchFn(m.cpuID)
if err != nil {
return nil, fmt.Errorf("failed to get %q for CPU ID %v: %w", m.metric, m.cpuID, err)
}
return map[string]interface{}{
fmt.Sprintf("%s_%s", m.metric, m.units): round(val),
}, nil
}
func (m *cpuMetric[T]) tags() map[string]string {
return map[string]string{
"core_id": strconv.Itoa(m.coreID),
"cpu_id": strconv.Itoa(m.cpuID),
"package_id": strconv.Itoa(m.packageID),
}
}
// packageMetric is a generic type that has the information to identify a package-related metric,
// as well as the function to retrieve its value at any time. Implements metricAdder interface.
type packageMetric[T numeric] struct {
metricCommon
packageID int
fetchFn func(packageID int) (T, error)
}
//nolint:revive // Confusing-naming caused by a generic type that implements this interface method.
func (m *packageMetric[T]) fields() (map[string]interface{}, error) {
val, err := m.fetchFn(m.packageID)
if err != nil {
return nil, fmt.Errorf("failed to get %q for package ID %v: %w", m.metric, m.packageID, err)
}
return map[string]interface{}{
fmt.Sprintf("%s_%s", m.metric, m.units): round(val),
}, nil
}
//nolint:revive // Confusing-naming caused by a generic type that implements this interface method.
func (m *packageMetric[T]) tags() map[string]string {
return map[string]string{
"package_id": strconv.Itoa(m.packageID),
}
}
// round returns the result of rounding the argument, only if it's a 64 bit floating-point type.
func round[T numeric](val T) T {
if v, ok := any(val).(float64); ok {
val = T(math.Round(v*100) / 100)
}
return val
}

View File

@ -0,0 +1,151 @@
//go:build linux && amd64
package intel_powerstat
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestCoreMetric_String(t *testing.T) {
testCases := []struct {
name string
metricName string
}{
{
name: "CPUFrequency",
metricName: "cpu_frequency",
},
{
name: "CPUTemperature",
metricName: "cpu_temperature",
},
{
name: "CPUC0StateResidency",
metricName: "cpu_c0_state_residency",
},
{
name: "CPUC1StateResidency",
metricName: "cpu_c1_state_residency",
},
{
name: "CPUC3StateResidency",
metricName: "cpu_c3_state_residency",
},
{
name: "CPUC6StateResidency",
metricName: "cpu_c6_state_residency",
},
{
name: "CPUC7StateResidency",
metricName: "cpu_c7_state_residency",
},
{
name: "CPUBusyCycles",
metricName: "cpu_busy_cycles",
},
{
name: "CPUBusyFrequency",
metricName: "cpu_busy_frequency",
},
{
name: "CPUC0SubstateC01Percent",
metricName: "cpu_c0_substate_c01",
},
{
name: "CPUC0SubstateC02Percent",
metricName: "cpu_c0_substate_c02",
},
{
name: "CPUC0SubstateC0WaitPercent",
metricName: "cpu_c0_substate_c0_wait",
},
{
name: "Invalid",
metricName: "",
},
}
for i, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
metric := cpuMetricType(i)
require.Equal(t, tc.metricName, metric.String())
})
}
}
func TestPackageMetric_String(t *testing.T) {
testCases := []struct {
name string
metricName string
}{
{
name: "PackageCurrentPowerConsumption",
metricName: "current_power_consumption",
},
{
name: "PackageCurrentDramPowerConsumption",
metricName: "current_dram_power_consumption",
},
{
name: "PackageThermalDesignPower",
metricName: "thermal_design_power",
},
{
name: "PackageCPUBaseFrequency",
metricName: "cpu_base_frequency",
},
{
name: "PackageUncoreFrequency",
metricName: "uncore_frequency",
},
{
name: "PackageTurboLimit",
metricName: "max_turbo_frequency",
},
{
name: "Invalid",
metricName: "",
},
}
for i, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
metric := packageMetricType(i)
require.Equal(t, tc.metricName, metric.String())
})
}
}
func TestCPUMetricTypeFromString(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
for m := cpuMetricType(0); m < cpuC0SubstateC0WaitPercent+1; m++ {
val, err := cpuMetricTypeFromString(m.String())
require.NoError(t, err)
require.Equal(t, m, val)
}
})
t.Run("Invalid", func(t *testing.T) {
val, err := cpuMetricTypeFromString("invalid")
require.Error(t, err)
require.Equal(t, cpuMetricType(-1), val)
})
}
func TestPackageMetricTypeFromString(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
for m := packageMetricType(0); m < packageTurboLimit+1; m++ {
val, err := packageMetricTypeFromString(m.String())
require.NoError(t, err)
require.Equal(t, m, val)
}
})
t.Run("Invalid", func(t *testing.T) {
val, err := packageMetricTypeFromString("invalid")
require.Error(t, err)
require.Equal(t, packageMetricType(-1), val)
})
}

View File

@ -1,327 +0,0 @@
//go:build linux
package intel_powerstat
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"golang.org/x/sync/errgroup"
"github.com/influxdata/telegraf"
)
const (
systemCPUPath = "/sys/devices/system/cpu/"
cpuCurrentFreqPartialPath = "/sys/devices/system/cpu/cpu%s/cpufreq/scaling_cur_freq"
msrPartialPath = "/dev/cpu/%s/msr"
uncoreFreqPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_%s_die_%s/%s%s_freq_khz"
c3StateResidencyLocation = 0x3FC
c6StateResidencyLocation = 0x3FD
c7StateResidencyLocation = 0x3FE
maximumFrequencyClockCountLocation = 0xE7
actualFrequencyClockCountLocation = 0xE8
throttleTemperatureLocation = 0x1A2
temperatureLocation = 0x19C
timestampCounterLocation = 0x10
turboRatioLimitLocation = 0x1AD
turboRatioLimit1Location = 0x1AE
turboRatioLimit2Location = 0x1AF
atomCoreTurboRatiosLocation = 0x66C
uncorePerfStatusLocation = 0x621
platformInfo = 0xCE
fsbFreq = 0xCD
)
const (
msrTurboRatioLimitString = "MSR_TURBO_RATIO_LIMIT"
msrTurboRatioLimit1String = "MSR_TURBO_RATIO_LIMIT1"
msrTurboRatioLimit2String = "MSR_TURBO_RATIO_LIMIT2"
msrAtomCoreTurboRatiosString = "MSR_ATOM_CORE_TURBO_RATIOS"
msrUncorePerfStatusString = "MSR_UNCORE_PERF_STATUS"
msrPlatformInfoString = "MSR_PLATFORM_INFO"
msrFSBFreqString = "MSR_FSB_FREQ"
)
// msrService is responsible for interactions with MSR.
type msrService interface {
getCPUCoresData() map[string]*msrData
retrieveCPUFrequencyForCore(core string) (float64, error)
retrieveUncoreFrequency(socketID string, typeFreq string, kind string, die string) (float64, error)
openAndReadMsr(core string) error
readSingleMsr(core string, msr string) (uint64, error)
isMsrLoaded() bool
}
type msrServiceImpl struct {
cpuCoresData map[string]*msrData
msrOffsets []int64
fs fileService
log telegraf.Logger
}
func (m *msrServiceImpl) getCPUCoresData() map[string]*msrData {
return m.cpuCoresData
}
func (m *msrServiceImpl) isMsrLoaded() bool {
for cpuID := range m.getCPUCoresData() {
err := m.openAndReadMsr(cpuID)
if err == nil {
return true
}
}
return false
}
func (m *msrServiceImpl) retrieveCPUFrequencyForCore(core string) (float64, error) {
cpuFreqPath := fmt.Sprintf(cpuCurrentFreqPartialPath, core)
err := checkFile(cpuFreqPath)
if err != nil {
return 0, err
}
cpuFreqFile, err := os.Open(cpuFreqPath)
if err != nil {
return 0, fmt.Errorf("error opening scaling_cur_freq file on path %q: %w", cpuFreqPath, err)
}
defer cpuFreqFile.Close()
cpuFreq, _, err := m.fs.readFileToFloat64(cpuFreqFile)
return convertKiloHertzToMegaHertz(cpuFreq), err
}
func (m *msrServiceImpl) retrieveUncoreFrequency(socketID string, typeFreq string, kind string, die string) (float64, error) {
uncoreFreqPath, err := createUncoreFreqPath(socketID, typeFreq, kind, die)
if err != nil {
return 0, fmt.Errorf("unable to create uncore freq read path for socketID %q, and frequency type %q: %w", socketID, typeFreq, err)
}
err = checkFile(uncoreFreqPath)
if err != nil {
return 0, err
}
uncoreFreqFile, err := os.Open(uncoreFreqPath)
if err != nil {
return 0, fmt.Errorf("error opening uncore frequncy file on %q: %w", uncoreFreqPath, err)
}
defer uncoreFreqFile.Close()
uncoreFreq, _, err := m.fs.readFileToFloat64(uncoreFreqFile)
return convertKiloHertzToMegaHertz(uncoreFreq), err
}
func createUncoreFreqPath(socketID string, typeFreq string, kind string, die string) (string, error) {
if socketID >= "0" && socketID <= "9" {
socketID = fmt.Sprintf("0%s", socketID)
}
if die >= "0" && die <= "9" {
die = fmt.Sprintf("0%s", die)
}
var prefix string
switch typeFreq {
case "initial":
prefix = "initial_"
case "current":
prefix = ""
default:
return "", fmt.Errorf("unknown frequency type %s, only 'initial' and 'current' are supported", typeFreq)
}
if kind != "min" && kind != "max" {
return "", fmt.Errorf("unknown frequency type %s, only 'min' and 'max' are supported", kind)
}
return fmt.Sprintf(uncoreFreqPath, socketID, die, prefix, kind), nil
}
func (m *msrServiceImpl) openAndReadMsr(core string) error {
path := fmt.Sprintf(msrPartialPath, core)
err := checkFile(path)
if err != nil {
return err
}
msrFile, err := os.Open(path)
if err != nil {
return fmt.Errorf("error opening MSR file on path %q: %w", path, err)
}
defer msrFile.Close()
err = m.readDataFromMsr(core, msrFile)
if err != nil {
return fmt.Errorf("error reading data from MSR for core %q: %w", core, err)
}
return nil
}
func (m *msrServiceImpl) readSingleMsr(core string, msr string) (uint64, error) {
path := fmt.Sprintf(msrPartialPath, core)
err := checkFile(path)
if err != nil {
return 0, err
}
msrFile, err := os.Open(path)
if err != nil {
return 0, fmt.Errorf("error opening MSR file on path %q: %w", path, err)
}
defer msrFile.Close()
var msrAddress int64
switch msr {
case msrTurboRatioLimitString:
msrAddress = turboRatioLimitLocation
case msrTurboRatioLimit1String:
msrAddress = turboRatioLimit1Location
case msrTurboRatioLimit2String:
msrAddress = turboRatioLimit2Location
case msrAtomCoreTurboRatiosString:
msrAddress = atomCoreTurboRatiosLocation
case msrUncorePerfStatusString:
msrAddress = uncorePerfStatusLocation
case msrPlatformInfoString:
msrAddress = platformInfo
case msrFSBFreqString:
msrAddress = fsbFreq
default:
return 0, fmt.Errorf("incorrect name of MSR %s", msr)
}
value, err := m.fs.readFileAtOffsetToUint64(msrFile, msrAddress)
if err != nil {
return 0, err
}
return value, nil
}
func (m *msrServiceImpl) readDataFromMsr(core string, reader io.ReaderAt) error {
g, ctx := errgroup.WithContext(context.Background())
// Create and populate a map that contains msr offsets along with their respective channels
msrOffsetsWithChannels := make(map[int64]chan uint64)
for _, offset := range m.msrOffsets {
msrOffsetsWithChannels[offset] = make(chan uint64)
}
// Start a goroutine for each msr offset
for offset, channel := range msrOffsetsWithChannels {
// Wrap around function to avoid race on loop counter
func(off int64, ch chan uint64) {
g.Go(func() error {
defer close(ch)
err := m.readValueFromFileAtOffset(ctx, ch, reader, off)
if err != nil {
return fmt.Errorf("error reading MSR file: %w", err)
}
return nil
})
}(offset, channel)
}
newC3 := <-msrOffsetsWithChannels[c3StateResidencyLocation]
newC6 := <-msrOffsetsWithChannels[c6StateResidencyLocation]
newC7 := <-msrOffsetsWithChannels[c7StateResidencyLocation]
newMperf := <-msrOffsetsWithChannels[maximumFrequencyClockCountLocation]
newAperf := <-msrOffsetsWithChannels[actualFrequencyClockCountLocation]
newTsc := <-msrOffsetsWithChannels[timestampCounterLocation]
newThrottleTemp := <-msrOffsetsWithChannels[throttleTemperatureLocation]
newTemp := <-msrOffsetsWithChannels[temperatureLocation]
if err := g.Wait(); err != nil {
return fmt.Errorf("received error during reading MSR values in goroutines: %w", err)
}
m.cpuCoresData[core].c3Delta = newC3 - m.cpuCoresData[core].c3
m.cpuCoresData[core].c6Delta = newC6 - m.cpuCoresData[core].c6
m.cpuCoresData[core].c7Delta = newC7 - m.cpuCoresData[core].c7
m.cpuCoresData[core].mperfDelta = newMperf - m.cpuCoresData[core].mperf
m.cpuCoresData[core].aperfDelta = newAperf - m.cpuCoresData[core].aperf
m.cpuCoresData[core].timeStampCounterDelta = newTsc - m.cpuCoresData[core].timeStampCounter
m.cpuCoresData[core].c3 = newC3
m.cpuCoresData[core].c6 = newC6
m.cpuCoresData[core].c7 = newC7
m.cpuCoresData[core].mperf = newMperf
m.cpuCoresData[core].aperf = newAperf
m.cpuCoresData[core].timeStampCounter = newTsc
// MSR (1A2h) IA32_TEMPERATURE_TARGET bits 23:16.
m.cpuCoresData[core].throttleTemp = int64((newThrottleTemp >> 16) & 0xFF)
// MSR (19Ch) IA32_THERM_STATUS bits 22:16.
m.cpuCoresData[core].temp = int64((newTemp >> 16) & 0x7F)
return nil
}
func (m *msrServiceImpl) readValueFromFileAtOffset(ctx context.Context, ch chan uint64, reader io.ReaderAt, offset int64) error {
value, err := m.fs.readFileAtOffsetToUint64(reader, offset)
if err != nil {
return err
}
// Detect context cancellation and return an error if other goroutine fails
select {
case <-ctx.Done():
return ctx.Err()
case ch <- value:
}
return nil
}
// setCPUCores initialize cpuCoresData map.
func (m *msrServiceImpl) setCPUCores() error {
m.cpuCoresData = make(map[string]*msrData)
cpuPrefix := "cpu"
cpuCore := fmt.Sprintf("%s%s", cpuPrefix, "[0-9]*")
cpuCorePattern := fmt.Sprintf("%s/%s", systemCPUPath, cpuCore)
cpuPaths, err := m.fs.getStringsMatchingPatternOnPath(cpuCorePattern)
if err != nil {
return err
}
if len(cpuPaths) == 0 {
m.log.Debugf("CPU core data wasn't found using pattern: %s", cpuCorePattern)
return nil
}
for _, cpuPath := range cpuPaths {
core := strings.TrimPrefix(filepath.Base(cpuPath), cpuPrefix)
m.cpuCoresData[core] = &msrData{
mperf: 0,
aperf: 0,
timeStampCounter: 0,
c3: 0,
c6: 0,
c7: 0,
throttleTemp: 0,
temp: 0,
mperfDelta: 0,
aperfDelta: 0,
timeStampCounterDelta: 0,
c3Delta: 0,
c6Delta: 0,
c7Delta: 0,
}
}
return nil
}
func newMsrServiceWithFs(logger telegraf.Logger, fs fileService) *msrServiceImpl {
msrService := &msrServiceImpl{
fs: fs,
log: logger,
}
err := msrService.setCPUCores()
if err != nil {
// This error does not prevent plugin from working thus it is not returned.
msrService.log.Error(err)
}
msrService.msrOffsets = []int64{c3StateResidencyLocation, c6StateResidencyLocation, c7StateResidencyLocation,
maximumFrequencyClockCountLocation, actualFrequencyClockCountLocation, timestampCounterLocation,
throttleTemperatureLocation, temperatureLocation}
return msrService
}

View File

@ -1,134 +0,0 @@
//go:build linux
// Code generated by mockery v2.12.3. DO NOT EDIT.
package intel_powerstat
import mock "github.com/stretchr/testify/mock"
// mockMsrService is an autogenerated mock type for the mockMsrService type
type mockMsrService struct {
mock.Mock
}
// isMsrLoaded provides a mock function with given fields:
func (_m *mockMsrService) isMsrLoaded() bool {
ret := _m.Called()
var r0 bool
if rf, ok := ret.Get(0).(func() bool); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// getCPUCoresData provides a mock function with given fields:
func (_m *mockMsrService) getCPUCoresData() map[string]*msrData {
ret := _m.Called()
var r0 map[string]*msrData
if rf, ok := ret.Get(0).(func() map[string]*msrData); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string]*msrData)
}
}
return r0
}
// openAndReadMsr provides a mock function with given fields: core
func (_m *mockMsrService) openAndReadMsr(core string) error {
ret := _m.Called(core)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(core)
} else {
r0 = ret.Error(0)
}
return r0
}
// readSingleMsr provides a mock function with given fields: core, msr
func (_m *mockMsrService) readSingleMsr(core string, msr string) (uint64, error) {
ret := _m.Called(core, msr)
var r0 uint64
if rf, ok := ret.Get(0).(func(string, string) uint64); ok {
r0 = rf(core, msr)
} else {
r0 = ret.Get(0).(uint64)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(core, msr)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// retrieveCPUFrequencyForCore provides a mock function with given fields: core
func (_m *mockMsrService) retrieveCPUFrequencyForCore(core string) (float64, error) {
ret := _m.Called(core)
var r0 float64
if rf, ok := ret.Get(0).(func(string) float64); ok {
r0 = rf(core)
} else {
r0 = ret.Get(0).(float64)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(core)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// retrieveUncoreFrequency provides a mock function with given fields: socketID, typeFreq, kind, die
func (_m *mockMsrService) retrieveUncoreFrequency(socketID string, typeFreq string, kind string, die string) (float64, error) {
ret := _m.Called(socketID, typeFreq, kind, die)
var r0 float64
if rf, ok := ret.Get(0).(func(string, string, string, string) float64); ok {
r0 = rf(socketID, typeFreq, kind, die)
} else {
r0 = ret.Get(0).(float64)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, string, string) error); ok {
r1 = rf(socketID, typeFreq, kind, die)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
type newmockMsrServiceT interface {
mock.TestingT
Cleanup(func())
}
// newmockMsrService creates a new instance of mockMsrService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newmockMsrService(t newmockMsrServiceT) *mockMsrService {
mock := &mockMsrService{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,188 +0,0 @@
//go:build linux
package intel_powerstat
import (
"context"
"errors"
"strings"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func TestReadDataFromMsrPositive(t *testing.T) {
firstValue := uint64(1000000)
secondValue := uint64(5000000)
delta := secondValue - firstValue
cpuCores := []string{"cpu0", "cpu1"}
msr, fsMock := getMsrServiceWithMockedFs()
prepareTestData(fsMock, cpuCores, msr, t)
cores := trimCPUFromCores(cpuCores)
methodCallNumberForFirstValue := len(msr.msrOffsets) * len(cores)
methodCallNumberForSecondValue := methodCallNumberForFirstValue * 2
fsMock.On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(firstValue, nil).Times(methodCallNumberForFirstValue)
for _, core := range cores {
require.NoError(t, msr.readDataFromMsr(core, nil))
}
fsMock.AssertNumberOfCalls(t, "readFileAtOffsetToUint64", methodCallNumberForFirstValue)
verifyCPUCoresData(cores, t, msr, firstValue, false, 0)
fsMock.On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(secondValue, nil).Times(methodCallNumberForFirstValue)
for _, core := range cores {
require.NoError(t, msr.readDataFromMsr(core, nil))
}
fsMock.AssertNumberOfCalls(t, "readFileAtOffsetToUint64", methodCallNumberForSecondValue)
verifyCPUCoresData(cores, t, msr, secondValue, true, delta)
}
func trimCPUFromCores(cpuCores []string) []string {
cores := make([]string, 0)
for _, core := range cpuCores {
cores = append(cores, strings.TrimPrefix(core, "cpu"))
}
return cores
}
func TestReadDataFromMsrNegative(t *testing.T) {
firstValue := uint64(1000000)
cpuCores := []string{"cpu0", "cpu1"}
msr, fsMock := getMsrServiceWithMockedFs()
prepareTestData(fsMock, cpuCores, msr, t)
cores := trimCPUFromCores(cpuCores)
methodCallNumberPerCore := len(msr.msrOffsets)
// Normal execution for first core.
fsMock.On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(firstValue, nil).Times(methodCallNumberPerCore).
// Fail to read file for second core.
On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(uint64(0), errors.New("error reading file")).Times(methodCallNumberPerCore)
require.NoError(t, msr.readDataFromMsr(cores[0], nil))
require.Error(t, msr.readDataFromMsr(cores[1], nil))
}
func TestReadValueFromFileAtOffset(t *testing.T) {
cores := []string{"cpu0", "cpu1"}
msr, fsMock := getMsrServiceWithMockedFs()
ctx := context.Background()
testChannel := make(chan uint64, 1)
defer close(testChannel)
zero := uint64(0)
prepareTestData(fsMock, cores, msr, t)
fsMock.On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(zero, errors.New("error reading file")).Once()
require.Error(t, msr.readValueFromFileAtOffset(ctx, testChannel, nil, 0))
fsMock.On("readFileAtOffsetToUint64", mock.Anything, mock.Anything).
Return(zero, nil).Once()
require.NoError(t, msr.readValueFromFileAtOffset(ctx, testChannel, nil, 0))
require.Equal(t, zero, <-testChannel)
}
func TestCreateUncoreFreqPath(t *testing.T) {
path, err := createUncoreFreqPath("0", "initial", "min", "0")
expectedPath := "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/initial_min_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "initial", "max", "0")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/initial_max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "current", "min", "0")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/min_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "current", "max", "0")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("9", "current", "max", "0")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_09_die_00/max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("99", "current", "max", "0")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_99_die_00/max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "current", "max", "9")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_09/max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "current", "max", "99")
expectedPath = "/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_99/max_freq_khz"
require.NoError(t, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "foo", "max", "0")
expectedPath = ""
expectedError := errors.New("unknown frequency type foo, only 'initial' and 'current' are supported")
require.Equal(t, expectedError, err)
require.Equal(t, expectedPath, path)
path, err = createUncoreFreqPath("0", "current", "bar", "0")
expectedPath = ""
expectedError = errors.New("unknown frequency type bar, only 'min' and 'max' are supported")
require.Equal(t, expectedError, err)
require.Equal(t, expectedPath, path)
}
func prepareTestData(fsMock *mockFileService, cores []string, msr *msrServiceImpl, t *testing.T) {
// Prepare MSR offsets and CPUCoresData for test.
fsMock.On("getStringsMatchingPatternOnPath", mock.Anything).
Return(cores, nil).Once()
require.NoError(t, msr.setCPUCores())
fsMock.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
}
func verifyCPUCoresData(cores []string, t *testing.T, msr *msrServiceImpl, expectedValue uint64, verifyDelta bool, delta uint64) {
for _, core := range cores {
require.Equal(t, expectedValue, msr.cpuCoresData[core].c3)
require.Equal(t, expectedValue, msr.cpuCoresData[core].c6)
require.Equal(t, expectedValue, msr.cpuCoresData[core].c7)
require.Equal(t, expectedValue, msr.cpuCoresData[core].mperf)
require.Equal(t, expectedValue, msr.cpuCoresData[core].aperf)
require.Equal(t, expectedValue, msr.cpuCoresData[core].timeStampCounter)
require.Equal(t, int64((expectedValue>>16)&0xFF), msr.cpuCoresData[core].throttleTemp)
require.Equal(t, int64((expectedValue>>16)&0x7F), msr.cpuCoresData[core].temp)
if verifyDelta {
require.Equal(t, delta, msr.cpuCoresData[core].c3Delta)
require.Equal(t, delta, msr.cpuCoresData[core].c6Delta)
require.Equal(t, delta, msr.cpuCoresData[core].c7Delta)
require.Equal(t, delta, msr.cpuCoresData[core].mperfDelta)
require.Equal(t, delta, msr.cpuCoresData[core].aperfDelta)
require.Equal(t, delta, msr.cpuCoresData[core].timeStampCounterDelta)
}
}
}
func getMsrServiceWithMockedFs() (*msrServiceImpl, *mockFileService) {
cores := []string{"cpu0", "cpu1", "cpu2", "cpu3"}
logger := testutil.Logger{Name: "PowerPluginTest"}
fsMock := &mockFileService{}
fsMock.On("getStringsMatchingPatternOnPath", mock.Anything).
Return(cores, nil).Once()
msr := newMsrServiceWithFs(logger, fsMock)
return msr, fsMock
}

View File

@ -0,0 +1,184 @@
//go:build linux && amd64
package intel_powerstat
import (
"slices"
"time"
ptel "github.com/intel/powertelemetry"
"github.com/influxdata/telegraf"
)
// optConfig represents plugin configuration fields needed to generate options.
type optConfig struct {
cpuMetrics []cpuMetricType
packageMetrics []packageMetricType
includedCPUs []int
excludedCPUs []int
perfEventFile string
msrReadTimeout time.Duration
log telegraf.Logger
}
// optionGenerator takes a struct with the plugin configuration, and generates options
// needed to gather metrics.
type optionGenerator interface {
generate(cfg optConfig) []ptel.Option
}
// optGenerator implements optionGenerator interface.
type optGenerator struct{}
// generate takes plugin configuration options and generates options needed
// to gather requested metrics.
func (g *optGenerator) generate(cfg optConfig) []ptel.Option {
opts := make([]ptel.Option, 0)
if len(cfg.includedCPUs) != 0 {
opts = append(opts, ptel.WithIncludedCPUs(cfg.includedCPUs))
}
if len(cfg.excludedCPUs) != 0 {
opts = append(opts, ptel.WithExcludedCPUs(cfg.excludedCPUs))
}
if needsMsrCPU(cfg.cpuMetrics) || needsMsrPackage(cfg.packageMetrics) {
if cfg.msrReadTimeout == 0 {
opts = append(opts, ptel.WithMsr())
} else {
opts = append(opts, ptel.WithMsrTimeout(cfg.msrReadTimeout))
}
}
if needsRapl(cfg.packageMetrics) {
opts = append(opts, ptel.WithRapl())
}
if needsCoreFreq(cfg.cpuMetrics) {
opts = append(opts, ptel.WithCoreFrequency())
}
if needsUncoreFreq(cfg.packageMetrics) {
opts = append(opts, ptel.WithUncoreFrequency())
}
if needsPerf(cfg.cpuMetrics) {
opts = append(opts, ptel.WithPerf(cfg.perfEventFile))
}
if cfg.log != nil {
opts = append(opts, ptel.WithLogger(cfg.log))
}
return opts
}
// needsMsr takes a slice of strings, representing supported metrics, and
// returns true if any relies on msr registers.
func needsMsrCPU(metrics []cpuMetricType) bool {
for _, m := range metrics {
switch m {
case cpuTemperature:
case cpuC0StateResidency:
case cpuC1StateResidency:
case cpuC3StateResidency:
case cpuC6StateResidency:
case cpuC7StateResidency:
case cpuBusyCycles:
case cpuBusyFrequency:
default:
continue
}
return true
}
return false
}
// needsMsrPackage takes a slice of strings, representing supported metrics, and
// returns true if any relies on msr registers.
func needsMsrPackage(metrics []packageMetricType) bool {
for _, m := range metrics {
switch m {
case packageCPUBaseFrequency:
case packageTurboLimit:
case packageUncoreFrequency:
// Fallback mechanism retrieves this metric from MSR registers.
default:
continue
}
return true
}
return false
}
// needsTimeRelatedMsr takes a slice of strings, representing supported metrics, and
// returns true if any relies on time-related reads of msr registers.
func needsTimeRelatedMsr(metrics []cpuMetricType) bool {
for _, m := range metrics {
switch m {
case cpuC0StateResidency:
case cpuC1StateResidency:
case cpuC3StateResidency:
case cpuC6StateResidency:
case cpuC7StateResidency:
case cpuBusyCycles:
case cpuBusyFrequency:
default:
continue
}
return true
}
return false
}
// needsRapl takes a slice of strings, representing supported metrics, and
// returns true if any relies on intel-rapl control zone.
func needsRapl(metrics []packageMetricType) bool {
for _, m := range metrics {
switch m {
case packageCurrentPowerConsumption:
case packageCurrentDramPowerConsumption:
case packageThermalDesignPower:
default:
continue
}
return true
}
return false
}
// needsCoreFreq takes a slice of strings, representing supported metrics, and
// returns true if any relies on sysfs "/sys/devices/system/cpu/" with global and
// individual CPU attributes.
func needsCoreFreq(metrics []cpuMetricType) bool {
return slices.Contains(metrics, cpuFrequency)
}
// needsUncoreFreq takes a slice of strings, representing supported metrics, and returns
// true if any relies on sysfs interface "/sys/devices/system/cpu/intel_uncore_frequency/"
// provided by intel_uncore_frequency kernel module.
func needsUncoreFreq(metrics []packageMetricType) bool {
return slices.Contains(metrics, packageUncoreFrequency)
}
// needsPerf takes a slice of strings, representing supported metrics, and
// returns true if any relies on perf_events interface.
func needsPerf(metrics []cpuMetricType) bool {
for _, m := range metrics {
switch m {
case cpuC0SubstateC01Percent:
case cpuC0SubstateC02Percent:
case cpuC0SubstateC0WaitPercent:
default:
continue
}
return true
}
return false
}

View File

@ -0,0 +1,305 @@
//go:build linux && amd64
package intel_powerstat
import (
"reflect"
"runtime"
"strings"
"testing"
"time"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
func TestGenerate(t *testing.T) {
t.Run("NoCPUsSpecified", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
cpuMetrics: []cpuMetricType{
cpuFrequency, // needs coreFreq
cpuC0SubstateC01Percent, // needs perf
},
packageMetrics: []packageMetricType{
packageCurrentPowerConsumption, // needs rapl
packageUncoreFrequency, // needs uncoreFreq and msr
},
})
require.Len(t, opts, 5)
})
t.Run("ExcludedCPUs", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
excludedCPUs: []int{0, 1, 2, 3},
cpuMetrics: []cpuMetricType{
// needs msr
cpuTemperature,
},
packageMetrics: []packageMetricType{
// needs rapl
packageCurrentPowerConsumption,
},
})
require.Len(t, opts, 3)
})
t.Run("IncludedCPUs", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
includedCPUs: []int{0, 1, 2, 3},
cpuMetrics: []cpuMetricType{
cpuFrequency, // needs coreFreq
cpuC0SubstateC0WaitPercent, // needs perf
},
packageMetrics: []packageMetricType{
packageTurboLimit, // needs msr
packageCurrentDramPowerConsumption, // needs rapl
packageUncoreFrequency, // needs uncoreFreq
},
})
require.Len(t, opts, 6)
})
t.Run("WithMsrTimeout", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
cpuMetrics: []cpuMetricType{
cpuTemperature,
},
msrReadTimeout: time.Second,
})
require.Len(t, opts, 1)
withMsrTimeoutUsed := false
for _, opt := range opts {
if strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), ".WithMsrTimeout.") {
withMsrTimeoutUsed = true
continue
}
}
require.True(t, withMsrTimeoutUsed, "WithMsrTimeout wasn't included in the generated options")
})
t.Run("WithMsr", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
cpuMetrics: []cpuMetricType{
cpuC7StateResidency,
},
msrReadTimeout: 0, //timeout disabled
})
require.Len(t, opts, 1)
withMsrUsed := false
for _, opt := range opts {
if strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), ".WithMsr.") {
withMsrUsed = true
continue
}
}
require.True(t, withMsrUsed, "WithMsr wasn't included in the generated options")
})
t.Run("WithLogger", func(t *testing.T) {
g := &optGenerator{}
opts := g.generate(optConfig{
cpuMetrics: []cpuMetricType{
cpuC3StateResidency,
},
log: &testutil.Logger{},
})
require.Len(t, opts, 2)
withLoggerUsed := false
for _, opt := range opts {
if strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), ".WithLogger.") {
withLoggerUsed = true
continue
}
}
require.True(t, withLoggerUsed, "WithLogger wasn't included in the generated options")
})
}
func TestNeedsMsrPackage(t *testing.T) {
packageMetrics := []packageMetricType{
packageThermalDesignPower, // needs rapl
packageCurrentDramPowerConsumption, // needs rapl
packageMetricType(420),
}
t.Run("False", func(t *testing.T) {
require.False(t, needsMsrPackage(packageMetrics))
})
t.Run("True", func(t *testing.T) {
t.Run("CPUBaseFreq", func(t *testing.T) {
packageMetrics[len(packageMetrics)-1] = packageCPUBaseFrequency
require.True(t, needsMsrPackage(packageMetrics))
})
t.Run("PackageTurboLimit", func(t *testing.T) {
packageMetrics[len(packageMetrics)-1] = packageTurboLimit
require.True(t, needsMsrPackage(packageMetrics))
})
t.Run("PackageUncoreFrequency", func(t *testing.T) {
packageMetrics[len(packageMetrics)-1] = packageUncoreFrequency
require.True(t, needsMsrPackage(packageMetrics))
})
})
}
func TestNeedsMsrCPU(t *testing.T) {
cpuMetrics := []cpuMetricType{
cpuFrequency, // needs cpuFreq
cpuC0SubstateC01Percent, // needs perf
}
t.Run("False", func(t *testing.T) {
require.False(t, needsMsrCPU(cpuMetrics))
})
t.Run("True", func(t *testing.T) {
t.Run("CPUTemperature", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuTemperature
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUC0StateResidency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuC0StateResidency
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUC1StateResidency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuC1StateResidency
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUC3StateResidency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuC3StateResidency
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUC6StateResidency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuC6StateResidency
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUC7StateResidency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuC7StateResidency
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUBusyCycles", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuBusyCycles
require.True(t, needsMsrCPU(cpuMetrics))
})
t.Run("CPUBusyFrequency", func(t *testing.T) {
cpuMetrics[len(cpuMetrics)-1] = cpuBusyFrequency
require.True(t, needsMsrCPU(cpuMetrics))
})
})
}
func TestNeedsRapl(t *testing.T) {
metrics := []packageMetricType{
packageCPUBaseFrequency, // needs msr
packageUncoreFrequency, // needs uncoreFreq
packageMetricType(420),
}
t.Run("False", func(t *testing.T) {
require.False(t, needsRapl(metrics))
})
t.Run("True", func(t *testing.T) {
t.Run("PackageCurrentPowerConsumption", func(t *testing.T) {
metrics[len(metrics)-1] = packageCurrentPowerConsumption
require.True(t, needsRapl(metrics))
})
t.Run("PackageCurrentDramPowerConsumption", func(t *testing.T) {
metrics[len(metrics)-1] = packageCurrentDramPowerConsumption
require.True(t, needsRapl(metrics))
})
t.Run("PackageThermalDesignPower", func(t *testing.T) {
metrics[len(metrics)-1] = packageThermalDesignPower
require.True(t, needsRapl(metrics))
})
})
}
func TestNeedsCoreFreq(t *testing.T) {
metrics := []cpuMetricType{
cpuTemperature, // needs msr
cpuC1StateResidency, // needs msr
cpuC0SubstateC01Percent, // needs perf
cpuMetricType(420),
}
t.Run("False", func(t *testing.T) {
require.False(t, needsCoreFreq(metrics))
})
t.Run("True", func(t *testing.T) {
metrics[len(metrics)-1] = cpuFrequency
require.True(t, needsCoreFreq(metrics))
})
}
func TestNeedsUncoreFreq(t *testing.T) {
metrics := []packageMetricType{
packageCPUBaseFrequency, // needs msr
packageThermalDesignPower, // needs rapl
packageMetricType(420),
}
t.Run("False", func(t *testing.T) {
require.False(t, needsUncoreFreq(metrics))
})
t.Run("True", func(t *testing.T) {
metrics[len(metrics)-1] = packageUncoreFrequency
require.True(t, needsUncoreFreq(metrics))
})
}
func TestNeedsPerf(t *testing.T) {
metrics := []cpuMetricType{
cpuFrequency, // needs cpuFreq
cpuC1StateResidency, // needs msr
cpuMetricType(420),
}
t.Run("False", func(t *testing.T) {
require.False(t, needsPerf(metrics))
})
t.Run("True", func(t *testing.T) {
t.Run("CPUC0SubstateC01Percent", func(t *testing.T) {
metrics[len(metrics)-1] = cpuC0SubstateC01Percent
require.True(t, needsPerf(metrics))
})
t.Run("CPUC0SubstateC02Percent", func(t *testing.T) {
metrics[len(metrics)-1] = cpuC0SubstateC02Percent
require.True(t, needsPerf(metrics))
})
t.Run("CPUC0SubstateC0WaitPercent", func(t *testing.T) {
metrics[len(metrics)-1] = cpuC0SubstateC0WaitPercent
require.True(t, needsPerf(metrics))
})
})
}

View File

@ -1,265 +0,0 @@
//go:build linux
package intel_powerstat
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/influxdata/telegraf"
)
const (
intelRaplPath = "/sys/devices/virtual/powercap/intel-rapl"
intelRaplSocketPartialPath = "%s/intel-rapl:%s"
energyUjPartialPath = "%s/energy_uj"
maxEnergyRangeUjPartialPath = "%s/max_energy_range_uj"
maxPowerUwPartialPath = "%s/constraint_0_max_power_uw"
intelRaplDramPartialPath = "%s/intel-rapl:%s/%s"
intelRaplDramNamePartialPath = "%s/name"
)
// raplService is responsible for interactions with RAPL.
type raplService interface {
initializeRaplData()
getRaplData() map[string]*raplData
retrieveAndCalculateData(socketID string) error
getConstraintMaxPowerWatts(socketID string) (float64, error)
}
type raplServiceImpl struct {
log telegraf.Logger
data map[string]*raplData
dramFolders map[string]string
fs fileService
logOnce map[string]error
}
// initializeRaplData looks for RAPL folders and initializes data map with fetched information.
func (r *raplServiceImpl) initializeRaplData() {
r.prepareData()
r.findDramFolders()
}
func (r *raplServiceImpl) getRaplData() map[string]*raplData {
return r.data
}
func (r *raplServiceImpl) retrieveAndCalculateData(socketID string) error {
socketRaplPath := fmt.Sprintf(intelRaplSocketPartialPath, intelRaplPath, socketID)
socketEnergyUjPath := fmt.Sprintf(energyUjPartialPath, socketRaplPath)
err := checkFile(socketEnergyUjPath)
if err != nil {
return err
}
socketEnergyUjFile, err := os.Open(socketEnergyUjPath)
if err != nil {
return fmt.Errorf("error opening socket energy_uj file on path %q: %w", socketEnergyUjPath, err)
}
defer socketEnergyUjFile.Close()
dramRaplPath := fmt.Sprintf(intelRaplDramPartialPath, intelRaplPath, socketID, r.dramFolders[socketID])
dramEnergyUjPath := fmt.Sprintf(energyUjPartialPath, dramRaplPath)
err = checkFile(dramEnergyUjPath)
if err != nil {
return err
}
dramEnergyUjFile, err := os.Open(dramEnergyUjPath)
if err != nil {
return fmt.Errorf("error opening dram energy_uj file on path %q: %w", dramEnergyUjPath, err)
}
defer dramEnergyUjFile.Close()
socketMaxEnergyUjPath := fmt.Sprintf(maxEnergyRangeUjPartialPath, socketRaplPath)
err = checkFile(socketMaxEnergyUjPath)
if err != nil {
return err
}
socketMaxEnergyUjFile, err := os.Open(socketMaxEnergyUjPath)
if err != nil {
return fmt.Errorf("error opening socket max_energy_range_uj file on path %q: %w", socketMaxEnergyUjPath, err)
}
defer socketMaxEnergyUjFile.Close()
dramMaxEnergyUjPath := fmt.Sprintf(maxEnergyRangeUjPartialPath, dramRaplPath)
err = checkFile(dramMaxEnergyUjPath)
if err != nil {
return err
}
dramMaxEnergyUjFile, err := os.Open(dramMaxEnergyUjPath)
if err != nil {
return fmt.Errorf("error opening dram max_energy_range_uj file on path %q: %w", dramMaxEnergyUjPath, err)
}
defer dramMaxEnergyUjFile.Close()
return r.calculateData(socketID, socketEnergyUjFile, dramEnergyUjFile, socketMaxEnergyUjFile, dramMaxEnergyUjFile)
}
func (r *raplServiceImpl) getConstraintMaxPowerWatts(socketID string) (float64, error) {
socketRaplPath := fmt.Sprintf(intelRaplSocketPartialPath, intelRaplPath, socketID)
socketMaxPowerPath := fmt.Sprintf(maxPowerUwPartialPath, socketRaplPath)
err := checkFile(socketMaxPowerPath)
if err != nil {
return 0, err
}
socketMaxPowerFile, err := os.Open(socketMaxPowerPath)
if err != nil {
return 0, fmt.Errorf("error opening constraint_0_max_power_uw file on path %q: %w", socketMaxPowerPath, err)
}
defer socketMaxPowerFile.Close()
socketMaxPower, _, err := r.fs.readFileToFloat64(socketMaxPowerFile)
return convertMicroWattToWatt(socketMaxPower), err
}
func (r *raplServiceImpl) prepareData() {
intelRaplPrefix := "intel-rapl:"
intelRapl := fmt.Sprintf("%s%s", intelRaplPrefix, "[0-9]*")
raplPattern := fmt.Sprintf("%s/%s", intelRaplPath, intelRapl)
raplPaths, err := r.fs.getStringsMatchingPatternOnPath(raplPattern)
if err != nil {
r.log.Errorf("error while preparing RAPL data: %v", err)
r.data = make(map[string]*raplData)
return
}
if len(raplPaths) == 0 {
r.log.Debugf("RAPL data wasn't found using pattern: %s", raplPattern)
r.data = make(map[string]*raplData)
return
}
// If RAPL exists initialize data map (if it wasn't initialized before).
if len(r.data) == 0 {
for _, raplPath := range raplPaths {
socketID := strings.TrimPrefix(filepath.Base(raplPath), intelRaplPrefix)
r.data[socketID] = &raplData{
socketCurrentEnergy: 0,
dramCurrentEnergy: 0,
socketEnergy: 0,
dramEnergy: 0,
readDate: 0,
}
}
}
}
func (r *raplServiceImpl) findDramFolders() {
intelRaplPrefix := "intel-rapl:"
intelRaplDram := fmt.Sprintf("%s%s", intelRaplPrefix, "[0-9]*[0-9]*")
// Clean existing map
r.dramFolders = make(map[string]string)
for socketID := range r.data {
path := fmt.Sprintf(intelRaplSocketPartialPath, intelRaplPath, socketID)
raplFoldersPattern := fmt.Sprintf("%s/%s", path, intelRaplDram)
pathsToRaplFolders, err := r.fs.getStringsMatchingPatternOnPath(raplFoldersPattern)
if err != nil {
r.log.Errorf("error during lookup for rapl dram: %v", err)
continue
}
if len(pathsToRaplFolders) == 0 {
r.log.Debugf("RAPL folders weren't found using pattern: %s", raplFoldersPattern)
continue
}
raplFolders := make([]string, 0)
for _, folderPath := range pathsToRaplFolders {
raplFolders = append(raplFolders, filepath.Base(folderPath))
}
r.findDramFolder(raplFolders, socketID)
}
}
func (r *raplServiceImpl) findDramFolder(raplFolders []string, socketID string) {
if r.logOnce == nil {
r.logOnce = make(map[string]error)
}
for _, raplFolder := range raplFolders {
potentialDramPath := fmt.Sprintf(intelRaplDramPartialPath, intelRaplPath, socketID, raplFolder)
nameFilePath := fmt.Sprintf(intelRaplDramNamePartialPath, potentialDramPath)
read, err := r.fs.readFile(nameFilePath)
if err != nil {
if val := r.logOnce[nameFilePath]; val == nil || val.Error() != err.Error() {
r.log.Errorf("error reading file on path %q: %v", nameFilePath, err)
r.logOnce[nameFilePath] = err
}
continue
}
r.logOnce[nameFilePath] = nil
// Remove new line character
trimmedString := strings.TrimRight(string(read), "\n")
if trimmedString == "dram" {
// There should be only one DRAM folder per socket
r.dramFolders[socketID] = raplFolder
return
}
}
}
func (r *raplServiceImpl) calculateData(socketID string, socketEnergyUjFile io.Reader, dramEnergyUjFile io.Reader,
socketMaxEnergyUjFile io.Reader, dramMaxEnergyUjFile io.Reader,
) error {
newSocketEnergy, _, err := r.readEnergyInJoules(socketEnergyUjFile)
if err != nil {
return err
}
newDramEnergy, readDate, err := r.readEnergyInJoules(dramEnergyUjFile)
if err != nil {
return err
}
interval := convertNanoSecondsToSeconds(readDate - r.data[socketID].readDate)
r.data[socketID].readDate = readDate
if interval == 0 {
return fmt.Errorf("interval between last two Telegraf cycles is 0")
}
if newSocketEnergy >= r.data[socketID].socketEnergy {
r.data[socketID].socketCurrentEnergy = (newSocketEnergy - r.data[socketID].socketEnergy) / interval
} else {
socketMaxEnergy, _, err := r.readEnergyInJoules(socketMaxEnergyUjFile)
if err != nil {
return err
}
// When socket energy_uj counter reaches maximum value defined in max_energy_range_uj file it
// starts counting from 0.
r.data[socketID].socketCurrentEnergy = (socketMaxEnergy - r.data[socketID].socketEnergy + newSocketEnergy) / interval
}
if newDramEnergy >= r.data[socketID].dramEnergy {
r.data[socketID].dramCurrentEnergy = (newDramEnergy - r.data[socketID].dramEnergy) / interval
} else {
dramMaxEnergy, _, err := r.readEnergyInJoules(dramMaxEnergyUjFile)
if err != nil {
return err
}
// When dram energy_uj counter reaches maximum value defined in max_energy_range_uj file it
// starts counting from 0.
r.data[socketID].dramCurrentEnergy = (dramMaxEnergy - r.data[socketID].dramEnergy + newDramEnergy) / interval
}
r.data[socketID].socketEnergy = newSocketEnergy
r.data[socketID].dramEnergy = newDramEnergy
return nil
}
func (r *raplServiceImpl) readEnergyInJoules(reader io.Reader) (float64, int64, error) {
currentEnergy, readDate, err := r.fs.readFileToFloat64(reader)
return convertMicroJoulesToJoules(currentEnergy), readDate, err
}
func newRaplServiceWithFs(logger telegraf.Logger, fs fileService) *raplServiceImpl {
return &raplServiceImpl{
log: logger,
data: make(map[string]*raplData),
dramFolders: make(map[string]string),
fs: fs,
}
}

View File

@ -1,83 +0,0 @@
//go:build linux
// Code generated by mockery v2.12.3. DO NOT EDIT.
package intel_powerstat
import mock "github.com/stretchr/testify/mock"
// mockRaplService is an autogenerated mock type for the mockRaplService type
type mockRaplService struct {
mock.Mock
}
// getConstraintMaxPowerWatts provides a mock function with given fields: socketID
func (_m *mockRaplService) getConstraintMaxPowerWatts(socketID string) (float64, error) {
ret := _m.Called(socketID)
var r0 float64
if rf, ok := ret.Get(0).(func(string) float64); ok {
r0 = rf(socketID)
} else {
r0 = ret.Get(0).(float64)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(socketID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// getRaplData provides a mock function with given fields:
func (_m *mockRaplService) getRaplData() map[string]*raplData {
ret := _m.Called()
var r0 map[string]*raplData
if rf, ok := ret.Get(0).(func() map[string]*raplData); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string]*raplData)
}
}
return r0
}
// initializeRaplData provides a mock function with given fields:
func (_m *mockRaplService) initializeRaplData() {
_m.Called()
}
// retrieveAndCalculateData provides a mock function with given fields: socketID
func (_m *mockRaplService) retrieveAndCalculateData(socketID string) error {
ret := _m.Called(socketID)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(socketID)
} else {
r0 = ret.Error(0)
}
return r0
}
type newmockRaplServiceT interface {
mock.TestingT
Cleanup(func())
}
// newmockRaplService creates a new instance of mockRaplService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newmockRaplService(t newmockRaplServiceT) *mockRaplService {
mock := &mockRaplService{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,115 +0,0 @@
//go:build linux
package intel_powerstat
import (
"errors"
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func TestPrepareData(t *testing.T) {
sockets := []string{"intel-rapl:0", "intel-rapl:1"}
rapl, fsMock := getRaplWithMockedFs()
fsMock.On("getStringsMatchingPatternOnPath", mock.Anything).Return(sockets, nil).Twice()
rapl.prepareData()
fsMock.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
require.Equal(t, len(sockets), len(rapl.getRaplData()))
// Verify no data is wiped in the next calls
socketEnergy := 74563813417.0
socketID := "0"
rapl.data[socketID].socketEnergy = socketEnergy
rapl.prepareData()
fsMock.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
require.Equal(t, len(sockets), len(rapl.getRaplData()))
require.Equal(t, socketEnergy, rapl.data[socketID].socketEnergy)
// Verify data is wiped once there is no RAPL folders
fsMock.On("getStringsMatchingPatternOnPath", mock.Anything).
Return(nil, errors.New("missing RAPL")).Once()
rapl.prepareData()
fsMock.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
require.Empty(t, rapl.getRaplData())
}
func TestFindDramFolders(t *testing.T) {
sockets := []string{"0", "1"}
raplFolders := []string{"intel-rapl:0:1", "intel-rapl:0:2", "intel-rapl:0:3"}
rapl, fsMock := getRaplWithMockedFs()
for _, socketID := range sockets {
rapl.data[socketID] = &raplData{}
}
firstPath := fmt.Sprintf(intelRaplDramNamePartialPath,
fmt.Sprintf(intelRaplDramPartialPath, intelRaplPath, "0", raplFolders[2]))
secondPath := fmt.Sprintf(intelRaplDramNamePartialPath,
fmt.Sprintf(intelRaplDramPartialPath, intelRaplPath, "1", raplFolders[1]))
fsMock.
On("getStringsMatchingPatternOnPath", mock.Anything).Return(raplFolders, nil).Twice().
On("readFile", firstPath).Return([]byte("dram"), nil).Once().
On("readFile", secondPath).Return([]byte("dram"), nil).Once().
On("readFile", mock.Anything).Return([]byte("random"), nil)
rapl.findDramFolders()
require.Equal(t, len(sockets), len(rapl.dramFolders))
require.Equal(t, raplFolders[2], rapl.dramFolders["0"])
require.Equal(t, raplFolders[1], rapl.dramFolders["1"])
fsMock.AssertNumberOfCalls(t, "readFile", 5)
}
func TestCalculateDataOverflowCases(t *testing.T) {
socketID := "1"
rapl, fsMock := getRaplWithMockedFs()
rapl.data[socketID] = &raplData{}
rapl.data[socketID].socketEnergy = convertMicroJoulesToJoules(23424123.1)
rapl.data[socketID].dramEnergy = convertMicroJoulesToJoules(345611233.2)
rapl.data[socketID].readDate = 54123
interval := int64(54343)
convertedInterval := convertNanoSecondsToSeconds(interval - rapl.data[socketID].readDate)
newEnergy := 3343443.4
maxEnergy := 234324546456.6
convertedNewEnergy := convertMicroJoulesToJoules(newEnergy)
convertedMaxNewEnergy := convertMicroJoulesToJoules(maxEnergy)
maxDramEnergy := 981230834098.3
newDramEnergy := 4533311.1
convertedMaxDramEnergy := convertMicroJoulesToJoules(maxDramEnergy)
convertedDramEnergy := convertMicroJoulesToJoules(newDramEnergy)
expectedCurrentEnergy := (convertedMaxNewEnergy - rapl.data[socketID].socketEnergy + convertedNewEnergy) / convertedInterval
expectedDramCurrentEnergy := (convertedMaxDramEnergy - rapl.data[socketID].dramEnergy + convertedDramEnergy) / convertedInterval
fsMock.
On("readFileToFloat64", mock.Anything).Return(newEnergy, int64(12321), nil).Once().
On("readFileToFloat64", mock.Anything).Return(newDramEnergy, interval, nil).Once().
On("readFileToFloat64", mock.Anything).Return(maxEnergy, int64(64534), nil).Once().
On("readFileToFloat64", mock.Anything).Return(maxDramEnergy, int64(98342), nil).Once()
require.NoError(t, rapl.calculateData(socketID, strings.NewReader(mock.Anything), strings.NewReader(mock.Anything),
strings.NewReader(mock.Anything), strings.NewReader(mock.Anything)))
require.Equal(t, expectedCurrentEnergy, rapl.data[socketID].socketCurrentEnergy)
require.Equal(t, expectedDramCurrentEnergy, rapl.data[socketID].dramCurrentEnergy)
}
func getRaplWithMockedFs() (*raplServiceImpl, *mockFileService) {
logger := testutil.Logger{Name: "PowerPluginTest"}
fsMock := &mockFileService{}
rapl := newRaplServiceWithFs(logger, fsMock)
return rapl, fsMock
}

View File

@ -1,15 +1,15 @@
# Intel PowerStat plugin enables monitoring of platform metrics (power, TDP)
# and per-CPU metrics like temperature, power and utilization. Please see the
# plugin readme for details on software and hardware compatability.
# This plugin ONLY supports Linux
# This plugin ONLY supports Linux.
[[inputs.intel_powerstat]]
## The user can choose which package metrics are monitored by the plugin with
## the package_metrics setting:
## - The default, will collect "current_power_consumption",
## "current_dram_power_consumption" and "thermal_design_power"
## - Leaving this setting empty means no package metrics will be collected
## "current_dram_power_consumption" and "thermal_design_power".
## - Leaving this setting empty means no package metrics will be collected.
## - Finally, a user can specify individual metrics to capture from the
## supported options list
## supported options list.
## Supported options:
## "current_power_consumption", "current_dram_power_consumption",
## "thermal_design_power", "max_turbo_frequency", "uncore_frequency",
@ -22,7 +22,29 @@
## by the plugin.
## Supported options:
## "cpu_frequency", "cpu_c0_state_residency", "cpu_c1_state_residency",
## "cpu_c6_state_residency", "cpu_busy_cycles", "cpu_temperature",
## "cpu_busy_frequency"
## ATTENTION: cpu_busy_cycles is DEPRECATED - use cpu_c0_state_residency
## "cpu_c3_state_residency", "cpu_c6_state_residency", "cpu_c7_state_residency",
## "cpu_temperature", "cpu_busy_frequency", "cpu_c0_substate_c01",
## "cpu_c0_substate_c02", "cpu_c0_substate_c0_wait"
# cpu_metrics = []
## Optionally the user can choose for which CPUs metrics configured in cpu_metrics array should be gathered.
## Can't be combined with excluded_cpus.
## Empty or missing array means CPU metrics are gathered for all CPUs.
## e.g. ["0-3", "4,5,6"] or ["1-3,4"]
# included_cpus = []
## Optionally the user can choose which CPUs should be excluded from gathering metrics configured in cpu_metrics array.
## Can't be combined with included_cpus.
## Empty or missing array means CPU metrics are gathered for all CPUs.
## e.g. ["0-3", "4,5,6"] or ["1-3,4"]
# excluded_cpus = []
## Filesystem location of JSON file that contains PMU event definitions.
## Mandatory only for perf-related metrics (cpu_c0_substate_c01, cpu_c0_substate_c02, cpu_c0_substate_c0_wait).
# event_definitions = ""
## The user can set the timeout duration for MSR reading.
## Enabling this timeout can be useful in situations where, on heavily loaded systems,
## the code waits too long for a kernel response to MSR read requests.
## 0 disables the timeout (default).
# msr_read_timeout = "0ms"

View File

@ -0,0 +1,27 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,26 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,111 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 1
cpu cores : 56
apicid : 2
initial apicid : 2
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:
processor : 2
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 2
cpu cores : 56
apicid : 4
initial apicid : 4
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:
processor : 3
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 3
cpu cores : 56
apicid : 6
initial apicid : 6
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,27 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,27 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 14
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,27 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 143
model name : Intel(R) Xeon(R) Platinum 8480+
stepping : 8
microcode : 0xab0000c0
cpu MHz : 2000.000
cache size : 107520 KB
physical id : 0
siblings : 112
core id : 0
cpu cores : 56
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 32
wp : yes
flags : fpu vme de pse tsc pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb
bogomips : 4000.00
clflush size : 64
cache_alignment : 64
address sizes : 52 bits physical, 57 bits virtual
power management:

View File

@ -0,0 +1,299 @@
{
"Header": {
"Copyright": "Copyright (c) 2001 - 2023 Intel Corporation. All rights reserved.",
"Info": "Performance Monitoring Events for 4th Generation Intel(R) Xeon(R) Processor Scalable Family based on Sapphire Rapids microarchitecture - V1.15",
"DatePublished": "06/28/2023",
"Version": "1.15",
"Legend": ""
},
"Events": [
{
"EventCode": "0x00",
"UMask": "0x02",
"EventName": "CPU_CLK_UNHALTED.THREAD",
"BriefDescription": "Core cycles when the thread is not in halt state",
"PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events.",
"Counter": "Fixed counter 1",
"PEBScounters": "33",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0x00",
"UMask": "0x03",
"EventName": "CPU_CLK_UNHALTED.REF_TSC",
"BriefDescription": "Reference cycles when the core is not in halt state.",
"PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.",
"Counter": "Fixed counter 2",
"PEBScounters": "34",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0x3c",
"UMask": "0x00",
"EventName": "CPU_CLK_UNHALTED.THREAD_P",
"BriefDescription": "Thread cycles when thread is not in halt state",
"PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0x3c",
"UMask": "0x01",
"EventName": "CPU_CLK_UNHALTED.REF_TSC_P",
"BriefDescription": "Reference cycles when the core is not in halt state.",
"PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0x3c",
"UMask": "0x02",
"EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE",
"BriefDescription": "Core crystal clock cycles when this thread is unhalted and the other thread is halted.",
"PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "25003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0x3c",
"UMask": "0x08",
"EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED",
"BriefDescription": "Core crystal clock cycles. Cycle counts are evenly distributed between active threads in the Core.",
"PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x02",
"EventName": "CPU_CLK_UNHALTED.DISTRIBUTED",
"BriefDescription": "Cycle counts are evenly distributed between active threads in the Core.",
"PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x10",
"EventName": "CPU_CLK_UNHALTED.C01",
"BriefDescription": "Core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.",
"PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x20",
"EventName": "CPU_CLK_UNHALTED.C02",
"BriefDescription": "Core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.",
"PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x40",
"EventName": "CPU_CLK_UNHALTED.PAUSE",
"BriefDescription": "CPU_CLK_UNHALTED.PAUSE",
"PublicDescription": "CPU_CLK_UNHALTED.PAUSE",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x40",
"EventName": "CPU_CLK_UNHALTED.PAUSE_INST",
"BriefDescription": "CPU_CLK_UNHALTED.PAUSE_INST",
"PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "1",
"Invert": "0",
"EdgeDetect": "1",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
},
{
"EventCode": "0xec",
"UMask": "0x70",
"EventName": "CPU_CLK_UNHALTED.C0_WAIT",
"BriefDescription": "Core clocks when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.",
"PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.",
"Counter": "0,1,2,3,4,5,6,7",
"PEBScounters": "0,1,2,3,4,5,6,7",
"SampleAfterValue": "2000003",
"MSRIndex": "0x00",
"MSRValue": "0x00",
"CollectPEBSRecord": "2",
"TakenAlone": "0",
"CounterMask": "0",
"Invert": "0",
"EdgeDetect": "0",
"PEBS": "0",
"Data_LA": "0",
"L1_Hit_Indication": "0",
"Errata": "null",
"Offcore": "0",
"Deprecated": "0",
"Speculative": "1"
}
]
}

View File

@ -1,49 +0,0 @@
//go:build linux
package intel_powerstat
import (
"math"
"strconv"
)
const (
microJouleToJoule = 1.0 / 1000000
microWattToWatt = 1.0 / 1000000
kiloHertzToMegaHertz = 1.0 / 1000
nanoSecondsToSeconds = 1.0 / 1000000000
cyclesToHertz = 1.0 / 1000000
)
func convertMicroJoulesToJoules(mJ float64) float64 {
return mJ * microJouleToJoule
}
func convertMicroWattToWatt(mW float64) float64 {
return mW * microWattToWatt
}
func convertKiloHertzToMegaHertz(kiloHertz float64) float64 {
return kiloHertz * kiloHertzToMegaHertz
}
func convertNanoSecondsToSeconds(ns int64) float64 {
return float64(ns) * nanoSecondsToSeconds
}
func convertProcessorCyclesToHertz(pc uint64) float64 {
return float64(pc) * cyclesToHertz
}
func roundFloatToNearestTwoDecimalPlaces(n float64) float64 {
return math.Round(n*100) / 100
}
func convertIntegerArrayToStringArray(array []int64) []string {
stringArray := make([]string, 0)
for _, value := range array {
stringArray = append(stringArray, strconv.FormatInt(value, 10))
}
return stringArray
}