From f5c4671bfbad96bf346bd7e9a21fc4317b4959df Mon Sep 17 00:00:00 2001 From: Indrajith K L Date: Sat, 3 Dec 2022 17:00:20 +0530 Subject: Adds most of the tools --- v_windows/v/vlib/benchmark/README.md | 45 +++++++ v_windows/v/vlib/benchmark/benchmark.v | 218 +++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 v_windows/v/vlib/benchmark/README.md create mode 100644 v_windows/v/vlib/benchmark/benchmark.v (limited to 'v_windows/v/vlib/benchmark') diff --git a/v_windows/v/vlib/benchmark/README.md b/v_windows/v/vlib/benchmark/README.md new file mode 100644 index 0000000..6f4f7db --- /dev/null +++ b/v_windows/v/vlib/benchmark/README.md @@ -0,0 +1,45 @@ +Example usage of this module: +```v +import benchmark + +mut bmark := benchmark.new_benchmark() +// by default the benchmark will be verbose, i.e. it will include timing information +// if you want it to be silent, set bmark.verbose = false +for { + bmark.step() // call this when you want to advance the benchmark. + // The timing info in bmark.step_message will be measured starting from the last call to bmark.step + // .... + // bmark.fail() // call this if the step failed + // bmark.step_message(('failed') + bmark.ok() // call this when the step succeeded + println(bmark.step_message('ok')) +} +bmark.stop() +// call when you want to finalize the benchmark +println(bmark.total_message('remarks about the benchmark')) +``` + +benchmark.start() and b.measure() are convenience methods, +intended to be used in combination. Their goal is to make +benchmarking of small snippets of code as *short*, easy to +write, and then to read and analyze the results, as possible. + +Example: +```v +import time +import benchmark + +mut b := benchmark.start() +// your code section 1 ... +time.sleep(1500 * time.millisecond) +b.measure('code_1') +// your code section 2 ... +time.sleep(500 * time.millisecond) +b.measure('code_2') +``` + +... which will produce on stdout something like this: +```text +SPENT 1500.063 ms in code_1 +SPENT 500.061 ms in code_2 +``` diff --git a/v_windows/v/vlib/benchmark/benchmark.v b/v_windows/v/vlib/benchmark/benchmark.v new file mode 100644 index 0000000..cd9f994 --- /dev/null +++ b/v_windows/v/vlib/benchmark/benchmark.v @@ -0,0 +1,218 @@ +module benchmark + +import time +import term + +pub const ( + b_ok = term.ok_message('OK ') + b_fail = term.fail_message('FAIL') + b_skip = term.warn_message('SKIP') + b_spent = term.ok_message('SPENT') +) + +pub struct Benchmark { +pub mut: + bench_timer time.StopWatch + verbose bool + no_cstep bool + step_timer time.StopWatch + ntotal int + nok int + nfail int + nskip int + nexpected_steps int + cstep int + bok string + bfail string +} + +// new_benchmark returns a `Benchmark` instance on the stack. +pub fn new_benchmark() Benchmark { + return Benchmark{ + bench_timer: time.new_stopwatch() + verbose: true + } +} + +// new_benchmark_no_cstep returns a new `Benchmark` instance with step counting disabled. +pub fn new_benchmark_no_cstep() Benchmark { + return Benchmark{ + bench_timer: time.new_stopwatch() + verbose: true + no_cstep: true + } +} + +// new_benchmark_pointer returns a new `Benchmark` instance allocated on the heap. +// This is useful for long-lived use of `Benchmark` instances. +pub fn new_benchmark_pointer() &Benchmark { + return &Benchmark{ + bench_timer: time.new_stopwatch() + verbose: true + } +} + +// set_total_expected_steps sets the the total amount of steps the benchmark is expected to take. +pub fn (mut b Benchmark) set_total_expected_steps(n int) { + b.nexpected_steps = n +} + +// stop stops the internal benchmark timer. +pub fn (mut b Benchmark) stop() { + b.bench_timer.stop() +} + +// step increases the step count by 1 and restarts the internal timer. +pub fn (mut b Benchmark) step() { + b.step_timer.restart() + if !b.no_cstep { + b.cstep++ + } +} + +// fail increases the fail count by 1 and stops the internal timer. +pub fn (mut b Benchmark) fail() { + b.step_timer.stop() + b.ntotal++ + b.nfail++ +} + +// ok increases the ok count by 1 and stops the internal timer. +pub fn (mut b Benchmark) ok() { + b.step_timer.stop() + b.ntotal++ + b.nok++ +} + +// skip increases the skip count by 1 and stops the internal timer. +pub fn (mut b Benchmark) skip() { + b.step_timer.stop() + b.ntotal++ + b.nskip++ +} + +// fail_many increases the fail count by `n` and stops the internal timer. +pub fn (mut b Benchmark) fail_many(n int) { + b.step_timer.stop() + b.ntotal += n + b.nfail += n +} + +// ok_many increases the ok count by `n` and stops the internal timer. +pub fn (mut b Benchmark) ok_many(n int) { + b.step_timer.stop() + b.ntotal += n + b.nok += n +} + +// neither_fail_nor_ok stops the internal timer. +pub fn (mut b Benchmark) neither_fail_nor_ok() { + b.step_timer.stop() +} + +// start returns a new, running, instance of `Benchmark`. +// This is a shorthand for calling `new_benchmark().step()`. +pub fn start() Benchmark { + mut b := new_benchmark() + b.step() + return b +} + +// measure prints the current time spent doing `label`, since the benchmark was started. +pub fn (mut b Benchmark) measure(label string) i64 { + b.ok() + res := b.step_timer.elapsed().microseconds() + println(b.step_message_with_label(benchmark.b_spent, 'in $label')) + b.step() + return res +} + +// step_message_with_label_and_duration returns a string describing the current step. +pub fn (b &Benchmark) step_message_with_label_and_duration(label string, msg string, sduration time.Duration) string { + timed_line := b.tdiff_in_ms(msg, sduration.microseconds()) + if b.nexpected_steps > 1 { + mut sprogress := '' + if b.nexpected_steps < 10 { + sprogress = if b.no_cstep { + 'TMP1/${b.nexpected_steps:1d}' + } else { + '${b.cstep:1d}/${b.nexpected_steps:1d}' + } + } else if b.nexpected_steps >= 10 && b.nexpected_steps < 100 { + sprogress = if b.no_cstep { + 'TMP2/${b.nexpected_steps:2d}' + } else { + '${b.cstep:2d}/${b.nexpected_steps:2d}' + } + } else if b.nexpected_steps >= 100 && b.nexpected_steps < 1000 { + sprogress = if b.no_cstep { + 'TMP3/${b.nexpected_steps:3d}' + } else { + '${b.cstep:3d}/${b.nexpected_steps:3d}' + } + } else { + sprogress = if b.no_cstep { + 'TMP4/${b.nexpected_steps:4d}' + } else { + '${b.cstep:4d}/${b.nexpected_steps:4d}' + } + } + return '${label:-5s} [$sprogress] $timed_line' + } + return '${label:-5s}$timed_line' +} + +// step_message_with_label returns a string describing the current step using current time as duration. +pub fn (b &Benchmark) step_message_with_label(label string, msg string) string { + return b.step_message_with_label_and_duration(label, msg, b.step_timer.elapsed()) +} + +// step_message returns a string describing the current step. +pub fn (b &Benchmark) step_message(msg string) string { + return b.step_message_with_label('', msg) +} + +// step_message_ok returns a string describing the current step with an standard "OK" label. +pub fn (b &Benchmark) step_message_ok(msg string) string { + return b.step_message_with_label(benchmark.b_ok, msg) +} + +// step_message_fail returns a string describing the current step with an standard "FAIL" label. +pub fn (b &Benchmark) step_message_fail(msg string) string { + return b.step_message_with_label(benchmark.b_fail, msg) +} + +// step_message_skip returns a string describing the current step with an standard "SKIP" label. +pub fn (b &Benchmark) step_message_skip(msg string) string { + return b.step_message_with_label(benchmark.b_skip, msg) +} + +// total_message returns a string with total summary of the benchmark run. +pub fn (b &Benchmark) total_message(msg string) string { + the_label := term.colorize(term.gray, msg) + mut tmsg := '${term.colorize(term.bold, 'Summary for $the_label:')} ' + if b.nfail > 0 { + tmsg += term.colorize(term.bold, term.colorize(term.red, '$b.nfail failed')) + ', ' + } + if b.nok > 0 { + tmsg += term.colorize(term.bold, term.colorize(term.green, '$b.nok passed')) + ', ' + } + if b.nskip > 0 { + tmsg += term.colorize(term.bold, term.colorize(term.yellow, '$b.nskip skipped')) + ', ' + } + tmsg += '$b.ntotal total. ${term.colorize(term.bold, 'Runtime:')} ${b.bench_timer.elapsed().microseconds() / 1000} ms.\n' + return tmsg +} + +// total_duration returns the duration in ms. +pub fn (b &Benchmark) total_duration() i64 { + return b.bench_timer.elapsed().milliseconds() +} + +// tdiff_in_ms prefixes `s` with a time difference calculation. +fn (b &Benchmark) tdiff_in_ms(s string, tdiff i64) string { + if b.verbose { + return '${f64(tdiff) / 1000.0:9.3f} ms $s' + } + return s +} -- cgit v1.2.3