diff --git a/Cargo.lock b/Cargo.lock index ed47b24a64..0f93377962 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,13 +9,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" dependencies = [ "bitflags 1.3.2", - "bytes", + "bytes 1.6.0", "futures-core", "futures-sink", "log", "memchr", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.12", + "tokio 1.37.0", "tokio-util", ] @@ -45,7 +45,7 @@ dependencies = [ "actix-utils", "actix-web", "bitflags 2.4.1", - "bytes", + "bytes 1.6.0", "derive_more", "futures-core", "http-range", @@ -53,7 +53,7 @@ dependencies = [ "mime", "mime_guess", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.12", "v_htmlescape", ] @@ -72,7 +72,7 @@ dependencies = [ "base64 0.21.0", "bitflags 2.4.1", "brotli", - "bytes", + "bytes 1.6.0", "bytestring", "derive_more", "encoding_rs", @@ -87,11 +87,11 @@ dependencies = [ "local-channel", "mime", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.12", "rand 0.8.5", "sha1", "smallvec", - "tokio", + "tokio 1.37.0", "tokio-util", "tracing", "zstd 0.13.0", @@ -116,7 +116,7 @@ dependencies = [ "actix-multipart-derive", "actix-utils", "actix-web", - "bytes", + "bytes 1.6.0", "derive_more", "futures-core", "futures-util", @@ -129,7 +129,7 @@ dependencies = [ "serde_json", "serde_plain", "tempfile", - "tokio", + "tokio 1.37.0", ] [[package]] @@ -165,7 +165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" dependencies = [ "futures-core", - "tokio", + "tokio 1.37.0", ] [[package]] @@ -182,7 +182,7 @@ dependencies = [ "mio", "num_cpus", "socket2 0.4.9", - "tokio", + "tokio 1.37.0", "tracing", ] @@ -194,7 +194,7 @@ checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" dependencies = [ "futures-core", "paste", - "pin-project-lite", + "pin-project-lite 0.2.12", ] [[package]] @@ -208,9 +208,9 @@ dependencies = [ "actix-utils", "futures-core", "impl-more", - "pin-project-lite", + "pin-project-lite 0.2.12", "rustls-pki-types", - "tokio", + "tokio 1.37.0", "tokio-rustls 0.25.0", "tokio-util", "tracing", @@ -223,7 +223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" dependencies = [ "local-waker", - "pin-project-lite", + "pin-project-lite 0.2.12", ] [[package]] @@ -243,7 +243,7 @@ dependencies = [ "actix-utils", "actix-web-codegen", "ahash", - "bytes", + "bytes 1.6.0", "bytestring", "cfg-if", "cookie", @@ -256,7 +256,7 @@ dependencies = [ "log", "mime", "once_cell", - "pin-project-lite", + "pin-project-lite 0.2.12", "regex", "serde", "serde_json", @@ -288,7 +288,7 @@ dependencies = [ "actix-web", "futures-core", "futures-util", - "pin-project-lite", + "pin-project-lite 0.2.12", ] [[package]] @@ -300,7 +300,7 @@ dependencies = [ "actix-http", "actix-router", "actix-web", - "bytes", + "bytes 1.6.0", "futures", "futures-util", "log", @@ -482,7 +482,7 @@ dependencies = [ "serde_json", "sparse", "thiserror", - "tokio", + "tokio 1.37.0", "tonic", "tonic-build", "tracing", @@ -520,6 +520,28 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-compression" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +dependencies = [ + "brotli", + "bytes 0.5.6", + "bzip2", + "flate2", + "futures-core", + "futures-io", + "memchr", + "pin-project-lite 0.2.12", + "tokio 0.2.25", + "tokio 0.3.7", + "tokio 1.37.0", + "xz2", + "zstd 0.11.2+zstd.1.5.2", + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "async-stream" version = "0.3.3" @@ -584,7 +606,7 @@ dependencies = [ "async-trait", "axum-core", "bitflags 1.3.2", - "bytes", + "bytes 1.6.0", "futures-util", "http 0.2.9", "http-body 0.4.5", @@ -594,7 +616,7 @@ dependencies = [ "memchr", "mime", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.12", "rustversion", "serde", "sync_wrapper", @@ -610,7 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" dependencies = [ "async-trait", - "bytes", + "bytes 1.6.0", "futures-util", "http 0.2.9", "http-body 0.4.5", @@ -797,6 +819,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.6.0" @@ -809,7 +837,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7f83e57d9154148e355404702e2694463241880b939570d7c97c014da7a69a1" dependencies = [ - "bytes", + "bytes 1.6.0", ] [[package]] @@ -838,7 +866,7 @@ name = "cancel" version = "0.0.0" dependencies = [ "thiserror", - "tokio", + "tokio 1.37.0", "tokio-util", ] @@ -1055,7 +1083,7 @@ dependencies = [ "async-trait", "atomicwrites", "bitvec", - "bytes", + "bytes 1.6.0", "cancel", "chrono", "collection", @@ -1095,7 +1123,7 @@ dependencies = [ "tempfile", "thiserror", "tinyvec", - "tokio", + "tokio 1.37.0", "tokio-util", "tonic", "tracing", @@ -1132,7 +1160,7 @@ dependencies = [ "serde", "thiserror", "thread-priority", - "tokio", + "tokio 1.37.0", "validator", ] @@ -1199,7 +1227,7 @@ dependencies = [ "serde", "serde_json", "thread_local", - "tokio", + "tokio 1.37.0", "tokio-stream", "tonic", "tracing", @@ -1521,6 +1549,18 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "dataset" +version = "0.0.0" +dependencies = [ + "anyhow", + "async-compression", + "flate2", + "indicatif", + "project-root", + "reqwest", +] + [[package]] name = "debugid" version = "0.8.0" @@ -1787,9 +1827,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide 0.7.1", @@ -1967,7 +2007,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.12", "pin-utils", "slab", ] @@ -2126,7 +2166,7 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ - "bytes", + "bytes 1.6.0", "fnv", "futures-core", "futures-sink", @@ -2134,7 +2174,7 @@ dependencies = [ "http 0.2.9", "indexmap 2.2.6", "slab", - "tokio", + "tokio 1.37.0", "tokio-util", "tracing", ] @@ -2145,7 +2185,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" dependencies = [ - "bytes", + "bytes 1.6.0", "fnv", "futures-core", "futures-sink", @@ -2153,7 +2193,7 @@ dependencies = [ "http 1.0.0", "indexmap 2.2.6", "slab", - "tokio", + "tokio 1.37.0", "tokio-util", "tracing", ] @@ -2266,7 +2306,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "bytes", + "bytes 1.6.0", "fnv", "itoa", ] @@ -2277,7 +2317,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" dependencies = [ - "bytes", + "bytes 1.6.0", "fnv", "itoa", ] @@ -2288,9 +2328,9 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", + "bytes 1.6.0", "http 0.2.9", - "pin-project-lite", + "pin-project-lite 0.2.12", ] [[package]] @@ -2299,7 +2339,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ - "bytes", + "bytes 1.6.0", "http 1.0.0", ] @@ -2309,11 +2349,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ - "bytes", + "bytes 1.6.0", "futures-core", "http 1.0.0", "http-body 1.0.0", - "pin-project-lite", + "pin-project-lite 0.2.12", ] [[package]] @@ -2356,7 +2396,7 @@ version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ - "bytes", + "bytes 1.6.0", "futures-channel", "futures-core", "futures-util", @@ -2366,9 +2406,9 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite", + "pin-project-lite 0.2.12", "socket2 0.4.9", - "tokio", + "tokio 1.37.0", "tower-service", "tracing", "want", @@ -2380,7 +2420,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ - "bytes", + "bytes 1.6.0", "futures-channel", "futures-util", "h2 0.4.4", @@ -2388,9 +2428,9 @@ dependencies = [ "http-body 1.0.0", "httparse", "itoa", - "pin-project-lite", + "pin-project-lite 0.2.12", "smallvec", - "tokio", + "tokio 1.37.0", "want", ] @@ -2406,7 +2446,7 @@ dependencies = [ "hyper-util", "rustls 0.22.4", "rustls-pki-types", - "tokio", + "tokio 1.37.0", "tokio-rustls 0.25.0", "tower-service", ] @@ -2418,8 +2458,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ "hyper 0.14.26", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.12", + "tokio 1.37.0", "tokio-io-timeout", ] @@ -2429,15 +2469,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ - "bytes", + "bytes 1.6.0", "futures-channel", "futures-util", "http 1.0.0", "http-body 1.0.0", "hyper 1.2.0", - "pin-project-lite", + "pin-project-lite 0.2.12", "socket2 0.5.5", - "tokio", + "tokio 1.37.0", "tower", "tower-service", "tracing", @@ -3101,6 +3141,17 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "macro_rules_attribute" version = "0.2.0" @@ -3653,6 +3704,12 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + [[package]] name = "pin-project-lite" version = "0.2.12" @@ -3818,6 +3875,12 @@ dependencies = [ "hex", ] +[[package]] +name = "project-root" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bccbff07d5ed689c4087d20d7307a52ab6141edeedf487c3876a55b86cf63df" + [[package]] name = "prometheus" version = "0.13.4" @@ -3858,7 +3921,7 @@ version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ - "bytes", + "bytes 1.6.0", "prost-derive 0.11.9", ] @@ -3868,7 +3931,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ - "bytes", + "bytes 1.6.0", "prost-derive 0.12.3", ] @@ -3878,7 +3941,7 @@ version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ - "bytes", + "bytes 1.6.0", "heck 0.4.1", "itertools 0.10.5", "lazy_static", @@ -3902,7 +3965,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ - "bytes", + "bytes 1.6.0", "heck 0.4.1", "itertools 0.10.5", "log", @@ -4101,7 +4164,7 @@ dependencies = [ "tempfile", "thiserror", "tikv-jemallocator", - "tokio", + "tokio 1.37.0", "tonic", "tonic-reflection", "tower", @@ -4364,7 +4427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ "base64 0.22.0", - "bytes", + "bytes 1.6.0", "futures-channel", "futures-core", "futures-util", @@ -4381,7 +4444,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.12", "rustls 0.22.4", "rustls-pemfile 2.1.2", "rustls-pki-types", @@ -4389,7 +4452,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "tokio", + "tokio 1.37.0", "tokio-rustls 0.25.0", "tokio-util", "tower-service", @@ -4865,12 +4928,14 @@ dependencies = [ "chrono", "common", "criterion", + "dataset", "fnv", "fs_extra", "generic-tests", "geo", "geohash", "indexmap 2.2.6", + "indicatif", "io", "io-uring", "is_sorted", @@ -5213,15 +5278,21 @@ name = "sparse" version = "0.1.0" dependencies = [ "common", + "criterion", + "dataset", + "indicatif", "io", "itertools 0.12.1", "memmap2 0.9.4", "memory", "ordered-float 4.2.0", "parking_lot", + "pprof", "rand 0.8.5", "schemars", "serde", + "serde_json", + "sparse", "tempfile", "validator", ] @@ -5286,7 +5357,7 @@ dependencies = [ "tar", "tempfile", "thiserror", - "tokio", + "tokio 1.37.0", "tonic", "tracing", "url", @@ -5602,6 +5673,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "tokio" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +dependencies = [ + "bytes 0.5.6", + "pin-project-lite 0.1.12", +] + +[[package]] +name = "tokio" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46409491c9375a693ce7032101970a54f8a2010efb77e13f70788f0d84489e39" +dependencies = [ + "autocfg", + "pin-project-lite 0.2.12", +] + [[package]] name = "tokio" version = "1.37.0" @@ -5609,12 +5700,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", - "bytes", + "bytes 1.6.0", "libc", "mio", "num_cpus", "parking_lot", - "pin-project-lite", + "pin-project-lite 0.2.12", "signal-hook-registry", "socket2 0.5.5", "tokio-macros", @@ -5628,8 +5719,8 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" dependencies = [ - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.12", + "tokio 1.37.0", ] [[package]] @@ -5650,7 +5741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls 0.21.11", - "tokio", + "tokio 1.37.0", ] [[package]] @@ -5661,7 +5752,7 @@ checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ "rustls 0.22.4", "rustls-pki-types", - "tokio", + "tokio 1.37.0", ] [[package]] @@ -5671,8 +5762,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.12", + "tokio 1.37.0", ] [[package]] @@ -5681,11 +5772,11 @@ version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ - "bytes", + "bytes 1.6.0", "futures-core", "futures-sink", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.12", + "tokio 1.37.0", ] [[package]] @@ -5740,7 +5831,7 @@ dependencies = [ "async-trait", "axum", "base64 0.21.0", - "bytes", + "bytes 1.6.0", "flate2", "futures-core", "futures-util", @@ -5753,7 +5844,7 @@ dependencies = [ "pin-project", "prost 0.11.9", "rustls-pemfile 1.0.3", - "tokio", + "tokio 1.37.0", "tokio-rustls 0.24.1", "tokio-stream", "tower", @@ -5783,7 +5874,7 @@ checksum = "0543d7092032041fbeac1f2c84304537553421a11a623c2301b12ef0264862c7" dependencies = [ "prost 0.11.9", "prost-types 0.11.9", - "tokio", + "tokio 1.37.0", "tokio-stream", "tonic", ] @@ -5798,10 +5889,10 @@ dependencies = [ "futures-util", "indexmap 1.9.2", "pin-project", - "pin-project-lite", + "pin-project-lite 0.2.12", "rand 0.8.5", "slab", - "tokio", + "tokio 1.37.0", "tokio-util", "tower-layer", "tower-service", @@ -5827,7 +5918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite", + "pin-project-lite 0.2.12", "tracing-attributes", "tracing-core", ] @@ -6635,6 +6726,15 @@ dependencies = [ "libc", ] +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yada" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 804fa8e027..154ca19e1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,9 @@ fnv = "1.0" futures = "0.3.30" futures-util = "0.3.30" indexmap = { version = "2", features = ["serde"] } +indicatif = "0.17.8" parking_lot = { version = "0.12.2", features = ["deadlock_detection", "serde"] } +pprof = { version = "0.12", features = ["flamegraph", "prost-codec"] } prost = "0.11.9" prost-wkt-types = "0.4.2" reqwest = { version = "0.12.4", default-features = false, features = ["http2", "stream", "rustls-tls", "blocking"] } diff --git a/lib/collection/Cargo.toml b/lib/collection/Cargo.toml index 29f5a761f1..d09d709ff0 100644 --- a/lib/collection/Cargo.toml +++ b/lib/collection/Cargo.toml @@ -21,7 +21,7 @@ collection = { path = ".", features = ["testing"] } common = { path = "../common/common", features = ["testing"] } [target.'cfg(not(target_os = "windows"))'.dev-dependencies] -pprof = { version = "0.12", features = ["flamegraph", "prost-codec"] } +pprof = { workspace = true } [dependencies] parking_lot = { workspace = true } @@ -63,7 +63,7 @@ sparse = { path = "../sparse" } api = { path = "../api" } itertools = "0.12" -indicatif = "0.17.8" +indicatif = { workspace = true } chrono = { workspace = true } schemars = { workspace = true } tar = { workspace = true } diff --git a/lib/common/dataset/Cargo.toml b/lib/common/dataset/Cargo.toml new file mode 100644 index 0000000000..83b0d51a58 --- /dev/null +++ b/lib/common/dataset/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "dataset" +version = "0.0.0" +authors = [ + "Andrey Vasnetsov ", + "Qdrant Team ", +] +license = "Apache-2.0" +edition = "2021" +publish = false + +[dependencies] +anyhow = "1.0.82" +async-compression = {version="0.3.13", features=["all", "stream"]} +flate2 = { version = "1.0.30" } +indicatif = { workspace = true } +project-root = "0.2.2" +reqwest = { workspace = true } diff --git a/lib/common/dataset/src/lib.rs b/lib/common/dataset/src/lib.rs new file mode 100644 index 0000000000..a8a7c921f9 --- /dev/null +++ b/lib/common/dataset/src/lib.rs @@ -0,0 +1,108 @@ +use std::fs::{create_dir_all, File}; +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, Context, Result}; +use flate2::read::GzDecoder; +use indicatif::{ProgressBar, ProgressDrawTarget}; + +pub enum Dataset { + // https://github.com/qdrant/sparse-vectors-experiments + SpladeWikiMovies, + + // https://github.com/qdrant/sparse-vectors-benchmark + NeurIps2023Full, + NeurIps2023_1M, + NeurIps2023Small, + NeurIps2023Queries, +} + +impl Dataset { + pub fn download(&self) -> Result { + download_cached(&self.url()) + } + + fn url(&self) -> String { + const NEUR_IPS_2023_BASE: &str = + "https://storage.googleapis.com/ann-challenge-sparse-vectors/csr"; + match self { + Dataset::SpladeWikiMovies => { + "https://storage.googleapis.com/dataset-sparse-vectors/sparse-vectors.jsonl.gz" + .to_string() + } + Dataset::NeurIps2023Full => format!("{NEUR_IPS_2023_BASE}/base_full.csr.gz"), + Dataset::NeurIps2023_1M => format!("{NEUR_IPS_2023_BASE}/base_1M.csr.gz"), + Dataset::NeurIps2023Small => format!("{NEUR_IPS_2023_BASE}/base_small.csr.gz"), + Dataset::NeurIps2023Queries => format!("{NEUR_IPS_2023_BASE}/queries.dev.csr.gz"), + } + } +} + +fn download_cached(url: &str) -> Result { + // Filename without an ".gz" extension, e.g. "base_full.csr". + let basename = { + let path = Path::new(url); + match path.extension() { + Some(gz) if gz == "gz" => path.file_stem(), + _ => path.file_name(), + } + .ok_or_else(|| anyhow!("Failed to extract basename from {url}"))? + }; + + // Cache directory, e.g. "target/datasets". + let cache_dir = workspace_dir() + .join(std::env::var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())) + .join("datasets"); + + // Cache file path, e.g. "target/datasets/base_full.csr". + let cache_path = cache_dir.join(basename); + + if cache_path.exists() { + return Ok(cache_path); + } + + eprintln!("Downloading {url} to {cache_path:?}..."); + + create_dir_all(cache_dir)?; + + let resp = reqwest::blocking::get(url)?; + if !resp.status().is_success() { + anyhow::bail!("Failed to download {url}, status: {}", resp.status()); + } + let total_size = resp.content_length(); + + // Download to a temporary file, e.g. "target/datasets/base_full.csr.tmp", to avoid + // incomplete files. + let mut tmp_fname = cache_path.clone().into_os_string(); + tmp_fname.push(".tmp"); + + // Progress bar. + let pb = ProgressBar::with_draw_target(total_size, ProgressDrawTarget::stderr_with_hz(12)); + pb.set_style( + indicatif::ProgressStyle::default_bar() + .template("{msg} {wide_bar} {bytes}/{total_bytes} (eta:{eta})") + .expect("failed to set style"), + ); + + // Download + decompress. + std::io::copy( + &mut GzDecoder::new(pb.wrap_read(resp)), + &mut File::create(&tmp_fname)?, + )?; + + std::fs::rename(&tmp_fname, &cache_path) + .with_context(|| format!("Failed to rename {tmp_fname:?} to {cache_path:?}"))?; + + Ok(cache_path) +} + +fn workspace_dir() -> PathBuf { + let output = std::process::Command::new(env!("CARGO")) + .arg("locate-project") + .arg("--workspace") + .arg("--message-format=plain") + .output() + .unwrap() + .stdout; + let cargo_path = Path::new(std::str::from_utf8(&output).unwrap().trim()); + cargo_path.parent().unwrap().to_path_buf() +} diff --git a/lib/segment/Cargo.toml b/lib/segment/Cargo.toml index 775562cdac..114273e030 100644 --- a/lib/segment/Cargo.toml +++ b/lib/segment/Cargo.toml @@ -16,6 +16,8 @@ testing = [] [dev-dependencies] criterion = "0.5" +dataset = { path = "../common/dataset" } +indicatif = { workspace = true } rmp-serde = "~1.3" rand_distr = "0.4.3" walkdir = "2.5.0" @@ -24,7 +26,7 @@ segment = { path = ".", features = ["testing"] } proptest = "1.4.0" [target.'cfg(not(target_os = "windows"))'.dev-dependencies] -pprof = { version = "0.12", features = ["flamegraph", "prost-codec"] } +pprof = { workspace = true } [dependencies] bitpacking = "0.9.2" diff --git a/lib/segment/benches/sparse_index_search.rs b/lib/segment/benches/sparse_index_search.rs index 8adac31a14..23863cc405 100644 --- a/lib/segment/benches/sparse_index_search.rs +++ b/lib/segment/benches/sparse_index_search.rs @@ -6,10 +6,13 @@ use std::sync::Arc; use common::cpu::CpuPermit; use common::types::PointOffsetType; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use dataset::Dataset; +use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; +use itertools::Itertools as _; use rand::rngs::StdRng; use rand::SeedableRng; -use segment::fixtures::sparse_fixtures::fixture_sparse_index_ram; +use segment::fixtures::sparse_fixtures::fixture_sparse_index_ram_from_iter; use segment::index::hnsw_index::num_rayon_threads; use segment::index::sparse_index::sparse_index_config::{SparseIndexConfig, SparseIndexType}; use segment::index::sparse_index::sparse_vector_index::SparseVectorIndex; @@ -17,29 +20,67 @@ use segment::index::{PayloadIndex, VectorIndex}; use segment::types::PayloadSchemaType::Keyword; use segment::types::{Condition, FieldCondition, Filter, Payload}; use serde_json::json; -use sparse::common::sparse_vector_fixture::random_positive_sparse_vector; +use sparse::common::sparse_vector::SparseVector; +use sparse::common::sparse_vector_fixture::{random_positive_sparse_vector, random_sparse_vector}; use sparse::index::inverted_index::inverted_index_mmap::InvertedIndexMmap; +use sparse::index::loaders::Csr; use tempfile::Builder; const NUM_VECTORS: usize = 50_000; const MAX_SPARSE_DIM: usize = 30_000; +const NUM_QUERIES: usize = 2048; const TOP: usize = 10; const FULL_SCAN_THRESHOLD: usize = 1; // low value to trigger index usage by default fn sparse_vector_index_search_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("sparse-vector-search-group"); + let mut rnd = StdRng::seed_from_u64(0); + let query_vectors = (0..NUM_QUERIES) + // Positive values to test pruning. + .map(|_| random_positive_sparse_vector(&mut rnd, MAX_SPARSE_DIM)) + .collect::>(); + + let mut rnd = StdRng::seed_from_u64(42); + let random_vectors = (0..NUM_VECTORS).map(|_| random_sparse_vector(&mut rnd, MAX_SPARSE_DIM)); + sparse_vector_index_search_benchmark_impl(c, "random-50k", random_vectors, &query_vectors); + + let dataset_vectors = Csr::open(Dataset::NeurIps2023_1M.download().unwrap()).unwrap(); + let query_vectors = Csr::open(Dataset::NeurIps2023Queries.download().unwrap()) + .unwrap() + .iter() + .map(|v| v.unwrap()) + .collect_vec(); + sparse_vector_index_search_benchmark_impl( + c, + "neurips2023-1M", + dataset_vectors.iter().map(|v| v.unwrap()), + &query_vectors, + ); +} + +fn sparse_vector_index_search_benchmark_impl( + c: &mut Criterion, + group: &str, + vectors: impl ExactSizeIterator, + query_vectors: &[SparseVector], +) { + let mut group = c.benchmark_group(format!("sparse_vector_index_search/{}", group)); + group.sample_size(10); + + let vectors_len = vectors.len(); let stopped = AtomicBool::new(false); - let mut rnd = StdRng::seed_from_u64(42); let data_dir = Builder::new().prefix("data_dir").tempdir().unwrap(); - let sparse_vector_index = fixture_sparse_index_ram( - &mut rnd, - NUM_VECTORS, - MAX_SPARSE_DIM, + + let sparse_vector_index = fixture_sparse_index_ram_from_iter( + progress("Indexing (1/3)", vectors_len).wrap_iter(vectors), FULL_SCAN_THRESHOLD, data_dir.path(), &stopped, + || { + let pb = progress("Indexing (2/3)", vectors_len); + move || pb.inc(1) + }, ); // adding payload on field @@ -59,11 +100,7 @@ fn sparse_vector_index_search_benchmark(c: &mut Criterion) { } drop(payload_index); - // shared query vector (positive values to test pruning) - let vector = random_positive_sparse_vector(&mut rnd, MAX_SPARSE_DIM); - eprintln!("sparse_vector size = {:#?}", vector.values.len()); - let sparse_vector = vector.clone(); - let query_vector = vector.into(); + let mut query_vector_it = query_vectors.iter().cycle(); let permit_cpu_count = num_rayon_threads(0); let permit = Arc::new(CpuPermit::dummy(permit_cpu_count as u32)); @@ -82,31 +119,41 @@ fn sparse_vector_index_search_benchmark(c: &mut Criterion) { &stopped, ) .unwrap(); + let pb = progress("Indexing (3/3)", vectors_len); sparse_vector_index_mmap - .build_index(permit, &stopped) + .build_index_with_progress(permit, &stopped, || pb.inc(1)) .unwrap(); - assert_eq!(sparse_vector_index_mmap.indexed_vector_count(), NUM_VECTORS); + pb.finish_and_clear(); + assert_eq!(sparse_vector_index_mmap.indexed_vector_count(), vectors_len); // intent: bench `search` without filter on mmap inverted index group.bench_function("mmap-inverted-index-search", |b| { - b.iter(|| { - let results = sparse_vector_index_mmap - .search(&[&query_vector], None, TOP, None, &Default::default()) - .unwrap(); + b.iter_batched( + || query_vector_it.next().unwrap().clone().into(), + |vec| { + let results = sparse_vector_index_mmap + .search(&[&vec], None, TOP, None, &Default::default()) + .unwrap(); - assert_eq!(results[0].len(), TOP); - }) + assert_eq!(results[0].len(), TOP); + }, + BatchSize::SmallInput, + ) }); // intent: bench `search` without filter group.bench_function("inverted-index-search", |b| { - b.iter(|| { - let results = sparse_vector_index - .search(&[&query_vector], None, TOP, None, &Default::default()) - .unwrap(); + b.iter_batched( + || query_vector_it.next().unwrap().clone().into(), + |vec| { + let results = sparse_vector_index + .search(&[&vec], None, TOP, None, &Default::default()) + .unwrap(); - assert_eq!(results[0].len(), TOP); - }) + assert_eq!(results[0].len(), TOP); + }, + BatchSize::SmallInput, + ) }); // filter by field @@ -116,22 +163,28 @@ fn sparse_vector_index_search_benchmark(c: &mut Criterion) { ))); // intent: bench plain search when the filtered payload key is not indexed - group.bench_function("inverted-index-filtered-plain", |b| { - b.iter(|| { - let mut prefiltered_points = None; - let results = sparse_vector_index - .search_plain( - &sparse_vector, - &filter, - TOP, - &mut prefiltered_points, - &Default::default(), - ) - .unwrap(); + if vectors_len < 100_000 { + group.bench_function("inverted-index-filtered-plain", |b| { + b.iter_batched( + || query_vector_it.next().unwrap(), + |vec| { + let mut prefiltered_points = None; + let results = sparse_vector_index + .search_plain( + vec, + &filter, + TOP, + &mut prefiltered_points, + &Default::default(), + ) + .unwrap(); - assert_eq!(results.len(), TOP); - }) - }); + assert_eq!(results.len(), TOP); + }, + BatchSize::SmallInput, + ) + }); + } let mut payload_index = sparse_vector_index.payload_index.borrow_mut(); @@ -144,42 +197,58 @@ fn sparse_vector_index_search_benchmark(c: &mut Criterion) { // intent: bench `search` when the filtered payload key is indexed group.bench_function("inverted-index-filtered-payload-index", |b| { - b.iter(|| { - let results = sparse_vector_index - .search( - &[&query_vector], - Some(&filter), - TOP, - None, - &Default::default(), - ) - .unwrap(); + b.iter_batched( + || query_vector_it.next().unwrap().clone().into(), + |vec| { + let results = sparse_vector_index + .search(&[&vec], Some(&filter), TOP, None, &Default::default()) + .unwrap(); - assert_eq!(results[0].len(), TOP); - }) + assert_eq!(results[0].len(), TOP); + }, + BatchSize::SmallInput, + ); }); // intent: bench plain search when the filtered payload key is indexed - group.bench_function("plain-filtered-payload-index", |b| { - b.iter(|| { - let mut prefiltered_points = None; - let results = sparse_vector_index - .search_plain( - &sparse_vector, - &filter, - TOP, - &mut prefiltered_points, - &Default::default(), - ) - .unwrap(); + if vectors_len < 100_000 { + group.bench_function("plain-filtered-payload-index", |b| { + b.iter_batched( + || query_vector_it.next().unwrap(), + |vec| { + let mut prefiltered_points = None; + let results = sparse_vector_index + .search_plain( + vec, + &filter, + TOP, + &mut prefiltered_points, + &Default::default(), + ) + .unwrap(); - assert_eq!(results.len(), TOP); - }) - }); + assert_eq!(results.len(), TOP); + }, + BatchSize::SmallInput, + ) + }); + } group.finish(); } +fn progress(name: &str, len: usize) -> ProgressBar { + let pb = + ProgressBar::with_draw_target(Some(len as u64), ProgressDrawTarget::stderr_with_hz(12)); + pb.set_style( + ProgressStyle::default_bar() + .template("{msg} {wide_bar} {pos}/{len} (eta:{eta})") + .unwrap(), + ); + pb.set_message(name.to_owned()); + pb +} + #[cfg(not(target_os = "windows"))] criterion_group! { name = benches; diff --git a/lib/segment/src/fixtures/sparse_fixtures.rs b/lib/segment/src/fixtures/sparse_fixtures.rs index 46d221b136..d0d9eb1faa 100644 --- a/lib/segment/src/fixtures/sparse_fixtures.rs +++ b/lib/segment/src/fixtures/sparse_fixtures.rs @@ -89,6 +89,24 @@ pub fn fixture_sparse_index_ram( data_dir: &Path, stopped: &AtomicBool, ) -> SparseVectorIndex { + fixture_sparse_index_ram_from_iter( + (0..num_vectors).map(|_| random_sparse_vector(rnd, max_dim)), + full_scan_threshold, + data_dir, + stopped, + || || (), + ) +} + +/// Prepares a sparse vector index with a given iterator of sparse vectors +pub fn fixture_sparse_index_ram_from_iter( + vectors: impl ExactSizeIterator, + full_scan_threshold: usize, + data_dir: &Path, + stopped: &AtomicBool, + progress: impl FnOnce() -> P, +) -> SparseVectorIndex { + let num_vectors = vectors.len(); let mut sparse_vector_index = fixture_open_sparse_index( data_dir, num_vectors, @@ -100,10 +118,9 @@ pub fn fixture_sparse_index_ram( let mut borrowed_storage = sparse_vector_index.vector_storage.borrow_mut(); // add points to storage - for idx in 0..num_vectors { - let vec = &random_sparse_vector(rnd, max_dim); + for (idx, vec) in vectors.enumerate() { borrowed_storage - .insert_vector(idx as PointOffsetType, vec.into()) + .insert_vector(idx as PointOffsetType, (&vec).into()) .unwrap(); } drop(borrowed_storage); @@ -114,7 +131,7 @@ pub fn fixture_sparse_index_ram( .vector_storage .borrow() .available_vector_count(), - num_vectors + num_vectors, ); // assert no points are indexed following open for RAM index @@ -124,7 +141,10 @@ pub fn fixture_sparse_index_ram( let permit = Arc::new(CpuPermit::dummy(permit_cpu_count as u32)); // build index to refresh RAM index - sparse_vector_index.build_index(permit, stopped).unwrap(); + let tick_progress = progress(); + sparse_vector_index + .build_index_with_progress(permit, stopped, tick_progress) + .unwrap(); assert_eq!(sparse_vector_index.indexed_vector_count(), num_vectors); sparse_vector_index } diff --git a/lib/segment/src/index/hnsw_index/hnsw.rs b/lib/segment/src/index/hnsw_index/hnsw.rs index 31edc91997..2931a563ab 100644 --- a/lib/segment/src/index/hnsw_index/hnsw.rs +++ b/lib/segment/src/index/hnsw_index/hnsw.rs @@ -665,7 +665,12 @@ impl VectorIndex for HNSWIndex { } } - fn build_index(&mut self, permit: Arc, stopped: &AtomicBool) -> OperationResult<()> { + fn build_index_with_progress( + &mut self, + permit: Arc, + stopped: &AtomicBool, + _tick_progress: impl FnMut(), + ) -> OperationResult<()> { // Build main index graph let id_tracker = self.id_tracker.borrow(); let vector_storage = self.vector_storage.borrow(); diff --git a/lib/segment/src/index/plain_payload_index.rs b/lib/segment/src/index/plain_payload_index.rs index 31ee799ec7..65e22d8dfa 100644 --- a/lib/segment/src/index/plain_payload_index.rs +++ b/lib/segment/src/index/plain_payload_index.rs @@ -317,10 +317,11 @@ impl VectorIndex for PlainIndex { } } - fn build_index( + fn build_index_with_progress( &mut self, _permit: Arc, _stopped: &AtomicBool, + _tick_progress: impl FnMut(), ) -> OperationResult<()> { Ok(()) } diff --git a/lib/segment/src/index/sparse_index/sparse_vector_index.rs b/lib/segment/src/index/sparse_index/sparse_vector_index.rs index f54681370e..53088386c6 100644 --- a/lib/segment/src/index/sparse_index/sparse_vector_index.rs +++ b/lib/segment/src/index/sparse_index/sparse_vector_index.rs @@ -71,6 +71,7 @@ impl SparseVectorIndex { vector_storage.clone(), path, stopped, + || (), )?; (config, inverted_index, indices_tracker) } else if config_path.exists() { @@ -114,6 +115,7 @@ impl SparseVectorIndex { vector_storage: Arc>, path: &Path, stopped: &AtomicBool, + mut tick_progress: impl FnMut(), ) -> OperationResult<(TInvertedIndex, IndicesTracker)> { let borrowed_vector_storage = vector_storage.borrow(); let borrowed_id_tracker = id_tracker.borrow(); @@ -143,6 +145,7 @@ impl SparseVectorIndex { ram_index_builder.add(id, vector); } } + tick_progress(); } Ok(( TInvertedIndex::from_ram_index(ram_index_builder.build(), path)?, @@ -440,16 +443,18 @@ impl VectorIndex for SparseVectorIndex, stopped: &AtomicBool, + tick_progress: impl FnMut(), ) -> OperationResult<()> { let (inverted_index, indices_tracker) = Self::build_inverted_index( self.id_tracker.clone(), self.vector_storage.clone(), &self.path, stopped, + tick_progress, )?; self.inverted_index = inverted_index; diff --git a/lib/segment/src/index/vector_index_base.rs b/lib/segment/src/index/vector_index_base.rs index d240d56df0..3ead70bc28 100644 --- a/lib/segment/src/index/vector_index_base.rs +++ b/lib/segment/src/index/vector_index_base.rs @@ -30,7 +30,17 @@ pub trait VectorIndex { ) -> OperationResult>>; /// Force internal index rebuild. - fn build_index(&mut self, permit: Arc, stopped: &AtomicBool) -> OperationResult<()>; + fn build_index(&mut self, permit: Arc, stopped: &AtomicBool) -> OperationResult<()> { + self.build_index_with_progress(permit, stopped, || ()) + } + + /// Force internal index rebuild. + fn build_index_with_progress( + &mut self, + permit: Arc, + stopped: &AtomicBool, + tick_progress: impl FnMut(), + ) -> OperationResult<()>; fn get_telemetry_data(&self, detail: TelemetryDetail) -> VectorIndexSearchesTelemetry; @@ -91,13 +101,28 @@ impl VectorIndex for VectorIndexEnum { } } - fn build_index(&mut self, permit: Arc, stopped: &AtomicBool) -> OperationResult<()> { + fn build_index_with_progress( + &mut self, + permit: Arc, + stopped: &AtomicBool, + tick_progress: impl FnMut(), + ) -> OperationResult<()> { match self { - VectorIndexEnum::Plain(index) => index.build_index(permit, stopped), - VectorIndexEnum::HnswRam(index) => index.build_index(permit, stopped), - VectorIndexEnum::HnswMmap(index) => index.build_index(permit, stopped), - VectorIndexEnum::SparseRam(index) => index.build_index(permit, stopped), - VectorIndexEnum::SparseMmap(index) => index.build_index(permit, stopped), + VectorIndexEnum::Plain(index) => { + index.build_index_with_progress(permit, stopped, tick_progress) + } + VectorIndexEnum::HnswRam(index) => { + index.build_index_with_progress(permit, stopped, tick_progress) + } + VectorIndexEnum::HnswMmap(index) => { + index.build_index_with_progress(permit, stopped, tick_progress) + } + VectorIndexEnum::SparseRam(index) => { + index.build_index_with_progress(permit, stopped, tick_progress) + } + VectorIndexEnum::SparseMmap(index) => { + index.build_index_with_progress(permit, stopped, tick_progress) + } } } diff --git a/lib/sparse/Cargo.toml b/lib/sparse/Cargo.toml index 92799b8890..cc21e4c453 100644 --- a/lib/sparse/Cargo.toml +++ b/lib/sparse/Cargo.toml @@ -8,6 +8,9 @@ authors = [ license = "Apache-2.0" edition = "2021" +[features] +testing = [] + [dependencies] common = { path = "../common/common" } io = { path = "../common/io" } @@ -15,9 +18,23 @@ memory = { path = "../common/memory" } memmap2 = "0.9.4" schemars = { workspace = true } serde = { workspace = true } +serde_json = { workspace = true } tempfile = "3.10.1" ordered-float = "4.2" rand = "0.8.5" validator = { workspace = true } itertools = "0.12.1" parking_lot = "0.12.2" + +[dev-dependencies] +criterion = "0.5" +dataset = { path = "../common/dataset" } +indicatif = { workspace = true } +sparse = { path = ".", features = ["testing"] } + +[target.'cfg(not(target_os = "windows"))'.dev-dependencies] +pprof = { workspace = true } + +[[bench]] +name = "search" +harness = false diff --git a/lib/sparse/benches/prof.rs b/lib/sparse/benches/prof.rs new file mode 100644 index 0000000000..eeb8ab6065 --- /dev/null +++ b/lib/sparse/benches/prof.rs @@ -0,0 +1,89 @@ +use std::fs::File; +use std::io::Write; +use std::os::raw::c_int; +use std::path::Path; + +use criterion::profiler::Profiler; +use pprof::flamegraph::TextTruncateDirection; +use pprof::protos::Message; +use pprof::ProfilerGuard; + +/// Small custom profiler that can be used with Criterion to create a flamegraph for benchmarks. +/// Also see [the Criterion documentation on this][custom-profiler]. +/// +/// ## Example on how to enable the custom profiler: +/// +/// ``` +/// mod perf; +/// use perf::FlamegraphProfiler; +/// +/// fn fibonacci_profiled(criterion: &mut Criterion) { +/// // Use the criterion struct as normal here. +/// } +/// +/// fn custom() -> Criterion { +/// Criterion::default().with_profiler(FlamegraphProfiler::new()) +/// } +/// +/// criterion_group! { +/// name = benches; +/// config = custom(); +/// targets = fibonacci_profiled +/// } +/// ``` +/// +/// The neat thing about this is that it will sample _only_ the benchmark, and not other stuff like +/// the setup process. +/// +/// Further, it will only kick in if `--profile-time