mirror of
https://github.com/Crocmagnon/fat-contexts-article-companion.git
synced 2024-12-22 06:11:48 +01:00
initial commit
This commit is contained in:
commit
4230659178
7 changed files with 226 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
data
|
||||||
|
plot.html
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# fat contexts
|
||||||
|
|
||||||
|
This repo holds code for [On context-induced performance bottleneck in Go](https://gabnotes.org/fat-contexts/).
|
||||||
|
|
||||||
|
Reproduce my results:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ go test -bench=.
|
||||||
|
goos: darwin
|
||||||
|
goarch: arm64
|
||||||
|
pkg: trash
|
||||||
|
BenchmarkContext/shadow_1000-8 19352 61271 ns/op
|
||||||
|
BenchmarkContext/fat_1000-8 532 2187010 ns/op
|
||||||
|
BenchmarkContext/shadow_10000-8 1903 639371 ns/op
|
||||||
|
BenchmarkContext/fat_10000-8 5 219400100 ns/op
|
||||||
|
BenchmarkContext/shadow_100000-8 194 6374344 ns/op
|
||||||
|
BenchmarkContext/fat_100000-8 1 21851940167 ns/op
|
||||||
|
PASS
|
||||||
|
ok trash 30.801s
|
||||||
|
$ go run ./generate/main.go > data
|
||||||
|
$ go run ./plot/main.go
|
||||||
|
$ open plot.html
|
||||||
|
```
|
||||||
|
|
||||||
|
Sorry there are a lot of hardcoded file names in here, but since I don't intend on reusing this code I won't fix it.
|
51
bench_test.go
Normal file
51
bench_test.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package main_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand/v2"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const key = "key"
|
||||||
|
|
||||||
|
func BenchmarkContext(b *testing.B) {
|
||||||
|
benchmarks := []struct {
|
||||||
|
times uint64
|
||||||
|
}{
|
||||||
|
{1_000},
|
||||||
|
{10_000},
|
||||||
|
{100_000},
|
||||||
|
}
|
||||||
|
for _, bm := range benchmarks {
|
||||||
|
ctx := context.WithValue(context.Background(), key, "some value")
|
||||||
|
b.Run(fmt.Sprintf("shadow %v", bm.times), func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
shadow(ctx, bm.times)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run(fmt.Sprintf("fat %v", bm.times), func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
fat(ctx, bm.times)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadow(ctx context.Context, times uint64) {
|
||||||
|
for range times {
|
||||||
|
ctx := contextWithRandom(ctx)
|
||||||
|
_ = ctx.Value(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fat(ctx context.Context, times uint64) {
|
||||||
|
for range times {
|
||||||
|
ctx = contextWithRandom(ctx)
|
||||||
|
_ = ctx.Value(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextWithRandom(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, "other_key", rand.Int64())
|
||||||
|
}
|
50
generate/main.go
Normal file
50
generate/main.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofrs/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const key = "key"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const times = 10_000
|
||||||
|
|
||||||
|
// Setup the value we want to retrieve in each iteration
|
||||||
|
ctx := context.WithValue(context.Background(), key, "some-val")
|
||||||
|
|
||||||
|
fat(ctx, times)
|
||||||
|
shadow(ctx, times)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fat(ctx context.Context, times uint64) {
|
||||||
|
for range times {
|
||||||
|
// wrap the context, each iteration makes it bigger
|
||||||
|
ctx = contextWithRandom(ctx)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
// simulate the logging lib which retrieves context values
|
||||||
|
_ = ctx.Value(key)
|
||||||
|
|
||||||
|
fmt.Printf("fat,%v\n", time.Since(start).Nanoseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadow(ctx context.Context, times uint64) {
|
||||||
|
for range times {
|
||||||
|
// shadow the context, each iteration creates a new one and it doesn't grow
|
||||||
|
ctx := contextWithRandom(ctx)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
_ = ctx.Value(key)
|
||||||
|
|
||||||
|
fmt.Printf("shadow,%v\n", time.Since(start).Nanoseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextWithRandom(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, "other_key", uuid.Must(uuid.NewV4()))
|
||||||
|
}
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module trash
|
||||||
|
|
||||||
|
go 1.22.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-echarts/go-echarts/v2 v2.3.3
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible
|
||||||
|
)
|
12
go.sum
Normal file
12
go.sum
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-echarts/go-echarts/v2 v2.3.3 h1:uImZAk6qLkC6F9ju6mZ5SPBqTyK8xjZKwSmwnCg4bxg=
|
||||||
|
github.com/go-echarts/go-echarts/v2 v2.3.3/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
|
||||||
|
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
77
plot/main.go
Normal file
77
plot/main.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"github.com/go-echarts/go-echarts/v2/charts"
|
||||||
|
"github.com/go-echarts/go-echarts/v2/opts"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
shadow, fat := getData()
|
||||||
|
plot := charts.NewLine()
|
||||||
|
xAxis := make([]int, len(shadow))
|
||||||
|
for i := range xAxis {
|
||||||
|
xAxis[i] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
plot.SetGlobalOptions(
|
||||||
|
charts.WithXAxisOpts(opts.XAxis{Name: "loop count"}),
|
||||||
|
charts.WithYAxisOpts(opts.YAxis{Name: "Nanosecond"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
plot.
|
||||||
|
SetXAxis(xAxis).
|
||||||
|
AddSeries("Shadow", shadow).
|
||||||
|
AddSeries("Fat", fat)
|
||||||
|
|
||||||
|
f, err := os.Create("plot.html")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = plot.Render(f)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getData() ([]opts.LineData, []opts.LineData) {
|
||||||
|
var shadow []opts.LineData
|
||||||
|
var fat []opts.LineData
|
||||||
|
|
||||||
|
f, err := os.Open("data")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
for {
|
||||||
|
record, err := r.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
series := record[0]
|
||||||
|
val, err := strconv.ParseUint(record[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
point := opts.LineData{Value: val, Name: "ns"}
|
||||||
|
|
||||||
|
switch series {
|
||||||
|
case "shadow":
|
||||||
|
shadow = append(shadow, point)
|
||||||
|
case "fat":
|
||||||
|
fat = append(fat, point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow, fat
|
||||||
|
}
|
Loading…
Reference in a new issue