From f627beca8c6ae73a2eb7ed1cf0401148fe6ec1f9 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 12 Apr 2024 20:11:43 -0300 Subject: [PATCH 1/2] Limit the number of byte chunks in handle_get --- Cargo.lock | 194 +++++++++++------------------------------------- Cargo.toml | 2 +- src/crud_ops.rs | 32 ++++---- 3 files changed, 62 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dccbcd1..c9f8710 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,7 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -78,11 +78,13 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.8.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener", + "event-listener 4.0.3", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -161,49 +163,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "bytecount" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" - [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" version = "1.0.83" @@ -384,35 +349,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno" -version = "0.3.8" +name = "event-listener" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] -name = "error-chain" -version = "0.12.4" +name = "event-listener" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ - "version_check", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] -name = "fastrand" -version = "2.0.1" +name = "event-listener-strategy" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] [[package]] name = "flate2" @@ -556,12 +528,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "h2" version = "0.3.26" @@ -874,12 +840,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - [[package]] name = "lock_api" version = "0.4.11" @@ -905,15 +865,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "mach2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" -dependencies = [ - "libc", -] - [[package]] name = "match_cfg" version = "0.1.0" @@ -982,21 +933,21 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8017ec3548ffe7d4cef7ac0e12b044c01164a74c0f3119420faeaf13490ad8b" +checksum = "87bfd249f570638bfb0b4f9d258e6b8cddd2a5a7d0ed47e8bb8b176bfc0e7a17" dependencies = [ "async-lock", "async-trait", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", + "event-listener 5.3.0", "futures-util", "once_cell", "parking_lot", "quanta", "rustc_version", - "skeptic", "smallvec", "tagptr", "thiserror", @@ -1117,6 +1068,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1179,26 +1136,14 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" -dependencies = [ - "bitflags 1.3.2", - "memchr", - "unicase", -] - [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", "wasi", @@ -1263,11 +1208,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", ] [[package]] @@ -1407,19 +1352,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - [[package]] name = "rustls" version = "0.21.10" @@ -1531,9 +1463,6 @@ name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" -dependencies = [ - "serde", -] [[package]] name = "serde" @@ -1596,21 +1525,6 @@ dependencies = [ "libc", ] -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.9" @@ -1719,19 +1633,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "thiserror" version = "1.0.50" @@ -1915,15 +1816,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.14" diff --git a/Cargo.toml b/Cargo.toml index 1b0792b..552a3f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ anyhow = { version = "1", features = ["backtrace"] } once_cell = "1.18" async-channel = "1.9.0" crossbeam-queue = "0.3.8" -moka = { version = "0.12.0", features = ["future"] } +moka = { version = "0.12.6", features = ["future"] } url = "2.4" serde = "1" serde_json = "1" diff --git a/src/crud_ops.rs b/src/crud_ops.rs index 51ccdc5..e638af8 100644 --- a/src/crud_ops.rs +++ b/src/crud_ops.rs @@ -95,24 +95,28 @@ pub(crate) async fn handle_get(slice: &mut [u8], path: &Path, config: &Config) - // Single part Get let body = client.get(path).await?; - let mut chunks = body.into_stream().collect::>().await; - if let Some(pos) = chunks.iter().position(|result| result.is_err()) { - let e = chunks.remove(pos).err().expect("already checked for error"); - tracing::warn!("Error while fetching a chunk: {}", e); - return Err(e.into()); - } + let mut batch_stream = body.into_stream().chunks(8); let mut received_bytes = 0; - for result in chunks { - let chunk = result.expect("checked `chunks` for errors before calling `spawn`"); - let len = chunk.len(); + while let Some(batch) = batch_stream.next().await { + for result in batch { + let chunk = match result { + Ok(c) => c, + Err(e) => { + tracing::warn!("Error while fetching a chunk: {}", e); + return Err(e.into()); + } + }; - if received_bytes + len > slice.len() { - return Err(anyhow!("Supplied buffer was too small")); - } + let len = chunk.len(); + + if received_bytes + len > slice.len() { + return Err(anyhow!("Supplied buffer was too small")); + } - slice[received_bytes..(received_bytes + len)].copy_from_slice(&chunk); - received_bytes += len; + slice[received_bytes..(received_bytes + len)].copy_from_slice(&chunk); + received_bytes += len; + } } Ok(received_bytes) From 22555cc31a424c9b4c8415961c5155ed2d71a126 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 18 Apr 2024 13:16:44 -0300 Subject: [PATCH 2/2] Adds custom allocator to track memory live_bytes --- Cargo.lock | 196 ++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 14 +++- benches/baseline.rs | 61 ++++++++++++++ benches/overhead.rs | 61 ++++++++++++++ src/lib.rs | 11 +++ src/metrics.rs | 93 +++++++++++++++++++++ 6 files changed, 429 insertions(+), 7 deletions(-) create mode 100644 benches/baseline.rs create mode 100644 benches/overhead.rs create mode 100644 src/metrics.rs diff --git a/Cargo.lock b/Cargo.lock index c9f8710..9756506 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anyhow" version = "1.0.75" @@ -98,6 +104,17 @@ dependencies = [ "syn 2.0.40", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -169,6 +186,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.0.83" @@ -198,6 +221,54 @@ dependencies = [ "windows-targets 0.52.0", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cmake" version = "0.1.50" @@ -241,6 +312,40 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -283,6 +388,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -540,13 +651,29 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.3" @@ -559,6 +686,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.3" @@ -742,6 +878,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -749,7 +895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -779,6 +925,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -980,7 +1135,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.3", "libc", ] @@ -1005,7 +1160,7 @@ dependencies = [ "futures", "humantime", "hyper", - "itertools", + "itertools 0.12.1", "md-5", "parking_lot", "percent-encoding", @@ -1031,6 +1186,7 @@ dependencies = [ "async-compression", "backoff", "bytes", + "criterion", "crossbeam-queue", "flate2", "futures-util", @@ -1056,12 +1212,24 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "overload" version = "0.1.1" @@ -1633,6 +1801,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + [[package]] name = "thiserror" version = "1.0.50" @@ -1655,14 +1829,24 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 552a3f2..574b559 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,18 @@ name = "object_store_ffi" version = "0.6.4" edition = "2021" +[[bench]] +harness = false +name = "baseline" + +[[bench]] +harness = false +name = "overhead" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] +bench = false # https://doc.rust-lang.org/cargo/reference/profiles.html [profile.release] @@ -36,3 +45,6 @@ backoff = "0.4" hyper = { version = "0.14", default-features = false } flate2 = { version = "1.0.28", features=["zlib-ng"], default-features = false} async-compression = { version = "0.4.6", default-features = false, features = ["tokio", "gzip", "zlib", "deflate", "zstd"] } + +[dev-dependencies] +criterion = { version = "0.4", default-features = false, features = ["cargo_bench_support", "html_reports"] } diff --git a/benches/baseline.rs b/benches/baseline.rs new file mode 100644 index 0000000..79aec5b --- /dev/null +++ b/benches/baseline.rs @@ -0,0 +1,61 @@ +use std::{time::{Duration, Instant}, sync::atomic::AtomicBool}; + +use criterion::{criterion_group, criterion_main, Criterion}; + +pub static STOP: AtomicBool = AtomicBool::new(false); + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("system allocation", |b| { + // This simply measures the overhead of using the system allocator normally. + b.iter(|| Vec::::with_capacity(128)); + }); + + c.bench_function("system allocation multithreaded", |b| { + // This simply measures the overhead of using the system allocator normally. + b.iter_custom(|iters| { + let start = Instant::now(); + let n = 4; + let mut handles = vec![]; + for _t in 0..n { + handles.push(std::thread::spawn(move || { + for _i in 0..(iters / n) { + criterion::black_box(Vec::::with_capacity(128)); + } + })); + } + + for handle in handles { + handle.join().unwrap(); + } + + start.elapsed() + }); + }); + c.bench_function("system allocation incremental", |b| { + // This simply measures the overhead of using the system allocator normally. + b.iter_custom(|iters| { + let mut data = Vec::with_capacity(100 * 1024 * 1024); + let start = Instant::now(); + for i in 0..iters { + if data.len() < 100 * 1024 * 1024 { + data.push(Box::new(i)); + } else { + data.clear(); + data.push(Box::new(i)); + } + } + start.elapsed() + }); + }); +} + +criterion_group!( + name = benches; + config = Criterion::default() + .significance_level(0.02) + .noise_threshold(0.05) + .measurement_time(Duration::from_secs(10)) + .warm_up_time(Duration::from_secs(3)); + targets = criterion_benchmark +); +criterion_main!(benches); diff --git a/benches/overhead.rs b/benches/overhead.rs new file mode 100644 index 0000000..871225a --- /dev/null +++ b/benches/overhead.rs @@ -0,0 +1,61 @@ +use std::{sync::atomic::AtomicBool, time::Instant}; + +use criterion::{criterion_group, criterion_main, Criterion}; + +pub static STOP: AtomicBool = AtomicBool::new(false); + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("instrumented allocation", |b| { + b.iter(|| Vec::::with_capacity(128)); + }); + + + c.bench_function("instrumented allocation multithreaded", |b| { + b.iter_custom(|iters| { + let start = Instant::now(); + let n = 4; + let mut handles = vec![]; + for _t in 0..n { + handles.push(std::thread::spawn(move || { + for _i in 0..(iters / n) { + criterion::black_box(Vec::::with_capacity(128)); + } + })); + } + + for handle in handles { + handle.join().unwrap(); + } + + start.elapsed() + }); + }); + + c.bench_function("instrumented allocation incremental", |b| { + // This simply measures the overhead of using the system allocator normally. + b.iter_custom(|iters| { + let mut data = Vec::with_capacity(100 * 1024 * 1024); + let start = Instant::now(); + for i in 0..iters { + if data.len() < 100 * 1024 * 1024 { + data.push(Box::new(i)); + } else { + data.clear(); + data.push(Box::new(i)); + } + } + start.elapsed() + }); + }); +} + +criterion_group!( + name = benches; + config = Criterion::default() + .significance_level(0.02) + .noise_threshold(0.05) + .measurement_time(std::time::Duration::from_secs(10)) + .warm_up_time(std::time::Duration::from_secs(3)); + targets = criterion_benchmark +); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index cee30b0..5a831d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +#[global_allocator] +static GLOBAL: metrics::InstrumentedAllocator = metrics::InstrumentedAllocator {}; + use futures_util::StreamExt; use object_store::RetryConfig; use once_cell::sync::OnceCell; @@ -31,6 +34,9 @@ use crud_ops::{handle_get, handle_put, handle_delete, Response}; mod stream; use stream::{handle_get_stream, handle_put_stream, GetStreamResponse, PutStreamResponse}; +mod metrics; +pub use metrics::{InstrumentedAllocator, METRICS}; + // Our global variables needed by our library at runtime. Note that we follow Rust's // safety rules here by making them immutable with write-exactly-once semantics using // either Lazy or OnceCell. @@ -558,3 +564,8 @@ pub extern "C" fn _trigger_panic() -> CResult { }); CResult::Error } + +#[no_mangle] +pub extern "C" fn current_metrics() -> metrics::MetricsSnapshot { + metrics::MetricsSnapshot::current() +} diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 0000000..3357f4b --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,93 @@ +use std::alloc::{GlobalAlloc, Layout, System}; +use std::sync::atomic::{AtomicI64, Ordering}; + +#[derive(Debug, Default)] +#[repr(C)] +pub struct Metrics { + live_bytes: AtomicI64 +} + +#[repr(C)] +pub struct MetricsSnapshot { + live_bytes: i64 +} + +impl MetricsSnapshot { + pub fn current() -> MetricsSnapshot { + MetricsSnapshot { + live_bytes: METRICS.live_bytes.load(Ordering::Relaxed) + } + } +} + +impl Metrics { + pub const fn new() -> Self { + Metrics { + live_bytes: AtomicI64::new(0) + } + } +} + +pub static METRICS: Metrics = Metrics::new(); + +thread_local! { + static LOCAL_METRICS: std::cell::Cell = const { std::cell::Cell::new(0) }; +} + +#[cold] +fn flush(v: i64) { + METRICS.live_bytes.fetch_add(v, Ordering::AcqRel); +} + +pub struct InstrumentedAllocator; +unsafe impl GlobalAlloc for InstrumentedAllocator { + unsafe fn alloc(&self, l: Layout) -> *mut u8 { + LOCAL_METRICS.with(|cell| { + let live_bytes = cell.get() + (l.size() as i64); + if live_bytes < 100 * 1024 { + cell.set(live_bytes); + } else { + flush(live_bytes); + cell.set(0); + } + }); + System.alloc(l) + } + + unsafe fn dealloc(&self, ptr: *mut u8, l: Layout) { + LOCAL_METRICS.with(|cell| { + let live_bytes = cell.get() - (l.size() as i64); + if live_bytes > - (100 * 1024) { + cell.set(live_bytes); + } else { + flush(live_bytes); + cell.set(0); + } + }); + System.dealloc(ptr, l); + } + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + LOCAL_METRICS.with(|cell| { + let live_bytes = cell.get() + (new_size - layout.size()) as i64; + if live_bytes.abs() < 100 * 1024 { + cell.set(live_bytes); + } else { + flush(live_bytes); + cell.set(0); + } + }); + System.realloc(ptr, layout, new_size) + } + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + LOCAL_METRICS.with(|cell| { + let live_bytes = cell.get() + (layout.size() as i64); + if live_bytes < 100 * 1024 { + cell.set(live_bytes); + } else { + flush(live_bytes); + cell.set(0); + } + }); + System.alloc_zeroed(layout) + } +}