From 9788561ff6f6b52eba7ecfa18de034d736d20cd1 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Tue, 23 May 2023 21:05:32 +1200 Subject: [PATCH 1/3] better performance with object pooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit at the moment is broken, but bench is very promising: ``` time: [14.653 µs 14.666 µs 14.678 µs] thrpt: [68.127 Kelem/s 68.187 Kelem/s 68.245 Kelem/s] change: time: [-32.673% -32.541% -32.415%] (p = 0.00 < 0.05) thrpt: [+47.962% +48.238% +48.529%] Performance has improved. ``` --- Cargo.lock | 179 +++++++++++++++++++++++++++++++++- rust/json-canon/Cargo.toml | 1 + rust/json-canon/src/object.rs | 53 ++++++++-- rust/json-canon/src/ser.rs | 2 +- 4 files changed, 224 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62ea244..d9a5ac0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,6 +90,20 @@ dependencies = [ "itertools", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -124,6 +138,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -154,6 +178,29 @@ dependencies = [ "memchr", ] +[[package]] +name = "easy-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e5ff17f98f39dbe4214cdf737ba15729852ccc7c701462adbe406af91d6a51" +dependencies = [ + "crossbeam", + "easy_pool_proc_macro", + "once_cell", + "parking_lot", +] + +[[package]] +name = "easy_pool_proc_macro" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4e720f99fb79c02058af2ee61f5072fbc30d53fcd59d2ae0e57a0827b1fafd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "either" version = "1.8.1" @@ -213,6 +260,7 @@ name = "json-canon" version = "0.1.3" dependencies = [ "criterion", + "easy-pool", "ryu-js", "serde", "serde_derive", @@ -231,6 +279,16 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -286,6 +344,29 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "plotters" version = "0.3.4" @@ -354,6 +435,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.8.1" @@ -420,7 +510,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -434,6 +524,23 @@ dependencies = [ "serde", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.15" @@ -507,7 +614,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.15", "wasm-bindgen-shared", ] @@ -529,7 +636,7 @@ checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -580,3 +687,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/rust/json-canon/Cargo.toml b/rust/json-canon/Cargo.toml index 7131317..f864719 100644 --- a/rust/json-canon/Cargo.toml +++ b/rust/json-canon/Cargo.toml @@ -14,6 +14,7 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +easy-pool = "0.2.7" ryu-js = { version = "0.2.2", default-features = false } serde = { version = "1.0.162", default-features = false } serde_json = { version = "1.0.96", default-features = false, features = ["std", "float_roundtrip"] } diff --git a/rust/json-canon/src/object.rs b/rust/json-canon/src/object.rs index cd7f974..e41eef1 100644 --- a/rust/json-canon/src/object.rs +++ b/rust/json-canon/src/object.rs @@ -1,20 +1,31 @@ use std::{ io::{self, sink, Error, ErrorKind, Write}, + ops::{Deref, DerefMut}, str::from_utf8_unchecked, }; +use easy_pool::{Clear, EasyPoolArayQueue, PoolObjectContainer}; use serde_json::ser::{CompactFormatter, Formatter}; -#[derive(Clone, Debug)] -pub(crate) struct ObjectEntry { +#[derive(EasyPoolArayQueue, Clone, Debug)] +pub(crate) struct ObjectEntryInner { key: Vec, key_bytes: Vec, value: Vec, is_key_done: bool, } -impl ObjectEntry { - pub(crate) fn new() -> Self { +impl Clear for ObjectEntryInner { + fn clear(&mut self) { + self.key.clear(); + self.key_bytes.clear(); + self.value.clear(); + self.is_key_done = false; + } +} + +impl Default for ObjectEntryInner { + fn default() -> Self { Self { key: Vec::new(), key_bytes: Vec::new(), @@ -22,6 +33,33 @@ impl ObjectEntry { is_key_done: false, } } +} + +#[derive(Debug)] +pub(crate) struct ObjectEntry { + inner: PoolObjectContainer, +} + +impl Deref for ObjectEntry { + type Target = ObjectEntryInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ObjectEntry { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl ObjectEntry { + pub(crate) fn new() -> Self { + Self { + inner: ObjectEntryInner::create(), + } + } #[inline] pub(crate) fn end_key(&mut self) { @@ -50,7 +88,8 @@ impl ObjectEntry { #[inline] pub(crate) fn scope_with_key(&mut self) -> io::Result { let writer = if self.is_in_key() { - EitherWriter::Left(BothWriter::new(&mut self.key, &mut self.key_bytes)) + EitherWriter::Left(&mut self.key) + // EitherWriter::Left(BothWriter::new(&mut self.key, &mut self.key_bytes)) } else { EitherWriter::Right(&mut self.value) }; @@ -84,7 +123,7 @@ impl ObjectEntry { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct Object { entries: Vec, } @@ -164,7 +203,7 @@ impl Object { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct ObjectStack { objects: Vec, } diff --git a/rust/json-canon/src/ser.rs b/rust/json-canon/src/ser.rs index f29c835..cf2c415 100644 --- a/rust/json-canon/src/ser.rs +++ b/rust/json-canon/src/ser.rs @@ -71,7 +71,7 @@ static MAX_SAFE_INTEGER_I64: i64 = 9_007_199_254_740_991; static MAX_SAFE_INTEGER_U128: u128 = 9_007_199_254_740_991; static MAX_SAFE_INTEGER_I128: i128 = 9_007_199_254_740_991; -#[derive(Clone, Debug)] +#[derive(Debug)] #[repr(transparent)] pub struct CanonicalFormatter { stack: ObjectStack, From ca1991eaca7a9ae7475d2a87b8d4a26f59cb3235 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Tue, 23 May 2023 21:44:11 +1200 Subject: [PATCH 2/3] bring easy-pool code inside, solve issue. also instantiate vecs with capacity --- Cargo.lock | 171 +--------------------------------- rust/json-canon/Cargo.toml | 3 +- rust/json-canon/src/lib.rs | 1 + rust/json-canon/src/object.rs | 56 ++++------- rust/json-canon/src/pool.rs | 110 ++++++++++++++++++++++ 5 files changed, 138 insertions(+), 203 deletions(-) create mode 100644 rust/json-canon/src/pool.rs diff --git a/Cargo.lock b/Cargo.lock index d9a5ac0..7a8a148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,20 +90,6 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -178,29 +164,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "easy-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e5ff17f98f39dbe4214cdf737ba15729852ccc7c701462adbe406af91d6a51" -dependencies = [ - "crossbeam", - "easy_pool_proc_macro", - "once_cell", - "parking_lot", -] - -[[package]] -name = "easy_pool_proc_macro" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4e720f99fb79c02058af2ee61f5072fbc30d53fcd59d2ae0e57a0827b1fafd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "either" version = "1.8.1" @@ -260,7 +223,8 @@ name = "json-canon" version = "0.1.3" dependencies = [ "criterion", - "easy-pool", + "crossbeam-queue", + "lazy_static", "ryu-js", "serde", "serde_derive", @@ -279,16 +243,6 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.17" @@ -344,29 +298,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - [[package]] name = "plotters" version = "0.3.4" @@ -435,15 +366,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" version = "1.8.1" @@ -510,7 +432,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn", ] [[package]] @@ -524,23 +446,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.15" @@ -614,7 +519,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.15", + "syn", "wasm-bindgen-shared", ] @@ -636,7 +541,7 @@ checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -687,69 +592,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/rust/json-canon/Cargo.toml b/rust/json-canon/Cargo.toml index f864719..0810ffe 100644 --- a/rust/json-canon/Cargo.toml +++ b/rust/json-canon/Cargo.toml @@ -14,7 +14,8 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -easy-pool = "0.2.7" +crossbeam-queue = "0.3.8" +lazy_static = "1.4.0" ryu-js = { version = "0.2.2", default-features = false } serde = { version = "1.0.162", default-features = false } serde_json = { version = "1.0.96", default-features = false, features = ["std", "float_roundtrip"] } diff --git a/rust/json-canon/src/lib.rs b/rust/json-canon/src/lib.rs index 45b4199..7986e5a 100644 --- a/rust/json-canon/src/lib.rs +++ b/rust/json-canon/src/lib.rs @@ -35,6 +35,7 @@ //! mod object; +mod pool; mod ser; pub use self::ser::{to_string, to_vec, to_writer}; diff --git a/rust/json-canon/src/object.rs b/rust/json-canon/src/object.rs index e41eef1..db10f0c 100644 --- a/rust/json-canon/src/object.rs +++ b/rust/json-canon/src/object.rs @@ -1,21 +1,27 @@ use std::{ io::{self, sink, Error, ErrorKind, Write}, - ops::{Deref, DerefMut}, str::from_utf8_unchecked, + sync::Arc, }; -use easy_pool::{Clear, EasyPoolArayQueue, PoolObjectContainer}; +use lazy_static::lazy_static; use serde_json::ser::{CompactFormatter, Formatter}; -#[derive(EasyPoolArayQueue, Clone, Debug)] -pub(crate) struct ObjectEntryInner { +use crate::pool::{Clear, Pool, PoolObjectContainer}; + +lazy_static! { + static ref POOL: Arc> = Arc::new(Pool::default()); +} + +#[derive(Clone, Debug)] +pub(crate) struct ObjectEntry { key: Vec, key_bytes: Vec, value: Vec, is_key_done: bool, } -impl Clear for ObjectEntryInner { +impl Clear for ObjectEntry { fn clear(&mut self) { self.key.clear(); self.key_bytes.clear(); @@ -24,41 +30,20 @@ impl Clear for ObjectEntryInner { } } -impl Default for ObjectEntryInner { +impl Default for ObjectEntry { fn default() -> Self { Self { - key: Vec::new(), - key_bytes: Vec::new(), - value: Vec::new(), + key: Vec::with_capacity(16), + key_bytes: Vec::with_capacity(16), + value: Vec::with_capacity(64), is_key_done: false, } } } -#[derive(Debug)] -pub(crate) struct ObjectEntry { - inner: PoolObjectContainer, -} - -impl Deref for ObjectEntry { - type Target = ObjectEntryInner; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ObjectEntry { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - impl ObjectEntry { - pub(crate) fn new() -> Self { - Self { - inner: ObjectEntryInner::create(), - } + pub(crate) fn new() -> PoolObjectContainer { + Pool::create(POOL.clone()) } #[inline] @@ -88,8 +73,7 @@ impl ObjectEntry { #[inline] pub(crate) fn scope_with_key(&mut self) -> io::Result { let writer = if self.is_in_key() { - EitherWriter::Left(&mut self.key) - // EitherWriter::Left(BothWriter::new(&mut self.key, &mut self.key_bytes)) + EitherWriter::Left(BothWriter::new(&mut self.key, &mut self.key_bytes)) } else { EitherWriter::Right(&mut self.value) }; @@ -125,7 +109,7 @@ impl ObjectEntry { #[derive(Debug)] pub(crate) struct Object { - entries: Vec, + entries: Vec>, } impl Object { @@ -135,7 +119,7 @@ impl Object { } } - pub(crate) fn current_entry(&mut self) -> io::Result<&mut ObjectEntry> { + pub(crate) fn current_entry(&mut self) -> io::Result<&mut PoolObjectContainer> { self.entries.last_mut().ok_or_else(|| { Error::new( ErrorKind::InvalidData, diff --git a/rust/json-canon/src/pool.rs b/rust/json-canon/src/pool.rs new file mode 100644 index 0000000..5dc55fd --- /dev/null +++ b/rust/json-canon/src/pool.rs @@ -0,0 +1,110 @@ +use std::{ + fmt::Debug, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr, + sync::Arc, +}; + +use crossbeam_queue::ArrayQueue; + +pub trait Clear { + fn clear(&mut self); +} + +#[derive(Debug)] +pub struct Pool { + pub(crate) values: ArrayQueue, + pub(crate) max_size: usize, +} + +impl Pool +where + T: Clear, +{ + #[inline] + pub fn new(capacity: usize) -> Self { + Self { + values: ArrayQueue::new(capacity), + max_size: capacity, + } + } + + #[inline] + pub fn create(self: Arc) -> PoolObjectContainer + where + T: Clear + Default, + { + let val = self.values.pop().unwrap_or_else(|| Default::default()); + PoolObjectContainer::new(val, self) + } + + #[inline] + pub fn max_size(&self) -> usize { + self.max_size + } + + #[inline] + pub fn len(&self) -> usize { + self.values.len() + } + + #[inline] + pub fn push(&self, value: T) -> Result<(), T> { + self.values.push(value) + } +} + +impl Default for Pool { + #[inline] + fn default() -> Self { + Self::new(1024) + } +} + +#[derive(Debug)] +pub struct PoolObjectContainer { + pool: Arc>, + inner: ManuallyDrop, +} + +impl PoolObjectContainer { + #[inline] + fn new(val: T, pool: Arc>) -> Self { + Self { + pool, + inner: ManuallyDrop::new(val), + } + } +} + +impl Deref for PoolObjectContainer { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for PoolObjectContainer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Drop for PoolObjectContainer { + fn drop(&mut self) { + let val = unsafe { ptr::read(&self.inner) }; + let mut val = ManuallyDrop::into_inner(val); + + let pool = &self.pool; + if pool.len() >= pool.max_size() { + drop(val); + } else { + val.clear(); + if let Err(val) = pool.push(val) { + drop(val); + } + } + } +} From 7407161c327e6d7cc953239184ee6ac5b33d3145 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Tue, 23 May 2023 22:22:59 +1200 Subject: [PATCH 3/3] reduce the pool capacity --- rust/json-canon/src/object.rs | 8 ++++---- rust/json-canon/src/pool.rs | 11 +++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/rust/json-canon/src/object.rs b/rust/json-canon/src/object.rs index db10f0c..a31cabe 100644 --- a/rust/json-canon/src/object.rs +++ b/rust/json-canon/src/object.rs @@ -10,7 +10,7 @@ use serde_json::ser::{CompactFormatter, Formatter}; use crate::pool::{Clear, Pool, PoolObjectContainer}; lazy_static! { - static ref POOL: Arc> = Arc::new(Pool::default()); + static ref POOL: Arc> = Arc::new(Pool::with_capacity(256)); } #[derive(Clone, Debug)] @@ -33,9 +33,9 @@ impl Clear for ObjectEntry { impl Default for ObjectEntry { fn default() -> Self { Self { - key: Vec::with_capacity(16), - key_bytes: Vec::with_capacity(16), - value: Vec::with_capacity(64), + key: Vec::with_capacity(8), + key_bytes: Vec::with_capacity(8), + value: Vec::with_capacity(16), is_key_done: false, } } diff --git a/rust/json-canon/src/pool.rs b/rust/json-canon/src/pool.rs index 5dc55fd..fbf50de 100644 --- a/rust/json-canon/src/pool.rs +++ b/rust/json-canon/src/pool.rs @@ -23,7 +23,7 @@ where T: Clear, { #[inline] - pub fn new(capacity: usize) -> Self { + pub fn with_capacity(capacity: usize) -> Self { Self { values: ArrayQueue::new(capacity), max_size: capacity, @@ -55,13 +55,6 @@ where } } -impl Default for Pool { - #[inline] - fn default() -> Self { - Self::new(1024) - } -} - #[derive(Debug)] pub struct PoolObjectContainer { pool: Arc>, @@ -81,12 +74,14 @@ impl PoolObjectContainer { impl Deref for PoolObjectContainer { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for PoolObjectContainer { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }