├── .github ├── dependabot.yml └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── addr_validate.rs └── collector.rs ├── build.rs ├── examples ├── backtrace_while_sampling.rs ├── criterion.rs ├── flamegraph.rs ├── multithread.rs ├── multithread_flamegraph.rs ├── post_processor.rs ├── prime_number.rs ├── profile_proto_with_prost.rs └── profile_proto_with_protobuf_codec.rs ├── proto ├── perftools.profiles.rs └── profile.proto ├── rustfmt.toml └── src ├── addr_validate.rs ├── backtrace ├── backtrace_rs.rs ├── frame_pointer.rs ├── framehop_unwinder.rs ├── framehop_unwinder │ └── shlib.rs └── mod.rs ├── collector.rs ├── criterion.rs ├── error.rs ├── frames.rs ├── lib.rs ├── perfmap.rs ├── profiler.rs ├── report.rs └── timer.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: build 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | lint: 11 | name: Format and Clippy 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v3 17 | 18 | - name: Install Rust toolchain 19 | uses: actions-rs/toolchain@v1.0.7 20 | with: 21 | profile: minimal 22 | toolchain: 1.74.0 23 | override: true 24 | components: rustfmt, clippy 25 | 26 | - name: Install protobuf compiler 27 | run: sudo apt-get install -y protobuf-compiler 28 | 29 | - name: Run cargo fmt 30 | uses: actions-rs/cargo@v1.0.3 31 | with: 32 | command: fmt 33 | args: --all -- --check 34 | 35 | - name: Remove pre-generated prost files to force regeneration 36 | run: rm proto/*.rs 37 | 38 | - name: Run cargo clippy prost 39 | uses: actions-rs/cargo@v1.0.3 40 | with: 41 | command: clippy 42 | args: --all-targets --features flamegraph,prost-codec -- -D warnings 43 | 44 | - name: Run cargo clippy protobuf 45 | uses: actions-rs/cargo@v1.0.3 46 | with: 47 | command: clippy 48 | args: --all-targets --features flamegraph,protobuf-codec -- -D warnings 49 | 50 | - name: Check if the prost file committed to git is up-to-date 51 | run: | 52 | git diff --no-ext-diff --exit-code 53 | 54 | build: 55 | name: Build 56 | strategy: 57 | matrix: 58 | os: [ubuntu-latest, macos-latest] 59 | toolchain: [stable, nightly, 1.74.0] 60 | target: 61 | [ 62 | x86_64-unknown-linux-gnu, 63 | aarch64-unknown-linux-gnu, 64 | x86_64-unknown-linux-musl, 65 | x86_64-apple-darwin, 66 | aarch64-apple-darwin, 67 | ] 68 | exclude: 69 | - os: ubuntu-latest 70 | target: x86_64-apple-darwin 71 | - os: ubuntu-latest 72 | target: aarch64-apple-darwin 73 | - os: macos-latest 74 | target: x86_64-unknown-linux-gnu 75 | - os: macos-latest 76 | target: aarch64-unknown-linux-gnu 77 | - os: macos-latest 78 | target: x86_64-unknown-linux-musl 79 | fail-fast: false 80 | runs-on: ${{ matrix.os }} 81 | 82 | steps: 83 | - name: Checkout sources 84 | uses: actions/checkout@v3 85 | 86 | - name: Install Rust toolchain 87 | uses: actions-rs/toolchain@v1.0.7 88 | with: 89 | profile: minimal 90 | toolchain: ${{ matrix.toolchain }} 91 | target: ${{ matrix.target }} 92 | override: true 93 | 94 | - name: Run cargo build prost 95 | uses: actions-rs/cargo@v1.0.3 96 | with: 97 | command: build 98 | args: --features flamegraph,prost-codec --target ${{ matrix.target }} 99 | 100 | - name: Run cargo build protobuf 101 | uses: actions-rs/cargo@v1.0.3 102 | with: 103 | command: build 104 | args: --features flamegraph,protobuf-codec --target ${{ matrix.target }} 105 | 106 | - name: Run cargo build frame pointer 107 | if: ${{ matrix.toolchain == 'nightly' && matrix.os == 'ubuntu-latest' }} 108 | uses: actions-rs/cargo@v1.0.3 109 | with: 110 | command: build 111 | args: --no-default-features --features frame-pointer --target ${{ matrix.target }} 112 | 113 | test: 114 | name: Test 115 | strategy: 116 | matrix: 117 | os: [ubuntu-latest, macos-latest] 118 | toolchain: [stable, nightly] 119 | target: 120 | [ 121 | x86_64-unknown-linux-gnu, 122 | x86_64-unknown-linux-musl, 123 | x86_64-apple-darwin, 124 | ] 125 | exclude: 126 | - os: ubuntu-latest 127 | target: x86_64-apple-darwin 128 | - os: macos-latest 129 | target: x86_64-unknown-linux-gnu 130 | - os: macos-latest 131 | target: x86_64-unknown-linux-musl 132 | fail-fast: false 133 | runs-on: ${{ matrix.os }} 134 | 135 | steps: 136 | - name: Checkout sources 137 | uses: actions/checkout@v3 138 | 139 | - name: Install Rust toolchain 140 | uses: actions-rs/toolchain@v1.0.7 141 | with: 142 | profile: minimal 143 | toolchain: ${{ matrix.toolchain }} 144 | target: ${{ matrix.target }} 145 | override: true 146 | 147 | - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' }} 148 | name: Install musl 149 | run: sudo apt install musl-tools 150 | 151 | - name: Run cargo test prost 152 | uses: actions-rs/cargo@v1.0.3 153 | with: 154 | command: test 155 | args: --features flamegraph,prost-codec --target ${{ matrix.target }} 156 | 157 | - name: Run cargo test protobuf 158 | uses: actions-rs/cargo@v1.0.3 159 | with: 160 | command: test 161 | args: --features flamegraph,protobuf-codec --target ${{ matrix.target }} 162 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | .idea 9 | .vscode 10 | 11 | # Ignore some files produced by the examples. 12 | *.svg 13 | profile.pb 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.15.0] - 202 8 | 9 | ### Added 10 | - Add support for framehop as unwinder (#267) 11 | - Add support for perfmap debug info format (#267) 12 | 13 | ### Fixed 14 | - Use spin-rs to replace parking lot to avoid potential deadlock (#268) 15 | 16 | ### Changed 17 | - Bump version of protobuf to 3.7.2 (#264) 18 | - Increase MSRV to 1.74.0 (#264) 19 | 20 | ## [0.14.0] - 2023-11-08 21 | 22 | ### Fixed 23 | - Fix the alignment of the collector and validate function (#255) 24 | 25 | ### Changed 26 | - Bump the MSRV to 1.66.0 (#255) 27 | 28 | ## [0.13.0] - 2023-09-27 29 | 30 | ### Changed 31 | - Upgrade `prost`, `prost-derive`, `prost-build` to 0.12 (#223) 32 | 33 | ## [0.12.1] - 2023-07-25 34 | 35 | ### Fixed 36 | - Handle potentially unaligned frame pointer (#217) 37 | - Fix the register field name according to libc (#218) 38 | 39 | ## [0.12.0] - 2023-07-03 40 | 41 | ### Added 42 | - Support building `pprof-rs` for `android` target (#202) 43 | - Support building `pprof-rs` for `freebsd` target (#213) 44 | 45 | ### Changed 46 | - Upgrade `criterion` to 0.5 (#212) 47 | - Bump the MSRV to 1.64.0 (#204) 48 | 49 | ### Fixed 50 | - Hide `perf_signal_handler` frames on macOS (#207) 51 | 52 | ## [0.11.1] - 2023-02-21 53 | 54 | ### Added 55 | - Support RISC-V architecture (#169) 56 | - Support LoongArch64 architecture (#174) 57 | 58 | ### Fixed 59 | - Use a globally shared pipe to validate memory to avoid FD leak (#198) 60 | 61 | ## [0.11.0] - 2022-11-03 62 | 63 | ### Changed 64 | - Upgrade prost 0.11 (#166) 65 | - Upgrade criterion from 0.3 to 0.4 (#163) 66 | 67 | ### Fixed 68 | - Restart syscalls interuppted by SIGPROF when possible (#167) 69 | - Only do per-frame-blocklist-check when frame-pointer is enabled (#172) 70 | 71 | ## [0.10.1] - 2022-08-29 72 | 73 | ### Changed 74 | - Update `MAX_DEPTH` to 128 (#159) 75 | 76 | ### Fixed 77 | - Fixed clippy warnnings and ignore prost mod (#160) 78 | 79 | ## [0.10.0] - 2022-06-27 80 | 81 | ### Changed 82 | - Remove `backtrace-rs` feature, as the default choice when not specified (#130) 83 | 84 | ### Added 85 | - Add `sample_timestamp` to Frames and UnresolvedFrames in order to have more fine-grained info on when the samples are collected (#133) 86 | - 87 | ### Fixed 88 | - Export `UnresolvedReport` type to allow developers to get the unresolved report (#132) 89 | 90 | ## [0.9.1] - 2022-05-19 91 | 92 | ### Fixed 93 | - Protect the error number in signal handler (#128) 94 | 95 | ## [0.9.0] - 2022-05-09 96 | 97 | ### Added 98 | - Add `frame-pointer` feature to unwind the stack with frame pointer (#116) 99 | 100 | ### Changed 101 | - The user has to specify one unwind implementation (`backtrace-rs` or `frame-pointer`) in the features (#116) 102 | 103 | ## [0.8.0] - 2022-04-20 104 | 105 | ### Changed 106 | - Update prost from 0.9 to 0.10 (#113, #114, #115) 107 | 108 | ### Fixed 109 | - Fix pthread_getname_np not available on musl (#110) 110 | 111 | ## [0.7.0] - 2022-03-08 112 | 113 | ### Added 114 | - Add rust-protobuf support by adding protobuf-codec features (#106) 115 | 116 | ### Changed 117 | - protobuf feature is renamed to prost-codec to align all other tikv projects (#106) 118 | 119 | ## [0.6.2] - 2021-12-24 120 | ### Added 121 | - implement `Clone` for `ProfilerGuardBuilder` [@yangkeao](https://github.com/YangKeao) 122 | - Add thread names and timing information to protobuf reports [@free](https://github.com/free) 123 | 124 | ## [0.6.1] - 2021-11-01 125 | ### Added 126 | - `blocklist` to skip sampling in selected shared library [@yangkeao](https://github.com/YangKeao) 127 | 128 | ### Fixed 129 | - Fix memory leak in collector of samples [@yangkeao](https://github.com/YangKeao) 130 | 131 | ## [0.6.0] - 2021-10-21 132 | ### Changed 133 | - Bump prost* to v0.9.0 [@PsiACE](https://github.com/PsiACE) 134 | 135 | ### Security 136 | - Bump nix to v0.23 [@PsiACE](https://github.com/PsiACE) 137 | 138 | ## [0.5.0] - 2021-10-21 139 | ### Changed 140 | - Bump version of prost* [@PsiACE](https://github.com/PsiACE) 141 | 142 | ## [0.4.4] - 2021-07-13 143 | ### Fixed 144 | - Fix the lifetime mark is not used by criterion output [@yangkeao](https://github.com/YangKeao) 145 | 146 | ## [0.4.3] - 2021-03-18 147 | ### Changed 148 | - Change the output paths for `criterion::PProfProfiler` to support benchmark groups [@yangkeao](https://github.com/YangKeao) 149 | 150 | ### Security 151 | - Bump nix to v0.20 [@yangkeao](https://github.com/YangKeao) 152 | 153 | ## [0.4.2] - 2021-02-20 154 | ### Added 155 | - Implement criterion profiler [@yangkeao](https://github.com/YangKeao) 156 | 157 | ### Fixed 158 | - Fix compilation error on arm architecture [@yangkeao](https://github.com/YangKeao) 159 | 160 | ## [0.4.1] - 2021-02-10 161 | ### Added 162 | - Allow passing custom flamegraph options [@yangkeao](https://github.com/YangKeao) 163 | 164 | ## [0.4.0] - 2020-12-30 165 | ### Fix 166 | - Fix flamegraph inline functions [@yangkeao](https://github.com/YangKeao) 167 | 168 | ## [0.3.21] - 2020-12-28 169 | ### Changed 170 | - Bump version of prost* [@xhebox](https://github.com/xhebox) 171 | 172 | ### Security 173 | - Bump rand to v0.8 @dependabot 174 | - Bump nix to v0.19 @dependabot 175 | 176 | ## [0.3.20] - 2020-12-11 177 | ### Changed 178 | - Split `symbolic-demangle` into multiple features [@yangkeao](https://github.com/YangKeao) 179 | 180 | ## [0.3.19] - 2020-12-11 181 | ### Fix 182 | - Ignore SIGPROF signal after stop, rather than reset to the default handler [@yangkeao](https://github.com/YangKeao) 183 | 184 | ## [0.3.18] - 2020-08-07 185 | ### Added 186 | - Add `Report::build_unresolved` [@umanwizard](https://github.com/umanwizard) 187 | 188 | ### Changed 189 | - Change from `&mut self` to `&self` in `RpoertBuilder::build` [@umanwizard](https://github.com/umanwizard) 190 | 191 | ## [0.3.16] - 2020-02-25 192 | ### Added 193 | - Support cpp demangle [@yangkeao](https://github.com/YangKeao) 194 | 195 | ## [0.3.15] - 2020-02-05 196 | ### Added 197 | - Filter out signal handler functions [@yangkeao](https://github.com/YangKeao) 198 | 199 | ### Fixed 200 | - Fix protobuf unit [@yangkeao](https://github.com/YangKeao) 201 | 202 | ## [0.3.14] - 2020-02-05 203 | ### Fixed 204 | - Don't get lock inside `backtrace::Backtrace` [@yangkeao](https://github.com/YangKeao) 205 | 206 | ## [0.3.13] - 2020-01-31 207 | ### Added 208 | - Export `prost::Message` [@yangkeao](https://github.com/YangKeao) 209 | 210 | ### Fixed 211 | - Only use thread name on linux and macos [@yangkeao](https://github.com/YangKeao) 212 | - Disable `#![feature(test)]` outside of tests [@kennytm](https://github.com/kennytm) 213 | 214 | ## [0.3.12] - 2019-11-27 215 | ### Fixed 216 | - Stop timer before profiler stops [@yangkeao](https://github.com/YangKeao) 217 | 218 | ## [0.3.9] - 2019-11-08 219 | ### Added 220 | - Support profobuf output [@lonng](https://github.com/lonng) 221 | 222 | ## [0.3.5] - 2019-11-04 223 | ### Changed 224 | - Change crate name from `rsperftools` to `pprof-rs` [@yangkeao](https://github.com/YangKeao) 225 | 226 | ## [0.3.4] - 2019-11-04 227 | ### Changed 228 | - Use less stack space [@yangkeao](https://github.com/YangKeao) 229 | 230 | ## [0.3.2] - 2019-11-01 231 | ### Fixed 232 | - Seek to the start before reading file in `TempFdArray`[@yangkeao](https://github.com/YangKeao) 233 | 234 | ## [0.3.1] - 2019-11-01 235 | ### Added 236 | - Support customized post processor for frames [@yangkeao](https://github.com/YangKeao) 237 | 238 | ### Fixed 239 | - Fix deadlock inside the `std::thread::current().name()` [@yangkeao](https://github.com/YangKeao) 240 | 241 | ## [0.2.3] - 2019-10-31 242 | ### Fixed 243 | - Avoid calling `malloc` inside the signal handler [@yangkeao](https://github.com/YangKeao) 244 | 245 | ## [0.1.4] - 2019-10-25 246 | ### Changed 247 | - Implement `Send` for `Symbol` [@yangkeao](https://github.com/YangKeao) 248 | 249 | ## [0.1.3] - 2019-10-24 250 | ### Added 251 | - Add log [@yangkeao](https://github.com/YangKeao) 252 | 253 | ### Fixed 254 | - Stop signal handler after processing started [@yangkeao](https://github.com/YangKeao) 255 | 256 | ## [0.1.1] - 2019-10-22 257 | ### Added 258 | - Check whether profiler is running when starting the profiler [@yangkeao](https://github.com/YangKeao) 259 | 260 | ## [0.1.0] - 2019-10-22 261 | ### Added 262 | - Support profiling with signal handler [@yangkeao](https://github.com/YangKeao) 263 | - Support generating flamegraph [@yangkeao](https://github.com/YangKeao) 264 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.20.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 10 | dependencies = [ 11 | "gimli 0.27.3", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "adler2" 22 | version = "2.0.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 25 | 26 | [[package]] 27 | name = "ahash" 28 | version = "0.8.11" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 31 | dependencies = [ 32 | "cfg-if", 33 | "getrandom", 34 | "once_cell", 35 | "version_check", 36 | "zerocopy 0.7.35", 37 | ] 38 | 39 | [[package]] 40 | name = "aho-corasick" 41 | version = "1.1.1" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" 44 | dependencies = [ 45 | "memchr", 46 | ] 47 | 48 | [[package]] 49 | name = "aligned-vec" 50 | version = "0.6.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "7e0966165eaf052580bd70eb1b32cb3d6245774c0104d1b2793e9650bf83b52a" 53 | dependencies = [ 54 | "equator", 55 | ] 56 | 57 | [[package]] 58 | name = "anes" 59 | version = "0.1.6" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" 62 | 63 | [[package]] 64 | name = "anstyle" 65 | version = "1.0.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" 68 | 69 | [[package]] 70 | name = "anyhow" 71 | version = "1.0.75" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 74 | 75 | [[package]] 76 | name = "arc-swap" 77 | version = "1.7.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" 80 | 81 | [[package]] 82 | name = "arrayvec" 83 | version = "0.7.4" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 86 | 87 | [[package]] 88 | name = "autocfg" 89 | version = "1.1.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 92 | 93 | [[package]] 94 | name = "backtrace" 95 | version = "0.3.68" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 98 | dependencies = [ 99 | "addr2line", 100 | "cc", 101 | "cfg-if", 102 | "libc", 103 | "miniz_oxide 0.7.1", 104 | "object 0.31.1", 105 | "rustc-demangle", 106 | ] 107 | 108 | [[package]] 109 | name = "bitflags" 110 | version = "1.3.2" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 113 | 114 | [[package]] 115 | name = "bitflags" 116 | version = "2.4.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" 119 | 120 | [[package]] 121 | name = "block-buffer" 122 | version = "0.10.4" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 125 | dependencies = [ 126 | "generic-array", 127 | ] 128 | 129 | [[package]] 130 | name = "bumpalo" 131 | version = "3.14.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 134 | 135 | [[package]] 136 | name = "bytemuck" 137 | version = "1.14.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" 140 | 141 | [[package]] 142 | name = "byteorder" 143 | version = "1.5.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 146 | 147 | [[package]] 148 | name = "bytes" 149 | version = "1.5.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 152 | 153 | [[package]] 154 | name = "cast" 155 | version = "0.3.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 158 | 159 | [[package]] 160 | name = "cc" 161 | version = "1.0.83" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 164 | dependencies = [ 165 | "libc", 166 | ] 167 | 168 | [[package]] 169 | name = "cfg-if" 170 | version = "1.0.0" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 173 | 174 | [[package]] 175 | name = "ciborium" 176 | version = "0.2.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" 179 | dependencies = [ 180 | "ciborium-io", 181 | "ciborium-ll", 182 | "serde", 183 | ] 184 | 185 | [[package]] 186 | name = "ciborium-io" 187 | version = "0.2.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" 190 | 191 | [[package]] 192 | name = "ciborium-ll" 193 | version = "0.2.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" 196 | dependencies = [ 197 | "ciborium-io", 198 | "half", 199 | ] 200 | 201 | [[package]] 202 | name = "clap" 203 | version = "4.3.24" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" 206 | dependencies = [ 207 | "clap_builder", 208 | ] 209 | 210 | [[package]] 211 | name = "clap_builder" 212 | version = "4.3.24" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" 215 | dependencies = [ 216 | "anstyle", 217 | "clap_lex", 218 | ] 219 | 220 | [[package]] 221 | name = "clap_lex" 222 | version = "0.5.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 225 | 226 | [[package]] 227 | name = "cpp_demangle" 228 | version = "0.4.3" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" 231 | dependencies = [ 232 | "cfg-if", 233 | ] 234 | 235 | [[package]] 236 | name = "cpufeatures" 237 | version = "0.2.9" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 240 | dependencies = [ 241 | "libc", 242 | ] 243 | 244 | [[package]] 245 | name = "crc32fast" 246 | version = "1.4.2" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 249 | dependencies = [ 250 | "cfg-if", 251 | ] 252 | 253 | [[package]] 254 | name = "criterion" 255 | version = "0.5.1" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" 258 | dependencies = [ 259 | "anes", 260 | "cast", 261 | "ciborium", 262 | "clap", 263 | "criterion-plot", 264 | "is-terminal", 265 | "itertools", 266 | "num-traits", 267 | "once_cell", 268 | "oorandom", 269 | "plotters", 270 | "rayon", 271 | "regex", 272 | "serde", 273 | "serde_derive", 274 | "serde_json", 275 | "tinytemplate", 276 | "walkdir", 277 | ] 278 | 279 | [[package]] 280 | name = "criterion-plot" 281 | version = "0.5.0" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" 284 | dependencies = [ 285 | "cast", 286 | "itertools", 287 | ] 288 | 289 | [[package]] 290 | name = "crossbeam-deque" 291 | version = "0.8.3" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 294 | dependencies = [ 295 | "cfg-if", 296 | "crossbeam-epoch", 297 | "crossbeam-utils", 298 | ] 299 | 300 | [[package]] 301 | name = "crossbeam-epoch" 302 | version = "0.9.15" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 305 | dependencies = [ 306 | "autocfg", 307 | "cfg-if", 308 | "crossbeam-utils", 309 | "memoffset", 310 | "scopeguard", 311 | ] 312 | 313 | [[package]] 314 | name = "crossbeam-utils" 315 | version = "0.8.20" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 318 | 319 | [[package]] 320 | name = "crypto-common" 321 | version = "0.1.6" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 324 | dependencies = [ 325 | "generic-array", 326 | "typenum", 327 | ] 328 | 329 | [[package]] 330 | name = "debugid" 331 | version = "0.8.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" 334 | dependencies = [ 335 | "uuid", 336 | ] 337 | 338 | [[package]] 339 | name = "digest" 340 | version = "0.10.7" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 343 | dependencies = [ 344 | "block-buffer", 345 | "crypto-common", 346 | ] 347 | 348 | [[package]] 349 | name = "either" 350 | version = "1.9.0" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 353 | 354 | [[package]] 355 | name = "equator" 356 | version = "0.2.2" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" 359 | dependencies = [ 360 | "equator-macro", 361 | ] 362 | 363 | [[package]] 364 | name = "equator-macro" 365 | version = "0.2.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" 368 | dependencies = [ 369 | "proc-macro2", 370 | "quote", 371 | "syn", 372 | ] 373 | 374 | [[package]] 375 | name = "equivalent" 376 | version = "1.0.1" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 379 | 380 | [[package]] 381 | name = "errno" 382 | version = "0.3.3" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" 385 | dependencies = [ 386 | "errno-dragonfly", 387 | "libc", 388 | "windows-sys", 389 | ] 390 | 391 | [[package]] 392 | name = "errno-dragonfly" 393 | version = "0.1.2" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 396 | dependencies = [ 397 | "cc", 398 | "libc", 399 | ] 400 | 401 | [[package]] 402 | name = "fallible-iterator" 403 | version = "0.3.0" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" 406 | 407 | [[package]] 408 | name = "fastrand" 409 | version = "2.0.1" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 412 | 413 | [[package]] 414 | name = "findshlibs" 415 | version = "0.10.2" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" 418 | dependencies = [ 419 | "cc", 420 | "lazy_static", 421 | "libc", 422 | "winapi", 423 | ] 424 | 425 | [[package]] 426 | name = "fixedbitset" 427 | version = "0.4.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 430 | 431 | [[package]] 432 | name = "flate2" 433 | version = "1.0.34" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" 436 | dependencies = [ 437 | "crc32fast", 438 | "miniz_oxide 0.8.0", 439 | ] 440 | 441 | [[package]] 442 | name = "framehop" 443 | version = "0.13.2" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "59bdf491caf8284489b65c99366d0f88393709b8214e4ccff2f55d9892da7713" 446 | dependencies = [ 447 | "arrayvec", 448 | "cfg-if", 449 | "fallible-iterator", 450 | "gimli 0.31.1", 451 | "macho-unwind-info", 452 | "pe-unwind-info", 453 | ] 454 | 455 | [[package]] 456 | name = "generic-array" 457 | version = "0.14.7" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 460 | dependencies = [ 461 | "typenum", 462 | "version_check", 463 | ] 464 | 465 | [[package]] 466 | name = "getrandom" 467 | version = "0.2.10" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 470 | dependencies = [ 471 | "cfg-if", 472 | "libc", 473 | "wasi", 474 | ] 475 | 476 | [[package]] 477 | name = "gimli" 478 | version = "0.27.3" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 481 | 482 | [[package]] 483 | name = "gimli" 484 | version = "0.31.1" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 487 | dependencies = [ 488 | "fallible-iterator", 489 | "stable_deref_trait", 490 | ] 491 | 492 | [[package]] 493 | name = "half" 494 | version = "1.8.2" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 497 | 498 | [[package]] 499 | name = "hashbrown" 500 | version = "0.14.0" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 503 | 504 | [[package]] 505 | name = "heck" 506 | version = "0.4.1" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 509 | 510 | [[package]] 511 | name = "hermit-abi" 512 | version = "0.3.3" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 515 | 516 | [[package]] 517 | name = "home" 518 | version = "0.5.5" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" 521 | dependencies = [ 522 | "windows-sys", 523 | ] 524 | 525 | [[package]] 526 | name = "indexmap" 527 | version = "2.0.0" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 530 | dependencies = [ 531 | "equivalent", 532 | "hashbrown", 533 | ] 534 | 535 | [[package]] 536 | name = "inferno" 537 | version = "0.11.17" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "c50453ec3a6555fad17b1cd1a80d16af5bc7cb35094f64e429fd46549018c6a3" 540 | dependencies = [ 541 | "ahash", 542 | "indexmap", 543 | "is-terminal", 544 | "itoa", 545 | "log", 546 | "num-format", 547 | "once_cell", 548 | "quick-xml", 549 | "rgb", 550 | "str_stack", 551 | ] 552 | 553 | [[package]] 554 | name = "is-terminal" 555 | version = "0.4.9" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 558 | dependencies = [ 559 | "hermit-abi", 560 | "rustix", 561 | "windows-sys", 562 | ] 563 | 564 | [[package]] 565 | name = "itertools" 566 | version = "0.10.5" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 569 | dependencies = [ 570 | "either", 571 | ] 572 | 573 | [[package]] 574 | name = "itoa" 575 | version = "1.0.9" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 578 | 579 | [[package]] 580 | name = "js-sys" 581 | version = "0.3.64" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 584 | dependencies = [ 585 | "wasm-bindgen", 586 | ] 587 | 588 | [[package]] 589 | name = "lazy_static" 590 | version = "1.4.0" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 593 | 594 | [[package]] 595 | name = "libc" 596 | version = "0.2.161" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" 599 | 600 | [[package]] 601 | name = "linux-raw-sys" 602 | version = "0.4.7" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" 605 | 606 | [[package]] 607 | name = "lock_api" 608 | version = "0.4.12" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 611 | dependencies = [ 612 | "autocfg", 613 | "scopeguard", 614 | ] 615 | 616 | [[package]] 617 | name = "log" 618 | version = "0.4.20" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 621 | 622 | [[package]] 623 | name = "macho-unwind-info" 624 | version = "0.5.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" 627 | dependencies = [ 628 | "thiserror 2.0.12", 629 | "zerocopy 0.8.25", 630 | "zerocopy-derive 0.8.25", 631 | ] 632 | 633 | [[package]] 634 | name = "memchr" 635 | version = "2.6.3" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" 638 | 639 | [[package]] 640 | name = "memmap2" 641 | version = "0.5.10" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" 644 | dependencies = [ 645 | "libc", 646 | ] 647 | 648 | [[package]] 649 | name = "memoffset" 650 | version = "0.9.0" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 653 | dependencies = [ 654 | "autocfg", 655 | ] 656 | 657 | [[package]] 658 | name = "miniz_oxide" 659 | version = "0.7.1" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 662 | dependencies = [ 663 | "adler", 664 | ] 665 | 666 | [[package]] 667 | name = "miniz_oxide" 668 | version = "0.8.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 671 | dependencies = [ 672 | "adler2", 673 | ] 674 | 675 | [[package]] 676 | name = "multimap" 677 | version = "0.8.3" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" 680 | 681 | [[package]] 682 | name = "nix" 683 | version = "0.26.4" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" 686 | dependencies = [ 687 | "bitflags 1.3.2", 688 | "cfg-if", 689 | "libc", 690 | ] 691 | 692 | [[package]] 693 | name = "num-format" 694 | version = "0.4.4" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" 697 | dependencies = [ 698 | "arrayvec", 699 | "itoa", 700 | ] 701 | 702 | [[package]] 703 | name = "num-traits" 704 | version = "0.2.16" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" 707 | dependencies = [ 708 | "autocfg", 709 | ] 710 | 711 | [[package]] 712 | name = "object" 713 | version = "0.29.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" 716 | dependencies = [ 717 | "flate2", 718 | "memchr", 719 | ] 720 | 721 | [[package]] 722 | name = "object" 723 | version = "0.31.1" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 726 | dependencies = [ 727 | "memchr", 728 | ] 729 | 730 | [[package]] 731 | name = "once_cell" 732 | version = "1.18.0" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 735 | 736 | [[package]] 737 | name = "oorandom" 738 | version = "11.1.3" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 741 | 742 | [[package]] 743 | name = "pe-unwind-info" 744 | version = "0.3.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "11fe3d7d11dde0fd142bf734ae5d645a4c62ede7c188bccc73dec5082359ff84" 747 | dependencies = [ 748 | "arrayvec", 749 | "bitflags 2.4.0", 750 | "thiserror 1.0.69", 751 | "zerocopy 0.7.35", 752 | "zerocopy-derive 0.7.35", 753 | ] 754 | 755 | [[package]] 756 | name = "petgraph" 757 | version = "0.6.4" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" 760 | dependencies = [ 761 | "fixedbitset", 762 | "indexmap", 763 | ] 764 | 765 | [[package]] 766 | name = "plotters" 767 | version = "0.3.5" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" 770 | dependencies = [ 771 | "num-traits", 772 | "plotters-backend", 773 | "plotters-svg", 774 | "wasm-bindgen", 775 | "web-sys", 776 | ] 777 | 778 | [[package]] 779 | name = "plotters-backend" 780 | version = "0.3.5" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" 783 | 784 | [[package]] 785 | name = "plotters-svg" 786 | version = "0.3.5" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" 789 | dependencies = [ 790 | "plotters-backend", 791 | ] 792 | 793 | [[package]] 794 | name = "pprof" 795 | version = "0.15.0" 796 | dependencies = [ 797 | "aligned-vec", 798 | "arc-swap", 799 | "backtrace", 800 | "cfg-if", 801 | "criterion", 802 | "findshlibs", 803 | "framehop", 804 | "inferno", 805 | "libc", 806 | "log", 807 | "memmap2", 808 | "nix", 809 | "object 0.29.0", 810 | "once_cell", 811 | "prost", 812 | "prost-build", 813 | "prost-derive", 814 | "protobuf", 815 | "protobuf-codegen", 816 | "rand", 817 | "sha2", 818 | "smallvec", 819 | "spin", 820 | "symbolic-demangle", 821 | "tempfile", 822 | "thiserror 2.0.12", 823 | ] 824 | 825 | [[package]] 826 | name = "ppv-lite86" 827 | version = "0.2.17" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 830 | 831 | [[package]] 832 | name = "prettyplease" 833 | version = "0.2.15" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" 836 | dependencies = [ 837 | "proc-macro2", 838 | "syn", 839 | ] 840 | 841 | [[package]] 842 | name = "proc-macro2" 843 | version = "1.0.94" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 846 | dependencies = [ 847 | "unicode-ident", 848 | ] 849 | 850 | [[package]] 851 | name = "prost" 852 | version = "0.12.1" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" 855 | dependencies = [ 856 | "bytes", 857 | "prost-derive", 858 | ] 859 | 860 | [[package]] 861 | name = "prost-build" 862 | version = "0.12.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac" 865 | dependencies = [ 866 | "bytes", 867 | "heck", 868 | "itertools", 869 | "log", 870 | "multimap", 871 | "once_cell", 872 | "petgraph", 873 | "prettyplease", 874 | "prost", 875 | "prost-types", 876 | "regex", 877 | "syn", 878 | "tempfile", 879 | "which", 880 | ] 881 | 882 | [[package]] 883 | name = "prost-derive" 884 | version = "0.12.1" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" 887 | dependencies = [ 888 | "anyhow", 889 | "itertools", 890 | "proc-macro2", 891 | "quote", 892 | "syn", 893 | ] 894 | 895 | [[package]] 896 | name = "prost-types" 897 | version = "0.12.1" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" 900 | dependencies = [ 901 | "prost", 902 | ] 903 | 904 | [[package]] 905 | name = "protobuf" 906 | version = "3.7.2" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" 909 | dependencies = [ 910 | "once_cell", 911 | "protobuf-support", 912 | "thiserror 1.0.69", 913 | ] 914 | 915 | [[package]] 916 | name = "protobuf-codegen" 917 | version = "3.7.2" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "5d3976825c0014bbd2f3b34f0001876604fe87e0c86cd8fa54251530f1544ace" 920 | dependencies = [ 921 | "anyhow", 922 | "once_cell", 923 | "protobuf", 924 | "protobuf-parse", 925 | "regex", 926 | "tempfile", 927 | "thiserror 1.0.69", 928 | ] 929 | 930 | [[package]] 931 | name = "protobuf-parse" 932 | version = "3.7.2" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973" 935 | dependencies = [ 936 | "anyhow", 937 | "indexmap", 938 | "log", 939 | "protobuf", 940 | "protobuf-support", 941 | "tempfile", 942 | "thiserror 1.0.69", 943 | "which", 944 | ] 945 | 946 | [[package]] 947 | name = "protobuf-support" 948 | version = "3.7.2" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" 951 | dependencies = [ 952 | "thiserror 1.0.69", 953 | ] 954 | 955 | [[package]] 956 | name = "quick-xml" 957 | version = "0.26.0" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" 960 | dependencies = [ 961 | "memchr", 962 | ] 963 | 964 | [[package]] 965 | name = "quote" 966 | version = "1.0.39" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" 969 | dependencies = [ 970 | "proc-macro2", 971 | ] 972 | 973 | [[package]] 974 | name = "rand" 975 | version = "0.8.5" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 978 | dependencies = [ 979 | "libc", 980 | "rand_chacha", 981 | "rand_core", 982 | ] 983 | 984 | [[package]] 985 | name = "rand_chacha" 986 | version = "0.3.1" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 989 | dependencies = [ 990 | "ppv-lite86", 991 | "rand_core", 992 | ] 993 | 994 | [[package]] 995 | name = "rand_core" 996 | version = "0.6.4" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 999 | dependencies = [ 1000 | "getrandom", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "rayon" 1005 | version = "1.8.0" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" 1008 | dependencies = [ 1009 | "either", 1010 | "rayon-core", 1011 | ] 1012 | 1013 | [[package]] 1014 | name = "rayon-core" 1015 | version = "1.12.0" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" 1018 | dependencies = [ 1019 | "crossbeam-deque", 1020 | "crossbeam-utils", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "redox_syscall" 1025 | version = "0.3.5" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1028 | dependencies = [ 1029 | "bitflags 1.3.2", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "regex" 1034 | version = "1.9.5" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" 1037 | dependencies = [ 1038 | "aho-corasick", 1039 | "memchr", 1040 | "regex-automata", 1041 | "regex-syntax", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "regex-automata" 1046 | version = "0.3.8" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" 1049 | dependencies = [ 1050 | "aho-corasick", 1051 | "memchr", 1052 | "regex-syntax", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "regex-syntax" 1057 | version = "0.7.5" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" 1060 | 1061 | [[package]] 1062 | name = "rgb" 1063 | version = "0.8.36" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" 1066 | dependencies = [ 1067 | "bytemuck", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "rustc-demangle" 1072 | version = "0.1.23" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1075 | 1076 | [[package]] 1077 | name = "rustix" 1078 | version = "0.38.14" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" 1081 | dependencies = [ 1082 | "bitflags 2.4.0", 1083 | "errno", 1084 | "libc", 1085 | "linux-raw-sys", 1086 | "windows-sys", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "ryu" 1091 | version = "1.0.15" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1094 | 1095 | [[package]] 1096 | name = "same-file" 1097 | version = "1.0.6" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1100 | dependencies = [ 1101 | "winapi-util", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "scopeguard" 1106 | version = "1.2.0" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1109 | 1110 | [[package]] 1111 | name = "serde" 1112 | version = "1.0.188" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" 1115 | dependencies = [ 1116 | "serde_derive", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "serde_derive" 1121 | version = "1.0.188" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" 1124 | dependencies = [ 1125 | "proc-macro2", 1126 | "quote", 1127 | "syn", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "serde_json" 1132 | version = "1.0.107" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" 1135 | dependencies = [ 1136 | "itoa", 1137 | "ryu", 1138 | "serde", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "sha2" 1143 | version = "0.10.7" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 1146 | dependencies = [ 1147 | "cfg-if", 1148 | "cpufeatures", 1149 | "digest", 1150 | ] 1151 | 1152 | [[package]] 1153 | name = "smallvec" 1154 | version = "1.11.1" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" 1157 | 1158 | [[package]] 1159 | name = "spin" 1160 | version = "0.10.0" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" 1163 | dependencies = [ 1164 | "lock_api", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "stable_deref_trait" 1169 | version = "1.2.0" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1172 | 1173 | [[package]] 1174 | name = "str_stack" 1175 | version = "0.1.0" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" 1178 | 1179 | [[package]] 1180 | name = "symbolic-common" 1181 | version = "12.4.1" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "fac08504d60cf5bdffeb8a6a028f1a4868a5da1098bb19eb46239440039163fb" 1184 | dependencies = [ 1185 | "debugid", 1186 | "memmap2", 1187 | "stable_deref_trait", 1188 | "uuid", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "symbolic-demangle" 1193 | version = "12.4.1" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "8b212728d4f6c527c1d50d6169e715f6e02d849811843c13e366d8ca6d0cf5c4" 1196 | dependencies = [ 1197 | "cpp_demangle", 1198 | "rustc-demangle", 1199 | "symbolic-common", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "syn" 1204 | version = "2.0.100" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 1207 | dependencies = [ 1208 | "proc-macro2", 1209 | "quote", 1210 | "unicode-ident", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "tempfile" 1215 | version = "3.8.0" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" 1218 | dependencies = [ 1219 | "cfg-if", 1220 | "fastrand", 1221 | "redox_syscall", 1222 | "rustix", 1223 | "windows-sys", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "thiserror" 1228 | version = "1.0.69" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1231 | dependencies = [ 1232 | "thiserror-impl 1.0.69", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "thiserror" 1237 | version = "2.0.12" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 1240 | dependencies = [ 1241 | "thiserror-impl 2.0.12", 1242 | ] 1243 | 1244 | [[package]] 1245 | name = "thiserror-impl" 1246 | version = "1.0.69" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1249 | dependencies = [ 1250 | "proc-macro2", 1251 | "quote", 1252 | "syn", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "thiserror-impl" 1257 | version = "2.0.12" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 1260 | dependencies = [ 1261 | "proc-macro2", 1262 | "quote", 1263 | "syn", 1264 | ] 1265 | 1266 | [[package]] 1267 | name = "tinytemplate" 1268 | version = "1.2.1" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 1271 | dependencies = [ 1272 | "serde", 1273 | "serde_json", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "typenum" 1278 | version = "1.17.0" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1281 | 1282 | [[package]] 1283 | name = "unicode-ident" 1284 | version = "1.0.12" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1287 | 1288 | [[package]] 1289 | name = "uuid" 1290 | version = "1.4.1" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" 1293 | 1294 | [[package]] 1295 | name = "version_check" 1296 | version = "0.9.4" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1299 | 1300 | [[package]] 1301 | name = "walkdir" 1302 | version = "2.4.0" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" 1305 | dependencies = [ 1306 | "same-file", 1307 | "winapi-util", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "wasi" 1312 | version = "0.11.0+wasi-snapshot-preview1" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1315 | 1316 | [[package]] 1317 | name = "wasm-bindgen" 1318 | version = "0.2.87" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 1321 | dependencies = [ 1322 | "cfg-if", 1323 | "wasm-bindgen-macro", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "wasm-bindgen-backend" 1328 | version = "0.2.87" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 1331 | dependencies = [ 1332 | "bumpalo", 1333 | "log", 1334 | "once_cell", 1335 | "proc-macro2", 1336 | "quote", 1337 | "syn", 1338 | "wasm-bindgen-shared", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "wasm-bindgen-macro" 1343 | version = "0.2.87" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 1346 | dependencies = [ 1347 | "quote", 1348 | "wasm-bindgen-macro-support", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "wasm-bindgen-macro-support" 1353 | version = "0.2.87" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 1356 | dependencies = [ 1357 | "proc-macro2", 1358 | "quote", 1359 | "syn", 1360 | "wasm-bindgen-backend", 1361 | "wasm-bindgen-shared", 1362 | ] 1363 | 1364 | [[package]] 1365 | name = "wasm-bindgen-shared" 1366 | version = "0.2.87" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 1369 | 1370 | [[package]] 1371 | name = "web-sys" 1372 | version = "0.3.64" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 1375 | dependencies = [ 1376 | "js-sys", 1377 | "wasm-bindgen", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "which" 1382 | version = "4.4.2" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 1385 | dependencies = [ 1386 | "either", 1387 | "home", 1388 | "once_cell", 1389 | "rustix", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "winapi" 1394 | version = "0.3.9" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1397 | dependencies = [ 1398 | "winapi-i686-pc-windows-gnu", 1399 | "winapi-x86_64-pc-windows-gnu", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "winapi-i686-pc-windows-gnu" 1404 | version = "0.4.0" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1407 | 1408 | [[package]] 1409 | name = "winapi-util" 1410 | version = "0.1.6" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 1413 | dependencies = [ 1414 | "winapi", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "winapi-x86_64-pc-windows-gnu" 1419 | version = "0.4.0" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1422 | 1423 | [[package]] 1424 | name = "windows-sys" 1425 | version = "0.48.0" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1428 | dependencies = [ 1429 | "windows-targets", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "windows-targets" 1434 | version = "0.48.5" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1437 | dependencies = [ 1438 | "windows_aarch64_gnullvm", 1439 | "windows_aarch64_msvc", 1440 | "windows_i686_gnu", 1441 | "windows_i686_msvc", 1442 | "windows_x86_64_gnu", 1443 | "windows_x86_64_gnullvm", 1444 | "windows_x86_64_msvc", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "windows_aarch64_gnullvm" 1449 | version = "0.48.5" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1452 | 1453 | [[package]] 1454 | name = "windows_aarch64_msvc" 1455 | version = "0.48.5" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1458 | 1459 | [[package]] 1460 | name = "windows_i686_gnu" 1461 | version = "0.48.5" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1464 | 1465 | [[package]] 1466 | name = "windows_i686_msvc" 1467 | version = "0.48.5" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1470 | 1471 | [[package]] 1472 | name = "windows_x86_64_gnu" 1473 | version = "0.48.5" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1476 | 1477 | [[package]] 1478 | name = "windows_x86_64_gnullvm" 1479 | version = "0.48.5" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1482 | 1483 | [[package]] 1484 | name = "windows_x86_64_msvc" 1485 | version = "0.48.5" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1488 | 1489 | [[package]] 1490 | name = "zerocopy" 1491 | version = "0.7.35" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1494 | dependencies = [ 1495 | "byteorder", 1496 | "zerocopy-derive 0.7.35", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "zerocopy" 1501 | version = "0.8.25" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" 1504 | dependencies = [ 1505 | "zerocopy-derive 0.8.25", 1506 | ] 1507 | 1508 | [[package]] 1509 | name = "zerocopy-derive" 1510 | version = "0.7.35" 1511 | source = "registry+https://github.com/rust-lang/crates.io-index" 1512 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1513 | dependencies = [ 1514 | "proc-macro2", 1515 | "quote", 1516 | "syn", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "zerocopy-derive" 1521 | version = "0.8.25" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" 1524 | dependencies = [ 1525 | "proc-macro2", 1526 | "quote", 1527 | "syn", 1528 | ] 1529 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pprof" 3 | version = "0.15.0" 4 | authors = ["Yang Keao "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | description = "An internal perf tools for rust programs." 8 | repository = "https://github.com/tikv/pprof-rs" 9 | documentation = "https://docs.rs/pprof/" 10 | readme = "README.md" 11 | rust-version = "1.74.0" # MSRV 12 | 13 | [features] 14 | default = ["cpp"] 15 | cpp = ["symbolic-demangle/cpp"] 16 | flamegraph = ["inferno"] 17 | frame-pointer = [] 18 | 19 | # A private feature to indicate either prost-codec or protobuf-codec is enabled. 20 | _protobuf = [] 21 | prost-codec = ["prost", "prost-derive", "prost-build", "sha2", "_protobuf"] 22 | protobuf-codec = ["protobuf", "protobuf-codegen", "_protobuf"] 23 | framehop-unwinder = ["framehop", "memmap2", "object"] 24 | perfmaps = ["arc-swap"] 25 | large-depth = [] 26 | huge-depth = [] 27 | 28 | [dependencies] 29 | backtrace = { version = "0.3" } 30 | once_cell = "1.9" 31 | libc = "^0.2.66" 32 | log = "0.4" 33 | nix = { version = "0.26", default-features = false, features = ["signal", "fs"] } 34 | spin = "0.10" 35 | tempfile = "3.1" 36 | thiserror = "2.0" 37 | findshlibs = "0.10" 38 | cfg-if = "1.0" 39 | smallvec = "1.7" 40 | 41 | inferno = { version = "0.11", default-features = false, features = ["nameattr"], optional = true } 42 | prost = { version = "0.12", optional = true } 43 | prost-derive = { version = "0.12", optional = true } 44 | protobuf = { version = ">=3.7.2", optional = true } 45 | criterion = {version = "0.5", optional = true} 46 | aligned-vec = "0.6" 47 | 48 | # framehop unwinder dependencies 49 | framehop = { version = "0.13", optional = true } 50 | memmap2 = { version = "0.5.5", optional = true } 51 | object = { version = "0.29.0", optional = true } 52 | arc-swap = { version = "1.7.1", optional = true } 53 | 54 | [dependencies.symbolic-demangle] 55 | version = "12.1" 56 | default-features = false 57 | features = ["rust"] 58 | 59 | [dev-dependencies] 60 | criterion = "0.5" 61 | rand = "0.8.0" 62 | 63 | [build-dependencies] 64 | prost-build = { version = "0.12", optional = true } 65 | sha2 = { version = "0.10", optional = true } 66 | protobuf-codegen = { version = "3.7.2", optional = true } 67 | 68 | [[example]] 69 | name = "flamegraph" 70 | required-features = ["flamegraph"] 71 | 72 | [[example]] 73 | name = "profile_proto_with_prost" 74 | required-features = ["protobuf", "prost-codec"] 75 | 76 | [[example]] 77 | name = "profile_proto_with_protobuf_codec" 78 | required-features = ["protobuf", "protobuf-codec"] 79 | 80 | [[example]] 81 | name = "multithread_flamegraph" 82 | required-features = ["flamegraph"] 83 | 84 | [[example]] 85 | name = "criterion" 86 | required-features = ["flamegraph", "criterion"] 87 | 88 | [[bench]] 89 | name = "collector" 90 | path = "benches/collector.rs" 91 | harness = false 92 | 93 | [[bench]] 94 | name = "addr_validate" 95 | path = "benches/addr_validate.rs" 96 | harness = false 97 | 98 | [package.metadata.docs.rs] 99 | all-features = true 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 TiKV Project Authors. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pprof 2 | 3 | `pprof` is a cpu profiler that can be easily integrated into a rust program. 4 | 5 | [![Actions Status](https://github.com/tikv/pprof-rs/workflows/build/badge.svg)](https://github.com/tikv/pprof-rs/actions) 6 | [![Crates.io](https://img.shields.io/crates/v/pprof.svg)](https://crates.io/crates/pprof) 7 | [![Dependency Status](https://deps.rs/repo/github/tikv/pprof-rs/status.svg)](https://deps.rs/repo/github/tikv/pprof-rs) 8 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftikv%2Fpprof-rs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftikv%2Fpprof-rs?ref=badge_shield) 9 | 10 | ## Usage 11 | 12 | First, get a guard to start profiling. Profiling will continue until this guard was dropped. 13 | 14 | ```rust 15 | let guard = pprof::ProfilerGuardBuilder::default().frequency(1000).blocklist(&["libc", "libgcc", "pthread", "vdso"]).build().unwrap(); 16 | ``` 17 | 18 | During the profiling time, you can get a report with the guard. 19 | 20 | ```rust 21 | if let Ok(report) = guard.report().build() { 22 | println!("report: {:?}", &report); 23 | }; 24 | ``` 25 | 26 | `Debug` was implemented for `Report`. It will print a human-readable stack counter report. Here is an example: 27 | 28 | ``` 29 | FRAME: backtrace::backtrace::trace::h3e91a3123a3049a5 -> FRAME: pprof::profiler::perf_signal_handler::h7b995c4ab2e66493 -> FRAME: Unknown -> FRAME: prime_number::is_prime_number::h70653a2633b88023 -> FRAME: prime_number::main::h47f1058543990c8b -> FRAME: std::rt::lang_start::{{closure}}::h4262e250f8024b06 -> FRAME: std::rt::lang_start_internal::{{closure}}::h812f70926ebbddd0 -> std::panicking::try::do_call::h3210e2ce6a68897b -> FRAME: __rust_maybe_catch_panic -> FRAME: std::panicking::try::h28c2e2ec1c3871ce -> std::panic::catch_unwind::h05e542185e35aabf -> std::rt::lang_start_internal::hd7efcfd33686f472 -> FRAME: main -> FRAME: __libc_start_main -> FRAME: _start -> FRAME: Unknown -> THREAD: prime_number 1217 30 | FRAME: backtrace::backtrace::trace::h3e91a3123a3049a5 -> FRAME: pprof::profiler::perf_signal_handler::h7b995c4ab2e66493 -> FRAME: Unknown -> FRAME: alloc::alloc::box_free::h82cea48ed688e081 -> FRAME: prime_number::main::h47f1058543990c8b -> FRAME: std::rt::lang_start::{{closure}}::h4262e250f8024b06 -> FRAME: std::rt::lang_start_internal::{{closure}}::h812f70926ebbddd0 -> std::panicking::try::do_call::h3210e2ce6a68897b -> FRAME: __rust_maybe_catch_panic -> FRAME: std::panicking::try::h28c2e2ec1c3871ce -> std::panic::catch_unwind::h05e542185e35aabf -> std::rt::lang_start_internal::hd7efcfd33686f472 -> FRAME: main -> FRAME: __libc_start_main -> FRAME: _start -> FRAME: Unknown -> THREAD: prime_number 1 31 | FRAME: backtrace::backtrace::trace::h3e91a3123a3049a5 -> FRAME: pprof::profiler::perf_signal_handler::h7b995c4ab2e66493 -> FRAME: Unknown -> FRAME: prime_number::main::h47f1058543990c8b -> FRAME: std::rt::lang_start::{{closure}}::h4262e250f8024b06 -> FRAME: std::rt::lang_start_internal::{{closure}}::h812f70926ebbddd0 -> std::panicking::try::do_call::h3210e2ce6a68897b -> FRAME: __rust_maybe_catch_panic -> FRAME: std::panicking::try::h28c2e2ec1c3871ce -> std::panic::catch_unwind::h05e542185e35aabf -> std::rt::lang_start_internal::hd7efcfd33686f472 -> FRAME: main -> FRAME: __libc_start_main -> FRAME: _start -> FRAME: Unknown -> THREAD: prime_number 1 32 | ``` 33 | 34 | 35 | ## Features 36 | 37 | - `cpp` enables the cpp demangle. 38 | - `flamegraph` enables the flamegraph report format. 39 | - `prost-codec` enables the pprof protobuf report format through `prost`. 40 | - `protobuf-codec` enables the pprof protobuf report format through `protobuf` crate. 41 | - `frame-pointer` gets the backtrace through frame pointer. **only available for nightly** 42 | 43 | ## Flamegraph 44 | 45 | ```toml 46 | pprof = { version = "0.15", features = ["flamegraph"] } 47 | ``` 48 | 49 | If `flamegraph` feature is enabled, you can generate flamegraph from the report. `Report` struct has a method `flamegraph` which can generate flamegraph and write it into a `Write`. 50 | 51 | ```rust 52 | if let Ok(report) = guard.report().build() { 53 | let file = File::create("flamegraph.svg").unwrap(); 54 | report.flamegraph(file).unwrap(); 55 | }; 56 | ``` 57 | 58 | Additionally, custom flamegraph options can be specified. 59 | 60 | ```rust 61 | if let Ok(report) = guard.report().build() { 62 | let file = File::create("flamegraph.svg").unwrap(); 63 | let mut options = pprof::flamegraph::Options::default(); 64 | options.image_width = Some(2500); 65 | report.flamegraph_with_options(file, &mut options).unwrap(); 66 | }; 67 | ``` 68 | 69 | Here is an example of generated flamegraph: 70 | 71 | ![flamegraph](https://user-images.githubusercontent.com/5244316/68021936-c1265e80-fcdd-11e9-8fa5-62b548bc751d.png) 72 | 73 | ## Frame Post Processor 74 | 75 | Before the report was generated, `frame_post_processor` was provided as an interface to modify raw statistic data. If you want to group several symbols/thread or demangle for some symbols, this feature will benefit you. 76 | 77 | For example: 78 | 79 | ```rust 80 | fn frames_post_processor() -> impl Fn(&mut pprof::Frames) { 81 | let thread_rename = [ 82 | (Regex::new(r"^grpc-server-\d*$").unwrap(), "grpc-server"), 83 | (Regex::new(r"^cop-high\d*$").unwrap(), "cop-high"), 84 | (Regex::new(r"^cop-normal\d*$").unwrap(), "cop-normal"), 85 | (Regex::new(r"^cop-low\d*$").unwrap(), "cop-low"), 86 | (Regex::new(r"^raftstore-\d*$").unwrap(), "raftstore"), 87 | (Regex::new(r"^raftstore-\d*-\d*$").unwrap(), "raftstore"), 88 | (Regex::new(r"^sst-importer\d*$").unwrap(), "sst-importer"), 89 | ( 90 | Regex::new(r"^store-read-low\d*$").unwrap(), 91 | "store-read-low", 92 | ), 93 | (Regex::new(r"^rocksdb:bg\d*$").unwrap(), "rocksdb:bg"), 94 | (Regex::new(r"^rocksdb:low\d*$").unwrap(), "rocksdb:low"), 95 | (Regex::new(r"^rocksdb:high\d*$").unwrap(), "rocksdb:high"), 96 | (Regex::new(r"^snap sender\d*$").unwrap(), "snap-sender"), 97 | (Regex::new(r"^snap-sender\d*$").unwrap(), "snap-sender"), 98 | (Regex::new(r"^apply-\d*$").unwrap(), "apply"), 99 | (Regex::new(r"^future-poller-\d*$").unwrap(), "future-poller"), 100 | ]; 101 | 102 | move |frames| { 103 | for (regex, name) in thread_rename.iter() { 104 | if regex.is_match(&frames.thread_name) { 105 | frames.thread_name = name.to_string(); 106 | } 107 | } 108 | } 109 | } 110 | ``` 111 | 112 | ```rust 113 | if let Ok(report) = guard.frames_post_processor(frames_post_processor()).report().build() { 114 | let file = File::create("flamegraph.svg").unwrap(); 115 | report.flamegraph(file).unwrap(); 116 | } 117 | ``` 118 | 119 | ## Use with `pprof` 120 | 121 | With `protobuf` feature enabled, `pprof-rs` can also output [`profile.proto`](https://github.com/google/pprof/blob/master/proto/profile.proto) format. 122 | 123 | ```rust 124 | match guard.report().build() { 125 | Ok(report) => { 126 | let mut file = File::create("profile.pb").unwrap(); 127 | let profile = report.pprof().unwrap(); 128 | 129 | let mut content = Vec::new(); 130 | profile.encode(&mut content).unwrap(); 131 | file.write_all(&content).unwrap(); 132 | 133 | println!("report: {}", &report); 134 | } 135 | Err(_) => {} 136 | }; 137 | ``` 138 | 139 | Then you can use `pprof` command with `profile.pb`. For example: 140 | 141 | ```shell 142 | ~/go/bin/pprof -svg profile.pb 143 | ``` 144 | 145 | Then `pprof` will generate a svg file according to the profile. 146 | 147 | ![tree](https://user-images.githubusercontent.com/5244316/68571082-1f50ff80-049d-11ea-8437-211ab0d80480.png) 148 | 149 | ## Integrate with `criterion` 150 | 151 | With `criterion` feature enabled, a criterion custom profiler is provided in `pprof-rs`. 152 | 153 | ```rust 154 | use pprof::criterion::{PProfProfiler, Output}; 155 | 156 | criterion_group!{ 157 | name = benches; 158 | config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); 159 | targets = bench 160 | } 161 | criterion_main!(benches); 162 | ``` 163 | 164 | After running the benchmark, you can find the flamegraph at `target/criterion//profile/flamegraph.svg`. `protobuf` output is also available with the `Output::Protobuf` option; these end up at `target/criterion//profile.pb`. 165 | 166 | For more details, you can check the [`examples/criterion.rs`](examples/criterion.rs), and the profiling document of [`criterion`](https://bheisler.github.io/criterion.rs/book/user_guide/profiling.html). For a quick start, you can run this example with `cargo run --example criterion --release --features="flamegraph criterion" -- --bench --profile-time 5` 167 | 168 | ## Why not ... 169 | 170 | There have been tons of profilers, why we create a new one? Here we make a comparison between `pprof-rs` and other popular profilers to help you choose the best fit one. 171 | 172 | ### gperftools 173 | 174 | `gperftools` is also an integrated profiler. There is also a wrapper for `gperftools` in rust called [`cpuprofiler`](https://crates.io/crates/cpuprofiler) which makes it programmable for a rust program. 175 | 176 | #### Pros 177 | 178 | 1. `pprof-rs` has a modern build system and can be integrated into a rust program easily while compiling `gperftools` statically is buggy. 179 | 2. `pprof-rs` has a native rust interface while `gperftools`'s wrapper is **just** a wrapper. 180 | 3. Programming with rust guarantees thread safety natively. 181 | 182 | #### Cons 183 | 184 | 1. `gperftools` is a collection of performance analysis tools which contains cpu profiler, heap profiler... `pprof-rs` focuses on cpu profiler now. 185 | 186 | ### perf 187 | 188 | `perf` is a performance analyzing tool in Linux. 189 | 190 | #### Pros 191 | 192 | 1. You don't need to start another process to perf with `pprof-rs`. 193 | 2. `pprof-rs` can be easily integrated with rust program which means you don't need to install any other programs. 194 | 3. `pprof-rs` has a modern programmable interface to hack with 195 | 4. `pprof-rs` theoretically supports all POSIX systems and can easily support more systems in the future. 196 | 197 | #### Cons 198 | 199 | 1. `perf` is much more feature-rich than `pprof-rs`. 200 | 2. `perf` is highly integrated with Linux. 201 | 202 | ## Implementation 203 | 204 | When profiling was started, `setitimer` system call was used to set up a timer which will send a SIGPROF to this program every constant interval. 205 | 206 | When receiving a SIGPROF signal, the signal handler will capture a backtrace and increase the count of it. After a while, the profiler can get every possible backtrace and their count. Finally, we can generate a report with profiler data. 207 | 208 | However, the real world is full of thorns. There are many worths of note parts in the implementation. 209 | 210 | ### Backtrace 211 | 212 | Unfortunately, there is no 100% robust stack tracing method. [Some related researches](https://github.com/gperftools/gperftools/wiki/gperftools%27-stacktrace-capturing-methods-and-their-issues) have been done by gperftools. `pprof-rs` uses [`backtrace-rs`](https://github.com/rust-lang/backtrace-rs) which finally uses libunwind provided by `libgcc` 213 | 214 | **WARN:** as described in former gperftools documents, libunwind provided by `libgcc` is not signal safe. 215 | 216 | > libgcc's unwind method is not safe to use from signal handlers. One particular cause of deadlock is when profiling tick happens when program is propagating thrown exception. 217 | 218 | This can be resolved by adding a blocklist: 219 | 220 | ```rust 221 | let guard = pprof::ProfilerGuardBuilder::default().frequency(1000).blocklist(&["libc", "libgcc", "pthread", "vdso"]).build().unwrap(); 222 | ``` 223 | 224 | The `vdso` should also be added to the blocklist, because in some distribution (e.g. ubuntu 18.04), the dwarf information in vdso is incorrect. 225 | 226 | ### Frame Pointer 227 | 228 | The `pprof-rs` also supports unwinding through frame pointer, without the need to use `libunwind`. However, the standard library shipped with the rust compiler does not have the correct frame pointer in every function, so you need to use `cargo +nightly -Z build-std` to build the standard library from source. 229 | 230 | As we cannot get the stack boundaries inside the signal handler, it's also not possible to ensure the safety. If the frame pointer was set to a wrong value, the program will panic. 231 | 232 | ### Signal Safety 233 | 234 | Signal safety is hard to guarantee. But it's not *that* hard. 235 | 236 | First, we have to avoid deadlock. When profiler samples or reports, it will get a global lock on the profiler. Particularly, deadlock happenswhen the running program is getting a report from the profiler (which will hold the lock), at the same time, a SIGPROF signal is triggered and the profiler wants to sample (which will also hold the lock). So we don't wait for the lock in signal handler, instead we `try_lock` in the signal handler. If the global lock cannot be gotten, the profiler will give up directly. 237 | 238 | Then, signal safety POSIX function is quite limited as [listed here](http://man7.org/linux/man-pages/man7/signal-safety.7.html). The most bothering issue is that we cannot use `malloc` in signal handler. So we can only use pre-allocated memory in profiler. The simplest way is `write` every sample serially into a file. We optimized it with a fix-sized hashmap that has a fixed number of buckets and every bucket is an array with a fixed number of items. If the hashmap is full, we pop out the item with minimum count and write it into a temporary file. 239 | 240 | Unit tests have been added to guarantee there is no `malloc` in sample functions. 241 | 242 | `futex` is also not safe to use in signal handler. So we use a spin lock to avoid usage of `futex`. 243 | 244 | ## TODO 245 | 246 | 1. Restore the original SIGPROF handler after stopping the profiler. 247 | 248 | ## Minimum Supported Rust Version 249 | 250 | Rust 1.74 or higher. 251 | 252 | Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. 253 | 254 | ## License 255 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftikv%2Fpprof-rs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftikv%2Fpprof-rs?ref=badge_large) 256 | -------------------------------------------------------------------------------- /benches/addr_validate.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use criterion::{criterion_group, criterion_main, Criterion}; 4 | use pprof::validate; 5 | 6 | fn bench_validate_addr(c: &mut Criterion) { 7 | c.bench_function("validate stack addr", |b| { 8 | let stack_addrs = [0; 100]; 9 | 10 | b.iter(|| { 11 | stack_addrs.iter().for_each(|item| { 12 | validate(item as *const _ as *const libc::c_void); 13 | }) 14 | }) 15 | }); 16 | 17 | c.bench_function("validate heap addr", |b| { 18 | let heap_addrs = vec![0; 100]; 19 | 20 | b.iter(|| { 21 | heap_addrs.iter().for_each(|item| { 22 | validate(item as *const _ as *const libc::c_void); 23 | }) 24 | }) 25 | }); 26 | } 27 | 28 | criterion_group!(benches, bench_validate_addr); 29 | criterion_main!(benches); 30 | -------------------------------------------------------------------------------- /benches/collector.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use criterion::{criterion_group, criterion_main, Criterion}; 4 | use pprof::{Collector, HashCounter}; 5 | 6 | fn bench_write_to_collector(c: &mut Criterion) { 7 | c.bench_function("write_to_collector", |b| { 8 | let mut collector = Collector::new().unwrap(); 9 | 10 | const SIZE: usize = 1000; 11 | 12 | let mut vec: Vec = Vec::with_capacity(SIZE); 13 | for _ in 0..vec.capacity() { 14 | vec.push(rand::random()); 15 | } 16 | 17 | b.iter(|| { 18 | vec.iter().for_each(|item| { 19 | collector.add(*item, 1).unwrap(); 20 | }) 21 | }) 22 | }); 23 | 24 | c.bench_function("write_into_stack_hash_counter", |b| { 25 | let mut collector = HashCounter::default(); 26 | 27 | const SIZE: usize = 1000; 28 | 29 | let mut vec: Vec = Vec::with_capacity(SIZE); 30 | for _ in 0..vec.capacity() { 31 | vec.push(rand::random()); 32 | } 33 | 34 | b.iter(|| { 35 | vec.iter().for_each(|item| { 36 | collector.add(*item, 1); 37 | }) 38 | }); 39 | }); 40 | } 41 | 42 | criterion_group!(benches, bench_write_to_collector); 43 | criterion_main!(benches); 44 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | #[cfg(feature = "protobuf-codec")] 3 | // Allow deprecated as TiKV pin versions to a outdated one. 4 | fn generate_protobuf() { 5 | use std::io::Write; 6 | let customize = ::default(); 7 | // Set the output directory for generated files 8 | let out_dir = std::env::var("OUT_DIR").unwrap(); 9 | 10 | let mut cg = protobuf_codegen::Codegen::new(); 11 | cg.pure(); 12 | 13 | cg.inputs(["proto/profile.proto"]).includes(["proto"]); 14 | 15 | cg.customize(customize); 16 | cg.out_dir(&out_dir).run().unwrap(); 17 | 18 | // Optionally, write a mod.rs file for module inclusion 19 | let mut f = std::fs::File::create(format!("{}/mod.rs", out_dir)).unwrap(); 20 | write!(f, "pub mod profile;").unwrap(); 21 | } 22 | 23 | #[cfg(feature = "prost-codec")] 24 | fn generate_prost() { 25 | use sha2::{Digest, Sha256}; 26 | use std::{ 27 | fmt::Write, 28 | fs::{self, File}, 29 | io::{self, BufRead, BufReader}, 30 | }; 31 | 32 | const PRE_GENERATED_PATH: &str = "proto/perftools.profiles.rs"; 33 | 34 | // Calculate the SHA256 of the proto file 35 | let mut hasher = Sha256::new(); 36 | let mut proto_file = BufReader::new(File::open("proto/profile.proto").unwrap()); 37 | io::copy(&mut proto_file, &mut hasher).unwrap(); 38 | let mut hex = String::new(); 39 | for b in hasher.finalize() { 40 | write!(&mut hex, "{:x}", b).unwrap(); 41 | } 42 | let hash_comment = format!("// {} proto/profile.proto", hex); 43 | 44 | let first_line = File::open(PRE_GENERATED_PATH) 45 | .and_then(|f| { 46 | let mut reader = BufReader::new(f); 47 | let mut first_line = String::new(); 48 | reader.read_line(&mut first_line)?; 49 | Ok(first_line) 50 | }) 51 | .unwrap_or_default(); 52 | // If the hash of the proto file changes, regenerate the prost file. 53 | if first_line.trim() != hash_comment { 54 | prost_build::Config::new() 55 | .out_dir("proto/") 56 | .compile_protos(&["proto/profile.proto"], &["proto/"]) 57 | .unwrap(); 58 | // Prepend the hash comment to the generated file. 59 | let generated = fs::read_to_string(PRE_GENERATED_PATH).unwrap(); 60 | let with_hex = format!("{}\n\n{}", hash_comment, generated); 61 | fs::write(PRE_GENERATED_PATH, with_hex).unwrap(); 62 | } 63 | } 64 | 65 | fn main() { 66 | #[cfg(feature = "prost-codec")] 67 | generate_prost(); 68 | #[cfg(feature = "protobuf-codec")] 69 | generate_protobuf(); 70 | } 71 | -------------------------------------------------------------------------------- /examples/backtrace_while_sampling.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fs::File; 4 | 5 | fn deep_recursive(depth: i32) { 6 | if depth > 0 { 7 | deep_recursive(depth - 1); 8 | } else { 9 | backtrace::Backtrace::new(); 10 | } 11 | } 12 | 13 | fn main() { 14 | let guard = pprof::ProfilerGuardBuilder::default() 15 | .frequency(1000) 16 | .blocklist(&["libc", "libgcc", "pthread"]) 17 | .build() 18 | .unwrap(); 19 | 20 | for _ in 0..10000 { 21 | deep_recursive(20); 22 | } 23 | 24 | if let Ok(report) = guard.report().build() { 25 | let file = File::create("flamegraph.svg").unwrap(); 26 | report.flamegraph(file).unwrap(); 27 | 28 | println!("report: {:?}", &report); 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /examples/criterion.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | use criterion::{black_box, BenchmarkId, Criterion}; 4 | 5 | use pprof::criterion::{Output, PProfProfiler}; 6 | 7 | // Thanks to the example provided by @jebbow in his article 8 | // https://www.jibbow.com/posts/criterion-flamegraphs/ 9 | 10 | fn fibonacci(n: u64) -> u64 { 11 | match n { 12 | 0 | 1 => 1, 13 | n => fibonacci(n - 1) + fibonacci(n - 2), 14 | } 15 | } 16 | 17 | fn bench(c: &mut Criterion) { 18 | c.bench_function("Fibonacci", |b| b.iter(|| fibonacci(black_box(20)))); 19 | } 20 | 21 | fn bench_group(c: &mut Criterion) { 22 | let mut group = c.benchmark_group("Fibonacci Sizes"); 23 | 24 | for s in &[1, 10, 100, 1000] { 25 | group.bench_with_input(BenchmarkId::from_parameter(s), s, |b, s| { 26 | b.iter(|| fibonacci(black_box(*s))) 27 | }); 28 | } 29 | } 30 | 31 | criterion_group! { 32 | name = benches; 33 | config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); 34 | targets = bench, bench_group 35 | } 36 | criterion_main!(benches); 37 | -------------------------------------------------------------------------------- /examples/flamegraph.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fs::File; 4 | 5 | #[inline(never)] 6 | fn is_prime_number1(v: usize, prime_numbers: &[usize]) -> bool { 7 | if v < 10000 { 8 | let r = prime_numbers.binary_search(&v); 9 | return r.is_ok(); 10 | } 11 | 12 | for n in prime_numbers { 13 | if v % n == 0 { 14 | return false; 15 | } 16 | } 17 | 18 | true 19 | } 20 | 21 | #[inline(always)] 22 | fn is_prime_number2(v: usize, prime_numbers: &[usize]) -> bool { 23 | if v < 10000 { 24 | let r = prime_numbers.binary_search(&v); 25 | return r.is_ok(); 26 | } 27 | 28 | for n in prime_numbers { 29 | if v % n == 0 { 30 | return false; 31 | } 32 | } 33 | 34 | true 35 | } 36 | 37 | #[inline(never)] 38 | fn is_prime_number3(v: usize, prime_numbers: &[usize]) -> bool { 39 | if v < 10000 { 40 | let r = prime_numbers.binary_search(&v); 41 | return r.is_ok(); 42 | } 43 | 44 | for n in prime_numbers { 45 | if v % n == 0 { 46 | return false; 47 | } 48 | } 49 | 50 | true 51 | } 52 | 53 | #[inline(never)] 54 | fn prepare_prime_numbers() -> Vec { 55 | // bootstrap: Generate a prime table of 0..10000 56 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 57 | prime_number_table[0] = false; 58 | prime_number_table[1] = false; 59 | for i in 2..10000 { 60 | if prime_number_table[i] { 61 | let mut v = i * 2; 62 | while v < 10000 { 63 | prime_number_table[v] = false; 64 | v += i; 65 | } 66 | } 67 | } 68 | let mut prime_numbers = vec![]; 69 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 70 | if *exist { 71 | prime_numbers.push(i); 72 | } 73 | } 74 | prime_numbers 75 | } 76 | 77 | fn main() { 78 | let prime_numbers = prepare_prime_numbers(); 79 | 80 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 81 | 82 | let mut v = 0; 83 | 84 | for i in 2..5000000 { 85 | if i % 4 == 0 { 86 | if is_prime_number1(i, &prime_numbers) { 87 | v += 1; 88 | } 89 | } else if i % 4 == 1 { 90 | if is_prime_number2(i, &prime_numbers) { 91 | v += 1; 92 | } 93 | } else if is_prime_number3(i, &prime_numbers) { 94 | v += 1; 95 | } 96 | } 97 | 98 | println!("Prime numbers: {}", v); 99 | 100 | if let Ok(report) = guard.report().build() { 101 | let file = File::create("flamegraph.svg").unwrap(); 102 | report.flamegraph(file).unwrap(); 103 | 104 | println!("report: {:?}", &report); 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /examples/multithread.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::sync::Arc; 4 | 5 | #[inline(never)] 6 | fn is_prime_number(v: usize, prime_numbers: Arc>) -> bool { 7 | if v < 10000 { 8 | let r = prime_numbers.binary_search(&v); 9 | return r.is_ok(); 10 | } 11 | 12 | for n in prime_numbers.iter() { 13 | if v % n == 0 { 14 | return false; 15 | } 16 | } 17 | 18 | true 19 | } 20 | 21 | #[inline(never)] 22 | fn prepare_prime_numbers() -> Vec { 23 | // bootstrap: Generate a prime table of 0..10000 24 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 25 | prime_number_table[0] = false; 26 | prime_number_table[1] = false; 27 | for i in 2..10000 { 28 | if prime_number_table[i] { 29 | let mut v = i * 2; 30 | while v < 10000 { 31 | prime_number_table[v] = false; 32 | v += i; 33 | } 34 | } 35 | } 36 | let mut prime_numbers = vec![]; 37 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 38 | if *exist { 39 | prime_numbers.push(i); 40 | } 41 | } 42 | prime_numbers 43 | } 44 | 45 | fn main() { 46 | let prime_numbers = Arc::new(prepare_prime_numbers()); 47 | 48 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 49 | 50 | let p1 = prime_numbers.clone(); 51 | std::thread::Builder::new() 52 | .name("THREAD_ONE".to_owned()) 53 | .spawn(move || loop { 54 | let mut _v = 0; 55 | 56 | for i in 2..50000 { 57 | if is_prime_number(i, p1.clone()) { 58 | _v += 1; 59 | } 60 | } 61 | }) 62 | .unwrap(); 63 | 64 | let p2 = prime_numbers.clone(); 65 | std::thread::Builder::new() 66 | .name("THREAD_TWO".to_owned()) 67 | .spawn(move || loop { 68 | let mut _v = 0; 69 | 70 | for i in 2..50000 { 71 | if is_prime_number(i, p2.clone()) { 72 | _v += 1; 73 | } 74 | } 75 | }) 76 | .unwrap(); 77 | 78 | let p3 = prime_numbers; 79 | std::thread::spawn(move || loop { 80 | let mut _v = 0; 81 | 82 | for i in 2..50000 { 83 | if is_prime_number(i, p3.clone()) { 84 | _v += 1; 85 | } 86 | } 87 | }); 88 | 89 | loop { 90 | if let Ok(report) = guard.report().build() { 91 | println!("{:?}", report); 92 | }; 93 | std::thread::sleep(std::time::Duration::from_secs(1)) 94 | } 95 | // pprof::PROFILER.lock().unwrap().stop(); 96 | } 97 | -------------------------------------------------------------------------------- /examples/multithread_flamegraph.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fs::File; 4 | use std::sync::Arc; 5 | 6 | #[inline(never)] 7 | fn is_prime_number(v: usize, prime_numbers: Arc>) -> bool { 8 | if v < 10000 { 9 | let r = prime_numbers.binary_search(&v); 10 | return r.is_ok(); 11 | } 12 | 13 | for n in prime_numbers.iter() { 14 | if v % n == 0 { 15 | return false; 16 | } 17 | } 18 | 19 | true 20 | } 21 | 22 | #[inline(never)] 23 | fn prepare_prime_numbers() -> Vec { 24 | // bootstrap: Generate a prime table of 0..10000 25 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 26 | prime_number_table[0] = false; 27 | prime_number_table[1] = false; 28 | for i in 2..10000 { 29 | if prime_number_table[i] { 30 | let mut v = i * 2; 31 | while v < 10000 { 32 | prime_number_table[v] = false; 33 | v += i; 34 | } 35 | } 36 | } 37 | let mut prime_numbers = vec![]; 38 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 39 | if *exist { 40 | prime_numbers.push(i); 41 | } 42 | } 43 | prime_numbers 44 | } 45 | 46 | fn main() { 47 | let prime_numbers = Arc::new(prepare_prime_numbers()); 48 | 49 | // println!("{}", std::mem::size_of::>()); 50 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 51 | 52 | let p1 = prime_numbers.clone(); 53 | std::thread::Builder::new() 54 | .name("THREAD_ONE".to_owned()) 55 | .spawn(move || loop { 56 | let mut _v = 0; 57 | 58 | for i in 2..50000 { 59 | if is_prime_number(i, p1.clone()) { 60 | _v += 1; 61 | } 62 | } 63 | }) 64 | .unwrap(); 65 | 66 | let p2 = prime_numbers.clone(); 67 | std::thread::Builder::new() 68 | .name("THREAD_TWO".to_owned()) 69 | .spawn(move || loop { 70 | let mut _v = 0; 71 | 72 | for i in 2..50000 { 73 | if is_prime_number(i, p2.clone()) { 74 | _v += 1; 75 | } 76 | } 77 | }) 78 | .unwrap(); 79 | 80 | let p3 = prime_numbers; 81 | std::thread::spawn(move || loop { 82 | let mut _v = 0; 83 | 84 | for i in 2..50000 { 85 | if is_prime_number(i, p3.clone()) { 86 | _v += 1; 87 | } 88 | } 89 | }); 90 | 91 | std::thread::sleep(std::time::Duration::from_secs(5)); 92 | if let Ok(report) = guard.report().build() { 93 | let file = File::create("flamegraph.svg").unwrap(); 94 | report.flamegraph(file).unwrap(); 95 | 96 | println!("{:?}", report); 97 | }; 98 | 99 | // pprof::PROFILER.lock().unwrap().stop(); 100 | } 101 | -------------------------------------------------------------------------------- /examples/post_processor.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::sync::Arc; 4 | 5 | #[inline(never)] 6 | fn is_prime_number(v: usize, prime_numbers: Arc>) -> bool { 7 | if v < 10000 { 8 | let r = prime_numbers.binary_search(&v); 9 | return r.is_ok(); 10 | } 11 | 12 | for n in prime_numbers.iter() { 13 | if v % n == 0 { 14 | return false; 15 | } 16 | } 17 | 18 | true 19 | } 20 | 21 | #[inline(never)] 22 | fn prepare_prime_numbers() -> Vec { 23 | // bootstrap: Generate a prime table of 0..10000 24 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 25 | prime_number_table[0] = false; 26 | prime_number_table[1] = false; 27 | for i in 2..10000 { 28 | if prime_number_table[i] { 29 | let mut v = i * 2; 30 | while v < 10000 { 31 | prime_number_table[v] = false; 32 | v += i; 33 | } 34 | } 35 | } 36 | let mut prime_numbers = vec![]; 37 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 38 | if *exist { 39 | prime_numbers.push(i); 40 | } 41 | } 42 | prime_numbers 43 | } 44 | 45 | fn main() { 46 | let prime_numbers = Arc::new(prepare_prime_numbers()); 47 | 48 | // println!("{}", std::mem::size_of::>()); 49 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 50 | 51 | let p1 = prime_numbers.clone(); 52 | std::thread::Builder::new() 53 | .name("THREAD_ONE".to_owned()) 54 | .spawn(move || loop { 55 | let mut _v = 0; 56 | 57 | for i in 2..50000 { 58 | if is_prime_number(i, p1.clone()) { 59 | _v += 1; 60 | } 61 | } 62 | }) 63 | .unwrap(); 64 | 65 | let p2 = prime_numbers.clone(); 66 | std::thread::Builder::new() 67 | .name("THREAD_TWO".to_owned()) 68 | .spawn(move || loop { 69 | let mut _v = 0; 70 | 71 | for i in 2..50000 { 72 | if is_prime_number(i, p2.clone()) { 73 | _v += 1; 74 | } 75 | } 76 | }) 77 | .unwrap(); 78 | 79 | let p3 = prime_numbers; 80 | std::thread::spawn(move || loop { 81 | let mut _v = 0; 82 | 83 | for i in 2..50000 { 84 | if is_prime_number(i, p3.clone()) { 85 | _v += 1; 86 | } 87 | } 88 | }); 89 | 90 | loop { 91 | if let Ok(report) = guard 92 | .report() 93 | .frames_post_processor(|frames| { 94 | frames.thread_name = "PROCESSED".to_string(); 95 | }) 96 | .build() 97 | { 98 | println!("{:?}", report); 99 | }; 100 | std::thread::sleep(std::time::Duration::from_secs(1)) 101 | } 102 | // pprof::PROFILER.lock().unwrap().stop(); 103 | } 104 | -------------------------------------------------------------------------------- /examples/prime_number.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[inline(never)] 4 | fn is_prime_number(v: usize, prime_numbers: &[usize]) -> bool { 5 | if v < 10000 { 6 | let r = prime_numbers.binary_search(&v); 7 | return r.is_ok(); 8 | } 9 | 10 | for n in prime_numbers { 11 | if v % n == 0 { 12 | return false; 13 | } 14 | } 15 | 16 | true 17 | } 18 | 19 | #[inline(never)] 20 | fn prepare_prime_numbers() -> Vec { 21 | // bootstrap: Generate a prime table of 0..10000 22 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 23 | prime_number_table[0] = false; 24 | prime_number_table[1] = false; 25 | for i in 2..10000 { 26 | if prime_number_table[i] { 27 | let mut v = i * 2; 28 | while v < 10000 { 29 | prime_number_table[v] = false; 30 | v += i; 31 | } 32 | } 33 | } 34 | let mut prime_numbers = vec![]; 35 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 36 | if *exist { 37 | prime_numbers.push(i); 38 | } 39 | } 40 | prime_numbers 41 | } 42 | 43 | fn main() { 44 | let prime_numbers = prepare_prime_numbers(); 45 | 46 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 47 | 48 | loop { 49 | let mut v = 0; 50 | 51 | for i in 2..50000 { 52 | if is_prime_number(i, &prime_numbers) { 53 | v += 1; 54 | } 55 | } 56 | 57 | println!("Prime numbers: {}", v); 58 | 59 | if let Ok(report) = guard.report().build() { 60 | println!("{:?}", report); 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/profile_proto_with_prost.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use pprof::protos::Message; 4 | use std::fs::File; 5 | use std::io::Write; 6 | 7 | #[inline(never)] 8 | fn is_prime_number1(v: usize, prime_numbers: &[usize]) -> bool { 9 | if v < 10000 { 10 | let r = prime_numbers.binary_search(&v); 11 | return r.is_ok(); 12 | } 13 | 14 | for n in prime_numbers { 15 | if v % n == 0 { 16 | return false; 17 | } 18 | } 19 | 20 | true 21 | } 22 | 23 | #[inline(always)] 24 | fn is_prime_number2(v: usize, prime_numbers: &[usize]) -> bool { 25 | if v < 10000 { 26 | let r = prime_numbers.binary_search(&v); 27 | return r.is_ok(); 28 | } 29 | 30 | for n in prime_numbers { 31 | if v % n == 0 { 32 | return false; 33 | } 34 | } 35 | 36 | true 37 | } 38 | 39 | #[inline(never)] 40 | fn is_prime_number3(v: usize, prime_numbers: &[usize]) -> bool { 41 | if v < 10000 { 42 | let r = prime_numbers.binary_search(&v); 43 | return r.is_ok(); 44 | } 45 | 46 | for n in prime_numbers { 47 | if v % n == 0 { 48 | return false; 49 | } 50 | } 51 | 52 | true 53 | } 54 | 55 | #[inline(never)] 56 | fn prepare_prime_numbers() -> Vec { 57 | // bootstrap: Generate a prime table of 0..10000 58 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 59 | prime_number_table[0] = false; 60 | prime_number_table[1] = false; 61 | for i in 2..10000 { 62 | if prime_number_table[i] { 63 | let mut v = i * 2; 64 | while v < 10000 { 65 | prime_number_table[v] = false; 66 | v += i; 67 | } 68 | } 69 | } 70 | let mut prime_numbers = vec![]; 71 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 72 | if *exist { 73 | prime_numbers.push(i); 74 | } 75 | } 76 | prime_numbers 77 | } 78 | 79 | fn main() { 80 | let prime_numbers = prepare_prime_numbers(); 81 | 82 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 83 | 84 | let mut v = 0; 85 | 86 | for i in 2..5000000 { 87 | if i % 4 == 0 { 88 | if is_prime_number1(i, &prime_numbers) { 89 | v += 1; 90 | } 91 | } else if i % 4 == 1 { 92 | if is_prime_number2(i, &prime_numbers) { 93 | v += 1; 94 | } 95 | } else if is_prime_number3(i, &prime_numbers) { 96 | v += 1; 97 | } 98 | } 99 | 100 | println!("Prime numbers: {}", v); 101 | 102 | if let Ok(report) = guard.report().build() { 103 | let mut file = File::create("profile.pb").unwrap(); 104 | let profile = report.pprof().unwrap(); 105 | 106 | let mut content = Vec::new(); 107 | profile.encode(&mut content).unwrap(); 108 | file.write_all(&content).unwrap(); 109 | 110 | println!("report: {:?}", report); 111 | }; 112 | } 113 | -------------------------------------------------------------------------------- /examples/profile_proto_with_protobuf_codec.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use pprof::protos::Message; 4 | use std::fs::File; 5 | use std::io::Write; 6 | 7 | #[inline(never)] 8 | fn is_prime_number1(v: usize, prime_numbers: &[usize]) -> bool { 9 | if v < 10000 { 10 | let r = prime_numbers.binary_search(&v); 11 | return r.is_ok(); 12 | } 13 | 14 | for n in prime_numbers { 15 | if v % n == 0 { 16 | return false; 17 | } 18 | } 19 | 20 | true 21 | } 22 | 23 | #[inline(always)] 24 | fn is_prime_number2(v: usize, prime_numbers: &[usize]) -> bool { 25 | if v < 10000 { 26 | let r = prime_numbers.binary_search(&v); 27 | return r.is_ok(); 28 | } 29 | 30 | for n in prime_numbers { 31 | if v % n == 0 { 32 | return false; 33 | } 34 | } 35 | 36 | true 37 | } 38 | 39 | #[inline(never)] 40 | fn is_prime_number3(v: usize, prime_numbers: &[usize]) -> bool { 41 | if v < 10000 { 42 | let r = prime_numbers.binary_search(&v); 43 | return r.is_ok(); 44 | } 45 | 46 | for n in prime_numbers { 47 | if v % n == 0 { 48 | return false; 49 | } 50 | } 51 | 52 | true 53 | } 54 | 55 | #[inline(never)] 56 | fn prepare_prime_numbers() -> Vec { 57 | // bootstrap: Generate a prime table of 0..10000 58 | let mut prime_number_table: [bool; 10000] = [true; 10000]; 59 | prime_number_table[0] = false; 60 | prime_number_table[1] = false; 61 | for i in 2..10000 { 62 | if prime_number_table[i] { 63 | let mut v = i * 2; 64 | while v < 10000 { 65 | prime_number_table[v] = false; 66 | v += i; 67 | } 68 | } 69 | } 70 | let mut prime_numbers = vec![]; 71 | for (i, exist) in prime_number_table.iter().enumerate().skip(2) { 72 | if *exist { 73 | prime_numbers.push(i); 74 | } 75 | } 76 | prime_numbers 77 | } 78 | 79 | fn main() { 80 | let prime_numbers = prepare_prime_numbers(); 81 | 82 | let guard = pprof::ProfilerGuard::new(100).unwrap(); 83 | 84 | let mut v = 0; 85 | 86 | for i in 2..5000000 { 87 | if i % 4 == 0 { 88 | if is_prime_number1(i, &prime_numbers) { 89 | v += 1; 90 | } 91 | } else if i % 4 == 1 { 92 | if is_prime_number2(i, &prime_numbers) { 93 | v += 1; 94 | } 95 | } else if is_prime_number3(i, &prime_numbers) { 96 | v += 1; 97 | } 98 | } 99 | 100 | println!("Prime numbers: {}", v); 101 | 102 | if let Ok(report) = guard.report().build() { 103 | let mut file = File::create("profile.pb").unwrap(); 104 | let profile = report.pprof().unwrap(); 105 | 106 | let mut content = Vec::new(); 107 | profile.write_to_vec(&mut content).unwrap(); 108 | file.write_all(&content).unwrap(); 109 | 110 | println!("report: {:?}", report); 111 | }; 112 | } 113 | -------------------------------------------------------------------------------- /proto/perftools.profiles.rs: -------------------------------------------------------------------------------- 1 | // f9f855b960d01b292a3c2642e263e6156d52631e78e0177fe51416ed5bbecc81 proto/profile.proto 2 | 3 | #[allow(clippy::derive_partial_eq_without_eq)] 4 | #[derive(Clone, PartialEq, ::prost::Message)] 5 | pub struct Profile { 6 | /// A description of the samples associated with each Sample.value. 7 | /// For a cpu profile this might be: 8 | /// \[["cpu","nanoseconds"]\] or \[["wall","seconds"]\] or \[["syscall","count"]\] 9 | /// For a heap profile, this might be: 10 | /// \[["allocations","count"\], \["space","bytes"]\], 11 | /// If one of the values represents the number of events represented 12 | /// by the sample, by convention it should be at index 0 and use 13 | /// sample_type.unit == "count". 14 | #[prost(message, repeated, tag = "1")] 15 | pub sample_type: ::prost::alloc::vec::Vec, 16 | /// The set of samples recorded in this profile. 17 | #[prost(message, repeated, tag = "2")] 18 | pub sample: ::prost::alloc::vec::Vec, 19 | /// Mapping from address ranges to the image/binary/library mapped 20 | /// into that address range. mapping\[0\] will be the main binary. 21 | #[prost(message, repeated, tag = "3")] 22 | pub mapping: ::prost::alloc::vec::Vec, 23 | /// Useful program location 24 | #[prost(message, repeated, tag = "4")] 25 | pub location: ::prost::alloc::vec::Vec, 26 | /// Functions referenced by locations 27 | #[prost(message, repeated, tag = "5")] 28 | pub function: ::prost::alloc::vec::Vec, 29 | /// A common table for strings referenced by various messages. 30 | /// string_table\[0\] must always be "". 31 | #[prost(string, repeated, tag = "6")] 32 | pub string_table: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, 33 | /// frames with Function.function_name fully matching the following 34 | /// regexp will be dropped from the samples, along with their successors. 35 | /// 36 | /// Index into string table. 37 | #[prost(int64, tag = "7")] 38 | pub drop_frames: i64, 39 | /// frames with Function.function_name fully matching the following 40 | /// regexp will be kept, even if it matches drop_functions. 41 | /// 42 | /// Index into string table. 43 | #[prost(int64, tag = "8")] 44 | pub keep_frames: i64, 45 | /// Time of collection (UTC) represented as nanoseconds past the epoch. 46 | #[prost(int64, tag = "9")] 47 | pub time_nanos: i64, 48 | /// Duration of the profile, if a duration makes sense. 49 | #[prost(int64, tag = "10")] 50 | pub duration_nanos: i64, 51 | /// The kind of events between sampled ocurrences. 52 | /// e.g \[ "cpu","cycles" \] or \[ "heap","bytes" \] 53 | #[prost(message, optional, tag = "11")] 54 | pub period_type: ::core::option::Option, 55 | /// The number of events between sampled occurrences. 56 | #[prost(int64, tag = "12")] 57 | pub period: i64, 58 | /// Freeform text associated to the profile. 59 | /// 60 | /// Indices into string table. 61 | #[prost(int64, repeated, tag = "13")] 62 | pub comment: ::prost::alloc::vec::Vec, 63 | /// Index into the string table of the type of the preferred sample 64 | /// value. If unset, clients should default to the last sample value. 65 | #[prost(int64, tag = "14")] 66 | pub default_sample_type: i64, 67 | } 68 | /// ValueType describes the semantics and measurement units of a value. 69 | #[allow(clippy::derive_partial_eq_without_eq)] 70 | #[derive(Clone, PartialEq, ::prost::Message)] 71 | pub struct ValueType { 72 | /// Rename it from type to ty to avoid using keyword in Rust. 73 | /// 74 | /// Index into string table. 75 | #[prost(int64, tag = "1")] 76 | pub ty: i64, 77 | /// Index into string table. 78 | #[prost(int64, tag = "2")] 79 | pub unit: i64, 80 | } 81 | /// Each Sample records values encountered in some program 82 | /// context. The program context is typically a stack trace, perhaps 83 | /// augmented with auxiliary information like the thread-id, some 84 | /// indicator of a higher level request being handled etc. 85 | #[allow(clippy::derive_partial_eq_without_eq)] 86 | #[derive(Clone, PartialEq, ::prost::Message)] 87 | pub struct Sample { 88 | /// The ids recorded here correspond to a Profile.location.id. 89 | /// The leaf is at location_id\[0\]. 90 | #[prost(uint64, repeated, tag = "1")] 91 | pub location_id: ::prost::alloc::vec::Vec, 92 | /// The type and unit of each value is defined by the corresponding 93 | /// entry in Profile.sample_type. All samples must have the same 94 | /// number of values, the same as the length of Profile.sample_type. 95 | /// When aggregating multiple samples into a single sample, the 96 | /// result has a list of values that is the elemntwise sum of the 97 | /// lists of the originals. 98 | #[prost(int64, repeated, tag = "2")] 99 | pub value: ::prost::alloc::vec::Vec, 100 | /// label includes additional context for this sample. It can include 101 | /// things like a thread id, allocation size, etc 102 | #[prost(message, repeated, tag = "3")] 103 | pub label: ::prost::alloc::vec::Vec