Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/config/config_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi
{Name: "Package Power / TDP", Description: "--tdp <Watts>", Values: []string{extract.TDPFromOutput(outputs)}},
{Name: "Core SSE Frequency", Description: "--core-max <GHz>", Values: []string{sseFrequenciesFromOutput(outputs)}},
}
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) {
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) || strings.Contains(uarch, cpus.UarchDMR) {
fields = append(fields, []table.Field{
{Name: "Uncore Max Frequency (Compute)", Description: "--uncore-max-compute <GHz>", Values: []string{extract.UncoreMinMaxDieFrequencyFromOutput(true, true, outputs)}},
{Name: "Uncore Min Frequency (Compute)", Description: "--uncore-min-compute <GHz>", Values: []string{extract.UncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}},
Expand All @@ -89,8 +89,8 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []table.Fi
{Name: "Energy Performance Preference", Description: "--epp <0-255>", Values: []string{extract.EPPFromOutput(outputs)}},
{Name: "Scaling Governor", Description: "--gov <" + strings.Join(governorOptions, "|") + ">", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}},
}...)
// add ELC (for SRF, CWF and GNR only)
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) {
// add ELC (for SRF, CWF, GNR, and DMR only)
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) || strings.Contains(uarch, cpus.UarchDMR) {
fields = append(fields, table.Field{Name: "Efficiency Latency Control", Description: "--elc <" + strings.Join(elcOptions, "|") + ">", Values: []string{extract.ELCSummaryFromOutput(outputs)}})
}
// add prefetchers
Expand Down
4 changes: 2 additions & 2 deletions cmd/config/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ done
`,
Superuser: true,
Vendors: []string{cpus.IntelVendor},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR},
Depends: []string{"pcm-tpmi"},
}
_, err := runScript(myTarget, setScript, localTempDir)
Expand All @@ -842,7 +842,7 @@ pcm-tpmi 2 0x18 -d -b 38:32 -w 0 # EFFICIENCY_LATENCY_CTRL_LOW_THRESHOLD
`,
Superuser: true,
Vendors: []string{cpus.IntelVendor},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF},
MicroArchitectures: []string{cpus.UarchGNR, cpus.UarchGNR_D, cpus.UarchSRF, cpus.UarchCWF, cpus.UarchDMR},
Depends: []string{"pcm-tpmi"},
}
_, err := runScript(myTarget, setScript, localTempDir)
Expand Down
2 changes: 1 addition & 1 deletion cmd/report/report_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,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, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) {
if strings.Contains(uarch, cpus.UarchSRF) || strings.Contains(uarch, cpus.UarchGNR) || strings.Contains(uarch, cpus.UarchCWF) || strings.Contains(uarch, cpus.UarchDMR) {
return []table.Field{
{Name: "Min Frequency (Compute)", Values: []string{extract.UncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}},
{Name: "Min Frequency (I/O)", Values: []string{extract.UncoreMinMaxDieFrequencyFromOutput(false, false, outputs)}},
Expand Down
2 changes: 1 addition & 1 deletion internal/cpus/cpus.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ var cpuCharacteristicsMap = map[string]CPUCharacteristics{
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: 16}, // Clearwater Forest - generic
UarchDMR: {MicroArchitecture: UarchDMR, MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 0}, // Diamond Rapids
UarchDMR: {MicroArchitecture: UarchDMR, MemoryChannelCount: 16, LogicalThreadCount: 1, CacheWayCount: 10}, // Diamond Rapids - generic
// AMD CPUs
UarchNaples: {MicroArchitecture: UarchNaples, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Naples
UarchRome: {MicroArchitecture: UarchRome, MemoryChannelCount: 8, LogicalThreadCount: 2, CacheWayCount: 0}, // Rome
Expand Down
6 changes: 5 additions & 1 deletion internal/extract/power.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,13 @@ func ELCFieldValuesFromOutput(outputs map[string]script.ScriptOutput) (fieldValu
func TDPFromOutput(outputs map[string]script.ScriptOutput) string {
msrHex := strings.TrimSpace(outputs[script.PackagePowerLimitName].Stdout)
msr, err := strconv.ParseInt(msrHex, 16, 0)
if err != nil || msr == 0 {
if err != nil {
slog.Error("failed to parse TDP value", slog.String("error", err.Error()), slog.String("msrHex", msrHex))
return ""
}
if msr == 0 {
return "Unknown"
}
return fmt.Sprint(msr/8) + "W"
}

Expand Down
215 changes: 119 additions & 96 deletions internal/extract/prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,36 @@ const (
PrefetcherHomelessName = "Homeless"
PrefetcherLLCName = "LLC"
PrefetcherLLCStreamName = "LLC Stream"
PrefetcherL2PName = "L2P"
)

// PrefetcherDefinition represents a prefetcher configuration.
type PrefetcherDefinition struct {
ShortName string
Description string
Msr int
Bit int
Uarchs []string
ShortName string
Description string
Msr int
Bit int
Uarchs []string
ManagedByL2P bool // indicates if the prefetcher is dynamically managed by the L2P algorithm
}

// PrefetcherDefinitions contains all known prefetcher definitions.
var PrefetcherDefinitions = []PrefetcherDefinition{
{
ShortName: PrefetcherL2HWName,
Description: "L2 Hardware (MLC Streamer) fetches additional lines of code or data into the L2 cache.",
Msr: MsrPrefetchControl,
Bit: 0,
Uarchs: []string{"all"},
ShortName: PrefetcherL2HWName,
Description: "L2 Hardware (MLC Streamer) fetches additional lines of code or data into the L2 cache.",
Msr: MsrPrefetchControl,
Bit: 0,
Uarchs: []string{"all"},
ManagedByL2P: true,
},
{
ShortName: PrefetcherL2AdjName,
Description: "L2 Adjacent Cache Line (MLC Spatial) fetches the cache line that comprises a cache line pair.",
Msr: MsrPrefetchControl,
Bit: 1,
Uarchs: []string{"all"},
ShortName: PrefetcherL2AdjName,
Description: "L2 Adjacent Cache Line (MLC Spatial) fetches the cache line that comprises a cache line pair.",
Msr: MsrPrefetchControl,
Bit: 1,
Uarchs: []string{"all"},
ManagedByL2P: true,
},
{
ShortName: PrefetcherDCUHWName,
Expand All @@ -83,18 +87,20 @@ var PrefetcherDefinitions = []PrefetcherDefinition{
Uarchs: []string{"all"},
},
{
ShortName: PrefetcherAMPName,
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{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR},
ShortName: PrefetcherAMPName,
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{cpus.UarchSPR, cpus.UarchEMR, cpus.UarchGNR, cpus.UarchDMR},
ManagedByL2P: true,
},
{
ShortName: PrefetcherLLCPPName,
Description: "Last Level Cache Page (MLC LLC Page) Prefetcher",
Msr: MsrPrefetchControl,
Bit: 6,
Uarchs: []string{cpus.UarchGNR},
ShortName: PrefetcherLLCPPName,
Description: "Last Level Cache Page (MLC LLC Page) Prefetcher",
Msr: MsrPrefetchControl,
Bit: 6,
Uarchs: []string{cpus.UarchGNR, cpus.UarchDMR},
ManagedByL2P: true,
},
{
ShortName: PrefetcherAOPName,
Expand All @@ -103,6 +109,15 @@ var PrefetcherDefinitions = []PrefetcherDefinition{
Bit: 7,
Uarchs: []string{cpus.UarchGNR},
},
{
// ON DMR, when enabled, prefetchers at bit 0, 1, 5, and 6 are dynamically controlled by the L2P algorithm
// ON SPR/EMR/GNR, if prefetchers at bit 0, 1, 5, and 6 are enabled, they are dynamically controlled by the L2P algorithm
ShortName: PrefetcherL2PName,
Description: "L2P is an algorithm that dynamically enables or disables prefetchers based on real-time telemetry.",
Msr: MsrPrefetchControl,
Bit: 12,
Uarchs: []string{cpus.UarchDMR},
},
{
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.",
Expand Down Expand Up @@ -155,89 +170,97 @@ func IsPrefetcherEnabled(msrValue string, bit int) (bool, error) {
return bitMask&msrInt == 0, nil
}

// PrefetchersFromOutput extracts prefetcher status from script outputs.
func PrefetchersFromOutput(outputs map[string]script.ScriptOutput) [][]string {
out := make([][]string, 0)
// resolvedPrefetcher holds the resolved status of a single prefetcher.
type resolvedPrefetcher struct {
Definition PrefetcherDefinition
Status string // "Enabled", "Disabled", or "Managed by L2P"
}

// resolvePrefetchers determines the status of each applicable prefetcher from script outputs.
func resolvePrefetchers(outputs map[string]script.ScriptOutput) []resolvedPrefetcher {
uarch := UarchFromOutput(outputs)
if uarch == "" {
return [][]string{}
return nil
}
for _, pf := range PrefetcherDefinitions {
if slices.Contains(pf.Uarchs, "all") || slices.Contains(pf.Uarchs, uarch[:3]) {
var scriptName string
switch pf.Msr {
case MsrPrefetchControl:
scriptName = script.PrefetchControlName
case MsrPrefetchers:
scriptName = script.PrefetchersName
case MsrAtomPrefTuning1:
scriptName = script.PrefetchersAtomName
default:
slog.Error("unknown msr for prefetcher", slog.String("msr", fmt.Sprintf("0x%x", pf.Msr)))
continue
}
msrVal := ValFromRegexSubmatch(outputs[scriptName].Stdout, `^([0-9a-fA-F]+)`)
if msrVal == "" {
continue
}
var enabledDisabled string
enabled, err := IsPrefetcherEnabled(msrVal, pf.Bit)
// if on DMR, we need to check if L2P is enabled first, as it dynamically manages the prefetchers at bit 0, 1, 5, and 6
l2pEnabled := false
if slices.Contains([]string{cpus.UarchDMR}, uarch[:3]) {
l2pVal := ValFromRegexSubmatch(outputs[script.PrefetchControlName].Stdout, `^([0-9a-fA-F]+)`)
if l2pVal != "" {
var err error
l2pEnabled, err = IsPrefetcherEnabled(l2pVal, 12)
if err != nil {
slog.Warn("error checking prefetcher enabled status", slog.String("error", err.Error()))
continue
}
if enabled {
enabledDisabled = "Enabled"
} else {
enabledDisabled = "Disabled"
slog.Warn("error checking L2P enabled status", slog.String("error", err.Error()))
}
out = append(out, []string{pf.ShortName, pf.Description, fmt.Sprintf("0x%04X", pf.Msr), strconv.Itoa(pf.Bit), enabledDisabled})
}
}
var results []resolvedPrefetcher
for _, pf := range PrefetcherDefinitions {
if !slices.Contains(pf.Uarchs, "all") && !slices.Contains(pf.Uarchs, uarch[:3]) {
continue
}
var scriptName string
switch pf.Msr {
case MsrPrefetchControl:
scriptName = script.PrefetchControlName
case MsrPrefetchers:
scriptName = script.PrefetchersName
case MsrAtomPrefTuning1:
scriptName = script.PrefetchersAtomName
default:
slog.Error("unknown msr for prefetcher", slog.String("msr", fmt.Sprintf("0x%x", pf.Msr)))
continue
}
msrVal := ValFromRegexSubmatch(outputs[scriptName].Stdout, `^([0-9a-fA-F]+)`)
if msrVal == "" {
continue
}
enabled, err := IsPrefetcherEnabled(msrVal, pf.Bit)
if err != nil {
slog.Warn("error checking prefetcher enabled status", slog.String("error", err.Error()))
continue
}
var status string
if l2pEnabled && pf.ManagedByL2P {
status = "Managed by L2P"
} else if enabled {
status = "Enabled"
} else {
status = "Disabled"
}
results = append(results, resolvedPrefetcher{Definition: pf, Status: status})
}
return results
}

// PrefetchersFromOutput extracts prefetcher status from script outputs.
func PrefetchersFromOutput(outputs map[string]script.ScriptOutput) [][]string {
resolved := resolvePrefetchers(outputs)
if resolved == nil {
return [][]string{}
}
out := make([][]string, 0, len(resolved))
for _, r := range resolved {
out = append(out, []string{
r.Definition.ShortName,
r.Definition.Description,
fmt.Sprintf("0x%04X", r.Definition.Msr),
strconv.Itoa(r.Definition.Bit),
r.Status,
})
}
return out
}

// PrefetchersSummaryFromOutput returns a summary of all prefetcher statuses.
func PrefetchersSummaryFromOutput(outputs map[string]script.ScriptOutput) string {
uarch := UarchFromOutput(outputs)
if uarch == "" {
return ""
}
var prefList []string
for _, pf := range PrefetcherDefinitions {
if slices.Contains(pf.Uarchs, "all") || slices.Contains(pf.Uarchs, uarch[:3]) {
var scriptName string
switch pf.Msr {
case MsrPrefetchControl:
scriptName = script.PrefetchControlName
case MsrPrefetchers:
scriptName = script.PrefetchersName
case MsrAtomPrefTuning1:
scriptName = script.PrefetchersAtomName
default:
slog.Error("unknown msr for prefetcher", slog.String("msr", fmt.Sprintf("0x%x", pf.Msr)))
continue
}
msrVal := ValFromRegexSubmatch(outputs[scriptName].Stdout, `^([0-9a-fA-F]+)`)
if msrVal == "" {
continue
}
var enabledDisabled string
enabled, err := IsPrefetcherEnabled(msrVal, pf.Bit)
if err != nil {
slog.Warn("error checking prefetcher enabled status", slog.String("error", err.Error()))
continue
}
if enabled {
enabledDisabled = "Enabled"
} else {
enabledDisabled = "Disabled"
}
prefList = append(prefList, fmt.Sprintf("%s: %s", pf.ShortName, enabledDisabled))
}
resolved := resolvePrefetchers(outputs)
if len(resolved) == 0 {
return "None"
}
if len(prefList) > 0 {
return strings.Join(prefList, ", ")
prefList := make([]string, 0, len(resolved))
for _, r := range resolved {
prefList = append(prefList, fmt.Sprintf("%s: %s", r.Definition.ShortName, r.Status))
}
return "None"
return strings.Join(prefList, ", ")
}