Skip to content
Merged
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
2 changes: 1 addition & 1 deletion cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func printConfig(myTargets []target.Target, localTempDir string) (err error) {
}
// create the report for this single table
var reportBytes []byte
if reportBytes, err = report.Create("txt", tableValues, targetScriptOutputs.ScriptOutputs, targetScriptOutputs.TargetName); err != nil {
if reportBytes, err = report.Create("txt", tableValues, targetScriptOutputs.TargetName); err != nil {
err = fmt.Errorf("failed to create report: %v", err)
return
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/config/flag_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ const (
const (
flagCoreCountName = "cores"
flagLLCSizeName = "llc"
flagAllCoreMaxFrequencyName = "core-max"
flagTDPName = "tdp"
flagAllCoreMaxFrequencyName = "core-max"
flagEPBName = "epb"
flagEPPName = "epp"
flagGovernorName = "gov"
Expand Down Expand Up @@ -93,13 +93,13 @@ func initializeFlags(cmd *cobra.Command) {
func(cmd *cobra.Command) bool { value, _ := cmd.Flags().GetInt(flagCoreCountName); return value > 0 }),
newFloat64Flag(cmd, flagLLCSizeName, 0, setLlcSize, "LLC size in MB", "greater than 0",
func(cmd *cobra.Command) bool { value, _ := cmd.Flags().GetFloat64(flagLLCSizeName); return value > 0 }),
newIntFlag(cmd, flagTDPName, 0, setTDP, "maximum power per processor in Watts", "greater than 0",
func(cmd *cobra.Command) bool { value, _ := cmd.Flags().GetInt(flagTDPName); return value > 0 }),
newFloat64Flag(cmd, flagAllCoreMaxFrequencyName, 0, setCoreFrequency, "all-core max frequency in GHz", "greater than 0.1",
func(cmd *cobra.Command) bool {
value, _ := cmd.Flags().GetFloat64(flagAllCoreMaxFrequencyName)
return value > 0.1
}),
newIntFlag(cmd, flagTDPName, 0, setTDP, "maximum power per processor in Watts", "greater than 0",
func(cmd *cobra.Command) bool { value, _ := cmd.Flags().GetInt(flagTDPName); return value > 0 }),
newIntFlag(cmd, flagEPBName, 0, setEPB, "energy perf bias from best performance (0) to most power savings (15)", "0-15",
func(cmd *cobra.Command) bool {
value, _ := cmd.Flags().GetInt(flagEPBName)
Expand Down
2 changes: 1 addition & 1 deletion internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ func (rc *ReportingCommand) createReports(appContext AppContext, orderedTargetSc
})
// create the report(s)
for _, format := range formats {
reportBytes, err := report.Create(format, allTableValues, targetScriptOutputs.ScriptOutputs, targetScriptOutputs.TargetName)
reportBytes, err := report.Create(format, allTableValues, targetScriptOutputs.TargetName)
if err != nil {
err = fmt.Errorf("failed to create report: %w", err)
return nil, err
Expand Down
41 changes: 41 additions & 0 deletions internal/report/render_text.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,44 @@ func DefaultTextTableRendererFunc(tableValues TableValues) string {
}
return sb.String()
}

// configurationTableTextRenderer renders the configuration table for text reports.
// It's similar to the default text table renderer, but uses the Description field
// to show the command line argument for each config item.
// Example output:
// Configuration
// =============
// Cores per Socket: 86 --cores <N>
// L3 Cache: 336M --llc <MB>
// Package Power / TDP: 350W --tdp <Watts>
// All-Core Max Frequency: 3.2GHz --core-max <GHz>
func configurationTableTextRenderer(tableValues TableValues) string {
var sb strings.Builder

// Find the longest field name and value for formatting
maxFieldNameLen := 0
maxValueLen := 0
for _, field := range tableValues.Fields {
if len(field.Name) > maxFieldNameLen {
maxFieldNameLen = len(field.Name)
}
if len(field.Values) > 0 && len(field.Values[0]) > maxValueLen {
maxValueLen = len(field.Values[0])
}
}

// Print each field with name, value, and description (command-line arg)
for _, field := range tableValues.Fields {
var value string
if len(field.Values) > 0 {
value = field.Values[0]
}
// Format: "Field Name: Value Description"
sb.WriteString(fmt.Sprintf("%-*s %-*s %s\n",
maxFieldNameLen+1, field.Name+":",
maxValueLen, value,
field.Description))
}

return sb.String()
}
5 changes: 1 addition & 4 deletions internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ package report
import (
"fmt"
"strings"

"perfspect/internal/script"
)

const (
Expand All @@ -32,13 +30,12 @@ var FormatOptions = []string{FormatHtml, FormatXlsx, FormatJson, FormatTxt}
// Parameters:
// - format: The desired format of the report (txt, json, html, xlsx, raw).
// - tableValues: The values for each field in each table.
// - scriptOutputs: The outputs of any scripts used in the report.
// - targetName: The name of the target for which the report is being generated.
//
// Returns:
// - out: The generated report as a byte slice.
// - err: An error, if any occurred during report generation.
func Create(format string, allTableValues []TableValues, scriptOutputs map[string]script.ScriptOutput, targetName string) (out []byte, err error) {
func Create(format string, allTableValues []TableValues, targetName string) (out []byte, err error) {
// make sure that all fields have the same number of values
for _, tableValue := range allTableValues {
numRows := -1
Expand Down
52 changes: 30 additions & 22 deletions internal/report/table_defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,8 @@ var tableDefinitions = map[string]TableDefinition{
script.CstatesScriptName,
script.C1DemotionScriptName,
},
FieldsFunc: configurationTableValues},
TextTableRendererFunc: configurationTableTextRenderer,
FieldsFunc: configurationTableValues},
//
// benchmarking tables
//
Expand Down Expand Up @@ -2176,34 +2177,36 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []Field {
slog.Error("failed to get uarch from script outputs")
return []Field{}
}

// This table is only shown in text mode on stdout for the config command. The config
// command implements its own print logic and uses the Description field to show the command line
// argument for each config item.
fields := []Field{
{Name: "Cores per Socket", Values: []string{valFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Core\(s\) per socket:\s*(.+)$`)}},
{Name: "L3 Cache", Values: []string{l3InstanceFromOutput(outputs)}},
{Name: "Package Power / TDP", Values: []string{tdpFromOutput(outputs)}},
{Name: "All-Core Max Frequency", Values: []string{allCoreMaxFrequencyFromOutput(outputs)}},
{Name: "Cores per Socket", Description: "--cores <N>", Values: []string{valFromRegexSubmatch(outputs[script.LscpuScriptName].Stdout, `^Core\(s\) per socket:\s*(.+)$`)}},
{Name: "L3 Cache", Description: "--llc <MB>", Values: []string{l3InstanceFromOutput(outputs)}},
{Name: "Package Power / TDP", Description: "--tdp <Watts>", Values: []string{tdpFromOutput(outputs)}},
{Name: "All-Core Max Frequency", Description: "--core-max <GHz>", Values: []string{allCoreMaxFrequencyFromOutput(outputs)}},
}
if strings.Contains(uarch, "SRF") || strings.Contains(uarch, "GNR") || strings.Contains(uarch, "CWF") {
fields = append(fields, []Field{
{Name: "Uncore Min Frequency (Compute)", Values: []string{uncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}},
{Name: "Uncore Min Frequency (I/O)", Values: []string{uncoreMinMaxDieFrequencyFromOutput(false, false, outputs)}},
{Name: "Uncore Max Frequency (Compute)", Values: []string{uncoreMinMaxDieFrequencyFromOutput(true, true, outputs)}},
{Name: "Uncore Max Frequency (I/O)", Values: []string{uncoreMinMaxDieFrequencyFromOutput(true, false, outputs)}},
{Name: "Uncore Max Frequency (Compute)", Description: "--uncore-max-compute <GHz>", Values: []string{uncoreMinMaxDieFrequencyFromOutput(true, true, outputs)}},
{Name: "Uncore Min Frequency (Compute)", Description: "--uncore-min-compute <GHz>", Values: []string{uncoreMinMaxDieFrequencyFromOutput(false, true, outputs)}},
{Name: "Uncore Max Frequency (I/O)", Description: "--uncore-max-io <GHz>", Values: []string{uncoreMinMaxDieFrequencyFromOutput(true, false, outputs)}},
{Name: "Uncore Min Frequency (I/O)", Description: "--uncore-min-io <GHz>", Values: []string{uncoreMinMaxDieFrequencyFromOutput(false, false, outputs)}},
}...)
} else {
fields = append(fields, []Field{
{Name: "Uncore Max Frequency (GHz)", Values: []string{uncoreMaxFrequencyFromOutput(outputs)}},
{Name: "Uncore Min Frequency (GHz)", Values: []string{uncoreMinFrequencyFromOutput(outputs)}},
{Name: "Uncore Max Frequency", Description: "--uncore-max <GHz>", Values: []string{uncoreMaxFrequencyFromOutput(outputs)}},
{Name: "Uncore Min Frequency", Description: "--uncore-min <GHz>", Values: []string{uncoreMinFrequencyFromOutput(outputs)}},
}...)
}
fields = append(fields, []Field{
{Name: "Energy Performance Bias", Values: []string{epbFromOutput(outputs)}},
{Name: "Energy Performance Preference", Values: []string{eppFromOutput(outputs)}},
{Name: "Scaling Governor", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}},
{Name: "Energy Performance Bias", Description: "--epb <0-15>", Values: []string{epbFromOutput(outputs)}},
{Name: "Energy Performance Preference", Description: "--epp <0-255>", Values: []string{eppFromOutput(outputs)}},
{Name: "Scaling Governor", Description: "--gov <performance|powersave>", Values: []string{strings.TrimSpace(outputs[script.ScalingGovernorScriptName].Stdout)}},
}...)
// add ELC (for SRF, CWF and GNR only)
if strings.Contains(uarch, "SRF") || strings.Contains(uarch, "GNR") || strings.Contains(uarch, "CWF") {
fields = append(fields, Field{Name: "Efficiency Latency Control", Values: []string{elcSummaryFromOutput(outputs)}})
fields = append(fields, Field{Name: "Efficiency Latency Control", Description: "--elc <default|latency-optimized>", Values: []string{elcSummaryFromOutput(outputs)}})
}
// add prefetchers
for _, pf := range prefetcherDefinitions {
Expand Down Expand Up @@ -2232,18 +2235,23 @@ func configurationTableValues(outputs map[string]script.ScriptOutput) []Field {
} else {
enabledDisabled = "Disabled"
}
fields = append(fields, Field{Name: pf.ShortName + " prefetcher", Values: []string{enabledDisabled}})
fields = append(fields,
Field{
Name: pf.ShortName + " prefetcher",
Description: "--" + "pref-" + strings.ReplaceAll(strings.ToLower(pf.ShortName), " ", "") + " <enable|disable>",
Values: []string{enabledDisabled}},
)
}
}
// add C-states
cstates := cstatesSummaryFromOutput(outputs)
if cstates != "" {
fields = append(fields, Field{Name: "C-states", Values: []string{cstates}})
// add C6
c6 := c6FromOutput(outputs)
if c6 != "" {
fields = append(fields, Field{Name: "C6", Description: "--c6 <enable|disable>", Values: []string{c6}})
}
// add C1 Demotion
c1Demotion := strings.TrimSpace(outputs[script.C1DemotionScriptName].Stdout)
if c1Demotion != "" {
fields = append(fields, Field{Name: "C1 Demotion", Values: []string{c1Demotion}})
fields = append(fields, Field{Name: "C1 Demotion", Description: "--c1-demotion <enable|disable>", Values: []string{c1Demotion}})
}
return fields
}
Expand Down
13 changes: 13 additions & 0 deletions internal/report/table_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,19 @@ type cstateInfo struct {
Status string
}

func c6FromOutput(outputs map[string]script.ScriptOutput) string {
cstatesInfo := cstatesFromOutput(outputs)
if cstatesInfo == nil {
return ""
}
for _, cstateInfo := range cstatesInfo {
if cstateInfo.Name == "C6" {
return cstateInfo.Status
}
}
return ""
}

func cstatesFromOutput(outputs map[string]script.ScriptOutput) []cstateInfo {
var cstatesInfo []cstateInfo
output := outputs[script.CstatesScriptName].Stdout
Expand Down