-
Notifications
You must be signed in to change notification settings - Fork 3
feat(stats): state both goodput ratios, per run and per operation #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: brandon2/plt-1078-outcome-report
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,11 @@ type OperationReport struct { | |
| LatencyP99 time.Duration `json:"latency_p99_ns"` | ||
| SampleCount int `json:"sample_count"` | ||
| Window time.Duration `json:"window_ns"` | ||
| // Outcomes is this operation's share of the run's ledger. The run-level | ||
| // totals cannot separate a revert rate spread evenly across operations from | ||
| // one concentrated in a single call, and those are different findings: the | ||
| // first points at the chain, the second at the workload. | ||
| Outcomes ExecutionOutcomes `json:"outcomes"` | ||
| } | ||
|
|
||
| // LoadTestStatistics represents basic load test metrics | ||
|
|
@@ -110,6 +115,15 @@ func (fs *FinalStats) String() string { | |
| op.LatencyP99.Round(time.Millisecond), | ||
| op.SampleCount, op.Successes, | ||
| op.Window.Round(time.Millisecond)) | ||
| // A second line rather than a wider first one. The line above is at | ||
| // its readable limit, and anything parsing it keeps working. | ||
| if op.Outcomes.Tracked { | ||
| result += fmt.Sprintf( | ||
| " outcomes: committed=%d reverted=%d expired=%d unobserved=%d | goodput %.2f%% offered, %.2f%% accepted\n", | ||
|
seidroid[bot] marked this conversation as resolved.
seidroid[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [suggestion] Still open from the previous review — no changes have landed since. The per-operation line prints four of the seven outcome counts, and the three it drops are the ones that would explain a zero. Every visible count is zero and goodput is zero, which reads as a chain that committed nothing — the exact false accusation the run-level report is careful to avoid, and which Adding |
||
| op.Outcomes.Committed, op.Outcomes.Reverted, op.Outcomes.Expired, | ||
| op.Outcomes.StatusUnavailable, | ||
| op.Outcomes.GoodputOfAttempted()*100, op.Outcomes.GoodputOfAccepted()*100) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -200,6 +214,11 @@ func (l *Logger) BuildFinalStats( | |
| scenarioDistribution[scenario] = count | ||
| } | ||
|
|
||
| // Read before the loop below: every per-operation ledger carries it, and a | ||
| // report whose operations disagree with its totals about whether the run | ||
| // measured anything is worse than one that reports nothing. | ||
| incl, tracked := inclusion.Get() | ||
|
|
||
| // Sorted by scenario then operation: Go map iteration order is unspecified, and | ||
| // a report whose lines move cannot be compared against another run. | ||
| operations := l.collector.GetOperationStats() | ||
|
|
@@ -215,6 +234,19 @@ func (l *Logger) BuildFinalStats( | |
| LatencyP99: op.P99Latency, | ||
| SampleCount: op.SampleCount, | ||
| Window: op.Window, | ||
| Outcomes: ExecutionOutcomes{ | ||
|
seidroid[bot] marked this conversation as resolved.
seidroid[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [suggestion] Still open from the previous review — no test reaches this wiring.
That is the half of the PR the user story is about ("per operation, because the total cannot tell you where"), and this mapping is exactly the kind that fails silently: a transposed |
||
| Tracked: tracked, | ||
| Attempted: op.Count, | ||
| Accepted: op.Successes, | ||
| Committed: op.Committed, | ||
| Reverted: op.Reverted, | ||
| Expired: op.Expired, | ||
| DroppedAtCap: op.DroppedAtCap, | ||
| DroppedAtHandoff: op.DroppedAtHandoff, | ||
| StatusUnavailable: op.StatusUnavailable, | ||
| Unrecorded: op.Unrecorded, | ||
| ReapAfter: reapAfter, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
|
|
@@ -260,6 +292,7 @@ func (l *Logger) BuildFinalStats( | |
| // feature removes; only InflightAtShutdown is the tracker's alone. | ||
| execution := ExecutionOutcomes{ReapAfter: reapAfter} | ||
| for _, op := range operations { | ||
| execution.Attempted += op.Count | ||
| execution.Accepted += op.Successes | ||
| execution.Committed += op.Committed | ||
| execution.Reverted += op.Reverted | ||
|
|
@@ -269,7 +302,7 @@ func (l *Logger) BuildFinalStats( | |
| execution.StatusUnavailable += op.StatusUnavailable | ||
| execution.Unrecorded += op.Unrecorded | ||
| } | ||
| if incl, ok := inclusion.Get(); ok { | ||
| if tracked { | ||
| execution.Tracked = true | ||
| execution.InflightAtShutdown = incl.InflightAtShutdown | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] This claim is false in general, and the same claim is repeated at
stats/execution_outcomes.go:197-198and in the PR description.The gap between the two ratios is
not
Rejected/Attempted. The two coincide only whenCommitted == Accepted, which is exactly the caseTestBothRatiosAreStatedpicks (Attempted: 200, Accepted: 100, Committed: 100→ gap 50%, rejection share 50%), so the test confirms the wrong invariant rather than catching it.The PR body's own example disproves it: offered 200, accepted 190, goodput 44.00% / 46.32% → gap 2.32%, rejection share 10/200 = 5%.
What actually holds is multiplicative:
GoodputOfAttempted = GoodputOfAccepted × (Accepted/Attempted), i.e. the ratio of the two ratios is the acceptance rate. Since these comments are how a reader is told to interpret the report, either state the multiplicative relation or drop the "exactly its share" wording and letrejected %dspeak for itself.