Update SszEncoder

This commit is contained in:
Paul Hauner 2019-05-06 09:26:58 +10:00
parent aeb17c73f6
commit 480c5ff160
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
7 changed files with 104 additions and 37 deletions

View File

@ -4,6 +4,15 @@ extern crate criterion;
use criterion::black_box; use criterion::black_box;
use criterion::{Benchmark, Criterion}; use criterion::{Benchmark, Criterion};
use ssz::{Decodable, Encodable}; use ssz::{Decodable, Encodable};
use ssz_derive::{Decode, Encode};
#[derive(Clone, Copy, Encode, Decode)]
pub struct FixedLen {
a: u64,
b: u64,
c: u64,
d: u64,
}
fn criterion_benchmark(c: &mut Criterion) { fn criterion_benchmark(c: &mut Criterion) {
let n = 8196; let n = 8196;
@ -32,6 +41,39 @@ fn criterion_benchmark(c: &mut Criterion) {
}) })
.sample_size(100), .sample_size(100),
); );
let fixed_len = FixedLen {
a: 42,
b: 42,
c: 42,
d: 42,
};
let fixed_len_vec: Vec<FixedLen> = vec![fixed_len; 8196];
let vec = fixed_len_vec.clone();
c.bench(
&format!("vec_of_{}_struct", n),
Benchmark::new("as_ssz_bytes", move |b| {
b.iter_with_setup(|| vec.clone(), |vec| black_box(vec.as_ssz_bytes()))
})
.sample_size(100),
);
let vec = fixed_len_vec.clone();
let bytes = vec.as_ssz_bytes();
c.bench(
&format!("vec_of_{}_struct", n),
Benchmark::new("from_ssz_bytes", move |b| {
b.iter_with_setup(
|| bytes.clone(),
|bytes| {
let vec: Vec<u64> = Vec::from_ssz_bytes(&bytes).unwrap();
black_box(vec)
},
)
})
.sample_size(100),
);
} }
criterion_group!(benches, criterion_benchmark); criterion_group!(benches, criterion_benchmark);

View File

@ -0,0 +1,32 @@
//! Encode and decode a list many times.
//!
//! Useful for `cargo flamegraph`.
use ssz::{Decodable, Encodable};
use ssz_derive::{Decode, Encode};
#[derive(Clone, Copy, Encode, Decode)]
pub struct FixedLen {
a: u64,
b: u64,
c: u64,
d: u64,
}
fn main() {
let fixed_len = FixedLen {
a: 42,
b: 42,
c: 42,
d: 42,
};
let vec: Vec<FixedLen> = vec![fixed_len; 8196];
let output: Vec<Vec<u64>> = (0..40_000)
.into_iter()
.map(|_| Vec::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap())
.collect();
println!("{}", output.len());
}

View File

@ -1,4 +1,4 @@
use ssz::{Decodable, DecodeError, Encodable, SszDecoderBuilder, SszEncoder, SszStream}; use ssz::{Decodable, DecodeError, Encodable, SszDecoderBuilder, SszEncoder};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Foo { pub struct Foo {
@ -23,7 +23,7 @@ impl Encodable for Foo {
encoder.append(&self.b); encoder.append(&self.b);
encoder.append(&self.c); encoder.append(&self.c);
buf.append(&mut encoder.drain()); encoder.drain_onto(buf);
} }
} }

View File

@ -32,10 +32,14 @@ pub struct SszEncoder {
} }
impl SszEncoder { impl SszEncoder {
pub fn list(num_fixed_bytes: usize) -> Self {
Self::container(num_fixed_bytes)
}
pub fn container(num_fixed_bytes: usize) -> Self { pub fn container(num_fixed_bytes: usize) -> Self {
Self { Self {
offset: num_fixed_bytes, offset: num_fixed_bytes,
fixed_bytes: vec![], fixed_bytes: Vec::with_capacity(num_fixed_bytes),
variable_bytes: vec![], variable_bytes: vec![],
} }
} }
@ -51,10 +55,9 @@ impl SszEncoder {
} }
} }
pub fn drain(mut self) -> Vec<u8> { pub fn drain_onto(mut self, buf: &mut Vec<u8>) {
self.fixed_bytes.append(&mut self.variable_bytes); buf.append(&mut self.fixed_bytes);
buf.append(&mut self.variable_bytes);
self.fixed_bytes
} }
} }
@ -63,6 +66,7 @@ pub struct VariableLengths {
pub variable_bytes_length: usize, pub variable_bytes_length: usize,
} }
/*
/// Provides a buffer for appending SSZ values. /// Provides a buffer for appending SSZ values.
#[derive(Default)] #[derive(Default)]
pub struct SszStream { pub struct SszStream {
@ -152,6 +156,7 @@ impl SszStream {
self.fixed_bytes self.fixed_bytes
} }
} }
*/
/// Encode `len` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length. /// Encode `len` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length.
/// ///

