telegraf/plugins/inputs/intel_powerstat/intel_powerstat_test.go

852 lines
29 KiB
Go
Raw Normal View History

//go:build linux
package intel_powerstat
import (
"errors"
"strconv"
"sync"
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil"
)
type MockServices struct {
fs *mockFileService
msr *mockMsrService
rapl *mockRaplService
}
func TestInitPlugin(t *testing.T) {
cores := []string{"cpu0", "cpu1", "cpu2", "cpu3"}
power, mockServices := getPowerWithMockedServices()
mockServices.fs.On("getCPUInfoStats", mock.Anything).
Return(nil, errors.New("error getting cpu stats")).Once()
require.Error(t, power.Init())
mockServices.fs.On("getCPUInfoStats", mock.Anything).
Return(make(map[string]*cpuInfo), nil).Once()
require.Error(t, power.Init())
mockServices.fs.On("getCPUInfoStats", mock.Anything).
Return(map[string]*cpuInfo{"0": {
vendorID: "GenuineIntel",
cpuFamily: "test",
}}, nil).Once()
require.Error(t, power.Init())
mockServices.fs.On("getStringsMatchingPatternOnPath", mock.Anything).
Return(cores, nil).Once().
On("getCPUInfoStats", mock.Anything).
Return(map[string]*cpuInfo{"0": {
vendorID: "GenuineIntel",
cpuFamily: "6",
}}, nil)
// Verify MSR service initialization.
power.cpuFrequency = true
require.NoError(t, power.Init())
mockServices.fs.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
require.Equal(t, len(cores), len(power.msr.getCPUCoresData()))
mockServices.fs.On("getStringsMatchingPatternOnPath", mock.Anything).
Return(nil, errors.New("error during getStringsMatchingPatternOnPath")).Once()
// In case of an error when fetching cpu cores plugin should proceed with execution.
require.NoError(t, power.Init())
mockServices.fs.AssertCalled(t, "getStringsMatchingPatternOnPath", mock.Anything)
require.Empty(t, power.msr.getCPUCoresData())
}
func TestParseCPUMetricsConfig(t *testing.T) {
power, _ := getPowerWithMockedServices()
disableCoreMetrics(power)
power.CPUMetrics = []string{
"cpu_frequency", "cpu_c0_state_residency", "cpu_c1_state_residency", "cpu_c6_state_residency", "cpu_busy_cycles", "cpu_temperature",
"cpu_busy_frequency",
}
power.parseCPUMetricsConfig()
verifyCoreMetrics(t, power, true)
disableCoreMetrics(power)
verifyCoreMetrics(t, power, false)
power.CPUMetrics = []string{}
power.parseCPUMetricsConfig()
power.CPUMetrics = []string{"cpu_c6_state_residency", "#@$sdkjdfsdf3@", "1pu_c1_state_residency"}
power.parseCPUMetricsConfig()
require.False(t, power.cpuC1StateResidency)
require.True(t, power.cpuC6StateResidency)
disableCoreMetrics(power)
verifyCoreMetrics(t, power, false)
power.CPUMetrics = []string{"#@$sdkjdfsdf3@", "1pu_c1_state_residency", "123"}
power.parseCPUMetricsConfig()
verifyCoreMetrics(t, power, false)
}
func verifyCoreMetrics(t *testing.T, power *PowerStat, enabled bool) {
require.Equal(t, enabled, power.cpuFrequency)
require.Equal(t, enabled, power.cpuC1StateResidency)
require.Equal(t, enabled, power.cpuC6StateResidency)
require.Equal(t, enabled, power.cpuC0StateResidency)
require.Equal(t, enabled, power.cpuBusyCycles)
require.Equal(t, enabled, power.cpuBusyFrequency)
require.Equal(t, enabled, power.cpuTemperature)
}
func TestGather(t *testing.T) {
var acc testutil.Accumulator
packageIDs := []string{"0", "1"}
coreIDs := []string{"0", "1", "2", "3"}
socketCurrentEnergy := 13213852.2
dramCurrentEnergy := 784552.0
preparedCPUData := getPreparedCPUData(coreIDs)
raplDataMap := prepareRaplDataMap(packageIDs, socketCurrentEnergy, dramCurrentEnergy)
power, mockServices := getPowerWithMockedServices()
prepareCPUInfo(power, coreIDs, packageIDs)
enableCoreMetrics(power)
power.skipFirstIteration = false
mockServices.rapl.On("initializeRaplData", mock.Anything).
On("getRaplData").Return(raplDataMap).
On("retrieveAndCalculateData", mock.Anything).Return(nil).Times(len(raplDataMap)).
On("getConstraintMaxPowerWatts", mock.Anything).Return(546783852.3, nil)
mockServices.msr.On("getCPUCoresData").Return(preparedCPUData).
On("isMsrLoaded", mock.Anything).Return(true).
On("openAndReadMsr", mock.Anything).Return(nil).
On("retrieveCPUFrequencyForCore", mock.Anything).Return(1200000.2, nil)
require.NoError(t, power.Gather(&acc))
// Number of global metrics : 3
// Number of per core metrics : 7
require.Len(t, acc.GetTelegrafMetrics(), 3*len(packageIDs)+7*len(coreIDs))
}
func TestAddGlobalMetricsNegative(t *testing.T) {
var acc testutil.Accumulator
socketCurrentEnergy := 13213852.2
dramCurrentEnergy := 784552.0
raplDataMap := prepareRaplDataMap([]string{"0", "1"}, socketCurrentEnergy, dramCurrentEnergy)
power, mockServices := getPowerWithMockedServices()
power.skipFirstIteration = false
mockServices.rapl.On("initializeRaplData", mock.Anything).Once().
On("getRaplData").Return(raplDataMap).Once().
On("retrieveAndCalculateData", mock.Anything).Return(errors.New("error while calculating data")).Times(len(raplDataMap))
power.addGlobalMetrics(&acc)
require.Empty(t, acc.GetTelegrafMetrics())
mockServices.rapl.AssertNumberOfCalls(t, "retrieveAndCalculateData", len(raplDataMap))
mockServices.rapl.On("initializeRaplData", mock.Anything).Once().
On("getRaplData").Return(make(map[string]*raplData)).Once()
power.addGlobalMetrics(&acc)
require.Empty(t, acc.GetTelegrafMetrics())
mockServices.rapl.AssertNotCalled(t, "retrieveAndCalculateData")
mockServices.rapl.On("initializeRaplData", mock.Anything).Once().
On("getRaplData").Return(raplDataMap).
On("retrieveAndCalculateData", mock.Anything).Return(nil).Once().
On("retrieveAndCalculateData", mock.Anything).Return(errors.New("error while calculating data")).Once().
On("getConstraintMaxPowerWatts", mock.Anything).Return(12313851.5, nil).Twice()
power.addGlobalMetrics(&acc)
require.Len(t, acc.GetTelegrafMetrics(), 3)
}
func TestAddGlobalMetricsPositive(t *testing.T) {
var acc testutil.Accumulator
socketCurrentEnergy := 3644574.4
dramCurrentEnergy := 124234872.5
raplDataMap := prepareRaplDataMap([]string{"0", "1"}, socketCurrentEnergy, dramCurrentEnergy)
maxPower := 546783852.9
power, mockServices := getPowerWithMockedServices()
power.skipFirstIteration = false
mockServices.rapl.On("initializeRaplData", mock.Anything).
On("getRaplData").Return(raplDataMap).
On("retrieveAndCalculateData", mock.Anything).Return(nil).Times(len(raplDataMap)).
On("getConstraintMaxPowerWatts", mock.Anything).Return(maxPower, nil).Twice().
On("getCurrentDramPowerConsumption", mock.Anything).Return(dramCurrentEnergy)
power.addGlobalMetrics(&acc)
require.Len(t, acc.GetTelegrafMetrics(), 6)
expectedResults := getGlobalMetrics(maxPower, socketCurrentEnergy, dramCurrentEnergy)
for _, test := range expectedResults {
acc.AssertContainsTaggedFields(t, "powerstat_package", test.fields, test.tags)
}
}
func TestAddMetricsForSingleCoreNegative(t *testing.T) {
var wg sync.WaitGroup
var acc testutil.Accumulator
core := "0"
power, mockServices := getPowerWithMockedServices()
mockServices.msr.On("openAndReadMsr", core).Return(errors.New("error reading MSR file")).Once()
// Skip generating metric for CPU frequency.
power.cpuFrequency = false
wg.Add(1)
power.addMetricsForSingleCore(core, &acc, &wg)
wg.Wait()
require.Empty(t, acc.GetTelegrafMetrics())
}
func TestAddCPUFrequencyMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "1"
coreID := "3"
packageID := "0"
frequency := 1200000.2
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
mockServices.msr.On("retrieveCPUFrequencyForCore", mock.Anything).
Return(float64(0), errors.New("error on reading file")).Once()
power.addCPUFrequencyMetric(cpuID, &acc)
require.Empty(t, acc.GetTelegrafMetrics())
mockServices.msr.On("retrieveCPUFrequencyForCore", mock.Anything).Return(frequency, nil).Once()
power.addCPUFrequencyMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
expectedFrequency := roundFloatToNearestTwoDecimalPlaces(frequency)
expectedMetric := getPowerCoreMetric("cpu_frequency_mhz", expectedFrequency, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
}
func TestReadUncoreFreq(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "0"
packageID := "0"
die := "0"
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
preparedData := getPreparedCPUData([]string{cpuID})
mockServices.msr.On("getCPUCoresData").Return(preparedData)
mockServices.msr.On("isMsrLoaded").Return(true)
mockServices.msr.On("readSingleMsr", "0", msrUncorePerfStatusString).Return(uint64(10), nil)
mockServices.msr.On("retrieveUncoreFrequency", "0", "initial", "min", "0").
Return(float64(500), nil)
mockServices.msr.On("retrieveUncoreFrequency", "0", "initial", "max", "0").
Return(float64(1200), nil)
mockServices.msr.On("retrieveUncoreFrequency", "0", "current", "min", "0").
Return(float64(600), nil)
mockServices.msr.On("retrieveUncoreFrequency", "0", "current", "max", "0").
Return(float64(1100), nil)
power.readUncoreFreq("current", packageID, die, &acc)
power.readUncoreFreq("initial", packageID, die, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 2)
expectedMetric := getPowerUncoreFreqMetric("initial", float64(500), float64(1200), nil, packageID, die)
acc.AssertContainsTaggedFields(t, "powerstat_package", expectedMetric.fields, expectedMetric.tags)
expectedMetric = getPowerUncoreFreqMetric("current", float64(600), float64(1100), uint64(1000), packageID, die)
acc.AssertContainsTaggedFields(t, "powerstat_package", expectedMetric.fields, expectedMetric.tags)
}
func TestAddCoreCPUTemperatureMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "2"
packageID := "1"
power, mockServices := getPowerWithMockedServices()
preparedData := getPreparedCPUData([]string{cpuID})
expectedTemp := preparedData[cpuID].throttleTemp - preparedData[cpuID].temp
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
mockServices.msr.On("getCPUCoresData").Return(preparedData).Once()
power.addCPUTemperatureMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
expectedMetric := getPowerCoreMetric("cpu_temperature_celsius", expectedTemp, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
}
func TestAddC6StateResidencyMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "2"
packageID := "1"
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
preparedData := getPreparedCPUData([]string{cpuID})
expectedC6 := roundFloatToNearestTwoDecimalPlaces(percentageMultiplier *
float64(preparedData[cpuID].c6Delta) / float64(preparedData[cpuID].timeStampCounterDelta))
mockServices.msr.On("getCPUCoresData").Return(preparedData).Twice()
power.addCPUC6StateResidencyMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
expectedMetric := getPowerCoreMetric("cpu_c6_state_residency_percent", expectedC6, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
acc.ClearMetrics()
preparedData[cpuID].timeStampCounterDelta = 0
power.addCPUC6StateResidencyMetric(cpuID, &acc)
require.Empty(t, acc.GetTelegrafMetrics())
}
func TestAddC0StateResidencyMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "2"
packageID := "1"
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
preparedData := getPreparedCPUData([]string{cpuID})
expectedBusyCycles := roundFloatToNearestTwoDecimalPlaces(percentageMultiplier * float64(preparedData[cpuID].mperfDelta) /
float64(preparedData[cpuID].timeStampCounterDelta))
mockServices.msr.On("getCPUCoresData").Return(preparedData).Twice()
power.cpuBusyCycles, power.cpuC0StateResidency = true, true
power.addCPUC0StateResidencyMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 2)
expectedMetric := getPowerCoreMetric("cpu_c0_state_residency_percent", expectedBusyCycles, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
// Deprecated
expectedMetric = getPowerCoreMetric("cpu_busy_cycles_percent", expectedBusyCycles, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
acc.ClearMetrics()
preparedData[cpuID].timeStampCounterDelta = 0
power.addCPUC0StateResidencyMetric(cpuID, &acc)
require.Empty(t, acc.GetTelegrafMetrics())
}
func TestAddProcessorBusyFrequencyMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "2"
packageID := "1"
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
preparedData := getPreparedCPUData([]string{cpuID})
power.skipFirstIteration = false
mockServices.msr.On("getCPUCoresData").Return(preparedData).Twice()
power.addCPUBusyFrequencyMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
acc.ClearMetrics()
preparedData[cpuID].mperfDelta = 0
power.addCPUBusyFrequencyMetric(cpuID, &acc)
require.Empty(t, acc.GetTelegrafMetrics())
}
func TestAddC1StateResidencyMetric(t *testing.T) {
var acc testutil.Accumulator
cpuID := "0"
coreID := "2"
packageID := "1"
power, mockServices := getPowerWithMockedServices()
prepareCPUInfoForSingleCPU(power, cpuID, coreID, packageID)
preparedData := getPreparedCPUData([]string{cpuID})
c1 := preparedData[cpuID].timeStampCounterDelta - preparedData[cpuID].mperfDelta - preparedData[cpuID].c3Delta -
preparedData[cpuID].c6Delta - preparedData[cpuID].c7Delta
expectedC1 := roundFloatToNearestTwoDecimalPlaces(percentageMultiplier * float64(c1) / float64(preparedData[cpuID].timeStampCounterDelta))
mockServices.msr.On("getCPUCoresData").Return(preparedData).Twice()
power.addCPUC1StateResidencyMetric(cpuID, &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
expectedMetric := getPowerCoreMetric("cpu_c1_state_residency_percent", expectedC1, coreID, packageID, cpuID)
acc.AssertContainsTaggedFields(t, "powerstat_core", expectedMetric.fields, expectedMetric.tags)
acc.ClearMetrics()
preparedData[cpuID].timeStampCounterDelta = 0
power.addCPUC1StateResidencyMetric(cpuID, &acc)
require.Empty(t, acc.GetTelegrafMetrics())
}
func TestAddThermalDesignPowerMetric(t *testing.T) {
var acc testutil.Accumulator
sockets := []string{"0"}
maxPower := 195720672.1
power, mockServices := getPowerWithMockedServices()
mockServices.rapl.On("getConstraintMaxPowerWatts", mock.Anything).
Return(float64(0), errors.New("getConstraintMaxPowerWatts error")).Once().
On("getConstraintMaxPowerWatts", mock.Anything).Return(maxPower, nil).Once()
power.addThermalDesignPowerMetric(sockets[0], &acc)
require.Empty(t, acc.GetTelegrafMetrics())
power.addThermalDesignPowerMetric(sockets[0], &acc)
require.Len(t, acc.GetTelegrafMetrics(), 1)
expectedTDP := roundFloatToNearestTwoDecimalPlaces(maxPower)
expectedMetric := getPowerGlobalMetric("thermal_design_power_watts", expectedTDP, sockets[0])
acc.AssertContainsTaggedFields(t, "powerstat_package", expectedMetric.fields, expectedMetric.tags)
}
func TestCalculateTurboRatioGroup(t *testing.T) {
coreCounts := uint64(0x0807060504030201)
msr := uint64(0x0807060504030201)
turboRatioLimitGroups := make(map[int]uint64)
calculateTurboRatioGroup(coreCounts, msr, turboRatioLimitGroups)
require.Len(t, turboRatioLimitGroups, 8)
require.Equal(t, uint64(100), turboRatioLimitGroups[1])
require.Equal(t, uint64(200), turboRatioLimitGroups[2])
require.Equal(t, uint64(300), turboRatioLimitGroups[3])
require.Equal(t, uint64(400), turboRatioLimitGroups[4])
require.Equal(t, uint64(500), turboRatioLimitGroups[5])
require.Equal(t, uint64(600), turboRatioLimitGroups[6])
require.Equal(t, uint64(700), turboRatioLimitGroups[7])
require.Equal(t, uint64(800), turboRatioLimitGroups[8])
coreCounts = uint64(0x100e0c0a08060402)
calculateTurboRatioGroup(coreCounts, msr, turboRatioLimitGroups)
require.Len(t, turboRatioLimitGroups, 16)
require.Equal(t, uint64(100), turboRatioLimitGroups[1])
require.Equal(t, uint64(100), turboRatioLimitGroups[2])
require.Equal(t, uint64(200), turboRatioLimitGroups[3])
require.Equal(t, uint64(200), turboRatioLimitGroups[4])
require.Equal(t, uint64(300), turboRatioLimitGroups[5])
require.Equal(t, uint64(300), turboRatioLimitGroups[6])
require.Equal(t, uint64(400), turboRatioLimitGroups[7])
require.Equal(t, uint64(400), turboRatioLimitGroups[8])
require.Equal(t, uint64(500), turboRatioLimitGroups[9])
require.Equal(t, uint64(500), turboRatioLimitGroups[10])
require.Equal(t, uint64(600), turboRatioLimitGroups[11])
require.Equal(t, uint64(600), turboRatioLimitGroups[12])
require.Equal(t, uint64(700), turboRatioLimitGroups[13])
require.Equal(t, uint64(700), turboRatioLimitGroups[14])
require.Equal(t, uint64(800), turboRatioLimitGroups[15])
require.Equal(t, uint64(800), turboRatioLimitGroups[16])
coreCounts = uint64(0x1211)
msr = uint64(0xfffe)
calculateTurboRatioGroup(coreCounts, msr, turboRatioLimitGroups)
require.Len(t, turboRatioLimitGroups, 18)
require.Equal(t, uint64(25400), turboRatioLimitGroups[17])
require.Equal(t, uint64(25500), turboRatioLimitGroups[18])
coreCounts = uint64(0x1201)
msr = uint64(0x0202)
calculateTurboRatioGroup(coreCounts, msr, turboRatioLimitGroups)
require.Len(t, turboRatioLimitGroups, 18)
require.Equal(t, uint64(200), turboRatioLimitGroups[1])
require.Equal(t, uint64(200), turboRatioLimitGroups[2])
require.Equal(t, uint64(200), turboRatioLimitGroups[3])
require.Equal(t, uint64(200), turboRatioLimitGroups[4])
require.Equal(t, uint64(200), turboRatioLimitGroups[5])
require.Equal(t, uint64(200), turboRatioLimitGroups[6])
require.Equal(t, uint64(200), turboRatioLimitGroups[7])
require.Equal(t, uint64(200), turboRatioLimitGroups[8])
require.Equal(t, uint64(200), turboRatioLimitGroups[9])
require.Equal(t, uint64(200), turboRatioLimitGroups[10])
require.Equal(t, uint64(200), turboRatioLimitGroups[11])
require.Equal(t, uint64(200), turboRatioLimitGroups[12])
require.Equal(t, uint64(200), turboRatioLimitGroups[13])
require.Equal(t, uint64(200), turboRatioLimitGroups[14])
require.Equal(t, uint64(200), turboRatioLimitGroups[15])
require.Equal(t, uint64(200), turboRatioLimitGroups[16])
require.Equal(t, uint64(200), turboRatioLimitGroups[17])
require.Equal(t, uint64(200), turboRatioLimitGroups[18])
coreCounts = uint64(0x1211)
msr = uint64(0xfffe)
turboRatioLimitGroups = make(map[int]uint64)
calculateTurboRatioGroup(coreCounts, msr, turboRatioLimitGroups)
require.Len(t, turboRatioLimitGroups, 2)
require.Equal(t, uint64(25400), turboRatioLimitGroups[17])
require.Equal(t, uint64(25500), turboRatioLimitGroups[18])
}
func getPreparedCPUData(cores []string) map[string]*msrData {
msrDataMap := make(map[string]*msrData)
for _, core := range cores {
msrDataMap[core] = &msrData{
mperf: 43079,
aperf: 82001,
timeStampCounter: 15514,
c3: 52829,
c6: 86930,
c7: 25340,
throttleTemp: 88150,
temp: 40827,
mperfDelta: 23515,
aperfDelta: 33866,
timeStampCounterDelta: 13686000,
c3Delta: 20003,
c6Delta: 44518,
c7Delta: 20979,
}
}
return msrDataMap
}
func getGlobalMetrics(maxPower float64, socketCurrentEnergy float64, dramCurrentEnergy float64) []struct {
fields map[string]interface{}
tags map[string]string
} {
return []struct {
fields map[string]interface{}
tags map[string]string
}{
getPowerGlobalMetric("thermal_design_power_watts", roundFloatToNearestTwoDecimalPlaces(maxPower), "0"),
getPowerGlobalMetric("thermal_design_power_watts", roundFloatToNearestTwoDecimalPlaces(maxPower), "1"),
getPowerGlobalMetric("current_power_consumption_watts", roundFloatToNearestTwoDecimalPlaces(socketCurrentEnergy), "0"),
getPowerGlobalMetric("current_power_consumption_watts", roundFloatToNearestTwoDecimalPlaces(socketCurrentEnergy), "1"),
getPowerGlobalMetric("current_dram_power_consumption_watts", roundFloatToNearestTwoDecimalPlaces(dramCurrentEnergy), "0"),
getPowerGlobalMetric("current_dram_power_consumption_watts", roundFloatToNearestTwoDecimalPlaces(dramCurrentEnergy), "1"),
}
}
func getPowerCoreMetric(name string, value interface{}, coreID string, packageID string, cpuID string) struct {
fields map[string]interface{}
tags map[string]string
} {
return getPowerMetric(name, value, map[string]string{"package_id": packageID, "core_id": coreID, "cpu_id": cpuID})
}
func getPowerGlobalMetric(name string, value interface{}, socketID string) struct {
fields map[string]interface{}
tags map[string]string
} {
return getPowerMetric(name, value, map[string]string{"package_id": socketID})
}
func getPowerUncoreFreqMetric(typeFreq string, limitMin interface{}, limitMax interface{}, current interface{}, socketID string, die string) struct {
fields map[string]interface{}
tags map[string]string
} {
var ret struct {
fields map[string]interface{}
tags map[string]string
}
ret.tags = make(map[string]string)
ret.fields = make(map[string]interface{})
ret.tags["package_id"] = socketID
ret.tags["die"] = die
ret.tags["type"] = typeFreq
ret.fields["uncore_frequency_limit_mhz_min"] = limitMin
ret.fields["uncore_frequency_limit_mhz_max"] = limitMax
if typeFreq == "current" {
ret.fields["uncore_frequency_mhz_cur"] = current
}
return ret
}
func getPowerMetric(name string, value interface{}, tags map[string]string) struct {
fields map[string]interface{}
tags map[string]string
} {
return struct {
fields map[string]interface{}
tags map[string]string
}{
map[string]interface{}{
name: value,
},
tags,
}
}
func prepareCPUInfoForSingleCPU(power *PowerStat, cpuID string, coreID string, packageID string) {
power.cpuInfo = make(map[string]*cpuInfo)
power.cpuInfo[cpuID] = &cpuInfo{
physicalID: packageID,
coreID: coreID,
cpuID: cpuID,
}
}
func prepareCPUInfo(power *PowerStat, coreIDs []string, packageIDs []string) {
power.cpuInfo = make(map[string]*cpuInfo)
currentCPU := 0
for _, packageID := range packageIDs {
for _, coreID := range coreIDs {
cpuID := strconv.Itoa(currentCPU)
power.cpuInfo[cpuID] = &cpuInfo{
physicalID: packageID,
cpuID: cpuID,
coreID: coreID,
}
currentCPU++
}
}
}
func enableCoreMetrics(power *PowerStat) {
power.cpuC0StateResidency = true
power.cpuC1StateResidency = true
power.cpuC6StateResidency = true
power.cpuTemperature = true
power.cpuBusyFrequency = true
power.cpuFrequency = true
power.cpuBusyCycles = true
}
func disableCoreMetrics(power *PowerStat) {
power.cpuC0StateResidency = false
power.cpuC1StateResidency = false
power.cpuC6StateResidency = false
power.cpuBusyCycles = false
power.cpuTemperature = false
power.cpuBusyFrequency = false
power.cpuFrequency = false
}
func prepareRaplDataMap(socketIDs []string, socketCurrentEnergy float64, dramCurrentEnergy float64) map[string]*raplData {
raplDataMap := make(map[string]*raplData, len(socketIDs))
for _, socketID := range socketIDs {
raplDataMap[socketID] = &raplData{
socketCurrentEnergy: socketCurrentEnergy,
dramCurrentEnergy: dramCurrentEnergy,
}
}
return raplDataMap
}
func getPowerWithMockedServices() (*PowerStat, *MockServices) {
var mockServices MockServices
mockServices.fs = &mockFileService{}
mockServices.msr = &mockMsrService{}
mockServices.rapl = &mockRaplService{}
p := newPowerStat(mockServices.fs)
p.Log = testutil.Logger{Name: "PowerPluginTest"}
p.rapl = mockServices.rapl
p.msr = mockServices.msr
p.packageCurrentPowerConsumption = true
p.packageCurrentDramPowerConsumption = true
p.packageThermalDesignPower = true
return p, &mockServices
}
func TestGetBusClock(t *testing.T) {
tests := []struct {
name string
modelCPU uint64
socketID string
msrFSBFreqValue uint64
readSingleMsrErrFSB error
cpuBusClockValue float64
}{
{
name: "Error_withUnknownCPUmodel",
socketID: "0",
modelCPU: 0xFF,
cpuBusClockValue: 0,
},
{
name: "OK_withFBS100",
socketID: "0",
modelCPU: 106,
msrFSBFreqValue: 1,
cpuBusClockValue: 100.0,
},
{
name: "OK_withFBS133",
socketID: "0",
modelCPU: 0x1F,
cpuBusClockValue: 133,
},
{
name: "Error_withFBSCalculated",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 0,
readSingleMsrErrFSB: errors.New("something is wrong"),
},
{
name: "OK_withFBSCalculated83.3",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 0,
cpuBusClockValue: 83.3,
},
{
name: "OK_withFBSCalculated100",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 1,
cpuBusClockValue: 100,
},
{
name: "OK_withFBSCalculated133.3",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 2,
cpuBusClockValue: 133.3,
},
{
name: "OK_withFBSCalculated116.7",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 3,
cpuBusClockValue: 116.7,
},
{
name: "OK_withFBSCalculated80",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 4,
cpuBusClockValue: 80,
},
{
name: "OK_withFBSCalculatedUnknownFSBFreq",
socketID: "0",
modelCPU: 0x37,
msrFSBFreqValue: 5,
cpuBusClockValue: 116.7,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p, mockServices := getPowerWithMockedServices()
busClockCalculate := []uint64{0x37, 0x4D}
p.cpuInfo = map[string]*cpuInfo{
tt.socketID: {cpuID: tt.socketID, physicalID: tt.socketID, model: strconv.FormatUint(tt.modelCPU, 10)},
}
if contains(busClockCalculate, tt.modelCPU) {
mockServices.msr.On("readSingleMsr", mock.Anything, msrFSBFreqString).Return(tt.msrFSBFreqValue, tt.readSingleMsrErrFSB)
}
defer mockServices.msr.AssertExpectations(t)
value := p.getBusClock(tt.socketID)
require.Equal(t, tt.cpuBusClockValue, value)
})
}
}
func TestFillCPUBusClock(t *testing.T) {
tests := []struct {
name string
modelCPU uint64
busClockValue float64
packageCPUBaseFrequencySet bool
}{
{
name: "NotSet_0",
modelCPU: 0xFF,
busClockValue: 0,
},
{
name: "Set_100",
modelCPU: 0x2A,
busClockValue: 100,
packageCPUBaseFrequencySet: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p, _ := getPowerWithMockedServices()
p.packageCPUBaseFrequency = true
p.cpuInfo = map[string]*cpuInfo{
"0": {cpuID: "0", physicalID: "0", model: strconv.FormatUint(tt.modelCPU, 10)},
}
p.fillCPUBusClock()
require.Equal(t, tt.busClockValue, p.cpuBusClockValue)
require.Equal(t, tt.packageCPUBaseFrequencySet, p.packageCPUBaseFrequency)
})
}
}
func TestAddCPUBaseFreq(t *testing.T) {
tests := []struct {
name string
socketID string
readSingleMsrErrRatio error
msrPlatformInfoValue uint64
setupPowerstat func(t *testing.T)
clockBusValue float64
nonTurboRatio float64
metricExpected bool
}{
{
name: "Error_reading_msr",
socketID: "0",
clockBusValue: 100,
readSingleMsrErrRatio: errors.New("can't read msr"),
metricExpected: false,
},
{
name: "NoMetric_Ratio_is_0",
socketID: "0",
msrPlatformInfoValue: 0x8008082FF2810000,
clockBusValue: 100,
nonTurboRatio: 0,
metricExpected: false,
},
{
name: "OK_Ratio_is_24",
socketID: "0",
msrPlatformInfoValue: 0x8008082FF2811800,
clockBusValue: 100,
nonTurboRatio: 24,
metricExpected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator
p, mockServices := getPowerWithMockedServices()
p.cpuInfo = map[string]*cpuInfo{
tt.socketID: {cpuID: tt.socketID, physicalID: tt.socketID},
}
p.cpuBusClockValue = tt.clockBusValue
mockServices.msr.On("readSingleMsr", mock.Anything, msrPlatformInfoString).Return(tt.msrPlatformInfoValue, tt.readSingleMsrErrRatio)
defer mockServices.msr.AssertExpectations(t)
p.addCPUBaseFreq(tt.socketID, &acc)
actual := acc.GetTelegrafMetrics()
if !tt.metricExpected {
require.Empty(t, actual)
return
}
require.Len(t, actual, 1)
expected := []telegraf.Metric{
testutil.MustMetric(
"powerstat_package",
map[string]string{
"package_id": tt.socketID,
},
map[string]interface{}{
"cpu_base_frequency_mhz": uint64(tt.nonTurboRatio * tt.clockBusValue),
},
time.Unix(0, 0),
telegraf.Gauge,
),
}
testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())
})
}
}