Include terminal charts in benchmark report
This commit is contained in:
@@ -243,7 +243,7 @@ func (s *System) RunNvidiaBenchmark(ctx context.Context, baseDir string, opts Nv
|
|||||||
return "", fmt.Errorf("write result.json: %w", err)
|
return "", fmt.Errorf("write result.json: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
report := renderBenchmarkReport(result)
|
report := renderBenchmarkReportWithCharts(result, loadBenchmarkReportCharts(runDir, selected))
|
||||||
if err := os.WriteFile(filepath.Join(runDir, "report.txt"), []byte(report), 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(runDir, "report.txt"), []byte(report), 0644); err != nil {
|
||||||
return "", fmt.Errorf("write report.txt: %w", err)
|
return "", fmt.Errorf("write report.txt: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,25 @@ package platform
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func renderBenchmarkReport(result NvidiaBenchmarkResult) string {
|
func renderBenchmarkReport(result NvidiaBenchmarkResult) string {
|
||||||
|
return renderBenchmarkReportWithCharts(result, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type benchmarkReportChart struct {
|
||||||
|
Title string
|
||||||
|
Content string
|
||||||
|
}
|
||||||
|
|
||||||
|
var ansiEscapePattern = regexp.MustCompile(`\x1b\[[0-9;]*m`)
|
||||||
|
|
||||||
|
func renderBenchmarkReportWithCharts(result NvidiaBenchmarkResult, charts []benchmarkReportChart) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
fmt.Fprintf(&b, "Bee NVIDIA Benchmark Report\n")
|
fmt.Fprintf(&b, "Bee NVIDIA Benchmark Report\n")
|
||||||
fmt.Fprintf(&b, "===========================\n\n")
|
fmt.Fprintf(&b, "===========================\n\n")
|
||||||
@@ -93,6 +107,20 @@ func renderBenchmarkReport(result NvidiaBenchmarkResult) string {
|
|||||||
b.WriteString("\n")
|
b.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(charts) > 0 {
|
||||||
|
fmt.Fprintf(&b, "Terminal Charts\n")
|
||||||
|
fmt.Fprintf(&b, "---------------\n")
|
||||||
|
for _, chart := range charts {
|
||||||
|
content := strings.TrimSpace(stripANSIEscapeSequences(chart.Content))
|
||||||
|
if content == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, "%s\n", chart.Title)
|
||||||
|
fmt.Fprintf(&b, "%s\n", strings.Repeat("~", len(chart.Title)))
|
||||||
|
fmt.Fprintf(&b, "%s\n\n", content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Fprintf(&b, "Methodology\n")
|
fmt.Fprintf(&b, "Methodology\n")
|
||||||
fmt.Fprintf(&b, "-----------\n")
|
fmt.Fprintf(&b, "-----------\n")
|
||||||
fmt.Fprintf(&b, "- Profile %s uses standardized baseline, warmup, steady-state, interconnect, and cooldown phases.\n", result.BenchmarkProfile)
|
fmt.Fprintf(&b, "- Profile %s uses standardized baseline, warmup, steady-state, interconnect, and cooldown phases.\n", result.BenchmarkProfile)
|
||||||
@@ -117,6 +145,36 @@ func renderBenchmarkReport(result NvidiaBenchmarkResult) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadBenchmarkReportCharts(runDir string, gpuIndices []int) []benchmarkReportChart {
|
||||||
|
phases := []struct {
|
||||||
|
name string
|
||||||
|
label string
|
||||||
|
}{
|
||||||
|
{name: "baseline", label: "Baseline"},
|
||||||
|
{name: "steady", label: "Steady State"},
|
||||||
|
{name: "cooldown", label: "Cooldown"},
|
||||||
|
}
|
||||||
|
var charts []benchmarkReportChart
|
||||||
|
for _, idx := range gpuIndices {
|
||||||
|
for _, phase := range phases {
|
||||||
|
path := filepath.Join(runDir, fmt.Sprintf("gpu-%d-%s-metrics-term.txt", idx, phase.name))
|
||||||
|
raw, err := os.ReadFile(path)
|
||||||
|
if err != nil || len(raw) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
charts = append(charts, benchmarkReportChart{
|
||||||
|
Title: fmt.Sprintf("GPU %d %s", idx, phase.label),
|
||||||
|
Content: string(raw),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return charts
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripANSIEscapeSequences(raw string) string {
|
||||||
|
return ansiEscapePattern.ReplaceAllString(raw, "")
|
||||||
|
}
|
||||||
|
|
||||||
func renderBenchmarkSummary(result NvidiaBenchmarkResult) string {
|
func renderBenchmarkSummary(result NvidiaBenchmarkResult) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
fmt.Fprintf(&b, "run_at_utc=%s\n", result.GeneratedAt.Format(time.RFC3339))
|
fmt.Fprintf(&b, "run_at_utc=%s\n", result.GeneratedAt.Format(time.RFC3339))
|
||||||
|
|||||||
@@ -145,3 +145,35 @@ func TestRenderBenchmarkReportIncludesFindingsAndScores(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenderBenchmarkReportIncludesTerminalChartsWithoutANSI(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
report := renderBenchmarkReportWithCharts(NvidiaBenchmarkResult{
|
||||||
|
BenchmarkProfile: NvidiaBenchmarkProfileStandard,
|
||||||
|
OverallStatus: "OK",
|
||||||
|
SelectedGPUIndices: []int{0},
|
||||||
|
Normalization: BenchmarkNormalization{
|
||||||
|
Status: "full",
|
||||||
|
},
|
||||||
|
}, []benchmarkReportChart{
|
||||||
|
{
|
||||||
|
Title: "GPU 0 Steady State",
|
||||||
|
Content: "\x1b[31mGPU 0 chart\x1b[0m\n 42┤───",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, needle := range []string{
|
||||||
|
"Terminal Charts",
|
||||||
|
"GPU 0 Steady State",
|
||||||
|
"GPU 0 chart",
|
||||||
|
"42┤───",
|
||||||
|
} {
|
||||||
|
if !strings.Contains(report, needle) {
|
||||||
|
t.Fatalf("report missing %q\n%s", needle, report)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(report, "\x1b[31m") {
|
||||||
|
t.Fatalf("report should not contain ANSI escapes\n%s", report)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user