diff --git a/Cargo.toml b/Cargo.toml index fa03539cea..ee68028b77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,3 +3,7 @@ members = [ "rust/sbp", "rust/sbp2json" ] + +[profile.release] +lto = true +codegen-units = 1 diff --git a/generator/sbpg/targets/resources/sbp2json-cargo.toml b/generator/sbpg/targets/resources/sbp2json-cargo.toml index 69b42e4f2d..d74a04aabd 100644 --- a/generator/sbpg/targets/resources/sbp2json-cargo.toml +++ b/generator/sbpg/targets/resources/sbp2json-cargo.toml @@ -19,14 +19,12 @@ features = ["json"] env_logger = "0.8" serde_json = "1.0" structopt = "0.3" +mimalloc = { version = "0.1", default-features = false } [dependencies.dencode] version = "0.3.0" default-features = false -[target.'cfg(all(not(windows), not(target_env = "musl")))'.dependencies] -jemallocator = "0.3" - [dev-dependencies] sha2 = "0.8" hex = "0.4" diff --git a/rust/sbp/src/json/de.rs b/rust/sbp/src/json/de.rs index a18d1e5424..be21da9596 100644 --- a/rust/sbp/src/json/de.rs +++ b/rust/sbp/src/json/de.rs @@ -9,7 +9,7 @@ use crate::{ de::Frame, json::{Json2JsonInput, JsonError, JsonInput}, messages::Sbp, - MAX_PAYLOAD_LEN, + BUFLEN, }; /// Deserialize the IO stream into an iterator of messages. @@ -40,7 +40,7 @@ struct JsonDecoder { impl JsonDecoder { fn new() -> Self { JsonDecoder { - payload_buf: Vec::with_capacity(MAX_PAYLOAD_LEN), + payload_buf: Vec::with_capacity(BUFLEN), } } diff --git a/rust/sbp/src/json/ser.rs b/rust/sbp/src/json/ser.rs index 3ceecf4e93..50ec22ed71 100644 --- a/rust/sbp/src/json/ser.rs +++ b/rust/sbp/src/json/ser.rs @@ -11,10 +11,10 @@ use crate::{ de::Frame, json::{CommonJson, HaskellishFloatFormatter, Json2JsonInput, Json2JsonOutput}, messages::Sbp, - SbpMessage, CRC_LEN, HEADER_LEN, MAX_PAYLOAD_LEN, PREAMBLE, + SbpMessage, BUFLEN, CRC_LEN, HEADER_LEN, PREAMBLE, }; -const BASE64_MAX_PAYLOAD_LEN: usize = MAX_PAYLOAD_LEN / 3 * 4 + 4; +const BASE64_BUFLEN: usize = BUFLEN * 4; /// Serialize the given message as JSON into the IO stream. pub fn to_writer(mut writer: W, msg: &M) -> Result<(), JsonError> @@ -22,9 +22,9 @@ where W: io::Write, M: SbpMessage + Serialize, { - let mut frame = BytesMut::new(); - let mut payload = String::new(); - let mut buf = BytesMut::new(); + let mut frame = BytesMut::with_capacity(BUFLEN); + let mut payload = String::with_capacity(BUFLEN); + let mut buf = BytesMut::with_capacity(BUFLEN); to_buffer( &mut frame, &mut payload, @@ -41,9 +41,9 @@ pub fn to_vec(msg: &M) -> Result, JsonError> where M: SbpMessage + Serialize, { - let mut frame = BytesMut::new(); - let mut payload = String::new(); - let mut buf = BytesMut::new(); + let mut frame = BytesMut::with_capacity(BUFLEN); + let mut payload = String::with_capacity(BUFLEN); + let mut buf = BytesMut::with_capacity(BUFLEN); to_buffer( &mut frame, &mut payload, @@ -114,8 +114,8 @@ struct JsonEncoderInner { impl JsonEncoderInner { fn new(formatter: F) -> Self { JsonEncoderInner { - frame_buf: BytesMut::with_capacity(MAX_PAYLOAD_LEN), - payload_buf: String::with_capacity(BASE64_MAX_PAYLOAD_LEN), + frame_buf: BytesMut::with_capacity(BUFLEN), + payload_buf: String::with_capacity(BASE64_BUFLEN), formatter, } } @@ -181,8 +181,8 @@ struct Json2JsonEncoderInner { impl Json2JsonEncoderInner { fn new(formatter: F) -> Self { Json2JsonEncoderInner { - frame_buf: BytesMut::with_capacity(MAX_PAYLOAD_LEN), - payload_buf: String::with_capacity(BASE64_MAX_PAYLOAD_LEN), + frame_buf: BytesMut::with_capacity(BUFLEN), + payload_buf: String::with_capacity(BASE64_BUFLEN), formatter, } } diff --git a/rust/sbp/src/lib.rs b/rust/sbp/src/lib.rs index 73d926e1ac..36163d8a97 100644 --- a/rust/sbp/src/lib.rs +++ b/rust/sbp/src/lib.rs @@ -91,6 +91,9 @@ pub const PREAMBLE: u8 = 0x55; /// Length of the header section. pub const HEADER_LEN: usize = 1 /*preamble*/ + 2 /*msg_type*/ + 2 /*sender_id*/ + 1 /*len*/; +/// Internal buffer length. +pub(crate) const BUFLEN: usize = 128; + /// Max length of the variable-sized payload field. pub const MAX_PAYLOAD_LEN: usize = 255; diff --git a/rust/sbp/src/ser.rs b/rust/sbp/src/ser.rs index 2e1faf9e91..787e8233d5 100644 --- a/rust/sbp/src/ser.rs +++ b/rust/sbp/src/ser.rs @@ -6,7 +6,7 @@ use dencode::{Encoder, FramedWrite, IterSinkExt}; use crate::wire_format::WireFormat; use crate::{Sbp, SbpMessage}; -use crate::{MAX_PAYLOAD_LEN, PREAMBLE}; +use crate::{BUFLEN, MAX_PAYLOAD_LEN, PREAMBLE}; /// Serialize the given message into the IO stream. /// @@ -36,7 +36,7 @@ where W: io::Write, M: SbpMessage, { - let mut buf = BytesMut::with_capacity(msg.len()); + let mut buf = BytesMut::with_capacity(BUFLEN); to_buffer(&mut buf, msg)?; writer.write_all(&buf)?; Ok(()) @@ -65,7 +65,7 @@ where /// } /// ``` pub fn to_vec(msg: &M) -> Result, Error> { - let mut buf = BytesMut::with_capacity(msg.len()); + let mut buf = BytesMut::with_capacity(BUFLEN); to_buffer(&mut buf, msg)?; Ok(buf.to_vec()) } diff --git a/rust/sbp/src/wire_format.rs b/rust/sbp/src/wire_format.rs index 9ee6ebb7fa..afdd09fdb5 100644 --- a/rust/sbp/src/wire_format.rs +++ b/rust/sbp/src/wire_format.rs @@ -8,6 +8,8 @@ use std::{ use bytes::{Buf, BufMut}; +use crate::BUFLEN; + pub trait WireFormat: Sized { /// Minimum number of bytes this type will take in the frame. const MIN_LEN: usize = mem::size_of::(); @@ -51,7 +53,7 @@ where } fn parse_unchecked(buf: &mut B) -> Self { - let mut v = Vec::new(); + let mut v = Vec::with_capacity(BUFLEN); while buf.remaining() >= T::MIN_LEN { v.push(T::parse_unchecked(buf)); } diff --git a/rust/sbp2json/Cargo.toml b/rust/sbp2json/Cargo.toml index 6a1639cccc..12c0b5bcba 100644 --- a/rust/sbp2json/Cargo.toml +++ b/rust/sbp2json/Cargo.toml @@ -19,14 +19,12 @@ features = ["json"] env_logger = "0.8" serde_json = "1.0" structopt = "0.3" +mimalloc = { version = "0.1", default-features = false } [dependencies.dencode] version = "0.3.0" default-features = false -[target.'cfg(all(not(windows), not(target_env = "musl")))'.dependencies] -jemallocator = "0.3" - [dev-dependencies] sha2 = "0.8" hex = "0.4" diff --git a/rust/sbp2json/src/bin/json2json.rs b/rust/sbp2json/src/bin/json2json.rs index c3812beeaa..338d8fa190 100644 --- a/rust/sbp2json/src/bin/json2json.rs +++ b/rust/sbp2json/src/bin/json2json.rs @@ -5,9 +5,8 @@ use structopt::StructOpt; use converters::{json2json, Result}; -#[cfg(all(not(windows), not(target_env = "musl")))] #[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; /// Convert "compact" SBP JSON data to an "exploded" form /// diff --git a/rust/sbp2json/src/bin/json2sbp.rs b/rust/sbp2json/src/bin/json2sbp.rs index 98c10143d3..9aa36a6ece 100644 --- a/rust/sbp2json/src/bin/json2sbp.rs +++ b/rust/sbp2json/src/bin/json2sbp.rs @@ -4,9 +4,8 @@ use structopt::StructOpt; use converters::{json2sbp, Result}; -#[cfg(all(not(windows), not(target_env = "musl")))] #[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; /// Convert SBP JSON data to binary SBP. /// diff --git a/rust/sbp2json/src/bin/sbp2json.rs b/rust/sbp2json/src/bin/sbp2json.rs index dca5a1d725..5cefb93d7b 100644 --- a/rust/sbp2json/src/bin/sbp2json.rs +++ b/rust/sbp2json/src/bin/sbp2json.rs @@ -5,9 +5,8 @@ use structopt::StructOpt; use converters::{sbp2json, Result}; -#[cfg(all(not(windows), not(target_env = "musl")))] #[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; /// Convert binary SBP data to JSON. /// diff --git a/test_data/benchmark_main.py b/test_data/benchmark_main.py index 10a109b9f9..d4b6e93a57 100755 --- a/test_data/benchmark_main.py +++ b/test_data/benchmark_main.py @@ -11,16 +11,16 @@ # How much faster Rust should be than other implementations RATIOS_SBP2JSON = { - "haskell": 2.06, - "python": 26.0, + "haskell": 2.19, + "python": 17.72, } RATIOS_JSON2SBP = { - "haskell": 2.18, + "haskell": 2.75, } RATIOS_JSON2JSON = { - "haskell": 2.68, + "haskell": 3.45, } FAILED = [False]