Skip to content
Merged
2 changes: 1 addition & 1 deletion cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func printConfig(reports map[string][]byte, toStdout bool, toFile bool, outputDi
// collectOnTarget runs the scripts on the target and sends the results to the appropriate channels
func collectOnTarget(myTarget target.Target, scriptsToRun []script.ScriptDefinition, localTempDir string, channelTargetScriptOutputs chan common.TargetScriptOutputs, channelError chan error, statusUpdate progress.MultiSpinnerUpdateFunc) {
// run the scripts on the target
scriptOutputs, err := script.RunScripts(myTarget, scriptsToRun, true, localTempDir, statusUpdate, "collecting configuration")
scriptOutputs, err := common.RunScripts(myTarget, scriptsToRun, true, localTempDir, statusUpdate, "collecting configuration", false)
if err != nil {
if statusUpdate != nil {
_ = statusUpdate(myTarget.GetName(), fmt.Sprintf("error collecting configuration: %v", err))
Expand Down
7 changes: 5 additions & 2 deletions cmd/config/config_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ var tableDefinitions = map[string]table.TableDefinition{
script.PrefetchersAtomName,
script.CstatesScriptName,
script.C1DemotionScriptName,
script.ArmImplementerScriptName,
script.ArmPartScriptName,
script.ArmDmidecodePartScriptName,
},
FieldsFunc: configurationTableValues},
}
Expand All @@ -67,7 +70,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi
{Name: "Package Power / TDP", Description: "--tdp <Watts>", Values: []string{common.TDPFromOutput(outputs)}},
{Name: "Core SSE Frequency", Description: "--core-max <GHz>", Values: []string{sseFrequenciesFromOutput(outputs)}},
}
if strings.Contains(uarch, "SRF") || strings.Contains(uarch, "GNR") || strings.Contains(uarch, "CWF") {
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) {
fields = append(fields, []table.Field{
{Name: "Uncore Max Frequency (Compute)", Description: "--uncore-max-compute <GHz>", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(true, true, outputs)}},
{Name: "Uncore Min Frequency (Compute)", Description: "--uncore-min-compute <GHz>", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}},
Expand All @@ -86,7 +89,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi
{Name: "Scaling Governor", Description: "--gov <performance|powersave>", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}},
}...)
// add ELC (for SRF, CWF and GNR only)
if strings.Contains(uarch, "SRF") || strings.Contains(uarch, "GNR") || strings.Contains(uarch, "CWF") {
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 <default|latency-optimized>", Values: []string{common.ELCSummaryFromOutput(outputs)}})
}
// add prefetchers
Expand Down
90 changes: 34 additions & 56 deletions cmd/config/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func setLlcSize(desiredLlcSize float64, myTarget target.Target, localTempDir str
scripts = append(scripts, script.GetScriptByName(script.LspciBitsScriptName))
scripts = append(scripts, script.GetScriptByName(script.LspciDevicesScriptName))
scripts = append(scripts, script.GetScriptByName(script.L3CacheWayEnabledName))
outputs, err := script.RunScripts(myTarget, scripts, true, localTempDir, nil, "")
outputs, err := common.RunScripts(myTarget, scripts, true, localTempDir, nil, "", false)
if err != nil {
return fmt.Errorf("failed to run scripts on target: %w", err)
}
Expand Down Expand Up @@ -181,15 +181,15 @@ func setLlcSize(desiredLlcSize float64, myTarget target.Target, localTempDir str
}

func setSSEFrequency(sseFrequency float64, myTarget target.Target, localTempDir string) error {
targetFamily, err := myTarget.GetFamily()
targetFamily, err := common.GetTargetFamily(myTarget)
if err != nil {
return fmt.Errorf("failed to get target family: %w", err)
}
targetModel, err := myTarget.GetModel()
targetModel, err := common.GetTargetModel(myTarget)
if err != nil {
return fmt.Errorf("failed to get target model: %w", err)
}
targetVendor, err := myTarget.GetVendor()
targetVendor, err := common.GetTargetVendor(myTarget)
if err != nil {
return fmt.Errorf("failed to get target vendor: %w", err)
}
Expand Down Expand Up @@ -340,15 +340,15 @@ func expandConsolidatedFrequencies(consolidatedStr string, bucketSizes []int) ([
// Note that the buckets have been consolidated where frequencies are the same, so they
// will need to be expanded back out to individual buckets for setting.
func setSSEFrequencies(sseFrequencies string, myTarget target.Target, localTempDir string) error {
targetFamily, err := myTarget.GetFamily()
targetFamily, err := common.GetTargetFamily(myTarget)
if err != nil {
return fmt.Errorf("failed to get target family: %w", err)
}
targetModel, err := myTarget.GetModel()
targetModel, err := common.GetTargetModel(myTarget)
if err != nil {
return fmt.Errorf("failed to get target model: %w", err)
}
targetVendor, err := myTarget.GetVendor()
targetVendor, err := common.GetTargetVendor(myTarget)
if err != nil {
return fmt.Errorf("failed to get target vendor: %w", err)
}
Expand Down Expand Up @@ -390,11 +390,11 @@ func setSSEFrequencies(sseFrequencies string, myTarget target.Target, localTempD
return fmt.Errorf("failed to get microarchitecture: %w", err)
}
var archMultiplier int
if strings.Contains(uarch, "SRF") || strings.Contains(uarch, "CWF") {
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchCWF) {
archMultiplier = 4
} else if strings.Contains(uarch, "GNR_X3") {
} else if strings.Contains(uarch, cpus.UarchGNR_X3) {
archMultiplier = 3
} else if strings.Contains(uarch, "GNR_X2") {
} else if strings.Contains(uarch, cpus.UarchGNR_X2) {
archMultiplier = 2
} else {
archMultiplier = 1
Expand Down Expand Up @@ -477,31 +477,19 @@ func setUncoreDieFrequency(maxFreq bool, computeDie bool, uncoreFrequency float6
uncoreDieFrequencyMutex.Lock()
defer uncoreDieFrequencyMutex.Unlock()

targetFamily, err := myTarget.GetFamily()
if err != nil {
return fmt.Errorf("failed to get target family: %w", err)
}
targetModel, err := myTarget.GetModel()
if err != nil {
return fmt.Errorf("failed to get target model: %w", err)
}
if targetFamily != "6" || (targetFamily == "6" && targetModel != "173" && targetModel != "174" && targetModel != "175" && targetModel != "221") { // not Intel || not GNR, GNR-D, SRF, CWF
return fmt.Errorf("uncore frequency setting not supported on %s due to family/model mismatch", myTarget.GetName())
}
type dieId struct {
instance string
entry string
}
var dies []dieId
// build list of compute or IO dies
scripts := []script.ScriptDefinition{}
scripts = append(scripts, script.GetScriptByName(script.UncoreDieTypesFromTPMIScriptName))
outputs, err := script.RunScripts(myTarget, scripts, true, localTempDir, nil, "")
dieTypesScript := script.GetScriptByName(script.UncoreDieTypesFromTPMIScriptName)
scriptOutput, err := common.RunScript(myTarget, dieTypesScript, localTempDir, false)
if err != nil {
return fmt.Errorf("failed to run scripts on target: %w", err)
return fmt.Errorf("failed to run script on target: %w", err)
}
re := regexp.MustCompile(`Read bits \d+:\d+ value (\d+) from TPMI ID .* for entry (\d+) in instance (\d+)`)
for line := range strings.SplitSeq(outputs[script.UncoreDieTypesFromTPMIScriptName].Stdout, "\n") {
for line := range strings.SplitSeq(scriptOutput.Stdout, "\n") {
match := re.FindStringSubmatch(line)
if match == nil {
continue
Expand All @@ -525,7 +513,7 @@ func setUncoreDieFrequency(maxFreq bool, computeDie bool, uncoreFrequency float6
freqType = "min"
}
// run script for each die of specified type
scripts = []script.ScriptDefinition{}
scripts := []script.ScriptDefinition{}
for _, die := range dies {
setScript := script.ScriptDefinition{
Name: fmt.Sprintf("write %s uncore frequency TPMI %s %s", freqType, die.instance, die.entry),
Expand All @@ -537,7 +525,7 @@ func setUncoreDieFrequency(maxFreq bool, computeDie bool, uncoreFrequency float6
}
scripts = append(scripts, setScript)
}
_, err = script.RunScripts(myTarget, scripts, false, localTempDir, nil, "")
_, err = common.RunScripts(myTarget, scripts, false, localTempDir, nil, "", false)
if err != nil {
err = fmt.Errorf("failed to set uncore die frequency: %w", err)
slog.Error(err.Error())
Expand All @@ -550,31 +538,20 @@ func setUncoreFrequency(maxFreq bool, uncoreFrequency float64, myTarget target.T
uncoreFrequencyMutex.Lock()
defer uncoreFrequencyMutex.Unlock()

scripts := []script.ScriptDefinition{}
scripts = append(scripts, script.ScriptDefinition{
Name: "get uncore frequency MSR",
ScriptTemplate: "rdmsr 0x620",
Vendors: []string{cpus.IntelVendor},
Superuser: true,
getScript := script.ScriptDefinition{
Name: "get uncore frequency MSR",
ScriptTemplate: "rdmsr 0x620",
Vendors: []string{cpus.IntelVendor},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF},
Superuser: true,
// Depends: []string{"rdmsr"},
// Lkms: []string{"msr"},
})
outputs, err := script.RunScripts(myTarget, scripts, true, localTempDir, nil, "")
if err != nil {
return fmt.Errorf("failed to run scripts on target: %w", err)
}
targetFamily, err := myTarget.GetFamily()
if err != nil {
return fmt.Errorf("failed to get target family: %w", err)
}
targetModel, err := myTarget.GetModel()
scriptOutput, err := common.RunScript(myTarget, getScript, localTempDir, false)
if err != nil {
return fmt.Errorf("failed to get target model: %w", err)
}
if targetFamily != "6" || (targetFamily == "6" && (targetModel == "173" || targetModel == "174" || targetModel == "175" || targetModel == "221")) { // not Intel || not GNR, GNR-D, SRF, CWF
return fmt.Errorf("uncore frequency setting not supported on %s due to family/model mismatch", myTarget.GetName())
return fmt.Errorf("failed to run scripts on target: %w", err)
}
msrUint, err := strconv.ParseUint(strings.TrimSpace(outputs["get uncore frequency MSR"].Stdout), 16, 0)
msrUint, err := strconv.ParseUint(strings.TrimSpace(scriptOutput.Stdout), 16, 0)
if err != nil {
return fmt.Errorf("failed to parse uncore frequency MSR: %w", err)
}
Expand All @@ -592,10 +569,11 @@ func setUncoreFrequency(maxFreq bool, uncoreFrequency float64, myTarget target.T
newVal = newVal | newFreq<<8
}
setScript := script.ScriptDefinition{
Name: "set uncore frequency MSR",
ScriptTemplate: fmt.Sprintf("wrmsr -a 0x620 %d", newVal),
Superuser: true,
Vendors: []string{cpus.IntelVendor},
Name: "set uncore frequency MSR",
ScriptTemplate: fmt.Sprintf("wrmsr -a 0x620 %d", newVal),
Superuser: true,
Vendors: []string{cpus.IntelVendor},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF},
// Depends: []string{"wrmsr"},
// Lkms: []string{"msr"},
}
Expand All @@ -615,7 +593,7 @@ func setTDP(power int, myTarget target.Target, localTempDir string) error {
// Lkms: []string{"msr"},
// Depends: []string{"rdmsr"},
}
readOutput, err := script.RunScript(myTarget, readScript, localTempDir)
readOutput, err := common.RunScript(myTarget, readScript, localTempDir, false)
if err != nil {
return fmt.Errorf("failed to read power MSR: %w", err)
} else {
Expand Down Expand Up @@ -804,7 +782,7 @@ func setELC(elc string, myTarget target.Target, localTempDir string) error {
ScriptTemplate: fmt.Sprintf("bhs-power-mode.sh --%s", mode),
Superuser: true,
Vendors: []string{cpus.IntelVendor},
MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF"},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF},
Depends: []string{"bhs-power-mode.sh", "pcm-tpmi"},
}
_, err := runScript(myTarget, setScript, localTempDir)
Expand All @@ -819,7 +797,7 @@ func getUarch(myTarget target.Target, localTempDir string) (string, error) {
scripts = append(scripts, script.GetScriptByName(script.LscpuScriptName))
scripts = append(scripts, script.GetScriptByName(script.LspciBitsScriptName))
scripts = append(scripts, script.GetScriptByName(script.LspciDevicesScriptName))
outputs, err := script.RunScripts(myTarget, scripts, true, localTempDir, nil, "")
outputs, err := common.RunScripts(myTarget, scripts, true, localTempDir, nil, "", false)
if err != nil {
return "", fmt.Errorf("failed to run scripts on target: %w", err)
}
Expand Down Expand Up @@ -992,7 +970,7 @@ func setC1Demotion(enableDisable string, myTarget target.Target, localTempDir st

// runScript runs a script on the target and returns the output
func runScript(myTarget target.Target, myScript script.ScriptDefinition, localTempDir string) (string, error) {
output, err := script.RunScript(myTarget, myScript, localTempDir) // nosemgrep
output, err := common.RunScript(myTarget, myScript, localTempDir, false) // nosemgrep
if err != nil {
slog.Error("failed to run script on target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error()), slog.String("stdout", output.Stdout), slog.String("stderr", output.Stderr))
} else {
Expand Down
37 changes: 15 additions & 22 deletions cmd/metrics/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package metrics
import (
"fmt"
"log/slog"
"strings"
"perfspect/internal/cpus"

"github.com/casbin/govaluate"
)
Expand Down Expand Up @@ -64,7 +64,6 @@ type Loader interface {
}

type BaseLoader struct {
microarchitecture string
}

type LegacyLoader struct {
Expand All @@ -79,44 +78,38 @@ type ComponentLoader struct {
BaseLoader
}

// NewLoader creates the right type of Loader for each CPU microarchitecture
// Input is the CPU microarchitecture name as defined in the cpus module.
func NewLoader(uarch string) (Loader, error) {
uarch = strings.ToLower(uarch)
uarch = strings.Split(uarch, " ")[0] // Handle "Turin (Zen 5)" case
switch uarch {
case "clx", "skx", "bdx", "bergamo", "genoa", "turin":
case cpus.UarchCLX, cpus.UarchSKX, cpus.UarchBDX, cpus.UarchBergamo, cpus.UarchGenoa, cpus.UarchTurinZen5, cpus.UarchTurinZen5c:
slog.Debug("Using legacy loader for microarchitecture", slog.String("uarch", uarch))
return newLegacyLoader(uarch), nil
case "gnr", "srf", "emr", "spr", "icx":
return newLegacyLoader(), nil
case cpus.UarchGNR, cpus.UarchGNR_X1, cpus.UarchGNR_X2, cpus.UarchGNR_X3, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchSRF_SP, cpus.UarchSRF_AP, cpus.UarchEMR, cpus.UarchEMR_MCC, cpus.UarchEMR_XCC, cpus.UarchSPR, cpus.UarchSPR_MCC, cpus.UarchSPR_XCC, cpus.UarchICX:
slog.Debug("Using perfmon loader for microarchitecture", slog.String("uarch", uarch))
return newPerfmonLoader(uarch), nil
case "neoverse-n2", "neoverse-v2", "neoverse-n1", "neoverse-v1":
return newPerfmonLoader(), nil
case cpus.UarchGraviton2, cpus.UarchGraviton3, cpus.UarchGraviton4, cpus.UarchAxion, cpus.UarchAmpereOneAC03, cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1:
slog.Debug("Using component loader for microarchitecture", slog.String("uarch", uarch))
return newComponentLoader(uarch), nil
return newComponentLoader(), nil
default:
return nil, fmt.Errorf("unsupported microarchitecture: %s", uarch)
}
}

func newLegacyLoader(uarch string) *LegacyLoader {
func newLegacyLoader() *LegacyLoader {
return &LegacyLoader{
BaseLoader: BaseLoader{
microarchitecture: uarch,
},
BaseLoader: BaseLoader{},
}
}

func newPerfmonLoader(uarch string) *PerfmonLoader {
func newPerfmonLoader() *PerfmonLoader {
return &PerfmonLoader{
BaseLoader: BaseLoader{
microarchitecture: uarch,
},
BaseLoader: BaseLoader{},
}
}

func newComponentLoader(uarch string) *ComponentLoader {
func newComponentLoader() *ComponentLoader {
return &ComponentLoader{
BaseLoader: BaseLoader{
microarchitecture: uarch,
},
BaseLoader: BaseLoader{},
}
}
23 changes: 15 additions & 8 deletions cmd/metrics/loader_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"log/slog"
"os"
"path/filepath"
"perfspect/internal/cpus"
"perfspect/internal/util"
"regexp"
"slices"
Expand Down Expand Up @@ -67,7 +68,7 @@ func (l *ComponentLoader) loadMetricDefinitions(metricDefinitionOverridePath str
}
} else {
var archDir string
archDir, err = getArchDir(metadata.Microarchitecture)
archDir, err = getUarchDir(metadata.Microarchitecture)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -168,7 +169,7 @@ func compareCPUID(mapCpuId string, idStr string) (int, error) {
// skip metrics.json
func (l *ComponentLoader) loadEventDefinitions(metadata Metadata) (events []ComponentEvent, err error) {
var archDir string
archDir, err = getArchDir(metadata.Microarchitecture)
archDir, err = getUarchDir(metadata.Microarchitecture)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -490,16 +491,22 @@ func initializeComponentMetricEvaluable(expression string, evaluatorFunctions ma
return expr
}

func getArchDir(uarch string) (string, error) {
if strings.ToLower(uarch) == "neoverse-n2" || strings.ToLower(uarch) == "neoverse-v2" {
// getUarchDir maps from the CPU's microarchitecture, as defined in
// the cpus module, to the directory where the associated events and metrics reside
func getUarchDir(uarch string) (string, error) {
switch uarch {
case cpus.UarchGraviton4, cpus.UarchAxion:
return "neoverse-n2-v2", nil
} else if strings.ToLower(uarch) == "neoverse-n1" {
case cpus.UarchGraviton2:
return "neoverse-n1", nil
} else if strings.ToLower(uarch) == "neoverse-v1" {
case cpus.UarchGraviton3:
return "neoverse-v1", nil
} else {
return "", fmt.Errorf("unsupported component loader architecture")
case cpus.UarchAmpereOneAC03:
return "ampereone", nil
case cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1:
return "ampereonex", nil
}
return "", fmt.Errorf("unsupported component loader architecture: %s", uarch)
}

// deduplicateGroups eliminates duplicate and overlapping groups
Expand Down
Loading