From 25f9707e695f310b842ea3cedc8005fee3f4ab09 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 04:41:09 -0800 Subject: [PATCH 01/15] refactor to make CPU microarchitecture detection more flexible Signed-off-by: Harper, Jason M --- cmd/config/config.go | 2 +- cmd/config/set.go | 88 +++---- cmd/metrics/loader.go | 36 +-- cmd/metrics/loader_component.go | 18 +- cmd/metrics/loader_legacy.go | 16 +- cmd/metrics/loader_perfmon.go | 19 +- cmd/metrics/metadata.go | 95 ++++--- cmd/metrics/metrics.go | 12 +- cmd/metrics/nmi_watchdog.go | 6 +- cmd/metrics/perf_mux.go | 7 +- cmd/metrics/process.go | 4 +- cmd/report/cpu.go | 4 +- internal/common/common.go | 38 ++- internal/common/table_helpers.go | 12 +- internal/common/targets.go | 304 ++++++++++++++++++++++ internal/cpus/cpu_defs.go | 294 --------------------- internal/cpus/cpu_defs_test.go | 177 ------------- internal/cpus/cpus.go | 429 +++++++++++++++++++++++++++++++ internal/script/script.go | 71 ----- internal/table/table.go | 53 ---- internal/target/helpers.go | 85 ------ internal/target/local_target.go | 112 +++++--- internal/target/remote_target.go | 112 +++++--- internal/target/target.go | 60 +++-- 24 files changed, 1123 insertions(+), 931 deletions(-) delete mode 100644 internal/cpus/cpu_defs.go delete mode 100644 internal/cpus/cpu_defs_test.go create mode 100644 internal/cpus/cpus.go diff --git a/cmd/config/config.go b/cmd/config/config.go index 22f98141..7508486e 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -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)) diff --git a/cmd/config/set.go b/cmd/config/set.go index 0549a3a3..2273aef4 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -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) } @@ -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) } @@ -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) } @@ -477,31 +477,26 @@ 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) + supported, err := common.ScriptSupportedOnTarget(myTarget, dieTypesScript, localTempDir, false) + if err != nil { + return fmt.Errorf("failed to check if script is supported on target: %w", err) + } + if !supported { + return fmt.Errorf("uncore die frequency setting not supported on %s", myTarget.GetName()) + } + scriptOutput, err := common.RunScript(myTarget, dieTypesScript, localTempDir, false) if err != nil { return fmt.Errorf("failed to run scripts 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 @@ -525,7 +520,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), @@ -537,7 +532,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()) @@ -550,31 +545,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{"GNR", "GNR-D", "SRF", "CWF"}, + 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) } @@ -592,13 +576,15 @@ 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{"GNR", "GNR-D", "SRF", "CWF"}, // Depends: []string{"wrmsr"}, // Lkms: []string{"msr"}, } + // don't need to check script for target compatability since we already checked support above _, err = runScript(myTarget, setScript, localTempDir) if err != nil { err = fmt.Errorf("failed to set uncore frequency: %w", err) @@ -615,7 +601,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 { @@ -819,7 +805,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) } @@ -992,7 +978,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 { diff --git a/cmd/metrics/loader.go b/cmd/metrics/loader.go index f3e445eb..5838d0c9 100644 --- a/cmd/metrics/loader.go +++ b/cmd/metrics/loader.go @@ -6,7 +6,6 @@ package metrics import ( "fmt" "log/slog" - "strings" "github.com/casbin/govaluate" ) @@ -64,7 +63,6 @@ type Loader interface { } type BaseLoader struct { - microarchitecture string } type LegacyLoader struct { @@ -79,44 +77,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 "CLX", "SKX", "BDX", "Bergamo", "Genoa", "Turin": 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 "GNR", "SRF", "EMR", "SPR", "ICX": 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 "Graviton2", "Graviton3", "Graviton4", "Axion", "AmpereOne AC04", "AmpereOne AC04_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{}, } } diff --git a/cmd/metrics/loader_component.go b/cmd/metrics/loader_component.go index c7e709a6..e1633ac2 100644 --- a/cmd/metrics/loader_component.go +++ b/cmd/metrics/loader_component.go @@ -67,7 +67,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 } @@ -168,7 +168,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 } @@ -490,16 +490,18 @@ 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 "Graviton4", "Axion", "AmpereOne AC04", "AmpereOne AC04_1": return "neoverse-n2-v2", nil - } else if strings.ToLower(uarch) == "neoverse-n1" { + case "Graviton2": return "neoverse-n1", nil - } else if strings.ToLower(uarch) == "neoverse-v1" { + case "Graviton3": return "neoverse-v1", nil - } else { - return "", fmt.Errorf("unsupported component loader architecture") } + return "", fmt.Errorf("unsupported component loader architecture: %s", uarch) } // deduplicateGroups eliminates duplicate and overlapping groups diff --git a/cmd/metrics/loader_legacy.go b/cmd/metrics/loader_legacy.go index 2a98715e..1009b081 100644 --- a/cmd/metrics/loader_legacy.go +++ b/cmd/metrics/loader_legacy.go @@ -32,6 +32,14 @@ func (l *LegacyLoader) Load(loaderConfig LoaderConfig) ([]MetricDefinition, []Gr return configuredMetricDefinitions, loadedEventGroups, nil } +// getUarchFileName maps the CPU's microarchitecture, as defined in the cpus +// module, to the resource file name used by the legacy loader +func getUarchFileName(uarch string) string { + filename := strings.ToLower(uarch) + filename = strings.Split(filename, " ")[0] // Handle "Turin (Zen 5)" case + return filename +} + // loadMetricDefinitions reads and parses metric definitions from an architecture-specific metric // definition file. When the override path argument is empty, the function will load metrics from // the file associated with the platform's architecture found in the provided metadata. When @@ -44,9 +52,7 @@ func (l *LegacyLoader) loadMetricDefinitions(metricDefinitionOverridePath string return } } else { - uarch := strings.ToLower(strings.Split(metadata.Microarchitecture, "_")[0]) - uarch = strings.Split(uarch, " ")[0] - metricFileName := fmt.Sprintf("%s.json", uarch) + metricFileName := fmt.Sprintf("%s.json", getUarchFileName(metadata.Microarchitecture)) if bytes, err = resources.ReadFile(filepath.Join("resources", "legacy", "metrics", metadata.Architecture, metadata.Vendor, metricFileName)); err != nil { return } @@ -90,9 +96,7 @@ func (l *LegacyLoader) loadEventGroups(eventDefinitionOverridePath string, metad return } } else { - uarch := strings.ToLower(strings.Split(metadata.Microarchitecture, "_")[0]) - uarch = strings.Split(uarch, " ")[0] - eventFileName := fmt.Sprintf("%s.txt", uarch) + eventFileName := fmt.Sprintf("%s.txt", getUarchFileName(metadata.Microarchitecture)) if file, err = resources.Open(filepath.Join("resources", "legacy", "events", metadata.Architecture, metadata.Vendor, eventFileName)); err != nil { return } diff --git a/cmd/metrics/loader_perfmon.go b/cmd/metrics/loader_perfmon.go index 6f62fcba..fc50cf53 100644 --- a/cmd/metrics/loader_perfmon.go +++ b/cmd/metrics/loader_perfmon.go @@ -69,7 +69,7 @@ type MetricsConfig struct { func (l *PerfmonLoader) Load(loaderConfig LoaderConfig) ([]MetricDefinition, []GroupDefinition, error) { // Load the metrics configuration from the JSON file - config, err := l.loadMetricsConfig(loaderConfig.ConfigFileOverride) + config, err := l.loadMetricsConfig(loaderConfig) if err != nil { return nil, nil, fmt.Errorf("failed to load metrics config: %w", err) } @@ -179,18 +179,27 @@ func (l *PerfmonLoader) Load(loaderConfig LoaderConfig) ([]MetricDefinition, []G return metricDefs, allGroups, nil } -func (l *PerfmonLoader) loadMetricsConfig(configFileOverride string) (MetricsConfig, error) { +// uarchToResourceName maps from the CPU's microarchiteture, as defined in the cpus +// module, to the associated perfmon resource directory and config file name +func uarchToResourceName(uarch string) string { + name := strings.ToLower(uarch) + name = strings.Split(name, "_")[0] // Handle "GNR_X2", etc. + return name +} + +func (l *PerfmonLoader) loadMetricsConfig(loaderConfig LoaderConfig) (MetricsConfig, error) { var config MetricsConfig var bytes []byte - if configFileOverride != "" { + if loaderConfig.ConfigFileOverride != "" { var err error - bytes, err = os.ReadFile(configFileOverride) + bytes, err = os.ReadFile(loaderConfig.ConfigFileOverride) if err != nil { return MetricsConfig{}, fmt.Errorf("error reading metric config override file: %w", err) } } else { var err error - bytes, err = resources.ReadFile(filepath.Join("resources", "perfmon", strings.ToLower(l.microarchitecture), strings.ToLower(l.microarchitecture)+".json")) + resourceName := uarchToResourceName(loaderConfig.Metadata.Microarchitecture) + bytes, err = resources.ReadFile(filepath.Join("resources", "perfmon", resourceName, resourceName+".json")) if err != nil { return MetricsConfig{}, fmt.Errorf("error reading metrics config file: %w", err) } diff --git a/cmd/metrics/metadata.go b/cmd/metrics/metadata.go index 8aa53d91..5aaaab9a 100644 --- a/cmd/metrics/metadata.go +++ b/cmd/metrics/metadata.go @@ -79,8 +79,8 @@ type Metadata struct { // LoadMetadata - populates and returns a Metadata structure containing state of the // system. -func LoadMetadata(myTarget target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { - uarch, err := myTarget.GetArchitecture() +func LoadMetadata(t target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { + uarch, err := common.GetTargetArchitecture(t) if err != nil { return Metadata{}, fmt.Errorf("failed to get target architecture: %v", err) } @@ -88,11 +88,11 @@ func LoadMetadata(myTarget target.Target, noRoot bool, noSystemSummary bool, loc if err != nil { return Metadata{}, fmt.Errorf("failed to create metadata collector: %v", err) } - return collector.CollectMetadata(myTarget, noRoot, noSystemSummary, localTempDir, statusUpdate) + return collector.CollectMetadata(t, noRoot, noSystemSummary, localTempDir, statusUpdate) } type MetadataCollector interface { - CollectMetadata(myTarget target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) + CollectMetadata(t target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) } func NewMetadataCollector(architecture string) (MetadataCollector, error) { @@ -114,14 +114,13 @@ type X86MetadataCollector struct { type ARMMetadataCollector struct { } -func (c *X86MetadataCollector) CollectMetadata(myTarget target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { +func (c *X86MetadataCollector) CollectMetadata(t target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { var metadata Metadata var err error // Hostname - metadata.Hostname = myTarget.GetName() + metadata.Hostname = t.GetName() // CPU Info (from /proc/cpuinfo) - var cpuInfo []map[string]string - cpuInfo, err = getCPUInfo(myTarget) + cpuInfo, err := getCPUInfo(t) if err != nil || len(cpuInfo) < 1 { return Metadata{}, fmt.Errorf("failed to read cpu info: %v", err) } @@ -149,11 +148,10 @@ func (c *X86MetadataCollector) CollectMetadata(myTarget target.Target, noRoot bo // Vendor (from cpuInfo) metadata.Vendor = cpuInfo[0]["vendor_id"] // CPU microarchitecture (from cpuInfo) - cpu, err := cpus.GetCPU(cpuInfo[0]["cpu family"], cpuInfo[0]["model"], cpuInfo[0]["stepping"]) + metadata.Microarchitecture, err = common.GetTargetMicroArchitecture(t, localTempDir, noRoot) if err != nil { - return Metadata{}, err + return Metadata{}, fmt.Errorf("failed to get x86 microarchitecture: %v", err) } - metadata.Microarchitecture = cpu.MicroArchitecture // Number of General Purpose Counters metadata.NumGeneralPurposeCounters, err = getNumGPCounters(metadata.Microarchitecture) if err != nil { @@ -165,7 +163,7 @@ func (c *X86MetadataCollector) CollectMetadata(myTarget target.Target, noRoot bo return Metadata{}, fmt.Errorf("failed to get metadata scripts: %v", err) } // run the scripts - scriptOutputs, err := script.RunScripts(myTarget, metadataScripts, true, localTempDir, statusUpdate, "collecting metadata") // nosemgrep + scriptOutputs, err := common.RunScripts(t, metadataScripts, true, localTempDir, statusUpdate, "collecting metadata", noRoot) // nosemgrep if err != nil { return Metadata{}, fmt.Errorf("failed to run metadata scripts: %v", err) } @@ -285,12 +283,17 @@ func (c *X86MetadataCollector) CollectMetadata(myTarget target.Target, noRoot bo return metadata, nil } -func (c *ARMMetadataCollector) CollectMetadata(myTarget target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { +func (c *ARMMetadataCollector) CollectMetadata(t target.Target, noRoot bool, noSystemSummary bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc) (Metadata, error) { var metadata Metadata // Hostname - metadata.Hostname = myTarget.GetName() + metadata.Hostname = t.GetName() + // CPU Info (from /proc/cpuinfo) + cpuInfo, err := getCPUInfo(t) + if err != nil || len(cpuInfo) < 1 { + return Metadata{}, fmt.Errorf("failed to read cpu info: %v", err) + } // lscpu output will be used for several metadata fields - lscpu, err := getLscpu(myTarget) + lscpu, err := getLscpu(t) if err != nil { return Metadata{}, fmt.Errorf("failed to get lscpu output: %v", err) } @@ -325,22 +328,11 @@ func (c *ARMMetadataCollector) CollectMetadata(myTarget target.Target, noRoot bo for i := range metadata.CoresPerSocket { metadata.CPUSocketMap[i] = 0 } - // family, model, stepping used to get microarchitecture - family := "" // not used for ARM - model, err := parseLscpuStringField(lscpu, `^Model:\s*(.+)$`) - if err != nil { - return Metadata{}, fmt.Errorf("failed to parse model: %v", err) - } - stepping, err := parseLscpuStringField(lscpu, `^Stepping:\s*(.+)$`) + metadata.Microarchitecture, err = common.GetTargetMicroArchitecture(t, localTempDir, noRoot) if err != nil { - return Metadata{}, fmt.Errorf("failed to parse stepping: %v", err) + return Metadata{}, fmt.Errorf("failed to get ARM microarchitecture: %v", err) } - cpu, err := cpus.GetCPU(family, model, stepping) - if err != nil { - return Metadata{}, err - } - metadata.Microarchitecture = cpu.MicroArchitecture - metadata.NumGeneralPurposeCounters, err = getNumGPCountersARM(myTarget) + metadata.NumGeneralPurposeCounters, err = getNumGPCountersARM(t, localTempDir, noRoot) if err != nil { return Metadata{}, fmt.Errorf("failed to get number of general purpose counters: %v", err) } @@ -350,7 +342,7 @@ func (c *ARMMetadataCollector) CollectMetadata(myTarget target.Target, noRoot bo return Metadata{}, fmt.Errorf("failed to get metadata scripts: %v", err) } // run the scripts - scriptOutputs, err := script.RunScripts(myTarget, metadataScripts, true, localTempDir, nil, "") // nosemgrep + scriptOutputs, err := common.RunScripts(t, metadataScripts, true, localTempDir, nil, "", noRoot) // nosemgrep if err != nil { return Metadata{}, fmt.Errorf("failed to run metadata scripts: %v", err) } @@ -662,9 +654,9 @@ func getUncoreDeviceIDs(isAMDArchitecture bool, scriptOutputs map[string]script. } // getCPUInfo - reads and returns all data from /proc/cpuinfo -func getCPUInfo(myTarget target.Target) (cpuInfo []map[string]string, err error) { +func getCPUInfo(t target.Target) (cpuInfo []map[string]string, err error) { cmd := exec.Command("cat", "/proc/cpuinfo") - stdout, stderr, exitcode, err := myTarget.RunCommand(cmd, 0, true) + stdout, stderr, exitcode, err := t.RunCommand(cmd, 0, true) if err != nil { err = fmt.Errorf("failed to get cpuinfo: %s, %d, %v", stderr, exitcode, err) return @@ -687,9 +679,9 @@ func getCPUInfo(myTarget target.Target) (cpuInfo []map[string]string, err error) } // getLscpu - runs lscpu on the target and returns the output -func getLscpu(myTarget target.Target) (output string, err error) { +func getLscpu(t target.Target) (output string, err error) { cmd := exec.Command("lscpu") - output, stderr, exitcode, err := myTarget.RunCommand(cmd, 0, true) + output, stderr, exitcode, err := t.RunCommand(cmd, 0, true) if err != nil || exitcode != 0 { err = fmt.Errorf("failed to run lscpu: %s, %d, %v", stderr, exitcode, err) return @@ -834,19 +826,24 @@ func getNumGPCounters(uarch string) (numGPCounters int, err error) { // Copyright 2025 Google LLC. // SPDX-License-Identifier: BSD-3-Clause // Contributed by Edwin Chiu -func getNumGPCountersARM(target target.Target) (numGPCounters int, err error) { - numGPCounters = 0 - var cmd *exec.Cmd - if target.CanElevatePrivileges() { - cmd = exec.Command("sudo", "bash", "-c", "dmesg | grep -i \"PMU Driver\"") - } else { - cmd = exec.Command("bash", "-c", "dmesg | grep -i \"PMU Driver\"") - } - stdout, stderr, exitcode, err := target.RunCommand(cmd, 0, true) +func getNumGPCountersARM(t target.Target, localTempDir string, noRoot bool) (numGPCounters int, err error) { + getScript := script.ScriptDefinition{ + Name: "get pmu driver version line", + ScriptTemplate: "dmesg | grep -i \"PMU Driver\"", + Superuser: !noRoot, + Architectures: []string{cpus.ARMArchitecture}, + } + scriptOutput, err := common.RunScript(t, getScript, localTempDir, noRoot) if err != nil { - err = fmt.Errorf("failed to get PMU Driver line: %s, %d, %v", stderr, exitcode, err) + err = fmt.Errorf("failed to run pmu driver version script: %v", err) + return + } + lines := strings.Split(strings.TrimSpace(scriptOutput.Stdout), "\n") + if len(lines) == 0 { + err = fmt.Errorf("no output from pmu driver version script") return } + stdout := lines[0] // examples: // [ 1.339550] hw perfevents: enabled with armv8_pmuv3_0 PMU driver, 5 counters available // [ 3.663956] hw perfevents: enabled with armv8_pmuv3_0 PMU driver, 6 (0,8000001f) counters available @@ -901,10 +898,12 @@ func getARMSlots(scriptOutputs map[string]script.ScriptOutput) (slots int, err e // Used as a fallback when we cannot read the slots from sysfs func getARMSlotsByArchitecture(uarch string) (slots int, err error) { switch uarch { - case "Neoverse-N2", "Neoverse-V2": + case "Graviton4", "Axion": slots = 8 - case "Neoverse-N1", "Neoverse-V1": - slots = 6 // TODO: confirm + case "Graviton2", "Graviton3": + slots = 6 + case "AmpereOne AC04", "AmpereOne AC04_1": + slots = 10 default: err = fmt.Errorf("unsupported ARM uarch: %s", uarch) return @@ -959,7 +958,7 @@ func getPMUDriverVersion(scriptOutputs map[string]script.ScriptOutput) (version } // getTSCFreqHz returns the frequency of the Time Stamp Counter (TSC) in hertz. -// It takes a myTarget parameter of type target.Target and returns the frequency +// It takes a t parameter of type target.Target and returns the frequency // in hertz and an error if any. func getTSCFreqHz(scriptOutputs map[string]script.ScriptOutput) (freqHz int, err error) { if scriptOutputs["tsc"].Exitcode != 0 { diff --git a/cmd/metrics/metrics.go b/cmd/metrics/metrics.go index dbfc7dee..2d9b7533 100644 --- a/cmd/metrics/metrics.go +++ b/cmd/metrics/metrics.go @@ -949,7 +949,7 @@ func runCmd(cmd *cobra.Command, args []string) error { } // check if all targets have the same architecture for _, target := range myTargets { - tArch, err := target.GetArchitecture() + tArch, err := common.GetTargetArchitecture(target) if err != nil { err = fmt.Errorf("failed to get architecture: %w", err) fmt.Fprintf(os.Stderr, "Error: %v\n", err) @@ -957,7 +957,7 @@ func runCmd(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true return err } - tArch0, err := myTargets[0].GetArchitecture() + tArch0, err := common.GetTargetArchitecture(myTargets[0]) if err != nil { err = fmt.Errorf("failed to get architecture: %w", err) fmt.Fprintf(os.Stderr, "Error: %v\n", err) @@ -1141,8 +1141,8 @@ func prepareTarget(targetContext *targetContext, localTempDir string, channelErr _ = statusUpdate(myTarget.GetName(), "configuring target") // are PMUs being used on target? if !flagNoRoot { - if family, err := myTarget.GetFamily(); err == nil && cpus.IsIntelCPUFamilyStr(family) { - output, err := script.RunScript(myTarget, script.GetScriptByName(script.PMUBusyScriptName), localTempDir) + if family, err := common.GetTargetFamily(myTarget); err == nil && cpus.IsIntelCPUFamilyStr(family) { + output, err := common.RunScript(myTarget, script.GetScriptByName(script.PMUBusyScriptName), localTempDir, flagNoRoot) if err != nil { err = fmt.Errorf("failed to check if PMUs are in use: %w", err) _ = statusUpdate(myTarget.GetName(), fmt.Sprintf("Error: %v", err)) @@ -1192,7 +1192,7 @@ func prepareTarget(targetContext *targetContext, localTempDir string, channelErr perfMuxInterval := flagPerfMuxInterval if useDefaultMuxInterval { // set the default mux interval to 16ms for AMD architecture - vendor, err := myTarget.GetVendor() + vendor, err := common.GetTargetVendor(myTarget) if err == nil && vendor == cpus.AMDVendor { perfMuxInterval = 16 } @@ -1411,7 +1411,7 @@ func runPerf(myTarget target.Target, noRoot bool, processes []Process, perfComma Superuser: !noRoot, } // start goroutine to run perf, output will be streamed back in provided channels - go script.RunScriptStream(myTarget, perfStatScript, localTempDir, stdoutChannel, stderrChannel, exitcodeChannel, scriptErrorChannel, cmdChannel) + go common.RunScriptStream(myTarget, perfStatScript, localTempDir, stdoutChannel, stderrChannel, exitcodeChannel, scriptErrorChannel, cmdChannel, flagNoRoot) select { case <-cmdChannel: case err := <-scriptErrorChannel: diff --git a/cmd/metrics/nmi_watchdog.go b/cmd/metrics/nmi_watchdog.go index 23527985..8f0644da 100644 --- a/cmd/metrics/nmi_watchdog.go +++ b/cmd/metrics/nmi_watchdog.go @@ -11,6 +11,7 @@ import ( "os/exec" "strings" + "perfspect/internal/common" "perfspect/internal/script" "perfspect/internal/target" ) @@ -64,11 +65,12 @@ func setNMIWatchdog(myTarget target.Target, setting string, localTempDir string) if sysctl, err = findSysctl(myTarget); err != nil { return } - _, err = script.RunScript(myTarget, script.ScriptDefinition{ + _, err = common.RunScript(myTarget, script.ScriptDefinition{ Name: "set NMI watchdog", ScriptTemplate: fmt.Sprintf("%s kernel.nmi_watchdog=%s", sysctl, setting), Superuser: true}, - localTempDir) + localTempDir, + flagNoRoot) if err != nil { err = fmt.Errorf("failed to set NMI watchdog to %s, %v", setting, err) return diff --git a/cmd/metrics/perf_mux.go b/cmd/metrics/perf_mux.go index 28b57e10..a70eda84 100644 --- a/cmd/metrics/perf_mux.go +++ b/cmd/metrics/perf_mux.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" + "perfspect/internal/common" "perfspect/internal/script" "perfspect/internal/target" ) @@ -17,7 +18,7 @@ import ( // GetMuxIntervals - get a map of sysfs device file names to current mux value for the associated device func GetMuxIntervals(myTarget target.Target, localTempDir string) (intervals map[string]int, err error) { bash := "for file in $(find /sys/devices -type f -name perf_event_mux_interval_ms); do echo $file $(cat $file); done" - scriptOutput, err := script.RunScript(myTarget, script.ScriptDefinition{Name: "get mux intervals", ScriptTemplate: bash, Superuser: false}, localTempDir) + scriptOutput, err := common.RunScript(myTarget, script.ScriptDefinition{Name: "get mux intervals", ScriptTemplate: bash, Superuser: false}, localTempDir, flagNoRoot) if err != nil { return } @@ -39,13 +40,13 @@ func SetMuxIntervals(myTarget target.Target, intervals map[string]int, localTemp for device := range intervals { bash += fmt.Sprintf("echo %d > %s; ", intervals[device], device) } - _, err = script.RunScript(myTarget, script.ScriptDefinition{Name: "set mux intervals", ScriptTemplate: bash, Superuser: true}, localTempDir) + _, err = common.RunScript(myTarget, script.ScriptDefinition{Name: "set mux intervals", ScriptTemplate: bash, Superuser: true}, localTempDir, flagNoRoot) return } // SetAllMuxIntervals - writes the given interval (ms) to all perf mux sysfs device files func SetAllMuxIntervals(myTarget target.Target, interval int, localTempDir string) (err error) { bash := fmt.Sprintf("for file in $(find /sys/devices -type f -name perf_event_mux_interval_ms); do echo %d > $file; done", interval) - _, err = script.RunScript(myTarget, script.ScriptDefinition{Name: "set all mux intervals", ScriptTemplate: bash, Superuser: true}, localTempDir) + _, err = common.RunScript(myTarget, script.ScriptDefinition{Name: "set all mux intervals", ScriptTemplate: bash, Superuser: true}, localTempDir, flagNoRoot) return } diff --git a/cmd/metrics/process.go b/cmd/metrics/process.go index edced970..f71f1b94 100644 --- a/cmd/metrics/process.go +++ b/cmd/metrics/process.go @@ -158,7 +158,7 @@ done | sort -nr | head -n %d `, filter, maxCgroups), Superuser: true, } - output, err := script.RunScript(myTarget, hotCgroupsScript, localTempDir) + output, err := common.RunScript(myTarget, hotCgroupsScript, localTempDir, flagNoRoot) if err != nil { err = fmt.Errorf("failed to get hot cgroups: %v", err) return @@ -219,7 +219,7 @@ echo $cgroup_path `, cid), Superuser: true, } - output, err := script.RunScript(myTarget, cgroupScript, localTempDir) + output, err := common.RunScript(myTarget, cgroupScript, localTempDir, flagNoRoot) if err != nil { err = fmt.Errorf("failed to get cgroup: %v", err) return diff --git a/cmd/report/cpu.go b/cmd/report/cpu.go index 5efc548b..6022abce 100644 --- a/cmd/report/cpu.go +++ b/cmd/report/cpu.go @@ -47,9 +47,9 @@ func channelsFromOutput(outputs map[string]script.ScriptOutput) string { stepping := common.ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Stepping:\s*(.+)$`) capid4 := common.ValFromRegexSubmatch(outputs[script.LspciBitsScriptName].Stdout, `^([0-9a-fA-F]+)`) devices := common.ValFromRegexSubmatch(outputs[script.LspciDevicesScriptName].Stdout, `^([0-9]+)`) - cpu, err := cpus.GetCPUExtended(family, model, stepping, capid4, devices) + cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) if err != nil { - slog.Error("error getting CPU from CPUdb", slog.String("error", err.Error())) + slog.Error("error getting CPU characteristics", slog.String("error", err.Error())) return "" } return fmt.Sprintf("%d", cpu.MemoryChannelCount) diff --git a/internal/common/common.go b/internal/common/common.go index f44ea1e3..4b6589ea 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -523,7 +523,7 @@ func outputsFromTargets(cmd *cobra.Command, myTargets []target.Target, tables [] targetTables = append(targetTables, []table.TableDefinition{}) targetScriptNames = append(targetScriptNames, []string{}) for _, tbl := range tables { - if table.IsTableForTarget(tbl, target) { + if isTableForTarget(tbl, target, localTempDir) { // add table to list of tables to collect targetTables[targetIdx] = append(targetTables[targetIdx], tbl) // add scripts to list of scripts to run @@ -569,6 +569,40 @@ func outputsFromTargets(cmd *cobra.Command, myTargets []target.Target, tables [] return orderedTargetScriptOutputs, nil } +// isTableForTarget checks if the given table is applicable for the specified target +func isTableForTarget(tbl table.TableDefinition, t target.Target, localTempDir string) bool { + if len(tbl.Architectures) > 0 { + architecture, err := t.GetArchitecture() + if err != nil { + slog.Error("failed to get architecture for target", slog.String("target", t.GetName()), slog.String("error", err.Error())) + return false + } + if !slices.Contains(tbl.Architectures, architecture) { + return false + } + } + if len(tbl.Vendors) > 0 { + vendor, err := GetTargetVendor(t) + if err != nil { + slog.Error("failed to get vendor for target", slog.String("target", t.GetName()), slog.String("error", err.Error())) + return false + } + if !slices.Contains(tbl.Vendors, vendor) { + return false + } + } + if len(tbl.MicroArchitectures) > 0 { + uarch, err := GetTargetMicroArchitecture(t, localTempDir, false) + if err != nil { + slog.Error("failed to get microarchitecture for target", slog.String("target", t.GetName()), slog.String("error", err.Error())) + } + if !slices.Contains(tbl.MicroArchitectures, uarch) && !slices.Contains(tbl.MicroArchitectures, strings.Split(uarch, "_")[0]) { + return false + } + } + return true +} + // elevatedPrivilegesRequired returns true if any of the scripts needed for the tables require elevated privileges func elevatedPrivilegesRequired(tables []table.TableDefinition) bool { for _, tbl := range tables { @@ -591,7 +625,7 @@ func collectOnTarget(myTarget target.Target, scriptsToRun []script.ScriptDefinit } else if duration != "0" && duration != "" { status += fmt.Sprintf(" for %s seconds", duration) } - scriptOutputs, err := script.RunScripts(myTarget, scriptsToRun, true, localTempDir, statusUpdate, status) + scriptOutputs, err := RunScripts(myTarget, scriptsToRun, true, localTempDir, statusUpdate, status, false) if err != nil { if statusUpdate != nil { _ = statusUpdate(myTarget.GetName(), fmt.Sprintf("error collecting data: %v", err)) diff --git a/internal/common/table_helpers.go b/internal/common/table_helpers.go index b3b36e30..d229ea73 100644 --- a/internal/common/table_helpers.go +++ b/internal/common/table_helpers.go @@ -196,11 +196,12 @@ func UarchFromOutput(outputs map[string]script.ScriptOutput) string { stepping := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Stepping:\s*(.+)$`) capid4 := ValFromRegexSubmatch(outputs[script.LspciBitsScriptName].Stdout, `^([0-9a-fA-F]+)`) devices := ValFromRegexSubmatch(outputs[script.LspciDevicesScriptName].Stdout, `^([0-9]+)`) - cpu, err := cpus.GetCPUExtended(family, model, stepping, capid4, devices) - if err == nil { - return cpu.MicroArchitecture + cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) + if err != nil { + slog.Error("error getting CPU characteristics", slog.String("error", err.Error())) + return "" } - return "" + return cpu.MicroArchitecture } func HyperthreadingFromOutput(outputs map[string]script.ScriptOutput) string { @@ -239,8 +240,9 @@ func HyperthreadingFromOutput(outputs map[string]script.ScriptOutput) string { slog.Error("error parsing cores per sockets from lscpu") return "" } - cpu, err := cpus.GetCPUExtended(family, model, stepping, "", "") + cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, "", "")) if err != nil { + slog.Warn("error getting CPU characteristics", slog.String("error", err.Error())) return "" } if numOnlineCpus > 0 && numOnlineCpus < numCPUs { diff --git a/internal/common/targets.go b/internal/common/targets.go index 30ab6026..02cb13e8 100644 --- a/internal/common/targets.go +++ b/internal/common/targets.go @@ -11,6 +11,7 @@ import ( "os/user" "path" "perfspect/internal/cpus" + "perfspect/internal/progress" "perfspect/internal/script" "perfspect/internal/target" "perfspect/internal/util" @@ -542,3 +543,306 @@ func isDirNoExec(t target.Target, dir string) (bool, error) { } return false, fmt.Errorf("filesystem %s and mount point %s are not found in mount records", filesystem, mountedOn) } + +func GetTargetArchitecture(t target.Target) (string, error) { + return t.GetArchitecture() +} + +func GetTargetVendor(t target.Target) (string, error) { + vendor := t.GetVendor() + if vendor == "" { + cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^Vendor ID:\" | awk '{print $NF}'") + var err error + vendor, _, _, err = t.RunCommand(cmd, 0, true) + if err != nil { + return "", fmt.Errorf("failed to get target CPU vendor: %v", err) + } + vendor = strings.TrimSpace(vendor) + t.SetVendor(vendor) + } + return vendor, nil +} + +func GetTargetFamily(t target.Target) (string, error) { + family := t.GetFamily() + if family == "" { + cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^CPU family:\" | awk '{print $NF}'") + var err error + family, _, _, err = t.RunCommand(cmd, 0, true) + if err != nil { + return "", fmt.Errorf("failed to get target CPU family: %v", err) + } + family = strings.TrimSpace(family) + t.SetFamily(family) + } + return family, nil +} + +func GetTargetModel(t target.Target) (string, error) { + model := t.GetModel() + if model == "" { + cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^Model:\" | awk '{print $NF}'") + var err error + model, _, _, err = t.RunCommand(cmd, 0, true) + if err != nil { + return "", fmt.Errorf("failed to get target CPU model: %v", err) + } + model = strings.TrimSpace(model) + t.SetModel(model) + } + return model, nil +} + +func GetTargetStepping(t target.Target) (string, error) { + stepping := t.GetStepping() + if stepping == "" { + cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^Stepping:\" | awk '{print $NF}'") + var err error + stepping, _, _, err = t.RunCommand(cmd, 0, true) + if err != nil { + return "", fmt.Errorf("failed to get target CPU stepping: %v", err) + } + stepping = strings.TrimSpace(stepping) + t.SetStepping(stepping) + } + return stepping, nil +} + +func GetTargetCapid4(t target.Target, localTempDir string, noRoot bool) (string, error) { + capid4 := t.GetCapid4() + if capid4 == "" { + getScript := script.GetScriptByName(script.LspciBitsScriptName) + scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop + if err != nil { + return "", fmt.Errorf("failed to run cpuid capid4 script: %v", err) + } + capid4 = strings.TrimSpace(scriptOutput.Stdout) + t.SetCapid4(capid4) + } + return capid4, nil +} + +func GetTargetDevices(t target.Target, localTempDir string, noRoot bool) (string, error) { + devices := t.GetDevices() + if devices == "" { + getScript := script.GetScriptByName(script.LspciDevicesScriptName) + scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop + if err != nil { + return "", fmt.Errorf("failed to run cpu devices script: %v", err) + } + devices = strings.TrimSpace(scriptOutput.Stdout) + t.SetDevices(devices) + } + return devices, nil +} + +func GetTargetImplementer(t target.Target, localTempDir string, noRoot bool) (string, error) { + implementer := t.GetImplementer() + if implementer == "" { + getScript := script.ScriptDefinition{ + Name: "get target implementer", + ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU implementer\" | head -1 | awk '{print $NF}'", + Superuser: !noRoot, + } + scriptOutput, err := script.RunScript(t, getScript, localTempDir) + if err != nil { + return "", fmt.Errorf("failed to run implementer retrieval script: %v", err) + } + implementer = strings.TrimSpace(scriptOutput.Stdout) + t.SetImplementer(implementer) + } + return implementer, nil +} + +func GetTargetPart(t target.Target, localTempDir string, noRoot bool) (string, error) { + part := t.GetPart() + if part == "" { + getScript := script.ScriptDefinition{ + Name: "get target part", + ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU part\" | head -1 | awk '{print $NF}'", + Superuser: !noRoot, + } + scriptOutput, err := script.RunScript(t, getScript, localTempDir) + if err != nil { + return "", fmt.Errorf("failed to run part retrieval script: %v", err) + } + part = strings.TrimSpace(scriptOutput.Stdout) + t.SetPart(part) + } + return part, nil +} + +func GetTargetDmidecodePart(t target.Target, localTempDir string, noRoot bool) (string, error) { + dmidecodePart := t.GetDmidecodePart() + if dmidecodePart == "" { + getScript := script.ScriptDefinition{ + Name: "get dmidecode processor part number", + ScriptTemplate: "dmidecode -t processor | grep -m 1 \"Part Number\" | awk -F': ' '{print $2}'", + Superuser: !noRoot, + Depends: []string{"dmidecode"}, + } + scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop + if err != nil { + return "", fmt.Errorf("failed to run dmidecode part number script: %v", err) + } + dmidecodePart = strings.TrimSpace(scriptOutput.Stdout) + t.SetDmidecodePart(dmidecodePart) + } + return dmidecodePart, nil +} + +func GetTargetMicroArchitecture(t target.Target, localTempDir string, noRoot bool) (string, error) { + uarch := t.GetMicroarchitecture() + if uarch == "" { + arch, err := GetTargetArchitecture(t) + if err != nil { + return "", err + } + switch arch { + case cpus.X86Architecture: + uarch, err = GetX86TargetMicroarchitecture(t, localTempDir, noRoot) + case cpus.ARMArchitecture: + uarch, err = GetARMTargetMicroarchitecture(t, localTempDir, noRoot) + default: + uarch, err = "", fmt.Errorf("unsupported architecture: %s", arch) + } + if err != nil { + return "", err + } + t.SetMicroarchitecture(uarch) + } + return uarch, nil +} + +func GetX86TargetMicroarchitecture(t target.Target, localTempDir string, noRoot bool) (string, error) { + family, err := GetTargetFamily(t) + if err != nil { + return "", err + } + model, err := GetTargetModel(t) + if err != nil { + return "", err + } + stepping, err := GetTargetStepping(t) + if err != nil { + return "", err + } + capid4, err := GetTargetCapid4(t, localTempDir, noRoot) + if err != nil { + return "", err + } + devices, err := GetTargetDevices(t, localTempDir, noRoot) + if err != nil { + return "", err + } + cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) + if err != nil { + return "", err + } + return cpu.MicroArchitecture, nil +} + +func GetARMTargetMicroarchitecture(t target.Target, localTempDir string, noRoot bool) (string, error) { + implementer, err := GetTargetImplementer(t, localTempDir, noRoot) + if err != nil { + return "", err + } + part, err := GetTargetPart(t, localTempDir, noRoot) + if err != nil { + return "", err + } + dmidecodePart, err := GetTargetDmidecodePart(t, localTempDir, noRoot) + if err != nil { + return "", err + } + cpu, err := cpus.GetCPU(cpus.NewARMIdentifier(implementer, part, dmidecodePart)) + if err != nil { + return "", err + } + return cpu.MicroArchitecture, nil +} + +func ScriptSupportedOnTarget(t target.Target, scriptDef script.ScriptDefinition, localTempDir string, noRoot bool) (bool, error) { + if len(scriptDef.Architectures) > 0 { + arch, err := GetTargetArchitecture(t) + if err != nil { + return false, err + } + if !slices.Contains(scriptDef.Architectures, arch) { + slog.Info("script not supported on target architecture", slog.String("script", scriptDef.Name), slog.String("target", t.GetName()), slog.String("architecture", arch)) + return false, nil + } + } + if len(scriptDef.Vendors) > 0 { + vendor, err := GetTargetVendor(t) + if err != nil { + return false, err + } + if !slices.Contains(scriptDef.Vendors, vendor) { + slog.Info("script not supported on target CPU vendor", slog.String("script", scriptDef.Name), slog.String("target", t.GetName()), slog.String("vendor", vendor)) + return false, nil + } + } + if len(scriptDef.MicroArchitectures) > 0 { + uarch, err := GetTargetMicroArchitecture(t, localTempDir, noRoot) + if err != nil { + return false, err + } + if !slices.Contains(scriptDef.MicroArchitectures, uarch) && !slices.Contains(scriptDef.MicroArchitectures, strings.Split(uarch, "_")[0]) { + slog.Info("script not supported on target CPU microarchitecture", slog.String("script", scriptDef.Name), slog.String("target", t.GetName()), slog.String("microarchitecture", uarch)) + return false, nil + } + } + return true, nil +} + +func FilterScriptsForTarget(t target.Target, scriptDefs []script.ScriptDefinition, localTempDir string, noRoot bool) (supportedScripts []script.ScriptDefinition, err error) { + for _, scriptDef := range scriptDefs { + supported, err := ScriptSupportedOnTarget(t, scriptDef, localTempDir, noRoot) + if err != nil { + slog.Warn("failed to determine if script is compatible with target", slog.String("script", scriptDef.Name), slog.String("target", t.GetName())) + continue + } + if supported { + supportedScripts = append(supportedScripts, scriptDef) + } + } + return +} + +// Create wrappers around script.RunScript* that first check if the scripts are compatible with the target + +func RunScript(t target.Target, s script.ScriptDefinition, localTempDir string, noRoot bool) (script.ScriptOutput, error) { + supported, err := ScriptSupportedOnTarget(t, s, localTempDir, noRoot) + if err != nil { + return script.ScriptOutput{}, fmt.Errorf("failed to check if script is supported on target %v", err) + } + if !supported { + return script.ScriptOutput{}, fmt.Errorf("script %s not supported on target %s", s.Name, t.GetName()) + } + return script.RunScript(t, s, localTempDir) +} + +func RunScripts(t target.Target, s []script.ScriptDefinition, ignoreScriptErrors bool, localTempDir string, statusUpdate progress.MultiSpinnerUpdateFunc, collectingStatusMsg string, noRoot bool) (map[string]script.ScriptOutput, error) { + supportedScripts, err := FilterScriptsForTarget(t, s, localTempDir, noRoot) + if err != nil { + return nil, fmt.Errorf("failed to check if scripts are supported on target %v", err) + } + if len(supportedScripts) == 0 { + return nil, fmt.Errorf("script are not supported on target %s", t.GetName()) + } + return script.RunScripts(t, supportedScripts, ignoreScriptErrors, localTempDir, statusUpdate, collectingStatusMsg) +} + +func RunScriptStream(t target.Target, s script.ScriptDefinition, localTempDir string, stdoutChannel chan []byte, stderrChannel chan []byte, exitcodeChannel chan int, errorChannel chan error, cmdChannel chan *exec.Cmd, noRoot bool) { + supported, err := ScriptSupportedOnTarget(t, s, localTempDir, noRoot) + if err != nil { + errorChannel <- fmt.Errorf("failed to check if script is supported on target %v", err) + return + } + if !supported { + errorChannel <- fmt.Errorf("script %s not supported on target %s", s.Name, t.GetName()) + return + } + script.RunScriptStream(t, s, localTempDir, stdoutChannel, stderrChannel, exitcodeChannel, errorChannel, cmdChannel) +} diff --git a/internal/cpus/cpu_defs.go b/internal/cpus/cpu_defs.go deleted file mode 100644 index f37af735..00000000 --- a/internal/cpus/cpu_defs.go +++ /dev/null @@ -1,294 +0,0 @@ -// Package cpus provides CPU definitions and lookup utilities for microarchitecture, -// family, model, and stepping, supporting both x86 and ARM architectures. -package cpus - -// Copyright (C) 2021-2025 Intel Corporation -// SPDX-License-Identifier: BSD-3-Clause - -import ( - "fmt" - "regexp" - "slices" - "strconv" - "strings" -) - -const IntelVendor = "GenuineIntel" -const AMDVendor = "AuthenticAMD" - -const X86Architecture = "x86_64" -const ARMArchitecture = "aarch64" - -var IntelFamilies = []int{6, 19} - -// IsIntelCPUFamily checks if the CPU family corresponds to Intel CPUs. -func IsIntelCPUFamily(family int) bool { - return slices.Contains(IntelFamilies, family) -} - -// IsIntelCPUFamilyStr checks if the CPU family string corresponds to Intel CPUs. -func IsIntelCPUFamilyStr(familyStr string) bool { - family, err := strconv.Atoi(familyStr) - if err != nil { - return false - } - return IsIntelCPUFamily(family) -} - -// CPUDefinition - used to lookup micro architecture and channels by family, model, and stepping -// -// The model and stepping fields will be interpreted as regular expressions -// An empty stepping field means 'any' stepping -type CPUDefinition struct { - MicroArchitecture string - Family string - Model string - Stepping string - Architecture string - MemoryChannelCount int - LogicalThreadCount int - CacheWayCount int -} - -func (c CPUDefinition) GetMicroArchitecture() string { - return c.MicroArchitecture -} - -func (c CPUDefinition) GetShortMicroArchitecture() string { - return strings.Split(c.MicroArchitecture, "_")[0] -} - -// GetCPU retrieves the CPU structure that matches the provided args -func GetCPU(family, model, stepping string) (cpu CPUDefinition, err error) { - return GetCPUExtended(family, model, stepping, "", "") -} - -var cpuDefinitions = []CPUDefinition{ - // Intel Core CPUs - {MicroArchitecture: "HSW", Family: "6", Model: "(50|69|70)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Haswell - {MicroArchitecture: "BDW", Family: "6", Model: "(61|71)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Broadwell - {MicroArchitecture: "SKL", Family: "6", Model: "(78|94)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Skylake - {MicroArchitecture: "KBL", Family: "6", Model: "(142|158)", Stepping: "9", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Kabylake - {MicroArchitecture: "CFL", Family: "6", Model: "(142|158)", Stepping: "(10|11|12|13)", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Coffeelake - {MicroArchitecture: "RKL", Family: "6", Model: "167", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Rocket Lake - {MicroArchitecture: "TGL", Family: "6", Model: "(140|141)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Tiger Lake - {MicroArchitecture: "ADL", Family: "6", Model: "(151|154)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Alder Lake - {MicroArchitecture: "MTL", Family: "6", Model: "170", Stepping: "4", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Meteor Lake - {MicroArchitecture: "ARL", Family: "6", Model: "197", Stepping: "2", Architecture: X86Architecture, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Arrow Lake - // Intel Xeon CPUs - {MicroArchitecture: "HSX", Family: "6", Model: "63", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Haswell - {MicroArchitecture: "BDX", Family: "6", Model: "(79|86)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Broadwell - {MicroArchitecture: "SKX", Family: "6", Model: "85", Stepping: "(0|1|2|3|4)", Architecture: X86Architecture, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Skylake - {MicroArchitecture: "CLX", Family: "6", Model: "85", Stepping: "(5|6|7)", Architecture: X86Architecture, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cascadelake - {MicroArchitecture: "CPX", Family: "6", Model: "85", Stepping: "11", Architecture: X86Architecture, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cooperlake - {MicroArchitecture: "ICX", Family: "6", Model: "(106|108)", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 12}, // Icelake - {MicroArchitecture: "SPR", Family: "6", Model: "143", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - generic - {MicroArchitecture: "SPR_MCC", Family: "6", Model: "143", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - MCC - {MicroArchitecture: "SPR_XCC", Family: "6", Model: "143", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - XCC - {MicroArchitecture: "EMR", Family: "6", Model: "207", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - generic - {MicroArchitecture: "EMR_MCC", Family: "6", Model: "207", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - MCC - {MicroArchitecture: "EMR_XCC", Family: "6", Model: "207", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 20}, // Emerald Rapids - XCC - {MicroArchitecture: "SRF", Family: "6", Model: "175", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 0, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - {MicroArchitecture: "SRF_SP", Family: "6", Model: "175", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - {MicroArchitecture: "SRF_AP", Family: "6", Model: "175", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - {MicroArchitecture: "GNR", Family: "6", Model: "173", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 0, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - generic - {MicroArchitecture: "GNR_X1", Family: "6", Model: "173", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (MCC/LCC) - {MicroArchitecture: "GNR_X2", Family: "6", Model: "173", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (XCC) - {MicroArchitecture: "GNR_X3", Family: "6", Model: "173", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - AP (UCC) - {MicroArchitecture: "GNR_D", Family: "6", Model: "174", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 0, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D - {MicroArchitecture: "CWF", Family: "6", Model: "221", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 0}, // Clearwater Forest - generic - {MicroArchitecture: "DMR", Family: "19", Model: "1", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids - // AMD CPUs - {MicroArchitecture: "Naples", Family: "23", Model: "1", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Naples - {MicroArchitecture: "Rome", Family: "23", Model: "49", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Rome - {MicroArchitecture: "Milan", Family: "25", Model: "1", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Milan - {MicroArchitecture: "Genoa", Family: "25", Model: "(1[6-9]|2[0-9]|3[01])", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Genoa, model 16-31 - {MicroArchitecture: "Bergamo", Family: "25", Model: "(16[0-9]|17[0-5])", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Bergamo, model 160-175 - {MicroArchitecture: "Turin (Zen 5)", Family: "26", Model: "2", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5) - {MicroArchitecture: "Turin (Zen 5c)", Family: "26", Model: "17", Stepping: "", Architecture: X86Architecture, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5c) - - // ARM CPUs - {MicroArchitecture: "Neoverse-N1", Family: "", Model: "1", Stepping: "r3p1", Architecture: ARMArchitecture, MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 0}, // AWS Graviton 2 ([m|c|r]6g) - {MicroArchitecture: "Neoverse-V1", Family: "", Model: "1", Stepping: "r1p1", Architecture: ARMArchitecture, MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 0}, // AWS Graviton 3 ([m|c|r]7g) - {MicroArchitecture: "Neoverse-V2", Family: "", Model: "1", Stepping: "r0p1", Architecture: ARMArchitecture, MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 0}, // AWS Graviton 4 ([m|c|r]8g), GCP Axion (c4a) -} - -// GetCPUExtended retrieves the CPU structure that matches the provided args -// capid4 needed to differentiate EMR MCC from EMR XCC -// -// capid4: $ lspci -s $(lspci | grep 325b | awk 'NR==1{{print $1}}') -xxx | awk '$1 ~ /^90/{{print $9 $8 $7 $6; exit}}' -// -// devices needed to differentiate GNR X1/2/3 -// -// devices: $ lspci -d 8086:3258 | wc -l -func GetCPUExtended(family, model, stepping, capid4, devices string) (cpu CPUDefinition, err error) { - for _, info := range cpuDefinitions { - // if family matches - if info.Family == family { - var reModel *regexp.Regexp - reModel, err = regexp.Compile(info.Model) - if err != nil { - return - } - // if model matches - if reModel.FindString(model) == model { - // if there is a stepping - if info.Stepping != "" { - var reStepping *regexp.Regexp - reStepping, err = regexp.Compile(info.Stepping) - if err != nil { - return - } - // if stepping does NOT match - if reStepping.FindString(stepping) == "" { - // no match - continue - } - } - cpu = info - if cpu.Family == "6" && (cpu.Model == "143" || cpu.Model == "207" || cpu.Model == "173" || cpu.Model == "175") { // SPR, EMR, GNR, SRF - cpu, err = getSpecificCPU(family, model, capid4, devices) - } - return - } - } - } - err = fmt.Errorf("CPU match not found for family %s, model %s, stepping %s", family, model, stepping) - return -} - -func GetCPUByMicroArchitecture(uarch string) (cpu CPUDefinition, err error) { - for _, info := range cpuDefinitions { - if strings.EqualFold(info.MicroArchitecture, uarch) { - cpu = info - return - } - } - err = fmt.Errorf("CPU match not found for uarch %s", uarch) - return -} - -func getSpecificCPU(family, model, capid4, devices string) (cpu CPUDefinition, err error) { - if family == "6" && model == "143" { // SPR - cpu, err = getSPRCPU(capid4) - } else if family == "6" && model == "207" { // EMR - cpu, err = getEMRCPU(capid4) - } else if family == "6" && model == "173" { // GNR - cpu, err = getGNRCPU(devices) - } else if family == "6" && model == "175" { // SRF - cpu, err = getSRFCPU(devices) - } - return -} - -func getSPRCPU(capid4 string) (cpu CPUDefinition, err error) { - var uarch string - if capid4 != "" { - var bits int64 - var capid4Int int64 - capid4Int, err = strconv.ParseInt(capid4, 16, 64) - if err != nil { - return - } - bits = (capid4Int >> 6) & 0b11 - switch bits { - case 3: - uarch = "SPR_XCC" - case 1: - uarch = "SPR_MCC" - } - } - if uarch == "" { - uarch = "SPR" - } - for _, info := range cpuDefinitions { - if info.MicroArchitecture == uarch { - cpu = info - return - } - } - err = fmt.Errorf("did not find matching SPR architecture in CPU database: %s", uarch) - return -} - -func getEMRCPU(capid4 string) (cpu CPUDefinition, err error) { - var uarch string - if capid4 != "" { - var bits int64 - var capid4Int int64 - capid4Int, err = strconv.ParseInt(capid4, 16, 64) - if err != nil { - return - } - bits = (capid4Int >> 6) & 0b11 - switch bits { - case 3: - uarch = "EMR_XCC" - case 1: - uarch = "EMR_MCC" - } - } - if uarch == "" { - uarch = "EMR" - } - for _, info := range cpuDefinitions { - if info.MicroArchitecture == uarch { - cpu = info - return - } - } - err = fmt.Errorf("did not find matching EMR architecture in CPU database: %s", uarch) - return -} - -func getGNRCPU(devices string) (cpu CPUDefinition, err error) { - var uarch string - if devices != "" { - d, err := strconv.Atoi(devices) - if err == nil && d != 0 { - if d%5 == 0 { // device count is multiple of 5 - uarch = "GNR_X3" - } else if d%4 == 0 { // device count is multiple of 4 - uarch = "GNR_X2" - } else if d%3 == 0 { // device count is multiple of 3 - uarch = "GNR_X1" - } - } - } - if uarch == "" { - uarch = "GNR" - } - for _, info := range cpuDefinitions { - if info.MicroArchitecture == uarch { - cpu = info - return - } - } - err = fmt.Errorf("did not find matching GNR architecture in CPU database: %s", uarch) - return -} - -func getSRFCPU(devices string) (cpu CPUDefinition, err error) { - var uarch string - if devices != "" { - d, err := strconv.Atoi(devices) - if err == nil && d != 0 { - if d%3 == 0 { // device count is multiple of 3 - uarch = "SRF_SP" - } else if d%4 == 0 { // device count is multiple of 4 - uarch = "SRF_AP" - } - } - } - if uarch == "" { - uarch = "SRF" - } - for _, info := range cpuDefinitions { - if info.MicroArchitecture == uarch { - cpu = info - return - } - } - err = fmt.Errorf("did not find matching SRF architecture in CPU database: %s", uarch) - return -} diff --git a/internal/cpus/cpu_defs_test.go b/internal/cpus/cpu_defs_test.go deleted file mode 100644 index 92dfa758..00000000 --- a/internal/cpus/cpu_defs_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package cpus - -// Copyright (C) 2021-2025 Intel Corporation -// SPDX-License-Identifier: BSD-3-Clause - -import ( - "fmt" - "testing" -) - -func TestGetCPU(t *testing.T) { - // should fail - _, err := GetCPU("0", "0", "0") - if err == nil { - t.Fatal(err) - } - - cpu, err := GetCPU("6", "85", "4") //SKX - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "SKX" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("6", "85", "7") //CLX - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "CLX" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("6", "85", "6") //CLX - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "CLX" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("6", "108", "0") //ICX - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "ICX" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("6", "71", "0") //BDW - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "BDW" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPUExtended("6", "173", "", "", "10") // GNR_X3 - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "GNR_X3" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 12 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPUExtended("6", "173", "", "", "8") // GNR_X2 - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "GNR_X2" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPUExtended("6", "173", "", "", "6") // GNR_X1 - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "GNR_X1" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPU("6", "173", "") // GNR with no differentiation - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "GNR" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPUExtended("6", "207", "", "c0", "") // EMR XCC - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "EMR_XCC" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPUExtended("6", "207", "", "40", "") // EMR MCC - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "EMR_MCC" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPU("6", "207", "") // EMR with no differentiation - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "EMR" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPU("25", "1", "") // Milan - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "Milan" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 8 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPU("25", "17", "") // Genoa - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "Genoa" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - if cpu.MemoryChannelCount != 12 { - t.Fatal(fmt.Errorf("Incorrect channel count: %d", cpu.MemoryChannelCount)) - } - - cpu, err = GetCPU("6", "69", "99") //HSW - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "HSW" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("6", "70", "") //HSW - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "HSW" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } - - cpu, err = GetCPU("", "1", "r3p1") // N1 - if err != nil { - t.Fatal(err) - } - if cpu.MicroArchitecture != "Neoverse-N1" { - t.Fatal(fmt.Errorf("Found the wrong CPU: %s", cpu.MicroArchitecture)) - } -} diff --git a/internal/cpus/cpus.go b/internal/cpus/cpus.go new file mode 100644 index 00000000..be1d6f57 --- /dev/null +++ b/internal/cpus/cpus.go @@ -0,0 +1,429 @@ +// Package cpus provides CPU definitions and lookup utilities for microarchitecture, +// family, model, and stepping, supporting both x86 and ARM architectures. +package cpus + +// Copyright (C) 2021-2025 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause + +import ( + "fmt" + "regexp" + "slices" + "strconv" + "strings" +) + +const IntelVendor = "GenuineIntel" +const AMDVendor = "AuthenticAMD" + +const X86Architecture = "x86_64" +const ARMArchitecture = "aarch64" + +var IntelFamilies = []int{6, 19} + +type CPUCharacteristics struct { + MicroArchitecture string + MemoryChannelCount int + LogicalThreadCount int + CacheWayCount int +} + +type CPUIdentifierX86 struct { + Family string // from lscpu + Model string // from lscpu -- regex match + Stepping string // from lscpu -- empty field means 'any' stepping, otherwise regex match + Capid4 string // from lspci -- used to differentiate some CPUs + Devices string // from lspci -- used to differentiate some CPUs +} + +type CPUIdentifierARM struct { + Implementer string // from /proc/cpuinfo + Part string // from /proc/cpuinfo + DmidecodePart string // from dmidecode -- processor part number +} + +// CPUIdentifier is a unified type that can hold either x86 or ARM identification +type CPUIdentifier struct { + CPUIdentifierX86 + CPUIdentifierARM + + // Architecture hint (optional, can be auto-detected) + Architecture string +} + +// cpuCharacteristicsMap maps microarchitecture name to CPU characteristics +var cpuCharacteristicsMap = map[string]CPUCharacteristics{ + // Intel Core CPUs + "HSW": {MicroArchitecture: "HSW", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Haswell + "BDW": {MicroArchitecture: "BDW", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Broadwell + "SKL": {MicroArchitecture: "SKL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Skylake + "KBL": {MicroArchitecture: "KBL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Kabylake + "CFL": {MicroArchitecture: "CFL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Coffeelake + "RKL": {MicroArchitecture: "RKL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Rocket Lake + "TGL": {MicroArchitecture: "TGL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Tiger Lake + "ADL": {MicroArchitecture: "ADL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Alder Lake + "MTL": {MicroArchitecture: "MTL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Meteor Lake + "ARL": {MicroArchitecture: "ARL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Arrow Lake + // Intel Xeon CPUs + "HSX": {MicroArchitecture: "HSX", MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Haswell + "BDX": {MicroArchitecture: "BDX", MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Broadwell + "SKX": {MicroArchitecture: "SKX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Skylake + "CLX": {MicroArchitecture: "CLX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cascadelake + "CPX": {MicroArchitecture: "CPX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cooperlake + "ICX": {MicroArchitecture: "ICX", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 12}, // Icelake + "SPR": {MicroArchitecture: "SPR", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - generic + "SPR_MCC": {MicroArchitecture: "SPR_MCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - MCC + "SPR_XCC": {MicroArchitecture: "SPR_XCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - XCC + "EMR": {MicroArchitecture: "EMR", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - generic + "EMR_MCC": {MicroArchitecture: "EMR_MCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - MCC + "EMR_XCC": {MicroArchitecture: "EMR_XCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 20}, // Emerald Rapids - XCC + "SRF": {MicroArchitecture: "SRF", MemoryChannelCount: 0, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + "SRF_SP": {MicroArchitecture: "SRF_SP", MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + "SRF_AP": {MicroArchitecture: "SRF_AP", MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + "GNR": {MicroArchitecture: "GNR", MemoryChannelCount: 0, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - generic + "GNR_X1": {MicroArchitecture: "GNR_X1", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (MCC/LCC) + "GNR_X2": {MicroArchitecture: "GNR_X2", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (XCC) + "GNR_X3": {MicroArchitecture: "GNR_X3", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - AP (UCC) + "GNR_D": {MicroArchitecture: "GNR_D", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D + "CWF": {MicroArchitecture: "CWF", MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 0}, // Clearwater Forest - generic + "DMR": {MicroArchitecture: "DMR", MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids + // AMD CPUs + "Naples": {MicroArchitecture: "Naples", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Naples + "Rome": {MicroArchitecture: "Rome", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Rome + "Milan": {MicroArchitecture: "Milan", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Milan + "Genoa": {MicroArchitecture: "Genoa", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Genoa + "Bergamo": {MicroArchitecture: "Bergamo", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Bergamo + "Turin (Zen 5)": {MicroArchitecture: "Turin (Zen 5)", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5) + "Turin (Zen 5c)": {MicroArchitecture: "Turin (Zen 5c)", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5c) + // ARM CPUs + "Graviton2": {MicroArchitecture: "Graviton2", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 + "Graviton3": {MicroArchitecture: "Graviton3", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 + "Graviton4": {MicroArchitecture: "Graviton4", MemoryChannelCount: 12, LogicalThreadCount: 1}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 + "Axion": {MicroArchitecture: "Axion", MemoryChannelCount: 12, LogicalThreadCount: 1}, // GCP Axion (c4a) Neoverse-V2 + "Altra Family": {MicroArchitecture: "Altra Family", MemoryChannelCount: 8, LogicalThreadCount: 1}, // Ampere Altra + "AmpereOne AC03": {MicroArchitecture: "AmpereOne AC03", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC03 + "AmpereOne AC04": {MicroArchitecture: "AmpereOne AC04", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC04 + "AmpereOne AC04_1": {MicroArchitecture: "AmpereOne AC04_1", MemoryChannelCount: 12, LogicalThreadCount: 1}, // AmpereOne AC04_1 +} + +// cpuIdentifiersX86 maps x86 CPU identification to microarchitecture names +var cpuIdentifiersX86 = []struct { + Identifier CPUIdentifierX86 + MicroArchitecture string +}{ + // Intel Core CPUs + {CPUIdentifierX86{Family: "6", Model: "(50|69|70)", Stepping: "", Capid4: "", Devices: ""}, "HSW"}, // Haswell + {CPUIdentifierX86{Family: "6", Model: "(61|71)", Stepping: "", Capid4: "", Devices: ""}, "BDW"}, // Broadwell + {CPUIdentifierX86{Family: "6", Model: "(78|94)", Stepping: "", Capid4: "", Devices: ""}, "SKL"}, // Skylake + {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "9", Capid4: "", Devices: ""}, "KBL"}, // Kabylake + {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "(10|11|12|13)", Capid4: "", Devices: ""}, "CFL"}, // Coffeelake + {CPUIdentifierX86{Family: "6", Model: "167", Stepping: "", Capid4: "", Devices: ""}, "RKL"}, // Rocket Lake + {CPUIdentifierX86{Family: "6", Model: "(140|141)", Stepping: "", Capid4: "", Devices: ""}, "TGL"}, // Tiger Lake + {CPUIdentifierX86{Family: "6", Model: "(151|154)", Stepping: "", Capid4: "", Devices: ""}, "ADL"}, // Alder Lake + {CPUIdentifierX86{Family: "6", Model: "170", Stepping: "4", Capid4: "", Devices: ""}, "MTL"}, // Meteor Lake + {CPUIdentifierX86{Family: "6", Model: "197", Stepping: "2", Capid4: "", Devices: ""}, "ARL"}, // Arrow Lake + // Intel Xeon CPUs + {CPUIdentifierX86{Family: "6", Model: "63", Stepping: "", Capid4: "", Devices: ""}, "HSX"}, // Haswell + {CPUIdentifierX86{Family: "6", Model: "(79|86)", Stepping: "", Capid4: "", Devices: ""}, "BDX"}, // Broadwell + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(0|1|2|3|4)", Capid4: "", Devices: ""}, "SKX"}, // Skylake + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(5|6|7)", Capid4: "", Devices: ""}, "CLX"}, // Cascadelake + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "11", Capid4: "", Devices: ""}, "CPX"}, // Cooperlake + {CPUIdentifierX86{Family: "6", Model: "(106|108)", Stepping: "", Capid4: "", Devices: ""}, "ICX"}, // Icelake + {CPUIdentifierX86{Family: "6", Model: "143", Stepping: "", Capid4: "", Devices: ""}, "SPR"}, // Sapphire Rapids + {CPUIdentifierX86{Family: "6", Model: "207", Stepping: "", Capid4: "", Devices: ""}, "EMR"}, // Emerald Rapids + {CPUIdentifierX86{Family: "6", Model: "175", Stepping: "", Capid4: "", Devices: ""}, "SRF"}, // Sierra Forest + {CPUIdentifierX86{Family: "6", Model: "173", Stepping: "", Capid4: "", Devices: ""}, "GNR"}, // Granite Rapids + {CPUIdentifierX86{Family: "6", Model: "174", Stepping: "", Capid4: "", Devices: ""}, "GNR_D"}, // Granite Rapids - D + {CPUIdentifierX86{Family: "6", Model: "221", Stepping: "", Capid4: "", Devices: ""}, "CWF"}, // Clearwater Forest + {CPUIdentifierX86{Family: "19", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "DMR"}, // Diamond Rapids + // AMD CPUs + {CPUIdentifierX86{Family: "23", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "Naples"}, // Naples + {CPUIdentifierX86{Family: "23", Model: "49", Stepping: "", Capid4: "", Devices: ""}, "Rome"}, // Rome + {CPUIdentifierX86{Family: "25", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "Milan"}, // Milan + {CPUIdentifierX86{Family: "25", Model: "(1[6-9]|2[0-9]|3[01])", Stepping: "", Capid4: "", Devices: ""}, "Genoa"}, // Genoa, model 16-31 + {CPUIdentifierX86{Family: "25", Model: "(16[0-9]|17[0-5])", Stepping: "", Capid4: "", Devices: ""}, "Bergamo"}, // Bergamo, model 160-175 + {CPUIdentifierX86{Family: "26", Model: "2", Stepping: "", Capid4: "", Devices: ""}, "Turin (Zen 5)"}, // Turin (Zen 5) + {CPUIdentifierX86{Family: "26", Model: "17", Stepping: "", Capid4: "", Devices: ""}, "Turin (Zen 5c)"}, // Turin (Zen 5c) +} + +// cpuIdentifiersARM maps ARM CPU identification to microarchitecture names +var cpuIdentifiersARM = []struct { + Identifier CPUIdentifierARM + MicroArchitecture string +}{ + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: "AWS Graviton2"}, "Graviton2"}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd40", DmidecodePart: "AWS Graviton3"}, "Graviton3"}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "AWS Graviton4"}, "Graviton4"}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "Not Specified"}, "Axion"}, // GCP Axion (c4a) Neoverse-V2 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: ""}, "Altra Family"}, // Ampere Altra + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac3", DmidecodePart: ""}, "AmpereOne AC03"}, // AmpereOne AC03 + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "X"}, "AmpereOne AC04"}, // AmpereOne AC04 + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "M"}, "AmpereOne AC04_1"}, // AmpereOne AC04_1 +} + +// NewX86Identifier creates a CPUIdentifier for x86/AMD CPUs with extended parameters +func NewX86Identifier(family, model, stepping, capid4, devices string) CPUIdentifier { + return CPUIdentifier{ + CPUIdentifierX86: CPUIdentifierX86{ + Family: family, + Model: model, + Stepping: stepping, + Capid4: capid4, + Devices: devices, + }, + Architecture: X86Architecture, + } +} + +// NewARMIdentifier creates a CPUIdentifier for ARM CPUs +func NewARMIdentifier(implementer, part, dmidecodePart string) CPUIdentifier { + return CPUIdentifier{ + CPUIdentifierARM: CPUIdentifierARM{ + Implementer: implementer, + Part: part, + DmidecodePart: dmidecodePart, + }, + Architecture: ARMArchitecture, + } +} + +// GetCPU is a unified function that retrieves CPU characteristics for both x86 and ARM +func GetCPU(id CPUIdentifier) (CPUCharacteristics, error) { + // Auto-detect architecture if not specified + arch := id.Architecture + if arch == "" { + if id.Family != "" || id.Model != "" { + arch = X86Architecture + } else if id.Implementer != "" || id.Part != "" { + arch = ARMArchitecture + } else { + return CPUCharacteristics{}, fmt.Errorf("unable to determine CPU architecture") + } + } + + // Route to appropriate handler + switch arch { + case X86Architecture: + return getCPUX86(id.Family, id.Model, id.Stepping, id.Capid4, id.Devices) + case ARMArchitecture: + return getCPUARM(id.Implementer, id.Part, id.DmidecodePart) + } + + return CPUCharacteristics{}, fmt.Errorf("unsupported architecture: %s", arch) +} + +// getCPUARM is an internal helper for ARM CPU lookup +func getCPUARM(implementer, part, dmidecodePart string) (cpu CPUCharacteristics, err error) { + for _, entry := range cpuIdentifiersARM { + id := entry.Identifier + // any value specified in the definition must match + if id.Implementer != "" && id.Implementer != implementer { + continue + } + if id.Part != "" && id.Part != part { + continue + } + if id.DmidecodePart != "" && id.DmidecodePart != dmidecodePart { + continue + } + // Found matching identifier, look up characteristics + uarch := entry.MicroArchitecture + var ok bool + cpu, ok = cpuCharacteristicsMap[uarch] + if !ok { + err = fmt.Errorf("CPU characteristics not found for microarchitecture %s", uarch) + return + } + return + } + err = fmt.Errorf("CPU match not found for implementer %s, part %s, dmidecode part %s", implementer, part, dmidecodePart) + return +} + +// getCPUX86 is an internal helper for x86/AMD CPU lookup +// capid4 needed to differentiate EMR MCC from EMR XCC +// +// capid4: $ lspci -s $(lspci | grep 325b | awk 'NR==1{{print $1}}') -xxx | awk '$1 ~ /^90/{{print $9 $8 $7 $6; exit}}' +// +// devices needed to differentiate GNR X1/2/3 +// +// devices: $ lspci -d 8086:3258 | wc -l +func getCPUX86(family, model, stepping, capid4, devices string) (cpu CPUCharacteristics, err error) { + for _, entry := range cpuIdentifiersX86 { + id := entry.Identifier + // if family matches + if id.Family == family { + var reModel *regexp.Regexp + reModel, err = regexp.Compile(id.Model) + if err != nil { + return + } + // if model matches + if reModel.FindString(model) == model { + // if there is a stepping + if id.Stepping != "" { + var reStepping *regexp.Regexp + reStepping, err = regexp.Compile(id.Stepping) + if err != nil { + return + } + // if stepping does NOT match + if reStepping.FindString(stepping) == "" { + // no match + continue + } + } + // Found matching identifier + uarch := entry.MicroArchitecture + if family == "6" && (model == "143" || model == "207" || model == "173" || model == "175") { // SPR, EMR, GNR, SRF + uarch, err = getSpecificMicroArchitecture(family, model, capid4, devices) + if err != nil { + return + } + } + // Look up characteristics + var ok bool + cpu, ok = cpuCharacteristicsMap[uarch] + if !ok { + err = fmt.Errorf("CPU characteristics not found for microarchitecture %s", uarch) + return + } + return + } + } + } + err = fmt.Errorf("CPU match not found for family %s, model %s, stepping %s", family, model, stepping) + return +} + +func GetCPUByMicroArchitecture(uarch string) (cpu CPUCharacteristics, err error) { + // Try exact match first + if chars, ok := cpuCharacteristicsMap[uarch]; ok { + cpu = chars + return + } + // Try case-insensitive match + for key, chars := range cpuCharacteristicsMap { + if strings.EqualFold(key, uarch) { + cpu = chars + return + } + } + err = fmt.Errorf("CPU match not found for uarch %s", uarch) + return +} + +func getSpecificMicroArchitecture(family, model, capid4, devices string) (uarch string, err error) { + if family == "6" && model == "143" { // SPR + uarch, err = getSPRMicroArchitecture(capid4) + } else if family == "6" && model == "207" { // EMR + uarch, err = getEMRMicroArchitecture(capid4) + } else if family == "6" && model == "173" { // GNR + uarch, err = getGNRMicroArchitecture(devices) + } else if family == "6" && model == "175" { // SRF + uarch, err = getSRFMicroArchitecture(devices) + } + return +} + +func getSPRMicroArchitecture(capid4 string) (uarch string, err error) { + if capid4 != "" { + var bits int64 + var capid4Int int64 + capid4Int, err = strconv.ParseInt(capid4, 16, 64) + if err != nil { + return + } + bits = (capid4Int >> 6) & 0b11 + switch bits { + case 3: + uarch = "SPR_XCC" + case 1: + uarch = "SPR_MCC" + } + } + if uarch == "" { + uarch = "SPR" + } + return +} + +func getEMRMicroArchitecture(capid4 string) (uarch string, err error) { + if capid4 != "" { + var bits int64 + var capid4Int int64 + capid4Int, err = strconv.ParseInt(capid4, 16, 64) + if err != nil { + return + } + bits = (capid4Int >> 6) & 0b11 + switch bits { + case 3: + uarch = "EMR_XCC" + case 1: + uarch = "EMR_MCC" + } + } + if uarch == "" { + uarch = "EMR" + } + return +} + +func getGNRMicroArchitecture(devices string) (uarch string, err error) { + if devices != "" { + d, err := strconv.Atoi(devices) + if err == nil && d != 0 { + if d%5 == 0 { // device count is multiple of 5 + uarch = "GNR_X3" + } else if d%4 == 0 { // device count is multiple of 4 + uarch = "GNR_X2" + } else if d%3 == 0 { // device count is multiple of 3 + uarch = "GNR_X1" + } + } + } + if uarch == "" { + uarch = "GNR" + } + return +} + +func getSRFMicroArchitecture(devices string) (uarch string, err error) { + if devices != "" { + d, err := strconv.Atoi(devices) + if err == nil && d != 0 { + if d%3 == 0 { // device count is multiple of 3 + uarch = "SRF_SP" + } else if d%4 == 0 { // device count is multiple of 4 + uarch = "SRF_AP" + } + } + } + if uarch == "" { + uarch = "SRF" + } + return +} + +func (c CPUCharacteristics) GetMicroArchitecture() string { + return c.MicroArchitecture +} + +func (c CPUCharacteristics) GetShortMicroArchitecture() string { + return strings.Split(c.MicroArchitecture, "_")[0] +} + +// IsIntelCPUFamily checks if the CPU family corresponds to Intel CPUs. +func IsIntelCPUFamily(family int) bool { + return slices.Contains(IntelFamilies, family) +} + +// IsIntelCPUFamilyStr checks if the CPU family string corresponds to Intel CPUs. +func IsIntelCPUFamilyStr(familyStr string) bool { + family, err := strconv.Atoi(familyStr) + if err != nil { + return false + } + return IsIntelCPUFamily(family) +} diff --git a/internal/script/script.go b/internal/script/script.go index cc46876b..368b7a5f 100644 --- a/internal/script/script.go +++ b/internal/script/script.go @@ -11,12 +11,10 @@ import ( "os" "os/exec" "path" - "slices" "strconv" "strings" "text/template" - "perfspect/internal/cpus" "perfspect/internal/progress" "perfspect/internal/target" "perfspect/internal/util" @@ -34,10 +32,6 @@ type ScriptOutput struct { // RunScript runs a script on the specified target and returns the output. func RunScript(myTarget target.Target, script ScriptDefinition, localTempDir string) (ScriptOutput, error) { - if !scriptForTarget(script, myTarget) { - err := fmt.Errorf("the \"%s\" script is not intended for the target processor", script.Name) - return ScriptOutput{}, err - } scriptOutputs, err := RunScripts(myTarget, []ScriptDefinition{script}, false, localTempDir, nil, "") if scriptOutputs == nil { return ScriptOutput{}, err @@ -56,10 +50,6 @@ func RunScripts(myTarget target.Target, scripts []ScriptDefinition, ignoreScript var sequentialScripts []ScriptDefinition var parallelScripts []ScriptDefinition for _, script := range scripts { - if !scriptForTarget(script, myTarget) { - slog.Debug("skipping script because it is not intended to run on the target processor", slog.String("target", myTarget.GetName()), slog.String("script", script.Name)) - continue - } if script.Superuser && !canElevate { slog.Debug("skipping script because it requires superuser privileges and the user cannot elevate privileges on target", slog.String("script", script.Name)) continue @@ -184,17 +174,6 @@ func RunScripts(myTarget target.Target, scripts []ScriptDefinition, ignoreScript // RunScriptStream runs a script on the specified target and streams the output to the specified channels. func RunScriptStream(myTarget target.Target, script ScriptDefinition, localTempDir string, stdoutChannel chan []byte, stderrChannel chan []byte, exitcodeChannel chan int, errorChannel chan error, cmdChannel chan *exec.Cmd) { - targetArchitecture, err := myTarget.GetArchitecture() - if err != nil { - err = fmt.Errorf("error getting target architecture: %v", err) - errorChannel <- err - return - } - if len(script.Architectures) > 0 && !slices.Contains(script.Architectures, targetArchitecture) { - err = fmt.Errorf("skipping script because it is not meant for this architecture: %s", targetArchitecture) - errorChannel <- err - return - } installedLkms, err := prepareTargetToRunScripts(myTarget, []ScriptDefinition{script}, localTempDir, true) if err != nil { err = fmt.Errorf("error while preparing target to run script: %v", err) @@ -214,56 +193,6 @@ func RunScriptStream(myTarget target.Target, script ScriptDefinition, localTempD errorChannel <- err } -// scriptForTarget checks if the script is intended for the target processor. -func scriptForTarget(script ScriptDefinition, myTarget target.Target) bool { - if len(script.Architectures) > 0 { - architecture, err := myTarget.GetArchitecture() - if err != nil { - slog.Error("failed to get architecture for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(script.Architectures, architecture) { - return false - } - } - if len(script.Vendors) > 0 { - vendor, err := myTarget.GetVendor() - if err != nil { - slog.Error("failed to get vendor for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(script.Vendors, vendor) { - return false - } - } - if len(script.MicroArchitectures) > 0 { - family, err := myTarget.GetFamily() - if err != nil { - slog.Error("failed to get family for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - model, err := myTarget.GetModel() - if err != nil { - slog.Error("failed to get model for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - stepping, err := myTarget.GetStepping() - if err != nil { - slog.Error("failed to get stepping for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - cpu, err := cpus.GetCPU(family, model, stepping) - if err != nil { - slog.Error("failed to get CPU for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(script.MicroArchitectures, cpu.GetMicroArchitecture()) && !slices.Contains(script.MicroArchitectures, cpu.GetShortMicroArchitecture()) { - return false - } - } - return true -} - func prepareCommand(script ScriptDefinition, targetTempDirectory string) (cmd *exec.Cmd) { scriptPath := path.Join(targetTempDirectory, scriptNameToFilename(script.Name)) if script.Superuser { diff --git a/internal/table/table.go b/internal/table/table.go index ae52ae75..ce7f4313 100644 --- a/internal/table/table.go +++ b/internal/table/table.go @@ -7,10 +7,7 @@ package table import ( "fmt" "log/slog" - "perfspect/internal/cpus" "perfspect/internal/script" - "perfspect/internal/target" - "slices" "github.com/xuri/excelize/v2" ) @@ -58,56 +55,6 @@ type TableDefinition struct { InsightsFunc InsightsRetriever } -// IsTableForTarget checks if the given table is applicable for the specified target -func IsTableForTarget(table TableDefinition, myTarget target.Target) bool { - if len(table.Architectures) > 0 { - architecture, err := myTarget.GetArchitecture() - if err != nil { - slog.Error("failed to get architecture for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(table.Architectures, architecture) { - return false - } - } - if len(table.Vendors) > 0 { - vendor, err := myTarget.GetVendor() - if err != nil { - slog.Error("failed to get vendor for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(table.Vendors, vendor) { - return false - } - } - if len(table.MicroArchitectures) > 0 { - family, err := myTarget.GetFamily() - if err != nil { - slog.Error("failed to get family for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - model, err := myTarget.GetModel() - if err != nil { - slog.Error("failed to get model for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - stepping, err := myTarget.GetStepping() - if err != nil { - slog.Error("failed to get stepping for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - cpu, err := cpus.GetCPU(family, model, stepping) - if err != nil { - slog.Error("failed to get CPU for target", slog.String("target", myTarget.GetName()), slog.String("error", err.Error())) - return false - } - if !slices.Contains(table.MicroArchitectures, cpu.GetMicroArchitecture()) && !slices.Contains(table.MicroArchitectures, cpu.GetShortMicroArchitecture()) { - return false - } - } - return true -} - // ProcessTables processes the given tables and script outputs to generate table values. // It collects values for each field in the tables and returns a slice of TableValues. // If any error occurs during processing, it is returned along with the table values. diff --git a/internal/target/helpers.go b/internal/target/helpers.go index e80c5b19..241eaf16 100644 --- a/internal/target/helpers.go +++ b/internal/target/helpers.go @@ -210,88 +210,3 @@ func getArchitecture(t Target) (arch string, err error) { arch = strings.TrimSpace(arch) return } - -// getFamily retrieves the CPU family of the target system by executing a shell command. -// It runs the "lscpu" command to extract the "CPU family" field and returns the value as a string. -// -// Parameters: -// - t: A Target instance that provides the method to execute the command. -// -// Returns: -// - family: A string representing the CPU family of the target system. -// - err: An error if the command execution or parsing fails. -func getFamily(t Target) (family string, err error) { - cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^CPU family:\" | awk '{print $NF}'") - family, _, _, err = t.RunCommand(cmd, 0, true) - if err != nil { - return - } - family = strings.TrimSpace(family) - return -} - -// getModel retrieves the CPU model of the target system by executing a shell command. -// It runs the "lscpu" command, filters the output for the "Model" field, and extracts -// the last field of the line using "awk". The result is trimmed of any leading or trailing -// whitespace before being returned. -// -// Parameters: -// -// t - The Target interface that provides the ability to execute commands on the target system. -// -// Returns: -// -// model - A string representing the CPU model of the target system. -// err - An error if the command execution fails or if there is an issue retrieving the model. -func getModel(t Target) (model string, err error) { - cmd := exec.Command("bash", "-c", "lscpu | grep -i model: | awk '{print $NF}'") - model, _, _, err = t.RunCommand(cmd, 0, true) - if err != nil { - return - } - model = strings.TrimSpace(model) - return -} - -// getStepping retrieves the CPU stepping information of the target system. -// It executes a shell command to parse the output of the `lscpu` command -// and extracts the stepping value using `grep` and `awk`. -// -// Parameters: -// - t: A Target instance that provides the ability to execute commands. -// -// Returns: -// - stepping: A string representing the CPU stepping value. -// - err: An error if the command execution or parsing fails. -func getStepping(t Target) (stepping string, err error) { - cmd := exec.Command("bash", "-c", "lscpu | grep -i stepping: | awk '{print $NF}'") - stepping, _, _, err = t.RunCommand(cmd, 0, true) - if err != nil { - return - } - stepping = strings.TrimSpace(stepping) - return -} - -// getVendor retrieves the vendor ID of the CPU by executing a shell command. -// It runs the "lscpu" command, filters the output for the "Vendor ID" field, -// and extracts the last field using "awk". The result is then trimmed of any -// leading or trailing whitespace. -// -// Parameters: -// -// t Target - The target object that provides the RunCommand method. -// -// Returns: -// -// vendor (string) - The vendor ID of the CPU. -// err (error) - An error if the command execution or parsing fails. -func getVendor(t Target) (vendor string, err error) { - cmd := exec.Command("bash", "-c", "lscpu | grep -i \"^Vendor ID:\" | awk '{print $NF}'") - vendor, _, _, err = t.RunCommand(cmd, 0, true) - if err != nil { - return - } - vendor = strings.TrimSpace(vendor) - return -} diff --git a/internal/target/local_target.go b/internal/target/local_target.go index 77e499af..c66e94b8 100644 --- a/internal/target/local_target.go +++ b/internal/target/local_target.go @@ -51,38 +51,6 @@ func (t *LocalTarget) GetArchitecture() (string, error) { return t.arch, err } -func (t *LocalTarget) GetFamily() (string, error) { - var err error - if t.family == "" { - t.family, err = getFamily(t) - } - return t.family, err -} - -func (t *LocalTarget) GetModel() (string, error) { - var err error - if t.model == "" { - t.model, err = getModel(t) - } - return t.model, err -} - -func (t *LocalTarget) GetStepping() (string, error) { - var err error - if t.stepping == "" { - t.stepping, err = getStepping(t) - } - return t.stepping, err -} - -func (t *LocalTarget) GetVendor() (string, error) { - var err error - if t.vendor == "" { - t.vendor, err = getVendor(t) - } - return t.vendor, err -} - // CreateTempDirectory creates a temporary directory under the specified root directory. // If the root directory is not specified, the temporary directory will be created in the current directory. // It returns the path of the created temporary directory and any error encountered. @@ -266,3 +234,83 @@ func (t *LocalTarget) GetUserPath() (string, error) { } return t.userPath, nil } + +func (t *LocalTarget) GetFamily() string { + return t.family +} + +func (t *LocalTarget) SetFamily(family string) { + t.family = family +} + +func (t *LocalTarget) GetModel() string { + return t.model +} + +func (t *LocalTarget) SetModel(model string) { + t.model = model +} + +func (t *LocalTarget) GetStepping() string { + return t.stepping +} + +func (t *LocalTarget) SetStepping(stepping string) { + t.stepping = stepping +} + +func (t *LocalTarget) GetVendor() string { + return t.vendor +} + +func (t *LocalTarget) SetVendor(vendor string) { + t.vendor = vendor +} + +func (t *LocalTarget) GetCapid4() string { + return t.capid4 +} + +func (t *LocalTarget) SetCapid4(capid4 string) { + t.capid4 = capid4 +} + +func (t *LocalTarget) GetDevices() string { + return t.devices +} + +func (t *LocalTarget) SetDevices(devices string) { + t.devices = devices +} + +func (t *LocalTarget) GetImplementer() string { + return t.implementer +} + +func (t *LocalTarget) SetImplementer(implementer string) { + t.implementer = implementer +} + +func (t *LocalTarget) GetPart() string { + return t.part +} + +func (t *LocalTarget) SetPart(part string) { + t.part = part +} + +func (t *LocalTarget) GetDmidecodePart() string { + return t.dmidecodePart +} + +func (t *LocalTarget) SetDmidecodePart(dmidecodePart string) { + t.dmidecodePart = dmidecodePart +} + +func (t *LocalTarget) GetMicroarchitecture() string { + return t.microarchitecture +} + +func (t *LocalTarget) SetMicroarchitecture(microarchitecture string) { + t.microarchitecture = microarchitecture +} diff --git a/internal/target/remote_target.go b/internal/target/remote_target.go index 41eda2db..239af8c7 100644 --- a/internal/target/remote_target.go +++ b/internal/target/remote_target.go @@ -72,38 +72,6 @@ func (t *RemoteTarget) GetArchitecture() (string, error) { return t.arch, err } -func (t *RemoteTarget) GetFamily() (string, error) { - var err error - if t.family == "" { - t.family, err = getFamily(t) - } - return t.family, err -} - -func (t *RemoteTarget) GetModel() (string, error) { - var err error - if t.model == "" { - t.model, err = getModel(t) - } - return t.model, err -} - -func (t *RemoteTarget) GetStepping() (string, error) { - var err error - if t.stepping == "" { - t.stepping, err = getStepping(t) - } - return t.stepping, err -} - -func (t *RemoteTarget) GetVendor() (string, error) { - var err error - if t.vendor == "" { - t.vendor, err = getVendor(t) - } - return t.vendor, err -} - // CreateTempDirectory creates a temporary directory on the remote target. // If a temporary directory has already been created, it returns the existing one. // The function takes an optional rootDir parameter to specify the root directory @@ -260,6 +228,86 @@ func (t *RemoteTarget) GetUserPath() (string, error) { return t.userPath, nil } +func (t *RemoteTarget) GetFamily() string { + return t.family +} + +func (t *RemoteTarget) SetFamily(family string) { + t.family = family +} + +func (t *RemoteTarget) GetModel() string { + return t.model +} + +func (t *RemoteTarget) SetModel(model string) { + t.model = model +} + +func (t *RemoteTarget) GetStepping() string { + return t.stepping +} + +func (t *RemoteTarget) SetStepping(stepping string) { + t.stepping = stepping +} + +func (t *RemoteTarget) GetVendor() string { + return t.vendor +} + +func (t *RemoteTarget) SetVendor(vendor string) { + t.vendor = vendor +} + +func (t *RemoteTarget) GetCapid4() string { + return t.capid4 +} + +func (t *RemoteTarget) SetCapid4(capid4 string) { + t.capid4 = capid4 +} + +func (t *RemoteTarget) GetDevices() string { + return t.devices +} + +func (t *RemoteTarget) SetDevices(devices string) { + t.devices = devices +} + +func (t *RemoteTarget) GetImplementer() string { + return t.implementer +} + +func (t *RemoteTarget) SetImplementer(implementer string) { + t.implementer = implementer +} + +func (t *RemoteTarget) GetPart() string { + return t.part +} + +func (t *RemoteTarget) SetPart(part string) { + t.part = part +} + +func (t *RemoteTarget) GetDmidecodePart() string { + return t.dmidecodePart +} + +func (t *RemoteTarget) SetDmidecodePart(dmidecodePart string) { + t.dmidecodePart = dmidecodePart +} + +func (t *RemoteTarget) GetMicroarchitecture() string { + return t.microarchitecture +} + +func (t *RemoteTarget) SetMicroarchitecture(microarchitecture string) { + t.microarchitecture = microarchitecture +} + func (t *RemoteTarget) prepareSSHFlags(scp bool, useControlMaster bool, prompt bool) (flags []string) { flags = []string{ "-2", diff --git a/internal/target/target.go b/internal/target/target.go index 596cca0d..1b7883f5 100644 --- a/internal/target/target.go +++ b/internal/target/target.go @@ -32,22 +32,6 @@ type Target interface { // It returns a string representing the architecture and any error that occurred. GetArchitecture() (arch string, err error) - // GetFamily returns the family of the target system's CPU. - // It returns a string representing the family and any error that occurred. - GetFamily() (family string, err error) - - // GetModel returns the model of the target system's CPU. - // It returns a string representing the model and any error that occurred. - GetModel() (model string, err error) - - // GetStepping returns the stepping of the target system's CPU. - // It returns a string representing the stepping and any error that occurred. - GetStepping() (stepping string, err error) - - // GetVendor returns the vendor of the target system. - // It returns a string representing the vendor and any error that occurred. - GetVendor() (vendor string, err error) - // GetName returns the name of the target system. // It returns a string representing the host. GetName() (name string) @@ -56,6 +40,28 @@ type Target interface { // It returns a string representing the path and any error that occurred. GetUserPath() (path string, err error) + // GetSet* used to cache values for target + GetFamily() string + SetFamily(string) + GetModel() string + SetModel(string) + GetStepping() string + SetStepping(string) + GetVendor() string + SetVendor(string) + GetCapid4() string + SetCapid4(string) + GetDevices() string + SetDevices(string) + GetImplementer() string // for ARM + SetImplementer(string) // for ARM + GetPart() string // for ARM + SetPart(string) // for ARM + GetDmidecodePart() string // for ARM + SetDmidecodePart(string) // for ARM + GetMicroarchitecture() string + SetMicroarchitecture(string) + // RunCommand runs the specified command on the target. // Arguments: // - cmd: the command to run @@ -114,14 +120,20 @@ type Target interface { } type BaseTarget struct { - tempDir string - canElevate int // zero indicates unknown, 1 indicates yes, -1 indicates no - arch string - family string - model string - stepping string - vendor string - userPath string + tempDir string + canElevate int // zero indicates unknown, 1 indicates yes, -1 indicates no + arch string + family string + model string + stepping string + vendor string + capid4 string + devices string + implementer string + part string + dmidecodePart string + microarchitecture string + userPath string } type LocalTarget struct { From 23fafd4114ca39865ac879b6a0078bcc13d2704a Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 05:12:58 -0800 Subject: [PATCH 02/15] Turin Signed-off-by: Harper, Jason M --- cmd/metrics/loader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/metrics/loader.go b/cmd/metrics/loader.go index 5838d0c9..7e0bfe09 100644 --- a/cmd/metrics/loader.go +++ b/cmd/metrics/loader.go @@ -81,7 +81,7 @@ type ComponentLoader struct { // Input is the CPU microarchitecture name as defined in the cpus module. func NewLoader(uarch string) (Loader, error) { switch uarch { - case "CLX", "SKX", "BDX", "Bergamo", "Genoa", "Turin": + case "CLX", "SKX", "BDX", "Bergamo", "Genoa", "Turin (Zen 5)", "Turin (Zen 5c)": slog.Debug("Using legacy loader for microarchitecture", slog.String("uarch", uarch)) return newLegacyLoader(), nil case "GNR", "SRF", "EMR", "SPR", "ICX": From 373bb80fbb304b6fc52315deb5669554dcb9ff41 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 05:14:48 -0800 Subject: [PATCH 03/15] errmsg Signed-off-by: Harper, Jason M --- internal/common/targets.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/common/targets.go b/internal/common/targets.go index 02cb13e8..6a727b6b 100644 --- a/internal/common/targets.go +++ b/internal/common/targets.go @@ -829,7 +829,7 @@ func RunScripts(t target.Target, s []script.ScriptDefinition, ignoreScriptErrors return nil, fmt.Errorf("failed to check if scripts are supported on target %v", err) } if len(supportedScripts) == 0 { - return nil, fmt.Errorf("script are not supported on target %s", t.GetName()) + return nil, fmt.Errorf("zero scripts are supported on target %s", t.GetName()) } return script.RunScripts(t, supportedScripts, ignoreScriptErrors, localTempDir, statusUpdate, collectingStatusMsg) } From fe69a3103582cf4239bd11891cbec3939356e871 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 05:38:05 -0800 Subject: [PATCH 04/15] GNR-D Signed-off-by: Harper, Jason M --- cmd/metrics/loader.go | 2 +- cmd/metrics/loader_perfmon.go | 1 + internal/common/common.go | 5 ++++- internal/common/targets.go | 5 ++++- internal/cpus/cpus.go | 40 ++++++++++++++--------------------- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/cmd/metrics/loader.go b/cmd/metrics/loader.go index 7e0bfe09..d83b02b7 100644 --- a/cmd/metrics/loader.go +++ b/cmd/metrics/loader.go @@ -84,7 +84,7 @@ func NewLoader(uarch string) (Loader, error) { case "CLX", "SKX", "BDX", "Bergamo", "Genoa", "Turin (Zen 5)", "Turin (Zen 5c)": slog.Debug("Using legacy loader for microarchitecture", slog.String("uarch", uarch)) return newLegacyLoader(), nil - case "GNR", "SRF", "EMR", "SPR", "ICX": + case "GNR", "GNR_X1", "GNR_X2", "GNR_X3", "GNR-D", "SRF", "SRF_SP", "SRF_AP", "EMR", "EMR_MCC", "EMR_XCC", "SPR", "SPR_MCC", "SPR_XCC", "ICX": slog.Debug("Using perfmon loader for microarchitecture", slog.String("uarch", uarch)) return newPerfmonLoader(), nil case "Graviton2", "Graviton3", "Graviton4", "Axion", "AmpereOne AC04", "AmpereOne AC04_1": diff --git a/cmd/metrics/loader_perfmon.go b/cmd/metrics/loader_perfmon.go index fc50cf53..31259197 100644 --- a/cmd/metrics/loader_perfmon.go +++ b/cmd/metrics/loader_perfmon.go @@ -184,6 +184,7 @@ func (l *PerfmonLoader) Load(loaderConfig LoaderConfig) ([]MetricDefinition, []G func uarchToResourceName(uarch string) string { name := strings.ToLower(uarch) name = strings.Split(name, "_")[0] // Handle "GNR_X2", etc. + name = strings.Split(name, "-")[0] // Handle GNR-D return name } diff --git a/internal/common/common.go b/internal/common/common.go index 4b6589ea..314ab8e5 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -596,7 +596,10 @@ func isTableForTarget(tbl table.TableDefinition, t target.Target, localTempDir s if err != nil { slog.Error("failed to get microarchitecture for target", slog.String("target", t.GetName()), slog.String("error", err.Error())) } - if !slices.Contains(tbl.MicroArchitectures, uarch) && !slices.Contains(tbl.MicroArchitectures, strings.Split(uarch, "_")[0]) { + shortUarch := strings.Split(uarch, "_")[0] // handle EMR_XCC, etc. + shortUarch = strings.Split(shortUarch, "-")[0] // handle GNR-D + shortUarch = strings.Split(shortUarch, " ")[0] // handle Turin (Zen 5) + if !slices.Contains(tbl.MicroArchitectures, uarch) && !slices.Contains(tbl.MicroArchitectures, shortUarch) { return false } } diff --git a/internal/common/targets.go b/internal/common/targets.go index 6a727b6b..f85a74b4 100644 --- a/internal/common/targets.go +++ b/internal/common/targets.go @@ -788,7 +788,10 @@ func ScriptSupportedOnTarget(t target.Target, scriptDef script.ScriptDefinition, if err != nil { return false, err } - if !slices.Contains(scriptDef.MicroArchitectures, uarch) && !slices.Contains(scriptDef.MicroArchitectures, strings.Split(uarch, "_")[0]) { + shortUarch := strings.Split(uarch, "_")[0] // handle EMR_XCC, etc. + shortUarch = strings.Split(shortUarch, "-")[0] // handle GNR-D + shortUarch = strings.Split(shortUarch, " ")[0] // handle Turin (Zen 5) + if !slices.Contains(scriptDef.MicroArchitectures, uarch) && !slices.Contains(scriptDef.MicroArchitectures, shortUarch) { slog.Info("script not supported on target CPU microarchitecture", slog.String("script", scriptDef.Name), slog.String("target", t.GetName()), slog.String("microarchitecture", uarch)) return false, nil } diff --git a/internal/cpus/cpus.go b/internal/cpus/cpus.go index be1d6f57..fb2d6f54 100644 --- a/internal/cpus/cpus.go +++ b/internal/cpus/cpus.go @@ -84,7 +84,7 @@ var cpuCharacteristicsMap = map[string]CPUCharacteristics{ "GNR_X1": {MicroArchitecture: "GNR_X1", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (MCC/LCC) "GNR_X2": {MicroArchitecture: "GNR_X2", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (XCC) "GNR_X3": {MicroArchitecture: "GNR_X3", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - AP (UCC) - "GNR_D": {MicroArchitecture: "GNR_D", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D + "GNR-D": {MicroArchitecture: "GNR-D", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D "CWF": {MicroArchitecture: "CWF", MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 0}, // Clearwater Forest - generic "DMR": {MicroArchitecture: "DMR", MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids // AMD CPUs @@ -133,7 +133,7 @@ var cpuIdentifiersX86 = []struct { {CPUIdentifierX86{Family: "6", Model: "207", Stepping: "", Capid4: "", Devices: ""}, "EMR"}, // Emerald Rapids {CPUIdentifierX86{Family: "6", Model: "175", Stepping: "", Capid4: "", Devices: ""}, "SRF"}, // Sierra Forest {CPUIdentifierX86{Family: "6", Model: "173", Stepping: "", Capid4: "", Devices: ""}, "GNR"}, // Granite Rapids - {CPUIdentifierX86{Family: "6", Model: "174", Stepping: "", Capid4: "", Devices: ""}, "GNR_D"}, // Granite Rapids - D + {CPUIdentifierX86{Family: "6", Model: "174", Stepping: "", Capid4: "", Devices: ""}, "GNR-D"}, // Granite Rapids - D {CPUIdentifierX86{Family: "6", Model: "221", Stepping: "", Capid4: "", Devices: ""}, "CWF"}, // Clearwater Forest {CPUIdentifierX86{Family: "19", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "DMR"}, // Diamond Rapids // AMD CPUs @@ -313,6 +313,20 @@ func GetCPUByMicroArchitecture(uarch string) (cpu CPUCharacteristics, err error) return } +// IsIntelCPUFamily checks if the CPU family corresponds to Intel CPUs. +func IsIntelCPUFamily(family int) bool { + return slices.Contains(IntelFamilies, family) +} + +// IsIntelCPUFamilyStr checks if the CPU family string corresponds to Intel CPUs. +func IsIntelCPUFamilyStr(familyStr string) bool { + family, err := strconv.Atoi(familyStr) + if err != nil { + return false + } + return IsIntelCPUFamily(family) +} + func getSpecificMicroArchitecture(family, model, capid4, devices string) (uarch string, err error) { if family == "6" && model == "143" { // SPR uarch, err = getSPRMicroArchitecture(capid4) @@ -405,25 +419,3 @@ func getSRFMicroArchitecture(devices string) (uarch string, err error) { } return } - -func (c CPUCharacteristics) GetMicroArchitecture() string { - return c.MicroArchitecture -} - -func (c CPUCharacteristics) GetShortMicroArchitecture() string { - return strings.Split(c.MicroArchitecture, "_")[0] -} - -// IsIntelCPUFamily checks if the CPU family corresponds to Intel CPUs. -func IsIntelCPUFamily(family int) bool { - return slices.Contains(IntelFamilies, family) -} - -// IsIntelCPUFamilyStr checks if the CPU family string corresponds to Intel CPUs. -func IsIntelCPUFamilyStr(familyStr string) bool { - family, err := strconv.Atoi(familyStr) - if err != nil { - return false - } - return IsIntelCPUFamily(family) -} From d404f20c5ef2bdc30d85c687ce54959e9fda80b6 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 06:31:58 -0800 Subject: [PATCH 05/15] don't fail if can't read extended uarch Signed-off-by: Harper, Jason M --- internal/common/targets.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/common/targets.go b/internal/common/targets.go index f85a74b4..f995054a 100644 --- a/internal/common/targets.go +++ b/internal/common/targets.go @@ -614,7 +614,7 @@ func GetTargetCapid4(t target.Target, localTempDir string, noRoot bool) (string, getScript := script.GetScriptByName(script.LspciBitsScriptName) scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop if err != nil { - return "", fmt.Errorf("failed to run cpuid capid4 script: %v", err) + return "", fmt.Errorf("failed to run lspci bits script: %v", err) } capid4 = strings.TrimSpace(scriptOutput.Stdout) t.SetCapid4(capid4) @@ -628,7 +628,7 @@ func GetTargetDevices(t target.Target, localTempDir string, noRoot bool) (string getScript := script.GetScriptByName(script.LspciDevicesScriptName) scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop if err != nil { - return "", fmt.Errorf("failed to run cpu devices script: %v", err) + return "", fmt.Errorf("failed to run lspci devices script: %v", err) } devices = strings.TrimSpace(scriptOutput.Stdout) t.SetDevices(devices) @@ -729,11 +729,13 @@ func GetX86TargetMicroarchitecture(t target.Target, localTempDir string, noRoot } capid4, err := GetTargetCapid4(t, localTempDir, noRoot) if err != nil { - return "", err + slog.Warn("failed to read lspci bits to get capid4 for microarchitecture identification", slog.String("error", err.Error())) + // continue } devices, err := GetTargetDevices(t, localTempDir, noRoot) if err != nil { - return "", err + slog.Warn("failed to read lspci devices for microarchitecture identification", slog.String("error", err.Error())) + // continue } cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) if err != nil { From b7c8351a5c619d8d4ea2a5b779996d322da5d13a Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 07:17:47 -0800 Subject: [PATCH 06/15] add script dependencies Signed-off-by: Harper, Jason M --- cmd/config/config_tables.go | 3 +++ cmd/report/cpu.go | 5 ++++- cmd/report/report_tables.go | 20 ++++++++++++++++++-- internal/common/table_helpers.go | 13 +++++++++---- internal/common/targets.go | 19 +++---------------- internal/cpus/cpus.go | 21 ++++++++++++++++++++- internal/script/script_defs.go | 19 +++++++++++++++++++ 7 files changed, 76 insertions(+), 24 deletions(-) diff --git a/cmd/config/config_tables.go b/cmd/config/config_tables.go index aa16e0d1..079f9984 100644 --- a/cmd/config/config_tables.go +++ b/cmd/config/config_tables.go @@ -48,6 +48,9 @@ var tableDefinitions = map[string]table.TableDefinition{ script.PrefetchersAtomName, script.CstatesScriptName, script.C1DemotionScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, }, FieldsFunc: configurationTableValues}, } diff --git a/cmd/report/cpu.go b/cmd/report/cpu.go index 6022abce..85cbb39d 100644 --- a/cmd/report/cpu.go +++ b/cmd/report/cpu.go @@ -47,7 +47,10 @@ func channelsFromOutput(outputs map[string]script.ScriptOutput) string { stepping := common.ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Stepping:\s*(.+)$`) capid4 := common.ValFromRegexSubmatch(outputs[script.LspciBitsScriptName].Stdout, `^([0-9a-fA-F]+)`) devices := common.ValFromRegexSubmatch(outputs[script.LspciDevicesScriptName].Stdout, `^([0-9]+)`) - cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) + implementer := strings.TrimSpace(outputs[script.ArmImplementerScriptName].Stdout) + part := strings.TrimSpace(outputs[script.ArmPartScriptName].Stdout) + dmidecodePart := strings.TrimSpace(outputs[script.ArmDmidecodePartScriptName].Stdout) + cpu, err := cpus.GetCPU(cpus.NewCPUIdentifier(family, model, stepping, capid4, devices, implementer, part, dmidecodePart, "")) if err != nil { slog.Error("error getting CPU characteristics", slog.String("error", err.Error())) return "" diff --git a/cmd/report/report_tables.go b/cmd/report/report_tables.go index 604c42e8..819cee16 100644 --- a/cmd/report/report_tables.go +++ b/cmd/report/report_tables.go @@ -146,7 +146,10 @@ var tableDefinitions = map[string]table.TableDefinition{ script.MaximumFrequencyScriptName, script.SpecCoreFrequenciesScriptName, script.PPINName, - script.L3CacheWayEnabledName}, + script.L3CacheWayEnabledName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName}, FieldsFunc: cpuTableValues, InsightsFunc: cpuTableInsights}, PrefetcherTableName: { @@ -264,7 +267,11 @@ var tableDefinitions = map[string]table.TableDefinition{ script.LscpuScriptName, script.LspciBitsScriptName, script.LspciDevicesScriptName, - script.TmeScriptName}, + script.TmeScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, + }, FieldsFunc: memoryTableValues, InsightsFunc: memoryTableInsights}, DIMMTableName: { @@ -275,6 +282,12 @@ var tableDefinitions = map[string]table.TableDefinition{ script.LscpuScriptName, script.LspciBitsScriptName, script.LspciDevicesScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, }, FieldsFunc: dimmTableValues, InsightsFunc: dimmTableInsights}, @@ -449,6 +462,9 @@ var tableDefinitions = map[string]table.TableDefinition{ script.CstatesScriptName, script.ElcScriptName, script.CveScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, }, FieldsFunc: systemSummaryTableValues}, // diff --git a/internal/common/table_helpers.go b/internal/common/table_helpers.go index d229ea73..399959e4 100644 --- a/internal/common/table_helpers.go +++ b/internal/common/table_helpers.go @@ -188,15 +188,17 @@ func SectionValueFromOutput(output string, sectionName string) string { return sections[sectionName] } -// UarchFromOutput returns the architecture of the CPU that matches family, model, stepping, -// capid4, and devices information from the output or an empty string, if no match is found. +// UarchFromOutput returns the microarchitecture of the CPU or an empty string, if no match is found. func UarchFromOutput(outputs map[string]script.ScriptOutput) string { family := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^CPU family:\s*(.+)$`) model := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Model:\s*(.+)$`) stepping := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Stepping:\s*(.+)$`) capid4 := ValFromRegexSubmatch(outputs[script.LspciBitsScriptName].Stdout, `^([0-9a-fA-F]+)`) devices := ValFromRegexSubmatch(outputs[script.LspciDevicesScriptName].Stdout, `^([0-9]+)`) - cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, capid4, devices)) + implementer := strings.TrimSpace(outputs[script.ArmImplementerScriptName].Stdout) + part := strings.TrimSpace(outputs[script.ArmPartScriptName].Stdout) + dmidecodePart := strings.TrimSpace(outputs[script.ArmDmidecodePartScriptName].Stdout) + cpu, err := cpus.GetCPU(cpus.NewCPUIdentifier(family, model, stepping, capid4, devices, implementer, part, dmidecodePart, "")) if err != nil { slog.Error("error getting CPU characteristics", slog.String("error", err.Error())) return "" @@ -208,6 +210,9 @@ func HyperthreadingFromOutput(outputs map[string]script.ScriptOutput) string { family := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^CPU family:\s*(.+)$`) model := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Model:\s*(.+)$`) stepping := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Stepping:\s*(.+)$`) + implementer := strings.TrimSpace(outputs[script.ArmImplementerScriptName].Stdout) + part := strings.TrimSpace(outputs[script.ArmPartScriptName].Stdout) + dmidecodePart := strings.TrimSpace(outputs[script.ArmDmidecodePartScriptName].Stdout) sockets := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Socket\(s\):\s*(.+)$`) coresPerSocket := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Core\(s\) per socket:\s*(.+)$`) cpuCount := ValFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^CPU\(.*:\s*(.+?)$`) @@ -240,7 +245,7 @@ func HyperthreadingFromOutput(outputs map[string]script.ScriptOutput) string { slog.Error("error parsing cores per sockets from lscpu") return "" } - cpu, err := cpus.GetCPU(cpus.NewX86Identifier(family, model, stepping, "", "")) + cpu, err := cpus.GetCPU(cpus.NewCPUIdentifier(family, model, stepping, "", "", implementer, part, dmidecodePart, "")) if err != nil { slog.Warn("error getting CPU characteristics", slog.String("error", err.Error())) return "" diff --git a/internal/common/targets.go b/internal/common/targets.go index f995054a..d8dffcc5 100644 --- a/internal/common/targets.go +++ b/internal/common/targets.go @@ -639,11 +639,7 @@ func GetTargetDevices(t target.Target, localTempDir string, noRoot bool) (string func GetTargetImplementer(t target.Target, localTempDir string, noRoot bool) (string, error) { implementer := t.GetImplementer() if implementer == "" { - getScript := script.ScriptDefinition{ - Name: "get target implementer", - ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU implementer\" | head -1 | awk '{print $NF}'", - Superuser: !noRoot, - } + getScript := script.GetScriptByName(script.ArmImplementerScriptName) scriptOutput, err := script.RunScript(t, getScript, localTempDir) if err != nil { return "", fmt.Errorf("failed to run implementer retrieval script: %v", err) @@ -657,11 +653,7 @@ func GetTargetImplementer(t target.Target, localTempDir string, noRoot bool) (st func GetTargetPart(t target.Target, localTempDir string, noRoot bool) (string, error) { part := t.GetPart() if part == "" { - getScript := script.ScriptDefinition{ - Name: "get target part", - ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU part\" | head -1 | awk '{print $NF}'", - Superuser: !noRoot, - } + getScript := script.GetScriptByName(script.ArmPartScriptName) scriptOutput, err := script.RunScript(t, getScript, localTempDir) if err != nil { return "", fmt.Errorf("failed to run part retrieval script: %v", err) @@ -675,12 +667,7 @@ func GetTargetPart(t target.Target, localTempDir string, noRoot bool) (string, e func GetTargetDmidecodePart(t target.Target, localTempDir string, noRoot bool) (string, error) { dmidecodePart := t.GetDmidecodePart() if dmidecodePart == "" { - getScript := script.ScriptDefinition{ - Name: "get dmidecode processor part number", - ScriptTemplate: "dmidecode -t processor | grep -m 1 \"Part Number\" | awk -F': ' '{print $2}'", - Superuser: !noRoot, - Depends: []string{"dmidecode"}, - } + getScript := script.GetScriptByName(script.ArmDmidecodePartScriptName) scriptOutput, err := script.RunScript(t, getScript, localTempDir) // don't call common.RunScript, otherwise infinite loop if err != nil { return "", fmt.Errorf("failed to run dmidecode part number script: %v", err) diff --git a/internal/cpus/cpus.go b/internal/cpus/cpus.go index fb2d6f54..93b19dc3 100644 --- a/internal/cpus/cpus.go +++ b/internal/cpus/cpus.go @@ -161,6 +161,25 @@ var cpuIdentifiersARM = []struct { {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "M"}, "AmpereOne AC04_1"}, // AmpereOne AC04_1 } +// NewCPUIdentifier creates a CPUIdentifier with all data elements +func NewCPUIdentifier(family, model, stepping, capid4, devices, implementer, part, dmidecodePart, architecture string) CPUIdentifier { + return CPUIdentifier{ + CPUIdentifierX86: CPUIdentifierX86{ + Family: family, + Model: model, + Stepping: stepping, + Capid4: capid4, + Devices: devices, + }, + CPUIdentifierARM: CPUIdentifierARM{ + Implementer: implementer, + Part: part, + DmidecodePart: dmidecodePart, + }, + Architecture: architecture, + } +} + // NewX86Identifier creates a CPUIdentifier for x86/AMD CPUs with extended parameters func NewX86Identifier(family, model, stepping, capid4, devices string) CPUIdentifier { return CPUIdentifier{ @@ -192,7 +211,7 @@ func GetCPU(id CPUIdentifier) (CPUCharacteristics, error) { // Auto-detect architecture if not specified arch := id.Architecture if arch == "" { - if id.Family != "" || id.Model != "" { + if id.Implementer == "" && id.Family != "" && id.Model != "" { arch = X86Architecture } else if id.Implementer != "" || id.Part != "" { arch = ARMArchitecture diff --git a/internal/script/script_defs.go b/internal/script/script_defs.go index 73a49f7d..a1592bde 100644 --- a/internal/script/script_defs.go +++ b/internal/script/script_defs.go @@ -101,6 +101,9 @@ const ( GaudiFirmwareScriptName = "gaudi firmware" GaudiNumaScriptName = "gaudi numa" GaudiArchitectureScriptName = "gaudi architecture" + ArmImplementerScriptName = "arm implementer" + ArmPartScriptName = "arm part" + ArmDmidecodePartScriptName = "arm dmidecode part" // benchmark scripts MemoryBenchmarkScriptName = "memory benchmark" NumaBenchmarkScriptName = "numa benchmark" @@ -995,6 +998,22 @@ echo $__DEFAULT_HL_DEVICE `, Vendors: []string{cpus.IntelVendor}, }, + ArmImplementerScriptName: { + Name: ArmImplementerScriptName, + ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU implementer\" | head -1 | awk '{print $NF}'", + Architectures: []string{cpus.ARMArchitecture}, + }, + ArmPartScriptName: { + Name: ArmPartScriptName, + ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU part\" | head -1 | awk '{print $NF}'", + Architectures: []string{cpus.ARMArchitecture}, + }, + ArmDmidecodePartScriptName: { + Name: ArmDmidecodePartScriptName, + ScriptTemplate: "dmidecode -t processor | grep -m 1 \"Part Number\" | awk -F': ' '{print $2}'", + Architectures: []string{cpus.ARMArchitecture}, + Superuser: true, + }, MemoryBenchmarkScriptName: { Name: MemoryBenchmarkScriptName, ScriptTemplate: `# measure memory loaded latency From c30bc5aa63b0e9b6f536afe211d73d9ebbf67337 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 08:50:56 -0800 Subject: [PATCH 07/15] don't double filter Signed-off-by: Harper, Jason M --- cmd/config/set.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cmd/config/set.go b/cmd/config/set.go index 2273aef4..a0d9ba18 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -484,16 +484,9 @@ func setUncoreDieFrequency(maxFreq bool, computeDie bool, uncoreFrequency float6 var dies []dieId // build list of compute or IO dies dieTypesScript := script.GetScriptByName(script.UncoreDieTypesFromTPMIScriptName) - supported, err := common.ScriptSupportedOnTarget(myTarget, dieTypesScript, localTempDir, false) - if err != nil { - return fmt.Errorf("failed to check if script is supported on target: %w", err) - } - if !supported { - return fmt.Errorf("uncore die frequency setting not supported on %s", myTarget.GetName()) - } 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(scriptOutput.Stdout, "\n") { From f75612c0c2dcc4cd20676f1d43d12e4810d64b6d Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 08:51:47 -0800 Subject: [PATCH 08/15] duplicate scripts in list Signed-off-by: Harper, Jason M --- cmd/report/report_tables.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/report/report_tables.go b/cmd/report/report_tables.go index 819cee16..5e2ba95d 100644 --- a/cmd/report/report_tables.go +++ b/cmd/report/report_tables.go @@ -285,9 +285,6 @@ var tableDefinitions = map[string]table.TableDefinition{ script.ArmImplementerScriptName, script.ArmPartScriptName, script.ArmDmidecodePartScriptName, - script.ArmImplementerScriptName, - script.ArmPartScriptName, - script.ArmDmidecodePartScriptName, }, FieldsFunc: dimmTableValues, InsightsFunc: dimmTableInsights}, From e71bed655b7cefb71c9d5c19911d0406a0cd6736 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 08:58:59 -0800 Subject: [PATCH 09/15] useless cat Signed-off-by: Harper, Jason M --- internal/script/script_defs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/script/script_defs.go b/internal/script/script_defs.go index a1592bde..1192d346 100644 --- a/internal/script/script_defs.go +++ b/internal/script/script_defs.go @@ -1000,12 +1000,12 @@ echo $__DEFAULT_HL_DEVICE }, ArmImplementerScriptName: { Name: ArmImplementerScriptName, - ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU implementer\" | head -1 | awk '{print $NF}'", + ScriptTemplate: "grep -i \"^CPU implementer\" /proc/cpuinfo | head -1 | awk '{print $NF}'", Architectures: []string{cpus.ARMArchitecture}, }, ArmPartScriptName: { Name: ArmPartScriptName, - ScriptTemplate: "cat /proc/cpuinfo | grep -i \"^CPU part\" | head -1 | awk '{print $NF}'", + ScriptTemplate: "grep -i \"^CPU part\" /proc/cpuinfo | head -1 | awk '{print $NF}'", Architectures: []string{cpus.ARMArchitecture}, }, ArmDmidecodePartScriptName: { From 4182cdb3ae9bd19da19c2a0b13168f8cd26786bb Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 09:02:00 -0800 Subject: [PATCH 10/15] comments Signed-off-by: Harper, Jason M --- cmd/config/set.go | 1 - cmd/metrics/loader_perfmon.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/config/set.go b/cmd/config/set.go index a0d9ba18..c32cef07 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -577,7 +577,6 @@ func setUncoreFrequency(maxFreq bool, uncoreFrequency float64, myTarget target.T // Depends: []string{"wrmsr"}, // Lkms: []string{"msr"}, } - // don't need to check script for target compatability since we already checked support above _, err = runScript(myTarget, setScript, localTempDir) if err != nil { err = fmt.Errorf("failed to set uncore frequency: %w", err) diff --git a/cmd/metrics/loader_perfmon.go b/cmd/metrics/loader_perfmon.go index 31259197..0c73f043 100644 --- a/cmd/metrics/loader_perfmon.go +++ b/cmd/metrics/loader_perfmon.go @@ -179,7 +179,7 @@ func (l *PerfmonLoader) Load(loaderConfig LoaderConfig) ([]MetricDefinition, []G return metricDefs, allGroups, nil } -// uarchToResourceName maps from the CPU's microarchiteture, as defined in the cpus +// uarchToResourceName maps from the CPU's microarchitecture, as defined in the cpus // module, to the associated perfmon resource directory and config file name func uarchToResourceName(uarch string) string { name := strings.ToLower(uarch) From e087e7c5f4d0364adb71f48c8fab2e8ee6fb5007 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 10:43:45 -0800 Subject: [PATCH 11/15] uarch constants Signed-off-by: Harper, Jason M --- cmd/config/config_tables.go | 4 +- cmd/config/set.go | 12 +- cmd/metrics/loader.go | 7 +- cmd/metrics/loader_component.go | 7 +- cmd/metrics/metadata.go | 10 +- cmd/report/cpu.go | 12 +- cmd/report/report.go | 19 +-- cmd/report/report_tables.go | 34 ++--- internal/common/frequency.go | 7 +- internal/common/prefetcher.go | 15 +- internal/cpus/cpus.go | 251 +++++++++++++++++++------------- internal/script/script_defs.go | 18 +-- 12 files changed, 228 insertions(+), 168 deletions(-) diff --git a/cmd/config/config_tables.go b/cmd/config/config_tables.go index 079f9984..37831418 100644 --- a/cmd/config/config_tables.go +++ b/cmd/config/config_tables.go @@ -70,7 +70,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi {Name: "Package Power / TDP", Description: "--tdp ", Values: []string{common.TDPFromOutput(outputs)}}, {Name: "Core SSE Frequency", Description: "--core-max ", 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 ", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(true, true, outputs)}}, {Name: "Uncore Min Frequency (Compute)", Description: "--uncore-min-compute ", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}}, @@ -89,7 +89,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi {Name: "Scaling Governor", Description: "--gov ", 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 ", Values: []string{common.ELCSummaryFromOutput(outputs)}}) } // add prefetchers diff --git a/cmd/config/set.go b/cmd/config/set.go index c32cef07..44034761 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -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 @@ -542,7 +542,7 @@ func setUncoreFrequency(maxFreq bool, uncoreFrequency float64, myTarget target.T Name: "get uncore frequency MSR", ScriptTemplate: "rdmsr 0x620", Vendors: []string{cpus.IntelVendor}, - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF}, Superuser: true, // Depends: []string{"rdmsr"}, // Lkms: []string{"msr"}, @@ -573,7 +573,7 @@ func setUncoreFrequency(maxFreq bool, uncoreFrequency float64, myTarget target.T ScriptTemplate: fmt.Sprintf("wrmsr -a 0x620 %d", newVal), 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{"wrmsr"}, // Lkms: []string{"msr"}, } @@ -782,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) diff --git a/cmd/metrics/loader.go b/cmd/metrics/loader.go index d83b02b7..40544a49 100644 --- a/cmd/metrics/loader.go +++ b/cmd/metrics/loader.go @@ -6,6 +6,7 @@ package metrics import ( "fmt" "log/slog" + "perfspect/internal/cpus" "github.com/casbin/govaluate" ) @@ -81,13 +82,13 @@ type ComponentLoader struct { // Input is the CPU microarchitecture name as defined in the cpus module. func NewLoader(uarch string) (Loader, error) { switch uarch { - case "CLX", "SKX", "BDX", "Bergamo", "Genoa", "Turin (Zen 5)", "Turin (Zen 5c)": + 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(), nil - case "GNR", "GNR_X1", "GNR_X2", "GNR_X3", "GNR-D", "SRF", "SRF_SP", "SRF_AP", "EMR", "EMR_MCC", "EMR_XCC", "SPR", "SPR_MCC", "SPR_XCC", "ICX": + 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(), nil - case "Graviton2", "Graviton3", "Graviton4", "Axion", "AmpereOne AC04", "AmpereOne AC04_1": + case cpus.UarchGraviton2, cpus.UarchGraviton3, cpus.UarchGraviton4, cpus.UarchAxion, cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: slog.Debug("Using component loader for microarchitecture", slog.String("uarch", uarch)) return newComponentLoader(), nil default: diff --git a/cmd/metrics/loader_component.go b/cmd/metrics/loader_component.go index e1633ac2..893bffba 100644 --- a/cmd/metrics/loader_component.go +++ b/cmd/metrics/loader_component.go @@ -10,6 +10,7 @@ import ( "log/slog" "os" "path/filepath" + "perfspect/internal/cpus" "perfspect/internal/util" "regexp" "slices" @@ -494,11 +495,11 @@ func initializeComponentMetricEvaluable(expression string, evaluatorFunctions ma // the cpus module, to the directory where the associated events and metrics reside func getUarchDir(uarch string) (string, error) { switch uarch { - case "Graviton4", "Axion", "AmpereOne AC04", "AmpereOne AC04_1": + case cpus.UarchGraviton4, cpus.UarchAxion, cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: return "neoverse-n2-v2", nil - case "Graviton2": + case cpus.UarchGraviton2: return "neoverse-n1", nil - case "Graviton3": + case cpus.UarchGraviton3: return "neoverse-v1", nil } return "", fmt.Errorf("unsupported component loader architecture: %s", uarch) diff --git a/cmd/metrics/metadata.go b/cmd/metrics/metadata.go index 5aaaab9a..3e6c151a 100644 --- a/cmd/metrics/metadata.go +++ b/cmd/metrics/metadata.go @@ -809,9 +809,9 @@ func getSupportsFixedTMA(scriptOutputs map[string]script.ScriptOutput) (supporte func getNumGPCounters(uarch string) (numGPCounters int, err error) { shortUarch := uarch[:3] switch shortUarch { - case "BDX", "SKX", "CLX": + case cpus.UarchBDX, cpus.UarchSKX, cpus.UarchCLX: numGPCounters = 4 - case "ICX", "SPR", "EMR", "SRF", "CWF", "GNR": + case cpus.UarchICX, cpus.UarchSPR, cpus.UarchEMR, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchGNR: numGPCounters = 8 case "Gen", "Ber", "Tur": numGPCounters = 5 @@ -898,11 +898,11 @@ func getARMSlots(scriptOutputs map[string]script.ScriptOutput) (slots int, err e // Used as a fallback when we cannot read the slots from sysfs func getARMSlotsByArchitecture(uarch string) (slots int, err error) { switch uarch { - case "Graviton4", "Axion": + case cpus.UarchGraviton4, cpus.UarchAxion: slots = 8 - case "Graviton2", "Graviton3": + case cpus.UarchGraviton2, cpus.UarchGraviton3: slots = 6 - case "AmpereOne AC04", "AmpereOne AC04_1": + case cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: slots = 10 default: err = fmt.Errorf("unsupported ARM uarch: %s", uarch) diff --git a/cmd/report/cpu.go b/cmd/report/cpu.go index 85cbb39d..98b896fc 100644 --- a/cmd/report/cpu.go +++ b/cmd/report/cpu.go @@ -129,32 +129,32 @@ func clusteringModeFromOutput(outputs map[string]script.ScriptOutput) string { } nodesPerSocket := nodeCount / socketCount switch uarch { - case "GNR_X1": + case cpus.UarchGNR_X1: return "All2All" - case "GNR_X2": + case cpus.UarchGNR_X2: switch nodesPerSocket { case 1: return "UMA 4 (Quad)" case 2: return "SNC 2" } - case "GNR_X3": + case cpus.UarchGNR_X3: switch nodesPerSocket { case 1: return "UMA 6 (Hex)" case 3: return "SNC 3" } - case "SRF_SP": + case cpus.UarchSRF_SP: return "UMA 2 (Hemi)" - case "SRF_AP": + case cpus.UarchSRF_AP: switch nodesPerSocket { case 1: return "UMA 4 (Quad)" case 2: return "SNC 2" } - case "CWF": + case cpus.UarchCWF: switch nodesPerSocket { case 1: return "UMA 6 (Hex)" diff --git a/cmd/report/report.go b/cmd/report/report.go index c7829e1d..ff8bd84a 100644 --- a/cmd/report/report.go +++ b/cmd/report/report.go @@ -17,6 +17,7 @@ import ( "github.com/xuri/excelize/v2" "perfspect/internal/common" + "perfspect/internal/cpus" "perfspect/internal/report" "perfspect/internal/script" "perfspect/internal/table" @@ -483,15 +484,15 @@ type ReferenceDataKey struct { // referenceData is a map of reference data for microarchitectures var referenceData = map[ReferenceDataKey]ReferenceData{ - {"BDX", "2"}: {Description: "Reference (Intel 2S Xeon E5-2699 v4)", CPUSpeed: 403415, SingleCoreFreq: 3509, AllCoreFreq: 2980, MaxPower: 289.9, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 138.1, MemMinLatency: 78}, - {"SKX", "2"}: {Description: "Reference (Intel 2S Xeon 8180)", CPUSpeed: 585157, SingleCoreFreq: 3758, AllCoreFreq: 3107, MaxPower: 429.07, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 225.1, MemMinLatency: 71}, - {"CLX", "2"}: {Description: "Reference (Intel 2S Xeon 8280)", CPUSpeed: 548644, SingleCoreFreq: 3928, AllCoreFreq: 3926, MaxPower: 415.93, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 223.9, MemMinLatency: 72}, - {"ICX", "2"}: {Description: "Reference (Intel 2S Xeon 8380)", CPUSpeed: 933644, SingleCoreFreq: 3334, AllCoreFreq: 2950, MaxPower: 552, MaxTemp: 0, MinPower: 175.38, MemPeakBandwidth: 350.7, MemMinLatency: 70}, - {"SPR_XCC", "2"}: {Description: "Reference (Intel 2S Xeon 8480+)", CPUSpeed: 1678712, SingleCoreFreq: 3776, AllCoreFreq: 2996, MaxPower: 698.35, MaxTemp: 0, MinPower: 249.21, MemPeakBandwidth: 524.6, MemMinLatency: 111.8}, - {"SPR_XCC", "1"}: {Description: "Reference (Intel 1S Xeon 8480+)", CPUSpeed: 845743, SingleCoreFreq: 3783, AllCoreFreq: 2999, MaxPower: 334.68, MaxTemp: 0, MinPower: 163.79, MemPeakBandwidth: 264.0, MemMinLatency: 112.2}, - {"EMR_XCC", "2"}: {Description: "Reference (Intel 2S Xeon 8592V)", CPUSpeed: 1789534, SingleCoreFreq: 3862, AllCoreFreq: 2898, MaxPower: 664.4, MaxTemp: 0, MinPower: 166.36, MemPeakBandwidth: 553.5, MemMinLatency: 92.0}, - {"SRF_SP", "2"}: {Description: "Reference (Intel 2S Xeon 6780E)", CPUSpeed: 3022446, SingleCoreFreq: 3001, AllCoreFreq: 3001, MaxPower: 583.97, MaxTemp: 0, MinPower: 123.34, MemPeakBandwidth: 534.3, MemMinLatency: 129.25}, - {"GNR_X2", "2"}: {Description: "Reference (Intel 2S Xeon 6787P)", CPUSpeed: 3178562, SingleCoreFreq: 3797, AllCoreFreq: 3199, MaxPower: 679, MaxTemp: 0, MinPower: 248.49, MemPeakBandwidth: 749.6, MemMinLatency: 117.51}, + {cpus.UarchBDX, "2"}: {Description: "Reference (Intel 2S Xeon E5-2699 v4)", CPUSpeed: 403415, SingleCoreFreq: 3509, AllCoreFreq: 2980, MaxPower: 289.9, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 138.1, MemMinLatency: 78}, + {cpus.UarchSKX, "2"}: {Description: "Reference (Intel 2S Xeon 8180)", CPUSpeed: 585157, SingleCoreFreq: 3758, AllCoreFreq: 3107, MaxPower: 429.07, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 225.1, MemMinLatency: 71}, + {cpus.UarchCLX, "2"}: {Description: "Reference (Intel 2S Xeon 8280)", CPUSpeed: 548644, SingleCoreFreq: 3928, AllCoreFreq: 3926, MaxPower: 415.93, MaxTemp: 0, MinPower: 0, MemPeakBandwidth: 223.9, MemMinLatency: 72}, + {cpus.UarchICX, "2"}: {Description: "Reference (Intel 2S Xeon 8380)", CPUSpeed: 933644, SingleCoreFreq: 3334, AllCoreFreq: 2950, MaxPower: 552, MaxTemp: 0, MinPower: 175.38, MemPeakBandwidth: 350.7, MemMinLatency: 70}, + {cpus.UarchSPR_XCC, "2"}: {Description: "Reference (Intel 2S Xeon 8480+)", CPUSpeed: 1678712, SingleCoreFreq: 3776, AllCoreFreq: 2996, MaxPower: 698.35, MaxTemp: 0, MinPower: 249.21, MemPeakBandwidth: 524.6, MemMinLatency: 111.8}, + {cpus.UarchSPR_XCC, "1"}: {Description: "Reference (Intel 1S Xeon 8480+)", CPUSpeed: 845743, SingleCoreFreq: 3783, AllCoreFreq: 2999, MaxPower: 334.68, MaxTemp: 0, MinPower: 163.79, MemPeakBandwidth: 264.0, MemMinLatency: 112.2}, + {cpus.UarchEMR_XCC, "2"}: {Description: "Reference (Intel 2S Xeon 8592V)", CPUSpeed: 1789534, SingleCoreFreq: 3862, AllCoreFreq: 2898, MaxPower: 664.4, MaxTemp: 0, MinPower: 166.36, MemPeakBandwidth: 553.5, MemMinLatency: 92.0}, + {cpus.UarchSRF_SP, "2"}: {Description: "Reference (Intel 2S Xeon 6780E)", CPUSpeed: 3022446, SingleCoreFreq: 3001, AllCoreFreq: 3001, MaxPower: 583.97, MaxTemp: 0, MinPower: 123.34, MemPeakBandwidth: 534.3, MemMinLatency: 129.25}, + {cpus.UarchGNR_X2, "2"}: {Description: "Reference (Intel 2S Xeon 6787P)", CPUSpeed: 3178562, SingleCoreFreq: 3797, AllCoreFreq: 3199, MaxPower: 679, MaxTemp: 0, MinPower: 248.49, MemPeakBandwidth: 749.6, MemMinLatency: 117.51}, } // getFieldIndex returns the index of a field in a list of fields diff --git a/cmd/report/report_tables.go b/cmd/report/report_tables.go index 5e2ba95d..603a923d 100644 --- a/cmd/report/report_tables.go +++ b/cmd/report/report_tables.go @@ -173,7 +173,7 @@ var tableDefinitions = map[string]table.TableDefinition{ AcceleratorTableName: { Name: AcceleratorTableName, Vendors: []string{cpus.IntelVendor}, - MicroArchitectures: []string{"SPR", "EMR", "GNR", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, HasRows: true, ScriptNames: []string{ script.LshwScriptName, @@ -232,7 +232,7 @@ var tableDefinitions = map[string]table.TableDefinition{ FieldsFunc: uncoreTableValues}, ElcTableName: { Name: ElcTableName, - MicroArchitectures: []string{"GNR", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, HasRows: true, ScriptNames: []string{ script.ElcScriptName, @@ -241,7 +241,7 @@ var tableDefinitions = map[string]table.TableDefinition{ InsightsFunc: elcTableInsights}, SSTTFHPTableName: { Name: SSTTFHPTableName, - MicroArchitectures: []string{"GNR", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, HasRows: true, ScriptNames: []string{ script.SSTTFHPScriptName, @@ -249,7 +249,7 @@ var tableDefinitions = map[string]table.TableDefinition{ FieldsFunc: sstTFHPTableValues}, SSTTFLPTableName: { Name: SSTTFLPTableName, - MicroArchitectures: []string{"GNR", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, HasRows: true, ScriptNames: []string{ script.SSTTFLPScriptName, @@ -740,23 +740,23 @@ func cpuTableInsights(outputs map[string]script.ScriptOutput, tableValues table. slog.Warn(err.Error()) } else { xeonGens := map[string]int{ - "HSX": 1, - "BDX": 2, - "SKX": 3, - "CLX": 4, - "ICX": 5, - "SPR": 6, - "EMR": 7, - "SRF": 8, - "CWF": 8, - "GNR": 8, - "DMR": 9, + cpus.UarchHSX: 1, + cpus.UarchBDX: 2, + cpus.UarchSKX: 3, + cpus.UarchCLX: 4, + cpus.UarchICX: 5, + cpus.UarchSPR: 6, + cpus.UarchEMR: 7, + cpus.UarchSRF: 8, + cpus.UarchCWF: 8, + cpus.UarchGNR: 8, + cpus.UarchDMR: 9, } uarch := tableValues.Fields[uarchIndex].Values[0] if len(uarch) >= 3 { xeonGen, ok := xeonGens[uarch[:3]] if ok { - if xeonGen < xeonGens["SPR"] { + if xeonGen < xeonGens[cpus.UarchSPR] { insights = append(insights, table.Insight{ Recommendation: "Consider upgrading to the latest generation Intel(r) Xeon(r) CPU.", Justification: "The CPU is 2 or more generations behind the latest Intel(r) Xeon(r) CPU.", @@ -892,7 +892,7 @@ func uncoreTableValues(outputs map[string]script.ScriptOutput) []table.Field { slog.Error("failed to get uarch from script outputs") return []table.Field{} } - 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) { return []table.Field{ {Name: "Min Frequency (Compute)", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}}, {Name: "Min Frequency (I/O)", Values: []string{common.UncoreMinMaxDieFrequencyFromOutput(false, false, outputs)}}, diff --git a/internal/common/frequency.go b/internal/common/frequency.go index 5b968731..07b91012 100644 --- a/internal/common/frequency.go +++ b/internal/common/frequency.go @@ -3,6 +3,7 @@ package common import ( "fmt" "log/slog" + "perfspect/internal/cpus" "perfspect/internal/script" "perfspect/internal/util" "regexp" @@ -136,11 +137,11 @@ func GetSpecFrequencyBuckets(outputs map[string]script.ScriptOutput) ([][]string totalCoreStartRange := 1 startRange := 1 var archMultiplier int - if strings.Contains(arch, "SRF") || strings.Contains(arch, "CWF") { + if strings.Contains(arch, cpus.UarchSRF) || strings.Contains(arch, cpus.UarchCWF) { archMultiplier = 4 - } else if strings.Contains(arch, "GNR_X3") { + } else if strings.Contains(arch, cpus.UarchGNR_X3) { archMultiplier = 3 - } else if strings.Contains(arch, "GNR_X2") { + } else if strings.Contains(arch, cpus.UarchGNR_X2) { archMultiplier = 2 } else { archMultiplier = 1 diff --git a/internal/common/prefetcher.go b/internal/common/prefetcher.go index 4a633ae4..9b9719d5 100644 --- a/internal/common/prefetcher.go +++ b/internal/common/prefetcher.go @@ -6,6 +6,7 @@ package common import ( "fmt" "log/slog" + "perfspect/internal/cpus" "perfspect/internal/script" "slices" "strconv" @@ -83,42 +84,42 @@ var PrefetcherDefinitions = []PrefetcherDefinition{ Description: "Adaptive Multipath Probability (MLC AMP) predicts access patterns based on previous patterns and fetches the corresponding cache lines into the L2 cache.", Msr: MsrPrefetchControl, Bit: 5, - Uarchs: []string{"SPR", "EMR", "GNR"}, + Uarchs: []string{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR}, }, { ShortName: PrefetcherLLCPPName, Description: "Last Level Cache Page (MLC LLC Page) Prefetcher", Msr: MsrPrefetchControl, Bit: 6, - Uarchs: []string{"GNR"}, + Uarchs: []string{cpus.UarchGNR}, }, { ShortName: PrefetcherAOPName, Description: "L2 Array of Pointers (DCU AOP) Prefetcher", Msr: MsrPrefetchControl, Bit: 7, - Uarchs: []string{"GNR"}, + Uarchs: []string{cpus.UarchGNR}, }, { ShortName: PrefetcherHomelessName, - Description: "Homeless prefetch allows early fetch of the demand miss into the MLC when we don’t have enough resources to track this demand in the L1 cache.", + Description: "Homeless prefetch allows early fetch of the demand miss into the MLC when we don't have enough resources to track this demand in the L1 cache.", Msr: MsrPrefetchers, Bit: 14, - Uarchs: []string{"SPR", "EMR", "GNR"}, + Uarchs: []string{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR}, }, { ShortName: PrefetcherLLCName, Description: "Last level cache gives the core prefetcher the ability to prefetch data directly into the LLC without necessarily filling into the L1 and L2 caches first.", Msr: MsrPrefetchers, Bit: 42, - Uarchs: []string{"SPR", "EMR", "GNR"}, + Uarchs: []string{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR}, }, { ShortName: PrefetcherLLCStreamName, Description: "Last level cache stream prefetcher.", Msr: MsrAtomPrefTuning1, Bit: 43, - Uarchs: []string{"SRF", "CWF"}, + Uarchs: []string{cpus.UarchSRF, cpus.UarchCWF}, }, } diff --git a/internal/cpus/cpus.go b/internal/cpus/cpus.go index 93b19dc3..bf130b50 100644 --- a/internal/cpus/cpus.go +++ b/internal/cpus/cpus.go @@ -21,6 +21,61 @@ const ARMArchitecture = "aarch64" var IntelFamilies = []int{6, 19} +// Microarchitecture constants +const ( + // Intel Core CPUs + UarchHSW = "HSW" + UarchBDW = "BDW" + UarchSKL = "SKL" + UarchKBL = "KBL" + UarchCFL = "CFL" + UarchRKL = "RKL" + UarchTGL = "TGL" + UarchADL = "ADL" + UarchMTL = "MTL" + UarchARL = "ARL" + // Intel Xeon CPUs + UarchHSX = "HSX" + UarchBDX = "BDX" + UarchSKX = "SKX" + UarchCLX = "CLX" + UarchCPX = "CPX" + UarchICX = "ICX" + UarchSPR = "SPR" + UarchSPR_MCC = "SPR_MCC" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchSPR_XCC = "SPR_XCC" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchEMR = "EMR" + UarchEMR_MCC = "EMR_MCC" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchEMR_XCC = "EMR_XCC" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchSRF = "SRF" + UarchSRF_SP = "SRF_SP" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchSRF_AP = "SRF_AP" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchGNR = "GNR" + UarchGNR_X1 = "GNR_X1" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchGNR_X2 = "GNR_X2" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchGNR_X3 = "GNR_X3" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchGNR_D = "GNR-D" //lint:ignore ST1003 microarchitecture names use underscores to match Intel specifications + UarchCWF = "CWF" + UarchDMR = "DMR" + // AMD CPUs + UarchNaples = "Naples" + UarchRome = "Rome" + UarchMilan = "Milan" + UarchGenoa = "Genoa" + UarchBergamo = "Bergamo" + UarchTurinZen5 = "Turin (Zen 5)" + UarchTurinZen5c = "Turin (Zen 5c)" + // ARM CPUs + UarchGraviton2 = "Graviton2" + UarchGraviton3 = "Graviton3" + UarchGraviton4 = "Graviton4" + UarchAxion = "Axion" + UarchAltraFamily = "Altra Family" + UarchAmpereOneAC03 = "AmpereOne AC03" + UarchAmpereOneAC04 = "AmpereOne AC04" + UarchAmpereOneAC04_1 = "AmpereOne AC04_1" +) + type CPUCharacteristics struct { MicroArchitecture string MemoryChannelCount int @@ -54,56 +109,56 @@ type CPUIdentifier struct { // cpuCharacteristicsMap maps microarchitecture name to CPU characteristics var cpuCharacteristicsMap = map[string]CPUCharacteristics{ // Intel Core CPUs - "HSW": {MicroArchitecture: "HSW", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Haswell - "BDW": {MicroArchitecture: "BDW", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Broadwell - "SKL": {MicroArchitecture: "SKL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Skylake - "KBL": {MicroArchitecture: "KBL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Kabylake - "CFL": {MicroArchitecture: "CFL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Coffeelake - "RKL": {MicroArchitecture: "RKL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Rocket Lake - "TGL": {MicroArchitecture: "TGL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Tiger Lake - "ADL": {MicroArchitecture: "ADL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Alder Lake - "MTL": {MicroArchitecture: "MTL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Meteor Lake - "ARL": {MicroArchitecture: "ARL", MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Arrow Lake + UarchHSW: {MicroArchitecture: UarchHSW, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Haswell + UarchBDW: {MicroArchitecture: UarchBDW, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Broadwell + UarchSKL: {MicroArchitecture: UarchSKL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Skylake + UarchKBL: {MicroArchitecture: UarchKBL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Kabylake + UarchCFL: {MicroArchitecture: UarchCFL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Coffeelake + UarchRKL: {MicroArchitecture: UarchRKL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Rocket Lake + UarchTGL: {MicroArchitecture: UarchTGL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Tiger Lake + UarchADL: {MicroArchitecture: UarchADL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Alder Lake + UarchMTL: {MicroArchitecture: UarchMTL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Meteor Lake + UarchARL: {MicroArchitecture: UarchARL, MemoryChannelCount: 2, LogicalThreadCount: 2, CacheWayCount: 0}, // Arrow Lake // Intel Xeon CPUs - "HSX": {MicroArchitecture: "HSX", MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Haswell - "BDX": {MicroArchitecture: "BDX", MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Broadwell - "SKX": {MicroArchitecture: "SKX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Skylake - "CLX": {MicroArchitecture: "CLX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cascadelake - "CPX": {MicroArchitecture: "CPX", MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cooperlake - "ICX": {MicroArchitecture: "ICX", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 12}, // Icelake - "SPR": {MicroArchitecture: "SPR", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - generic - "SPR_MCC": {MicroArchitecture: "SPR_MCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - MCC - "SPR_XCC": {MicroArchitecture: "SPR_XCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - XCC - "EMR": {MicroArchitecture: "EMR", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - generic - "EMR_MCC": {MicroArchitecture: "EMR_MCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - MCC - "EMR_XCC": {MicroArchitecture: "EMR_XCC", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 20}, // Emerald Rapids - XCC - "SRF": {MicroArchitecture: "SRF", MemoryChannelCount: 0, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - "SRF_SP": {MicroArchitecture: "SRF_SP", MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - "SRF_AP": {MicroArchitecture: "SRF_AP", MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest - "GNR": {MicroArchitecture: "GNR", MemoryChannelCount: 0, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - generic - "GNR_X1": {MicroArchitecture: "GNR_X1", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (MCC/LCC) - "GNR_X2": {MicroArchitecture: "GNR_X2", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (XCC) - "GNR_X3": {MicroArchitecture: "GNR_X3", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - AP (UCC) - "GNR-D": {MicroArchitecture: "GNR-D", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D - "CWF": {MicroArchitecture: "CWF", MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 0}, // Clearwater Forest - generic - "DMR": {MicroArchitecture: "DMR", MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids + UarchHSX: {MicroArchitecture: UarchHSX, MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Haswell + UarchBDX: {MicroArchitecture: UarchBDX, MemoryChannelCount: 4, LogicalThreadCount: 2, CacheWayCount: 20}, // Broadwell + UarchSKX: {MicroArchitecture: UarchSKX, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Skylake + UarchCLX: {MicroArchitecture: UarchCLX, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cascadelake + UarchCPX: {MicroArchitecture: UarchCPX, MemoryChannelCount: 6, LogicalThreadCount: 2, CacheWayCount: 11}, // Cooperlake + UarchICX: {MicroArchitecture: UarchICX, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 12}, // Icelake + UarchSPR: {MicroArchitecture: UarchSPR, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - generic + UarchSPR_MCC: {MicroArchitecture: UarchSPR_MCC, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - MCC + UarchSPR_XCC: {MicroArchitecture: UarchSPR_XCC, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Sapphire Rapids - XCC + UarchEMR: {MicroArchitecture: UarchEMR, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - generic + UarchEMR_MCC: {MicroArchitecture: UarchEMR_MCC, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 15}, // Emerald Rapids - MCC + UarchEMR_XCC: {MicroArchitecture: UarchEMR_XCC, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 20}, // Emerald Rapids - XCC + UarchSRF: {MicroArchitecture: UarchSRF, MemoryChannelCount: 0, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + UarchSRF_SP: {MicroArchitecture: UarchSRF_SP, MemoryChannelCount: 8, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + UarchSRF_AP: {MicroArchitecture: UarchSRF_AP, MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 12}, // Sierra Forest + UarchGNR: {MicroArchitecture: UarchGNR, MemoryChannelCount: 0, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - generic + UarchGNR_X1: {MicroArchitecture: UarchGNR_X1, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (MCC/LCC) + UarchGNR_X2: {MicroArchitecture: UarchGNR_X2, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - SP (XCC) + UarchGNR_X3: {MicroArchitecture: UarchGNR_X3, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - AP (UCC) + UarchGNR_D: {MicroArchitecture: UarchGNR_D, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 16}, // Granite Rapids - D + UarchCWF: {MicroArchitecture: UarchCWF, MemoryChannelCount: 12, LogicalThreadCount: 1, CacheWayCount: 0}, // Clearwater Forest - generic + UarchDMR: {MicroArchitecture: UarchDMR, MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids // AMD CPUs - "Naples": {MicroArchitecture: "Naples", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Naples - "Rome": {MicroArchitecture: "Rome", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Rome - "Milan": {MicroArchitecture: "Milan", MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Milan - "Genoa": {MicroArchitecture: "Genoa", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Genoa - "Bergamo": {MicroArchitecture: "Bergamo", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Bergamo - "Turin (Zen 5)": {MicroArchitecture: "Turin (Zen 5)", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5) - "Turin (Zen 5c)": {MicroArchitecture: "Turin (Zen 5c)", MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5c) + UarchNaples: {MicroArchitecture: UarchNaples, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Naples + UarchRome: {MicroArchitecture: UarchRome, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Rome + UarchMilan: {MicroArchitecture: UarchMilan, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Milan + UarchGenoa: {MicroArchitecture: UarchGenoa, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Genoa + UarchBergamo: {MicroArchitecture: UarchBergamo, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Bergamo + UarchTurinZen5: {MicroArchitecture: UarchTurinZen5, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5) + UarchTurinZen5c: {MicroArchitecture: UarchTurinZen5c, MemoryChannelCount: 12, LogicalThreadCount: 2, CacheWayCount: 0}, // Turin (Zen 5c) // ARM CPUs - "Graviton2": {MicroArchitecture: "Graviton2", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 - "Graviton3": {MicroArchitecture: "Graviton3", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 - "Graviton4": {MicroArchitecture: "Graviton4", MemoryChannelCount: 12, LogicalThreadCount: 1}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 - "Axion": {MicroArchitecture: "Axion", MemoryChannelCount: 12, LogicalThreadCount: 1}, // GCP Axion (c4a) Neoverse-V2 - "Altra Family": {MicroArchitecture: "Altra Family", MemoryChannelCount: 8, LogicalThreadCount: 1}, // Ampere Altra - "AmpereOne AC03": {MicroArchitecture: "AmpereOne AC03", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC03 - "AmpereOne AC04": {MicroArchitecture: "AmpereOne AC04", MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC04 - "AmpereOne AC04_1": {MicroArchitecture: "AmpereOne AC04_1", MemoryChannelCount: 12, LogicalThreadCount: 1}, // AmpereOne AC04_1 + UarchGraviton2: {MicroArchitecture: UarchGraviton2, MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 + UarchGraviton3: {MicroArchitecture: UarchGraviton3, MemoryChannelCount: 8, LogicalThreadCount: 1}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 + UarchGraviton4: {MicroArchitecture: UarchGraviton4, MemoryChannelCount: 12, LogicalThreadCount: 1}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 + UarchAxion: {MicroArchitecture: UarchAxion, MemoryChannelCount: 12, LogicalThreadCount: 1}, // GCP Axion (c4a) Neoverse-V2 + UarchAltraFamily: {MicroArchitecture: UarchAltraFamily, MemoryChannelCount: 8, LogicalThreadCount: 1}, // Ampere Altra + UarchAmpereOneAC03: {MicroArchitecture: UarchAmpereOneAC03, MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC03 + UarchAmpereOneAC04: {MicroArchitecture: UarchAmpereOneAC04, MemoryChannelCount: 8, LogicalThreadCount: 1}, // AmpereOne AC04 + UarchAmpereOneAC04_1: {MicroArchitecture: UarchAmpereOneAC04_1, MemoryChannelCount: 12, LogicalThreadCount: 1}, // AmpereOne AC04_1 } // cpuIdentifiersX86 maps x86 CPU identification to microarchitecture names @@ -112,38 +167,38 @@ var cpuIdentifiersX86 = []struct { MicroArchitecture string }{ // Intel Core CPUs - {CPUIdentifierX86{Family: "6", Model: "(50|69|70)", Stepping: "", Capid4: "", Devices: ""}, "HSW"}, // Haswell - {CPUIdentifierX86{Family: "6", Model: "(61|71)", Stepping: "", Capid4: "", Devices: ""}, "BDW"}, // Broadwell - {CPUIdentifierX86{Family: "6", Model: "(78|94)", Stepping: "", Capid4: "", Devices: ""}, "SKL"}, // Skylake - {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "9", Capid4: "", Devices: ""}, "KBL"}, // Kabylake - {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "(10|11|12|13)", Capid4: "", Devices: ""}, "CFL"}, // Coffeelake - {CPUIdentifierX86{Family: "6", Model: "167", Stepping: "", Capid4: "", Devices: ""}, "RKL"}, // Rocket Lake - {CPUIdentifierX86{Family: "6", Model: "(140|141)", Stepping: "", Capid4: "", Devices: ""}, "TGL"}, // Tiger Lake - {CPUIdentifierX86{Family: "6", Model: "(151|154)", Stepping: "", Capid4: "", Devices: ""}, "ADL"}, // Alder Lake - {CPUIdentifierX86{Family: "6", Model: "170", Stepping: "4", Capid4: "", Devices: ""}, "MTL"}, // Meteor Lake - {CPUIdentifierX86{Family: "6", Model: "197", Stepping: "2", Capid4: "", Devices: ""}, "ARL"}, // Arrow Lake + {CPUIdentifierX86{Family: "6", Model: "(50|69|70)", Stepping: "", Capid4: "", Devices: ""}, UarchHSW}, // Haswell + {CPUIdentifierX86{Family: "6", Model: "(61|71)", Stepping: "", Capid4: "", Devices: ""}, UarchBDW}, // Broadwell + {CPUIdentifierX86{Family: "6", Model: "(78|94)", Stepping: "", Capid4: "", Devices: ""}, UarchSKL}, // Skylake + {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "9", Capid4: "", Devices: ""}, UarchKBL}, // Kabylake + {CPUIdentifierX86{Family: "6", Model: "(142|158)", Stepping: "(10|11|12|13)", Capid4: "", Devices: ""}, UarchCFL}, // Coffeelake + {CPUIdentifierX86{Family: "6", Model: "167", Stepping: "", Capid4: "", Devices: ""}, UarchRKL}, // Rocket Lake + {CPUIdentifierX86{Family: "6", Model: "(140|141)", Stepping: "", Capid4: "", Devices: ""}, UarchTGL}, // Tiger Lake + {CPUIdentifierX86{Family: "6", Model: "(151|154)", Stepping: "", Capid4: "", Devices: ""}, UarchADL}, // Alder Lake + {CPUIdentifierX86{Family: "6", Model: "170", Stepping: "4", Capid4: "", Devices: ""}, UarchMTL}, // Meteor Lake + {CPUIdentifierX86{Family: "6", Model: "197", Stepping: "2", Capid4: "", Devices: ""}, UarchARL}, // Arrow Lake // Intel Xeon CPUs - {CPUIdentifierX86{Family: "6", Model: "63", Stepping: "", Capid4: "", Devices: ""}, "HSX"}, // Haswell - {CPUIdentifierX86{Family: "6", Model: "(79|86)", Stepping: "", Capid4: "", Devices: ""}, "BDX"}, // Broadwell - {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(0|1|2|3|4)", Capid4: "", Devices: ""}, "SKX"}, // Skylake - {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(5|6|7)", Capid4: "", Devices: ""}, "CLX"}, // Cascadelake - {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "11", Capid4: "", Devices: ""}, "CPX"}, // Cooperlake - {CPUIdentifierX86{Family: "6", Model: "(106|108)", Stepping: "", Capid4: "", Devices: ""}, "ICX"}, // Icelake - {CPUIdentifierX86{Family: "6", Model: "143", Stepping: "", Capid4: "", Devices: ""}, "SPR"}, // Sapphire Rapids - {CPUIdentifierX86{Family: "6", Model: "207", Stepping: "", Capid4: "", Devices: ""}, "EMR"}, // Emerald Rapids - {CPUIdentifierX86{Family: "6", Model: "175", Stepping: "", Capid4: "", Devices: ""}, "SRF"}, // Sierra Forest - {CPUIdentifierX86{Family: "6", Model: "173", Stepping: "", Capid4: "", Devices: ""}, "GNR"}, // Granite Rapids - {CPUIdentifierX86{Family: "6", Model: "174", Stepping: "", Capid4: "", Devices: ""}, "GNR-D"}, // Granite Rapids - D - {CPUIdentifierX86{Family: "6", Model: "221", Stepping: "", Capid4: "", Devices: ""}, "CWF"}, // Clearwater Forest - {CPUIdentifierX86{Family: "19", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "DMR"}, // Diamond Rapids + {CPUIdentifierX86{Family: "6", Model: "63", Stepping: "", Capid4: "", Devices: ""}, UarchHSX}, // Haswell + {CPUIdentifierX86{Family: "6", Model: "(79|86)", Stepping: "", Capid4: "", Devices: ""}, UarchBDX}, // Broadwell + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(0|1|2|3|4)", Capid4: "", Devices: ""}, UarchSKX}, // Skylake + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "(5|6|7)", Capid4: "", Devices: ""}, UarchCLX}, // Cascadelake + {CPUIdentifierX86{Family: "6", Model: "85", Stepping: "11", Capid4: "", Devices: ""}, UarchCPX}, // Cooperlake + {CPUIdentifierX86{Family: "6", Model: "(106|108)", Stepping: "", Capid4: "", Devices: ""}, UarchICX}, // Icelake + {CPUIdentifierX86{Family: "6", Model: "143", Stepping: "", Capid4: "", Devices: ""}, UarchSPR}, // Sapphire Rapids + {CPUIdentifierX86{Family: "6", Model: "207", Stepping: "", Capid4: "", Devices: ""}, UarchEMR}, // Emerald Rapids + {CPUIdentifierX86{Family: "6", Model: "175", Stepping: "", Capid4: "", Devices: ""}, UarchSRF}, // Sierra Forest + {CPUIdentifierX86{Family: "6", Model: "173", Stepping: "", Capid4: "", Devices: ""}, UarchGNR}, // Granite Rapids + {CPUIdentifierX86{Family: "6", Model: "174", Stepping: "", Capid4: "", Devices: ""}, UarchGNR_D}, // Granite Rapids - D + {CPUIdentifierX86{Family: "6", Model: "221", Stepping: "", Capid4: "", Devices: ""}, UarchCWF}, // Clearwater Forest + {CPUIdentifierX86{Family: "19", Model: "1", Stepping: "", Capid4: "", Devices: ""}, UarchDMR}, // Diamond Rapids // AMD CPUs - {CPUIdentifierX86{Family: "23", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "Naples"}, // Naples - {CPUIdentifierX86{Family: "23", Model: "49", Stepping: "", Capid4: "", Devices: ""}, "Rome"}, // Rome - {CPUIdentifierX86{Family: "25", Model: "1", Stepping: "", Capid4: "", Devices: ""}, "Milan"}, // Milan - {CPUIdentifierX86{Family: "25", Model: "(1[6-9]|2[0-9]|3[01])", Stepping: "", Capid4: "", Devices: ""}, "Genoa"}, // Genoa, model 16-31 - {CPUIdentifierX86{Family: "25", Model: "(16[0-9]|17[0-5])", Stepping: "", Capid4: "", Devices: ""}, "Bergamo"}, // Bergamo, model 160-175 - {CPUIdentifierX86{Family: "26", Model: "2", Stepping: "", Capid4: "", Devices: ""}, "Turin (Zen 5)"}, // Turin (Zen 5) - {CPUIdentifierX86{Family: "26", Model: "17", Stepping: "", Capid4: "", Devices: ""}, "Turin (Zen 5c)"}, // Turin (Zen 5c) + {CPUIdentifierX86{Family: "23", Model: "1", Stepping: "", Capid4: "", Devices: ""}, UarchNaples}, // Naples + {CPUIdentifierX86{Family: "23", Model: "49", Stepping: "", Capid4: "", Devices: ""}, UarchRome}, // Rome + {CPUIdentifierX86{Family: "25", Model: "1", Stepping: "", Capid4: "", Devices: ""}, UarchMilan}, // Milan + {CPUIdentifierX86{Family: "25", Model: "(1[6-9]|2[0-9]|3[01])", Stepping: "", Capid4: "", Devices: ""}, UarchGenoa}, // Genoa, model 16-31 + {CPUIdentifierX86{Family: "25", Model: "(16[0-9]|17[0-5])", Stepping: "", Capid4: "", Devices: ""}, UarchBergamo}, // Bergamo, model 160-175 + {CPUIdentifierX86{Family: "26", Model: "2", Stepping: "", Capid4: "", Devices: ""}, UarchTurinZen5}, // Turin (Zen 5) + {CPUIdentifierX86{Family: "26", Model: "17", Stepping: "", Capid4: "", Devices: ""}, UarchTurinZen5c}, // Turin (Zen 5c) } // cpuIdentifiersARM maps ARM CPU identification to microarchitecture names @@ -151,14 +206,14 @@ var cpuIdentifiersARM = []struct { Identifier CPUIdentifierARM MicroArchitecture string }{ - {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: "AWS Graviton2"}, "Graviton2"}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 - {CPUIdentifierARM{Implementer: "0x41", Part: "0xd40", DmidecodePart: "AWS Graviton3"}, "Graviton3"}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 - {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "AWS Graviton4"}, "Graviton4"}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 - {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "Not Specified"}, "Axion"}, // GCP Axion (c4a) Neoverse-V2 - {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: ""}, "Altra Family"}, // Ampere Altra - {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac3", DmidecodePart: ""}, "AmpereOne AC03"}, // AmpereOne AC03 - {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "X"}, "AmpereOne AC04"}, // AmpereOne AC04 - {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "M"}, "AmpereOne AC04_1"}, // AmpereOne AC04_1 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: "AWS Graviton2"}, UarchGraviton2}, // AWS Graviton 2 ([m|c|r]6g) Neoverse-N1 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd40", DmidecodePart: "AWS Graviton3"}, UarchGraviton3}, // AWS Graviton 3 ([m|c|r]7g) Neoverse-V1 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "AWS Graviton4"}, UarchGraviton4}, // AWS Graviton 4 ([m|c|r]8g) Neoverse-V2 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd4f", DmidecodePart: "Not Specified"}, UarchAxion}, // GCP Axion (c4a) Neoverse-V2 + {CPUIdentifierARM{Implementer: "0x41", Part: "0xd0c", DmidecodePart: ""}, UarchAltraFamily}, // Ampere Altra + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac3", DmidecodePart: ""}, UarchAmpereOneAC03}, // AmpereOne AC03 + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "X"}, UarchAmpereOneAC04}, // AmpereOne AC04 + {CPUIdentifierARM{Implementer: "0xc0", Part: "0xac4", DmidecodePart: "M"}, UarchAmpereOneAC04_1}, // AmpereOne AC04_1 } // NewCPUIdentifier creates a CPUIdentifier with all data elements @@ -370,13 +425,13 @@ func getSPRMicroArchitecture(capid4 string) (uarch string, err error) { bits = (capid4Int >> 6) & 0b11 switch bits { case 3: - uarch = "SPR_XCC" + uarch = UarchSPR_XCC case 1: - uarch = "SPR_MCC" + uarch = UarchSPR_MCC } } if uarch == "" { - uarch = "SPR" + uarch = UarchSPR } return } @@ -392,13 +447,13 @@ func getEMRMicroArchitecture(capid4 string) (uarch string, err error) { bits = (capid4Int >> 6) & 0b11 switch bits { case 3: - uarch = "EMR_XCC" + uarch = UarchEMR_XCC case 1: - uarch = "EMR_MCC" + uarch = UarchEMR_MCC } } if uarch == "" { - uarch = "EMR" + uarch = UarchEMR } return } @@ -408,16 +463,16 @@ func getGNRMicroArchitecture(devices string) (uarch string, err error) { d, err := strconv.Atoi(devices) if err == nil && d != 0 { if d%5 == 0 { // device count is multiple of 5 - uarch = "GNR_X3" + uarch = UarchGNR_X3 } else if d%4 == 0 { // device count is multiple of 4 - uarch = "GNR_X2" + uarch = UarchGNR_X2 } else if d%3 == 0 { // device count is multiple of 3 - uarch = "GNR_X1" + uarch = UarchGNR_X1 } } } if uarch == "" { - uarch = "GNR" + uarch = UarchGNR } return } @@ -427,14 +482,14 @@ func getSRFMicroArchitecture(devices string) (uarch string, err error) { d, err := strconv.Atoi(devices) if err == nil && d != 0 { if d%3 == 0 { // device count is multiple of 3 - uarch = "SRF_SP" + uarch = UarchSRF_SP } else if d%4 == 0 { // device count is multiple of 4 - uarch = "SRF_AP" + uarch = UarchSRF_AP } } } if uarch == "" { - uarch = "SRF" + uarch = UarchSRF } return } diff --git a/internal/script/script_defs.go b/internal/script/script_defs.go index 1192d346..60f96d74 100644 --- a/internal/script/script_defs.go +++ b/internal/script/script_defs.go @@ -183,14 +183,14 @@ var scriptDefinitions = map[string]ScriptDefinition{ LspciBitsScriptName: { Name: LspciBitsScriptName, ScriptTemplate: `lspci -s $(lspci | grep 325b | awk 'NR==1{{"{"}}print $1{{"}"}}') -xxx | awk '$1 ~ /^90/{{"{"}}print $9 $8 $7 $6; exit{{"}"}}'`, - MicroArchitectures: []string{"SPR", "EMR"}, + MicroArchitectures: []string{cpus.UarchSPR, cpus.UarchEMR}, Superuser: true, Depends: []string{"lspci"}, }, LspciDevicesScriptName: { Name: LspciDevicesScriptName, ScriptTemplate: "lspci -d 8086:3258 | wc -l", - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, Depends: []string{"lspci"}, }, LspciVmmScriptName: { @@ -379,7 +379,7 @@ echo "$cores" "$sse" "$avx2" "$avx512" "$avx512h" "$amx"`, Name: PrefetchersAtomName, ScriptTemplate: "rdmsr 0x1320", // Atom Pref_tuning1 Vendors: []string{cpus.IntelVendor}, - MicroArchitectures: []string{"SRF", "CWF"}, // SRF, CWF + MicroArchitectures: []string{cpus.UarchSRF, cpus.UarchCWF}, // SRF, CWF Lkms: []string{"msr"}, Depends: []string{"rdmsr"}, Superuser: true, @@ -487,21 +487,21 @@ echo "$epb"`, UncoreMaxFromTPMIScriptName: { Name: UncoreMaxFromTPMIScriptName, ScriptTemplate: "pcm-tpmi 2 0x18 -d -b 8:14", - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, UncoreMinFromTPMIScriptName: { Name: UncoreMinFromTPMIScriptName, ScriptTemplate: "pcm-tpmi 2 0x18 -d -b 15:21", - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, UncoreDieTypesFromTPMIScriptName: { Name: UncoreDieTypesFromTPMIScriptName, ScriptTemplate: "pcm-tpmi 2 0x10 -d -b 26:26", - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, @@ -572,7 +572,7 @@ for die in "${!die_types[@]}"; do done <<< "$output" done `, - MicroArchitectures: []string{"GNR", "GNR-D", "SRF", "CWF", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, @@ -647,7 +647,7 @@ do echo "" # finish the line done `, - MicroArchitectures: []string{"GNR", "GNR-D", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, @@ -702,7 +702,7 @@ do done echo "" # finish the line `, - MicroArchitectures: []string{"GNR", "GNR-D", "DMR"}, + MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchDMR}, Depends: []string{"pcm-tpmi"}, Superuser: true, }, From fee24d29a95ba029d9f05d150ed2d2fe4b282db8 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 11:35:03 -0800 Subject: [PATCH 12/15] add arm id scripts to summary table def Signed-off-by: Harper, Jason M --- internal/common/table_defs.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/common/table_defs.go b/internal/common/table_defs.go index 705a2c47..fdeee4ec 100644 --- a/internal/common/table_defs.go +++ b/internal/common/table_defs.go @@ -36,6 +36,9 @@ var TableDefinitions = map[string]table.TableDefinition{ script.ScalingGovernorScriptName, script.CstatesScriptName, script.ElcScriptName, + script.ArmImplementerScriptName, + script.ArmPartScriptName, + script.ArmDmidecodePartScriptName, }, FieldsFunc: briefSummaryTableValues}, } From 7fa9e49ae631b7419f184756d5a9e558a75bd626 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 13:07:52 -0800 Subject: [PATCH 13/15] remove log Signed-off-by: Harper, Jason M --- internal/common/power.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/common/power.go b/internal/common/power.go index 90da61a1..06f1c73b 100644 --- a/internal/common/power.go +++ b/internal/common/power.go @@ -99,7 +99,6 @@ func EPPFromOutput(outputs map[string]script.ScriptOutput) string { // EPBFromOutput gets EPB value from script outputs func EPBFromOutput(outputs map[string]script.ScriptOutput) string { if outputs[script.EpbScriptName].Exitcode != 0 || len(outputs[script.EpbScriptName].Stdout) == 0 { - slog.Warn("EPB scripts failed or produced no output") return "" } epb := strings.TrimSpace(outputs[script.EpbScriptName].Stdout) From c5a5a1235cf587c7a34539fa707393e993fd23d4 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 13:13:00 -0800 Subject: [PATCH 14/15] add ampere events and metrics from linux perf Signed-off-by: Harper, Jason M --- cmd/metrics/loader.go | 2 +- cmd/metrics/loader_component.go | 6 +- cmd/metrics/metadata.go | 2 + .../resources/component/ampereone/branch.json | 17 + .../resources/component/ampereone/bus.json | 32 + .../resources/component/ampereone/cache.json | 103 ++++ .../component/ampereone/core-imp-def.json | 578 ++++++++++++++++++ .../component/ampereone/exception.json | 44 ++ .../component/ampereone/instruction.json | 86 +++ .../component/ampereone/intrinsic.json | 14 + .../resources/component/ampereone/memory.json | 46 ++ .../component/ampereone/metrics.json | 386 ++++++++++++ .../component/ampereone/pipeline.json | 29 + .../resources/component/ampereone/spe.json | 14 + .../component/ampereonex/branch.json | 125 ++++ .../resources/component/ampereonex/bus.json | 20 + .../resources/component/ampereonex/cache.json | 208 +++++++ .../component/ampereonex/core-imp-def.json | 464 ++++++++++++++ .../component/ampereonex/exception.json | 47 ++ .../component/ampereonex/instruction.json | 128 ++++ .../component/ampereonex/intrinsic.json | 14 + .../component/ampereonex/memory.json | 43 ++ .../component/ampereonex/metrics.json | 442 ++++++++++++++ .../resources/component/ampereonex/mmu.json | 170 ++++++ .../component/ampereonex/pipeline.json | 41 ++ .../resources/component/ampereonex/spe.json | 14 + 26 files changed, 3073 insertions(+), 2 deletions(-) create mode 100644 cmd/metrics/resources/component/ampereone/branch.json create mode 100644 cmd/metrics/resources/component/ampereone/bus.json create mode 100644 cmd/metrics/resources/component/ampereone/cache.json create mode 100644 cmd/metrics/resources/component/ampereone/core-imp-def.json create mode 100644 cmd/metrics/resources/component/ampereone/exception.json create mode 100644 cmd/metrics/resources/component/ampereone/instruction.json create mode 100644 cmd/metrics/resources/component/ampereone/intrinsic.json create mode 100644 cmd/metrics/resources/component/ampereone/memory.json create mode 100644 cmd/metrics/resources/component/ampereone/metrics.json create mode 100644 cmd/metrics/resources/component/ampereone/pipeline.json create mode 100644 cmd/metrics/resources/component/ampereone/spe.json create mode 100644 cmd/metrics/resources/component/ampereonex/branch.json create mode 100644 cmd/metrics/resources/component/ampereonex/bus.json create mode 100644 cmd/metrics/resources/component/ampereonex/cache.json create mode 100644 cmd/metrics/resources/component/ampereonex/core-imp-def.json create mode 100644 cmd/metrics/resources/component/ampereonex/exception.json create mode 100644 cmd/metrics/resources/component/ampereonex/instruction.json create mode 100644 cmd/metrics/resources/component/ampereonex/intrinsic.json create mode 100644 cmd/metrics/resources/component/ampereonex/memory.json create mode 100644 cmd/metrics/resources/component/ampereonex/metrics.json create mode 100644 cmd/metrics/resources/component/ampereonex/mmu.json create mode 100644 cmd/metrics/resources/component/ampereonex/pipeline.json create mode 100644 cmd/metrics/resources/component/ampereonex/spe.json diff --git a/cmd/metrics/loader.go b/cmd/metrics/loader.go index 40544a49..19a16af8 100644 --- a/cmd/metrics/loader.go +++ b/cmd/metrics/loader.go @@ -88,7 +88,7 @@ func NewLoader(uarch string) (Loader, error) { 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(), nil - case cpus.UarchGraviton2, cpus.UarchGraviton3, cpus.UarchGraviton4, cpus.UarchAxion, cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: + 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(), nil default: diff --git a/cmd/metrics/loader_component.go b/cmd/metrics/loader_component.go index 893bffba..ed3a9fdb 100644 --- a/cmd/metrics/loader_component.go +++ b/cmd/metrics/loader_component.go @@ -495,12 +495,16 @@ func initializeComponentMetricEvaluable(expression string, evaluatorFunctions ma // 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, cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: + case cpus.UarchGraviton4, cpus.UarchAxion: return "neoverse-n2-v2", nil case cpus.UarchGraviton2: return "neoverse-n1", nil case cpus.UarchGraviton3: return "neoverse-v1", nil + case cpus.UarchAmpereOneAC03: + return "ampereone", nil + case cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: + return "ampereonex", nil } return "", fmt.Errorf("unsupported component loader architecture: %s", uarch) } diff --git a/cmd/metrics/metadata.go b/cmd/metrics/metadata.go index 3e6c151a..156745d2 100644 --- a/cmd/metrics/metadata.go +++ b/cmd/metrics/metadata.go @@ -902,6 +902,8 @@ func getARMSlotsByArchitecture(uarch string) (slots int, err error) { slots = 8 case cpus.UarchGraviton2, cpus.UarchGraviton3: slots = 6 + case cpus.UarchAmpereOneAC03: + slots = 6 case cpus.UarchAmpereOneAC04, cpus.UarchAmpereOneAC04_1: slots = 10 default: diff --git a/cmd/metrics/resources/component/ampereone/branch.json b/cmd/metrics/resources/component/ampereone/branch.json new file mode 100644 index 00000000..c751d57f --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/branch.json @@ -0,0 +1,17 @@ +[ + { + "ArchStdEvent": "BR_IMMED_SPEC" + }, + { + "ArchStdEvent": "BR_RETURN_SPEC" + }, + { + "ArchStdEvent": "BR_INDIRECT_SPEC" + }, + { + "ArchStdEvent": "BR_MIS_PRED" + }, + { + "ArchStdEvent": "BR_PRED" + } +] diff --git a/cmd/metrics/resources/component/ampereone/bus.json b/cmd/metrics/resources/component/ampereone/bus.json new file mode 100644 index 00000000..8623be12 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/bus.json @@ -0,0 +1,32 @@ +[ + { + "ArchStdEvent": "CPU_CYCLES" + }, + { + "ArchStdEvent": "BUS_CYCLES" + }, + { + "ArchStdEvent": "BUS_ACCESS_RD" + }, + { + "ArchStdEvent": "BUS_ACCESS_WR" + }, + { + "ArchStdEvent": "BUS_ACCESS_SHARED" + }, + { + "ArchStdEvent": "BUS_ACCESS_NOT_SHARED" + }, + { + "ArchStdEvent": "BUS_ACCESS_NORMAL" + }, + { + "ArchStdEvent": "BUS_ACCESS_PERIPH" + }, + { + "ArchStdEvent": "BUS_ACCESS" + }, + { + "ArchStdEvent": "CNT_CYCLES" + } +] diff --git a/cmd/metrics/resources/component/ampereone/cache.json b/cmd/metrics/resources/component/ampereone/cache.json new file mode 100644 index 00000000..ac75f12e --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/cache.json @@ -0,0 +1,103 @@ +[ + { + "ArchStdEvent": "L1D_CACHE_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_INVAL", + "Errata": "Errata AC03_CPU_41", + "BriefDescription": "L1D cache invalidate. Impacted by errata -" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_VICTIM" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_CLEAN" + }, + { + "ArchStdEvent": "L2D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L1I_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1I_TLB_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL" + }, + { + "ArchStdEvent": "L1I_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L2D_CACHE_WB" + }, + { + "ArchStdEvent": "L1D_TLB" + }, + { + "ArchStdEvent": "L1I_TLB" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL" + }, + { + "ArchStdEvent": "L2I_TLB_REFILL" + }, + { + "ArchStdEvent": "L2D_TLB" + }, + { + "ArchStdEvent": "L2I_TLB" + }, + { + "ArchStdEvent": "DTLB_WALK" + }, + { + "ArchStdEvent": "ITLB_WALK" + }, + { + "ArchStdEvent": "L1D_CACHE_LMISS_RD" + }, + { + "ArchStdEvent": "L1I_CACHE_LMISS" + }, + { + "ArchStdEvent": "L2D_CACHE_LMISS_RD" + } +] diff --git a/cmd/metrics/resources/component/ampereone/core-imp-def.json b/cmd/metrics/resources/component/ampereone/core-imp-def.json new file mode 100644 index 00000000..879ff21e --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/core-imp-def.json @@ -0,0 +1,578 @@ +[ + { + "PublicDescription": "Level 2 prefetch requests, refilled to L2 cache", + "EventCode": "0x10A", + "EventName": "L2_PREFETCH_REFILL", + "BriefDescription": "Level 2 prefetch requests, refilled to L2 cache" + }, + { + "PublicDescription": "Level 2 prefetch requests, late", + "EventCode": "0x10B", + "EventName": "L2_PREFETCH_UPGRADE", + "BriefDescription": "Level 2 prefetch requests, late" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB", + "EventCode": "0x110", + "EventName": "BPU_HIT_BTB", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB", + "EventCode": "0x111", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor", + "EventCode": "0x112", + "EventName": "BPU_HIT_INDIRECT_PREDICTOR", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor", + "EventCode": "0x113", + "EventName": "BPU_HIT_RSB", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor" + }, + { + "PublicDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB", + "EventCode": "0x114", + "EventName": "BPU_UNCONDITIONAL_BRANCH_MISS_BTB", + "BriefDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted", + "EventCode": "0x115", + "EventName": "BPU_BRANCH_NO_HIT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict", + "EventCode": "0x116", + "EventName": "BPU_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict", + "EventCode": "0x117", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict", + "EventCode": "0x118", + "EventName": "BPU_INDIRECT_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict", + "EventCode": "0x119", + "EventName": "BPU_HIT_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict", + "EventCode": "0x11a", + "EventName": "BPU_MISS_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict", + "EventCode": "0x11b", + "EventName": "BPU_NO_PREDICTION_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict", + "EventCode": "0x11c", + "EventName": "BPU_BTB_UPDATE", + "BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict" + }, + { + "PublicDescription": "Count predict pipe stalls due to speculative return address predictor full", + "EventCode": "0x11d", + "EventName": "BPU_RSB_FULL_STALL", + "BriefDescription": "Count predict pipe stalls due to speculative return address predictor full" + }, + { + "PublicDescription": "Macro-ops speculatively decoded", + "EventCode": "0x11f", + "EventName": "ICF_INST_SPEC_DECODE", + "BriefDescription": "Macro-ops speculatively decoded" + }, + { + "PublicDescription": "Flushes", + "EventCode": "0x120", + "EventName": "GPC_FLUSH", + "BriefDescription": "Flushes" + }, + { + "PublicDescription": "Flushes due to memory hazards", + "EventCode": "0x121", + "EventName": "GPC_FLUSH_MEM_FAULT", + "BriefDescription": "Flushes due to memory hazards" + }, + { + "PublicDescription": "ETM extout bit 0", + "EventCode": "0x141", + "EventName": "MSC_ETM_EXTOUT0", + "BriefDescription": "ETM extout bit 0" + }, + { + "PublicDescription": "ETM extout bit 1", + "EventCode": "0x142", + "EventName": "MSC_ETM_EXTOUT1", + "BriefDescription": "ETM extout bit 1" + }, + { + "PublicDescription": "ETM extout bit 2", + "EventCode": "0x143", + "EventName": "MSC_ETM_EXTOUT2", + "BriefDescription": "ETM extout bit 2" + }, + { + "PublicDescription": "ETM extout bit 3", + "EventCode": "0x144", + "EventName": "MSC_ETM_EXTOUT3", + "BriefDescription": "ETM extout bit 3" + }, + { + "PublicDescription": "Bus request sn", + "EventCode": "0x156", + "EventName": "L2C_SNOOP", + "BriefDescription": "Bus request sn" + }, + { + "PublicDescription": "L2 TXDAT LCRD blocked", + "EventCode": "0x169", + "EventName": "L2C_DAT_CRD_STALL", + "BriefDescription": "L2 TXDAT LCRD blocked" + }, + { + "PublicDescription": "L2 TXRSP LCRD blocked", + "EventCode": "0x16a", + "EventName": "L2C_RSP_CRD_STALL", + "BriefDescription": "L2 TXRSP LCRD blocked" + }, + { + "PublicDescription": "L2 TXREQ LCRD blocked", + "EventCode": "0x16b", + "EventName": "L2C_REQ_CRD_STALL", + "BriefDescription": "L2 TXREQ LCRD blocked" + }, + { + "PublicDescription": "Early mispredict", + "EventCode": "0xD100", + "EventName": "ICF_EARLY_MIS_PRED", + "BriefDescription": "Early mispredict" + }, + { + "PublicDescription": "FEQ full cycles", + "EventCode": "0xD101", + "EventName": "ICF_FEQ_FULL", + "BriefDescription": "FEQ full cycles" + }, + { + "PublicDescription": "Instruction FIFO Full", + "EventCode": "0xD102", + "EventName": "ICF_INST_FIFO_FULL", + "BriefDescription": "Instruction FIFO Full" + }, + { + "PublicDescription": "L1I TLB miss", + "EventCode": "0xD103", + "EventName": "L1I_TLB_MISS", + "BriefDescription": "L1I TLB miss" + }, + { + "PublicDescription": "ICF sent 0 instructions to IDR this cycle", + "EventCode": "0xD104", + "EventName": "ICF_STALL", + "BriefDescription": "ICF sent 0 instructions to IDR this cycle" + }, + { + "PublicDescription": "PC FIFO Full", + "EventCode": "0xD105", + "EventName": "ICF_PC_FIFO_FULL", + "BriefDescription": "PC FIFO Full" + }, + { + "PublicDescription": "Stall due to BOB ID", + "EventCode": "0xD200", + "EventName": "IDR_STALL_BOB_ID", + "BriefDescription": "Stall due to BOB ID" + }, + { + "PublicDescription": "Dispatch stall due to LOB entries", + "EventCode": "0xD201", + "EventName": "IDR_STALL_LOB_ID", + "BriefDescription": "Dispatch stall due to LOB entries" + }, + { + "PublicDescription": "Dispatch stall due to SOB entries", + "EventCode": "0xD202", + "EventName": "IDR_STALL_SOB_ID", + "BriefDescription": "Dispatch stall due to SOB entries" + }, + { + "PublicDescription": "Dispatch stall due to IXU scheduler entries", + "EventCode": "0xD203", + "EventName": "IDR_STALL_IXU_SCHED", + "BriefDescription": "Dispatch stall due to IXU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to FSU scheduler entries", + "EventCode": "0xD204", + "EventName": "IDR_STALL_FSU_SCHED", + "BriefDescription": "Dispatch stall due to FSU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to ROB entries", + "EventCode": "0xD205", + "EventName": "IDR_STALL_ROB_ID", + "BriefDescription": "Dispatch stall due to ROB entries" + }, + { + "PublicDescription": "Dispatch stall due to flush (6 cycles)", + "EventCode": "0xD206", + "EventName": "IDR_STALL_FLUSH", + "BriefDescription": "Dispatch stall due to flush (6 cycles)" + }, + { + "PublicDescription": "Dispatch stall due to WFI", + "EventCode": "0xD207", + "EventName": "IDR_STALL_WFI", + "BriefDescription": "Dispatch stall due to WFI" + }, + { + "PublicDescription": "Number of SWOB drains triggered by timeout", + "EventCode": "0xD208", + "EventName": "IDR_STALL_SWOB_TIMEOUT", + "BriefDescription": "Number of SWOB drains triggered by timeout" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain", + "EventCode": "0xD209", + "EventName": "IDR_STALL_SWOB_RAW", + "BriefDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register write when SWOB full", + "EventCode": "0xD20A", + "EventName": "IDR_STALL_SWOB_FULL", + "BriefDescription": "Number of SWOB drains triggered by system register write when SWOB full" + }, + { + "PublicDescription": "Dispatch stall due to L1 instruction cache miss", + "EventCode": "0xD20B", + "EventName": "STALL_FRONTEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 instruction cache miss" + }, + { + "PublicDescription": "Dispatch stall due to L1 instruction TLB miss", + "EventCode": "0xD20C", + "EventName": "STALL_FRONTEND_TLB", + "BriefDescription": "Dispatch stall due to L1 instruction TLB miss" + }, + { + "PublicDescription": "Dispatch stall due to L1 data cache miss", + "EventCode": "0xD20D", + "EventName": "STALL_BACKEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 data cache miss" + }, + { + "PublicDescription": "Dispatch stall due to L1 data TLB miss", + "EventCode": "0xD20E", + "EventName": "STALL_BACKEND_TLB", + "BriefDescription": "Dispatch stall due to L1 data TLB miss" + }, + { + "PublicDescription": "Dispatch stall due to lack of any core resource", + "EventCode": "0xD20F", + "EventName": "STALL_BACKEND_RESOURCE", + "BriefDescription": "Dispatch stall due to lack of any core resource" + }, + { + "PublicDescription": "Instructions issued by the scheduler", + "EventCode": "0xD300", + "EventName": "IXU_NUM_UOPS_ISSUED", + "BriefDescription": "Instructions issued by the scheduler" + }, + { + "PublicDescription": "Any uop issued was canceled for any reason", + "EventCode": "0xD301", + "EventName": "IXU_ISSUE_CANCEL", + "BriefDescription": "Any uop issued was canceled for any reason" + }, + { + "PublicDescription": "A load wakeup to the scheduler has been cancelled", + "EventCode": "0xD302", + "EventName": "IXU_LOAD_CANCEL", + "BriefDescription": "A load wakeup to the scheduler has been cancelled" + }, + { + "PublicDescription": "The scheduler had to cancel one slow Uop due to resource conflict", + "EventCode": "0xD303", + "EventName": "IXU_SLOW_CANCEL", + "BriefDescription": "The scheduler had to cancel one slow Uop due to resource conflict" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA", + "EventCode": "0xD304", + "EventName": "IXU_IXA_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 0", + "EventCode": "0xD305", + "EventName": "IXU_IXA_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 1", + "EventCode": "0xD306", + "EventName": "IXU_IXA_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB", + "EventCode": "0xD307", + "EventName": "IXU_IXB_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 0", + "EventCode": "0xD308", + "EventName": "IXU_IXB_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 1", + "EventCode": "0xD309", + "EventName": "IXU_IXB_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC", + "EventCode": "0xD30A", + "EventName": "IXU_IXC_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 0", + "EventCode": "0xD30B", + "EventName": "IXU_IXC_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 1", + "EventCode": "0xD30C", + "EventName": "IXU_IXC_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD", + "EventCode": "0xD30D", + "EventName": "IXU_IXD_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 0", + "EventCode": "0xD30E", + "EventName": "IXU_IXD_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 1", + "EventCode": "0xD30F", + "EventName": "IXU_IXD_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 1" + }, + { + "PublicDescription": "Uops issued by the FSU scheduler", + "EventCode": "0xD400", + "EventName": "FSU_ISSUED", + "BriefDescription": "Uops issued by the FSU scheduler" + }, + { + "PublicDescription": "Uops issued by the scheduler on pipe X", + "EventCode": "0xD401", + "EventName": "FSU_FSX_ISSUED", + "BriefDescription": "Uops issued by the scheduler on pipe X" + }, + { + "PublicDescription": "Uops issued by the scheduler on pipe Y", + "EventCode": "0xD402", + "EventName": "FSU_FSY_ISSUED", + "BriefDescription": "Uops issued by the scheduler on pipe Y" + }, + { + "PublicDescription": "Uops issued by the scheduler on pipe Z", + "EventCode": "0xD403", + "EventName": "FSU_FSZ_ISSUED", + "BriefDescription": "Uops issued by the scheduler on pipe Z" + }, + { + "PublicDescription": "Uops canceled (load cancels)", + "EventCode": "0xD404", + "EventName": "FSU_CANCEL", + "BriefDescription": "Uops canceled (load cancels)" + }, + { + "PublicDescription": "Count scheduler stalls due to divide/sqrt", + "EventCode": "0xD405", + "EventName": "FSU_DIV_SQRT_STALL", + "BriefDescription": "Count scheduler stalls due to divide/sqrt" + }, + { + "PublicDescription": "Number of SWOB drains", + "EventCode": "0xD500", + "EventName": "GPC_SWOB_DRAIN", + "BriefDescription": "Number of SWOB drains" + }, + { + "PublicDescription": "GPC detected a Breakpoint instruction match", + "EventCode": "0xD501", + "EventName": "BREAKPOINT_MATCH", + "BriefDescription": "GPC detected a Breakpoint instruction match" + }, + { + "PublicDescription": "L1D TLB miss", + "EventCode": "0xD600", + "EventName": "L1D_TLB_MISS", + "BriefDescription": "L1D TLB miss" + }, + { + "PublicDescription": "OFB full cycles", + "EventCode": "0xD601", + "EventName": "OFB_FULL", + "BriefDescription": "OFB full cycles" + }, + { + "PublicDescription": "Load satisified from store forwarded data", + "EventCode": "0xD605", + "EventName": "LD_FROM_ST_FWD", + "BriefDescription": "Load satisified from store forwarded data" + }, + { + "PublicDescription": "L1 prefetcher, load prefetch requests generated", + "EventCode": "0xD606", + "EventName": "L1_PFETCH_LD_GEN", + "BriefDescription": "L1 prefetcher, load prefetch requests generated" + }, + { + "PublicDescription": "L1 prefetcher, load prefetch fills into the L1 cache", + "EventCode": "0xD607", + "EventName": "L1_PFETCH_LD_FILL", + "BriefDescription": "L1 prefetcher, load prefetch fills into the L1 cache" + }, + { + "PublicDescription": "L1 prefetcher, load prefetch to L2 generated", + "EventCode": "0xD608", + "EventName": "L1_PFETCH_L2_REQ", + "BriefDescription": "L1 prefetcher, load prefetch to L2 generated" + }, + { + "PublicDescription": "L1 prefetcher, distance was reset", + "EventCode": "0xD609", + "EventName": "L1_PFETCH_DIST_RST", + "BriefDescription": "L1 prefetcher, distance was reset" + }, + { + "PublicDescription": "L1 prefetcher, distance was increased", + "EventCode": "0xD60A", + "EventName": "L1_PFETCH_DIST_INC", + "BriefDescription": "L1 prefetcher, distance was increased" + }, + { + "PublicDescription": "L1 prefetcher, table entry is trained", + "EventCode": "0xD60B", + "EventName": "L1_PFETCH_ENTRY_TRAINED", + "BriefDescription": "L1 prefetcher, table entry is trained" + }, + { + "PublicDescription": "Store retirement pipe stall", + "EventCode": "0xD60C", + "EventName": "LSU_ST_RETIRE_STALL", + "BriefDescription": "Store retirement pipe stall" + }, + { + "PublicDescription": "LSU detected a Watchpoint data match", + "EventCode": "0xD60D", + "EventName": "WATCHPOINT_MATCH", + "BriefDescription": "LSU detected a Watchpoint data match" + }, + { + "PublicDescription": "L2 pipeline replay", + "EventCode": "0xD700", + "EventName": "L2C_PIPE_REPLAY", + "BriefDescription": "L2 pipeline replay" + }, + { + "PublicDescription": "L2 refill from I-side miss", + "EventCode": "0xD701", + "EventName": "L2C_INST_REFILL", + "BriefDescription": "L2 refill from I-side miss" + }, + { + "PublicDescription": "L2 refill from D-side miss", + "EventCode": "0xD702", + "EventName": "L2C_DATA_REFILL", + "BriefDescription": "L2 refill from D-side miss" + }, + { + "PublicDescription": "L2 prefetcher, load prefetch requests generated", + "EventCode": "0xD703", + "EventName": "L2_PREFETCH_REQ", + "BriefDescription": "L2 prefetcher, load prefetch requests generated" + }, + { + "PublicDescription": "L2D OTB allocate", + "EventCode": "0xD800", + "EventName": "MMU_D_OTB_ALLOC", + "BriefDescription": "L2D OTB allocate" + }, + { + "PublicDescription": "D-side Stage1 tablewalk fault", + "EventCode": "0xD80B", + "EventName": "MMU_D_S1_WALK_FAULT", + "BriefDescription": "D-side Stage1 tablewalk fault" + }, + { + "PublicDescription": "D-side Stage2 tablewalk fault", + "EventCode": "0xD80C", + "EventName": "MMU_D_S2_WALK_FAULT", + "BriefDescription": "D-side Stage2 tablewalk fault" + }, + { + "PublicDescription": "D-side Tablewalk steps or descriptor fetches", + "EventCode": "0xD80D", + "EventName": "MMU_D_WALK_STEPS", + "BriefDescription": "D-side Tablewalk steps or descriptor fetches" + }, + { + "PublicDescription": "L2I OTB allocate", + "EventCode": "0xD900", + "EventName": "MMU_I_OTB_ALLOC", + "BriefDescription": "L2I OTB allocate" + }, + { + "PublicDescription": "I-side Stage1 tablewalk fault", + "EventCode": "0xD90B", + "EventName": "MMU_I_S1_WALK_FAULT", + "BriefDescription": "I-side Stage1 tablewalk fault" + }, + { + "PublicDescription": "I-side Stage2 tablewalk fault", + "EventCode": "0xD90C", + "EventName": "MMU_I_S2_WALK_FAULT", + "BriefDescription": "I-side Stage2 tablewalk fault" + }, + { + "PublicDescription": "I-side Tablewalk steps or descriptor fetches", + "EventCode": "0xD90D", + "EventName": "MMU_I_WALK_STEPS", + "BriefDescription": "I-side Tablewalk steps or descriptor fetches" + } +] diff --git a/cmd/metrics/resources/component/ampereone/exception.json b/cmd/metrics/resources/component/ampereone/exception.json new file mode 100644 index 00000000..ada052e1 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/exception.json @@ -0,0 +1,44 @@ +[ + { + "ArchStdEvent": "EXC_UNDEF" + }, + { + "ArchStdEvent": "EXC_SVC" + }, + { + "ArchStdEvent": "EXC_PABORT" + }, + { + "ArchStdEvent": "EXC_DABORT" + }, + { + "ArchStdEvent": "EXC_IRQ" + }, + { + "ArchStdEvent": "EXC_FIQ" + }, + { + "ArchStdEvent": "EXC_HVC" + }, + { + "ArchStdEvent": "EXC_TRAP_PABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_DABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_OTHER" + }, + { + "ArchStdEvent": "EXC_TRAP_IRQ" + }, + { + "ArchStdEvent": "EXC_TRAP_FIQ" + }, + { + "ArchStdEvent": "EXC_TAKEN" + }, + { + "ArchStdEvent": "EXC_RETURN" + } +] diff --git a/cmd/metrics/resources/component/ampereone/instruction.json b/cmd/metrics/resources/component/ampereone/instruction.json new file mode 100644 index 00000000..9fe697d1 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/instruction.json @@ -0,0 +1,86 @@ +[ + { + "ArchStdEvent": "SW_INCR" + }, + { + "ArchStdEvent": "ST_RETIRED" + }, + { + "ArchStdEvent": "OP_SPEC" + }, + { + "ArchStdEvent": "LD_SPEC" + }, + { + "ArchStdEvent": "ST_SPEC" + }, + { + "ArchStdEvent": "LDST_SPEC" + }, + { + "ArchStdEvent": "DP_SPEC" + }, + { + "ArchStdEvent": "ASE_SPEC" + }, + { + "ArchStdEvent": "VFP_SPEC" + }, + { + "ArchStdEvent": "PC_WRITE_SPEC" + }, + { + "ArchStdEvent": "BR_IMMED_RETIRED" + }, + { + "ArchStdEvent": "BR_RETURN_RETIRED" + }, + { + "ArchStdEvent": "CRYPTO_SPEC" + }, + { + "ArchStdEvent": "ISB_SPEC" + }, + { + "ArchStdEvent": "DSB_SPEC" + }, + { + "ArchStdEvent": "DMB_SPEC" + }, + { + "ArchStdEvent": "RC_LD_SPEC" + }, + { + "ArchStdEvent": "RC_ST_SPEC" + }, + { + "ArchStdEvent": "INST_RETIRED" + }, + { + "ArchStdEvent": "CID_WRITE_RETIRED" + }, + { + "ArchStdEvent": "PC_WRITE_RETIRED" + }, + { + "ArchStdEvent": "INST_SPEC" + }, + { + "ArchStdEvent": "TTBR_WRITE_RETIRED" + }, + { + "ArchStdEvent": "BR_RETIRED" + }, + { + "ArchStdEvent": "BR_MIS_PRED_RETIRED" + }, + { + "ArchStdEvent": "OP_RETIRED" + }, + { + "PublicDescription": "Operation speculatively executed, NOP", + "EventCode": "0x100", + "EventName": "NOP_SPEC", + "BriefDescription": "Speculatively executed, NOP" + } +] diff --git a/cmd/metrics/resources/component/ampereone/intrinsic.json b/cmd/metrics/resources/component/ampereone/intrinsic.json new file mode 100644 index 00000000..7ecffb98 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/intrinsic.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "LDREX_SPEC" + }, + { + "ArchStdEvent": "STREX_PASS_SPEC" + }, + { + "ArchStdEvent": "STREX_FAIL_SPEC" + }, + { + "ArchStdEvent": "STREX_SPEC" + } +] diff --git a/cmd/metrics/resources/component/ampereone/memory.json b/cmd/metrics/resources/component/ampereone/memory.json new file mode 100644 index 00000000..13382d29 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/memory.json @@ -0,0 +1,46 @@ +[ + { + "ArchStdEvent": "LD_RETIRED", + "Errata": "Errata AC03_CPU_52", + "BriefDescription": "Instruction architecturally executed, condition code check pass, load. Impacted by errata -" + }, + { + "ArchStdEvent": "MEM_ACCESS_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_WR" + }, + { + "ArchStdEvent": "UNALIGNED_LD_SPEC" + }, + { + "ArchStdEvent": "UNALIGNED_ST_SPEC" + }, + { + "ArchStdEvent": "UNALIGNED_LDST_SPEC" + }, + { + "ArchStdEvent": "LD_ALIGN_LAT" + }, + { + "ArchStdEvent": "ST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS" + }, + { + "ArchStdEvent": "MEMORY_ERROR" + }, + { + "ArchStdEvent": "LDST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_WR" + } +] diff --git a/cmd/metrics/resources/component/ampereone/metrics.json b/cmd/metrics/resources/component/ampereone/metrics.json new file mode 100644 index 00000000..32410443 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/metrics.json @@ -0,0 +1,386 @@ +[ + { + "MetricName": "branch_miss_pred_rate", + "MetricExpr": "BR_MIS_PRED / BR_PRED", + "BriefDescription": "Branch predictor misprediction rate. May not count branches that are never resolved because they are in the misprediction shadow of an earlier branch", + "MetricGroup": "branch", + "ScaleUnit": "100%" + }, + { + "MetricName": "bus_utilization", + "MetricExpr": "((BUS_ACCESS / (BUS_CYCLES * 1)) * 100)", + "BriefDescription": "Core-to-uncore bus utilization", + "MetricGroup": "Bus", + "ScaleUnit": "1percent of bus cycles" + }, + { + "MetricName": "l1d_cache_miss_ratio", + "MetricExpr": "(L1D_CACHE_REFILL / L1D_CACHE)", + "BriefDescription": "This metric measures the ratio of level 1 data cache accesses missed to the total number of level 1 data cache accesses. This gives an indication of the effectiveness of the level 1 data cache.", + "MetricGroup": "Miss_Ratio;L1D_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_miss_ratio", + "MetricExpr": "(L1I_CACHE_REFILL / L1I_CACHE)", + "BriefDescription": "This metric measures the ratio of level 1 instruction cache accesses missed to the total number of level 1 instruction cache accesses. This gives an indication of the effectiveness of the level 1 instruction cache.", + "MetricGroup": "Miss_Ratio;L1I_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "Miss_Ratio;l1d_cache_read_miss", + "MetricExpr": "L1D_CACHE_LMISS_RD / L1D_CACHE_RD", + "BriefDescription": "L1D cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l2_cache_miss_ratio", + "MetricExpr": "(L2D_CACHE_REFILL / L2D_CACHE)", + "BriefDescription": "This metric measures the ratio of level 2 cache accesses missed to the total number of level 2 cache accesses. This gives an indication of the effectiveness of the level 2 cache, which is a unified cache that stores both data and instruction. Note that cache accesses in this cache are either data memory access or instruction fetch as this is a unified cache.", + "MetricGroup": "Miss_Ratio;L2_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_read_miss_rate", + "MetricExpr": "L1I_CACHE_LMISS / L1I_CACHE", + "BriefDescription": "L1I cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l2d_cache_read_miss_rate", + "MetricExpr": "L2D_CACHE_LMISS_RD / L2D_CACHE_RD", + "BriefDescription": "L2 cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l1d_cache_miss_mpki", + "MetricExpr": "(L1D_CACHE_LMISS_RD * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (data)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "l1i_cache_miss_mpki", + "MetricExpr": "(L1I_CACHE_LMISS * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (instruction)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "simd_percentage", + "MetricExpr": "((ASE_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures advanced SIMD operations as a percentage of total operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "crypto_percentage", + "MetricExpr": "((CRYPTO_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures crypto operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "gflops", + "MetricExpr": "VFP_SPEC / (duration_time * 1e9)", + "BriefDescription": "Giga-floating point operations per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "integer_dp_percentage", + "MetricExpr": "((DP_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures scalar integer operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "ipc", + "MetricExpr": "(INST_RETIRED / CPU_CYCLES)", + "BriefDescription": "This metric measures the number of instructions retired per cycle.", + "MetricGroup": "General", + "ScaleUnit": "1per cycle" + }, + { + "MetricName": "load_percentage", + "MetricExpr": "((LD_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures load operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "load_store_spec_rate", + "MetricExpr": "((LDST_SPEC / INST_SPEC) * 100)", + "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speculatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "retired_mips", + "MetricExpr": "INST_RETIRED / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "spec_utilization_mips", + "MetricExpr": "INST_SPEC / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "PEutilization" + }, + { + "MetricName": "pc_write_spec_rate", + "MetricExpr": "((PC_WRITE_SPEC / INST_SPEC) * 100)", + "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speculatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "store_percentage", + "MetricExpr": "((ST_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures store operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "scalar_fp_percentage", + "MetricExpr": "((VFP_SPEC / INST_SPEC) * 100)", + "BriefDescription": "This metric measures scalar floating point operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "1percent of operations" + }, + { + "MetricName": "retired_rate", + "MetricExpr": "OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted", + "MetricExpr": "1 - (OP_RETIRED / (CPU_CYCLES * #slots))", + "BriefDescription": "Of all the micro-operations issued, what proportion are lost", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted_rate", + "MetricExpr": "1 - OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are not retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "stall_backend_cache_rate", + "MetricExpr": "((STALL_BACKEND_CACHE / CPU_CYCLES) * 100)", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_backend_resource_rate", + "MetricExpr": "((STALL_BACKEND_RESOURCE / CPU_CYCLES) * 100)", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and resource full", + "MetricGroup": "Stall", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_backend_tlb_rate", + "MetricExpr": "((STALL_BACKEND_TLB / CPU_CYCLES) * 100)", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_frontend_cache_rate", + "MetricExpr": "((STALL_FRONTEND_CACHE / CPU_CYCLES) * 100)", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_frontend_tlb_rate", + "MetricExpr": "((STALL_FRONTEND_TLB / CPU_CYCLES) * 100)", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "dtlb_walk_ratio", + "MetricExpr": "(DTLB_WALK / L1D_TLB)", + "BriefDescription": "This metric measures the ratio of data TLB Walks to the total number of data TLB accesses. This gives an indication of the effectiveness of the data TLB accesses.", + "MetricGroup": "Miss_Ratio;DTLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "MetricName": "itlb_walk_ratio", + "MetricExpr": "(ITLB_WALK / L1I_TLB)", + "BriefDescription": "This metric measures the ratio of instruction TLB Walks to the total number of instruction TLB accesses. This gives an indication of the effectiveness of the instruction TLB accesses.", + "MetricGroup": "Miss_Ratio;ITLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "ArchStdEvent": "backend_bound" + }, + { + "ArchStdEvent": "frontend_bound", + "MetricExpr": "100 - (retired_fraction + slots_lost_misspeculation_fraction + backend_bound)" + }, + { + "MetricName": "slots_lost_misspeculation_fraction", + "MetricExpr": "100 * ((OP_SPEC - OP_RETIRED) / (CPU_CYCLES * #slots))", + "BriefDescription": "Fraction of slots lost due to misspeculation", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "retired_fraction", + "MetricExpr": "100 * (OP_RETIRED / (CPU_CYCLES * #slots))", + "BriefDescription": "Fraction of slots retiring, useful work", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "backend_core", + "MetricExpr": "(backend_bound / 100) - backend_memory", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend non-memory subsystem issues", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "backend_memory", + "MetricExpr": "(STALL_BACKEND_TLB + STALL_BACKEND_CACHE) / CPU_CYCLES", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend memory subsystem issues (cache/tlb miss)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "branch_mispredict", + "MetricExpr": "(BR_MIS_PRED_RETIRED / GPC_FLUSH) * slots_lost_misspeculation_fraction", + "BriefDescription": "Fraction of slots lost due to branch misprediciton", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_bandwidth", + "MetricExpr": "frontend_bound - frontend_latency", + "BriefDescription": "Fraction of slots the CPU did not dispatch at full bandwidth - able to dispatch partial slots only (1, 2, or 3 uops)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_latency", + "MetricExpr": "((STALL_FRONTEND - ((STALL_SLOT_FRONTEND - ((frontend_bound / 100) * CPU_CYCLES * #slots)) / #slots)) / CPU_CYCLES) * 100", + "BriefDescription": "Fraction of slots the CPU was stalled due to frontend latency issues (cache/tlb miss); nothing to dispatch", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "other_miss_pred", + "MetricExpr": "slots_lost_misspeculation_fraction - branch_mispredict", + "BriefDescription": "Fraction of slots lost due to other/non-branch misprediction misspeculation", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "pipe_utilization", + "MetricExpr": "100 * ((IXU_NUM_UOPS_ISSUED + FSU_ISSUED) / (CPU_CYCLES * 6))", + "BriefDescription": "Fraction of execute slots utilized", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "d_cache_l2_miss_rate", + "MetricExpr": "((STALL_BACKEND_MEM / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data L2 cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "d_cache_miss_rate", + "MetricExpr": "((STALL_BACKEND_CACHE / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "d_tlb_miss_rate", + "MetricExpr": "((STALL_BACKEND_TLB / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "fsu_pipe_utilization", + "MetricExpr": "((FSU_ISSUED / (CPU_CYCLES * 2)) * 100)", + "BriefDescription": "Fraction of FSU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "i_cache_miss_rate", + "MetricExpr": "((STALL_FRONTEND_CACHE / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "i_tlb_miss_rate", + "MetricExpr": "((STALL_FRONTEND_TLB / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "ixu_pipe_utilization", + "MetricExpr": "((IXU_NUM_UOPS_ISSUED / (CPU_CYCLES * #slots)) * 100)", + "BriefDescription": "Fraction of IXU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "stall_recovery_rate", + "MetricExpr": "((IDR_STALL_FLUSH / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled due to flush recovery", + "MetricGroup": "TopdownL3", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "stall_fsu_sched_rate", + "MetricExpr": "((IDR_STALL_FSU_SCHED / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled and FSU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_ixu_sched_rate", + "MetricExpr": "((IDR_STALL_IXU_SCHED / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled and IXU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_lob_id_rate", + "MetricExpr": "((IDR_STALL_LOB_ID / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled and LOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_rob_id_rate", + "MetricExpr": "((IDR_STALL_ROB_ID / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled and ROB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "1percent of cycles" + }, + { + "MetricName": "stall_sob_id_rate", + "MetricExpr": "((IDR_STALL_SOB_ID / CPU_CYCLES) * 100)", + "BriefDescription": "Fraction of cycles the CPU was stalled and SOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "1percent of cycles" + } +] diff --git a/cmd/metrics/resources/component/ampereone/pipeline.json b/cmd/metrics/resources/component/ampereone/pipeline.json new file mode 100644 index 00000000..71102837 --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/pipeline.json @@ -0,0 +1,29 @@ +[ + { + "ArchStdEvent": "STALL_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_BACKEND" + }, + { + "ArchStdEvent": "STALL", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT_BACKEND" + }, + { + "ArchStdEvent": "STALL_SLOT_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT" + }, + { + "ArchStdEvent": "STALL_BACKEND_MEM" + } +] diff --git a/cmd/metrics/resources/component/ampereone/spe.json b/cmd/metrics/resources/component/ampereone/spe.json new file mode 100644 index 00000000..20f2165c --- /dev/null +++ b/cmd/metrics/resources/component/ampereone/spe.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "SAMPLE_POP" + }, + { + "ArchStdEvent": "SAMPLE_FEED" + }, + { + "ArchStdEvent": "SAMPLE_FILTRATE" + }, + { + "ArchStdEvent": "SAMPLE_COLLISION" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/branch.json b/cmd/metrics/resources/component/ampereonex/branch.json new file mode 100644 index 00000000..a632755f --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/branch.json @@ -0,0 +1,125 @@ +[ + { + "ArchStdEvent": "BR_IMMED_SPEC" + }, + { + "ArchStdEvent": "BR_RETURN_SPEC" + }, + { + "ArchStdEvent": "BR_INDIRECT_SPEC" + }, + { + "ArchStdEvent": "BR_MIS_PRED" + }, + { + "ArchStdEvent": "BR_PRED" + }, + { + "PublicDescription": "Instruction architecturally executed, branch not taken", + "EventCode": "0x8107", + "EventName": "BR_SKIP_RETIRED", + "BriefDescription": "Instruction architecturally executed, branch not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, immediate branch taken", + "EventCode": "0x8108", + "EventName": "BR_IMMED_TAKEN_RETIRED", + "BriefDescription": "Instruction architecturally executed, immediate branch taken" + }, + { + "PublicDescription": "Instruction architecturally executed, indirect branch excluding return retired", + "EventCode": "0x810c", + "EventName": "BR_INDNR_TAKEN_RETIRED", + "BriefDescription": "Instruction architecturally executed, indirect branch excluding return retired" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted immediate branch", + "EventCode": "0x8110", + "EventName": "BR_IMMED_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted immediate branch" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted immediate branch", + "EventCode": "0x8111", + "EventName": "BR_IMMED_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted immediate branch" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted indirect branch", + "EventCode": "0x8112", + "EventName": "BR_IND_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted indirect branch" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch", + "EventCode": "0x8113", + "EventName": "BR_IND_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted procedure return", + "EventCode": "0x8114", + "EventName": "BR_RETURN_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted procedure return" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted procedure return", + "EventCode": "0x8115", + "EventName": "BR_RETURN_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted procedure return" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted indirect branch excluding return", + "EventCode": "0x8116", + "EventName": "BR_INDNR_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted indirect branch excluding return" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return", + "EventCode": "0x8117", + "EventName": "BR_INDNR_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch, taken", + "EventCode": "0x8118", + "EventName": "BR_TAKEN_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch, taken" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted branch, taken", + "EventCode": "0x8119", + "EventName": "BR_TAKEN_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted branch, taken" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch, not taken", + "EventCode": "0x811a", + "EventName": "BR_SKIP_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch, not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted branch, not taken", + "EventCode": "0x811b", + "EventName": "BR_SKIP_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted branch, not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch", + "EventCode": "0x811c", + "EventName": "BR_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch" + }, + { + "PublicDescription": "Instruction architecturally executed, indirect branch", + "EventCode": "0x811d", + "EventName": "BR_IND_RETIRED", + "BriefDescription": "Instruction architecturally executed, indirect branch" + }, + { + "PublicDescription": "Branch Record captured.", + "EventCode": "0x811f", + "EventName": "BRB_FILTRATE", + "BriefDescription": "Branch Record captured." + } +] diff --git a/cmd/metrics/resources/component/ampereonex/bus.json b/cmd/metrics/resources/component/ampereonex/bus.json new file mode 100644 index 00000000..2aeb9907 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/bus.json @@ -0,0 +1,20 @@ +[ + { + "ArchStdEvent": "CPU_CYCLES" + }, + { + "ArchStdEvent": "BUS_CYCLES" + }, + { + "ArchStdEvent": "BUS_ACCESS_RD" + }, + { + "ArchStdEvent": "BUS_ACCESS_WR" + }, + { + "ArchStdEvent": "BUS_ACCESS" + }, + { + "ArchStdEvent": "CNT_CYCLES" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/cache.json b/cmd/metrics/resources/component/ampereonex/cache.json new file mode 100644 index 00000000..f4bfe708 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/cache.json @@ -0,0 +1,208 @@ +[ + { + "ArchStdEvent": "L1D_CACHE_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_INVAL", + "Errata": "Errata AC04_CPU_1", + "BriefDescription": "L1D cache invalidate. Impacted by errata -" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_VICTIM" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_CLEAN" + }, + { + "ArchStdEvent": "L2D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L1I_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1I_TLB_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL" + }, + { + "ArchStdEvent": "L1I_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L2D_CACHE_WB" + }, + { + "ArchStdEvent": "L1D_TLB" + }, + { + "ArchStdEvent": "L1I_TLB" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL" + }, + { + "ArchStdEvent": "L2I_TLB_REFILL" + }, + { + "ArchStdEvent": "L2D_TLB" + }, + { + "ArchStdEvent": "L2I_TLB" + }, + { + "ArchStdEvent": "DTLB_WALK" + }, + { + "ArchStdEvent": "ITLB_WALK" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_LMISS_RD" + }, + { + "ArchStdEvent": "L1I_CACHE_LMISS" + }, + { + "ArchStdEvent": "L2D_CACHE_LMISS_RD" + }, + { + "PublicDescription": "Level 1 data or unified cache demand access", + "EventCode": "0x8140", + "EventName": "L1D_CACHE_RW", + "BriefDescription": "Level 1 data or unified cache demand access" + }, + { + "PublicDescription": "Level 1 data or unified cache preload or prefetch", + "EventCode": "0x8142", + "EventName": "L1D_CACHE_PRFM", + "BriefDescription": "Level 1 data or unified cache preload or prefetch" + }, + { + "PublicDescription": "Level 1 data or unified cache refill, preload or prefetch", + "EventCode": "0x8146", + "EventName": "L1D_CACHE_REFILL_PRFM", + "BriefDescription": "Level 1 data or unified cache refill, preload or prefetch" + }, + { + "ArchStdEvent": "L1D_TLB_RD" + }, + { + "ArchStdEvent": "L1D_TLB_WR" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_TLB_RD" + }, + { + "ArchStdEvent": "L2D_TLB_WR" + }, + { + "PublicDescription": "L1D TLB miss", + "EventCode": "0xD600", + "EventName": "L1D_TLB_MISS", + "BriefDescription": "L1D TLB miss" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch requests generated", + "EventCode": "0xd606", + "EventName": "L1_PREFETCH_LD_GEN", + "BriefDescription": "Level 1 prefetcher, load prefetch requests generated" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache", + "EventCode": "0xd607", + "EventName": "L1_PREFETCH_LD_FILL", + "BriefDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch to level 2 generated", + "EventCode": "0xd608", + "EventName": "L1_PREFETCH_L2_REQ", + "BriefDescription": "Level 1 prefetcher, load prefetch to level 2 generated" + }, + { + "PublicDescription": "L1 prefetcher, distance was reset", + "EventCode": "0xd609", + "EventName": "L1_PREFETCH_DIST_RST", + "BriefDescription": "L1 prefetcher, distance was reset" + }, + { + "PublicDescription": "L1 prefetcher, distance was increased", + "EventCode": "0xd60a", + "EventName": "L1_PREFETCH_DIST_INC", + "BriefDescription": "L1 prefetcher, distance was increased" + }, + { + "PublicDescription": "Level 1 prefetcher, table entry is trained", + "EventCode": "0xd60b", + "EventName": "L1_PREFETCH_ENTRY_TRAINED", + "BriefDescription": "Level 1 prefetcher, table entry is trained" + }, + { + "PublicDescription": "L1 data cache refill - Read or Write", + "EventCode": "0xd60e", + "EventName": "L1D_CACHE_REFILL_RW", + "BriefDescription": "L1 data cache refill - Read or Write" + }, + { + "PublicDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills", + "EventCode": "0xD701", + "EventName": "L2C_INST_REFILL", + "BriefDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills" + }, + { + "PublicDescription": "Level 2 cache refill from data-side miss, including DMMU refills", + "EventCode": "0xD702", + "EventName": "L2C_DATA_REFILL", + "BriefDescription": "Level 2 cache refill from data-side miss, including DMMU refills" + }, + { + "PublicDescription": "Level 2 cache prefetcher, load prefetch requests generated", + "EventCode": "0xD703", + "EventName": "L2_PREFETCH_REQ", + "BriefDescription": "Level 2 cache prefetcher, load prefetch requests generated" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/core-imp-def.json b/cmd/metrics/resources/component/ampereonex/core-imp-def.json new file mode 100644 index 00000000..eb5a2208 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/core-imp-def.json @@ -0,0 +1,464 @@ +[ + { + "PublicDescription": "Level 2 prefetch requests, refilled to L2 cache", + "EventCode": "0x10A", + "EventName": "L2_PREFETCH_REFILL", + "BriefDescription": "Level 2 prefetch requests, refilled to L2 cache" + }, + { + "PublicDescription": "Level 2 prefetch requests, late", + "EventCode": "0x10B", + "EventName": "L2_PREFETCH_UPGRADE", + "BriefDescription": "Level 2 prefetch requests, late" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB", + "EventCode": "0x110", + "EventName": "BPU_HIT_BTB", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB", + "EventCode": "0x111", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor", + "EventCode": "0x112", + "EventName": "BPU_HIT_INDIRECT_PREDICTOR", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor", + "EventCode": "0x113", + "EventName": "BPU_HIT_RSB", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor" + }, + { + "PublicDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB", + "EventCode": "0x114", + "EventName": "BPU_UNCONDITIONAL_BRANCH_MISS_BTB", + "BriefDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted", + "EventCode": "0x115", + "EventName": "BPU_BRANCH_NO_HIT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict", + "EventCode": "0x116", + "EventName": "BPU_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict", + "EventCode": "0x117", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict", + "EventCode": "0x118", + "EventName": "BPU_INDIRECT_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict", + "EventCode": "0x119", + "EventName": "BPU_HIT_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict", + "EventCode": "0x11a", + "EventName": "BPU_MISS_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict", + "EventCode": "0x11b", + "EventName": "BPU_NO_PREDICTION_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict" + }, + { + "PublicDescription": "Preditable branch update the BTB region buffer entry", + "EventCode": "0x11c", + "EventName": "BPU_BTB_UPDATE", + "BriefDescription": "Preditable branch update the BTB region buffer entry" + }, + { + "PublicDescription": "Count predict pipe stalls due to speculative return address predictor full", + "EventCode": "0x11d", + "EventName": "BPU_RSB_FULL_STALL", + "BriefDescription": "Count predict pipe stalls due to speculative return address predictor full" + }, + { + "PublicDescription": "Macro-ops speculatively decoded", + "EventCode": "0x11f", + "EventName": "ICF_INST_SPEC_DECODE", + "BriefDescription": "Macro-ops speculatively decoded" + }, + { + "PublicDescription": "Flushes", + "EventCode": "0x120", + "EventName": "GPC_FLUSH", + "BriefDescription": "Flushes" + }, + { + "PublicDescription": "Flushes due to memory hazards", + "EventCode": "0x121", + "EventName": "GPC_FLUSH_MEM_FAULT", + "BriefDescription": "Flushes due to memory hazards" + }, + { + "PublicDescription": "ETM extout bit 0", + "EventCode": "0x141", + "EventName": "MSC_ETM_EXTOUT0", + "BriefDescription": "ETM extout bit 0" + }, + { + "PublicDescription": "ETM extout bit 1", + "EventCode": "0x142", + "EventName": "MSC_ETM_EXTOUT1", + "BriefDescription": "ETM extout bit 1" + }, + { + "PublicDescription": "ETM extout bit 2", + "EventCode": "0x143", + "EventName": "MSC_ETM_EXTOUT2", + "BriefDescription": "ETM extout bit 2" + }, + { + "PublicDescription": "ETM extout bit 3", + "EventCode": "0x144", + "EventName": "MSC_ETM_EXTOUT3", + "BriefDescription": "ETM extout bit 3" + }, + { + "PublicDescription": "Bus request sn", + "EventCode": "0x156", + "EventName": "L2C_SNOOP", + "BriefDescription": "Bus request sn" + }, + { + "PublicDescription": "L2 TXDAT LCRD blocked", + "EventCode": "0x169", + "EventName": "L2C_DAT_CRD_STALL", + "BriefDescription": "L2 TXDAT LCRD blocked" + }, + { + "PublicDescription": "L2 TXRSP LCRD blocked", + "EventCode": "0x16a", + "EventName": "L2C_RSP_CRD_STALL", + "BriefDescription": "L2 TXRSP LCRD blocked" + }, + { + "PublicDescription": "L2 TXREQ LCRD blocked", + "EventCode": "0x16b", + "EventName": "L2C_REQ_CRD_STALL", + "BriefDescription": "L2 TXREQ LCRD blocked" + }, + { + "PublicDescription": "Early mispredict", + "EventCode": "0xD100", + "EventName": "ICF_EARLY_MIS_PRED", + "BriefDescription": "Early mispredict" + }, + { + "PublicDescription": "FEQ full cycles", + "EventCode": "0xD101", + "EventName": "ICF_FEQ_FULL", + "BriefDescription": "FEQ full cycles" + }, + { + "PublicDescription": "Instruction FIFO Full", + "EventCode": "0xD102", + "EventName": "ICF_INST_FIFO_FULL", + "BriefDescription": "Instruction FIFO Full" + }, + { + "PublicDescription": "L1I TLB miss", + "EventCode": "0xD103", + "EventName": "L1I_TLB_MISS", + "BriefDescription": "L1I TLB miss" + }, + { + "PublicDescription": "ICF sent 0 instructions to IDR this cycle", + "EventCode": "0xD104", + "EventName": "ICF_STALL", + "BriefDescription": "ICF sent 0 instructions to IDR this cycle" + }, + { + "PublicDescription": "PC FIFO Full", + "EventCode": "0xD105", + "EventName": "ICF_PC_FIFO_FULL", + "BriefDescription": "PC FIFO Full" + }, + { + "PublicDescription": "Stall due to BOB ID", + "EventCode": "0xD200", + "EventName": "IDR_STALL_BOB_ID", + "BriefDescription": "Stall due to BOB ID" + }, + { + "PublicDescription": "Dispatch stall due to LOB entries", + "EventCode": "0xD201", + "EventName": "IDR_STALL_LOB_ID", + "BriefDescription": "Dispatch stall due to LOB entries" + }, + { + "PublicDescription": "Dispatch stall due to SOB entries", + "EventCode": "0xD202", + "EventName": "IDR_STALL_SOB_ID", + "BriefDescription": "Dispatch stall due to SOB entries" + }, + { + "PublicDescription": "Dispatch stall due to IXU scheduler entries", + "EventCode": "0xD203", + "EventName": "IDR_STALL_IXU_SCHED", + "BriefDescription": "Dispatch stall due to IXU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to FSU scheduler entries", + "EventCode": "0xD204", + "EventName": "IDR_STALL_FSU_SCHED", + "BriefDescription": "Dispatch stall due to FSU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to ROB entries", + "EventCode": "0xD205", + "EventName": "IDR_STALL_ROB_ID", + "BriefDescription": "Dispatch stall due to ROB entries" + }, + { + "PublicDescription": "Dispatch stall due to flush", + "EventCode": "0xD206", + "EventName": "IDR_STALL_FLUSH", + "BriefDescription": "Dispatch stall due to flush" + }, + { + "PublicDescription": "Dispatch stall due to WFI", + "EventCode": "0xD207", + "EventName": "IDR_STALL_WFI", + "BriefDescription": "Dispatch stall due to WFI" + }, + { + "PublicDescription": "Number of SWOB drains triggered by timeout", + "EventCode": "0xD208", + "EventName": "IDR_STALL_SWOB_TIMEOUT", + "BriefDescription": "Number of SWOB drains triggered by timeout" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain", + "EventCode": "0xD209", + "EventName": "IDR_STALL_SWOB_RAW", + "BriefDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register write when SWOB full", + "EventCode": "0xD20A", + "EventName": "IDR_STALL_SWOB_FULL", + "BriefDescription": "Number of SWOB drains triggered by system register write when SWOB full" + }, + { + "PublicDescription": "Dispatch stall due to L1 instruction cache miss", + "EventCode": "0xD20B", + "EventName": "STALL_FRONTEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 instruction cache miss" + }, + { + "PublicDescription": "Dispatch stall due to L1 data cache miss", + "EventCode": "0xD20D", + "EventName": "STALL_BACKEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 data cache miss" + }, + { + "PublicDescription": "Dispatch stall due to lack of any core resource", + "EventCode": "0xD20F", + "EventName": "STALL_BACKEND_RESOURCE", + "BriefDescription": "Dispatch stall due to lack of any core resource" + }, + { + "PublicDescription": "Instructions issued by the scheduler", + "EventCode": "0xD300", + "EventName": "IXU_NUM_UOPS_ISSUED", + "BriefDescription": "Instructions issued by the scheduler" + }, + { + "PublicDescription": "Any uop issued was canceled for any reason", + "EventCode": "0xD301", + "EventName": "IXU_ISSUE_CANCEL", + "BriefDescription": "Any uop issued was canceled for any reason" + }, + { + "PublicDescription": "A load wakeup to the scheduler has been canceled", + "EventCode": "0xD302", + "EventName": "IXU_LOAD_CANCEL", + "BriefDescription": "A load wakeup to the scheduler has been canceled" + }, + { + "PublicDescription": "The scheduler had to cancel one slow Uop due to resource conflict", + "EventCode": "0xD303", + "EventName": "IXU_SLOW_CANCEL", + "BriefDescription": "The scheduler had to cancel one slow Uop due to resource conflict" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA", + "EventCode": "0xD304", + "EventName": "IXU_IXA_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 0", + "EventCode": "0xD305", + "EventName": "IXU_IXA_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 1", + "EventCode": "0xD306", + "EventName": "IXU_IXA_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB", + "EventCode": "0xD307", + "EventName": "IXU_IXB_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 0", + "EventCode": "0xD308", + "EventName": "IXU_IXB_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 1", + "EventCode": "0xD309", + "EventName": "IXU_IXB_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC", + "EventCode": "0xD30A", + "EventName": "IXU_IXC_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 0", + "EventCode": "0xD30B", + "EventName": "IXU_IXC_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 1", + "EventCode": "0xD30C", + "EventName": "IXU_IXC_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD", + "EventCode": "0xD30D", + "EventName": "IXU_IXD_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 0", + "EventCode": "0xD30E", + "EventName": "IXU_IXD_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 1", + "EventCode": "0xD30F", + "EventName": "IXU_IXD_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 1" + }, + { + "PublicDescription": "Uops issued by the FSU scheduler", + "EventCode": "0xD400", + "EventName": "FSU_ISSUED", + "BriefDescription": "Uops issued by the FSU scheduler" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSX", + "EventCode": "0xD401", + "EventName": "FSU_FSX_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSX" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSY", + "EventCode": "0xD402", + "EventName": "FSU_FSY_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSY" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSZ", + "EventCode": "0xD403", + "EventName": "FSU_FSZ_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSZ" + }, + { + "PublicDescription": "Uops canceled (load cancels)", + "EventCode": "0xD404", + "EventName": "FSU_CANCEL", + "BriefDescription": "Uops canceled (load cancels)" + }, + { + "PublicDescription": "Count scheduler stalls due to divide/sqrt", + "EventCode": "0xD405", + "EventName": "FSU_DIV_SQRT_STALL", + "BriefDescription": "Count scheduler stalls due to divide/sqrt" + }, + { + "PublicDescription": "Number of SWOB drains", + "EventCode": "0xD500", + "EventName": "GPC_SWOB_DRAIN", + "BriefDescription": "Number of SWOB drains" + }, + { + "PublicDescription": "GPC detected a Breakpoint instruction match", + "EventCode": "0xD501", + "EventName": "BREAKPOINT_MATCH", + "BriefDescription": "GPC detected a Breakpoint instruction match" + }, + { + "PublicDescription": "Core progress monitor triggered", + "EventCode": "0xd502", + "EventName": "GPC_CPM_TRIGGER", + "BriefDescription": "Core progress monitor triggered" + }, + { + "PublicDescription": "Fill buffer full", + "EventCode": "0xD601", + "EventName": "OFB_FULL", + "BriefDescription": "Fill buffer full" + }, + { + "PublicDescription": "Load satisified from store forwarded data", + "EventCode": "0xD605", + "EventName": "LD_FROM_ST_FWD", + "BriefDescription": "Load satisified from store forwarded data" + }, + { + "PublicDescription": "Store retirement pipe stall", + "EventCode": "0xD60C", + "EventName": "LSU_ST_RETIRE_STALL", + "BriefDescription": "Store retirement pipe stall" + }, + { + "PublicDescription": "LSU detected a Watchpoint data match", + "EventCode": "0xD60D", + "EventName": "WATCHPOINT_MATCH", + "BriefDescription": "LSU detected a Watchpoint data match" + }, + { + "PublicDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature", + "EventCode": "0xda00", + "EventName": "MSC_ETM_COMMIT_STALL", + "BriefDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/exception.json b/cmd/metrics/resources/component/ampereonex/exception.json new file mode 100644 index 00000000..bd59ba7b --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/exception.json @@ -0,0 +1,47 @@ +[ + { + "ArchStdEvent": "EXC_UNDEF" + }, + { + "ArchStdEvent": "EXC_SVC" + }, + { + "ArchStdEvent": "EXC_PABORT" + }, + { + "ArchStdEvent": "EXC_DABORT" + }, + { + "ArchStdEvent": "EXC_IRQ" + }, + { + "ArchStdEvent": "EXC_FIQ" + }, + { + "ArchStdEvent": "EXC_HVC" + }, + { + "ArchStdEvent": "EXC_TRAP_PABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_DABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_OTHER" + }, + { + "ArchStdEvent": "EXC_TRAP_IRQ" + }, + { + "ArchStdEvent": "EXC_TRAP_FIQ" + }, + { + "ArchStdEvent": "EXC_TAKEN" + }, + { + "ArchStdEvent": "EXC_RETURN" + }, + { + "ArchStdEvent": "EXC_SMC" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/instruction.json b/cmd/metrics/resources/component/ampereonex/instruction.json new file mode 100644 index 00000000..a6a20f54 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/instruction.json @@ -0,0 +1,128 @@ +[ + { + "ArchStdEvent": "SW_INCR" + }, + { + "ArchStdEvent": "ST_RETIRED" + }, + { + "ArchStdEvent": "LD_SPEC" + }, + { + "ArchStdEvent": "ST_SPEC" + }, + { + "ArchStdEvent": "LDST_SPEC" + }, + { + "ArchStdEvent": "DP_SPEC" + }, + { + "ArchStdEvent": "ASE_SPEC" + }, + { + "ArchStdEvent": "VFP_SPEC" + }, + { + "ArchStdEvent": "PC_WRITE_SPEC" + }, + { + "ArchStdEvent": "BR_IMMED_RETIRED" + }, + { + "ArchStdEvent": "BR_RETURN_RETIRED" + }, + { + "ArchStdEvent": "CRYPTO_SPEC" + }, + { + "ArchStdEvent": "ISB_SPEC" + }, + { + "ArchStdEvent": "DSB_SPEC" + }, + { + "ArchStdEvent": "DMB_SPEC" + }, + { + "ArchStdEvent": "RC_LD_SPEC" + }, + { + "ArchStdEvent": "RC_ST_SPEC" + }, + { + "ArchStdEvent": "INST_RETIRED" + }, + { + "ArchStdEvent": "CID_WRITE_RETIRED" + }, + { + "ArchStdEvent": "PC_WRITE_RETIRED" + }, + { + "ArchStdEvent": "INST_SPEC" + }, + { + "ArchStdEvent": "TTBR_WRITE_RETIRED" + }, + { + "ArchStdEvent": "BR_RETIRED" + }, + { + "ArchStdEvent": "BR_MIS_PRED_RETIRED" + }, + { + "ArchStdEvent": "OP_RETIRED" + }, + { + "ArchStdEvent": "OP_SPEC" + }, + { + "PublicDescription": "Operation speculatively executed - ASE Scalar", + "EventCode": "0xd210", + "EventName": "ASE_SCALAR_SPEC", + "BriefDescription": "Operation speculatively executed - ASE Scalar" + }, + { + "PublicDescription": "Operation speculatively executed - ASE Vector", + "EventCode": "0xd211", + "EventName": "ASE_VECTOR_SPEC", + "BriefDescription": "Operation speculatively executed - ASE Vector" + }, + { + "PublicDescription": "Barrier speculatively executed, CSDB", + "EventCode": "0x7f", + "EventName": "CSDB_SPEC", + "BriefDescription": "Barrier speculatively executed, CSDB" + }, + { + "PublicDescription": "Prefetch sent to L2.", + "EventCode": "0xd106", + "EventName": "ICF_PREFETCH_DISPATCH", + "BriefDescription": "Prefetch sent to L2." + }, + { + "PublicDescription": "Prefetch response received but was dropped since we don't support inflight upgrades.", + "EventCode": "0xd107", + "EventName": "ICF_PREFETCH_DROPPED_NO_UPGRADE", + "BriefDescription": "Prefetch response received but was dropped since we don't support inflight upgrades." + }, + { + "PublicDescription": "Prefetch request missed TLB.", + "EventCode": "0xd108", + "EventName": "ICF_PREFETCH_DROPPED_TLB_MISS", + "BriefDescription": "Prefetch request missed TLB." + }, + { + "PublicDescription": "Prefetch request dropped since duplicate was found in TLB.", + "EventCode": "0xd109", + "EventName": "ICF_PREFETCH_DROPPED_DUPLICATE", + "BriefDescription": "Prefetch request dropped since duplicate was found in TLB." + }, + { + "PublicDescription": "Prefetch request dropped since it was found in cache.", + "EventCode": "0xd10a", + "EventName": "ICF_PREFETCH_DROPPED_CACHE_HIT", + "BriefDescription": "Prefetch request dropped since it was found in cache." + } +] diff --git a/cmd/metrics/resources/component/ampereonex/intrinsic.json b/cmd/metrics/resources/component/ampereonex/intrinsic.json new file mode 100644 index 00000000..7ecffb98 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/intrinsic.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "LDREX_SPEC" + }, + { + "ArchStdEvent": "STREX_PASS_SPEC" + }, + { + "ArchStdEvent": "STREX_FAIL_SPEC" + }, + { + "ArchStdEvent": "STREX_SPEC" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/memory.json b/cmd/metrics/resources/component/ampereonex/memory.json new file mode 100644 index 00000000..6c06bc92 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/memory.json @@ -0,0 +1,43 @@ +[ + { + "ArchStdEvent": "LD_RETIRED", + "Errata": "Errata AC04_CPU_21", + "BriefDescription": "Instruction architecturally executed, condition code check pass, load. Impacted by errata -" + }, + { + "ArchStdEvent": "MEM_ACCESS_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_WR" + }, + { + "ArchStdEvent": "LD_ALIGN_LAT" + }, + { + "ArchStdEvent": "ST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS" + }, + { + "ArchStdEvent": "MEMORY_ERROR" + }, + { + "ArchStdEvent": "LDST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_WR" + }, + { + "PublicDescription": "Flushes due to memory hazards", + "EventCode": "0x121", + "EventName": "BPU_FLUSH_MEM_FAULT", + "BriefDescription": "Flushes due to memory hazards" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/metrics.json b/cmd/metrics/resources/component/ampereonex/metrics.json new file mode 100644 index 00000000..6817cac1 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/metrics.json @@ -0,0 +1,442 @@ +[ + { + "MetricName": "branch_miss_pred_rate", + "MetricExpr": "BR_MIS_PRED / BR_PRED", + "BriefDescription": "Branch predictor misprediction rate. May not count branches that are never resolved because they are in the misprediction shadow of an earlier branch", + "MetricGroup": "branch", + "ScaleUnit": "100%" + }, + { + "MetricName": "bus_utilization", + "MetricExpr": "BUS_ACCESS / (BUS_CYCLES * 1)", + "BriefDescription": "Core-to-uncore bus utilization", + "MetricGroup": "Bus", + "ScaleUnit": "100percent of bus cycles" + }, + { + "MetricName": "l1d_cache_miss_ratio", + "MetricExpr": "L1D_CACHE_REFILL / L1D_CACHE", + "BriefDescription": "This metric measures the ratio of level 1 data cache accesses missed to the total number of level 1 data cache accesses. This gives an indication of the effectiveness of the level 1 data cache.", + "MetricGroup": "Miss_Ratio;L1D_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_miss_ratio", + "MetricExpr": "L1I_CACHE_REFILL / L1I_CACHE", + "BriefDescription": "This metric measures the ratio of level 1 instruction cache accesses missed to the total number of level 1 instruction cache accesses. This gives an indication of the effectiveness of the level 1 instruction cache.", + "MetricGroup": "Miss_Ratio;L1I_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "Miss_Ratio;l1d_cache_read_miss", + "MetricExpr": "L1D_CACHE_LMISS_RD / L1D_CACHE_RD", + "BriefDescription": "L1D cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l2_cache_miss_ratio", + "MetricExpr": "L2D_CACHE_REFILL / L2D_CACHE", + "BriefDescription": "This metric measures the ratio of level 2 cache accesses missed to the total number of level 2 cache accesses. This gives an indication of the effectiveness of the level 2 cache, which is a unified cache that stores both data and instruction. Note that cache accesses in this cache are either data memory access or instruction fetch as this is a unified cache.", + "MetricGroup": "Miss_Ratio;L2_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_read_miss_rate", + "MetricExpr": "L1I_CACHE_LMISS / L1I_CACHE", + "BriefDescription": "L1I cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l2d_cache_read_miss_rate", + "MetricExpr": "L2D_CACHE_LMISS_RD / L2D_CACHE_RD", + "BriefDescription": "L2 cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l1d_cache_miss_mpki", + "MetricExpr": "(L1D_CACHE_LMISS_RD * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (data)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "l1i_cache_miss_mpki", + "MetricExpr": "(L1I_CACHE_LMISS * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (instruction)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "simd_percentage", + "MetricExpr": "ASE_SPEC / INST_SPEC", + "BriefDescription": "This metric measures advanced SIMD operations as a percentage of total operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "crypto_percentage", + "MetricExpr": "CRYPTO_SPEC / INST_SPEC", + "BriefDescription": "This metric measures crypto operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "gflops", + "MetricExpr": "VFP_SPEC / (duration_time * 1e9)", + "BriefDescription": "Giga-floating point operations per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "integer_dp_percentage", + "MetricExpr": "DP_SPEC / INST_SPEC", + "BriefDescription": "This metric measures scalar integer operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "ipc", + "MetricExpr": "INST_RETIRED / CPU_CYCLES", + "BriefDescription": "This metric measures the number of instructions retired per cycle.", + "MetricGroup": "General", + "ScaleUnit": "1per cycle" + }, + { + "MetricName": "load_percentage", + "MetricExpr": "LD_SPEC / INST_SPEC", + "BriefDescription": "This metric measures load operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "load_store_spec_rate", + "MetricExpr": "LDST_SPEC / INST_SPEC", + "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speculatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "retired_mips", + "MetricExpr": "INST_RETIRED / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "spec_utilization_mips", + "MetricExpr": "INST_SPEC / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "PEutilization" + }, + { + "MetricName": "pc_write_spec_rate", + "MetricExpr": "PC_WRITE_SPEC / INST_SPEC", + "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speculatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "store_percentage", + "MetricExpr": "ST_SPEC / INST_SPEC", + "BriefDescription": "This metric measures store operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "scalar_fp_percentage", + "MetricExpr": "VFP_SPEC / INST_SPEC", + "BriefDescription": "This metric measures scalar floating point operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "retired_rate", + "MetricExpr": "OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted", + "MetricExpr": "1 - (OP_RETIRED / (CPU_CYCLES * #slots))", + "BriefDescription": "Of all the micro-operations issued, what proportion are lost", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted_rate", + "MetricExpr": "1 - OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are not retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "stall_backend_cache_rate", + "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_backend_resource_rate", + "MetricExpr": "STALL_BACKEND_RESOURCE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and resource full", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_backend_tlb_rate", + "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_frontend_cache_rate", + "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_frontend_tlb_rate", + "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "dtlb_walk_ratio", + "MetricExpr": "DTLB_WALK / L1D_TLB", + "BriefDescription": "This metric measures the ratio of data TLB Walks to the total number of data TLB accesses. This gives an indication of the effectiveness of the data TLB accesses.", + "MetricGroup": "Miss_Ratio;DTLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "MetricName": "itlb_walk_ratio", + "MetricExpr": "ITLB_WALK / L1I_TLB", + "BriefDescription": "This metric measures the ratio of instruction TLB Walks to the total number of instruction TLB accesses. This gives an indication of the effectiveness of the instruction TLB accesses.", + "MetricGroup": "Miss_Ratio;ITLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "ArchStdEvent": "backend_bound" + }, + { + "ArchStdEvent": "frontend_bound", + "MetricExpr": "100 - (retired_fraction + slots_lost_misspeculation_fraction + backend_bound)" + }, + { + "MetricName": "slots_lost_misspeculation_fraction", + "MetricExpr": "100 * (OP_SPEC - OP_RETIRED) / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of slots lost due to misspeculation", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "retired_fraction", + "MetricExpr": "100 * OP_RETIRED / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of slots retiring, useful work", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "backend_core", + "MetricExpr": "(backend_bound / 100) - backend_memory", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend non-memory subsystem issues", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "backend_memory", + "MetricExpr": "(STALL_BACKEND_TLB + STALL_BACKEND_CACHE) / CPU_CYCLES", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend memory subsystem issues (cache/tlb miss)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "branch_mispredict", + "MetricExpr": "(BR_MIS_PRED_RETIRED / GPC_FLUSH) * slots_lost_misspeculation_fraction", + "BriefDescription": "Fraction of slots lost due to branch misprediciton", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_bandwidth", + "MetricExpr": "frontend_bound - 100 * frontend_latency", + "BriefDescription": "Fraction of slots the CPU did not dispatch at full bandwidth - able to dispatch partial slots only (1, 2, or 3 uops)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_latency", + "MetricExpr": "(STALL_FRONTEND - ((STALL_SLOT_FRONTEND - ((frontend_bound / 100) * CPU_CYCLES * #slots)) / #slots)) / CPU_CYCLES", + "BriefDescription": "Fraction of slots the CPU was stalled due to frontend latency issues (cache/tlb miss); nothing to dispatch", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "other_miss_pred", + "MetricExpr": "slots_lost_misspeculation_fraction - branch_mispredict", + "BriefDescription": "Fraction of slots lost due to other/non-branch misprediction misspeculation", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "pipe_utilization", + "MetricExpr": "100 * ((IXU_NUM_UOPS_ISSUED + FSU_ISSUED) / (CPU_CYCLES * 6))", + "BriefDescription": "Fraction of execute slots utilized", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "d_cache_l2_miss_rate", + "MetricExpr": "STALL_BACKEND_MEM / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data L2 cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "d_cache_miss_rate", + "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "d_tlb_miss_rate", + "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "fsu_pipe_utilization", + "MetricExpr": "FSU_ISSUED / (CPU_CYCLES * 2)", + "BriefDescription": "Fraction of FSU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "i_cache_miss_rate", + "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "i_tlb_miss_rate", + "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "ixu_pipe_utilization", + "MetricExpr": "IXU_NUM_UOPS_ISSUED / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of IXU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "stall_recovery_rate", + "MetricExpr": "IDR_STALL_FLUSH / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to flush recovery", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "stall_fsu_sched_rate", + "MetricExpr": "IDR_STALL_FSU_SCHED / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and FSU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_ixu_sched_rate", + "MetricExpr": "IDR_STALL_IXU_SCHED / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and IXU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_lob_id_rate", + "MetricExpr": "IDR_STALL_LOB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and LOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_rob_id_rate", + "MetricExpr": "IDR_STALL_ROB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and ROB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_sob_id_rate", + "MetricExpr": "IDR_STALL_SOB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and SOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "l1d_cache_access_demand", + "MetricExpr": "L1D_CACHE_RW / L1D_CACHE", + "BriefDescription": "L1D cache access - demand", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_access_prefetches", + "MetricExpr": "L1D_CACHE_PRFM / L1D_CACHE", + "BriefDescription": "L1D cache access - prefetch", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses", + "MetricExpr": "L1D_CACHE_REFILL_RW / L1D_CACHE", + "BriefDescription": "L1D cache demand misses", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses_read", + "MetricExpr": "L1D_CACHE_REFILL_RD / L1D_CACHE", + "BriefDescription": "L1D cache demand misses - read", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses_write", + "MetricExpr": "L1D_CACHE_REFILL_WR / L1D_CACHE", + "BriefDescription": "L1D cache demand misses - write", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_prefetch_misses", + "MetricExpr": "L1D_CACHE_REFILL_PRFM / L1D_CACHE", + "BriefDescription": "L1D cache prefetch misses", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "ase_scalar_mix", + "MetricExpr": "ASE_SCALAR_SPEC / OP_SPEC", + "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) scalar operations", + "MetricGroup": "Instructions", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "ase_vector_mix", + "MetricExpr": "ASE_VECTOR_SPEC / OP_SPEC", + "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) vector operations", + "MetricGroup": "Instructions", + "ScaleUnit": "100percent of cache acceses" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/mmu.json b/cmd/metrics/resources/component/ampereonex/mmu.json new file mode 100644 index 00000000..66d83b68 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/mmu.json @@ -0,0 +1,170 @@ +[ + { + "PublicDescription": "Level 2 data translation buffer allocation", + "EventCode": "0xD800", + "EventName": "MMU_D_OTB_ALLOC", + "BriefDescription": "Level 2 data translation buffer allocation" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L2 walk cache entry", + "EventCode": "0xd801", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L2_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L2 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L1 walk cache entry", + "EventCode": "0xd802", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L1_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L1 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L0 walk cache entry", + "EventCode": "0xd803", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L0_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L0 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S2L2 walk cache entry", + "EventCode": "0xd804", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L2_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L2 walk cache entry" + }, + { + "PublicDescrition": "Data TLB translation cache hit on S2L1 walk cache entry", + "EventCode": "0xd805", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L1_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L1 walk cache entry" + }, + { + "PublicDescrition": "Data TLB translation cache hit on S2L0 walk cache entry", + "EventCode": "0xd806", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L0_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L0 walk cache entry" + }, + { + "PublicDescrition": "Data-side S1 page walk cache lookup", + "EventCode": "0xd807", + "EventName": "MMU_D_S1_WALK_CACHE_LOOKUP", + "BriefDescription": "Data-side S1 page walk cache lookup" + }, + { + "PublicDescrition": "Data-side S1 page walk cache refill", + "EventCode": "0xd808", + "EventName": "MMU_D_S1_WALK_CACHE_REFILL", + "BriefDescription": "Data-side S1 page walk cache refill" + }, + { + "PublicDescrition": "Data-side S2 page walk cache lookup", + "EventCode": "0xd809", + "EventName": "MMU_D_S2_WALK_CACHE_LOOKUP", + "BriefDescription": "Data-side S2 page walk cache lookup" + }, + { + "PublicDescrition": "Data-side S2 page walk cache refill", + "EventCode": "0xd80a", + "EventName": "MMU_D_S2_WALK_CACHE_REFILL", + "BriefDescription": "Data-side S2 page walk cache refill" + }, + { + "PublicDescription": "Data-side S1 table walk fault", + "EventCode": "0xD80B", + "EventName": "MMU_D_S1_WALK_FAULT", + "BriefDescription": "Data-side S1 table walk fault" + }, + { + "PublicDescription": "Data-side S2 table walk fault", + "EventCode": "0xD80C", + "EventName": "MMU_D_S2_WALK_FAULT", + "BriefDescription": "Data-side S2 table walk fault" + }, + { + "PublicDescription": "Data-side table walk steps or descriptor fetches", + "EventCode": "0xD80D", + "EventName": "MMU_D_WALK_STEPS", + "BriefDescription": "Data-side table walk steps or descriptor fetches" + }, + { + "PublicDescription": "Level 2 instruction translation buffer allocation", + "EventCode": "0xD900", + "EventName": "MMU_I_OTB_ALLOC", + "BriefDescription": "Level 2 instruction translation buffer allocation" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L2 walk cache entry", + "EventCode": "0xd901", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L2_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L2 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L1 walk cache entry", + "EventCode": "0xd902", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L1_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L1 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L0 walk cache entry", + "EventCode": "0xd903", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L0_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L0 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L2 walk cache entry", + "EventCode": "0xd904", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L2_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L2 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L1 walk cache entry", + "EventCode": "0xd905", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L1_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L1 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L0 walk cache entry", + "EventCode": "0xd906", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L0_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L0 walk cache entry" + }, + { + "PublicDescrition": "Instruction-side S1 page walk cache lookup", + "EventCode": "0xd907", + "EventName": "MMU_I_S1_WALK_CACHE_LOOKUP", + "BriefDescription": "Instruction-side S1 page walk cache lookup" + }, + { + "PublicDescrition": "Instruction-side S1 page walk cache refill", + "EventCode": "0xd908", + "EventName": "MMU_I_S1_WALK_CACHE_REFILL", + "BriefDescription": "Instruction-side S1 page walk cache refill" + }, + { + "PublicDescrition": "Instruction-side S2 page walk cache lookup", + "EventCode": "0xd909", + "EventName": "MMU_I_S2_WALK_CACHE_LOOKUP", + "BriefDescription": "Instruction-side S2 page walk cache lookup" + }, + { + "PublicDescrition": "Instruction-side S2 page walk cache refill", + "EventCode": "0xd90a", + "EventName": "MMU_I_S2_WALK_CACHE_REFILL", + "BriefDescription": "Instruction-side S2 page walk cache refill" + }, + { + "PublicDescription": "Instruction-side S1 table walk fault", + "EventCode": "0xD90B", + "EventName": "MMU_I_S1_WALK_FAULT", + "BriefDescription": "Instruction-side S1 table walk fault" + }, + { + "PublicDescription": "Instruction-side S2 table walk fault", + "EventCode": "0xD90C", + "EventName": "MMU_I_S2_WALK_FAULT", + "BriefDescription": "Instruction-side S2 table walk fault" + }, + { + "PublicDescription": "Instruction-side table walk steps or descriptor fetches", + "EventCode": "0xD90D", + "EventName": "MMU_I_WALK_STEPS", + "BriefDescription": "Instruction-side table walk steps or descriptor fetches" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/pipeline.json b/cmd/metrics/resources/component/ampereonex/pipeline.json new file mode 100644 index 00000000..2fb2d1f1 --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/pipeline.json @@ -0,0 +1,41 @@ +[ + { + "ArchStdEvent": "STALL_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_BACKEND" + }, + { + "ArchStdEvent": "STALL", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT_BACKEND" + }, + { + "ArchStdEvent": "STALL_SLOT_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT" + }, + { + "ArchStdEvent": "STALL_BACKEND_MEM" + }, + { + "PublicDescription": "Frontend stall cycles, TLB", + "EventCode": "0x815c", + "EventName": "STALL_FRONTEND_TLB", + "BriefDescription": "Frontend stall cycles, TLB" + }, + { + "PublicDescription": "Backend stall cycles, TLB", + "EventCode": "0x8167", + "EventName": "STALL_BACKEND_TLB", + "BriefDescription": "Backend stall cycles, TLB" + } +] diff --git a/cmd/metrics/resources/component/ampereonex/spe.json b/cmd/metrics/resources/component/ampereonex/spe.json new file mode 100644 index 00000000..20f2165c --- /dev/null +++ b/cmd/metrics/resources/component/ampereonex/spe.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "SAMPLE_POP" + }, + { + "ArchStdEvent": "SAMPLE_FEED" + }, + { + "ArchStdEvent": "SAMPLE_FILTRATE" + }, + { + "ArchStdEvent": "SAMPLE_COLLISION" + } +] From 38131df55f4c52f92186a1f73931317c6994908c Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Mon, 8 Dec 2025 14:12:25 -0800 Subject: [PATCH 15/15] add cpus module unit tests Signed-off-by: Harper, Jason M --- internal/cpus/cpus_test.go | 350 +++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 internal/cpus/cpus_test.go diff --git a/internal/cpus/cpus_test.go b/internal/cpus/cpus_test.go new file mode 100644 index 00000000..d4b806b3 --- /dev/null +++ b/internal/cpus/cpus_test.go @@ -0,0 +1,350 @@ +// Copyright (C) 2021-2025 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause + +package cpus + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewX86Identifier(t *testing.T) { + id := NewX86Identifier("6", "143", "4", "c0", "4") + assert.Equal(t, "6", id.Family) + assert.Equal(t, "143", id.Model) + assert.Equal(t, "4", id.Stepping) + assert.Equal(t, "c0", id.Capid4) + assert.Equal(t, "4", id.Devices) + assert.Equal(t, X86Architecture, id.Architecture) +} + +func TestNewARMIdentifier(t *testing.T) { + id := NewARMIdentifier("0x41", "0xd0c", "AWS Graviton2") + assert.Equal(t, "0x41", id.Implementer) + assert.Equal(t, "0xd0c", id.Part) + assert.Equal(t, "AWS Graviton2", id.DmidecodePart) + assert.Equal(t, ARMArchitecture, id.Architecture) +} + +func TestNewCPUIdentifier(t *testing.T) { + id := NewCPUIdentifier("6", "143", "4", "c0", "4", "0x41", "0xd0c", "AWS Graviton2", X86Architecture) + assert.Equal(t, "6", id.Family) + assert.Equal(t, "143", id.Model) + assert.Equal(t, "4", id.Stepping) + assert.Equal(t, "0x41", id.Implementer) + assert.Equal(t, X86Architecture, id.Architecture) +} + +func TestGetCPU_X86_ICX(t *testing.T) { + // Test Ice Lake (ICX) - Family 6, Model 106 + id := NewX86Identifier("6", "106", "6", "", "") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchICX, cpu.MicroArchitecture) + assert.Equal(t, 8, cpu.MemoryChannelCount) + assert.Equal(t, 2, cpu.LogicalThreadCount) +} + +func TestGetCPU_X86_SKX(t *testing.T) { + // Test Skylake (SKX) - Family 6, Model 85 + id := NewX86Identifier("6", "85", "4", "", "") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchSKX, cpu.MicroArchitecture) + assert.Equal(t, 6, cpu.MemoryChannelCount) + assert.Equal(t, 2, cpu.LogicalThreadCount) +} + +func TestGetCPU_ARM_Graviton2(t *testing.T) { + // Test AWS Graviton2 + id := NewARMIdentifier("0x41", "0xd0c", "AWS Graviton2") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchGraviton2, cpu.MicroArchitecture) +} + +func TestGetCPU_ARM_Graviton3(t *testing.T) { + // Test AWS Graviton3 + id := NewARMIdentifier("0x41", "0xd40", "AWS Graviton3") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchGraviton3, cpu.MicroArchitecture) +} + +func TestGetCPU_UnknownX86(t *testing.T) { + // Test unknown x86 CPU + id := NewX86Identifier("99", "999", "0", "", "") + _, err := GetCPU(id) + assert.Error(t, err) + assert.Contains(t, err.Error(), "CPU match not found") +} + +func TestGetCPU_UnknownARM(t *testing.T) { + // Test unknown ARM CPU + id := NewARMIdentifier("0xff", "0xfff", "Unknown") + _, err := GetCPU(id) + assert.Error(t, err) + assert.Contains(t, err.Error(), "CPU match not found") +} + +func TestGetCPU_NoArchitecture(t *testing.T) { + // Test with insufficient information to determine architecture + id := CPUIdentifier{} + _, err := GetCPU(id) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unable to determine CPU architecture") +} + +func TestGetCPUByMicroArchitecture(t *testing.T) { + tests := []struct { + name string + uarch string + expectError bool + expectedUarch string + }{ + { + name: "exact match - ICX", + uarch: UarchICX, + expectError: false, + expectedUarch: UarchICX, + }, + { + name: "exact match - SPR", + uarch: UarchSPR, + expectError: false, + expectedUarch: UarchSPR, + }, + { + name: "case insensitive - icx", + uarch: "icx", + expectError: false, + expectedUarch: UarchICX, + }, + { + name: "unknown microarchitecture", + uarch: "UNKNOWN", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cpu, err := GetCPUByMicroArchitecture(tt.uarch) + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedUarch, cpu.MicroArchitecture) + } + }) + } +} + +func TestIsIntelCPUFamily(t *testing.T) { + tests := []struct { + name string + family int + expected bool + }{ + {"family 6", 6, true}, + {"family 19", 19, true}, + {"family 15", 15, false}, + {"family 0", 0, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := IsIntelCPUFamily(tt.family) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestIsIntelCPUFamilyStr(t *testing.T) { + tests := []struct { + name string + family string + expected bool + }{ + {"family 6", "6", true}, + {"family 19", "19", true}, + {"family 15", "15", false}, + {"invalid", "invalid", false}, + {"empty", "", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := IsIntelCPUFamilyStr(tt.family) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetSPRMicroArchitecture(t *testing.T) { + tests := []struct { + name string + capid4 string + expectedUarch string + expectError bool + }{ + { + name: "SPR XCC - bits 11", + capid4: "c0", // binary: 11000000, bits [7:6] = 11 (3) + expectedUarch: UarchSPR_XCC, + expectError: false, + }, + { + name: "SPR MCC - bits 01", + capid4: "40", // binary: 01000000, bits [7:6] = 01 (1) + expectedUarch: UarchSPR_MCC, + expectError: false, + }, + { + name: "SPR default - no capid4", + capid4: "", + expectedUarch: UarchSPR, + expectError: false, + }, + { + name: "SPR default - invalid capid4", + capid4: "invalid", + expectedUarch: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uarch, err := getSPRMicroArchitecture(tt.capid4) + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedUarch, uarch) + } + }) + } +} + +func TestGetEMRMicroArchitecture(t *testing.T) { + tests := []struct { + name string + capid4 string + expectedUarch string + expectError bool + }{ + { + name: "EMR XCC - bits 11", + capid4: "c0", + expectedUarch: UarchEMR_XCC, + expectError: false, + }, + { + name: "EMR MCC - bits 01", + capid4: "40", + expectedUarch: UarchEMR_MCC, + expectError: false, + }, + { + name: "EMR default - no capid4", + capid4: "", + expectedUarch: UarchEMR, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uarch, err := getEMRMicroArchitecture(tt.capid4) + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedUarch, uarch) + } + }) + } +} + +func TestGetGNRMicroArchitecture(t *testing.T) { + tests := []struct { + name string + devices string + expectedUarch string + }{ + {"GNR X3 - 5 devices", "5", UarchGNR_X3}, + {"GNR X3 - 10 devices", "10", UarchGNR_X3}, + {"GNR X2 - 4 devices", "4", UarchGNR_X2}, + {"GNR X2 - 8 devices", "8", UarchGNR_X2}, + {"GNR X1 - 3 devices", "3", UarchGNR_X1}, + {"GNR X1 - 6 devices", "6", UarchGNR_X1}, + {"GNR default - no devices", "", UarchGNR}, + {"GNR default - invalid devices", "invalid", UarchGNR}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uarch, err := getGNRMicroArchitecture(tt.devices) + require.NoError(t, err) + assert.Equal(t, tt.expectedUarch, uarch) + }) + } +} + +func TestGetSRFMicroArchitecture(t *testing.T) { + tests := []struct { + name string + devices string + expectedUarch string + }{ + {"SRF SP - 3 devices", "3", UarchSRF_SP}, + {"SRF SP - 6 devices", "6", UarchSRF_SP}, + {"SRF AP - 4 devices", "4", UarchSRF_AP}, + {"SRF AP - 8 devices", "8", UarchSRF_AP}, + {"SRF default - no devices", "", UarchSRF}, + {"SRF default - invalid devices", "invalid", UarchSRF}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uarch, err := getSRFMicroArchitecture(tt.devices) + require.NoError(t, err) + assert.Equal(t, tt.expectedUarch, uarch) + }) + } +} + +func TestGetCPU_SPR_WithCapid4(t *testing.T) { + // Test SPR XCC with capid4 + id := NewX86Identifier("6", "143", "4", "c0", "") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchSPR_XCC, cpu.MicroArchitecture) +} + +func TestGetCPU_GNR_WithDevices(t *testing.T) { + // Test GNR X2 with 4 devices + id := NewX86Identifier("6", "173", "0", "", "4") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchGNR_X2, cpu.MicroArchitecture) +} + +func TestGetCPU_AMD_Milan(t *testing.T) { + // Test AMD Milan - Family 25, Model 1 + id := NewX86Identifier("25", "1", "1", "", "") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchMilan, cpu.MicroArchitecture) +} + +func TestGetCPU_AMD_Genoa(t *testing.T) { + // Test AMD Genoa - Family 25, Model 17 + id := NewX86Identifier("25", "17", "0", "", "") + cpu, err := GetCPU(id) + require.NoError(t, err) + assert.Equal(t, UarchGenoa, cpu.MicroArchitecture) +}