-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Marc M. Adkins
committed
Aug 20, 2024
1 parent
01ab17e
commit 8112f4d
Showing
9 changed files
with
426 additions
and
358 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package bench | ||
|
||
import "github.com/madkins23/go-slog/internal/scoring/score" | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
type Average struct { | ||
Value score.Value | ||
Count uint | ||
} | ||
|
||
func (ba *Average) Add(v score.Value) *Average { | ||
ba.Value += v | ||
ba.Count++ | ||
return ba | ||
} | ||
|
||
func (ba *Average) AddMultiple(v score.Value, multiple uint) *Average { | ||
ba.Value += v * score.Value(multiple) | ||
ba.Count += multiple | ||
return ba | ||
} | ||
|
||
func (ba *Average) Average() score.Value { | ||
return ba.Value.Round() / score.Value(ba.Count) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package bench | ||
|
||
import ( | ||
"github.com/madkins23/go-slog/internal/data" | ||
"github.com/madkins23/go-slog/internal/scoring/score" | ||
) | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
type RollOver uint8 | ||
|
||
const ( | ||
OverData = iota | ||
OverTests | ||
) | ||
|
||
type HandlerData struct { | ||
byTest map[data.TestTag]*Average | ||
originalScore score.Value | ||
scores map[score.Type]score.Value | ||
subScore map[Weight]*Average | ||
rollup map[RollOver]*Average | ||
} | ||
|
||
func NewHandlerData() *HandlerData { | ||
hd := &HandlerData{ | ||
byTest: make(map[data.TestTag]*Average), | ||
scores: make(map[score.Type]score.Value), | ||
subScore: make(map[Weight]*Average), | ||
rollup: make(map[RollOver]*Average), | ||
} | ||
for _, weight := range WeightOrder { | ||
hd.subScore[weight] = &Average{} | ||
} | ||
return hd | ||
} | ||
|
||
func (hd *HandlerData) ByTest(test data.TestTag) *Average { | ||
if hd.byTest[test] == nil { | ||
hd.byTest[test] = &Average{} | ||
} | ||
return hd.byTest[test] | ||
} | ||
|
||
func (hd *HandlerData) Rollup(over RollOver) *Average { | ||
if hd.rollup[over] == nil { | ||
hd.rollup[over] = &Average{} | ||
} | ||
return hd.rollup[over] | ||
} | ||
|
||
func (hd *HandlerData) Score(scoreType score.Type) score.Value { | ||
return hd.scores[scoreType] | ||
} | ||
|
||
func (hd *HandlerData) SetScore(scoreType score.Type, value score.Value) { | ||
hd.scores[scoreType] = value | ||
} | ||
|
||
func (hd *HandlerData) SubScore(weight Weight) *Average { | ||
if hd.subScore[weight] == nil { | ||
hd.subScore[weight] = &Average{} | ||
} | ||
return hd.subScore[weight] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package bench | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
"github.com/madkins23/go-slog/internal/scoring/score" | ||
) | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
type Range interface { | ||
AddValueUint64(val uint64) | ||
AddValueFloat64(val float64) | ||
Length() float64 | ||
RangedValue(from float64) score.Value | ||
String() string | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
var _ Range = &RangeFloat64{} | ||
|
||
type RangeFloat64 struct { | ||
low, high float64 | ||
} | ||
|
||
func NewRangeFloat64() *RangeFloat64 { | ||
return &RangeFloat64{ | ||
low: math.MaxFloat64, | ||
high: 0.0, | ||
} | ||
} | ||
|
||
func (r *RangeFloat64) AddValueUint64(val uint64) { | ||
r.AddValueFloat64(float64(val)) | ||
} | ||
|
||
func (r *RangeFloat64) AddValueFloat64(val float64) { | ||
if val < r.low { | ||
r.low = val | ||
} | ||
if val > r.high { | ||
r.high = val | ||
} | ||
} | ||
|
||
func (r *RangeFloat64) Length() float64 { | ||
return r.high - r.low | ||
} | ||
|
||
func (r *RangeFloat64) RangedValue(from float64) score.Value { | ||
return score.Value(100.0 * (r.high - from) / r.Length()) | ||
} | ||
|
||
func (r *RangeFloat64) String() string { | ||
return fmt.Sprintf("%0.2f -> %0.2f", r.low, r.high) | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
var _ Range = &RangeUint64{} | ||
|
||
type RangeUint64 struct { | ||
low, high uint64 | ||
} | ||
|
||
func NewRangeUint64() *RangeUint64 { | ||
return &RangeUint64{ | ||
low: math.MaxUint64, | ||
high: 0, | ||
} | ||
} | ||
|
||
func (r *RangeUint64) AddValueFloat64(val float64) { | ||
r.AddValueUint64(uint64(val)) | ||
} | ||
|
||
func (r *RangeUint64) AddValueUint64(val uint64) { | ||
if val < r.low { | ||
r.low = val | ||
} | ||
if val > r.high { | ||
r.high = val | ||
} | ||
} | ||
|
||
func (r *RangeUint64) Length() float64 { | ||
return float64(r.high - r.low) | ||
} | ||
|
||
func (r *RangeUint64) RangedValue(from float64) score.Value { | ||
return score.Value(100.0 * (float64(r.high) - from) / r.Length()) | ||
} | ||
|
||
func (r *RangeUint64) String() string { | ||
return fmt.Sprintf("%0d -> %0d", r.low, r.high) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package bench | ||
|
||
import ( | ||
"fmt" | ||
"log/slog" | ||
"math" | ||
|
||
"github.com/madkins23/go-slog/internal/data" | ||
"github.com/madkins23/go-slog/internal/scoring/score" | ||
) | ||
|
||
type testRange struct { | ||
allocLow, allocHigh uint64 | ||
bytesLow, bytesHigh uint64 | ||
nanosLow, nanosHigh float64 | ||
} | ||
|
||
func (tr *testRange) String(bv Weight) string { | ||
switch bv { | ||
case Allocations: | ||
return fmt.Sprintf("%0d -> %0d", tr.allocLow, tr.allocHigh) | ||
case AllocBytes: | ||
return fmt.Sprintf("%0d -> %0d", tr.bytesLow, tr.bytesHigh) | ||
case Nanoseconds: | ||
return fmt.Sprintf("%0.2f -> %0.2f", tr.nanosLow, tr.nanosHigh) | ||
default: | ||
return "<unknown:" + string(bv) + ">" | ||
} | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
type Original struct { | ||
bench *data.Benchmarks | ||
count, tests uint | ||
collect, total score.Value | ||
ranges map[data.TestTag]*testRange | ||
testTags map[data.TestTag]bool | ||
weight map[Weight]uint | ||
} | ||
|
||
func NewOriginal(bench *data.Benchmarks, tagMap map[data.TestTag]bool, weights map[Weight]uint) *Original { | ||
return &Original{ | ||
bench: bench, | ||
ranges: make(map[data.TestTag]*testRange), | ||
testTags: tagMap, | ||
weight: weights, | ||
} | ||
} | ||
|
||
func (o *Original) HandlerTest(test data.TestTag, record data.TestRecord) { | ||
o.collect = 0 | ||
o.count = 0 | ||
rngTest := o.ranges[test] | ||
if scoreRange := float64(rngTest.allocHigh - rngTest.allocLow); scoreRange > 0 { | ||
o.collect += score.Value(float64(o.weight[Allocations]) * 100.0 * float64(rngTest.allocHigh-record.MemAllocsPerOp) / scoreRange) | ||
o.count += o.weight[Allocations] | ||
} | ||
if scoreRange := float64(rngTest.bytesHigh - rngTest.bytesLow); scoreRange > 0 { | ||
o.collect += score.Value(float64(o.weight[AllocBytes]) * 100.0 * float64(rngTest.bytesHigh-record.MemBytesPerOp) / scoreRange) | ||
o.count += o.weight[AllocBytes] | ||
} | ||
if scoreRange := rngTest.nanosHigh - rngTest.nanosLow; scoreRange > 0 { | ||
o.collect += score.Value(float64(o.weight[Nanoseconds]) * 100.0 * (rngTest.nanosHigh - record.NanosPerOp) / scoreRange) | ||
o.count += o.weight[Nanoseconds] | ||
} | ||
o.total += o.collect / score.Value(o.count) | ||
o.tests++ | ||
} | ||
|
||
func (o *Original) CheckRanges(ranges map[data.TestTag]map[Weight]Range) { | ||
for test := range ranges { | ||
if o.testTags[test] { | ||
for _, weight := range WeightOrder { | ||
original := o.ranges[test].String(weight) | ||
byOthers := ranges[test][weight].String() | ||
if byOthers != original { | ||
slog.Error("range comparison", "weight", weight, | ||
"Original", original, | ||
"ByOthers", byOthers) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (o *Original) CheckTest(handlerData *HandlerData, test data.TestTag) { | ||
if !fuzzyEqual(o.collect, handlerData.byTest[test].Value) { | ||
slog.Error("collect comparison", "Original", o.collect, "by Test", handlerData.byTest[test].Value) | ||
} | ||
if o.count != handlerData.byTest[test].Count { | ||
slog.Error("count comparison", "Original", o.count, "by Test", handlerData.byTest[test].Count) | ||
} | ||
} | ||
|
||
func (o *Original) CheckTotal(handlerData *HandlerData) { | ||
if !fuzzyEqual(o.total.Round(), handlerData.Rollup(OverTests).Value) { | ||
slog.Error("total comparison", | ||
"Original", o.total.Round(), | ||
"by Test", handlerData.Rollup(OverTests).Value) | ||
} | ||
if o.tests != handlerData.Rollup(OverTests).Count { | ||
slog.Warn("count comparison", | ||
"Original", o.tests, | ||
"by Test", handlerData.Rollup(OverTests).Count) | ||
} | ||
} | ||
|
||
func (o *Original) MakeRanges() { | ||
for _, test := range o.bench.TestTags() { | ||
if o.testTags[test] { | ||
aRange := &testRange{ | ||
allocLow: math.MaxUint64, | ||
bytesLow: math.MaxUint64, | ||
nanosLow: math.MaxFloat64, | ||
} | ||
for _, records := range o.bench.HandlerRecordsFor(test) { | ||
if records.MemAllocsPerOp > aRange.allocHigh { | ||
aRange.allocHigh = records.MemAllocsPerOp | ||
} | ||
if records.MemAllocsPerOp < aRange.allocLow { | ||
aRange.allocLow = records.MemAllocsPerOp | ||
} | ||
if records.MemBytesPerOp > aRange.bytesHigh { | ||
aRange.bytesHigh = records.MemBytesPerOp | ||
} | ||
if records.MemBytesPerOp < aRange.bytesLow { | ||
aRange.bytesLow = records.MemBytesPerOp | ||
} | ||
if records.NanosPerOp > aRange.nanosHigh { | ||
aRange.nanosHigh = records.NanosPerOp | ||
} | ||
if records.NanosPerOp < aRange.nanosLow { | ||
aRange.nanosLow = records.NanosPerOp | ||
} | ||
} | ||
o.ranges[test] = aRange | ||
} | ||
} | ||
} | ||
|
||
func (o *Original) ResetForHandler() { | ||
o.tests = 0 | ||
o.total = 0 | ||
} | ||
|
||
func (o *Original) Score() score.Value { | ||
return o.total.Round() / score.Value(o.tests) | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
func fuzzyEqual(a, b score.Value) bool { | ||
const epsilon = 0.000000001 | ||
return math.Abs(float64(a-b)) < epsilon | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package bench | ||
|
||
import "github.com/madkins23/go-slog/internal/data" | ||
|
||
// ----------------------------------------------------------------------------- | ||
|
||
type Weight string | ||
|
||
const ( | ||
Allocations Weight = "Allocations" | ||
AllocBytes Weight = "Alloc Bytes" | ||
Nanoseconds Weight = "Nanoseconds" | ||
) | ||
|
||
var WeightOrder = []Weight{ | ||
Nanoseconds, | ||
AllocBytes, | ||
Allocations, | ||
} | ||
|
||
func (bw Weight) Item() data.BenchItems { | ||
switch bw { | ||
case Allocations: | ||
return data.MemAllocs | ||
case AllocBytes: | ||
return data.MemBytes | ||
case Nanoseconds: | ||
return data.Nanos | ||
default: | ||
return 0.0 | ||
} | ||
} |
Oops, something went wrong.