View File

@ -31,7 +31,6 @@ impl<T: Encodable> Encodable for Vec<T> {
} }
fn ssz_append(&self, buf: &mut Vec<u8>) { fn ssz_append(&self, buf: &mut Vec<u8>) {
if T::is_ssz_fixed_len() { if T::is_ssz_fixed_len() {
buf.reserve(T::ssz_fixed_len() * self.len()); buf.reserve(T::ssz_fixed_len() * self.len());
@ -39,28 +38,13 @@ impl<T: Encodable> Encodable for Vec<T> {
item.ssz_append(buf); item.ssz_append(buf);
} }
} else { } else {
/* let mut encoder = SszEncoder::list(self.len() * BYTES_PER_LENGTH_OFFSET);
for item in self {
let mut substream = SszStream::new();
item.ssz_append(&mut substream);
s.append_variable_bytes(&substream.drain());
}
*/
let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET;
let mut fixed = Vec::with_capacity(offset);
let mut variable = vec![];
for item in self { for item in self {
fixed.append(&mut encode_length(offset)); encoder.append(item);
let mut bytes = item.as_ssz_bytes();
offset += bytes.len();
variable.append(&mut bytes);
} }
buf.append(&mut fixed); encoder.drain_onto(buf);
buf.append(&mut variable);
} }
} }
} }

View File

@ -17,21 +17,19 @@ mod decode;
mod encode; mod encode;
pub use decode::{Decodable, DecodeError, SszDecoderBuilder}; pub use decode::{Decodable, DecodeError, SszDecoderBuilder};
pub use encode::{Encodable, SszEncoder, SszStream}; pub use encode::{Encodable, SszEncoder};
pub const BYTES_PER_LENGTH_OFFSET: usize = 4; pub const BYTES_PER_LENGTH_OFFSET: usize = 4;
pub const MAX_LENGTH_VALUE: usize = 1 << (BYTES_PER_LENGTH_OFFSET * 8) - 1; pub const MAX_LENGTH_VALUE: usize = 1 << (BYTES_PER_LENGTH_OFFSET * 8) - 1;
/// Convenience function to SSZ encode an object supporting ssz::Encode. /// Convenience function to SSZ encode an object supporting ssz::Encode.
///
/// Equivalent to `val.as_ssz_bytes()`.
pub fn ssz_encode<T>(val: &T) -> Vec<u8> pub fn ssz_encode<T>(val: &T) -> Vec<u8>
where where
T: Encodable, T: Encodable,
{ {
let mut buf = vec![]; val.as_ssz_bytes()
val.ssz_append(&mut buf);
buf
} }
/* /*

View File

@ -1,4 +1,4 @@
#![recursion_limit="128"] #![recursion_limit = "128"]
extern crate proc_macro; extern crate proc_macro;
@ -81,6 +81,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
let field_idents = get_serializable_named_field_idents(&struct_data); let field_idents = get_serializable_named_field_idents(&struct_data);
let field_types_a = get_serializable_field_types(&struct_data); let field_types_a = get_serializable_field_types(&struct_data);
let field_types_b = field_types_a.clone(); let field_types_b = field_types_a.clone();
let field_types_c = field_types_a.clone();
let output = quote! { let output = quote! {
impl ssz::Encodable for #name { impl ssz::Encodable for #name {
@ -102,14 +103,19 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
} }
} }
fn as_ssz_bytes(&self) -> Vec<u8> { fn ssz_append(&self, buf: &mut Vec<u8>) {
let mut stream = ssz::SszStream::new(); let offset = #(
<#field_types_c as ssz::Encodable>::ssz_fixed_len() +
)*
0;
let mut encoder = ssz::SszEncoder::container(offset);
#( #(
stream.append(&self.#field_idents); encoder.append(&self.#field_idents);
)* )*
stream.drain() encoder.drain_onto(buf);
} }
} }
}; };