From 27dbeb4a4d6bfdc25754bd274f25b639e74e1223 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Sat, 1 Nov 2025 17:36:52 -0700 Subject: [PATCH 01/10] update processwatch Signed-off-by: Harper, Jason M --- cmd/telemetry/telemetry.go | 53 +++++++++++++++++---------- internal/report/render_html.go | 67 ++++++++++++++++++++++++++-------- internal/script/script_defs.go | 15 ++++---- tools/Makefile | 2 +- 4 files changed, 94 insertions(+), 43 deletions(-) diff --git a/cmd/telemetry/telemetry.go b/cmd/telemetry/telemetry.go index 74dfe7ce..1daccf3a 100644 --- a/cmd/telemetry/telemetry.go +++ b/cmd/telemetry/telemetry.go @@ -7,7 +7,6 @@ package telemetry import ( "fmt" "log/slog" - "regexp" "slices" "strconv" "strings" @@ -66,7 +65,6 @@ var ( flagNoSystemSummary bool flagInstrMixPid int - flagInstrMixFilter []string flagInstrMixFrequency int ) @@ -92,7 +90,6 @@ const ( flagNoSystemSummaryName = "no-summary" flagInstrMixPidName = "instrmix-pid" - flagInstrMixFilterName = "instrmix-filter" flagInstrMixFrequencyName = "instrmix-frequency" ) @@ -113,6 +110,11 @@ var categories = []common.Category{ {FlagName: flagGaudiName, FlagVar: &flagGaudi, DefaultValue: false, Help: "monitor gaudi", TableNames: []string{report.GaudiTelemetryTableName}}, } +const ( + instrmixFrequencyDefaultSystemWide = 10000000 + instrmixFrequencyDefaultPerPID = 100000 +) + func init() { // set up config category flags for _, cat := range categories { @@ -124,8 +126,7 @@ func init() { Cmd.Flags().IntVar(&flagDuration, flagDurationName, 30, "") Cmd.Flags().IntVar(&flagInterval, flagIntervalName, 2, "") Cmd.Flags().IntVar(&flagInstrMixPid, flagInstrMixPidName, 0, "") - Cmd.Flags().StringSliceVar(&flagInstrMixFilter, flagInstrMixFilterName, []string{"SSE", "AVX", "AVX2", "AVX512", "AMX_TILE"}, "") - Cmd.Flags().IntVar(&flagInstrMixFrequency, flagInstrMixFrequencyName, 10000000, "") // 10 million + Cmd.Flags().IntVar(&flagInstrMixFrequency, flagInstrMixFrequencyName, instrmixFrequencyDefaultSystemWide, "") Cmd.Flags().BoolVar(&flagNoSystemSummary, flagNoSystemSummaryName, false, "") common.AddTargetFlags(Cmd) @@ -193,13 +194,9 @@ func getFlagGroups() []common.FlagGroup { Name: flagInstrMixPidName, Help: "PID to monitor for instruction mix, no PID means all processes", }, - { - Name: flagInstrMixFilterName, - Help: "filter to apply to instruction mix", - }, { Name: flagInstrMixFrequencyName, - Help: "number of instructions between samples when no PID specified", + Help: "number of instructions between samples, default is 10,000,000 when collecting system wide and 100,000 when collecting for a specific PID", }, { Name: flagNoSystemSummaryName, @@ -259,16 +256,12 @@ func validateFlags(cmd *cobra.Command, args []string) error { if flagDuration == 0 && (target != "" || targets != "") { return common.FlagValidationError(cmd, "duration must be greater than 0 when collecting from a remote target") } - if cmd.Flags().Lookup(flagInstrMixFilterName).Changed { - re := regexp.MustCompile("^[A-Z0-9_]+$") - for _, filter := range flagInstrMixFilter { - if !re.MatchString(filter) { - return common.FlagValidationError(cmd, fmt.Sprintf("invalid filter: %s, must be uppercase letters, numbers, and underscores", filter)) - } - } - } if flagInstrMixFrequency < 100000 { // 100,000 instructions is the minimum frequency - return common.FlagValidationError(cmd, "instruction mix frequency must be 100,000 or greater") + return common.FlagValidationError(cmd, "instruction mix frequency must be 100,000 or greater to limit overhead") + } + // warn if instruction mix frequency is low when collecting system wide + if flagInstrMix && flagInstrMixPid == 0 && flagInstrMixFrequency < instrmixFrequencyDefaultSystemWide { + slog.Warn("instruction mix frequency is set to a value lower than default for system wide collection, consider using a higher frequency to limit collection overhead", slog.Int("frequency", flagInstrMixFrequency)) } // common target flags if err := common.ValidateTargetFlags(cmd); err != nil { @@ -289,6 +282,23 @@ func runCmd(cmd *cobra.Command, args []string) error { tableNames = append(tableNames, cat.TableNames...) } } + // confirm proper default for instrmix frequency + if flagInstrMix { + if flagInstrMixPid != 0 && !cmd.Flags().Changed(flagInstrMixFrequencyName) { + // per-PID collection and frequency not changed, set to per-PID default + flagInstrMixFrequency = instrmixFrequencyDefaultPerPID + } + } + // hidden feature - PDU telemetry, only enabled when four environment variables are set + // PERFSPECT_PDU_HOST, PERFSPECT_PDU_USER, PERFSPECT_PDU_PASSWORD, PERFSPECT_PDU_OUTLET + // pduHost := os.Getenv("PERFSPECT_PDU_HOST") + // pduUser := os.Getenv("PERFSPECT_PDU_USER") + // pduPassword := os.Getenv("PERFSPECT_PDU_PASSWORD") + // pduOutlet := os.Getenv("PERFSPECT_PDU_OUTLET") + // if pduHost != "" && pduUser != "" && pduPassword != "" && pduOutlet != "" { + // slog.Info("PDU telemetry enabled", slog.String("host", pduHost), slog.String("outlet", pduOutlet)) + // tableNames = append(tableNames, report.PDUTelemetryTableName) + // } // include telemetry summary table if all telemetry options are selected var summaryFunc common.SummaryFunc if flagAll { @@ -306,8 +316,11 @@ func runCmd(cmd *cobra.Command, args []string) error { "Interval": strconv.Itoa(flagInterval), "Duration": strconv.Itoa(flagDuration), "InstrMixPID": strconv.Itoa(flagInstrMixPid), - "InstrMixFilter": strings.Join(flagInstrMixFilter, " "), "InstrMixFrequency": strconv.Itoa(flagInstrMixFrequency), + // "PDUHost": pduHost, + // "PDUUser": pduUser, + // "PDUPassword": pduPassword, + // "PDUOutlet": pduOutlet, }, TableNames: tableNames, SummaryFunc: summaryFunc, diff --git a/internal/report/render_html.go b/internal/report/render_html.go index 30ccee7b..7233bc9d 100644 --- a/internal/report/render_html.go +++ b/internal/report/render_html.go @@ -377,7 +377,8 @@ const datasetTemplate = ` backgroundColor: '{{.Color}}', borderColor: '{{.Color}}', borderWidth: 1, - showLine: true + showLine: true, + hidden: {{.Hidden}} } ` const lineChartTemplate = `
@@ -715,20 +716,27 @@ func dimmTableHTMLRenderer(tableValues TableValues, targetName string) string { return renderHTMLTable(socketTableHeaders, socketTableValues, "pure-table pure-table-bordered", [][]string{}) } -func renderChart(chartType string, allFormattedPoints []string, datasetNames []string, xAxisLabels []string, config chartTemplateStruct) string { +func renderChart(chartType string, allFormattedPoints []string, datasetNames []string, xAxisLabels []string, config chartTemplateStruct, datasetHiddenFlags []bool) string { datasets := []string{} for dataIdx, formattedPoints := range allFormattedPoints { specValues := formattedPoints dst := texttemplate.Must(texttemplate.New("datasetTemplate").Parse(datasetTemplate)) buf := new(bytes.Buffer) + // determine hidden flag for this dataset + hidden := "false" + if datasetHiddenFlags != nil && dataIdx < len(datasetHiddenFlags) && datasetHiddenFlags[dataIdx] { + hidden = "true" + } err := dst.Execute(buf, struct { - Label string - Data string - Color string + Label string + Data string + Color string + Hidden string }{ - Label: datasetNames[dataIdx], - Data: specValues, - Color: getColor(dataIdx), + Label: datasetNames[dataIdx], + Data: specValues, + Color: getColor(dataIdx), + Hidden: hidden, }) if err != nil { slog.Error("error executing template", slog.String("error", err.Error())) @@ -781,10 +789,10 @@ func renderScatterChart(data [][]scatterPoint, datasetNames []string, config cha } allFormattedPoints = append(allFormattedPoints, strings.Join(formattedPoints, ",")) } - return renderChart("scatter", allFormattedPoints, datasetNames, nil, config) + return renderChart("scatter", allFormattedPoints, datasetNames, nil, config, nil) } -func renderLineChart(xAxisLabels []string, data [][]float64, datasetNames []string, config chartTemplateStruct) string { +func renderLineChart(xAxisLabels []string, data [][]float64, datasetNames []string, config chartTemplateStruct, datasetHiddenFlags []bool) string { allFormattedPoints := []string{} for dataIdx := range data { formattedPoints := []string{} @@ -793,7 +801,7 @@ func renderLineChart(xAxisLabels []string, data [][]float64, datasetNames []stri } allFormattedPoints = append(allFormattedPoints, strings.Join(formattedPoints, ",")) } - return renderChart("line", allFormattedPoints, datasetNames, xAxisLabels, config) + return renderChart("line", allFormattedPoints, datasetNames, xAxisLabels, config, datasetHiddenFlags) } func renderFrequencyTable(tableValues TableValues) (out string) { @@ -908,7 +916,7 @@ func telemetryTableHTMLRenderer(tableValues TableValues, data [][]float64, datas timestamps = append(timestamps, timestamp) } } - return renderLineChart(timestamps, data, datasetNames, chartConfig) + return renderLineChart(timestamps, data, datasetNames, chartConfig, nil) } func cpuUtilizationTelemetryTableHTMLRenderer(tableValues TableValues, targetName string) string { @@ -1361,11 +1369,23 @@ func c6TelemetryTableHTMLRenderer(tableValues TableValues, targetName string) st return telemetryTableHTMLRenderer(tableValues, data, datasetNames, chartConfig) } +// instructionTelemetryTableHTMLRenderer renders instruction set usage statistics +// These categories are included even if all values are zero: +// +// "SSE", "AVX", "AVX2", "AVX512", "AMX_TILE" +// +// Other categories are only included if they have non-zero values. +// Other categories are hidden by default. +// +// Each category is a separate dataset within the chart. func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname string) string { + //alwaysIncludeCategories := []string{"SSE", "AVX", "AVX2", "AVX512", "AMX_TILE"} data := [][]float64{} datasetNames := []string{} + var hiddenFlags []bool for _, field := range tableValues.Fields[1:] { points := []float64{} + sum := 0.0 for _, val := range field.Values { if val == "" { break @@ -1376,10 +1396,18 @@ func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname s return "" } points = append(points, stat) + sum += stat } if len(points) > 0 { - data = append(data, points) - datasetNames = append(datasetNames, field.Name) + //include := sum > 0 || slices.Contains(alwaysIncludeCategories, field.Name) + include := true + if include { + data = append(data, points) + datasetNames = append(datasetNames, field.Name) + // hidden if sum == 0 (which can only happen for 'always include' categories) + hidden := sum == 0 + hiddenFlags = append(hiddenFlags, hidden) + } } } chartConfig := chartTemplateStruct{ @@ -1393,7 +1421,16 @@ func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname s SuggestedMin: "0", SuggestedMax: "0", } - return telemetryTableHTMLRenderer(tableValues, data, datasetNames, chartConfig) + // render directly using renderLineChart to supply hidden flags + tsFieldIdx := 0 + var timestamps []string + for i := range tableValues.Fields[0].Values { + timestamp := tableValues.Fields[tsFieldIdx].Values[i] + if !slices.Contains(timestamps, timestamp) { + timestamps = append(timestamps, timestamp) + } + } + return renderLineChart(timestamps, data, datasetNames, chartConfig, hiddenFlags) } func renderGaudiStatsChart(tableValues TableValues, chartStatFieldName string, titleText string, yAxisText string, suggestedMax string) string { diff --git a/internal/script/script_defs.go b/internal/script/script_defs.go index 6a39995a..f7a055f3 100644 --- a/internal/script/script_defs.go +++ b/internal/script/script_defs.go @@ -1288,13 +1288,14 @@ if [ {{.InstrMixPID}} -eq 0 ]; then else arg_pid="-p {{.InstrMixPID}}" fi -# .InstrMixFilter is a space separated list of ISA categories -# for each category in the list, add -f to the command line -for category in {{.InstrMixFilter}}; do - arg_filter="$arg_filter -f $category" -done - -processwatch -c $arg_sampling_rate $arg_pid $arg_interval $arg_count $arg_filter & +# -c: CSV output, -a: all categories, -p: PID, -s: sampling rate,-i: interval, -n: count +# example output: +# interval,pid,name,INVALID,ADOX_ADCX,AES +# 0,ALL,ALL,0.000000,0.000000,0.000000,0.000000 +# 0,2038501,stress-ng-cpu,0.000000,0.000000,0.000000,0.000000 +# We only need the header line and the subsequent "ALL" lines (for each interval) +# Filter output: keep header (NR==1) and lines where 2nd and 3rd columns are ALL +processwatch -c -a $arg_pid $arg_sampling_rate $arg_interval $arg_count | awk -F',' 'NR==1 || ($2=="ALL" && $3=="ALL")' & echo $! > {{.ScriptName}}_cmd.pid wait `, diff --git a/tools/Makefile b/tools/Makefile index 1f684673..9a0e389e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -290,7 +290,7 @@ endif perf: perf-x86_64 perf-aarch64 @echo "Perf tools built successfully in bin/x86_64 and bin/aarch64 directories." -PROCESSWATCH_VERSION := "c394065" +PROCESSWATCH_VERSION := "v1.3" processwatch: ifeq ("$(wildcard processwatch)","") git clone --recursive https://github.com/intel/processwatch.git From 5dc5cd2c86b6be44ef839cd9b403bb69a48467bf Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Sat, 1 Nov 2025 17:45:17 -0700 Subject: [PATCH 02/10] sort Signed-off-by: Harper, Jason M --- internal/report/render_html.go | 57 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/internal/report/render_html.go b/internal/report/render_html.go index 7233bc9d..16e1382f 100644 --- a/internal/report/render_html.go +++ b/internal/report/render_html.go @@ -1370,24 +1370,21 @@ func c6TelemetryTableHTMLRenderer(tableValues TableValues, targetName string) st } // instructionTelemetryTableHTMLRenderer renders instruction set usage statistics -// These categories are included even if all values are zero: -// -// "SSE", "AVX", "AVX2", "AVX512", "AMX_TILE" -// -// Other categories are only included if they have non-zero values. -// Other categories are hidden by default. -// // Each category is a separate dataset within the chart. +// Categories with zero total usage are hidden by default. func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname string) string { - //alwaysIncludeCategories := []string{"SSE", "AVX", "AVX2", "AVX512", "AMX_TILE"} - data := [][]float64{} - datasetNames := []string{} - var hiddenFlags []bool - for _, field := range tableValues.Fields[1:] { + // Collect entries with their sums so we can sort per requirements + type instrEntry struct { + name string + points []float64 + sum float64 + } + entries := []instrEntry{} + for _, field := range tableValues.Fields[1:] { // skip timestamp field points := []float64{} sum := 0.0 for _, val := range field.Values { - if val == "" { + if val == "" { // end of data for this category break } stat, err := strconv.ParseFloat(val, 64) @@ -1398,18 +1395,32 @@ func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname s points = append(points, stat) sum += stat } - if len(points) > 0 { - //include := sum > 0 || slices.Contains(alwaysIncludeCategories, field.Name) - include := true - if include { - data = append(data, points) - datasetNames = append(datasetNames, field.Name) - // hidden if sum == 0 (which can only happen for 'always include' categories) - hidden := sum == 0 - hiddenFlags = append(hiddenFlags, hidden) - } + if len(points) > 0 { // only include categories with at least one point + entries = append(entries, instrEntry{name: field.Name, points: points, sum: sum}) } } + // Partition into non-zero and zero-sum groups + nonZero := []instrEntry{} + zero := []instrEntry{} + for _, e := range entries { + if e.sum > 0 { + nonZero = append(nonZero, e) + } else { + zero = append(zero, e) + } + } + sort.Slice(nonZero, func(i, j int) bool { return nonZero[i].name < nonZero[j].name }) + sort.Slice(zero, func(i, j int) bool { return zero[i].name < zero[j].name }) + ordered := append(nonZero, zero...) + data := make([][]float64, 0, len(ordered)) + datasetNames := make([]string, 0, len(ordered)) + hiddenFlags := make([]bool, 0, len(ordered)) + for _, e := range ordered { + data = append(data, e.points) + datasetNames = append(datasetNames, e.name) + // hide zero-sum categories by default + hiddenFlags = append(hiddenFlags, e.sum == 0) + } chartConfig := chartTemplateStruct{ ID: fmt.Sprintf("%s%d", tableValues.Name, util.RandUint(10000)), XaxisText: "Time", From f86adbf43248771a5f059046c9775ee6773c3e98 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Sat, 1 Nov 2025 17:54:26 -0700 Subject: [PATCH 03/10] height Signed-off-by: Harper, Jason M --- internal/report/render_html.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/report/render_html.go b/internal/report/render_html.go index 16e1382f..cb9f2893 100644 --- a/internal/report/render_html.go +++ b/internal/report/render_html.go @@ -1428,7 +1428,7 @@ func instructionTelemetryTableHTMLRenderer(tableValues TableValues, targetname s TitleText: "", DisplayTitle: "false", DisplayLegend: "true", - AspectRatio: "2", + AspectRatio: "1", // extra tall due to large number of data sets SuggestedMin: "0", SuggestedMax: "0", } From 043964afe8aff876c37e3b549100ad005e6951db Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Sat, 1 Nov 2025 18:09:04 -0700 Subject: [PATCH 04/10] move gaudi telemetry to hidden feature Signed-off-by: Harper, Jason M --- cmd/telemetry/telemetry.go | 11 ++++++++--- internal/script/script_defs.go | 23 +++++++++++------------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/cmd/telemetry/telemetry.go b/cmd/telemetry/telemetry.go index 1daccf3a..7fb98d94 100644 --- a/cmd/telemetry/telemetry.go +++ b/cmd/telemetry/telemetry.go @@ -7,6 +7,7 @@ package telemetry import ( "fmt" "log/slog" + "os" "slices" "strconv" "strings" @@ -60,7 +61,6 @@ var ( flagPower bool flagTemperature bool flagInstrMix bool - flagGaudi bool flagNoSystemSummary bool @@ -85,7 +85,6 @@ const ( flagPowerName = "power" flagTemperatureName = "temperature" flagInstrMixName = "instrmix" - flagGaudiName = "gaudi" flagNoSystemSummaryName = "no-summary" @@ -107,7 +106,6 @@ var categories = []common.Category{ {FlagName: flagStorageName, FlagVar: &flagStorage, DefaultValue: false, Help: "monitor storage", TableNames: []string{report.DriveTelemetryTableName}}, {FlagName: flagIRQRateName, FlagVar: &flagIRQRate, DefaultValue: false, Help: "monitor IRQ rate", TableNames: []string{report.IRQRateTelemetryTableName}}, {FlagName: flagInstrMixName, FlagVar: &flagInstrMix, DefaultValue: false, Help: "monitor instruction mix", TableNames: []string{report.InstructionTelemetryTableName}}, - {FlagName: flagGaudiName, FlagVar: &flagGaudi, DefaultValue: false, Help: "monitor gaudi", TableNames: []string{report.GaudiTelemetryTableName}}, } const ( @@ -289,6 +287,12 @@ func runCmd(cmd *cobra.Command, args []string) error { flagInstrMixFrequency = instrmixFrequencyDefaultPerPID } } + // hidden feature - Gaudi telemetry, only enabled when PERFSPECT_GAUDI_HLSMI_PATH is set + gaudiHlsmiPath := os.Getenv("PERFSPECT_GAUDI_HLSMI_PATH") // must be full path to hlsmi binary + if gaudiHlsmiPath != "" { + slog.Info("Gaudi telemetry enabled", slog.String("hlsmi_path", gaudiHlsmiPath)) + tableNames = append(tableNames, report.GaudiTelemetryTableName) + } // hidden feature - PDU telemetry, only enabled when four environment variables are set // PERFSPECT_PDU_HOST, PERFSPECT_PDU_USER, PERFSPECT_PDU_PASSWORD, PERFSPECT_PDU_OUTLET // pduHost := os.Getenv("PERFSPECT_PDU_HOST") @@ -317,6 +321,7 @@ func runCmd(cmd *cobra.Command, args []string) error { "Duration": strconv.Itoa(flagDuration), "InstrMixPID": strconv.Itoa(flagInstrMixPid), "InstrMixFrequency": strconv.Itoa(flagInstrMixFrequency), + "GaudiHlsmiPath": gaudiHlsmiPath, // "PDUHost": pduHost, // "PDUUser": pduUser, // "PDUPassword": pduPassword, diff --git a/internal/script/script_defs.go b/internal/script/script_defs.go index f7a055f3..6d2cb99a 100644 --- a/internal/script/script_defs.go +++ b/internal/script/script_defs.go @@ -1307,19 +1307,18 @@ wait GaudiTelemetryScriptName: { Name: GaudiTelemetryScriptName, ScriptTemplate: ` -# if the hl-smi program is in the path -if command -v hl-smi &> /dev/null; then - hl-smi --query-aip=timestamp,name,temperature.aip,module_id,utilization.aip,memory.total,memory.free,memory.used,power.draw --format=csv,nounits -l {{.Interval}} & - echo $! > {{.ScriptName}}_cmd.pid - # if duration is set, sleep for the duration then kill the process - if [ {{.Duration}} -ne 0 ]; then - sleep {{.Duration}} - kill -SIGINT $(cat {{.ScriptName}}_cmd.pid) - fi - wait +if command -v {{.GaudiHlsmiPath}} &> /dev/null; then + {{.GaudiHlsmiPath}} --query-aip=timestamp,name,temperature.aip,module_id,utilization.aip,memory.total,memory.free,memory.used,power.draw --format=csv,nounits -l {{.Interval}} & + echo $! > {{.ScriptName}}_cmd.pid + # if duration is set, sleep for the duration then kill the process + if [ {{.Duration}} -ne 0 ]; then + sleep {{.Duration}} + kill -SIGINT $(cat {{.ScriptName}}_cmd.pid) + fi + wait else - echo "hl-smi not found in the path" >&2 - exit 1 + echo "hl-smi not found at {{.GaudiHlsmiPath}}" >&2 + exit 1 fi `, Superuser: true, From bd91ec5c22504177d6bbe2956001a466453b8836 Mon Sep 17 00:00:00 2001 From: "Harper, Jason M" Date: Sun, 2 Nov 2025 05:53:10 -0800 Subject: [PATCH 05/10] skeleton for PDU temp Signed-off-by: Harper, Jason M --- cmd/telemetry/telemetry.go | 25 ++++++++++++------------- internal/report/render_html.go | 17 +++++++++++++++++ internal/report/table_defs.go | 15 +++++++++++++++ internal/script/script_defs.go | 7 +++++++ 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/cmd/telemetry/telemetry.go b/cmd/telemetry/telemetry.go index 7fb98d94..39955a04 100644 --- a/cmd/telemetry/telemetry.go +++ b/cmd/telemetry/telemetry.go @@ -294,15 +294,14 @@ func runCmd(cmd *cobra.Command, args []string) error { tableNames = append(tableNames, report.GaudiTelemetryTableName) } // hidden feature - PDU telemetry, only enabled when four environment variables are set - // PERFSPECT_PDU_HOST, PERFSPECT_PDU_USER, PERFSPECT_PDU_PASSWORD, PERFSPECT_PDU_OUTLET - // pduHost := os.Getenv("PERFSPECT_PDU_HOST") - // pduUser := os.Getenv("PERFSPECT_PDU_USER") - // pduPassword := os.Getenv("PERFSPECT_PDU_PASSWORD") - // pduOutlet := os.Getenv("PERFSPECT_PDU_OUTLET") - // if pduHost != "" && pduUser != "" && pduPassword != "" && pduOutlet != "" { - // slog.Info("PDU telemetry enabled", slog.String("host", pduHost), slog.String("outlet", pduOutlet)) - // tableNames = append(tableNames, report.PDUTelemetryTableName) - // } + pduHost := os.Getenv("PERFSPECT_PDU_HOST") + pduUser := os.Getenv("PERFSPECT_PDU_USER") + pduPassword := os.Getenv("PERFSPECT_PDU_PASSWORD") + pduOutlet := os.Getenv("PERFSPECT_PDU_OUTLET") + if pduHost != "" && pduUser != "" && pduPassword != "" && pduOutlet != "" { + slog.Info("PDU telemetry enabled", slog.String("host", pduHost), slog.String("outlet", pduOutlet)) + tableNames = append(tableNames, report.PDUTelemetryTableName) + } // include telemetry summary table if all telemetry options are selected var summaryFunc common.SummaryFunc if flagAll { @@ -322,10 +321,10 @@ func runCmd(cmd *cobra.Command, args []string) error { "InstrMixPID": strconv.Itoa(flagInstrMixPid), "InstrMixFrequency": strconv.Itoa(flagInstrMixFrequency), "GaudiHlsmiPath": gaudiHlsmiPath, - // "PDUHost": pduHost, - // "PDUUser": pduUser, - // "PDUPassword": pduPassword, - // "PDUOutlet": pduOutlet, + "PDUHost": pduHost, + "PDUUser": pduUser, + "PDUPassword": pduPassword, + "PDUOutlet": pduOutlet, }, TableNames: tableNames, SummaryFunc: summaryFunc, diff --git a/internal/report/render_html.go b/internal/report/render_html.go index cb9f2893..6ea104b1 100644 --- a/internal/report/render_html.go +++ b/internal/report/render_html.go @@ -1511,6 +1511,23 @@ func gaudiTelemetryTableHTMLRenderer(tableValues TableValues, targetName string) return out } +func pduTelemetryTableHTMLRenderer(tableValues TableValues, targetName string) string { + data := [][]float64{} + datasetNames := []string{} + chartConfig := chartTemplateStruct{ + ID: fmt.Sprintf("%s%d", tableValues.Name, util.RandUint(10000)), + XaxisText: "Time", + YaxisText: "Value", + TitleText: "", + DisplayTitle: "false", + DisplayLegend: "true", + AspectRatio: "2", + SuggestedMin: "0", + SuggestedMax: "0", + } + return telemetryTableHTMLRenderer(tableValues, data, datasetNames, chartConfig) +} + func callStackFrequencyTableHTMLRenderer(tableValues TableValues, targetName string) string { out := `