Skip to content

Commit

Permalink
add metering for deserialization (#524)
Browse files Browse the repository at this point in the history
* add metering for deserialization

* count type table cost

* increase limit

* make this opt-in

* fix

* fix

* make skipping twice expensive

* use canbench

* ci

* fix

* fix

* fix

* fix

* fix

* make skipping 50x expensive

* add diff

* fix

* fix

* fix

* fix

* add skipping limit

* fix cycle detection

* fix

* spec

* test

* docs

* fix

* fix

* refine cost description

* test description
  • Loading branch information
chenyan-dfinity authored Feb 27, 2024
1 parent 0b16feb commit 53cda2e
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 163 deletions.
8 changes: 3 additions & 5 deletions .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ jobs:
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
~/.cargo
target
key: ${{ runner.os }}-bench-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-bench-0.1.1-${{ hashFiles('**/Cargo.lock') }}
- name: Install canbench
run: cargo install canbench --force
run: cargo install canbench
- name: Run perf for base branch
if: false
run: |
Expand Down
44 changes: 32 additions & 12 deletions rust/bench/bench.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
use canbench_rs::{bench, bench_fn, bench_scope, BenchResult};
use candid::{CandidType, Decode, Deserialize, Encode, Int, Nat};
use candid::{CandidType, Decode, DecoderConfig, Deserialize, Encode, Int, Nat};
use std::collections::BTreeMap;

#[allow(clippy::all)]
mod nns;

const N: usize = 2097152;
const COST: usize = 20_000_000;
const SKIP: usize = 10_000;

#[bench(raw)]
fn blob() -> BenchResult {
use serde_bytes::ByteBuf;
let vec: Vec<u8> = vec![0x61; N];
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
bench_fn(|| {
let bytes = {
let _p = bench_scope("1. Encoding");
Encode!(&ByteBuf::from(vec)).unwrap()
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, ByteBuf).unwrap();
Decode!([config]; &bytes, ByteBuf).unwrap();
}
})
}
Expand All @@ -27,35 +31,41 @@ fn blob() -> BenchResult {
fn text() -> BenchResult {
let vec: Vec<u8> = vec![0x61; N];
let text = String::from_utf8(vec).unwrap();
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
bench_fn(|| {
let bytes = {
let _p = bench_scope("1. Encoding");
Encode!(&text).unwrap()
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, String).unwrap();
Decode!([config]; &bytes, String).unwrap();
}
})
}

#[bench(raw)]
fn vec_int64() -> BenchResult {
let vec: Vec<i64> = vec![-1; N];
fn vec_int16() -> BenchResult {
let vec: Vec<i16> = vec![-1; N];
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
bench_fn(|| {
let bytes = {
let _p = bench_scope("1. Encoding");
Encode!(&vec).unwrap()
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, Vec<i64>).unwrap();
Decode!([config]; &bytes, Vec<i16>).unwrap();
}
})
}

#[bench(raw)]
fn btreemap() -> BenchResult {
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
let n = 1048576;
let map: BTreeMap<String, Nat> = (0u32..n as u32)
.map(|i| (i.to_string(), Nat::from(i)))
Expand All @@ -67,13 +77,15 @@ fn btreemap() -> BenchResult {
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, BTreeMap<String, Nat>).unwrap();
Decode!([config]; &bytes, BTreeMap<String, Nat>).unwrap();
}
})
}

#[bench(raw)]
fn option_list() -> BenchResult {
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
let n = 2048;
#[derive(CandidType, Deserialize)]
struct List {
Expand All @@ -93,13 +105,15 @@ fn option_list() -> BenchResult {
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, Option<Box<List>>).unwrap();
Decode!([config]; &bytes, Option<Box<List>>).unwrap();
}
})
}

#[bench(raw)]
fn variant_list() -> BenchResult {
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
let n = 2048;
#[derive(CandidType, Deserialize)]
enum VariantList {
Expand All @@ -116,14 +130,16 @@ fn variant_list() -> BenchResult {
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, VariantList).unwrap();
Decode!([config]; &bytes, VariantList).unwrap();
}
})
}

#[bench(raw)]
fn nns() -> BenchResult {
use candid_parser::utils::CandidSource;
let mut config = DecoderConfig::new();
config.set_decoding_quota(COST).set_skipping_quota(SKIP);
let nns_did = CandidSource::Text(include_str!("./nns.did"));
let motion_proposal = r#"
(
Expand Down Expand Up @@ -207,16 +223,20 @@ fn nns() -> BenchResult {
};
{
let _p = bench_scope("2. Decoding");
Decode!(&bytes, nns::ManageNeuron).unwrap();
Decode!([config]; &bytes, nns::ManageNeuron).unwrap();
}
})
}

#[bench(raw)]
fn extra_args() -> BenchResult {
let bytes = hex::decode("4449444c036c01d6fca702016d026c00010080ade204").unwrap();
let mut config = DecoderConfig::new();
config.set_skipping_quota(SKIP);
let vec_null = hex::decode("4449444c036c01d6fca702016d026c00010080ade204").unwrap();
let vec_opt_record = hex::decode("4449444c176c02017f027f6c02010002006c02000101016c02000201026c02000301036c02000401046c02000501056c02000601066c02000701076c02000801086c02000901096c02000a010a6c02000b010b6c02000c010c6c02000d020d6c02000e010e6c02000f010f6c02001001106c02001101116c02001201126c02001301136e146d150116050101010101").unwrap();
bench_fn(|| {
let _ = Decode!(&bytes);
assert!(Decode!([config]; &vec_null).is_err());
assert!(Decode!([config]; &vec_opt_record).is_err());
})
}

Expand Down
Loading

0 comments on commit 53cda2e

Please sign in to comment.