diff --git a/benchmarks/README.md b/benchmarks/README.md index c76f5953204a4e8150728fb35a8f1f478c8616eb..25608c959611cc38b98e59de4b45d4456bf4c2d3 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,15 +1,8 @@ # Table of contents - [Requirements](#requirements) - [Run](#run) -- [Plot](#plot) ## Requirements -> [!note] NOTE -> -> these should only be required for plotting results - -- install [GPLT](https://gitlab.isae-supaero.fr/a.stevan/gplt) (for plotting) -- install [Virtualenv](https://github.com/pypa/virtualenv) (for managing Python virtual environments) - activate the `benchmarks` module ```bash use benchmarks @@ -168,44 +161,5 @@ const RESULTS_DIR = "/path/to/komodo-benchmark-results/" > } > ``` -## Plot -```bash -benchmarks plot -i $RESULTS_DIR -o out field group setup commit linalg fec --cpu-hash-pattern '^ee672bb3' --src-hash-pattern '^c8f3481f' --rust-build 'debug' -``` -```bash -benchmarks plot -i $RESULTS_DIR -o out field group setup commit linalg fec --cpu-hash-pattern '^ee672bb3' --src-hash-pattern '^(00086216|04541a50)' --rust-build 'release' -``` -```bash -use regex.nu * - -let srcs = [ - "00086216", # 909176b0, da197416 - "b4212615", # 825cec65 - "04541a50", # a780eb1d, 206fe9d2, 5727d551 - "544835dd", # 5727d551 - "fa141146", # 5727d551 - "491b37ea", # 5727d551 - "4daad4a0", # 5727d551 - "b92ecb2d", # 5727d551 - "64f25f1d", # 5727d551 - "53e7bf81", # 5727d551 - "e591a733", # 5727d551 - "43ad9f18", # 062a39b5 - "90394e42", # 057569f7 - "18b67518", # 0acf66a2 - "e8d6f8fa", # 943e5932 - "0d0768b9", # e7b9968c -] -(benchmarks plot - -i $RESULTS_DIR - -o out - protocols - --git-hash-pattern '' - --cpu-hash-pattern ('ee672bb315ea00fe5815f0e20db6aa88017c1ba8355794f411c10a6057377e57' | regex exact) - --src-hash-pattern ($srcs | regex or | regex start) - --rust-build 'release' -) -``` - [gitlab.isae-supaero.fr:dragoon/komodo-benchmark-results]: https://gitlab.isae-supaero.fr/dragoon/komodo-benchmark-results [`nuenv`]: https://github.com/nushell/nu_scripts/blob/main/nu-hooks/nu-hooks/nuenv/hook.nu diff --git a/benchmarks/mod.nu b/benchmarks/mod.nu index c1db0fdbb06c8d592657869d1a5fcd0ac47e910b..92f1056c8fc12d06091dd63e5825da2be42c09b8 100644 --- a/benchmarks/mod.nu +++ b/benchmarks/mod.nu @@ -1,6 +1,146 @@ -export use run.nu -export use plot.nu - export-env { ^$nu.current-exe ./scripts/check-nushell-version.nu } + +use ../log.nu [ "log info", "log warning", "log error", "log hint", "str color" ] + +const CPU_FIELDS = [ + "Architecture", + "CPU op-mode(s)", + "Address sizes", + "Byte Order", + "CPU(s)", + "On-line CPU(s) list", + "Model name", + "CPU family", + "Model", + "Thread(s) per core", + "Core(s) per socket", + "Socket(s)", + "Stepping", + "CPU max MHz", + "CPU min MHz", + "BogoMIPS", + "Virtualization", + "L1d cache", + "L1i cache", + "L2 cache", + "L3 cache", + "NUMA node(s)", + "NUMA node0 CPU(s)", +] + +const BENCHES = [ field, group, setup, commit, linalg, fec, recoding, semi-avid, kzg, aplonk ] + +def lscpu []: [ nothing -> record ] { + ^lscpu --json + | from json + | get lscpu + | update field { str trim --right --char ":" } + | transpose --header-row + | into record +} + +def --wrapped bench [--rust-build: string, ...args: string] { + let rust_build = match $rust_build { + "release" => { cargo_flag: [ "--release" ], build: "release" }, + "debug" => { cargo_flag: [], build: "debug" }, + _ => { + log warning $"unknown Rust build (ansi yellow)($rust_build)(ansi reset), defaulting to (ansi green)release(ansi reset) for best performance" + { cargo_flag: [ --release ], build: "release" } + }, + } + let options = [ + ...$rust_build.cargo_flag + --package benchmarks + -- + --rust-build $rust_build.build + ...$args + ] + + log info $"cargo run ($options | str join ' ')" + cargo run ...$options +} + +export def run [ + ...benches : string, + --all, + --output-dir (-o) : path = "./a.out", + --curves : list<string> = [], + --degrees : list<int> = [], + --matrix-sizes : list<int> = [], + --data-sizes : list<int> = [], + --ks : list<int> = [], + --rhos : list<float> = [], + --rust-build : string = "release", + --steps : list<string>, + --overwrite, +] { + let benches = match [ $all, ($benches | length) ] { + [ false, 0 ] => { + log error "nothing to do" + return + }, + [ false, _ ] => $benches, + [ true, 0 ] => $BENCHES, + [ true, _ ] => { + log warning "--all is raised even though benches have been provided" + $BENCHES + }, + } + + let target_dir = $output_dir + let cpus_dir = $target_dir | path join "cpus" + + if not ($target_dir | path exists) { + log warning $"creating directory ($target_dir | str color purple)" + mkdir $target_dir + } + + let komodo_hash = git rev-parse HEAD + let src_hash = ls src/*.rs benchmarks/**/*.rs + | each { open $in.name | hash sha256 } + | str join + | hash sha256 + let cpu = lscpu | select ...$CPU_FIELDS + let cpu_hash = $cpu | to json | hash sha256 + + def out [stem: string]: [ nothing -> path] { + { parent: $target_dir, stem: $stem, extension: "ndjson" } | path join + } + + for b in $benches { + let opts = match $b { + "field" => { out: $b , args: { n: 10000, rest: [ --curves ...$curves --all ] } }, + "group" => { out: $b , args: { n: 1000, rest: [ --curves ...$curves --all ] } }, + "setup" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --degrees ...$degrees ] } }, + "commit" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --degrees ...$degrees ] } }, + "linalg" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --sizes ...$matrix_sizes ] } }, + "fec" => { out: "fec" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos --encoding random ] } }, + "recoding" => { out: "fec" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --shards ...$ks ] } }, + "semi-avid" => { out: "protocols" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, + "kzg" => { out: "protocols" , args: { n: 5, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, + "aplonk" => { out: "protocols" , args: { n: 1, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, + _ => { + log error $"unknown bench `($b)`" + log hint $" choose one of these: ($BENCHES | each { str color green })" + continue + }, + } + let opts = [ + (if $overwrite { --overwrite }) + --git $komodo_hash + --cpu $cpu_hash + --src $src_hash + -n $opts.args.n + -o (out $opts.out) + $b + ...(if $steps != null { [--steps, ...$steps] } else { [] }) + ...$opts.args.rest + ] + bench --rust-build $rust_build ...($opts | compact) + } + + mkdir $cpus_dir + $cpu | to json | save --force ({ parent: $cpus_dir, stem: $cpu_hash, extension: "json"} | path join) +} diff --git a/benchmarks/plot.nu b/benchmarks/plot.nu deleted file mode 100644 index f1bafba37d611c0ef95c7376a5a0d4ef8566953b..0000000000000000000000000000000000000000 --- a/benchmarks/plot.nu +++ /dev/null @@ -1,771 +0,0 @@ -use std formats [ "from ndjson" ] - -use ../log.nu [ "log error", "log warning", "log info", "log hint", "str color" ] - -const PYTHON_VENV = "~/.cache" | path expand | path join "venvs" "C2OuW3BqljMdnmzbpnrjRjgXsfA3MbK1" -const PYTHON_DEPENDENCIES = [ matplotlib, rich ] - -const GRAPHS_FILE = "/tmp/graphs.json" - -const FIELD = '\mathbb{F}' -const GROUP = '\mathbb{G}_1' -const MATRIX_FIELD_R = $"\\mathcal{M}_{n \\times n}\(($FIELD)_r[X]\)" -const MATRIX_FIELD_Q = $"\\mathcal{M}_{n \\times n}\(($FIELD)_q[X]\)" - -const X_BASE = 2 -const Y_BASE = 10 - -const BENCHES = [ field, group, setup, commit, linalg, fec, semi-avid, kzg, aplonk, protocols ] - -def curve-to-color [curve: string]: [ nothing -> string] { - match $curve { - "BLS12-381" => "tab:blue", - "BN254" => "tab:green", - "PALLAS" => "tab:orange", - _ => "tab:gray", - } -} - -def k-to-color [k: int]: [ nothing -> string ] { - match $in.0.k { - 2 => "tab:blue", - 4 => "tab:green", - 8 => "tab:orange", - 16 => "tab:brown", - 32 => "tab:red", - 64 => "tab:purple", - _ => "tab:gray", - } -} - -# ``` -# nu scripts/get-arkworks-curves.nu -# | from json -# | each { -# $"\"($in.name | str upcase | str replace --all '_' '-')\" => { r: ($in.r_size), q: ($in.q_size) }," -# } -# | to text -# ``` -def curve-to-field-modulus [curve: string]: [ nothing -> record<q: int, r: int> ] { - match $curve { - "BLS12-381" => { r: 255, q: 381 }, - "BN254" => { r: 254, q: 254 }, - "PALLAS" => { r: 255, q: 255 }, - _ => { r: -1, q: -1 }, - } -} - -def update-time-unit [col: cell-path, time_unit: string]: [ table -> table ] { - let nb_ns_in_time_unit = $"1($time_unit)" | into duration | into int - $in | update $col { $in / $nb_ns_in_time_unit } -} - -def flatten-json-col [col: cell-path]: [ table -> table ] { - update $col { from json } | flatten $col -} - -def error-with-context [msg: string, context: record] { - if $context == {} { - log error $msg - } else { - log error $"($msg):" - } - - let width = $context | columns | each { str length } | math max - $context | items { |k, v| - let k = $k | fill --alignment right --width $width --character ' ' - log error $" ($k) : ($v)" - } - - null -} - -def parse-ndjson-benchmark-results [ - --git : string = '', - --cpu : string = '', - --src : string = '', - --build : string = '', - --bench : string, -]: [ - table<name: string, label: string, times: list<int>> -> table -] { - let filtered = flatten-json-col name | where ( - $it.git =~ $git and - $it.cpu =~ $cpu and - $it.src =~ $src and - $it.build =~ $build - ) - if ($filtered | is-empty) { - error-with-context "filter did not return anything" { - bench : $bench - git : $git - cpu : $cpu - src : $src - build : $build - } - return [] - } - - # merge times with the same label - $filtered - | group-by --to-table { $in.label } - | get items - | each { |it| - $it.0 | update times { $it.times | reduce --fold [] { |it, acc| $acc | append $it } } - } - | flatten-json-col label - # compute stats - | insert avg { $in.times | math avg } - | insert stddev { $in.times | into float | math stddev } - -} - -def plot-bars [ - --label (-l) : string, - --title (-t) : string, - --log-scale - --grid - --grid-behind - --time-unit (-u) : string = "ns", - --curve-field (-c) : string, - --filter : closure, - --grouper : closure, # basically the X axis - --include (-i) : list<string> = [], # the grouper should be in this - --exclude (-E) : list<string> = [], # the grouper should NOT be in this - --family : string, - --styler-color : closure, - --git-hash-pattern : string = '', - --cpu-hash-pattern : string = '', - --src-hash-pattern : string = '', - --rust-build : string = '', - --bench : string, - --output (-o) : path, -]: [ - table<name: string, label: string, times: list<int>> -> nothing -] { - if $grouper == null { log warning "--grouper is null" ; return } - if $family == null { log warning "--family is null" ; return } - if $styler_color == null { log warning "--styler-color is null" ; return } - - let raw = $in - | (parse-ndjson-benchmark-results - --git $git_hash_pattern - --cpu $cpu_hash_pattern - --src $src_hash_pattern - --build $rust_build - --bench $bench - ) - | reject times - | update-time-unit avg $time_unit - | update-time-unit stddev $time_unit - - let filtered = $raw - | if $filter != null { - where { |it| do $filter $it } - } else { - $in - } - if ($filtered | is-empty) { - error-with-context "filter did not return anything" { - bench : $bench, - git : $git_hash_pattern, - cpu : $cpu_hash_pattern, - src : $src_hash_pattern, - build : $rust_build, - } - log error "```" - for line in (view source $filter | nu-highlight | lines) { - log error $line - } - log error "```" - return - } - - let data = $filtered - | update curve { - let modulus = curve-to-field-modulus $in - $"($in) \($($curve_field): ($modulus | get $curve_field)$ bits\)" - } - | insert __grouper $grouper - | group-by __grouper --to-table - | reject items.__grouper - | update items { - each { { k: ($in | get $family), v: { y: $in.avg, e: $in.stddev} } } - | transpose --header-row - | into record - } - - let to_plot = if ($include | is-empty) { - $data.__grouper | uniq - } else { - $include - } | where $it not-in $exclude - - let style = $filtered - | get $family - | uniq - | each { |f| { k: $f, v: { color: (do $styler_color $f) } } } - | transpose --header-row - | into record - - let options = [ - --style ($style | to json) - ...(if $log_scale { [ --log-scale ] } else { [] }) - ...(if $grid { [ --grid ] } else { [] }) - ...(if $grid_behind { [ --grid-behind ] } else { [] }) - --fullscreen - --use-tex - ...(if $label != null { [ --label ($label | str replace --all '%unit' $time_unit) ] } else { [] }) - ...(if $title != null { [ --title ($title | str replace --all '%unit' $time_unit) ] } else { [] }) - ...(if $output != null { [ --save $output ] } else { [] }) - ] - - let graphs = $data - | where $it.__grouper in $to_plot - | transpose --header-row - | into record - - $graphs | save --force $GRAPHS_FILE - gplt multi-bar --json-data-file $GRAPHS_FILE ...$options -} - -def pretty-duration []: [ list<number> -> list<string> ] { - each { $in * 1ns } | each { - if $in < 1us { - format duration ns - } else if $in < 1ms { - format duration us - } else if $in < 1sec { - format duration ms - } else if $in < 1min { - format duration sec - } else if $in < 1hr { - format duration min - } else { - format duration hr - } - } -} -def pretty-filesize []: [ - number -> string, - filesize -> string, - list<number> -> list<string>, - list<filesize> -> list<string>, -] { - def convert []: [ filesize -> string ] { - if $in < 1kib { - format filesize B - } else if $in < 1mib { - format filesize KiB - } else if $in < 1gib { - format filesize MiB - } else if $in < 1tib { - format filesize GiB - } else if $in < 1pib { - format filesize TiB - } else { - format filesize PiB - } - } - - $in | into filesize | match ($in | describe --detailed).type { - "list" => { each { convert } }, - _ => { convert }, - } -} - -def plot [ - --title (-t): string, - --x-label (-x): string, - --y-label (-y): string, - --time-unit (-u): string = "ns", - --filter (-F): closure, # raw data is passed as first positional argument - --grouper (-G): closure, # filtered data is passed as either first positional argument or input - --styler-color (-C): closure, # filtered and grouped data is passed as input - --styler-line (-L): closure, # filtered and grouped data is passed as input - --uniqer (-U): closure, # filtered, grouped and styled data is passed as either first positional argument or input - --namer (-N): closure, # filtered, grouped and styled data is passed as input and field as first positional argument - --x-col (-X): cell-path, - --scale (-s): string = "linlin", - --x-unit : string = "plain", - --y-unit : string = "plain", - --curve-field (-c): string, - --git-hash-pattern : string = '', - --cpu-hash-pattern : string = '', - --src-hash-pattern : string = '', - --rust-build : string = '', - --bench : string, - --output (-o): path, -]: [ - table<name: string, label: string, times: list<int>> -> nothing -] { - let raw = $in - | (parse-ndjson-benchmark-results - --git $git_hash_pattern - --cpu $cpu_hash_pattern - --src $src_hash_pattern - --build $rust_build - --bench $bench - ) - | reject times - if ($raw | is-empty) { return } - - let x_col = $"($x_col)" | str replace --regex '^\$.' '' - - # give defaults to closure - let grouper = $grouper | default { || $in.curve } - let styler_color = $styler_color | default { || curve-to-color $in.0.curve } - let styler_line = $styler_line | default { || { marker: { shape: "." }, type: "solid" }} - let namer = $namer | default { |field| - let modulus = curve-to-field-modulus $in - $"($in) \($($field): ($modulus | get $field)$ bits\)" - } - - let filtered = $raw - | if $filter != null { - where { |it| do $filter $it } - } else { - $in - } - if ($filtered | is-empty) { - error-with-context "filter did not return anything" { - bench : $bench, - git : $git_hash_pattern, - cpu : $cpu_hash_pattern, - src : $src_hash_pattern, - build : $rust_build, - } - log error "```" - for line in (view source $filter | nu-highlight | lines) { - log error $line - } - log error "```" - return - } - - let graphs = $filtered - | insert __grouper $grouper - | group-by __grouper --to-table - | reject items.__grouper - | insert style.color { $in.items | do $styler_color } - | insert style.line { $in.items | do $styler_line } - | update items { - if $uniqer != null { - insert __uniq_key $uniqer - | uniq-by __uniq_key - | reject __uniq_key - } else { - $in - } - | select $x_col avg stddev - | rename --column { $x_col: x, avg: y, stddev: e } - } - | rename --column { __grouper: name, items: points } - | update name { do $namer $curve_field } - - # NOTE: assume the X ticks are powers of $X_BASE - let x_values = $graphs.0.points.x - let min_x_log_value = $x_values | math min | math log $X_BASE | math floor - let max_x_log_value = $x_values | math max | math log $X_BASE | math ceil - let x_ticks = $min_x_log_value..$max_x_log_value | each { $X_BASE ** $in } - let x_tick_labels = $x_ticks | match $x_unit { - "plain" => { $in }, - "duration" => { pretty-duration }, - "filesize" => { pretty-filesize }, - _ => { - log error $"unknown axis unit `($x_unit)` for X" - log hint $" choose one of these: ( - [ "plain", "duration", "filesize" ] | each { str color green } - )" - return - } - } - - # compute - # - the sub log tick in base $Y_BASE just below the lowest Y value - # - the sub log tick in base $Y_BASE just above the highest Y value - let y_values = $graphs.points | flatten | get y | uniq - let min_y_log_value = $y_values | math min | math log $Y_BASE | math floor # one tick too low - let max_y_log_value = $y_values | math max | math log $Y_BASE | math ceil # one tick too high - let y_ticks = $min_y_log_value..$max_y_log_value | each { $Y_BASE ** $in } - let y_ticks = $y_ticks - | append ((($y_values | math min) / ($y_ticks | first) | math floor) * ($y_ticks | first)) # below the lowest - | append ((($y_values | math max) / ($y_ticks | last) * $Y_BASE | math ceil) * ($y_ticks | last) / $Y_BASE) # above the highest - | skip 1 # remove $min_y_log_value and ... - | reverse # | - | drop nth 2 # | ... $max_y_log_value - let y_tick_labels = $y_ticks | match $y_unit { - "plain" => { $in }, - "duration" => { pretty-duration }, - "filesize" => { pretty-filesize }, - _ => { - log error $"unknown axis unit `($y_unit)` for Y" - log hint $" choose one of these: ( - [ "plain", "duration", "filesize" ] | each { str color green } - )" - return - } - } - - let options = [ - --fullscreen - --use-tex - --x-scale-base $X_BASE - --y-scale-base $Y_BASE - --x-ticks ...$x_ticks - --x-tick-labels ...$x_tick_labels - --y-ticks ...$y_ticks - --y-tick-labels ...$y_tick_labels - ...(do { - match $scale { - "linlin" => [ --x-scale linear --y-scale linear ] - "loglin" => [ --x-scale log --y-scale linear ] - "linlog" => [ --x-scale linear --y-scale log ] - "loglog" => [ --x-scale log --y-scale log ] - _ => { - log error $"unknown scale `($scale)`" - log hint $" choose one of these: ( - [ "linlin", "linlog", "loglin", "loglog" ] | each { str color green } - )" - return - } - } - }), - ...(if $x_label != null { [ --x-label ($x_label | str replace --all '%unit' $time_unit) ] } else { [] }) - ...(if $y_label != null { [ --y-label ($y_label | str replace --all '%unit' $time_unit) ] } else { [] }) - ...(if $title != null { [ --title ($title | str replace --all '%unit' $time_unit) ] } else { [] }) - ...(if $output != null { [ --save $output ] } else { [] }) - ] - - $graphs | save --force $GRAPHS_FILE - gplt plot --json-data-file $GRAPHS_FILE ...$options -} - -const BASIC_OPERATIONS = { - field: { - complex: [ "inverse", "sqrt", "legendre", "exponentiation", "random sampling" ], - }, - group: { - complex: [ "random sampling", "scalar multiplication", "affine scalar multiplication" ], - reject: [ "into affine", "from affine" ], - }, -} - -export def main [ - ...benches: string, - --all, - --input-dir (-i) : path, - --output-dir (-o) : path, - --git-hash-pattern (-g) : string = '', - --cpu-hash-pattern (-c) : string = '', - --src-hash-pattern (-s) : string = '', - --rust-build (-r) : string = '', -] { - let benches = match [ $all, ($benches | length) ] { - [ false, 0 ] => { - log error "nothing to do" - return - }, - [ false, _ ] => $benches, - [ true, 0 ] => $BENCHES, - [ true, _ ] => { - log warning "--all is raised even though benches have been provided" - $BENCHES - }, - } - - $env.PATH = $env.PATH | prepend ($PYTHON_VENV | path join "bin") - - if not ($PYTHON_VENV | path exists) { - log info $"creating virtual environment for plotting in ($PYTHON_VENV | str color purple)" - virtualenv -q $PYTHON_VENV - - log info $"installing dependencies: ($PYTHON_DEPENDENCIES | each { str color cyan })" - pip install ...$PYTHON_DEPENDENCIES - } - - if not ($output_dir | path exists) { - log warning $"creating directory ($output_dir | str color purple)" - mkdir $output_dir - } - def in [stem: string]: [ nothing -> path] { { parent: $input_dir, stem: $stem, extension: "ndjson" } | path join } - def out [stem: string]: [ nothing -> path] { { parent: $output_dir, stem: $stem, extension: "png" } | path join } - - for b in $benches { - match $b { - "field" => { - let data = open (in "field") - for it in [ - [ name , out , include , exclude ]; - [ "operations" , field , [] , [] ], - [ "simple operations" , field.simple , [] , $BASIC_OPERATIONS.field.complex ], - [ "complex operations" , field.complex , $BASIC_OPERATIONS.field.complex , [] ], - ] { - $data | (plot-bars - -o (out $it.out) - -t $"($it.name) in $($FIELD)_r$ \(time in %unit\)" - -l "time in %unit" - --log-scale - --grid - --grid-behind - -u ns - -c r - --grouper { |it| $it.operation } - --family curve - --styler-color { |it| curve-to-color $it } - -E $it.exclude - -i $it.include - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "field" - ) - } - }, - "group" => { - let data = open (in "group") - for it in [ - [ name , out , include , exclude ]; - [ "operations" , group , [] , [] ], - [ "simple operations" , group.simple , [] , ($BASIC_OPERATIONS.group.complex ++ $BASIC_OPERATIONS.group.reject) ], - [ "complex operations" , group.complex , $BASIC_OPERATIONS.group.complex , $BASIC_OPERATIONS.group.reject ], - ] { - $data | (plot-bars - -o (out $it.out) - -t $"($it.name) in $($GROUP)$ \($($FIELD)_q$\) \(time in %unit\)" - -l "time in %unit" - --log-scale - --grid - --grid-behind - -u ns - -c q - --grouper { |it| $it.operation } - --family curve - --styler-color { |it| curve-to-color $it } - -E $it.exclude - -i $it.include - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "group" - ) - } - }, - "setup" | "commit" => { - open (in $b) | (plot - -o (out $b) - -t (if $b == "setup" { - $'time to build a cryptographic setup to commit polynomial $P \in ($FIELD)_q[X]$' - } else { - $'time to commit polynomial $P \in ($FIELD)_q[X]$' - }) - -x '$\deg(P)$' - -X degree - -s "loglog" - --x-unit "plain" - --y-unit "duration" - -c q - -u ms - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench $b - ) - }, - "linalg" => { - let linalg_data = open (in "linalg") - for op in [ - [ name , title ]; - [ "inverse" , $'time to invert matrix $M \in ($MATRIX_FIELD_R)$' ], - [ "multiply" , $'time to multiply matrices $M, N \in ($MATRIX_FIELD_R)$' ], - [ "transpose" , $'time to transpose matrix $M \in ($MATRIX_FIELD_R)$' ], - ] { - $linalg_data | (plot - -o (out $"linalg-($op.name)") - -t $op.title - -x '$n$' - -X size - -s "loglog" - --x-unit "plain" - --y-unit "duration" - -F { |it| $it.operation == $op.name } - -c r - -u ms - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "linalg" - ) - } - }, - "fec" => { - open (in "fec") | (plot - -o (out "fec-encode") - -t $"time to \\textit{encode} data of size $|D|$ on \\textbf{BN254} \(r: $(curve-to-field-modulus 'BN254' | get r)$ bits\)" - -x '$|D|$' - -X nb_bytes - -s "loglog" - --x-unit "filesize" - --y-unit "duration" - -F { |it| ( - $it.step == "encode" and $it.curve == "BN254" - ) } - -G { || $"($in.k) ($in.n)" } - -C { || k-to-color $in.0.k } - -L { || - match [$in.0.k, $in.0.n] { - [2, 4] => { marker: { shape: "o" }, type: "solid" }, - [4, 8] => { marker: { shape: "^" }, type: "dotted" }, - [8, 16] => { marker: { shape: "s" }, type: "dashed" }, - [2, 10] => { marker: { shape: "2" }, type: "solid" }, - [4, 20] => { marker: { shape: "X" }, type: "dotted" }, - [8, 40] => { marker: { shape: "h" }, type: "dashed" }, - _ => { marker: { shape: "D" }, type: "dashdot" }, - } - } - -N { |field| - let parsed = $in | parse "{k} {n}" | into record | into int k n - $"$k = ($parsed.k)$, $\\rho = ($parsed.k / $parsed.n | math round -p 3)$" - } - -c r - -u ms - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "fec-encode" - ) - open (in "fec") | (plot - -o (out "fec-decode") - -t $"time to \\textit{decode} data of size $|D|$ on \\textbf{BN254} \(r: $(curve-to-field-modulus 'BN254' | get r)$ bits, $\\rho$ is irrelevant\)" - -x '$|D|$' - -X nb_bytes - -s "loglog" - --x-unit "filesize" - --y-unit "duration" - -F { |it| $it.step == "decode" and $it.curve == BN254 and $it.k in [ 2, 4, 64 ] } - -G { || $in.k } - -C { || k-to-color $in.0.k } - -L { || - match $in.0.k { - 2 => { marker: { shape: "o" }, type: "solid" }, - 4 => { marker: { shape: "^" }, type: "dotted" }, - 8 => { marker: { shape: "s" }, type: "dashed" }, - _ => { marker: { shape: "D" }, type: "dashdot" }, - } - } - -U { || $in.nb_bytes } - -N { |field| - let parsed = $in | parse "{k}" | into record | into int k - $"$k = ($parsed.k)$" - } - -c r - -u ms - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "fec-decode" - ) - open (in "fec") | (plot - -o (out "fec-recode") - -t $"time to \\textit{recode} data of size $|D|$ on \\textbf{BN254} \(r: $(curve-to-field-modulus 'BN254' | get r)$ bits, $\\rho$ is irrelevant, $x = \\frac{\\#shards}{k}$\)" - -x '$|D|$' - -X nb_bytes - -s "loglog" - --x-unit "filesize" - --y-unit "duration" - -F { |it| ( - $it.step == "recode" and $it.curve == "BN254" and [$it.k, $it.nb_shards] in [ - [ 2, 2], - [ 4, 2], - [ 8, 2], - [16, 2], - [32, 2], - [64, 2], - [ 2, 16], - [ 4, 16], - [ 8, 16], - [16, 16], - [32, 16], - [64, 16], - ] - ) } - -G { || $"($in.k) ($in.nb_shards)" } - -C { || k-to-color $in.0.k } - -L { || - match [$in.0.k, $in.0.nb_shards] { - [ 2, 2] => { marker: { shape: "o" }, type: "solid" }, - [ 8, 2] => { marker: { shape: "^" }, type: "dotted" }, - [64, 2] => { marker: { shape: "s" }, type: "dashed" }, - [ 2, 16] => { marker: { shape: "2" }, type: "solid" }, - [ 8, 16] => { marker: { shape: "X" }, type: "dotted" }, - [64, 16] => { marker: { shape: "h" }, type: "dashed" }, - _ => { marker: { shape: "D" }, type: "dashdot" }, - } - } - -N { |_| - let parsed = $in | parse "{k} {nb_shards}" | into record | into int k nb_shards - $"$k = ($parsed.k)$, $x = ($parsed.nb_shards / $parsed.k | math round -p 3)$" - } - -c r - -u ms - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "fec-recode" - ) - }, - "semi-avid" | "kzg" | "aplonk" => { - log warning $"plotting bench `($b)` is not implemented yet" - }, - "protocols" => { - for params in [ - { nb_bytes: 507904 , k: 8 , n: 16 }, - { nb_bytes: 130023424 , k: 8 , n: 16 }, - ] { - open (in "protocols") | (plot-bars - -o (out $"protocols-b($params.nb_bytes)-k($params.k)-n($params.n)") - -t $"time to run cryptographic \\textit{protocols} on data of size $($params.nb_bytes)$ \(($params.nb_bytes | pretty-filesize)\), $k = ($params.k)$ on \\textbf{BN254} \(r: $(curve-to-field-modulus 'BN254' | get r)$ bits\), $\\rho = \\frac{1}{2}$" - -l "time in %unit" - --log-scale - --grid - --grid-behind - -u ms - -c r - --filter { |it| ( - $it.curve == "BN254" and - $it.nb_bytes == $params.nb_bytes and - $it.k == $params.k and - $it.n == $params.n - )} - --grouper { |it| $it.step } - --family command - --styler-color { |it| - match $it { - "aplonk" => "tab:orange", - "kzg" => "tab:blue", - "semi_avid" => "tab:green", - _ => "tab:gray", - } - } - --git-hash-pattern $git_hash_pattern - --cpu-hash-pattern $cpu_hash_pattern - --src-hash-pattern $src_hash_pattern - --rust-build $rust_build - --bench "protocols" - ) - } - }, - _ => { - log error $"unknown bench `($b)`" - log hint $" choose one of these: ($BENCHES | each { str color green })" - }, - } - } -} diff --git a/benchmarks/run.nu b/benchmarks/run.nu deleted file mode 100644 index b3cf91ade970dde08c9ec7cb3576022f002b754f..0000000000000000000000000000000000000000 --- a/benchmarks/run.nu +++ /dev/null @@ -1,142 +0,0 @@ -use ../log.nu [ "log info", "log warning", "log error", "log hint", "str color" ] - -const CPU_FIELDS = [ - "Architecture", - "CPU op-mode(s)", - "Address sizes", - "Byte Order", - "CPU(s)", - "On-line CPU(s) list", - "Model name", - "CPU family", - "Model", - "Thread(s) per core", - "Core(s) per socket", - "Socket(s)", - "Stepping", - "CPU max MHz", - "CPU min MHz", - "BogoMIPS", - "Virtualization", - "L1d cache", - "L1i cache", - "L2 cache", - "L3 cache", - "NUMA node(s)", - "NUMA node0 CPU(s)", -] - -const BENCHES = [ field, group, setup, commit, linalg, fec, recoding, semi-avid, kzg, aplonk ] - -def lscpu []: [ nothing -> record ] { - ^lscpu --json - | from json - | get lscpu - | update field { str trim --right --char ":" } - | transpose --header-row - | into record -} - -def --wrapped bench [--rust-build: string, ...args: string] { - let rust_build = match $rust_build { - "release" => { cargo_flag: [ "--release" ], build: "release" }, - "debug" => { cargo_flag: [], build: "debug" }, - _ => { - log warning $"unknown Rust build (ansi yellow)($rust_build)(ansi reset), defaulting to (ansi green)release(ansi reset) for best performance" - { cargo_flag: [ --release ], build: "release" } - }, - } - let options = [ - ...$rust_build.cargo_flag - --package benchmarks - -- - --rust-build $rust_build.build - ...$args - ] - - log info $"cargo run ($options | str join ' ')" - cargo run ...$options -} - -export def main [ - ...benches : string, - --all, - --output-dir (-o) : path = "./a.out", - --curves : list<string> = [], - --degrees : list<int> = [], - --matrix-sizes : list<int> = [], - --data-sizes : list<int> = [], - --ks : list<int> = [], - --rhos : list<float> = [], - --rust-build : string = "release", - --steps : list<string>, - --overwrite, -] { - let benches = match [ $all, ($benches | length) ] { - [ false, 0 ] => { - log error "nothing to do" - return - }, - [ false, _ ] => $benches, - [ true, 0 ] => $BENCHES, - [ true, _ ] => { - log warning "--all is raised even though benches have been provided" - $BENCHES - }, - } - - let target_dir = $output_dir - let cpus_dir = $target_dir | path join "cpus" - - if not ($target_dir | path exists) { - log warning $"creating directory ($target_dir | str color purple)" - mkdir $target_dir - } - - let komodo_hash = git rev-parse HEAD - let src_hash = ls src/*.rs benchmarks/**/*.rs - | each { open $in.name | hash sha256 } - | str join - | hash sha256 - let cpu = lscpu | select ...$CPU_FIELDS - let cpu_hash = $cpu | to json | hash sha256 - - def out [stem: string]: [ nothing -> path] { - { parent: $target_dir, stem: $stem, extension: "ndjson" } | path join - } - - for b in $benches { - let opts = match $b { - "field" => { out: $b , args: { n: 10000, rest: [ --curves ...$curves --all ] } }, - "group" => { out: $b , args: { n: 1000, rest: [ --curves ...$curves --all ] } }, - "setup" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --degrees ...$degrees ] } }, - "commit" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --degrees ...$degrees ] } }, - "linalg" => { out: $b , args: { n: 10, rest: [ --curves ...$curves --sizes ...$matrix_sizes ] } }, - "fec" => { out: "fec" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos --encoding random ] } }, - "recoding" => { out: "fec" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --shards ...$ks ] } }, - "semi-avid" => { out: "protocols" , args: { n: 10, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, - "kzg" => { out: "protocols" , args: { n: 5, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, - "aplonk" => { out: "protocols" , args: { n: 1, rest: [ --curves ...$curves --sizes ...$data_sizes --ks ...$ks --rhos ...$rhos ] } }, - _ => { - log error $"unknown bench `($b)`" - log hint $" choose one of these: ($BENCHES | each { str color green })" - continue - }, - } - let opts = [ - (if $overwrite { --overwrite }) - --git $komodo_hash - --cpu $cpu_hash - --src $src_hash - -n $opts.args.n - -o (out $opts.out) - $b - ...(if $steps != null { [--steps, ...$steps] } else { [] }) - ...$opts.args.rest - ] - bench --rust-build $rust_build ...($opts | compact) - } - - mkdir $cpus_dir - $cpu | to json | save --force ({ parent: $cpus_dir, stem: $cpu_hash, extension: "json"} | path join) -} diff --git a/regex.nu b/regex.nu deleted file mode 100644 index 8dc70d04b3ee9295743e118ae3d009026133d34a..0000000000000000000000000000000000000000 --- a/regex.nu +++ /dev/null @@ -1,4 +0,0 @@ -export def "regex or" []: [ list<string> -> string ] { str join '|' | $"\(($in)\)" } -export def "regex start" []: [ string -> string ] { $"^($in)" } -export def "regex end" []: [ string -> string ] { $"($in)$" } -export def "regex exact" []: [ string -> string ] { $"^($in)$" }