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
23 changes: 13 additions & 10 deletions cmd/lock/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package lock
import (
"fmt"
"os"
"path/filepath"
"perfspect/internal/common"
"perfspect/internal/progress"
"perfspect/internal/report"
"perfspect/internal/script"
"perfspect/internal/target"
Expand Down Expand Up @@ -165,30 +167,31 @@ func formalizeOutputFormat(outputFormat []string) []string {
return result
}

func pullDataFiles(appContext common.AppContext, scriptOutputs map[string]script.ScriptOutput, myTarget target.Target) error {
// if target is RawTarget, the scriptOutputs may retrieved from a input file, which hints we should not be able to pull the
// perf archive file. In this situation, we don't treat it as an error.
_, isRawTarget := myTarget.(*target.RawTarget)
if isRawTarget {
return nil
}

func pullDataFiles(appContext common.AppContext, scriptOutputs map[string]script.ScriptOutput, myTarget target.Target, statusUpdate progress.MultiSpinnerUpdateFunc) error {
localOutputDir := appContext.OutputDir
tableValues := report.GetValuesForTable(report.KernelLockAnalysisTableName, scriptOutputs)
found := false
for _, field := range tableValues.Fields {
if field.Name == "Perf Package Path" {
for _, remoteFile := range field.Values {
if len(remoteFile) == 0 {
if remoteFile == "" {
continue
}
found = true
_ = statusUpdate(myTarget.GetName(), "retrieving lock package")
err := myTarget.PullFile(remoteFile, localOutputDir)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
_ = statusUpdate(myTarget.GetName(), fmt.Sprintf("failed to retrieve lock package: %v", err))
return err
}
_ = statusUpdate(myTarget.GetName(), fmt.Sprintf("retrieved lock package (%s)", filepath.Base(remoteFile)))
}
break
}
}
if !found {
_ = statusUpdate(myTarget.GetName(), "no lock package found")
}
return nil
}

Expand Down
68 changes: 45 additions & 23 deletions internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,11 @@ type FlagGroup struct {
}

type TargetScriptOutputs struct {
target target.Target
targetName string
scriptOutputs map[string]script.ScriptOutput
tableNames []string
}

func (tso *TargetScriptOutputs) GetTarget() target.Target {
return tso.target
}
func (tso *TargetScriptOutputs) GetScriptOutputs() map[string]script.ScriptOutput {
return tso.scriptOutputs
}
Expand Down Expand Up @@ -83,7 +80,7 @@ const (

type SummaryFunc func([]report.TableValues, map[string]script.ScriptOutput) report.TableValues
type InsightsFunc SummaryFunc
type AdhocFunc func(AppContext, map[string]script.ScriptOutput, target.Target) error
type AdhocFunc func(AppContext, map[string]script.ScriptOutput, target.Target, progress.MultiSpinnerUpdateFunc) error

type ReportingCommand struct {
Cmd *cobra.Command
Expand Down Expand Up @@ -119,6 +116,7 @@ func (rc *ReportingCommand) Run() error {
}()

var orderedTargetScriptOutputs []TargetScriptOutputs
var myTargets []target.Target
if FlagInput != "" {
var err error
orderedTargetScriptOutputs, err = outputsFromInput(rc.SummaryTableName)
Expand All @@ -130,7 +128,9 @@ func (rc *ReportingCommand) Run() error {
}
} else {
// get the targets
myTargets, targetErrs, err := GetTargets(rc.Cmd, elevatedPrivilegesRequired(rc.TableNames), false, localTempDir)
var targetErrs []error
var err error
myTargets, targetErrs, err = GetTargets(rc.Cmd, elevatedPrivilegesRequired(rc.TableNames), false, localTempDir)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
slog.Error(err.Error())
Expand Down Expand Up @@ -230,6 +230,36 @@ func (rc *ReportingCommand) Run() error {
for _, reportFilePath := range reportFilePaths {
fmt.Printf(" %s\n", reportFilePath)
}
// lastly, run any adhoc actions
if rc.AdhocFunc != nil {
fmt.Println()
// setup and start the progress indicator
multiSpinner := progress.NewMultiSpinner()
for _, target := range myTargets {
err := multiSpinner.AddSpinner(target.GetName())
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
slog.Error(err.Error())
rc.Cmd.SilenceUsage = true
return err
}
}
multiSpinner.Start()
adhocErrorChannel := make(chan error)
for i, t := range myTargets {
go func(target target.Target, i int) {
err := rc.AdhocFunc(appContext, orderedTargetScriptOutputs[i].scriptOutputs, target, multiSpinner.Status)
adhocErrorChannel <- err
}(t, i)
}
// wait for all adhoc actions to complete, errors were reported by the AdhocFunc
for range myTargets {
<-adhocErrorChannel
}
// stop the progress indicator
multiSpinner.Finish()
fmt.Println()
}
return nil
}

Expand Down Expand Up @@ -266,7 +296,7 @@ func DefaultInsightsFunc(allTableValues []report.TableValues, scriptOutputs map[
// createRawReports creates the raw report(s) from the collected data
func (rc *ReportingCommand) createRawReports(appContext AppContext, orderedTargetScriptOutputs []TargetScriptOutputs) error {
for _, targetScriptOutputs := range orderedTargetScriptOutputs {
reportBytes, err := report.CreateRawReport(rc.TableNames, targetScriptOutputs.scriptOutputs, targetScriptOutputs.target.GetName())
reportBytes, err := report.CreateRawReport(rc.TableNames, targetScriptOutputs.scriptOutputs, targetScriptOutputs.targetName)
if err != nil {
err = fmt.Errorf("failed to create raw report: %w", err)
return err
Expand All @@ -275,7 +305,7 @@ func (rc *ReportingCommand) createRawReports(appContext AppContext, orderedTarge
if rc.ReportNamePost != "" {
post = "_" + rc.ReportNamePost
}
reportFilename := fmt.Sprintf("%s%s.%s", targetScriptOutputs.target.GetName(), post, "raw")
reportFilename := fmt.Sprintf("%s%s.%s", targetScriptOutputs.targetName, post, "raw")
reportPath := filepath.Join(appContext.OutputDir, reportFilename)
if err = writeReport(reportBytes, reportPath); err != nil {
err = fmt.Errorf("failed to write report: %w", err)
Expand Down Expand Up @@ -324,13 +354,6 @@ func (rc *ReportingCommand) createReports(appContext AppContext, orderedTargetSc
insightsTableValues := rc.InsightsFunc(allTableValues, targetScriptOutputs.scriptOutputs)
allTableValues = append(allTableValues, insightsTableValues)
}
// special case - do some adhoc actions
if rc.AdhocFunc != nil {
err = rc.AdhocFunc(appContext, targetScriptOutputs.scriptOutputs, targetScriptOutputs.target)
if err != nil {
return nil, err
}
}
// special case - add tableValues for the application version
allTableValues = append(allTableValues, report.TableValues{
TableDefinition: report.TableDefinition{
Expand All @@ -342,20 +365,20 @@ func (rc *ReportingCommand) createReports(appContext AppContext, orderedTargetSc
})
// create the report(s)
for _, format := range formats {
reportBytes, err := report.Create(format, allTableValues, targetScriptOutputs.scriptOutputs, targetScriptOutputs.target.GetName())
reportBytes, err := report.Create(format, allTableValues, targetScriptOutputs.scriptOutputs, targetScriptOutputs.targetName)
if err != nil {
err = fmt.Errorf("failed to create report: %w", err)
return nil, err
}
if len(formats) == 1 && format == report.FormatTxt {
fmt.Printf("%s:\n", targetScriptOutputs.target.GetName())
fmt.Printf("%s:\n", targetScriptOutputs.targetName)
fmt.Print(string(reportBytes))
}
post := ""
if rc.ReportNamePost != "" {
post = "_" + rc.ReportNamePost
}
reportFilename := fmt.Sprintf("%s%s.%s", targetScriptOutputs.target.GetName(), post, format)
reportFilename := fmt.Sprintf("%s%s.%s", targetScriptOutputs.targetName, post, format)
reportPath := filepath.Join(appContext.OutputDir, reportFilename)
if err = writeReport(reportBytes, reportPath); err != nil {
err = fmt.Errorf("failed to write report: %w", err)
Expand All @@ -371,7 +394,7 @@ func (rc *ReportingCommand) createReports(appContext AppContext, orderedTargetSc
// - only those that we received output from
targetNames := make([]string, 0)
for _, targetScriptOutputs := range orderedTargetScriptOutputs {
targetNames = append(targetNames, targetScriptOutputs.target.GetName())
targetNames = append(targetNames, targetScriptOutputs.targetName)
}
multiTargetFormats := []string{report.FormatHtml, report.FormatXlsx}
for _, format := range multiTargetFormats {
Expand Down Expand Up @@ -413,8 +436,7 @@ func outputsFromInput(summaryTableName string) ([]TargetScriptOutputs, error) {
}
tableNames = util.UniqueAppend(tableNames, tableName)
}
rawTarget := target.NewRawTarget(rawReport.TargetName)
orderedTargetScriptOutputs = append(orderedTargetScriptOutputs, TargetScriptOutputs{target: rawTarget, scriptOutputs: rawReport.ScriptOutputs, tableNames: tableNames})
orderedTargetScriptOutputs = append(orderedTargetScriptOutputs, TargetScriptOutputs{targetName: rawReport.TargetName, scriptOutputs: rawReport.ScriptOutputs, tableNames: tableNames})
}
return orderedTargetScriptOutputs, nil
}
Expand Down Expand Up @@ -467,7 +489,7 @@ func outputsFromTargets(cmd *cobra.Command, myTargets []target.Target, tableName
// reorder to match order of myTargets
for targetIdx, target := range myTargets {
for _, targetScriptOutputs := range allTargetScriptOutputs {
if targetScriptOutputs.target.GetName() == target.GetName() {
if targetScriptOutputs.targetName == target.GetName() {
targetScriptOutputs.tableNames = targetTableNames[targetIdx]
orderedTargetScriptOutputs = append(orderedTargetScriptOutputs, targetScriptOutputs)
break
Expand Down Expand Up @@ -515,5 +537,5 @@ func collectOnTarget(myTarget target.Target, scriptsToRun []script.ScriptDefinit
if statusUpdate != nil {
_ = statusUpdate(myTarget.GetName(), "collection complete")
}
channelTargetScriptOutputs <- TargetScriptOutputs{target: myTarget, scriptOutputs: scriptOutputs}
channelTargetScriptOutputs <- TargetScriptOutputs{targetName: myTarget.GetName(), scriptOutputs: scriptOutputs}
}
3 changes: 1 addition & 2 deletions internal/report/table_defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1272,8 +1272,7 @@ func sstTFLPTableValues(outputs map[string]script.ScriptOutput) []Field {
for i, line := range lines {
// field names are in the header
if i == 0 {
fieldNames := strings.SplitSeq(line, ",")
for fieldName := range fieldNames {
for fieldName := range strings.SplitSeq(line, ",") {
fields = append(fields, Field{Name: fieldName + " (MHz)"})
}
continue
Expand Down
6 changes: 2 additions & 4 deletions internal/report/table_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1703,8 +1703,7 @@ func cveInfoFromOutput(outputs map[string]script.ScriptOutput) [][]string {
/* "1,3-5,8" -> [1,3,4,5,8] */
func expandCPUList(cpuList string) (cpus []int) {
if cpuList != "" {
tokens := strings.SplitSeq(cpuList, ",")
for token := range tokens {
for token := range strings.SplitSeq(cpuList, ",") {
if strings.Contains(token, "-") {
subTokens := strings.Split(token, "-")
if len(subTokens) == 2 {
Expand Down Expand Up @@ -1805,8 +1804,7 @@ func nicIRQMappingsFromOutput(outputs map[string]script.ScriptOutput) [][]string
// which is <irq>:<cpu(s)>
// we need to reverse it to <cpu>:<irq(s)>
cpuIRQMappings := make(map[int][]int)
irqCPUPairs := strings.SplitSeq(nic.CPUAffinity, ";")
for pair := range irqCPUPairs {
for pair := range strings.SplitSeq(nic.CPUAffinity, ";") {
if pair == "" {
continue
}
Expand Down
3 changes: 1 addition & 2 deletions internal/script/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,7 @@ func formMasterScript(targetTempDirectory string, parallelScripts []ScriptDefini
// It returns a list of ScriptOutput objects, one for each script that was run.
func parseMasterScriptOutput(masterScriptOutput string) (scriptOutputs []ScriptOutput) {
// split output of master script into individual script outputs
outputs := strings.SplitSeq(masterScriptOutput, "<---------------------->\n")
for output := range outputs {
for output := range strings.SplitSeq(masterScriptOutput, "<---------------------->\n") {
lines := strings.Split(output, "\n")
if len(lines) < 4 { // minimum lines for a script output
continue
Expand Down
Loading