mirror of
https://github.com/nushell/nu_scripts.git
synced 2024-10-05 17:48:11 +03:00
improve std bench
and add significant-digits
(#859)
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">
This commit is contained in:
parent
a921551619
commit
5271d68b7a
103
stdlib-candidate/std-rfc/bench.nu
Normal file
103
stdlib-candidate/std-rfc/bench.nu
Normal file
@ -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 {}
|
||||
}
|
||||
}
|
46
stdlib-candidate/std-rfc/math/mod.nu
Normal file
46
stdlib-candidate/std-rfc/math/mod.nu
Normal file
@ -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}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
22
stdlib-candidate/tests/bench.nu
Normal file
22
stdlib-candidate/tests/bench.nu
Normal file
@ -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
|
||||
}
|
21
stdlib-candidate/tests/math.nu
Normal file
21
stdlib-candidate/tests/math.nu
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user