diff --git a/cmd/config/config_tables.go b/cmd/config/config_tables.go index 58f06bfe..0b56b9ba 100644 --- a/cmd/config/config_tables.go +++ b/cmd/config/config_tables.go @@ -87,11 +87,11 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi fields = append(fields, []table.Field{ {Name: "Energy Performance Bias", Description: "--epb <0-15>", Values: []string{extract.EPBFromOutput(outputs)}}, {Name: "Energy Performance Preference", Description: "--epp <0-255>", Values: []string{extract.EPPFromOutput(outputs)}}, - {Name: "Scaling Governor", Description: "--gov ", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}}, + {Name: "Scaling Governor", Description: "--gov <" + strings.Join(governorOptions, "|") + ">", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}}, }...) // add ELC (for SRF, CWF and GNR only) if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) { - fields = append(fields, table.Field{Name: "Efficiency Latency Control", Description: "--elc ", Values: []string{extract.ELCSummaryFromOutput(outputs)}}) + fields = append(fields, table.Field{Name: "Efficiency Latency Control", Description: "--elc <" + strings.Join(elcOptions, "|") + ">", Values: []string{extract.ELCSummaryFromOutput(outputs)}}) } // add prefetchers for _, pf := range extract.PrefetcherDefinitions { @@ -123,7 +123,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi fields = append(fields, table.Field{ Name: pf.ShortName + " prefetcher", - Description: "--" + "pref-" + strings.ReplaceAll(strings.ToLower(pf.ShortName), " ", "") + " ", + Description: "--" + "pref-" + strings.ReplaceAll(strings.ToLower(pf.ShortName), " ", "") + " <" + strings.Join(prefetcherOptions, "|") + ">", Values: []string{enabledDisabled}}, ) } @@ -131,12 +131,12 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi // add C6 c6 := extract.C6FromOutput(outputs) if c6 != "" { - fields = append(fields, table.Field{Name: "C6", Description: "--c6 ", Values: []string{c6}}) + fields = append(fields, table.Field{Name: "C6", Description: "--c6 <" + strings.Join(c6Options, "|") + ">", Values: []string{c6}}) } // add C1 Demotion c1Demotion := strings.TrimSpace(outputs[script.C1DemotionScriptName].Stdout) if c1Demotion != "" { - fields = append(fields, table.Field{Name: "C1 Demotion", Description: "--c1-demotion ", Values: []string{c1Demotion}}) + fields = append(fields, table.Field{Name: "C1 Demotion", Description: "--c1-demotion <" + strings.Join(c1DemotionOptions, "|") + ">", Values: []string{c1Demotion}}) } return fields } diff --git a/cmd/config/flag_groups.go b/cmd/config/flag_groups.go index 114286ae..91a15521 100644 --- a/cmd/config/flag_groups.go +++ b/cmd/config/flag_groups.go @@ -76,7 +76,7 @@ const ( var governorOptions = []string{"performance", "powersave"} // elcOptions - list of valid elc options -var elcOptions = []string{"latency-optimized", "default"} +var elcOptions = []string{"latency", "power"} // prefetcherOptions - list of valid prefetcher options var prefetcherOptions = []string{"enable", "disable"} diff --git a/cmd/config/restore.go b/cmd/config/restore.go index c6e22b63..f12729a1 100644 --- a/cmd/config/restore.go +++ b/cmd/config/restore.go @@ -353,13 +353,8 @@ func convertValue(flagName string, rawValue string) (string, error) { // "performance" or "powersave" return parseEnableDisableOrOption(rawValue, governorOptions) case flagELCName: - // "Default" -> "default" - // "Latency-Optimized" -> "latency-optimized" - rawValueLower := strings.ToLower(rawValue) - if slices.Contains(elcOptions, rawValueLower) { - return rawValueLower, nil - } - return "", fmt.Errorf("invalid elc value: %s", rawValue) + // "power" or "latency" + return parseEnableDisableOrOption(rawValue, elcOptions) case flagC6Name: return parseEnableDisableOrOption(rawValue, c6Options) case flagC1DemotionName: diff --git a/cmd/config/restore_test.go b/cmd/config/restore_test.go index 056536fb..fa0a9a5a 100644 --- a/cmd/config/restore_test.go +++ b/cmd/config/restore_test.go @@ -142,8 +142,8 @@ func TestConvertValue(t *testing.T) { {"Prefetcher enabled", "pref-l2hw", "Enabled", "enable", false}, {"Prefetcher disabled", "pref-l2hw", "Disabled", "disable", false}, {"C6 enabled", "c6", "Enabled", "enable", false}, - {"ELC lowercase", "elc", "default", "default", false}, - {"ELC capitalized", "elc", "Default", "default", false}, + {"ELC lowercase", "elc", "power", "power", false}, + {"ELC capitalized", "elc", "Power", "power", false}, {"Core SSE freq buckets", "core-max-buckets", "1-44/3.6, 45-52/3.5, 53-60/3.4", "1-44/3.6, 45-52/3.5, 53-60/3.4", false}, {"Core SSE freq buckets full", "core-max-buckets", "1-44/3.6, 45-52/3.5, 53-60/3.4, 61-72/3.2, 73-76/3.1, 77-86/3.0", "1-44/3.6, 45-52/3.5, 53-60/3.4, 61-72/3.2, 73-76/3.1, 77-86/3.0", false}, {"Core SSE freq buckets invalid", "core-max-buckets", "invalid-format", "", true}, diff --git a/cmd/config/set.go b/cmd/config/set.go index 96699308..1983be49 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -775,31 +775,94 @@ func setGovernor(governor string, myTarget target.Target, localTempDir string) e return err } -func setELC(elc string, myTarget target.Target, localTempDir string) error { - var mode string - switch elc { - case elcOptions[0]: - mode = "latency-optimized-mode" - case elcOptions[1]: - mode = "default" - default: - return fmt.Errorf("invalid ELC mode: %s", elc) +// setELCOPM sets ELC to Optimized Power Mode (OPM) +func setELCOPM(myTarget target.Target, localTempDir string) error { + // The script is derived from bhs-power-mode script in the Intel PCM repository. + setScript := script.ScriptDefinition{ + Name: "set elc opm", + ScriptTemplate: ` +# determine I/O and compute dies +output=$(pcm-tpmi 2 0x10 -d -b 26:26) + +# Parse the output to build lists of I/O and compute dies +io_dies=() +compute_dies=() +declare -A die_types +while read -r line; do + if [[ $line == *"instance 0"* ]]; then + die=$(echo "$line" | grep -oP 'entry \K[0-9]+') + if [[ $line == *"value 1"* ]]; then + die_types[$die]="IO" + io_dies+=("$die") + elif [[ $line == *"value 0"* ]]; then + die_types[$die]="Compute" + compute_dies+=("$die") + fi + fi +done <<< "$output" + +# Set ELC parameters for I/O and Compute dies +# set values common to both die types +pcm-tpmi 2 0x18 -d -b 39:39 -w 1 # EFFICIENCY_LATENCY_CTRL_HIGH_THRESHOLD_ENABLE +pcm-tpmi 2 0x18 -d -b 46:40 -w 120 # EFFICIENCY_LATENCY_CTRL_HIGH_THRESHOLD (120 / 127 ~= 94%) +pcm-tpmi 2 0x18 -d -b 38:32 -w 13 # EFFICIENCY_LATENCY_CTRL_LOW_THRESHOLD (13 / 127 ~= 10%) + +# set values for I/O Dies +for die in "${io_dies[@]}"; do + pcm-tpmi 2 0x18 -d -e $die -b 28:22 -w 8 # EFFICIENCY_LATENCY_CTRL_RATIO 0.8 GHz for I/O Dies +done + +# set values for Compute Dies +for die in "${compute_dies[@]}"; do + pcm-tpmi 2 0x18 -d -e $die -b 28:22 -w 12 # EFFICIENCY_LATENCY_CTRL_RATIO 1.2 GHz for Compute Dies +done +`, + Superuser: true, + Vendors: []string{cpus.IntelVendor}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF}, + Depends: []string{"pcm-tpmi"}, } + _, err := runScript(myTarget, setScript, localTempDir) + if err != nil { + err = fmt.Errorf("failed to set ELC OPM mode: %w", err) + } + return err +} + +// setELCLOM sets ELC to Latency Optimized Mode (LOM) +func setELCLOM(myTarget target.Target, localTempDir string) error { + // The script is derived from bhs-power-mode script in the Intel PCM repository. setScript := script.ScriptDefinition{ - Name: "set elc", - ScriptTemplate: fmt.Sprintf("bhs-power-mode.sh --%s", mode), + Name: "set elc lom", + ScriptTemplate: ` +pcm-tpmi 2 0x18 -d -b 39:39 -w 1 # EFFICIENCY_LATENCY_CTRL_HIGH_THRESHOLD_ENABLE +pcm-tpmi 2 0x18 -d -b 28:22 -w 0 # EFFICIENCY_LATENCY_CTRL_RATIO +pcm-tpmi 2 0x18 -d -b 46:40 -w 0 # EFFICIENCY_LATENCY_CTRL_HIGH_THRESHOLD +pcm-tpmi 2 0x18 -d -b 38:32 -w 0 # EFFICIENCY_LATENCY_CTRL_LOW_THRESHOLD +`, Superuser: true, Vendors: []string{cpus.IntelVendor}, MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF}, - Depends: []string{"bhs-power-mode.sh", "pcm-tpmi"}, + Depends: []string{"pcm-tpmi"}, } _, err := runScript(myTarget, setScript, localTempDir) if err != nil { - err = fmt.Errorf("failed to set ELC mode: %w", err) + err = fmt.Errorf("failed to set ELC LOM mode: %w", err) } return err } +func setELC(elc string, myTarget target.Target, localTempDir string) error { + switch elc { + case elcOptions[0]: + return setELCLOM(myTarget, localTempDir) + case elcOptions[1]: + return setELCOPM(myTarget, localTempDir) + default: + return fmt.Errorf("invalid ELC mode: %s", elc) + } +} + func getUarch(myTarget target.Target, localTempDir string) (string, error) { scripts := []script.ScriptDefinition{} scripts = append(scripts, script.GetScriptByName(script.LscpuScriptName)) diff --git a/cmd/report/report_tables.go b/cmd/report/report_tables.go index f4672898..527a3a68 100644 --- a/cmd/report/report_tables.go +++ b/cmd/report/report_tables.go @@ -444,6 +444,10 @@ var tableDefinitions = map[string]table.TableDefinition{ script.EtcReleaseScriptName, script.PackagePowerLimitName, script.EpbScriptName, + script.EppScriptName, + script.EppValidScriptName, + script.EppPackageControlScriptName, + script.EppPackageScriptName, script.ScalingDriverScriptName, script.ScalingGovernorScriptName, script.CstatesScriptName, @@ -853,31 +857,39 @@ func elcTableInsights(outputs map[string]script.ScriptOutput, tableValues table. } // suggest setting ELC mode to 'Latency Optimized' or 'Default' based on the current setting for _, mode := range tableValues.Fields[modeFieldIndex].Values { - if mode != "" && mode != "Latency Optimized" { + if mode != "" && mode != extract.ELCModeLatencyOptimized { insights = append(insights, table.Insight{ - Recommendation: "Consider setting Efficiency Latency Control mode to 'Latency Optimized' when workload is highly sensitive to memory latency.", + Recommendation: "Consider setting Efficiency Latency Control mode to 'Latency Optimized Mode (LOM)' when workload is highly sensitive to memory latency.", Justification: fmt.Sprintf("ELC mode is set to '%s' on at least one die.", mode), }) break } } for _, mode := range tableValues.Fields[modeFieldIndex].Values { - if mode != "" && mode != "Default" { + if mode != "" && mode != extract.ELCModeOptimizedPower { insights = append(insights, table.Insight{ - Recommendation: "Consider setting Efficiency Latency Control mode to 'Default' to balance uncore performance and power utilization.", + Recommendation: "Consider setting Efficiency Latency Control mode to 'Optimized Power Mode (OPM)' to balance uncore performance and power utilization.", Justification: fmt.Sprintf("ELC mode is set to '%s' on at least one die.", mode), }) break } } - // if epb is not set to 'Performance (0)' and ELC mode is set to 'Latency Optimized', suggest setting epb to 'Performance (0)' + // if epb is not set to 'Performance (0)' and ELC mode is set to 'Latency Optimized Mode (LOM)', suggest setting epb to 'Performance (0)' epb := extract.EPBFromOutput(outputs) - if epb != "" && epb != "Performance (0)" && firstMode == "Latency Optimized" { + if epb != "" && epb != "Performance (0)" && firstMode == extract.ELCModeLatencyOptimized { insights = append(insights, table.Insight{ - Recommendation: "Consider setting Energy Performance Bias to 'Performance (0)' to allow Latency Optimized mode to operate as designed.", + Recommendation: "Consider setting Energy Performance Bias to 'Performance (0)' to allow Latency Optimized Mode (LOM) to operate as designed.", Justification: fmt.Sprintf("Energy Performance Bias is set to '%s' and ELC Mode is set to '%s'.", epb, firstMode), }) } + // if epp is not set to 'Performance (0)' and ELC mode is set to 'Latency Optimized Mode (LOM)', suggest setting epp to 'Performance (0)' + epp := extract.EPPFromOutput(outputs) + if epp != "" && epp != "Performance (0)" && firstMode == extract.ELCModeLatencyOptimized { + insights = append(insights, table.Insight{ + Recommendation: "Consider setting Energy Performance Preference to 'Performance (0)' to allow Latency Optimized Mode (LOM) to operate as designed.", + Justification: fmt.Sprintf("Energy Performance Preference is set to '%s' and ELC Mode is set to '%s'.", epp, firstMode), + }) + } } return insights } diff --git a/internal/extract/power.go b/internal/extract/power.go index 7f0d9983..396a41d1 100644 --- a/internal/extract/power.go +++ b/internal/extract/power.go @@ -176,6 +176,25 @@ func CstatesFromOutput(outputs map[string]script.ScriptOutput) []CstateInfo { return cstatesInfo } +// enum for the column indices in the ELC CSV output +const ( + elcFieldSocketID = iota + elcFieldDie + elcFieldDieType + elcFieldMinRatio + elcFieldMaxRatio + elcFieldELCRatio + elcFieldELCLowThreshold + elcFieldELCHighThreshold + elcFieldELCHighThresholdEnable +) + +const ( + ELCModeLatencyOptimized = "Latency Optimized Mode (LOM)" + ELCModeOptimizedPower = "Optimized Power Mode (OPM)" + ELCModeCustom = "Custom Mode" +) + // ELCFieldValuesFromOutput extracts Efficiency Latency Control field values. func ELCFieldValuesFromOutput(outputs map[string]script.ScriptOutput) (fieldValues []table.Field) { if outputs[script.ElcScriptName].Stdout == "" { @@ -189,6 +208,13 @@ func ELCFieldValuesFromOutput(outputs map[string]script.ScriptOutput) (fieldValu if len(rows) < 2 { return } + // confirm rows have expected number of columns + for _, row := range rows { + if len(row) < elcFieldELCHighThresholdEnable+1 { + slog.Warn("ELC script output has unexpected number of columns", slog.Int("expected", elcFieldELCHighThresholdEnable+1), slog.Int("actual", len(row))) + return + } + } for fieldNamesIndex, fieldName := range rows[0] { values := []string{} for _, row := range rows[1:] { @@ -197,30 +223,23 @@ func ELCFieldValuesFromOutput(outputs map[string]script.ScriptOutput) (fieldValu fieldValues = append(fieldValues, table.Field{Name: fieldName, Values: values}) } - values := []string{} + modeValues := []string{} for _, row := range rows[1:] { var mode string - if len(row) > 7 && row[2] == "IO" { - if row[5] == "0" && row[6] == "0" && row[7] == "0" { - mode = "Latency Optimized" - } else if row[5] == "800" && row[6] == "10" && row[7] == "94" { - mode = "Default" - } else { - mode = "Custom" - } - } else if len(row) > 5 { - switch row[5] { - case "0": - mode = "Latency Optimized" - case "1200": - mode = "Default" - default: - mode = "Custom" - } + if row[elcFieldELCRatio] == "0" && row[elcFieldELCLowThreshold] == "0" && row[elcFieldELCHighThreshold] == "0" && row[elcFieldELCHighThresholdEnable] == "1" { + mode = ELCModeLatencyOptimized + } else if row[elcFieldELCLowThreshold] == "10" && + row[elcFieldELCHighThreshold] == "94" && + row[elcFieldELCHighThresholdEnable] == "1" && + ((row[elcFieldDieType] == "IO" && row[elcFieldELCRatio] == "800") || + (row[elcFieldDieType] == "Compute" && row[elcFieldELCRatio] == "1200")) { + mode = ELCModeOptimizedPower + } else { + mode = ELCModeCustom } - values = append(values, mode) + modeValues = append(modeValues, mode) } - fieldValues = append(fieldValues, table.Field{Name: "Mode", Values: values}) + fieldValues = append(fieldValues, table.Field{Name: "Mode", Values: modeValues}) return } diff --git a/tools/Makefile b/tools/Makefile index f7b46bd0..a0252a46 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -41,7 +41,6 @@ tools-x86_64: async-profiler avx-turbo cpuid dmidecode ethtool fio ipmitool lshw cp msr-tools/rdmsr bin/x86_64/ cp msr-tools/wrmsr bin/x86_64/ cp pcm/build/bin/pcm-tpmi bin/x86_64/ - cp pcm/scripts/bhs-power-mode.sh bin/x86_64/ cp perf-archive/perf-archive.sh bin/x86_64/perf-archive && chmod +rx bin/x86_64/perf-archive cp spectre-meltdown-checker/spectre-meltdown-checker.sh bin/x86_64/ cp sshpass/sshpass bin/x86_64/