-
Notifications
You must be signed in to change notification settings - Fork 209
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hi! I propose several changes to `std bench`: - Remove insignificant precision by default (can be reverted with `--sign-digits=0`). - Remove the 'times' field by default (can be returned with `--list-timings`). - Add an option to set time units (inactive by default). For removing insignificant precision, I needed a new command `significant-digits` which is also included in this PR. This command has tests. <img width="747" alt="image" src="https://github.com/nushell/nu_scripts/assets/4896754/ce98aebe-7c1b-4d8f-b2d0-3282d1ff3883"> <img width="747" alt="image" src="https://github.com/nushell/nu_scripts/assets/4896754/508fef3e-ba70-40fd-8f9e-82b6ac608485"> <img width="747" alt="image" src="https://github.com/nushell/nu_scripts/assets/4896754/af755f28-8506-4f4c-8bc2-91b35798855d">
- Loading branch information
1 parent
a921551
commit 5271d68
Showing
6 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# A proposal for improving the original `std bench` command by @amtoine | ||
# https://github.com/nushell/nushell/blob/31f3d2f6642b585f0d88192724723bf0ce330ecf/crates/nu-std/std/mod.nu#L134 | ||
|
||
use ./math | ||
|
||
# convert an integer amount of nanoseconds to a real duration | ||
def "from ns" [ | ||
--units: string # units to convert duration to (min, sec, ms, µs, ns) | ||
--sign-digits: int # a number of first non-zero digits to keep (default 4; set 0 to disable rounding) | ||
] { | ||
if $sign_digits == 0 {} else { | ||
math significant-digits $sign_digits | ||
} | ||
| $"($in)ns" | ||
| into duration | ||
| if $units != null { | ||
format duration $units | ||
} else {} | ||
} | ||
|
||
# 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 | ||
# min: duration | ||
# max: duration | ||
# std: duration | ||
# times: list<duration> | ||
# > | ||
# ``` | ||
# | ||
# > **Note** | ||
# > `std bench --pretty` will return a `string`. | ||
# > the `--units` option will convert all durations to strings | ||
# | ||
# # Examples | ||
# measure the performance of simple addition | ||
# > bench {1 + 2} | ||
# ╭──────┬───────────╮ | ||
# │ mean │ 716ns │ | ||
# │ min │ 583ns │ | ||
# │ max │ 4µs 541ns │ | ||
# │ std │ 549ns │ | ||
# ╰──────┴───────────╯ | ||
# | ||
# get a pretty benchmark report | ||
# > std bench {1 + 2} --pretty | ||
# 922ns +/- 2µs 40ns | ||
# | ||
# format results as `ms` | ||
# > bench {sleep 0.1sec; 1 + 2} --units ms --rounds 5 | ||
# ╭──────┬───────────╮ | ||
# │ mean │ 104.90 ms │ | ||
# │ min │ 103.60 ms │ | ||
# │ max │ 105.90 ms │ | ||
# │ std │ 0.75 ms │ | ||
# ╰──────┴───────────╯ | ||
# | ||
# measure the performance of simple addition with 1ms delay and output each timing | ||
# > bench {sleep 1ms; 1 + 2} --rounds 2 --list-timings | table -e | ||
# ╭───────┬─────────────────────╮ | ||
# │ mean │ 1ms 272µs │ | ||
# │ min │ 1ms 259µs │ | ||
# │ max │ 1ms 285µs │ | ||
# │ std │ 13µs 370ns │ | ||
# │ │ ╭─────────────────╮ │ | ||
# │ times │ │ 1ms 285µs 791ns │ │ | ||
# │ │ │ 1ms 259µs 42ns │ │ | ||
# │ │ ╰─────────────────╯ │ | ||
# ╰───────┴─────────────────────╯ | ||
export def main [ | ||
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) # be more verbose (namely prints the progress) | ||
--pretty # shows the results in human-readable format: "<mean> +/- <stddev>" | ||
--units: string # units to convert duration to (min, sec, ms, µs, ns) | ||
--list-timings # list all rounds' timings in a `times` field | ||
--sign-digits: int = 4 # a number of first non-zero digits to keep (default 4; set 0 to disable rounding) | ||
] { | ||
let times = seq 1 $rounds | ||
| each {|i| | ||
if $verbose { print -n $"($i) / ($rounds)\r" } | ||
timeit { do $code } | into int | into float | ||
} | ||
|
||
if $verbose { print $"($rounds) / ($rounds)" } | ||
|
||
{ | ||
mean: ($times | math avg | from ns --units $units --sign-digits=$sign_digits) | ||
min: ($times | math min | from ns --units $units --sign-digits=$sign_digits) | ||
max: ($times | math max | from ns --units $units --sign-digits=$sign_digits) | ||
std: ($times | math stddev | from ns --units $units --sign-digits=$sign_digits) | ||
} | ||
| if $pretty { | ||
$"($in.mean) +/- ($in.std)" | ||
} else { | ||
if $list_timings { | ||
merge { times: ($times | each { from ns --units $units --sign-digits 0 }) } | ||
} else {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
|
||
use std iter scan | ||
|
||
# replace all insignificant digits with 0 | ||
# | ||
# | Significant Digits | Maximum Relative Error | | ||
# |--------------------|------------------------| | ||
# | 1 | 50% | | ||
# | 2 | 5% | | ||
# | 3 | 0.5% | | ||
# | 4 | 0.05% | | ||
# | 5 | 0.005% | | ||
# | 6 | 0.0005% | | ||
# | ||
# > 0.0000012346789 | significant-digits 2 | ||
# 0.0000012 | ||
# | ||
# > 1.2346789 | significant-digits 3 | ||
# 1.23 | ||
# | ||
# > 1sec / 3 | math significant-digits | ||
# 333ms | ||
export def 'significant-digits' [ | ||
n: int = 4 # a number of first non-zero digits to keep | ||
]: [int -> int, float -> float, duration -> duration] { | ||
let $input = $in | ||
let $chars = $input | into string | split chars | ||
|
||
let $rounded_str = $chars | ||
| scan --noinit 0 {|ind i| | ||
if $i =~ '\d' { | ||
if $ind == 0 and $i == '0' { | ||
$ind | ||
} else { $ind + 1 } | ||
} else {$ind} | ||
} | ||
| zip $chars | ||
| each {|i| if $i.1 =~ '\d' and $i.0 > $n {'0'} else {$i.1}} | ||
| str join | ||
|
||
match ($input | describe) { | ||
'duration' => {$rounded_str | into duration} | ||
'int' => {$rounded_str | into int} | ||
'float' => {$rounded_str | into float} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# modules | ||
export module record/ | ||
export module str/ | ||
export module math/ | ||
# commands | ||
export use bulk-rename.nu * | ||
export use set-env.nu * | ||
export use bench.nu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use std assert | ||
use ../std-rfc bench | ||
|
||
export def "test bench-units" [] { | ||
let $test = bench {sleep 0.001sec; 1 + 2} --units ns --rounds 2 | get mean | ||
assert str contains $test " ns" | ||
} | ||
|
||
export def "test bench-timings" [] { | ||
let $test = bench {1 + 2} --rounds 3 --list-timings | get times | length | ||
assert equal $test 3 | ||
} | ||
|
||
export def "test bench-pretty" [] { | ||
let $test = (bench {1 + 2} --rounds 3 --pretty) =~ '\d.* \+/- \d' | ||
assert equal $test true | ||
} | ||
|
||
export def "test bench-sign-digits" [] { | ||
let $test = bench {sleep 1ms} --sign-digits 1 --rounds 5 | get min | ||
assert equal $test 1ms | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use std assert | ||
use ../std-rfc/math | ||
|
||
#[test] | ||
export def "test significant-digits-decimals" [] { | ||
assert equal (0.0000012346789 | math significant-digits 2) 0.0000012 | ||
assert equal (11 / 3 | math significant-digits 6) 3.66666 | ||
assert not equal (0.0000012346789 | math significant-digits 2) 0.00000123 | ||
assert equal (1.999999 | math significant-digits 1) 1.0 | ||
} | ||
|
||
#[test] | ||
export def "test significant-digits-duration" [] { | ||
assert equal (2min / 7 | math significant-digits 3) 17100000000ns | ||
assert equal (1sec | math significant-digits 3) 1000000000ns | ||
} | ||
|
||
#[test] | ||
export def "test significant-digits-ints" [] { | ||
assert equal (123456 | math significant-digits 2) 120000 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export module bulk-rename.nu | ||
export module record.nu | ||
export module str_xpend.nu | ||
export module math.nu | ||
export module bench.nu |