Documentation ¶
Overview ¶
Package binstat implements file based code statistics in bins.
Generate bin based statistics on code by wrapping it with binstat functions. Every wallclock second, binstat will output bins to a text file if changed.
API:
bs := binstat.Enter[Time][Val]("<What>"[,<Val>]) binstat.Leave[Val](bs, [<Val>])
Bin (single text line in output file depends on .Enter*()/.Leave*() combo) anatomy:
/GOMAXPROCS=8,CPUS=8/what[~4whatExampleOne]/size[<num>-<num>]/time[<num>-<num>]=<num> <num> ^^^^^ Total wallclock ^^^^^ Number of samples ^^^^^^^^^^^^^^^^^^ If .EnterTime*() used ^^^^^^^^^^^^^^^^^^ If <Val> given in .Enter*Val() or .LeaveVal() ^^^^^^^^^^^^^^^^^^^^^^^ <What> string from .Enter*() ^^^^^ default <What> length to include in bin unless BINSTAT_LEN_WHAT ^^^^^^^^^^^^^^^^^^^^ normally does not change
Size and time ranges are optional and auto generated from a single value or time. E.g. time 0.012345 will be transformed to the range 0.010000 to 0.019999. E.g. value 234 will be transformed to the range 200 to 299. Note: Value can be optionally given with .Enter*Val() or .Leave*Val() as appropriate.
Using different API combinations then a varity of bin formats are possible:
/GOMAXPROCS=8,CPUS=8/what[~7formata]=<num> <num> /GOMAXPROCS=8,CPUS=8/what[~7formatb]/size[<num>-<num>]=<num> <num> /GOMAXPROCS=8,CPUS=8/what[~7formatc]/time[<num>-<num>]=<num> <num> /GOMAXPROCS=8,CPUS=8/what[~7formatd]/size[<num>-<num>]/time[<num>-<num>]=<num> <num>
In this way, code can be called millions of times, but relatively few bins generated & updated.
The number of bins used at run-time & output can be modified at process start via env vars. E.g. By default binstat is disabled and binstat function will just return, using little CPU. E.g. BINSTAT_LEN_WHAT=~what=0 means disable this particular <What> stat. E.g. BINSTAT_LEN_WHAT=~what=99 means create a longer <What> (therefore more bins) for this particular <What> stat.
Note: binstat also outputs bins for its internal function statistics.
Please see API examples below.
Please see README for examples of commenting and uncommenting.
Please see test for example of binstat versus pprof.
Index ¶
Examples ¶
Constants ¶
const ( BinNet = "~3net" BinStdmap = "~6stdmap" BinMakeID = "~6MakeID" )
Variables ¶
This section is empty.
Functions ¶
func Debug ¶
Example ¶
.Debug() only used for debugging binstat
package main import ( "fmt" "github.com/onflow/flow-go/utils/binstat" ) func main() { bs := binstat.Enter("~7exampleDebug") // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.Debug(bs, "hello world") // only for binstat debbuging, and enabled if env var BINSTAT_VERBOSE set binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here // e.g. STDOUT: {"level":"debug","message":"2.918396 71372=pid 18143200=tid utils/binstat_test.ExampleBinStat_Debug:301() // enter in 0.000044 // what[~7exampleDebug] .NumCPU()=8 .GOMAXPROCS(0)=8 .NumGoroutine()=3"} // e.g. STDOUT: {"level":"debug","message":"2.918504 71372=pid 18143200=tid utils/binstat_test.ExampleBinStat_Debug:301() // debug hello world"} // e.g. STDOUT: {"level":"debug","message":"2.918523 71372=pid 18143200=tid utils/binstat_test.ExampleBinStat_Debug:301() // leave in 0.000168 // /GOMAXPROCS=8,CPUS=8/what[~7exampleDebug]=[47]=1 0.000053"} fmt.Printf("debug via STDOUT only") }
Output: debug via STDOUT only
func Dump ¶
func Dump(dmpNonDefaultName string)
Dump binstat text file. Normally called automatically once per second if bins have changed. Consider calling explicity before exiting process. Called explicity in tests so as not to wait one second.
func LeaveVal ¶
Example ¶
package main import ( "fmt" "os/exec" "github.com/onflow/flow-go/utils/binstat" ) func grepOutputFileAndSanatize(file string, what string) []byte { binstat.Dump(file) cmd := fmt.Sprintf("cat ./binstat.test.pid-*.binstat.txt%s | egrep '%s' | perl -lane 's~\\d[\\d\\.]*~<num>~g; print;'", file, what) out, err := exec.Command("bash", "-c", cmd).CombinedOutput() if err != nil { panic(err) } return out } func main() { bs := binstat.Enter("~7exampleLeaveVal") // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.LeaveVal(bs, 123) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here, (c) creates "/size[<num>-<num>]=<num>" bin section fmt.Printf("%s", grepOutputFileAndSanatize(".test-example-leave-val.txt", "exampleLeaveVal")) // force binstat output & grep & sanitize line; digits to <num> so example test passes }
Output: /GOMAXPROCS=<num>,CPUS=<num>/what[~<num>exampleLeaveVal]/size[<num>-<num>]=<num> <num> // e.g. utils/binstat_test.ExampleLeaveVal:<num>
Types ¶
type BinStat ¶
type BinStat struct {
// contains filtered or unexported fields
}
func DebugParams ¶
Example ¶
.DebugParams() only used for debugging binstat
package main import ( "fmt" "github.com/onflow/flow-go/utils/binstat" ) func main() { bs := binstat.Enter("~7exampleDebug") // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.DebugParams(bs, "foo=1") // only for debbuging, and enabled if env var BINSTAT_VERBOSE set; used to add string representing parameters to debug output binstat.Debug(bs, "hello world") // only for debbuging, and enabled if env var BINSTAT_VERBOSE set binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here // e.g. STDOUT: {"level":"debug","message":"2.758196 72784=pid 18162115=tid utils/binstat_test.ExampleBinStat_DebugParams:314() // enter in 0.000015 // what[~7exampleDebug] .NumCPU()=8 .GOMAXPROCS(0)=8 .NumGoroutine()=3"} // e.g. STDOUT: {"level":"debug","message":"2.758255 72784=pid 18162119=tid utils/binstat_test.ExampleBinStat_DebugParams:314(foo=1) // debug hello world"} // e.g. STDOUT: {"level":"debug","message":"2.758447 72784=pid 18162119=tid utils/binstat_test.ExampleBinStat_DebugParams:314(foo=1) // leave in 0.000256 // /GOMAXPROCS=8,CPUS=8/what[~7exampleDebug]=[51]=2 0.000306"} fmt.Printf("debug via STDOUT only") }
Output: debug via STDOUT only
func Enter ¶
Example ¶
package main import ( "fmt" "os/exec" "github.com/onflow/flow-go/utils/binstat" ) func grepOutputFileAndSanatize(file string, what string) []byte { binstat.Dump(file) cmd := fmt.Sprintf("cat ./binstat.test.pid-*.binstat.txt%s | egrep '%s' | perl -lane 's~\\d[\\d\\.]*~<num>~g; print;'", file, what) out, err := exec.Command("bash", "-c", cmd).CombinedOutput() if err != nil { panic(err) } return out } func main() { bs := binstat.Enter("~7exampleEnter") // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here fmt.Printf("%s", grepOutputFileAndSanatize(".test-example-enter.txt", "exampleEnter")) // force binstat output & grep & sanitize line; digits to <num> so example test passes }
Output: /GOMAXPROCS=<num>,CPUS=<num>/what[~<num>exampleEnter]=<num> <num> // e.g. utils/binstat_test.ExampleEnter:<num>
func EnterTime ¶
Example ¶
package main import ( "fmt" "os/exec" "github.com/onflow/flow-go/utils/binstat" ) func grepOutputFileAndSanatize(file string, what string) []byte { binstat.Dump(file) cmd := fmt.Sprintf("cat ./binstat.test.pid-*.binstat.txt%s | egrep '%s' | perl -lane 's~\\d[\\d\\.]*~<num>~g; print;'", file, what) out, err := exec.Command("bash", "-c", cmd).CombinedOutput() if err != nil { panic(err) } return out } func main() { bs := binstat.EnterTime("~7exampleEnterTime") // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here, (c) creates "/time[<num>-<num>]" bin section fmt.Printf("%s", grepOutputFileAndSanatize(".test-example-enter-time.txt", "exampleEnterTime")) // force binstat output & grep & sanitize line; digits to <num> so example test passes }
Output: /GOMAXPROCS=<num>,CPUS=<num>/what[~<num>exampleEnterTime]/time[<num>-<num>]=<num> <num> // e.g. utils/binstat_test.ExampleEnterTime:<num>
func EnterTimeVal ¶
Example ¶
package main import ( "fmt" "os/exec" "github.com/onflow/flow-go/utils/binstat" ) func grepOutputFileAndSanatize(file string, what string) []byte { binstat.Dump(file) cmd := fmt.Sprintf("cat ./binstat.test.pid-*.binstat.txt%s | egrep '%s' | perl -lane 's~\\d[\\d\\.]*~<num>~g; print;'", file, what) out, err := exec.Command("bash", "-c", cmd).CombinedOutput() if err != nil { panic(err) } return out } func main() { bs := binstat.EnterTimeVal("~7exampleEnterTimeVal", 123) // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here, (c) creates "/time[<num>-<num>]" bin section, (d) creates "/size[<num>-<num>]=<num>" bin section fmt.Printf("%s", grepOutputFileAndSanatize(".test-example-enter-time-val.txt", "exampleEnterTimeVal")) // force binstat output & grep & sanitize line; digits to <num> so example test passes }
Output: /GOMAXPROCS=<num>,CPUS=<num>/what[~<num>exampleEnterTimeVal]/size[<num>-<num>]/time[<num>-<num>]=<num> <num> // e.g. utils/binstat_test.ExampleEnterTimeVal:<num>
func EnterVal ¶
Example ¶
package main import ( "fmt" "os/exec" "github.com/onflow/flow-go/utils/binstat" ) func grepOutputFileAndSanatize(file string, what string) []byte { binstat.Dump(file) cmd := fmt.Sprintf("cat ./binstat.test.pid-*.binstat.txt%s | egrep '%s' | perl -lane 's~\\d[\\d\\.]*~<num>~g; print;'", file, what) out, err := exec.Command("bash", "-c", cmd).CombinedOutput() if err != nil { panic(err) } return out } func main() { bs := binstat.EnterVal("~7exampleEnterVal", 123) // only 7 chars copied into bin unless env var set to e.g. BINSTAT_LEN_WHAT=~example=99") binstat.Leave(bs) // .Enter*()/.Leave*() creates bin and (a) increments its counter, (b) accumulates its time spent executing code here, (c) creates "/size[<num>-<num>]=<num>" bin section fmt.Printf("%s", grepOutputFileAndSanatize(".test-example-enter-val.txt", "exampleEnterVal")) // force binstat output & grep & sanitize line; digits to <num> so example test passes }
Output: /GOMAXPROCS=<num>,CPUS=<num>/what[~<num>exampleEnterVal]/size[<num>-<num>]=<num> <num> // e.g. utils/binstat_test.ExampleEnterVal:<num>
func (*BinStat) GetSizeRange ¶
functions for exposing binstat internals e.g. for running non-production experiments sampling data, etc