diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1362cb12..3a18e650 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,4 +24,26 @@ jobs: with: lfs: true - uses: moonrepo/setup-rust@v1 - - run: cargo test --all + + # Install memtrack for the memory integration tests + - name: Install dependencies required for libbpf-sys (vendored feature) + run: sudo apt-get update && sudo apt-get install -y autopoint bison flex + - name: Install memtrack + run: | + cargo install --path crates/memtrack --locked + echo "CODSPEED_MEMTRACK_BINARY=$(which codspeed-memtrack)" >> $GITHUB_ENV + + - run: cargo test --all --exclude memtrack + + bpf-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + lfs: true + - uses: moonrepo/setup-rust@v1 + - name: Install dependencies required for libbpf-sys (vendored feature) + run: sudo apt-get update && sudo apt-get install -y autopoint bison flex + - name: Run tests + run: sudo -E $(which cargo) test + working-directory: crates/memtrack diff --git a/Cargo.lock b/Cargo.lock index 8d2db378..2b19d5e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli 0.31.1", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -19,8 +10,8 @@ checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "cpp_demangle", "fallible-iterator", - "gimli 0.32.3", - "memmap2", + "gimli", + "memmap2 0.9.9", "object 0.37.3", "rustc-demangle", "smallvec", @@ -29,25 +20,19 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -59,9 +44,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -74,37 +59,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] @@ -115,48 +100,33 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "async-compression" -version = "0.4.18" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" +checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473" dependencies = [ - "flate2", + "compression-codecs", + "compression-core", "futures-core", - "memchr", "pin-project-lite", "tokio", ] [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line 0.24.2", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.36.7", - "rustc-demangle", - "windows-targets 0.52.6", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" @@ -173,6 +143,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.10.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.111", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -181,9 +171,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" @@ -196,9 +186,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -207,9 +197,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytecount" @@ -225,26 +215,68 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] [[package]] name = "cc" -version = "1.2.9" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -254,21 +286,31 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.6", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", ] [[package]] name = "clap" -version = "4.5.26" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -276,9 +318,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -288,27 +330,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "codspeed-runner" version = "4.4.1" dependencies = [ - "addr2line 0.25.1", + "addr2line", "anyhow", "async-compression", "async-trait", @@ -318,20 +360,22 @@ dependencies = [ "console", "debugid", "futures", - "gimli 0.32.3", + "gimli", "git2", "gql_client", "indicatif", "insta", - "itertools", + "ipc-channel", + "itertools 0.14.0", "lazy_static", "libc", "linux-perf-data", "log", "md5", - "memmap2", + "memmap2 0.9.9", + "memtrack", "nestify", - "nix", + "nix 0.29.0", "object 0.36.7", "open", "procfs", @@ -340,7 +384,8 @@ dependencies = [ "reqwest", "reqwest-middleware", "reqwest-retry", - "rstest", + "rmp-serde", + "rstest 0.25.0", "rstest_reuse", "runner-shared", "semver", @@ -356,6 +401,7 @@ dependencies = [ "tabled", "temp-env", "tempfile", + "test-log", "test-with", "tokio", "tokio-tar", @@ -365,15 +411,32 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compression-codecs" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", @@ -409,22 +472,31 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -452,9 +524,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -471,9 +543,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -506,7 +578,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -517,14 +589,14 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encode_unicode" @@ -541,20 +613,43 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -571,21 +666,27 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "a2152dbcb980c05735e2a651d96011320a949eb31a0c8b38b72645ce97dec676" dependencies = [ "crc32fast", "miniz_oxide", @@ -614,9 +715,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -677,7 +778,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -692,6 +793,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -722,9 +829,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -734,10 +841,16 @@ dependencies = [ ] [[package]] -name = "gimli" -version = "0.31.1" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] [[package]] name = "gimli" @@ -756,7 +869,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "libc", "libgit2-sys", "log", @@ -767,9 +880,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gql_client" @@ -784,9 +897,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -803,9 +916,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -849,9 +962,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -876,7 +989,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -898,16 +1011,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.62.2", ] [[package]] @@ -921,21 +1035,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -944,104 +1059,66 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", + "icu_locale_core", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1050,9 +1127,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1060,9 +1137,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown", @@ -1070,9 +1147,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.9" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", "number_prefix", @@ -1083,12 +1160,11 @@ dependencies = [ [[package]] name = "insta" -version = "1.42.0" +version = "1.44.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" +checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698" dependencies = [ "console", - "linked-hash-map", "once_cell", "pest", "pest_derive", @@ -1108,11 +1184,30 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ipc-channel" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f4c80f2df4fc64fb7fc2cff69fc034af26e6e6617ea9f1313131af464b9ca0" +dependencies = [ + "bincode", + "crossbeam-channel", + "fnv", + "lazy_static", + "libc", + "mio", + "rand", + "serde", + "tempfile", + "uuid", + "windows 0.58.0", +] + [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-docker" @@ -1135,39 +1230,73 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.11.0" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1179,11 +1308,53 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libbpf-cargo" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c6fbcb5088716de86d0ccbdccedc17b13e59f41a605a3274029335e71fcbb" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", + "libbpf-rs", + "libbpf-sys", + "memmap2 0.5.10", + "serde", + "serde_json", + "tempfile", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "libbpf-rs" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e23d252d93e246c8787198369f06806c99c5077b5295be29505295f4e5426dc4" +dependencies = [ + "bitflags 2.10.0", + "libbpf-sys", + "libc", + "vsprintf", +] + +[[package]] +name = "libbpf-sys" +version = "1.5.1+v1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "912fae30b08bcbdb861d4b85bd09c05352c0ac9d7b93765ced5ca23709e7e590" +dependencies = [ + "cc", + "nix 0.30.1", + "pkg-config", +] + [[package]] name = "libc" -version = "0.2.171" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libgit2-sys" @@ -1199,22 +1370,32 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.18", ] [[package]] name = "libssh2-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" dependencies = [ "cc", "libc", @@ -1226,9 +1407,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" dependencies = [ "cc", "libc", @@ -1243,16 +1424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "linux-perf-data" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-perf-data" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f85f35725e15ad6c62b9db73f3d62439094e616a2f83500f7bcdc01ae5b84d8" +checksum = "3ee44f48bb8d8ac1f6e55e294b211960d118c069863e7206913d138d2ddd6175" dependencies = [ "byteorder", "linear-map", @@ -1260,7 +1435,7 @@ dependencies = [ "memchr", "prost", "prost-derive", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -1269,10 +1444,10 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa8fc7e83909ea3b9e2784591655637d3401f2f16014f9d8d6e23ccd138e665f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "byteorder", "memchr", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] @@ -1281,27 +1456,41 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] [[package]] name = "md5" @@ -1311,17 +1500,51 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + +[[package]] +name = "memtrack" +version = "4.4.1" dependencies = [ + "anyhow", + "bindgen", + "clap", + "env_logger", + "ipc-channel", + "itertools 0.14.0", + "libbpf-cargo", + "libbpf-rs", "libc", + "log", + "paste", + "rstest 0.21.0", + "runner-shared", + "serde", + "serde_json", + "static_assertions", + "tempfile", + "test-log", + "vmlinux", ] [[package]] @@ -1340,31 +1563,39 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", + "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -1386,7 +1617,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -1395,12 +1626,34 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "ntapi" version = "0.4.1" @@ -1410,6 +1663,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1450,20 +1712,26 @@ checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "flate2", "memchr", - "ruzstd 0.8.1", + "ruzstd 0.8.2", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" -version = "5.3.2" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ "is-wsl", "libc", @@ -1472,11 +1740,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -1493,29 +1761,29 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.1+3.4.0" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -1554,12 +1822,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.12", ] [[package]] @@ -1578,17 +1846,23 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.3" @@ -1597,26 +1871,25 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.7.15" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" dependencies = [ "memchr", - "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.15" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f" dependencies = [ "pest", "pest_generator", @@ -1624,24 +1897,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.15" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "pest_meta" -version = "2.7.15" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -1660,15 +1932,33 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -1678,13 +1968,32 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.111", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1728,14 +2037,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1746,12 +2055,12 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "chrono", "flate2", "hex", "procfs-core", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -1760,7 +2069,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "chrono", "hex", ] @@ -1781,21 +2090,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools", + "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1823,14 +2138,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -1838,9 +2153,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -1866,11 +2181,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", ] [[package]] @@ -1879,16 +2194,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom", + "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1898,9 +2213,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1909,9 +2224,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "relative-path" @@ -1987,7 +2302,7 @@ dependencies = [ "async-trait", "chrono", "futures", - "getrandom", + "getrandom 0.2.16", "http", "hyper", "parking_lot 0.11.2", @@ -2011,14 +2326,66 @@ dependencies = [ "rand", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rstest" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afd55a67069d6e434a95161415f5beeada95a01c7b815508a82dcb0e1593682" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros 0.21.0", + "rustc_version", +] + [[package]] name = "rstest" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" dependencies = [ - "rstest_macros", + "rstest_macros 0.25.0", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4165dfae59a39dd41d8dec720d3cbfbc71f69744efb480a3920f5d4e0cc6798d" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", "rustc_version", + "syn 2.0.111", + "unicode-ident", ] [[package]] @@ -2034,7 +2401,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.96", + "syn 2.0.111", "unicode-ident", ] @@ -2046,7 +2413,7 @@ checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" dependencies = [ "quote", "rand", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -2055,16 +2422,25 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode", + "libc", "log", + "rmp", + "rmp-serde", "serde", "serde_json", ] [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -2077,17 +2453,30 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -2099,9 +2488,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ruzstd" @@ -2114,26 +2503,26 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" +checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" dependencies = [ "twox-hash 2.1.2", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2148,7 +2537,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "core-foundation", "core-foundation-sys", "libc", @@ -2157,9 +2546,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2167,15 +2556,19 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2183,22 +2576,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -2242,9 +2635,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2253,9 +2646,9 @@ dependencies = [ [[package]] name = "sha256" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" +checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" dependencies = [ "async-trait", "bytes", @@ -2264,6 +2657,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-quote" version = "0.7.2" @@ -2294,11 +2696,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simplelog" @@ -2313,34 +2721,41 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -2367,9 +2782,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -2384,13 +2799,13 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -2405,7 +2820,7 @@ dependencies = [ "ntapi", "rayon", "serde", - "windows", + "windows 0.57.0", ] [[package]] @@ -2468,21 +2883,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050" dependencies = [ "futures", - "parking_lot 0.12.3", + "parking_lot 0.12.5", ] [[package]] name = "tempfile" -version = "3.15.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", - "getrandom", + "getrandom 0.3.4", "once_cell", - "rustix", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -2494,17 +2908,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-log" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" +dependencies = [ + "env_logger", + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "test-with" -version = "0.15.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb2a43a245ab793321d71ff9f2be21785999c9aa5b2ea93dc507e97572be843" +checksum = "63b34ca6990bbf04e3d49c1e3ea4b4ad6c9e15602927d37ec48687df39c2ef8b" dependencies = [ "proc-macro-error2", "proc-macro2", "quote", "regex", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -2518,11 +2954,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -2533,25 +2969,34 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", ] [[package]] name = "time" -version = "0.3.37" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2564,15 +3009,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2580,9 +3025,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2590,29 +3035,28 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", "libc", "mio", "pin-project-lite", - "socket2", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] @@ -2653,9 +3097,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -2664,6 +3108,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "tower-service" version = "0.3.3" @@ -2672,9 +3146,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -2683,22 +3157,52 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "chrono", + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2731,9 +3235,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -2749,15 +3253,15 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unsafe-libyaml" @@ -2767,21 +3271,16 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2796,9 +3295,20 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -2812,6 +3322,21 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vmlinux" +version = "0.0.0" +source = "git+https://github.com/libbpf/vmlinux.h.git?rev=991dd4b8dfd8c9d62ce8999521b24f61d9b7fc52#991dd4b8dfd8c9d62ce8999521b24f61d9b7fc52" + +[[package]] +name = "vsprintf" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aec2f81b75ca063294776b4f7e8da71d1d5ae81c2b1b149c8d89969230265d63" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "want" version = "0.3.1" @@ -2823,41 +3348,37 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.100" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" +name = "wasm-bindgen" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.96", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -2868,9 +3389,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2878,22 +3399,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.96", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -2928,9 +3449,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -2964,11 +3485,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2988,11 +3509,12 @@ dependencies = [ ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -3002,12 +3524,38 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -3016,7 +3564,29 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", ] [[package]] @@ -3027,9 +3597,37 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", ] +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-result" version = "0.1.2" @@ -3039,6 +3637,43 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3066,6 +3701,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3090,13 +3743,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3109,6 +3779,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3121,6 +3797,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3133,12 +3815,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3151,6 +3845,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3163,6 +3863,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3175,6 +3881,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3187,6 +3899,21 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -3198,35 +3925,33 @@ dependencies = [ ] [[package]] -name = "write16" -version = "1.0.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xattr" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "rustix 1.1.2", ] [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3234,63 +3959,73 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", "synstructure", ] +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -3299,11 +4034,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.111", ] diff --git a/Cargo.toml b/Cargo.toml index 2d004322..306f51dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,11 @@ path = "src/main.rs" [dependencies] -anyhow = "1.0.75" -clap = { version = "4.4.8", features = ["derive", "env", "color"] } -itertools = "0.11.0" +anyhow = { workspace = true } +clap = { workspace = true, features = ["env", "color"] } +itertools = { workspace = true } lazy_static = "1.4.0" -log = "0.4.20" +log = { workspace = true } rand = "0.8.5" regex = "1.10.2" semver = "1.0" @@ -26,8 +26,8 @@ reqwest = { version = "0.11.22", features = [ ] } reqwest-middleware = "0.2.4" reqwest-retry = "0.3.0" -serde = { version = "1.0.192", features = ["derive"] } -serde_json = { version = "1.0.108", features = ["preserve_order"] } +serde = { workspace = true } +serde_json = { workspace = true, features = ["preserve_order"] } url = "2.4.1" sha256 = "1.4.0" tokio = { version = "1", features = ["macros", "rt"] } @@ -48,7 +48,7 @@ sysinfo = { version = "0.33.1", features = ["serde"] } indicatif = "0.17.8" console = "0.15.8" async-trait = "0.1.82" -libc = "0.2.171" +libc = { workspace = true } bincode = "1.3.3" object = "0.36.7" linux-perf-data = "0.11.0" @@ -57,12 +57,16 @@ memmap2 = "0.9.5" nix = { version = "0.29.0", features = ["fs", "time", "user"] } futures = "0.3.31" runner-shared = { path = "crates/runner-shared" } +memtrack = { path = "crates/memtrack", default-features = false } +ipc-channel = "0.18" shellexpand = { version = "3.1.1", features = ["tilde"] } addr2line = "0.25" gimli = "0.32" open = "5.3.2" tabled = "0.17" shell-words = "1.1.0" +rmp-serde = "1.3.0" +test-log = "0.2.19" [target.'cfg(target_os = "linux")'.dependencies] procfs = "0.17.0" @@ -76,7 +80,18 @@ rstest_reuse = "0.7.0" shell-quote = "0.7.2" [workspace] -members = ["crates/runner-shared"] +members = ["crates/runner-shared", "crates/memtrack"] + +[workspace.dependencies] +anyhow = "1.0" +clap = { version = "4.5", features = ["derive"] } +libc = "0.2" +log = "0.4.28" +serde_json = "1.0" +serde = { version = "1.0.228", features = ["derive"] } +ipc-channel = "0.18" +itertools = "0.14.0" +env_logger = "0.11.8" [workspace.metadata.release] sign-tag = true @@ -90,6 +105,9 @@ inherits = "release" lto = "thin" strip = true +[package.metadata.dist] +targets = ["aarch64-unknown-linux-musl", "x86_64-unknown-linux-musl"] + # Config for 'dist' [workspace.metadata.dist] # Whether to consider the binaries in a package for distribution (defaults true) @@ -100,8 +118,6 @@ cargo-dist-version = "0.28.4" ci = "github" # The installers to generate for each app installers = ["shell"] -# Target platforms to build apps for (Rust target-triple syntax) -targets = ["aarch64-unknown-linux-musl", "x86_64-unknown-linux-musl"] # The archive format to use for non-windows builds (defaults .tar.xz) unix-archive = ".tar.gz" # Which actions to run on pull requests @@ -112,6 +128,7 @@ post-announce-jobs = ["./bump-action"] install-path = "CARGO_HOME" # Whether to install an updater program install-updater = false +precise-builds = true [workspace.metadata.dist.github-custom-runners] aarch64-unknown-linux-musl = "buildjet-2vcpu-ubuntu-2204-arm" diff --git a/crates/memtrack/Cargo.toml b/crates/memtrack/Cargo.toml new file mode 100644 index 00000000..abd73e02 --- /dev/null +++ b/crates/memtrack/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "memtrack" +version = "4.4.1" +edition = "2024" +repository = "https://github.com/CodSpeedHQ/runner" + +[lib] +name = "memtrack" +path = "src/lib.rs" + +[[bin]] +name = "codspeed-memtrack" +path = "src/main.rs" +required-features = ["ebpf"] + +[features] +default = ["ebpf"] +ebpf = [ + "dep:libbpf-rs", + "dep:libbpf-cargo", + "dep:vmlinux", +] + +[dependencies] +anyhow = { workspace = true } +clap = { workspace = true } +libc = { workspace = true } +log = { workspace = true } +env_logger = { workspace = true } +serde_json = { workspace = true } +serde = { workspace = true } +runner-shared = { path = "../runner-shared" } +ipc-channel = { workspace = true } +static_assertions = "1.1" +itertools = { workspace = true } +paste = "1.0" +libbpf-rs = { version = "0.25.0", features = ["vendored"], optional = true } + +[build-dependencies] +libbpf-cargo = { version = "0.25.0", optional = true } +vmlinux = { git = "https://github.com/libbpf/vmlinux.h.git", rev = "991dd4b8dfd8c9d62ce8999521b24f61d9b7fc52", optional = true } +bindgen = "0.71" + +[dev-dependencies] +tempfile = "3.8" +rstest = "0.21" +test-log = "0.2" + +[package.metadata.dist] +dist = true +installers = ["shell"] +targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"] +features = ["libbpf-rs/static"] + +[package.metadata.dist.dependencies.apt] +build-essential = "*" +pkgconf = "*" +zlib1g-dev = "*" +libbpf-dev = "*" + +# Required for the vendored feature +autopoint = "*" +bison = "*" +flex = "*" diff --git a/crates/memtrack/build.rs b/crates/memtrack/build.rs new file mode 100644 index 00000000..3f9b2b24 --- /dev/null +++ b/crates/memtrack/build.rs @@ -0,0 +1,36 @@ +#[cfg(feature = "ebpf")] +use std::{env, path::PathBuf}; + +#[cfg(feature = "ebpf")] +fn build_ebpf() { + use libbpf_cargo::SkeletonBuilder; + + println!("cargo:rerun-if-changed=src/ebpf/c"); + + // Build the BPF program + let arch = env::var("CARGO_CFG_TARGET_ARCH") + .expect("CARGO_CFG_TARGET_ARCH must be set in build script"); + let memtrack_out = PathBuf::from(env::var("OUT_DIR").unwrap()).join("memtrack.skel.rs"); + SkeletonBuilder::new() + .source("src/ebpf/c/memtrack.bpf.c") + .clang_args([ + "-I", + &vmlinux::include_path_root().join(arch).to_string_lossy(), + ]) + .build_and_generate(&memtrack_out) + .unwrap(); + + // Generate bindings for event.h + let bindings = bindgen::Builder::default() + .header("wrapper.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .generate() + .expect("Unable to generate bindings"); + let out_file = PathBuf::from(env::var("OUT_DIR").unwrap()).join("event.rs"); + std::fs::write(&out_file, bindings.to_string()).expect("Couldn't write bindings!"); +} + +fn main() { + #[cfg(feature = "ebpf")] + build_ebpf(); +} diff --git a/crates/memtrack/src/ebpf/c/event.h b/crates/memtrack/src/ebpf/c/event.h new file mode 100644 index 00000000..0162078d --- /dev/null +++ b/crates/memtrack/src/ebpf/c/event.h @@ -0,0 +1,24 @@ +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#define EVENT_TYPE_MALLOC 1 +#define EVENT_TYPE_FREE 2 +#define EVENT_TYPE_EXECVE 3 +#define EVENT_TYPE_CALLOC 4 +#define EVENT_TYPE_REALLOC 5 +#define EVENT_TYPE_ALIGNED_ALLOC 6 +#define EVENT_TYPE_MMAP 7 +#define EVENT_TYPE_MUNMAP 8 +#define EVENT_TYPE_BRK 9 + +/* Event structure - shared between BPF and userspace */ +struct event { + uint8_t event_type; /* See EVENT_TYPE_* constants above */ + uint64_t timestamp; /* monotonic time in nanoseconds (CLOCK_MONOTONIC) */ + uint32_t pid; + uint32_t tid; + uint64_t addr; /* address returned/freed */ + uint64_t size; /* size requested */ +}; + +#endif /* __EVENT_H__ */ diff --git a/crates/memtrack/src/ebpf/c/memtrack.bpf.c b/crates/memtrack/src/ebpf/c/memtrack.bpf.c new file mode 100644 index 00000000..63c5be5f --- /dev/null +++ b/crates/memtrack/src/ebpf/c/memtrack.bpf.c @@ -0,0 +1,285 @@ +// clang-format off +// Prevent clang-format from reformatting the include statement, which is +// needed for the bpf headers below. +#include "vmlinux.h" +// clang-format on + +#include +#include +#include + +#include "event.h" + +char LICENSE[] SEC("license") = "GPL"; + +/* Macros for common map definitions */ +#define BPF_HASH_MAP(name, key_type, value_type, max_ents) \ + struct { \ + __uint(type, BPF_MAP_TYPE_HASH); \ + __uint(max_entries, max_ents); \ + __type(key, key_type); \ + __type(value, value_type); \ + } name SEC(".maps") + +#define BPF_ARRAY_MAP(name, value_type, max_ents) \ + struct { \ + __uint(type, BPF_MAP_TYPE_ARRAY); \ + __uint(max_entries, max_ents); \ + __type(key, __u32); \ + __type(value, value_type); \ + } name SEC(".maps") + +#define BPF_RINGBUF(name, size) \ + struct { \ + __uint(type, BPF_MAP_TYPE_RINGBUF); \ + __uint(max_entries, size); \ + } name SEC(".maps") + +BPF_HASH_MAP(tracked_pids, __u32, __u8, 10000); /* Map to store PIDs we're tracking */ +BPF_HASH_MAP(pids_ppid, __u32, __u32, 10000); /* Map to store parent-child relationships to detect hierarchy */ +BPF_RINGBUF(events, 256 * 1024); /* Ring buffer for sending events to userspace */ +BPF_ARRAY_MAP(tracking_enabled, __u8, 1); /* Map to control whether tracking is enabled (0 = disabled, 1 + = enabled) */ + +/* == Code that tracks process forks and execs == */ + +/* Helper to check if a PID or any of its ancestors should be tracked */ +static __always_inline int is_tracked(__u32 pid) { + /* Direct check */ + if (bpf_map_lookup_elem(&tracked_pids, &pid)) { + return 1; + } + +/* Check parent recursively (up to 5 levels) */ +#pragma unroll + for (int i = 0; i < 5; i++) { + __u32* ppid = bpf_map_lookup_elem(&pids_ppid, &pid); + if (!ppid) { + break; + } + pid = *ppid; + if (bpf_map_lookup_elem(&tracked_pids, &pid)) { + return 1; + } + } + + return 0; +} + +SEC("tracepoint/sched/sched_process_fork") +int tracepoint_sched_fork(struct trace_event_raw_sched_process_fork* ctx) { + __u32 parent_pid = ctx->parent_pid; + __u32 child_pid = ctx->child_pid; + + /* Print process fork with PIDs */ + // bpf_printk("sched_fork: parent_pid=%u child_pid=%u", parent_pid, child_pid); + + /* Check if parent is being tracked */ + if (is_tracked(parent_pid)) { + /* Auto-track this child */ + __u8 marker = 1; + bpf_map_update_elem(&tracked_pids, &child_pid, &marker, BPF_ANY); + bpf_map_update_elem(&pids_ppid, &child_pid, &parent_pid, BPF_ANY); + + // bpf_printk("auto-tracking child process: child_pid=%u", child_pid); + } + + return 0; +} + +/* == Helper functions for the allocation tracking == */ + +/* Helper to check if tracking is currently enabled */ +static __always_inline int is_enabled(void) { + __u32 key = 0; + __u8* enabled = bpf_map_lookup_elem(&tracking_enabled, &key); + + /* Default to enabled if map not initialized */ + if (!enabled) { + return 1; + } + + return *enabled; +} + +/* Helper to store parameter value in map for tracking between entry and return + */ +static __always_inline int store_param(void* map, __u64 value) { + __u64 tid = bpf_get_current_pid_tgid(); + __u32 pid = tid >> 32; + if (is_tracked(pid)) { + bpf_map_update_elem(map, &tid, &value, BPF_ANY); + } + return 0; +} + +/* Helper to take parameter value from map (lookup and delete) */ +static __always_inline __u64* take_param(void* map) { + __u64 tid = bpf_get_current_pid_tgid(); + __u64* value = bpf_map_lookup_elem(map, &tid); + if (value) { + bpf_map_delete_elem(map, &tid); + } + return value; +} + +/* Helper to submit an event to the ring buffer */ +static __always_inline int submit_event(__u64 addr, __u64 size, __u8 event_type) { + __u64 tid = bpf_get_current_pid_tgid(); + __u32 pid = tid >> 32; + + if (!is_tracked(pid) || !is_enabled()) { + return 0; + } + + struct event* e = bpf_ringbuf_reserve(&events, sizeof(*e), 0); + if (!e) { + return 0; + } + + e->timestamp = bpf_ktime_get_ns(); + e->pid = pid; + e->tid = tid & 0xFFFFFFFF; + e->event_type = event_type; + e->addr = addr; + e->size = size; + bpf_ringbuf_submit(e, 0); + + return 0; +} + +/* Macro to generate uprobe/uretprobe pairs for allocation functions */ +#define UPROBE_WITH_ARGS(name, size_expr, addr_expr, event_type) \ + BPF_HASH_MAP(name##_size, __u64, __u64, 10000); \ + SEC("uprobe") \ + int uprobe_##name(struct pt_regs* ctx) { return store_param(&name##_size, size_expr); } \ + SEC("uretprobe") \ + int uretprobe_##name(struct pt_regs* ctx) { \ + __u64* size_ptr = take_param(&name##_size); \ + if (!size_ptr) { \ + return 0; \ + } \ + __u64 addr = addr_expr; \ + if (addr == 0) { \ + return 0; \ + } \ + return submit_event(addr, *size_ptr, event_type); \ + } + +/* Macro for simple address-only functions like free */ +#define UPROBE_ADDR_ONLY(name, addr_expr, event_type) \ + SEC("uprobe") \ + int uprobe_##name(struct pt_regs* ctx) { \ + __u64 addr = addr_expr; \ + if (addr == 0) { \ + return 0; \ + } \ + return submit_event(addr, 0, event_type); \ + } + +/* malloc: allocates with size parameter */ +UPROBE_WITH_ARGS(malloc, PT_REGS_PARM1(ctx), PT_REGS_RC(ctx), EVENT_TYPE_MALLOC) + +/* free: deallocates by address */ +UPROBE_ADDR_ONLY(free, PT_REGS_PARM1(ctx), EVENT_TYPE_FREE) + +/* calloc: allocates with nmemb * size */ +UPROBE_WITH_ARGS(calloc, PT_REGS_PARM1(ctx) * PT_REGS_PARM2(ctx), PT_REGS_RC(ctx), EVENT_TYPE_CALLOC) + +/* realloc: reallocates with new size */ +UPROBE_WITH_ARGS(realloc, PT_REGS_PARM2(ctx), PT_REGS_RC(ctx), EVENT_TYPE_REALLOC) + +/* aligned_alloc: allocates with alignment and size */ +UPROBE_WITH_ARGS(aligned_alloc, PT_REGS_PARM2(ctx), PT_REGS_RC(ctx), EVENT_TYPE_ALIGNED_ALLOC) + +SEC("tracepoint/syscalls/sys_enter_execve") +int tracepoint_sys_execve(struct trace_event_raw_sys_enter* ctx) { return submit_event(0, 0, EVENT_TYPE_EXECVE); } + +/* Map to store mmap parameters between entry and return */ +struct mmap_args { + __u64 addr; + __u64 len; +}; + +BPF_HASH_MAP(mmap_temp, __u64, struct mmap_args, 10000); + +SEC("tracepoint/syscalls/sys_enter_mmap") +int tracepoint_sys_enter_mmap(struct trace_event_raw_sys_enter* ctx) { + __u64 tid = bpf_get_current_pid_tgid(); + __u32 pid = tid >> 32; + + if (is_tracked(pid)) { + struct mmap_args args = {0}; + + /* mmap(addr, len, prot, flags, fd, offset) + * We care about addr (can be 0 for kernel choice) and len */ + args.addr = ctx->args[0]; + args.len = ctx->args[1]; + + bpf_map_update_elem(&mmap_temp, &tid, &args, BPF_ANY); + } + + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_mmap") +int tracepoint_sys_exit_mmap(struct trace_event_raw_sys_exit* ctx) { + struct mmap_args* args = (struct mmap_args*)take_param(&mmap_temp); + if (!args) { + return 0; + } + + __s64 ret = ctx->ret; + if (ret <= 0) { + return 0; + } + + return submit_event((__u64)ret, args->len, EVENT_TYPE_MMAP); +} + +/* munmap tracking */ +SEC("tracepoint/syscalls/sys_enter_munmap") +int tracepoint_sys_enter_munmap(struct trace_event_raw_sys_enter* ctx) { + __u64 addr = ctx->args[0]; + __u64 len = ctx->args[1]; + + if (addr == 0 || len == 0) { + return 0; + } + + return submit_event(addr, len, EVENT_TYPE_MUNMAP); +} + +/* brk tracking - adjusts the program break (heap boundary) */ +BPF_HASH_MAP(brk_temp, __u64, __u64, 10000); + +SEC("tracepoint/syscalls/sys_enter_brk") +int tracepoint_sys_enter_brk(struct trace_event_raw_sys_enter* ctx) { + __u64 tid = bpf_get_current_pid_tgid(); + __u32 pid = tid >> 32; + + if (is_tracked(pid)) { + /* brk(addr) - if addr is 0, just queries current break */ + __u64 requested_brk = ctx->args[0]; + bpf_map_update_elem(&brk_temp, &tid, &requested_brk, BPF_ANY); + } + + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_brk") +int tracepoint_sys_exit_brk(struct trace_event_raw_sys_exit* ctx) { + __u64* requested_brk = take_param(&brk_temp); + if (!requested_brk) { + return 0; + } + + __u64 new_brk = ctx->ret; + __u64 req_brk = *requested_brk; + + if (req_brk == 0 || new_brk <= 0) { + return 0; + } + + return submit_event(new_brk, 0, EVENT_TYPE_BRK); +} diff --git a/crates/memtrack/src/ebpf/events.rs b/crates/memtrack/src/ebpf/events.rs new file mode 100644 index 00000000..f8edbc8f --- /dev/null +++ b/crates/memtrack/src/ebpf/events.rs @@ -0,0 +1,104 @@ +use runner_shared::artifacts::{MemtrackEvent, MemtrackEventKind}; +use serde::{Deserialize, Serialize}; + +// Include the bindings for event.h +pub mod bindings { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + #![allow(dead_code)] + + include!(concat!(env!("OUT_DIR"), "/event.rs")); +} +use bindings::*; + +#[repr(u8)] +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +pub enum EventType { + Malloc = EVENT_TYPE_MALLOC as u8, + Free = EVENT_TYPE_FREE as u8, + Execve = EVENT_TYPE_EXECVE as u8, + Calloc = EVENT_TYPE_CALLOC as u8, + Realloc = EVENT_TYPE_REALLOC as u8, + AlignedAlloc = EVENT_TYPE_ALIGNED_ALLOC as u8, + Mmap = EVENT_TYPE_MMAP as u8, + Munmap = EVENT_TYPE_MUNMAP as u8, + Brk = EVENT_TYPE_BRK as u8, +} + +impl From for EventType { + fn from(val: u8) -> Self { + match val as u32 { + bindings::EVENT_TYPE_MALLOC => EventType::Malloc, + bindings::EVENT_TYPE_FREE => EventType::Free, + bindings::EVENT_TYPE_EXECVE => EventType::Execve, + bindings::EVENT_TYPE_CALLOC => EventType::Calloc, + bindings::EVENT_TYPE_REALLOC => EventType::Realloc, + bindings::EVENT_TYPE_ALIGNED_ALLOC => EventType::AlignedAlloc, + bindings::EVENT_TYPE_MMAP => EventType::Mmap, + bindings::EVENT_TYPE_MUNMAP => EventType::Munmap, + bindings::EVENT_TYPE_BRK => EventType::Brk, + _ => panic!("Unknown event type: {val}"), + } + } +} + +// TODO: Can't we use the bindgen generated type? +#[repr(C)] +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] +pub struct Event { + pub event_type: EventType, + pub timestamp: u64, + pub pid: i32, + pub tid: i32, + pub addr: u64, + pub size: u64, +} + +impl From for MemtrackEvent { + fn from(val: Event) -> Self { + let kind = match val.event_type { + EventType::Malloc => MemtrackEventKind::Malloc { size: val.size }, + EventType::Free => MemtrackEventKind::Free, + EventType::Calloc => MemtrackEventKind::Calloc { size: val.size }, + EventType::Realloc => MemtrackEventKind::Realloc { size: val.size }, + EventType::AlignedAlloc => MemtrackEventKind::AlignedAlloc { size: val.size }, + EventType::Mmap => MemtrackEventKind::Mmap { size: val.size }, + EventType::Munmap => MemtrackEventKind::Munmap { size: val.size }, + EventType::Brk => MemtrackEventKind::Brk { size: val.size }, + _ => panic!("This event isn't meant to be used outside of memtrack"), + }; + + MemtrackEvent { + pid: val.pid, + tid: val.tid, + timestamp: val.timestamp, + addr: val.addr, + kind, + } + } +} + +mod assertions { + use super::*; + use static_assertions::{assert_eq_align, assert_eq_size, const_assert_eq}; + use std::mem::offset_of; + + // Verify size and alignment match the bindgen-generated event struct + assert_eq_size!(Event, bindings::event); + assert_eq_align!(Event, bindings::event); + + // Verify field offsets match the C struct + const_assert_eq!( + offset_of!(Event, timestamp), + offset_of!(bindings::event, timestamp) + ); + const_assert_eq!(offset_of!(Event, pid), offset_of!(bindings::event, pid)); + const_assert_eq!(offset_of!(Event, tid), offset_of!(bindings::event, tid)); + const_assert_eq!( + offset_of!(Event, event_type), + offset_of!(bindings::event, event_type) + ); + const_assert_eq!(offset_of!(Event, addr), offset_of!(bindings::event, addr)); + const_assert_eq!(offset_of!(Event, size), offset_of!(bindings::event, size)); +} diff --git a/crates/memtrack/src/ebpf/memtrack.rs b/crates/memtrack/src/ebpf/memtrack.rs new file mode 100644 index 00000000..c9ac47da --- /dev/null +++ b/crates/memtrack/src/ebpf/memtrack.rs @@ -0,0 +1,254 @@ +use anyhow::Context; +use anyhow::Result; +use libbpf_rs::Link; +use libbpf_rs::skel::OpenSkel; +use libbpf_rs::skel::SkelBuilder; +use libbpf_rs::{MapCore, UprobeOpts}; +use log::warn; +use paste::paste; +use std::mem::MaybeUninit; +use std::path::Path; + +use crate::ebpf::poller::RingBufferPoller; + +pub mod memtrack_skel { + include!(concat!(env!("OUT_DIR"), "/memtrack.skel.rs")); +} +pub use memtrack_skel::*; + +/// Macro to attach a function with both entry and return probes +macro_rules! attach_uprobe_uretprobe { + ($name:ident, $prog_entry:ident, $prog_return:ident, $func_str:expr) => { + fn $name(&mut self, libc_path: &Path) -> Result<()> { + let link = self + .skel + .progs + .$prog_entry + .attach_uprobe_with_opts( + -1, + libc_path, + 0, + UprobeOpts { + func_name: Some($func_str.to_string()), + retprobe: false, + ..Default::default() + }, + ) + .context(format!( + "Failed to attach {} uprobe in {}", + $func_str, + libc_path.display() + ))?; + self.probes.push(link); + + let link = self + .skel + .progs + .$prog_return + .attach_uprobe_with_opts( + -1, + libc_path, + 0, + UprobeOpts { + func_name: Some($func_str.to_string()), + retprobe: true, + ..Default::default() + }, + ) + .context(format!( + "Failed to attach {} uretprobe in {}", + $func_str, + libc_path.display() + ))?; + self.probes.push(link); + + Ok(()) + } + }; + ($name:ident) => { + paste! { + attach_uprobe_uretprobe!( + [], + [], + [], + stringify!($name) + ); + } + }; +} + +macro_rules! attach_uprobe { + ($name:ident, $prog:ident, $func_str:expr) => { + fn $name(&mut self, libc_path: &Path) -> Result<()> { + let link = self + .skel + .progs + .$prog + .attach_uprobe_with_opts( + -1, + libc_path, + 0, + UprobeOpts { + func_name: Some($func_str.to_string()), + retprobe: false, + ..Default::default() + }, + ) + .context(format!( + "Failed to attach {} uprobe in {}", + $func_str, + libc_path.display() + ))?; + self.probes.push(link); + Ok(()) + } + }; + ($name:ident) => { + paste! { + attach_uprobe!( + [], + [], + stringify!($name) + ); + } + }; +} + +macro_rules! attach_tracepoint { + ($func:ident, $prog:ident) => { + fn $func(&mut self) -> Result<()> { + let link = self + .skel + .progs + .$prog + .attach() + .context(format!("Failed to attach {} tracepoint", stringify!($prog)))?; + self.probes.push(link); + Ok(()) + } + }; + ($name:ident) => { + paste! { + attach_tracepoint!([], []); + } + }; +} + +pub struct MemtrackBpf { + skel: Box>, + probes: Vec, +} + +impl MemtrackBpf { + pub fn new() -> Result { + // Build and open the syscalls BPF program + let builder = MemtrackSkelBuilder::default(); + let open_object = Box::leak(Box::new(MaybeUninit::uninit())); + let open_skel = builder + .open(open_object) + .context("Failed to open syscalls BPF skeleton")?; + + let skel = Box::new( + open_skel + .load() + .context("Failed to load syscalls BPF skeleton")?, + ); + + Ok(Self { + skel, + probes: Vec::new(), + }) + } + + pub fn add_tracked_pid(&mut self, pid: i32) -> Result<()> { + self.skel + .maps + .tracked_pids + .update( + &pid.to_le_bytes(), + &1u8.to_le_bytes(), + libbpf_rs::MapFlags::ANY, + ) + .context("Failed to add PID to uprobes tracked set")?; + + Ok(()) + } + + /// Enable event tracking + pub fn enable_tracking(&mut self) -> Result<()> { + let key = 0u32; + let value = true as u8; + self.skel + .maps + .tracking_enabled + .update( + &key.to_le_bytes(), + &value.to_le_bytes(), + libbpf_rs::MapFlags::ANY, + ) + .context("Failed to enable tracking")?; + Ok(()) + } + + /// Disable event tracking + pub fn disable_tracking(&mut self) -> Result<()> { + let key = 0u32; + let value = false as u8; + self.skel + .maps + .tracking_enabled + .update( + &key.to_le_bytes(), + &value.to_le_bytes(), + libbpf_rs::MapFlags::ANY, + ) + .context("Failed to disable tracking")?; + Ok(()) + } + + attach_uprobe_uretprobe!(malloc); + attach_uprobe_uretprobe!(calloc); + attach_uprobe_uretprobe!(realloc); + attach_uprobe_uretprobe!(aligned_alloc); + attach_uprobe!(free); + + pub fn attach_probes(&mut self, libc_path: &Path) -> Result<()> { + self.attach_malloc(libc_path)?; + self.attach_free(libc_path)?; + self.attach_calloc(libc_path)?; + self.attach_realloc(libc_path)?; + self.attach_aligned_alloc(libc_path)?; + Ok(()) + } + + attach_tracepoint!(sched_fork); + attach_tracepoint!(sys_execve); + + pub fn attach_tracepoints(&mut self) -> Result<()> { + self.attach_sched_fork()?; + self.attach_sys_execve()?; + Ok(()) + } + + /// Start polling with an mpsc channel for events + pub fn start_polling_with_channel( + &self, + poll_timeout_ms: u64, + ) -> Result<( + RingBufferPoller, + std::sync::mpsc::Receiver, + )> { + // Use the syscalls skeleton's ring buffer (both programs share the same one) + RingBufferPoller::with_channel(&self.skel.maps.events, poll_timeout_ms) + } +} + +impl Drop for MemtrackBpf { + fn drop(&mut self) { + if self.probes.len() > 10 { + warn!( + "Dropping the MemtrackBpf instance, this can take some time when having many probes attached" + ); + } + } +} diff --git a/crates/memtrack/src/ebpf/mod.rs b/crates/memtrack/src/ebpf/mod.rs new file mode 100644 index 00000000..60747327 --- /dev/null +++ b/crates/memtrack/src/ebpf/mod.rs @@ -0,0 +1,8 @@ +mod events; +mod memtrack; +mod poller; +mod tracker; + +pub use events::{Event, EventType}; +pub use memtrack::MemtrackBpf; +pub use tracker::Tracker; diff --git a/crates/memtrack/src/ebpf/poller.rs b/crates/memtrack/src/ebpf/poller.rs new file mode 100644 index 00000000..05884773 --- /dev/null +++ b/crates/memtrack/src/ebpf/poller.rs @@ -0,0 +1,88 @@ +use anyhow::Result; +use libbpf_rs::{MapCore, RingBufferBuilder}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, mpsc}; +use std::thread::JoinHandle; +use std::time::Duration; + +use super::events::Event; + +/// A handler function for processing ring buffer events +pub type EventHandler = Box; + +/// RingBufferPoller manages polling a BPF ring buffer in a background thread +/// and sending events to handlers +pub struct RingBufferPoller { + shutdown: Arc, + poll_thread: Option>, +} + +impl RingBufferPoller { + /// Create a new RingBufferPoller for the given ring buffer map + /// + /// # Arguments + /// * `rb_map` - The BPF ring buffer map to poll + /// * `handler` - Callback function to handle each event + /// * `poll_timeout_ms` - How long to wait for events in each poll iteration + pub fn new( + rb_map: &M, + handler: EventHandler, + poll_timeout_ms: u64, + ) -> Result { + let mut builder = RingBufferBuilder::new(); + builder.add(rb_map, move |data| { + if data.len() >= std::mem::size_of::() { + let event = unsafe { &*(data.as_ptr() as *const Event) }; + handler(*event); + } + 0 + })?; + + let ringbuf = builder.build()?; + let shutdown = Arc::new(AtomicBool::new(false)); + let shutdown_clone = shutdown.clone(); + + let poll_thread = std::thread::spawn(move || { + while !shutdown_clone.load(Ordering::Relaxed) { + let _ = ringbuf.poll(Duration::from_millis(poll_timeout_ms)); + } + }); + + Ok(Self { + shutdown, + poll_thread: Some(poll_thread), + }) + } + + /// Create a new RingBufferPoller with an mpsc channel for events + /// + /// Returns the RingBufferPoller and the receiver end of the channel + pub fn with_channel( + rb_map: &M, + poll_timeout_ms: u64, + ) -> Result<(Self, mpsc::Receiver)> { + let (tx, rx) = mpsc::channel(); + let poller = Self::new( + rb_map, + Box::new(move |event| { + let _ = tx.send(event); + }), + poll_timeout_ms, + )?; + Ok((poller, rx)) + } + + /// Stop the polling thread and wait for it to finish + pub fn shutdown(&mut self) { + self.shutdown.store(true, Ordering::Relaxed); + if let Some(thread) = self.poll_thread.take() { + let _ = thread.join(); + } + } +} + +impl Drop for RingBufferPoller { + fn drop(&mut self) { + self.shutdown(); + } +} diff --git a/crates/memtrack/src/ebpf/tracker.rs b/crates/memtrack/src/ebpf/tracker.rs new file mode 100644 index 00000000..5c864918 --- /dev/null +++ b/crates/memtrack/src/ebpf/tracker.rs @@ -0,0 +1,88 @@ +use crate::ebpf::{Event, MemtrackBpf}; +use anyhow::Result; +use log::debug; +use std::sync::mpsc::{self, Receiver}; + +pub struct Tracker { + bpf: MemtrackBpf, +} + +impl Tracker { + /// Create a new tracker instance + /// + /// This will: + /// - Initialize the BPF subsystem + /// - Bump memlock limits + /// - Attach uprobes to all libc instances + /// - Attach tracepoints for fork tracking + pub fn new() -> Result { + // Bump memlock limits + Self::bump_memlock_rlimit()?; + + // Find and attach to all libc instances + let libc_paths = crate::libc::find_libc_paths()?; + debug!("Found {} libc instance(s)", libc_paths.len()); + + let mut bpf = MemtrackBpf::new()?; + bpf.attach_tracepoints()?; + + for libc_path in &libc_paths { + debug!("Attaching uprobes to: {}", libc_path.display()); + bpf.attach_probes(libc_path)?; + } + + Ok(Self { bpf }) + } + + /// Start tracking allocations for a specific PID + /// + /// Returns a receiver channel that will receive allocation events. + /// The receiver will continue to produce events until the tracker is dropped. + pub fn track(&mut self, pid: i32) -> Result> { + // Add the PID to track + self.bpf.add_tracked_pid(pid)?; + debug!("Tracking PID {pid}"); + + // Start polling with channel + let (_poller, event_rx) = self.bpf.start_polling_with_channel(10)?; + + // Keep the poller alive by moving it into the channel + // When the receiver is dropped, the poller will also be dropped + let (tx, rx) = mpsc::channel(); + std::thread::spawn(move || { + // Keep poller alive + let _p = _poller; + while let Ok(event) = event_rx.recv() { + if tx.send(event).is_err() { + break; + } + } + }); + + Ok(rx) + } + + fn bump_memlock_rlimit() -> Result<()> { + let rlimit = libc::rlimit { + rlim_cur: libc::RLIM_INFINITY, + rlim_max: libc::RLIM_INFINITY, + }; + + let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) }; + if ret != 0 { + anyhow::bail!("Failed to increase rlimit"); + } + + Ok(()) + } + + /// Enable event tracking in the BPF program + pub fn enable(&mut self) -> anyhow::Result<()> { + self.bpf.enable_tracking() + } + + /// Disable event tracking in the BPF program + pub fn disable(&mut self) -> anyhow::Result<()> { + self.bpf.disable_tracking() + } +} diff --git a/crates/memtrack/src/ipc.rs b/crates/memtrack/src/ipc.rs new file mode 100644 index 00000000..8c4c3b94 --- /dev/null +++ b/crates/memtrack/src/ipc.rs @@ -0,0 +1,117 @@ +use anyhow::{Context, Result}; +use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender}; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "ebpf")] +use crate::ebpf::Tracker; + +pub type MemtrackIpcServer = IpcOneShotServer>; + +/// Commands sent from the runner to control memtrack +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum IpcCommand { + Enable, + Disable, + Ping, +} + +/// Response sent back to runner +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum IpcResponse { + Ack, + Err, +} + +/// Message combining command and response channel +#[derive(Debug, Serialize, Deserialize)] +pub struct IpcMessage { + pub command: IpcCommand, + pub response_channel: IpcSender, +} + +/// Client for sending commands from runner to memtrack +pub struct MemtrackIpcClient { + sender: IpcSender, +} + +impl MemtrackIpcClient { + pub fn new(sender: IpcSender) -> Self { + Self { sender } + } + + /// Create from the connection accepted by the runner + pub fn from_accepted(sender: IpcSender) -> Self { + Self { sender } + } + + fn send_command(&self, cmd: IpcCommand) -> Result { + let (response_tx, response_rx) = ipc::channel::()?; + + let msg = IpcMessage { + command: cmd, + response_channel: response_tx, + }; + + self.sender.send(msg).context("Failed to send command")?; + let response = response_rx.recv().context("Failed to receive response")?; + + Ok(response) + } + + pub fn enable(&self) -> Result<()> { + let response = self.send_command(IpcCommand::Enable)?; + match response { + IpcResponse::Ack => Ok(()), + IpcResponse::Err => anyhow::bail!("Failed to enable tracking"), + } + } + + pub fn disable(&self) -> Result<()> { + let response = self.send_command(IpcCommand::Disable)?; + match response { + IpcResponse::Ack => Ok(()), + IpcResponse::Err => anyhow::bail!("Failed to disable tracking"), + } + } + + pub fn ping(&self) -> Result<()> { + let response = self.send_command(IpcCommand::Ping)?; + match response { + IpcResponse::Ack => Ok(()), + IpcResponse::Err => anyhow::bail!("Failed to ping memtrack"), + } + } +} + +/// Handle incoming IPC messages in memtrack +#[cfg(feature = "ebpf")] +pub fn handle_ipc_message(msg: IpcMessage, tracker: &std::sync::Arc>) { + use log::debug; + + let response = match msg.command { + IpcCommand::Enable => match tracker.lock() { + Ok(mut t) => match t.enable() { + Ok(_) => { + debug!("Tracking enabled"); + IpcResponse::Ack + } + Err(_) => IpcResponse::Err, + }, + Err(_) => IpcResponse::Err, + }, + IpcCommand::Disable => match tracker.lock() { + Ok(mut t) => match t.disable() { + Ok(_) => { + debug!("Tracking disabled"); + IpcResponse::Ack + } + Err(_) => IpcResponse::Err, + }, + Err(_) => IpcResponse::Err, + }, + IpcCommand::Ping => IpcResponse::Ack, + }; + + // Send response back + let _ = msg.response_channel.send(response); +} diff --git a/crates/memtrack/src/lib.rs b/crates/memtrack/src/lib.rs new file mode 100644 index 00000000..b62ed344 --- /dev/null +++ b/crates/memtrack/src/lib.rs @@ -0,0 +1,14 @@ +#[cfg(feature = "ebpf")] +mod ebpf; +mod ipc; +mod libc; +pub use ipc::{ + IpcCommand as MemtrackIpcCommand, IpcMessage as MemtrackIpcMessage, + IpcResponse as MemtrackIpcResponse, MemtrackIpcClient, MemtrackIpcServer, +}; + +#[cfg(feature = "ebpf")] +pub use ebpf::*; + +#[cfg(feature = "ebpf")] +pub use ipc::handle_ipc_message; diff --git a/crates/memtrack/src/libc.rs b/crates/memtrack/src/libc.rs new file mode 100644 index 00000000..46e6010d --- /dev/null +++ b/crates/memtrack/src/libc.rs @@ -0,0 +1,50 @@ +#[cfg(feature = "ebpf")] +pub fn find_libc_paths() -> anyhow::Result> { + use itertools::Itertools; + + let mut paths = vec![ + "/lib/x86_64-linux-gnu/libc.so.6".into(), + "/usr/lib/x86_64-linux-gnu/libc.so.6".into(), + "/lib64/libc.so.6".into(), + "/usr/lib64/libc.so.6".into(), + ]; + + // On NixOS, try to find all glibc versions in the Nix store + if let Ok(entries) = std::fs::read_dir("/nix/store") { + let nix_paths: Vec<_> = entries + .filter_map(|entry| { + let Ok(entry) = entry else { return None }; + + let path = entry.path(); + let file_name = path.file_name()?; + let name = file_name.to_string_lossy(); + + // Look for glibc directories + if name.contains("glibc") && !name.contains("locales") && !name.contains("iconv") { + return Some(path.join("lib").join("libc.so.6")); + } + None + }) + .collect(); + + paths.extend(nix_paths); + } + + let existing_paths = paths + .into_iter() + .filter_map(|p| p.canonicalize().ok()) + .filter(|path| { + let Ok(metadata) = std::fs::metadata(path) else { + return false; + }; + metadata.is_file() + }) + .dedup() + .collect::>(); + + if existing_paths.is_empty() { + anyhow::bail!("Could not find libc.so.6"); + } + + Ok(existing_paths) +} diff --git a/crates/memtrack/src/main.rs b/crates/memtrack/src/main.rs new file mode 100644 index 00000000..7d3d96ba --- /dev/null +++ b/crates/memtrack/src/main.rs @@ -0,0 +1,139 @@ +use anyhow::{Context, Result, anyhow}; +use clap::Parser; +use ipc_channel::ipc::{self}; +use log::{debug, info}; +use memtrack::{Event, MemtrackIpcMessage, Tracker, handle_ipc_message}; +use runner_shared::artifacts::{ArtifactExt, MemtrackArtifact}; +use std::path::PathBuf; +use std::process::Command; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; +use std::thread; + +#[derive(Parser)] +#[command(name = "memtrack")] +#[command(version, about = "Track memory allocations using eBPF", long_about = None)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Parser)] +enum Commands { + /// Track memory allocations for a command + Track { + /// Command to execute and track + command: String, + + /// Output folder for the allocations data + #[arg(short, long, default_value = ".")] + output: PathBuf, + + /// Optional IPC server name for receiving control commands + #[arg(long)] + ipc_server: Option, + }, +} + +fn main() -> Result<()> { + env_logger::builder() + .parse_env(env_logger::Env::new().filter_or("CODSPEED_LOG", "info")) + .format_timestamp(None) + .init(); + + let cli = Cli::parse(); + + match cli.command { + Commands::Track { + command, + output: out_dir, + ipc_server, + } => { + debug!("Starting memtrack for command: {command}"); + + let (root_pid, events, status) = + track_command(&command, ipc_server).context("Failed to track command")?; + let result = MemtrackArtifact { + events: events.into_iter().map(|event| event.into()).collect(), + }; + result.save_with_pid_to(&out_dir, root_pid as libc::pid_t)?; + + std::process::exit(status.code().unwrap_or(1)); + } + } +} + +fn track_command( + cmd_string: &str, + ipc_server_name: Option, +) -> anyhow::Result<(u32, Vec, std::process::ExitStatus)> { + let events = Arc::new(Mutex::new(Vec::new())); + let tracker = Tracker::new()?; + + let tracker_arc = Arc::new(Mutex::new(tracker)); + let ipc_handle = if let Some(server_name) = ipc_server_name { + debug!("Connecting to IPC server: {server_name}"); + + let (tx, rx) = ipc::channel::()?; + let sender = ipc::IpcSender::connect(server_name)?; + sender.send(tx)?; + + let tracker_clone = tracker_arc.clone(); + Some(thread::spawn(move || { + while let Ok(msg) = rx.recv() { + handle_ipc_message(msg, &tracker_clone); + } + })) + } else { + None + }; + + // Start the target command using bash to handle shell syntax + let mut child = Command::new("bash") + .arg("-c") + .arg(cmd_string) + .spawn() + .map_err(|e| anyhow!("Failed to spawn child process: {e}"))?; + let root_pid = child.id() as i32; + let event_rx = { tracker_arc.lock().unwrap().track(root_pid)? }; + info!("Spawned child with pid {root_pid}"); + + // Spawn event processing thread + let events_clone = events.clone(); + let process_events = Arc::new(AtomicBool::new(true)); + let process_events_clone = process_events.clone(); + let processing_thread = thread::spawn(move || { + loop { + if !process_events_clone.load(Ordering::Relaxed) { + break; + } + + let Ok(event) = event_rx.try_recv() else { + continue; + }; + + let Ok(mut e) = events_clone.lock() else { + continue; + }; + + e.push(event); + } + }); + + // Wait for the command to complete + let status = child.wait().context("Failed to wait for command")?; + info!("Command exited with status: {status}"); + + info!("Waiting for the event processing thread to finish"); + process_events.store(false, Ordering::Relaxed); + processing_thread + .join() + .map_err(|_| anyhow::anyhow!("Failed to join event thread"))?; + + // IPC thread will exit when channel closes + drop(ipc_handle); + + info!("Unwrapping and returning events"); + let events = Arc::try_unwrap(events).map_err(|_| anyhow::anyhow!("Failed to unwrap events"))?; + Ok((root_pid as u32, events.into_inner()?, status)) +} diff --git a/crates/memtrack/testdata/aligned_alloc_test.c b/crates/memtrack/testdata/aligned_alloc_test.c new file mode 100644 index 00000000..1ceea965 --- /dev/null +++ b/crates/memtrack/testdata/aligned_alloc_test.c @@ -0,0 +1,9 @@ +#include +#include + +int main() { + sleep(1); + void* p = aligned_alloc(64, 512); + free(p); + return 0; +} diff --git a/crates/memtrack/testdata/alloc_size.c b/crates/memtrack/testdata/alloc_size.c new file mode 100644 index 00000000..e1323a77 --- /dev/null +++ b/crates/memtrack/testdata/alloc_size.c @@ -0,0 +1,17 @@ +#include +#include + +int main() { + sleep(1); + void* ptr1 = malloc(1024); + void* ptr2 = malloc(2048); + void* ptr3 = malloc(512); + void* ptr4 = malloc(4096); + + free(ptr1); + free(ptr2); + free(ptr3); + free(ptr4); + + return 0; +} diff --git a/crates/memtrack/testdata/calloc_test.c b/crates/memtrack/testdata/calloc_test.c new file mode 100644 index 00000000..ed30361b --- /dev/null +++ b/crates/memtrack/testdata/calloc_test.c @@ -0,0 +1,9 @@ +#include +#include + +int main() { + sleep(1); + void* p = calloc(10, 100); + free(p); + return 0; +} diff --git a/crates/memtrack/testdata/double_malloc.c b/crates/memtrack/testdata/double_malloc.c new file mode 100644 index 00000000..cd9504f3 --- /dev/null +++ b/crates/memtrack/testdata/double_malloc.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + sleep(1); + void* p1 = malloc(1024); + void* p2 = malloc(2048); + free(p1); + free(p2); + return 0; +} diff --git a/crates/memtrack/testdata/fork_test.c b/crates/memtrack/testdata/fork_test.c new file mode 100644 index 00000000..1d2aa8fa --- /dev/null +++ b/crates/memtrack/testdata/fork_test.c @@ -0,0 +1,24 @@ +#include +#include +#include + +int main() { + sleep(1); + // Parent allocates + void* p_parent = malloc(256); + + pid_t child_pid = fork(); + + if (child_pid == 0) { + // Child allocates + void* p_child = malloc(512); + free(p_child); + exit(0); + } else { + // Parent waits for child + waitpid(child_pid, NULL, 0); + free(p_parent); + } + + return 0; +} diff --git a/crates/memtrack/testdata/malloc_free.c b/crates/memtrack/testdata/malloc_free.c new file mode 100644 index 00000000..0edce0fb --- /dev/null +++ b/crates/memtrack/testdata/malloc_free.c @@ -0,0 +1,9 @@ +#include +#include + +int main() { + sleep(1); + void* p = malloc(512); + free(p); + return 0; +} diff --git a/crates/memtrack/testdata/many_allocs.c b/crates/memtrack/testdata/many_allocs.c new file mode 100644 index 00000000..b626e090 --- /dev/null +++ b/crates/memtrack/testdata/many_allocs.c @@ -0,0 +1,20 @@ +#include +#include + +int main() { + sleep(1); + void** ptrs = malloc(sizeof(void*) * 100); + + // Allocate 100 times + for (int i = 0; i < 100; i++) { + ptrs[i] = malloc(64); + } + + // Free them all + for (int i = 0; i < 100; i++) { + free(ptrs[i]); + } + + free(ptrs); + return 0; +} diff --git a/crates/memtrack/testdata/ordering_test.c b/crates/memtrack/testdata/ordering_test.c new file mode 100644 index 00000000..f7abeda1 --- /dev/null +++ b/crates/memtrack/testdata/ordering_test.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + sleep(1); + void* p1 = malloc(100); + void* p2 = malloc(200); + void* p3 = malloc(300); + free(p1); + free(p2); + free(p3); + return 0; +} diff --git a/crates/memtrack/testdata/realloc_test.c b/crates/memtrack/testdata/realloc_test.c new file mode 100644 index 00000000..86117068 --- /dev/null +++ b/crates/memtrack/testdata/realloc_test.c @@ -0,0 +1,10 @@ +#include +#include + +int main() { + sleep(1); + void* p = malloc(100); + p = realloc(p, 200); + free(p); + return 0; +} diff --git a/crates/memtrack/tests/integration_test.rs b/crates/memtrack/tests/integration_test.rs new file mode 100644 index 00000000..1834fc81 --- /dev/null +++ b/crates/memtrack/tests/integration_test.rs @@ -0,0 +1,236 @@ +use libbpf_rs::ErrorExt; +use memtrack::{Event, EventType, Tracker}; +use rstest::rstest; +use std::fs; +use std::path::Path; +use std::process::Command; +use std::time::Duration; +use tempfile::TempDir; + +pub fn track_binary(binary: &Path) -> anyhow::Result<(Vec, std::thread::JoinHandle<()>)> { + let child = Command::new(binary) + .spawn() + .context("Failed to spawn command")?; + let root_pid = child.id() as i32; + + let mut tracker = Tracker::new()?; + tracker.enable()?; + let rx = tracker.track(root_pid)?; + + let mut events = Vec::new(); + while let Ok(event) = rx.recv_timeout(Duration::from_secs(10)) { + events.push(event); + } + + // Drop the tracker in a new thread to not block the test + let thread_handle = std::thread::spawn(move || core::mem::drop(tracker)); + + eprintln!("Tracked {} events", events.len()); + eprintln!("Events: {events:#?}"); + + Ok((events, thread_handle)) +} + +/// Compiles C source code and returns the binary path +fn compile_c_source( + source_code: &str, + name: &str, + output_dir: &Path, +) -> Result> { + let source_path = output_dir.join(format!("{name}.c")); + let binary_path = output_dir.join(name); + + fs::write(&source_path, source_code)?; + + let output = Command::new("gcc") + .args(["-o", binary_path.to_str().unwrap()]) + .arg(&source_path) + .output()?; + + if !output.status.success() { + eprintln!("gcc stderr: {}", String::from_utf8_lossy(&output.stderr)); + return Err("Failed to compile C fixture".into()); + } + + Ok(binary_path) +} + +/// Helper to count events of a specific type +fn count_events_by_type(events: &[Event], event_type: EventType) -> usize { + events.iter().filter(|e| e.event_type == event_type).count() +} + +// ============================================================================ +// PARAMETERIZED ALLOCATION TESTS +// ============================================================================ + +/// Test case definition for allocation tracking tests +struct AllocationTestCase { + name: &'static str, + source: &'static str, + assertions: &'static [(EventType, usize)], + allow_excess: bool, // Whether to allow >= instead of exact == for expected counts +} + +const ALLOCATION_TEST_CASES: &[AllocationTestCase] = &[ + AllocationTestCase { + name: "double_malloc", + source: include_str!("../testdata/double_malloc.c"), + assertions: &[(EventType::Malloc, 2)], + allow_excess: false, + }, + AllocationTestCase { + name: "malloc_free", + source: include_str!("../testdata/malloc_free.c"), + assertions: &[(EventType::Malloc, 1), (EventType::Free, 1)], + allow_excess: false, + }, + AllocationTestCase { + name: "calloc_test", + source: include_str!("../testdata/calloc_test.c"), + assertions: &[(EventType::Calloc, 1), (EventType::Free, 1)], + allow_excess: false, + }, + AllocationTestCase { + name: "realloc_test", + source: include_str!("../testdata/realloc_test.c"), + assertions: &[ + (EventType::Malloc, 1), + (EventType::Realloc, 1), + (EventType::Free, 1), + ], + allow_excess: false, + }, + AllocationTestCase { + name: "aligned_alloc_test", + source: include_str!("../testdata/aligned_alloc_test.c"), + assertions: &[(EventType::AlignedAlloc, 1), (EventType::Free, 1)], + allow_excess: false, + }, + AllocationTestCase { + name: "many_allocs", + source: include_str!("../testdata/many_allocs.c"), + assertions: &[(EventType::Malloc, 100), (EventType::Free, 100)], + allow_excess: true, // Allow >= because we allocate ptrs array + 100 allocations + }, +]; + +#[rstest] +#[case(&ALLOCATION_TEST_CASES[0])] +#[case(&ALLOCATION_TEST_CASES[1])] +#[case(&ALLOCATION_TEST_CASES[2])] +#[case(&ALLOCATION_TEST_CASES[3])] +#[case(&ALLOCATION_TEST_CASES[4])] +#[case(&ALLOCATION_TEST_CASES[5])] +#[test_log::test] +fn test_allocation_tracking( + #[case] test_case: &AllocationTestCase, +) -> Result<(), Box> { + let temp_dir = TempDir::new()?; + let binary = compile_c_source(test_case.source, test_case.name, temp_dir.path())?; + + let (events, thread_handle) = track_binary(&binary)?; + + for (event_type, expected_count) in test_case.assertions { + let actual_count = count_events_by_type(&events, *event_type); + + if test_case.allow_excess { + assert!( + actual_count >= *expected_count, + "Test '{}': Expected at least {} {:?} events, got {}", + test_case.name, + expected_count, + event_type, + actual_count + ); + } else { + assert_eq!( + actual_count, *expected_count, + "Test '{}': Expected {} {:?} events, got {}", + test_case.name, expected_count, event_type, actual_count + ); + } + } + + thread_handle.join().unwrap(); + + Ok(()) +} + +#[test] +fn test_fork_tracking() -> Result<(), Box> { + let temp_dir = TempDir::new()?; + let source = include_str!("../testdata/fork_test.c"); + let binary = compile_c_source(source, "fork_test", temp_dir.path())?; + + let (events, thread_handle) = track_binary(&binary)?; + + let malloc_count = count_events_by_type(&events, EventType::Malloc); + let free_count = count_events_by_type(&events, EventType::Free); + + // Should have at least 2 mallocs (parent + child) + assert!( + malloc_count >= 2, + "Expected at least 2 malloc events (parent + child), got {malloc_count}" + ); + + // Should have at least 2 frees (parent + child) + assert!( + free_count >= 2, + "Expected at least 2 free events (parent + child), got {free_count}" + ); + + // Verify we have events from different PIDs (parent and child) + let pids: std::collections::HashSet = events.iter().map(|e| e.pid as u32).collect(); + assert!( + !pids.is_empty(), + "Expected to track at least parent process" + ); + + thread_handle.join().unwrap(); + + Ok(()) +} + +#[test] +fn test_allocation_sizes() -> Result<(), Box> { + let temp_dir = TempDir::new()?; + let source = include_str!("../testdata/alloc_size.c"); + let binary = compile_c_source(source, "alloc_size", temp_dir.path())?; + + let (events, thread_handle) = track_binary(&binary)?; + + // Filter malloc events and collect their sizes + let malloc_events: Vec = events + .iter() + .filter(|e| e.event_type == EventType::Malloc) + .map(|e| e.size) + .collect(); + + // Expected sizes from alloc_size.c: 1024, 2048, 512, 4096 + let expected_sizes = vec![1024u64, 2048, 512, 4096]; + + // Check that we have exactly 4 malloc events + assert_eq!( + malloc_events.len(), + 4, + "Expected 4 malloc events, got {}", + malloc_events.len() + ); + + // Check that all expected sizes are present + for expected_size in &expected_sizes { + assert!( + malloc_events.contains(expected_size), + "Expected allocation size {expected_size} not found in malloc events: {malloc_events:?}" + ); + } + + // Check that we have 4 free events + let free_count = count_events_by_type(&events, EventType::Free); + assert_eq!(free_count, 4, "Expected 4 free events, got {free_count}"); + + thread_handle.join().unwrap(); + + Ok(()) +} diff --git a/crates/memtrack/wrapper.h b/crates/memtrack/wrapper.h new file mode 100644 index 00000000..541d55a1 --- /dev/null +++ b/crates/memtrack/wrapper.h @@ -0,0 +1,2 @@ +#include +#include "src/ebpf/c/event.h" diff --git a/crates/runner-shared/Cargo.toml b/crates/runner-shared/Cargo.toml index bacdb59a..242dd56c 100644 --- a/crates/runner-shared/Cargo.toml +++ b/crates/runner-shared/Cargo.toml @@ -5,8 +5,11 @@ version = "0.1.0" edition = "2024" [dependencies] -anyhow = "1.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +anyhow = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } bincode = "1.3" -log = "0.4" +log = { workspace = true } +rmp = "0.8.14" +rmp-serde = "1.3.0" +libc = { workspace = true } diff --git a/crates/runner-shared/src/artifacts/execution_timestamps.rs b/crates/runner-shared/src/artifacts/execution_timestamps.rs new file mode 100644 index 00000000..80360a01 --- /dev/null +++ b/crates/runner-shared/src/artifacts/execution_timestamps.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +use crate::fifo::MarkerType; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ExecutionTimestamps { + pub uri_by_ts: Vec<(u64, String)>, + pub markers: Vec, +} +impl super::ArtifactExt for ExecutionTimestamps {} + +impl ExecutionTimestamps { + pub fn new(uri_by_ts: &[(u64, String)], markers: &[crate::fifo::MarkerType]) -> Self { + Self { + uri_by_ts: uri_by_ts.to_vec(), + markers: markers.to_vec(), + } + } +} diff --git a/crates/runner-shared/src/artifacts/memtrack.rs b/crates/runner-shared/src/artifacts/memtrack.rs new file mode 100644 index 00000000..5be15242 --- /dev/null +++ b/crates/runner-shared/src/artifacts/memtrack.rs @@ -0,0 +1,31 @@ +use libc::pid_t; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemtrackArtifact { + pub events: Vec, +} +impl super::ArtifactExt for MemtrackArtifact {} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct MemtrackEvent { + pub pid: pid_t, + pub tid: pid_t, + pub timestamp: u64, + pub addr: u64, + #[serde(flatten)] + pub kind: MemtrackEventKind, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum MemtrackEventKind { + Malloc { size: u64 }, + Free, + Realloc { size: u64 }, + Calloc { size: u64 }, + AlignedAlloc { size: u64 }, + Mmap { size: u64 }, + Munmap { size: u64 }, + Brk { size: u64 }, +} diff --git a/crates/runner-shared/src/artifacts/mod.rs b/crates/runner-shared/src/artifacts/mod.rs new file mode 100644 index 00000000..a2d015bf --- /dev/null +++ b/crates/runner-shared/src/artifacts/mod.rs @@ -0,0 +1,44 @@ +use libc::pid_t; +use log::debug; +use serde::Serialize; + +mod execution_timestamps; +mod memtrack; + +pub use execution_timestamps::*; +pub use memtrack::*; + +pub trait ArtifactExt +where + Self: Sized + Serialize, +{ + /// WARNING: This doesn't support generic types + fn name() -> &'static str { + std::any::type_name::().rsplit("::").next().unwrap() + } + + fn save_file_to>( + &self, + folder: P, + filename: &str, + ) -> anyhow::Result<()> { + std::fs::create_dir_all(folder.as_ref())?; + let data = rmp_serde::to_vec_named(self)?; + std::fs::write(folder.as_ref().join(filename), data)?; + + debug!("Saved {} result to {:?}", Self::name(), folder.as_ref()); + Ok(()) + } + + fn save_to>(&self, folder: P) -> anyhow::Result<()> { + self.save_file_to(folder, &format!("{}.msgpack", Self::name())) + } + + fn save_with_pid_to>( + &self, + folder: P, + pid: pid_t, + ) -> anyhow::Result<()> { + self.save_file_to(folder, &format!("{pid}.{}.msgpack", Self::name())) + } +} diff --git a/crates/runner-shared/src/fifo.rs b/crates/runner-shared/src/fifo.rs index b45bbeb7..84baed2a 100644 --- a/crates/runner-shared/src/fifo.rs +++ b/crates/runner-shared/src/fifo.rs @@ -19,15 +19,34 @@ pub enum MarkerType { BenchmarkEnd(u64), } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +pub enum IntegrationMode { + Perf, + Simulation, + Analysis, +} + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)] pub enum Command { - CurrentBenchmark { pid: i32, uri: String }, + CurrentBenchmark { + pid: i32, + uri: String, + }, StartBenchmark, StopBenchmark, Ack, + #[deprecated(note = "Use `GetIntegrationMode` instead")] PingPerf, - SetIntegration { name: String, version: String }, + SetIntegration { + name: String, + version: String, + }, Err, - AddMarker { pid: i32, marker: MarkerType }, + AddMarker { + pid: i32, + marker: MarkerType, + }, SetVersion(u64), + GetIntegrationMode, + IntegrationModeResponse(IntegrationMode), } diff --git a/crates/runner-shared/src/lib.rs b/crates/runner-shared/src/lib.rs index a5d0237a..95950044 100644 --- a/crates/runner-shared/src/lib.rs +++ b/crates/runner-shared/src/lib.rs @@ -1,3 +1,4 @@ +pub mod artifacts; pub mod debug_info; pub mod fifo; pub mod metadata; diff --git a/crates/runner-shared/src/metadata.rs b/crates/runner-shared/src/metadata.rs index 19b884b2..5493fa39 100644 --- a/crates/runner-shared/src/metadata.rs +++ b/crates/runner-shared/src/metadata.rs @@ -14,12 +14,14 @@ pub struct PerfMetadata { pub integration: (String, String), /// The URIs of the benchmarks with the timestamps they were executed at. + #[deprecated(note = "Use ExecutionTimestamps in the 'artifacts' module instead")] pub uri_by_ts: Vec<(u64, String)>, /// Modules that should be ignored and removed from the folded trace and callgraph (e.g. python interpreter) pub ignored_modules: Vec<(String, u64, u64)>, /// Marker for certain regions in the profiling data + #[deprecated(note = "Use ExecutionTimestamps in the 'artifacts' module instead")] pub markers: Vec, /// Debug info for all modules across all processes, mapping PID to module debug info diff --git a/src/run/mod.rs b/src/run/mod.rs index 45bfb767..e6022203 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -148,6 +148,7 @@ pub enum RunnerMode { Instrumentation, Simulation, Walltime, + Memory, } #[derive(ValueEnum, Clone, Debug, PartialEq)] diff --git a/src/run/runner/helpers/env.rs b/src/run/runner/helpers/env.rs index 509f8a30..03fcdf40 100644 --- a/src/run/runner/helpers/env.rs +++ b/src/run/runner/helpers/env.rs @@ -15,6 +15,7 @@ pub fn get_base_injected_env( #[allow(deprecated)] RunnerMode::Instrumentation | RunnerMode::Simulation => "instrumentation", RunnerMode::Walltime => "walltime", + RunnerMode::Memory => "memory", }; HashMap::from([ ("PYTHONHASHSEED", "0".into()), diff --git a/src/run/runner/helpers/run_with_sudo.rs b/src/run/runner/helpers/run_with_sudo.rs index 88f39101..811f6dc0 100644 --- a/src/run/runner/helpers/run_with_sudo.rs +++ b/src/run/runner/helpers/run_with_sudo.rs @@ -67,8 +67,12 @@ pub fn wrap_with_sudo(mut cmd_builder: CommandBuilder) -> Result validate_sudo_access()?; cmd_builder.wrap( "sudo", - // Password prompt should not appear here since it has already been validated - ["--non-interactive"], + [ + // Password prompt should not appear here since it has already been validated + "--non-interactive", + // Forward all environment variables to the command + "--preserve-env", + ], ); Ok(cmd_builder) } else { diff --git a/src/run/runner/interfaces.rs b/src/run/runner/interfaces.rs index 66fbc6db..bc17e089 100644 --- a/src/run/runner/interfaces.rs +++ b/src/run/runner/interfaces.rs @@ -10,6 +10,7 @@ pub struct RunData { pub enum ExecutorName { Valgrind, WallTime, + Memory, } #[allow(clippy::to_string_trait_impl)] @@ -18,6 +19,7 @@ impl ToString for ExecutorName { match self { ExecutorName::Valgrind => "valgrind".to_string(), ExecutorName::WallTime => "walltime".to_string(), + ExecutorName::Memory => "memory".to_string(), } } } diff --git a/src/run/runner/memory/executor.rs b/src/run/runner/memory/executor.rs new file mode 100644 index 00000000..9c3024c1 --- /dev/null +++ b/src/run/runner/memory/executor.rs @@ -0,0 +1,184 @@ +use crate::prelude::*; +use crate::run::instruments::mongo_tracer::MongoTracer; +use crate::run::runner::executor::Executor; +use crate::run::runner::helpers::command::CommandBuilder; +use crate::run::runner::helpers::get_bench_command::get_bench_command; +use crate::run::runner::helpers::run_command_with_log_pipe::run_command_with_log_pipe_and_callback; +use crate::run::runner::helpers::run_with_sudo::wrap_with_sudo; +use crate::run::runner::shared::fifo::RunnerFifo; +use crate::run::runner::{ExecutorName, RunData}; +use crate::run::{check_system::SystemInfo, config::Config}; +use async_trait::async_trait; +use ipc_channel::ipc; +use memtrack::MemtrackIpcClient; +use memtrack::MemtrackIpcServer; +use runner_shared::artifacts::{ArtifactExt, ExecutionTimestamps}; +use runner_shared::fifo::Command as FifoCommand; +use runner_shared::fifo::IntegrationMode; +use std::path::Path; +use std::process::Command; +use std::rc::Rc; + +pub struct MemoryExecutor; + +impl MemoryExecutor { + fn build_memtrack_command( + config: &Config, + run_data: &RunData, + ) -> Result<(MemtrackIpcServer, CommandBuilder)> { + // FIXME: We only support native languages for now + + // Find memtrack binary - check env variable or use default command name + let memtrack_path = std::env::var("CODSPEED_MEMTRACK_BINARY") + .unwrap_or_else(|_| "codspeed-memtrack".to_string()); + + let mut cmd_builder = CommandBuilder::new(memtrack_path); + cmd_builder.arg("track"); + cmd_builder.arg(get_bench_command(config)?); + cmd_builder.arg("--output"); + cmd_builder.arg(run_data.profile_folder.join("results")); + + // Setup memtrack IPC server + let (ipc_server, server_name) = ipc::IpcOneShotServer::new()?; + cmd_builder.arg("--ipc-server"); + cmd_builder.arg(server_name); + + Ok((ipc_server, cmd_builder)) + } +} + +#[async_trait(?Send)] +impl Executor for MemoryExecutor { + fn name(&self) -> ExecutorName { + ExecutorName::Memory + } + + async fn setup( + &self, + _system_info: &SystemInfo, + _setup_cache_dir: Option<&Path>, + ) -> Result<()> { + // Validate that the codspeed-memtrack command is available + let memtrack_path = std::env::var("CODSPEED_MEMTRACK_BINARY") + .unwrap_or_else(|_| "codspeed-memtrack".to_string()); + + info!("Validating memtrack binary at path: {memtrack_path}"); + let output = Command::new(&memtrack_path).arg("--version").output()?; + if !output.status.success() { + bail!( + "codspeed-memtrack command is not available or failed to execute\nstdout: {}\nstderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + } + + Ok(()) + } + + async fn run( + &self, + config: &Config, + _system_info: &SystemInfo, + run_data: &RunData, + _mongo_tracer: &Option, + ) -> Result<()> { + // Create the results/ directory inside the profile folder to avoid having memtrack create it with wrong permissions + std::fs::create_dir_all(run_data.profile_folder.join("results"))?; + + let (ipc, cmd_builder) = Self::build_memtrack_command(config, run_data)?; + let cmd = wrap_with_sudo(cmd_builder)?.build(); + debug!("cmd: {cmd:?}"); + + let runner_fifo = RunnerFifo::new()?; + let on_process_started = async |pid| -> anyhow::Result<()> { + let marker_result = Self::handle_fifo(runner_fifo, pid, ipc).await?; + + // Directly write to the profile folder, to avoid having to define another field + marker_result + .save_to(run_data.profile_folder.join("results")) + .unwrap(); + + Ok(()) + }; + + let status = run_command_with_log_pipe_and_callback(cmd, on_process_started).await?; + debug!("cmd exit status: {status:?}"); + + if !status.success() { + bail!("failed to execute memory tracker process: {status}"); + } + + Ok(()) + } + + async fn teardown( + &self, + _config: &Config, + _system_info: &SystemInfo, + _run_data: &RunData, + ) -> Result<()> { + Ok(()) + } +} + +impl MemoryExecutor { + async fn handle_fifo( + mut runner_fifo: RunnerFifo, + pid: u32, + ipc: MemtrackIpcServer, + ) -> anyhow::Result { + debug!("handle_fifo called with PID {pid}"); + + // Accept the IPC connection from memtrack and get the sender it sends us + let (_, memtrack_sender) = ipc.accept()?; + let ipc_client = Rc::new(MemtrackIpcClient::from_accepted(memtrack_sender)); + + let ipc_client_health = Rc::clone(&ipc_client); + let health_check = async move || { + // Ping memtrack via IPC to check if it's still responding + match ipc_client_health.ping() { + Ok(()) => Ok(true), + Err(_) => Ok(false), + } + }; + + let on_cmd = async move |cmd: &FifoCommand| { + match cmd { + FifoCommand::CurrentBenchmark { pid, uri } => { + debug!("Current benchmark: {pid}, {uri}"); + } + FifoCommand::StartBenchmark => { + debug!("Enabling memtrack via IPC"); + if let Err(e) = ipc_client.enable() { + error!("Failed to enable memtrack: {e}"); + return Ok(FifoCommand::Err); + } + } + FifoCommand::StopBenchmark => { + debug!("Disabling memtrack via IPC"); + if let Err(e) = ipc_client.disable() { + // There's a chance that memtrack has already exited here, so just log as debug + debug!("Failed to disable memtrack: {e}"); + return Ok(FifoCommand::Err); + } + } + FifoCommand::GetIntegrationMode => { + return Ok(FifoCommand::IntegrationModeResponse( + IntegrationMode::Analysis, + )); + } + _ => { + warn!("Unhandled FIFO command: {cmd:?}"); + return Ok(FifoCommand::Err); + } + } + + Ok(FifoCommand::Ack) + }; + + let (marker_result, _) = runner_fifo + .handle_fifo_messages(health_check, on_cmd) + .await?; + Ok(marker_result) + } +} diff --git a/src/run/runner/memory/mod.rs b/src/run/runner/memory/mod.rs new file mode 100644 index 00000000..0c95fdab --- /dev/null +++ b/src/run/runner/memory/mod.rs @@ -0,0 +1 @@ +pub mod executor; diff --git a/src/run/runner/mod.rs b/src/run/runner/mod.rs index 77bff9c0..ffbe32e5 100644 --- a/src/run/runner/mod.rs +++ b/src/run/runner/mod.rs @@ -7,6 +7,8 @@ use super::{RunnerMode, config::Config}; mod executor; mod helpers; mod interfaces; +mod memory; +mod shared; #[cfg(test)] mod tests; mod valgrind; @@ -15,6 +17,7 @@ mod wall_time; use executor::Executor; use helpers::profile_folder::create_profile_folder; pub use interfaces::{ExecutorName, RunData}; +use memory::executor::MemoryExecutor; use valgrind::executor::ValgrindExecutor; use wall_time::executor::WallTimeExecutor; @@ -25,6 +28,7 @@ impl Display for RunnerMode { RunnerMode::Instrumentation => write!(f, "instrumentation"), RunnerMode::Simulation => write!(f, "simulation"), RunnerMode::Walltime => write!(f, "walltime"), + RunnerMode::Memory => write!(f, "memory"), } } } @@ -36,6 +40,7 @@ pub fn get_executor_from_mode(mode: &RunnerMode) -> Box { #[allow(deprecated)] RunnerMode::Instrumentation | RunnerMode::Simulation => Box::new(ValgrindExecutor), RunnerMode::Walltime => Box::new(WallTimeExecutor::new()), + RunnerMode::Memory => Box::new(MemoryExecutor), } } @@ -43,6 +48,7 @@ pub fn get_all_executors() -> Vec> { vec![ Box::new(ValgrindExecutor), Box::new(WallTimeExecutor::new()), + Box::new(MemoryExecutor), ] } diff --git a/src/run/runner/shared/fifo.rs b/src/run/runner/shared/fifo.rs new file mode 100644 index 00000000..3df7125a --- /dev/null +++ b/src/run/runner/shared/fifo.rs @@ -0,0 +1,224 @@ +use crate::prelude::*; +use anyhow::Context; +use nix::{sys::time::TimeValLike, time::clock_gettime}; +use runner_shared::artifacts::ExecutionTimestamps; +use runner_shared::fifo::{Command as FifoCommand, MarkerType}; +use runner_shared::fifo::{RUNNER_ACK_FIFO, RUNNER_CTL_FIFO}; +use std::cmp::Ordering; +use std::path::{Path, PathBuf}; +use std::{collections::HashSet, time::Duration}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::unix::pid_t; +use tokio::net::unix::pipe::OpenOptions as TokioPipeOpenOptions; +use tokio::net::unix::pipe::Receiver as TokioPipeReader; +use tokio::net::unix::pipe::Sender as TokioPipeSender; + +fn create_fifo>(path: P) -> anyhow::Result<()> { + // Remove the previous FIFO (if it exists) + let _ = nix::unistd::unlink(path.as_ref()); + + // Create the FIFO with RWX permissions for the owner + nix::unistd::mkfifo(path.as_ref(), nix::sys::stat::Mode::S_IRWXU)?; + + Ok(()) +} + +pub struct GenericFifo { + ctl_path: PathBuf, + ack_path: PathBuf, + ctl_sender: TokioPipeSender, + ack_reader: TokioPipeReader, +} + +impl GenericFifo { + pub fn new(ctl_fifo: &Path, ack_fifo: &Path) -> anyhow::Result { + create_fifo(ctl_fifo)?; + create_fifo(ack_fifo)?; + + let ctl_sender = get_pipe_open_options().open_sender(ctl_fifo)?; + let ack_reader = get_pipe_open_options().open_receiver(ack_fifo)?; + + Ok(Self { + ctl_path: ctl_fifo.to_path_buf(), + ack_path: ack_fifo.to_path_buf(), + ctl_sender, + ack_reader, + }) + } + + pub fn ctl_sender(&mut self) -> &mut TokioPipeSender { + &mut self.ctl_sender + } + + pub fn ack_reader(&mut self) -> &mut TokioPipeReader { + &mut self.ack_reader + } + + pub fn ctl_path(&self) -> &Path { + &self.ctl_path + } + + pub fn ack_path(&self) -> &Path { + &self.ack_path + } +} + +pub struct FifoBenchmarkData { + /// Name and version of the integration + pub integration: Option<(String, String)>, + pub bench_pids: HashSet, +} + +pub struct RunnerFifo { + ack_fifo: TokioPipeSender, + ctl_fifo: TokioPipeReader, +} + +fn get_pipe_open_options() -> TokioPipeOpenOptions { + #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] + let mut options = TokioPipeOpenOptions::new(); + #[cfg(target_os = "linux")] + options.read_write(true); + options +} + +impl RunnerFifo { + pub fn new() -> anyhow::Result { + create_fifo(RUNNER_CTL_FIFO)?; + create_fifo(RUNNER_ACK_FIFO)?; + + let ack_fifo = get_pipe_open_options().open_sender(RUNNER_ACK_FIFO)?; + let ctl_fifo = get_pipe_open_options().open_receiver(RUNNER_CTL_FIFO)?; + + Ok(Self { ctl_fifo, ack_fifo }) + } + + pub async fn recv_cmd(&mut self) -> anyhow::Result { + let mut len_buffer = [0u8; 4]; + self.ctl_fifo.read_exact(&mut len_buffer).await?; + let message_len = u32::from_le_bytes(len_buffer) as usize; + + let mut buffer = vec![0u8; message_len]; + loop { + if self.ctl_fifo.read_exact(&mut buffer).await.is_ok() { + break; + } + } + + let decoded = bincode::deserialize(&buffer).with_context(|| { + format!("Failed to deserialize FIFO command (len: {message_len}, data: {buffer:?})") + })?; + Ok(decoded) + } + + pub async fn send_cmd(&mut self, cmd: FifoCommand) -> anyhow::Result<()> { + let encoded = bincode::serialize(&cmd)?; + + self.ack_fifo + .write_all(&(encoded.len() as u32).to_le_bytes()) + .await?; + self.ack_fifo.write_all(&encoded).await?; + Ok(()) + } + + /// Handles all incoming FIFO messages until it's closed, or until the health check closure + /// returns `false` or an error. + pub async fn handle_fifo_messages( + &mut self, + mut health_check: impl AsyncFnMut() -> anyhow::Result, + mut handle_cmd: impl AsyncFnMut(&FifoCommand) -> anyhow::Result, + ) -> anyhow::Result<(ExecutionTimestamps, FifoBenchmarkData)> { + let mut bench_order_by_timestamp = Vec::<(u64, String)>::new(); + let mut bench_pids = HashSet::::new(); + let mut markers = Vec::::new(); + + let mut integration = None; + + let current_time = || { + clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC) + .unwrap() + .num_nanoseconds() as u64 + }; + + let mut benchmark_started = false; + loop { + let is_alive = health_check().await?; + if !is_alive { + break; + } + + let result = tokio::time::timeout(Duration::from_secs(5), self.recv_cmd()).await; + let cmd = match result { + Ok(Ok(cmd)) => cmd, + Ok(Err(e)) => { + warn!("Failed to parse FIFO command: {e}"); + break; + } + Err(_) => continue, + }; + trace!("Received command: {cmd:?}"); + + match &cmd { + FifoCommand::CurrentBenchmark { pid, uri } => { + bench_order_by_timestamp.push((current_time(), uri.to_string())); + bench_pids.insert(*pid); + } + FifoCommand::StartBenchmark => { + if benchmark_started { + warn!("Received duplicate StartBenchmark command, ignoring"); + self.send_cmd(FifoCommand::Ack).await?; + continue; + } + benchmark_started = true; + markers.push(MarkerType::SampleStart(current_time())); + } + FifoCommand::StopBenchmark => { + if !benchmark_started { + warn!("Received StopBenchmark command before StartBenchmark, ignoring"); + self.send_cmd(FifoCommand::Ack).await?; + continue; + } + benchmark_started = false; + markers.push(MarkerType::SampleEnd(current_time())); + } + FifoCommand::SetIntegration { name, version } => { + integration = Some((name.into(), version.into())); + self.send_cmd(FifoCommand::Ack).await?; + continue; + } + FifoCommand::AddMarker { marker, .. } => { + markers.push(*marker); + self.send_cmd(FifoCommand::Ack).await?; + continue; + } + FifoCommand::SetVersion(protocol_version) => { + match protocol_version.cmp(&runner_shared::fifo::CURRENT_PROTOCOL_VERSION) { + Ordering::Less => panic!( + "Integration is using an incompatible protocol version ({protocol_version} < {}). Please update the integration to the latest version.", + runner_shared::fifo::CURRENT_PROTOCOL_VERSION + ), + Ordering::Greater => panic!( + "Runner is using an incompatible protocol version ({} < {protocol_version}). Please update the runner to the latest version.", + runner_shared::fifo::CURRENT_PROTOCOL_VERSION + ), + Ordering::Equal => { + self.send_cmd(FifoCommand::Ack).await?; + continue; + } + } + } + _ => {} + } + + self.send_cmd(handle_cmd(&cmd).await?).await?; + } + + let marker_result = ExecutionTimestamps::new(&bench_order_by_timestamp, &markers); + let fifo_data = FifoBenchmarkData { + integration, + bench_pids, + }; + + Ok((marker_result, fifo_data)) + } +} diff --git a/src/run/runner/shared/mod.rs b/src/run/runner/shared/mod.rs new file mode 100644 index 00000000..2badf406 --- /dev/null +++ b/src/run/runner/shared/mod.rs @@ -0,0 +1 @@ +pub mod fifo; diff --git a/src/run/runner/tests.rs b/src/run/runner/tests.rs index 738755a1..50de4cf4 100644 --- a/src/run/runner/tests.rs +++ b/src/run/runner/tests.rs @@ -2,6 +2,7 @@ use crate::run::check_system::SystemInfo; use crate::run::config::Config; use crate::run::runner::executor::Executor; use crate::run::runner::interfaces::RunData; +use crate::run::runner::memory::executor::MemoryExecutor; use crate::run::runner::valgrind::executor::ValgrindExecutor; use crate::run::{RunnerMode, runner::wall_time::executor::WallTimeExecutor}; use rstest_reuse::{self, *}; @@ -129,23 +130,38 @@ async fn create_test_setup() -> (SystemInfo, RunData, TempDir) { (system_info, run_data, temp_dir) } +// Uprobes set by memtrack, lead to crashes in valgrind because they work by setting breakpoints on the first +// instruction. Valgrind doesn't rethrow those breakpoint exceptions, which makes the test crash. +// +// Therefore, we can only execute either valgrind or memtrack at any time, and not both at the same time. +static BPF_INSTRUMENTATION_LOCK: OnceCell = OnceCell::const_new(); + +async fn acquire_bpf_instrumentation_lock() -> SemaphorePermit<'static> { + let semaphore = BPF_INSTRUMENTATION_LOCK + .get_or_init(|| async { Semaphore::new(1) }) + .await; + semaphore.acquire().await.unwrap() +} + mod valgrind { use super::*; - async fn get_valgrind_executor() -> &'static ValgrindExecutor { + async fn get_valgrind_executor() -> (SemaphorePermit<'static>, &'static ValgrindExecutor) { static VALGRIND_EXECUTOR: OnceCell = OnceCell::const_new(); - VALGRIND_EXECUTOR + let executor = VALGRIND_EXECUTOR .get_or_init(|| async { let executor = ValgrindExecutor; let system_info = SystemInfo::new().unwrap(); executor.setup(&system_info, None).await.unwrap(); executor }) - .await + .await; + let _lock = acquire_bpf_instrumentation_lock().await; + + (_lock, executor) } - #[cfg(test)] fn valgrind_config(command: &str) -> Config { Config { mode: RunnerMode::Simulation, @@ -155,10 +171,10 @@ mod valgrind { } #[apply(test_cases)] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_valgrind_executor(#[case] cmd: &str) { let (system_info, run_data, _temp_dir) = create_test_setup().await; - let executor = get_valgrind_executor().await; + let (_lock, executor) = get_valgrind_executor().await; let config = valgrind_config(cmd); executor @@ -168,10 +184,10 @@ mod valgrind { } #[apply(env_test_cases)] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_valgrind_executor_with_env(#[case] env_case: (&str, &str)) { let (system_info, run_data, _temp_dir) = create_test_setup().await; - let executor = get_valgrind_executor().await; + let (_lock, executor) = get_valgrind_executor().await; let (env_var, env_value) = env_case; temp_env::async_with_vars(&[(env_var, Some(env_value))], async { @@ -222,7 +238,7 @@ mod walltime { #[apply(test_cases)] #[rstest::rstest] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_walltime_executor(#[case] cmd: &str, #[values(false, true)] enable_perf: bool) { let (system_info, run_data, _temp_dir) = create_test_setup().await; let (_permit, executor) = get_walltime_executor().await; @@ -236,7 +252,7 @@ mod walltime { #[apply(env_test_cases)] #[rstest::rstest] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_walltime_executor_with_env( #[case] env_case: (&str, &str), #[values(false, true)] enable_perf: bool, @@ -258,7 +274,7 @@ mod walltime { // Ensure that the working directory is used correctly #[rstest::rstest] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_walltime_executor_in_working_dir(#[values(false, true)] enable_perf: bool) { let (system_info, run_data, _temp_dir) = create_test_setup().await; let (_permit, executor) = get_walltime_executor().await; @@ -289,7 +305,7 @@ fi // Ensure that commands that fail actually fail #[rstest::rstest] - #[tokio::test] + #[test_log::test(tokio::test)] async fn test_walltime_executor_fails(#[values(false, true)] enable_perf: bool) { let (system_info, run_data, _temp_dir) = create_test_setup().await; let (_permit, executor) = get_walltime_executor().await; @@ -299,3 +315,73 @@ fi assert!(result.is_err(), "Command should fail"); } } + +mod memory { + use super::*; + + async fn get_memory_executor() -> ( + SemaphorePermit<'static>, + SemaphorePermit<'static>, + MemoryExecutor, + ) { + static MEMORY_INIT: OnceCell<()> = OnceCell::const_new(); + static MEMORY_SEMAPHORE: OnceCell = OnceCell::const_new(); + + MEMORY_INIT + .get_or_init(|| async { + let executor = MemoryExecutor; + let system_info = SystemInfo::new().unwrap(); + executor.setup(&system_info, None).await.unwrap(); + }) + .await; + + let semaphore = MEMORY_SEMAPHORE + .get_or_init(|| async { Semaphore::new(1) }) + .await; + let permit = semaphore.acquire().await.unwrap(); + + // Memory executor uses heaptrack which uses BPF-based instrumentation, which conflicts with valgrind. + let _lock = acquire_bpf_instrumentation_lock().await; + + (permit, _lock, MemoryExecutor) + } + + fn memory_config(command: &str) -> Config { + Config { + mode: RunnerMode::Memory, + command: command.to_string(), + ..Config::test() + } + } + + #[apply(test_cases)] + #[test_log::test(tokio::test)] + async fn test_memory_executor(#[case] cmd: &str) { + let (system_info, run_data, _temp_dir) = create_test_setup().await; + let (_permit, _lock, executor) = get_memory_executor().await; + + let config = memory_config(cmd); + executor + .run(&config, &system_info, &run_data, &None) + .await + .unwrap(); + } + + #[apply(env_test_cases)] + #[test_log::test(tokio::test)] + async fn test_memory_executor_with_env(#[case] env_case: (&str, &str)) { + let (system_info, run_data, _temp_dir) = create_test_setup().await; + let (_permit, _lock, executor) = get_memory_executor().await; + + let (env_var, env_value) = env_case; + temp_env::async_with_vars(&[(env_var, Some(env_value))], async { + let cmd = env_var_validation_script(env_var, env_value); + let config = memory_config(&cmd); + executor + .run(&config, &system_info, &run_data, &None) + .await + .unwrap(); + }) + .await; + } +} diff --git a/src/run/runner/wall_time/executor.rs b/src/run/runner/wall_time/executor.rs index 749aba01..4d586817 100644 --- a/src/run/runner/wall_time/executor.rs +++ b/src/run/runner/wall_time/executor.rs @@ -202,7 +202,7 @@ impl Executor for WallTimeExecutor { }; let status = status.map_err(|e| anyhow!("failed to execute the benchmark process. {e}"))?; - debug!("cmd exit status: {:?}", status); + debug!("cmd exit status: {status:?}"); if !status.success() { bail!("failed to execute the benchmark process: {status}"); @@ -248,7 +248,7 @@ mod tests { let mut script_file = tempfile::Builder::new() .suffix(".sh") .permissions(rwx) - .keep(true) + .disable_cleanup(true) .tempfile()?; script_file.write_all(content.as_bytes())?; diff --git a/src/run/runner/wall_time/perf/fifo.rs b/src/run/runner/wall_time/perf/fifo.rs index 5ba2c088..c82eb695 100644 --- a/src/run/runner/wall_time/perf/fifo.rs +++ b/src/run/runner/wall_time/perf/fifo.rs @@ -1,120 +1,38 @@ -use super::FifoCommand; -use anyhow::Context; -use runner_shared::fifo::{RUNNER_ACK_FIFO, RUNNER_CTL_FIFO}; -use std::path::PathBuf; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::unix::pipe::OpenOptions as TokioPipeOpenOptions; -use tokio::net::unix::pipe::Receiver as TokioPipeReader; -use tokio::net::unix::pipe::Sender as TokioPipeSender; - -fn create_fifo>(path: P) -> anyhow::Result<()> { - // Remove the previous FIFO (if it exists) - let _ = nix::unistd::unlink(path.as_ref()); - - // Create the FIFO with RWX permissions for the owner - nix::unistd::mkfifo(path.as_ref(), nix::sys::stat::Mode::S_IRWXU)?; - - Ok(()) -} - -pub struct RunnerFifo { - ack_fifo: TokioPipeSender, - ctl_fifo: TokioPipeReader, -} - -fn get_pipe_open_options() -> TokioPipeOpenOptions { - #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] - let mut options = TokioPipeOpenOptions::new(); - #[cfg(target_os = "linux")] - options.read_write(true); - options -} - -impl RunnerFifo { - pub fn new() -> anyhow::Result { - create_fifo(RUNNER_CTL_FIFO)?; - create_fifo(RUNNER_ACK_FIFO)?; - - let ack_fifo = get_pipe_open_options().open_sender(RUNNER_ACK_FIFO)?; - let ctl_fifo = get_pipe_open_options().open_receiver(RUNNER_CTL_FIFO)?; - - Ok(Self { ctl_fifo, ack_fifo }) - } - - pub async fn recv_cmd(&mut self) -> anyhow::Result { - let mut len_buffer = [0u8; 4]; - self.ctl_fifo.read_exact(&mut len_buffer).await?; - let message_len = u32::from_le_bytes(len_buffer) as usize; - - let mut buffer = vec![0u8; message_len]; - loop { - if self.ctl_fifo.read_exact(&mut buffer).await.is_ok() { - break; - } - } - - let decoded = bincode::deserialize(&buffer).with_context(|| { - format!("Failed to deserialize FIFO command (len: {message_len}, data: {buffer:?})") - })?; - Ok(decoded) - } - - pub async fn send_cmd(&mut self, cmd: FifoCommand) -> anyhow::Result<()> { - let encoded = bincode::serialize(&cmd)?; +use std::ops::Deref; - self.ack_fifo - .write_all(&(encoded.len() as u32).to_le_bytes()) - .await?; - self.ack_fifo.write_all(&encoded).await?; - Ok(()) - } -} +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use crate::run::runner::shared::fifo::GenericFifo; pub struct PerfFifo { - ctl_fifo: TokioPipeSender, - ack_fifo: TokioPipeReader, - - pub(crate) ctl_fifo_path: PathBuf, - pub(crate) ack_fifo_path: PathBuf, + fifo: GenericFifo, } impl PerfFifo { pub fn new() -> anyhow::Result { - let fifo_dir = tempfile::tempdir()?.into_path(); - - let ctl_fifo_path = fifo_dir.join("codspeed_perf.ctl.fifo"); - let ack_fifo_path = fifo_dir.join("codspeed_perf.ack.fifo"); - - create_fifo(&ctl_fifo_path)?; - create_fifo(&ack_fifo_path)?; - - let ack_fifo = get_pipe_open_options().open_receiver(&ack_fifo_path)?; - let ctl_fifo = get_pipe_open_options().open_sender(&ctl_fifo_path)?; - - Ok(Self { - ctl_fifo, - ack_fifo, - ctl_fifo_path, - ack_fifo_path, - }) + let fifo_dir = tempfile::tempdir()?.keep(); + let fifo = GenericFifo::new( + &fifo_dir.join("codspeed_perf.ctl.fifo"), + &fifo_dir.join("codspeed_perf.ack.fifo"), + )?; + Ok(Self { fifo }) } pub async fn start_events(&mut self) -> anyhow::Result<()> { - self.ctl_fifo.write_all(b"enable\n\0").await?; + self.fifo.ctl_sender().write_all(b"enable\n\0").await?; self.wait_for_ack().await; Ok(()) } pub async fn stop_events(&mut self) -> anyhow::Result<()> { - self.ctl_fifo.write_all(b"disable\n\0").await?; + self.fifo.ctl_sender().write_all(b"disable\n\0").await?; self.wait_for_ack().await; Ok(()) } pub async fn ping(&mut self) -> anyhow::Result<()> { - self.ctl_fifo.write_all(b"ping\n\0").await?; + self.fifo.ctl_sender().write_all(b"ping\n\0").await?; self.wait_for_ack().await; Ok(()) @@ -125,7 +43,7 @@ impl PerfFifo { loop { let mut buf: [u8; ACK.len()] = [0; ACK.len()]; - if self.ack_fifo.read_exact(&mut buf).await.is_err() { + if self.fifo.ack_reader().read_exact(&mut buf).await.is_err() { continue; } @@ -135,3 +53,11 @@ impl PerfFifo { } } } + +impl Deref for PerfFifo { + type Target = GenericFifo; + + fn deref(&self) -> &Self::Target { + &self.fifo + } +} diff --git a/src/run/runner/wall_time/perf/mod.rs b/src/run/runner/wall_time/perf/mod.rs index 3f7d4c74..a5a4a05a 100644 --- a/src/run/runner/wall_time/perf/mod.rs +++ b/src/run/runner/wall_time/perf/mod.rs @@ -8,6 +8,8 @@ use crate::run::runner::helpers::env::is_codspeed_debug_enabled; use crate::run::runner::helpers::run_command_with_log_pipe::run_command_with_log_pipe_and_callback; use crate::run::runner::helpers::run_with_sudo::run_with_sudo; use crate::run::runner::helpers::run_with_sudo::wrap_with_sudo; +use crate::run::runner::shared::fifo::FifoBenchmarkData; +use crate::run::runner::shared::fifo::RunnerFifo; use crate::run::runner::valgrind::helpers::ignored_objects_path::get_objects_path_to_ignore; use crate::run::runner::valgrind::helpers::perf_maps::harvest_perf_maps_for_pids; use crate::run::runner::wall_time::perf::debug_info::ProcessDebugInfo; @@ -15,20 +17,21 @@ use crate::run::runner::wall_time::perf::jit_dump::harvest_perf_jit_for_pids; use crate::run::runner::wall_time::perf::perf_executable::get_working_perf_executable; use crate::run::runner::wall_time::perf::unwind_data::UnwindDataExt; use anyhow::Context; -use fifo::{PerfFifo, RunnerFifo}; +use fifo::PerfFifo; use libc::pid_t; -use nix::sys::time::TimeValLike; -use nix::time::clock_gettime; use perf_map::ProcessSymbols; +use runner_shared::artifacts::ArtifactExt; +use runner_shared::artifacts::ExecutionTimestamps; use runner_shared::debug_info::ModuleDebugInfo; use runner_shared::fifo::Command as FifoCommand; -use runner_shared::fifo::MarkerType; +use runner_shared::fifo::IntegrationMode; use runner_shared::metadata::PerfMetadata; use runner_shared::unwind_data::UnwindData; -use std::collections::HashSet; use std::path::Path; +use std::sync::Arc; use std::time::Duration; use std::{cell::OnceCell, collections::HashMap, process::ExitStatus}; +use tokio::sync::Mutex; mod jit_dump; mod setup; @@ -137,8 +140,8 @@ impl PerfRunner { &format!("--call-graph={cg_mode}"), &format!( "--control=fifo:{},{}", - perf_fifo.ctl_fifo_path.to_string_lossy(), - perf_fifo.ack_fifo_path.to_string_lossy() + perf_fifo.ctl_path().to_string_lossy(), + perf_fifo.ack_path().to_string_lossy() ), "-o", "-", // forces pipe mode @@ -186,8 +189,8 @@ impl PerfRunner { // Harvest the perf maps generated by python. This will copy the perf // maps from /tmp to the profile folder. We have to write our own perf // maps to these files AFTERWARDS, otherwise it'll be overwritten! - harvest_perf_maps_for_pids(profile_folder, &bench_data.bench_pids).await?; - harvest_perf_jit_for_pids(profile_folder, &bench_data.bench_pids).await?; + harvest_perf_maps_for_pids(profile_folder, &bench_data.fifo_data.bench_pids).await?; + harvest_perf_jit_for_pids(profile_folder, &bench_data.fifo_data.bench_pids).await?; // Append perf maps, unwind info and other metadata if let Err(BenchmarkDataSaveError::MissingIntegration) = bench_data.save_to(profile_folder) @@ -275,145 +278,81 @@ impl PerfRunner { async fn handle_fifo( mut runner_fifo: RunnerFifo, - mut perf_fifo: PerfFifo, + perf_fifo: PerfFifo, ) -> anyhow::Result { - let mut bench_order_by_timestamp = Vec::<(u64, String)>::new(); - let mut bench_pids = HashSet::::new(); let mut symbols_by_pid = HashMap::::new(); let mut unwind_data_by_pid = HashMap::>::new(); - let mut markers = Vec::::new(); - let mut integration = None; + let perf_fifo = Arc::new(Mutex::new(perf_fifo)); let mut perf_ping_timeout = 5; - - let current_time = || { - clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC) - .unwrap() - .num_nanoseconds() as u64 - }; - - let mut benchmark_started = false; - loop { - let perf_ping = - tokio::time::timeout(Duration::from_secs(perf_ping_timeout), perf_fifo.ping()) - .await; + let health_check = async || { + let perf_ping = tokio::time::timeout(Duration::from_secs(perf_ping_timeout), async { + perf_fifo.lock().await.ping().await + }) + .await; if let Ok(Err(_)) | Err(_) = perf_ping { debug!("Failed to ping perf FIFO, ending perf fifo loop"); - break; + return Ok(false); } // Perf has started successfully, we can decrease the timeout for future pings perf_ping_timeout = 1; - let result = tokio::time::timeout(Duration::from_secs(5), runner_fifo.recv_cmd()).await; - let cmd = match result { - Ok(Ok(cmd)) => cmd, - Ok(Err(e)) => { - warn!("Failed to parse FIFO command: {e}"); - break; - } - Err(_) => continue, - }; - trace!("Received command: {cmd:?}"); + Ok(true) + }; + let on_cmd = async |cmd: &FifoCommand| { + #[allow(deprecated)] match cmd { - FifoCommand::CurrentBenchmark { pid, uri } => { - bench_order_by_timestamp.push((current_time(), uri)); - bench_pids.insert(pid); - + FifoCommand::StartBenchmark => { + perf_fifo.lock().await.start_events().await?; + } + FifoCommand::StopBenchmark => { + perf_fifo.lock().await.stop_events().await?; + } + FifoCommand::CurrentBenchmark { pid, .. } => { #[cfg(target_os = "linux")] - if !symbols_by_pid.contains_key(&pid) && !unwind_data_by_pid.contains_key(&pid) - { + if !symbols_by_pid.contains_key(pid) && !unwind_data_by_pid.contains_key(pid) { Self::process_memory_mappings( - pid, + *pid, &mut symbols_by_pid, &mut unwind_data_by_pid, )?; } - - runner_fifo.send_cmd(FifoCommand::Ack).await?; - } - FifoCommand::StartBenchmark => { - if benchmark_started { - warn!("Received duplicate StartBenchmark command, ignoring"); - runner_fifo.send_cmd(FifoCommand::Ack).await?; - continue; - } - benchmark_started = true; - markers.push(MarkerType::SampleStart(current_time())); - - perf_fifo.start_events().await?; - runner_fifo.send_cmd(FifoCommand::Ack).await?; - } - FifoCommand::StopBenchmark => { - if !benchmark_started { - warn!("Received StopBenchmark command before StartBenchmark, ignoring"); - runner_fifo.send_cmd(FifoCommand::Ack).await?; - continue; - } - benchmark_started = false; - - markers.push(MarkerType::SampleEnd(current_time())); - - perf_fifo.stop_events().await?; - runner_fifo.send_cmd(FifoCommand::Ack).await?; } FifoCommand::PingPerf => { - if perf_fifo.ping().await.is_ok() { - runner_fifo.send_cmd(FifoCommand::Ack).await?; - } else { - runner_fifo.send_cmd(FifoCommand::Err).await?; + if perf_fifo.lock().await.ping().await.is_err() { + return Ok(FifoCommand::Err); } } - FifoCommand::SetIntegration { name, version } => { - integration = Some((name, version)); - runner_fifo.send_cmd(FifoCommand::Ack).await?; - } - FifoCommand::AddMarker { marker, .. } => { - markers.push(marker); - runner_fifo.send_cmd(FifoCommand::Ack).await?; - } - FifoCommand::SetVersion(protocol_version) => { - if protocol_version < runner_shared::fifo::CURRENT_PROTOCOL_VERSION { - panic!( - "Integration is using an incompatible protocol version ({protocol_version} < {}). Please update the integration to the latest version.", - runner_shared::fifo::CURRENT_PROTOCOL_VERSION - ) - } else if protocol_version > runner_shared::fifo::CURRENT_PROTOCOL_VERSION { - panic!( - "Runner is using an incompatible protocol version ({} < {protocol_version}). Please update the runner to the latest version.", - runner_shared::fifo::CURRENT_PROTOCOL_VERSION - ) - }; - - runner_fifo.send_cmd(FifoCommand::Ack).await?; + FifoCommand::GetIntegrationMode => { + return Ok(FifoCommand::IntegrationModeResponse(IntegrationMode::Perf)); } _ => { - warn!("Received unexpected command: {cmd:?}"); - runner_fifo.send_cmd(FifoCommand::Err).await?; + warn!("Unhandled FIFO command: {cmd:?}"); + return Ok(FifoCommand::Err); } } - } + Ok(FifoCommand::Ack) + }; + + let (marker_result, fifo_data) = runner_fifo + .handle_fifo_messages(health_check, on_cmd) + .await?; Ok(BenchmarkData { - integration, - uri_by_ts: bench_order_by_timestamp, - bench_pids, + fifo_data, + marker_result, symbols_by_pid, unwind_data_by_pid, - markers, }) } } pub struct BenchmarkData { - /// Name and version of the integration - integration: Option<(String, String)>, - - uri_by_ts: Vec<(u64, String)>, - bench_pids: HashSet, - symbols_by_pid: HashMap, - unwind_data_by_pid: HashMap>, - markers: Vec, + fifo_data: FifoBenchmarkData, + marker_result: ExecutionTimestamps, + pub symbols_by_pid: HashMap, + pub unwind_data_by_pid: HashMap>, } #[derive(Debug)] @@ -426,6 +365,8 @@ impl BenchmarkData { &self, path: P, ) -> Result<(), BenchmarkDataSaveError> { + self.marker_result.save_to(&path).unwrap(); + for proc_sym in self.symbols_by_pid.values() { proc_sym.save_to(&path).unwrap(); } @@ -445,13 +386,15 @@ impl BenchmarkData { } } + #[allow(deprecated)] let metadata = PerfMetadata { version: PERF_METADATA_CURRENT_VERSION, integration: self + .fifo_data .integration .clone() .ok_or(BenchmarkDataSaveError::MissingIntegration)?, - uri_by_ts: self.uri_by_ts.clone(), + uri_by_ts: self.marker_result.uri_by_ts.clone(), ignored_modules: { let mut to_ignore = vec![]; @@ -497,7 +440,7 @@ impl BenchmarkData { to_ignore }, - markers: self.markers.clone(), + markers: self.marker_result.markers.clone(), debug_info_by_pid, }; metadata.save_to(&path).unwrap(); diff --git a/src/run/uploader/upload.rs b/src/run/uploader/upload.rs index ba436e6e..5cab24d9 100644 --- a/src/run/uploader/upload.rs +++ b/src/run/uploader/upload.rs @@ -58,7 +58,7 @@ async fn create_profile_archive( ) -> Result { let time_start = std::time::Instant::now(); let profile_archive = match executor_name { - ExecutorName::Valgrind => { + ExecutorName::Memory | ExecutorName::Valgrind => { debug!("Creating compressed tar archive for Valgrind"); let enc = GzipEncoder::new(Vec::new()); let mut tar = Builder::new(enc);