From 3268ecd116c35be7e5f55c7764caa64f915f0505 Mon Sep 17 00:00:00 2001 From: Antoine Stevan <44101798+amtoine@users.noreply.github.com> Date: Fri, 28 Apr 2023 09:07:23 +0200 Subject: [PATCH] FEATURE: add the `bench` command to the standard library (#8969) Should address the first point of - https://github.com/nushell/nushell/issues/8696. # Description i've seen a few appearances of this `benchmark` idea in recent works on `nu-std`, so i thought it would be great to add it finally. # User-Facing Changes a new `std bench` command to measure the performance of `nushell` closures and code blocks. # Tests + Formatting - :green_circle: `toolkit fmt` - :green_circle: `toolkit clippy` - :black_circle: `toolkit test` - :green_circle: `toolkit test stdlib` # After Submitting ``` $nothing ``` --- crates/nu-std/lib/mod.nu | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/crates/nu-std/lib/mod.nu b/crates/nu-std/lib/mod.nu index 8ed65171c..71d2f96c3 100644 --- a/crates/nu-std/lib/mod.nu +++ b/crates/nu-std/lib/mod.nu @@ -148,3 +148,73 @@ export def clip [ notify-send "std clip" "saved to clipboard" } } + +# convert an integer amount of nanoseconds to a real duration +def "from ns" [] { + [$in "ns"] | str join | into duration +} + +# run a piece of `nushell` code multiple times and measure the time of execution. +# +# this command returns a benchmark report of the following form: +# ``` +# record< +# mean: duration +# std: duration +# times: list +# > +# ``` +# +# > **Note** +# > `std bench --pretty` will return a `string`. +# +# # Examples +# measure the performance of simple addition +# > std bench { 1 + 2 } -n 10 +# ╭───────┬────────────────────╮ +# │ mean │ 4µs 956ns │ +# │ std │ 4µs 831ns │ +# │ │ ╭───┬────────────╮ │ +# │ times │ │ 0 │ 19µs 402ns │ │ +# │ │ │ 1 │ 4µs 322ns │ │ +# │ │ │ 2 │ 3µs 352ns │ │ +# │ │ │ 3 │ 2µs 966ns │ │ +# │ │ │ 4 │ 3µs │ │ +# │ │ │ 5 │ 3µs 86ns │ │ +# │ │ │ 6 │ 3µs 84ns │ │ +# │ │ │ 7 │ 3µs 604ns │ │ +# │ │ │ 8 │ 3µs 98ns │ │ +# │ │ │ 9 │ 3µs 653ns │ │ +# │ │ ╰───┴────────────╯ │ +# ╰───────┴────────────────────╯ +# +# get a pretty benchmark report +# > std bench { 1 + 2 } --pretty +# 3µs 125ns +/- 2µs 408ns +export def bench [ + code: closure # the piece of `nushell` code to measure the performance of + --rounds (-n): int = 50 # the number of benchmark rounds (hopefully the more rounds the less variance) + --verbose (-v): bool # be more verbose (namely prints the progress) + --pretty: bool # shows the results in human-readable format: " +/- " +] { + let times = ( + seq 1 $rounds | each {|i| + if $verbose { print -n $"($i) / ($rounds)\r" } + timeit { do $code } | into int | into decimal + } + ) + + if $verbose { print $"($rounds) / ($rounds)" } + + let report = { + mean: ($times | math avg | from ns) + std: ($times | math stddev | from ns) + times: ($times | each { from ns }) + } + + if $pretty { + $"($report.mean) +/- ($report.std)" + } else { + $report + } +}