//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 (*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 }