"A little copying is better than a little dependency."
var kyu = func() struct {
Start func(string) func()
Print func()
} {
m := make(map[string]time.Duration)
var mu sync.Mutex
Start := func(l string) (stop func()) {
start := time.Now()
called := false
return func() {
elapsed := time.Since(start)
mu.Lock()
if !called {
m[l] += elapsed
called = true
}
mu.Unlock()
}
}
Print := func() {
mu.Lock()
defer mu.Unlock()
var buf []byte
for l, d := range m {
buf = fmt.Appendf(buf, "kyu: %v: %v\n", l, d)
}
fmt.Print(string(buf))
}
return struct {
Start func(string) func()
Print func()
}{Start, Print}
}()
kyu
provides barebones span-based profiling. I use it frequently to answer simple questions like "where is this function spending most of its time?" without the hassle and noise of a full trace or CPU profile.
This is not a module. It is a single self-contained Go declaration that you can paste into any file; most modern editors will automatically add the requisite imports on save. No versioning, no go get
, no changes to your go.mod
or go.sum
, just good old copy-and-paste. You can even create a keybinding in your editor to paste it with one key chord!
Example usage:
func someFunction() {
defer kyu.Start("someFunction")()
for _, f := range foos {
endFoo := kyu.Start("foo")
processFoo(f)
endFoo()
}
endBars := kyu.Start("bars")
defer endBars() // guard against early return; first call wins
for _, b := range bars {
if !processBar(b) {
return
}
}
endBars()
defer kyu.Start("baz")()
processBaz(baz)
}
func main() {
someFunction()
kyu.Print()
}
Example output:
kyu: someFunction: 100ms
kyu: foo: 23ms
kyu: bars: 75ms
kyu: baz: 2ms
License: 0BSD