-
Notifications
You must be signed in to change notification settings - Fork 261
Expand file tree
/
Copy pathresult.go
More file actions
147 lines (123 loc) · 4.11 KB
/
result.go
File metadata and controls
147 lines (123 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//go:build evm
package benchmark
import (
"fmt"
"sort"
"testing"
"time"
e2e "github.com/evstack/ev-node/test/e2e"
)
// traceResult holds the collected spans from ev-node and (optionally) ev-reth.
type traceResult struct {
evNode []e2e.TraceSpan
evReth []e2e.TraceSpan
// rich spans include parent-child hierarchy for flowchart rendering.
// empty when the trace provider doesn't support rich span collection.
evNodeRich []richSpan
evRethRich []richSpan
// resource attributes extracted from trace spans (OTEL_RESOURCE_ATTRIBUTES).
evNodeAttrs *resourceAttrs
evRethAttrs *resourceAttrs
}
// displayFlowcharts renders ASCII flowcharts from rich spans. Falls back to
// flat trace reports when rich spans are not available.
func (tr *traceResult) displayFlowcharts(t testing.TB, serviceName string) {
if len(tr.evNodeRich) > 0 {
printFlowcharts(t, tr.evNodeRich)
printAggregateFlowcharts(t, tr.evNodeRich)
} else {
e2e.PrintTraceReport(t, serviceName, tr.evNode)
}
if len(tr.evRethRich) > 0 {
t.Logf("ev-reth: collected %d rich spans", len(tr.evRethRich))
printAggregateFlowcharts(t, tr.evRethRich)
} else if len(tr.evReth) > 0 {
e2e.PrintTraceReport(t, "ev-reth", tr.evReth)
}
}
// allSpans returns ev-node and ev-reth spans concatenated into a new slice.
func (tr *traceResult) allSpans() []e2e.TraceSpan {
out := make([]e2e.TraceSpan, 0, len(tr.evNode)+len(tr.evReth))
out = append(out, tr.evNode...)
out = append(out, tr.evReth...)
return out
}
// benchmarkResult collects all metrics from a single benchmark run and
// produces the final set of entries for the result writer.
type benchmarkResult struct {
prefix string
bm *blockMetrics
summary *blockMetricsSummary
traces *traceResult
}
func newBenchmarkResult(prefix string, bm *blockMetrics, traces *traceResult) *benchmarkResult {
return &benchmarkResult{
prefix: prefix,
bm: bm,
summary: bm.summarize(),
traces: traces,
}
}
// log prints all key benchmark metrics to the test log.
func (r *benchmarkResult) log(t testing.TB, wallClock time.Duration) {
r.summary.log(t, r.bm.StartBlock, r.bm.EndBlock, r.bm.TotalBlockCount, r.bm.BlockCount, wallClock)
if overhead, ok := evNodeOverhead(r.traces.evNode); ok {
t.Logf("ev-node overhead: %.1f%%", overhead)
}
if ggas, ok := rethExecutionRate(r.traces.evNode, r.bm.TotalGasUsed); ok {
t.Logf("ev-reth execution rate: %.3f GGas/s", ggas)
}
if stats := e2e.AggregateSpanStats(r.traces.evNode); stats != nil {
if pb, ok := stats[spanProduceBlock]; ok && pb.Count > 0 {
avg := pb.Total / time.Duration(pb.Count)
t.Logf("ProduceBlock avg: %dms", avg.Milliseconds())
}
}
if r.summary.AchievedMGas > 0 {
t.Logf("seconds_per_gigagas: %.4f", 1000.0/r.summary.AchievedMGas)
}
}
// entries returns all benchmark metrics as result writer entries.
func (r *benchmarkResult) entries() []entry {
var out []entry
out = append(out, r.summary.entries(r.prefix)...)
if overhead, ok := evNodeOverhead(r.traces.evNode); ok {
out = append(out, entry{Name: r.prefix + " - ev-node overhead", Unit: "%", Value: overhead})
}
if ggas, ok := rethExecutionRate(r.traces.evNode, r.bm.TotalGasUsed); ok {
out = append(out, entry{Name: r.prefix + " - ev-reth GGas/s", Unit: "GGas/s", Value: ggas})
}
out = append(out, engineSpanEntries(r.prefix, r.traces.evNode)...)
if r.summary.AchievedMGas > 0 {
out = append(out, entry{
Name: r.prefix + " - seconds_per_gigagas",
Unit: "s/Ggas",
Value: 1000.0 / r.summary.AchievedMGas,
})
}
out = append(out, spanAvgEntries(r.prefix, r.traces.allSpans())...)
return out
}
// spanAvgEntries aggregates trace spans into per-operation avg duration entries.
func spanAvgEntries(prefix string, spans []e2e.TraceSpan) []entry {
m := e2e.AggregateSpanStats(spans)
if len(m) == 0 {
return nil
}
names := make([]string, 0, len(m))
for name := range m {
names = append(names, name)
}
sort.Strings(names)
var out []entry
for _, name := range names {
s := m[name]
avg := float64(s.Total.Microseconds()) / float64(s.Count)
out = append(out, entry{
Name: fmt.Sprintf("%s - %s (avg)", prefix, name),
Unit: "us",
Value: avg,
})
}
return out
}