From 392f640a3b93c330e7586e62b36d3db014b7e83f Mon Sep 17 00:00:00 2001 From: STEVAN Antoine <antoine.stevan@isae-supaero.fr> Date: Fri, 26 Apr 2024 15:20:31 +0000 Subject: [PATCH] add a "fec" bench (dragoon/komodo!93) this MR adds - `examples/benches/bench_fec.rs` to the list of example benches - instructions on how to run the new benchmark and plot the results ## results    --- Cargo.toml | 4 ++ examples/benches/README.md | 70 ++++++++++++++++++++++++++ examples/benches/fec.rs | 100 +++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 examples/benches/fec.rs diff --git a/Cargo.toml b/Cargo.toml index 6e71ae55..da9d6d28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,3 +78,7 @@ path = "examples/benches/linalg.rs" [[example]] name = "bench_recoding" path = "examples/benches/recoding.rs" + +[[example]] +name = "bench_fec" +path = "examples/benches/fec.rs" diff --git a/examples/benches/README.md b/examples/benches/README.md index a01ef2a3..6939c07b 100644 --- a/examples/benches/README.md +++ b/examples/benches/README.md @@ -166,3 +166,73 @@ python scripts/plot/plot.py --title "recoding with k = 4" ( | to json ) ``` + +### FEC +```nushell +let rho = 1 / 2 + +"" out> fec.ndjson + +[3, 5] | each { |k| + cargo run --example bench_fec -- ...[ + ...[100, 1_000, 10_000] + --encoding vandermonde + -k $k + -n ($k / $rho) + --nb-measurements 100 + ] | from ndnuon | to ndjson out>> fec.ndjson +} +``` +```nushell +python scripts/plot/plot.py --title "encoding" --x-label "nb bytes" --y-label "time (in ms)" ( + open fec.ndjson + | update label { from json } + | flatten label + | ns-to-ms times + | compute-stats times + | insert foo { $"($in.name) / ($in.k)" } + | where step == "encode" + | rename --column { bytes: "x", mean: "y", stddev: "e" } + | group-by foo --to-table + | rename --column { group: "name", items: "points" } + | to json +) + +python scripts/plot/plot.py --title "decoding" --x-label "nb bytes" --y-label "time (in ms)" ( + open fec.ndjson + | update label { from json } + | flatten label + | ns-to-ms times + | compute-stats times + | insert foo { $"($in.name) / ($in.k)" } + | where step == "decode" + | rename --column { bytes: "x", mean: "y", stddev: "e" } + | group-by foo --to-table + | rename --column { group: "name", items: "points" } + | to json +) + +let x = open fec.ndjson + | update label { from json } + | flatten label + | insert foo { $"($in.name) / ($in.k) / ($in.bytes)" } + | group-by foo --to-table + | update items {|it| + $it.items + | update step e2e + | update times { $it.items.0.times | zip $it.items.1.times | each { $in.0 + $in.1 } } + } + | flatten --all + | reject group foo + +python scripts/plot/plot.py --title "e2e" --x-label "nb bytes" --y-label "time (in ms)" ( + $x + | ns-to-ms times + | compute-stats times + | insert foo { $"($in.name) / ($in.k)" } + | rename --column { bytes: "x", mean: "y", stddev: "e" } + | group-by foo --to-table + | rename --column { group: "name", items: "points" } + | to json +) +``` diff --git a/examples/benches/fec.rs b/examples/benches/fec.rs new file mode 100644 index 00000000..65463e4f --- /dev/null +++ b/examples/benches/fec.rs @@ -0,0 +1,100 @@ +// see `examples/benches/README.md` +use ark_ff::PrimeField; + +use clap::{arg, command, Parser, ValueEnum}; +use komodo::{fec, linalg::Matrix}; +use plnk::Bencher; +use rand::{rngs::ThreadRng, thread_rng, Rng, RngCore}; + +fn random_bytes(n: usize, rng: &mut ThreadRng) -> Vec<u8> { + (0..n).map(|_| rng.gen::<u8>()).collect() +} + +fn build_encoding_mat<F: PrimeField>( + k: usize, + n: usize, + encoding: &Encoding, + rng: &mut impl RngCore, +) -> Matrix<F> { + match encoding { + Encoding::Random => Matrix::random(k, n, rng), + Encoding::Vandermonde => { + let points: Vec<F> = (0..n) + .map(|i| F::from_le_bytes_mod_order(&i.to_le_bytes())) + .collect(); + Matrix::vandermonde_unchecked(&points, k) + } + } +} + +fn template<F: PrimeField>(b: &Bencher, nb_bytes: usize, k: usize, n: usize, encoding: &Encoding) { + let mut rng = thread_rng(); + + let encoding_mat = build_encoding_mat(k, n, encoding, &mut rng); + + plnk::bench( + b, + &format!( + r#"{{"bytes": {}, "step": "encode", "k": {}, "n": {}}}"#, + nb_bytes, k, n + ), + || { + let bytes = random_bytes(nb_bytes, &mut rng); + + plnk::timeit(|| fec::encode::<F>(&bytes, &encoding_mat).unwrap()) + }, + ); + + plnk::bench( + b, + &format!( + r#"{{"bytes": {}, "step": "decode", "k": {}, "n": {}}}"#, + nb_bytes, k, n + ), + || { + let bytes = random_bytes(nb_bytes, &mut rng); + let shards = fec::encode::<F>(&bytes, &encoding_mat).unwrap(); + + plnk::timeit(|| fec::decode::<F>(shards.clone()).unwrap()) + }, + ); +} + +#[derive(ValueEnum, Clone)] +enum Encoding { + Vandermonde, + Random, +} + +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct Cli { + /// the sizes of the data to consider + #[arg(num_args = 1.., value_delimiter = ' ')] + sizes: Vec<usize>, + + #[arg(short, long)] + encoding: Encoding, + + #[arg(short)] + k: usize, + #[arg(short)] + n: usize, + + /// the number of measurements to repeat each case, larger values will reduce the variance of + /// the measurements + #[arg(long)] + nb_measurements: usize, +} + +fn main() { + let cli = Cli::parse(); + + let b = plnk::Bencher::new(cli.nb_measurements); + + for n in cli.sizes { + template::<ark_bls12_381::Fr>(&b.with_name("BLS12-381"), n, cli.k, cli.n, &cli.encoding); + template::<ark_bn254::Fr>(&b.with_name("BN-254"), n, cli.k, cli.n, &cli.encoding); + template::<ark_pallas::Fr>(&b.with_name("PALLAS"), n, cli.k, cli.n, &cli.encoding); + } +} -- GitLab