diff --git a/Cargo.lock b/Cargo.lock index 7e078c7231c..293c1528307 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,15 @@ dependencies = [ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "callgrind" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "valgrind_request 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo_metadata" version = "0.6.3" @@ -275,6 +284,15 @@ dependencies = [ "tipb 0.0.1 (git+https://github.com/pingcap/tipb.git)", ] +[[package]] +name = "cpuprofiler" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crc" version = "1.8.1" @@ -294,7 +312,7 @@ dependencies = [ "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -329,7 +347,7 @@ dependencies = [ "crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -381,7 +399,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -395,7 +413,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -408,7 +426,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -435,7 +453,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -514,6 +532,14 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error-chain" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "error-chain" version = "0.12.0" @@ -631,7 +657,7 @@ dependencies = [ "cargo_metadata 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -766,7 +792,7 @@ version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -951,7 +977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1342,6 +1368,17 @@ dependencies = [ "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "profiler" +version = "0.0.1" +dependencies = [ + "callgrind 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tikv_alloc 0.1.0", + "valgrind_request 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "prometheus" version = "0.4.2" @@ -1363,7 +1400,7 @@ name = "prometheus-static-metric" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1523,7 +1560,7 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1553,7 +1590,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1601,7 +1638,7 @@ name = "rand_xorshift" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1629,7 +1666,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1838,7 +1875,7 @@ version = "0.1.0" source = "git+https://github.com/breeswish/slog-global.git?rev=91904ade#91904adec6e602df234e30560e98ef281d81eb84" dependencies = [ "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2116,7 +2153,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2159,6 +2196,7 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.0.1", "procinfo 0.4.2 (git+https://github.com/tikv/procinfo-rs)", + "profiler 0.0.1", "prometheus 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "prometheus-static-metric 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2382,7 +2420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2588,6 +2626,11 @@ dependencies = [ "serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "valgrind_request" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vcpkg" version = "0.2.2" @@ -2724,6 +2767,7 @@ dependencies = [ "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum bzip2-sys 0.1.7 (git+https://github.com/alexcrichton/bzip2-rs.git)" = "" +"checksum callgrind 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f7f788eaf239475a3c1e1acf89951255a46c4b9b46cf3e866fc4d0707b4b9e36" "checksum cargo_metadata 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "48e8d5fd5b81d86d3ec3c820ecf5a3027fa22d6aede2be981cf07a8ce16451bb" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" @@ -2734,6 +2778,7 @@ dependencies = [ "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626" +"checksum cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "33f07976bb6821459632d7a18d97ccca005cb5c552f251f822c7c1781c1d7035" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" @@ -2755,6 +2800,7 @@ dependencies = [ "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b90e520ec62c1864c8c78d637acbfe8baf5f63240f2fb8165b8325c07812dd" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143" "checksum fail 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd2e1a22c616c8c8c96b6e07c243014551f3ba77291d24c22e0bfea6830c0b4e" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" @@ -2797,7 +2843,7 @@ dependencies = [ "checksum kvproto 0.0.1 (git+https://github.com/pingcap/kvproto.git)" = "" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" "checksum libfuzzer-sys 0.1.0 (git+https://github.com/rust-fuzz/libfuzzer-sys.git)" = "" @@ -2962,6 +3008,7 @@ dependencies = [ "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum utime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4a9c0ddf7a5a39cd0c316dac124303d71fa197f8607027546c3be3e1c6f7bd9b" "checksum uuid 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8630752f979f1b6b87c49830a5e3784082545de63920d59fbaac252474319447" +"checksum valgrind_request 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0fb139b14473e1350e34439c888e44c805f37b4293d17f87ea920a66a20a99a" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" diff --git a/Cargo.toml b/Cargo.toml index bfe9aa486de..9d8fb60d84c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ jemalloc = ["tikv_alloc/jemalloc"] portable = ["engine/portable"] sse = ["engine/sse"] mem-profiling = ["tikv_alloc/mem-profiling"] +profiling = ["profiler/profiling"] no-fail = ["fail/no_fail"] [lib] @@ -115,6 +116,7 @@ hyper = { version = "0.12", default-features = false, features = ["runtime"] } tokio-threadpool = "0.1.13" vlog = "0.1.4" twoway = "0.2.0" +profiler = { path = "components/profiler" } cop_datatype = { path = "components/cop_datatype" } panic_hook = { path = "components/panic_hook" } tipb = { git = "https://github.com/pingcap/tipb.git" } diff --git a/components/profiler/Cargo.toml b/components/profiler/Cargo.toml new file mode 100644 index 00000000000..4b1f9e9b07d --- /dev/null +++ b/components/profiler/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "profiler" +version = "0.0.1" +edition = "2018" +publish = false + +[features] +profiling = ["lazy_static", "cpuprofiler", "callgrind", "valgrind_request"] + +[dependencies] +tikv_alloc = { path = "../tikv_alloc" } + +[target.'cfg(unix)'.dependencies] +lazy_static = { version = "1.3.0", optional = true } +cpuprofiler = { version = "0.0.3", optional = true } +callgrind = { version = "1.1.0", optional = true } +valgrind_request = { version = "1.1.0", optional = true } + +[[example]] +name = "prime" +required-features = ["profiling"] diff --git a/components/profiler/examples/prime.rs b/components/profiler/examples/prime.rs new file mode 100644 index 00000000000..558c30ebe6d --- /dev/null +++ b/components/profiler/examples/prime.rs @@ -0,0 +1,84 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +//! Profiling sample: Calculate prime numbers. +//! +//! ## Usage +//! +//! ### Build +//! +//! ```bash +//! cargo build --features "profiling" --example prime +//! ``` +//! +//! (You may also want `--release` in real scenarios). +//! +//! ### Run using CPU Profiler +//! +//! ```bash +//! ../../target/debug/examples/prime +//! ``` +//! +//! ### Run using Callgrind +//! +//! ```bash +//! valgrind --tool=callgrind --instr-atstart=no ../../target/debug/examples/prime +//! ``` +//! +//! You must not run example via `valgrind cargo run ...`. The framework won't detect Callgrind! + +#[inline(never)] +fn is_prime_number(v: usize, prime_numbers: &[usize]) -> bool { + if v < 10000 { + let r = prime_numbers.binary_search(&v); + return r.is_ok(); + } + + for n in prime_numbers { + if v % n == 0 { + return false; + } + } + + true +} + +#[inline(never)] +fn prepare_prime_numbers() -> Vec { + // bootstrap: Generate a prime table of 0..10000 + let mut prime_number_table: [bool; 10000] = [true; 10000]; + prime_number_table[0] = false; + prime_number_table[1] = false; + for i in 2..10000 { + if prime_number_table[i] { + let mut v = i * 2; + while v < 10000 { + prime_number_table[v] = false; + v += i; + } + } + } + let mut prime_numbers = vec![]; + for i in 2..10000 { + if prime_number_table[i] { + prime_numbers.push(i); + } + } + prime_numbers +} + +fn main() { + let prime_numbers = prepare_prime_numbers(); + + profiler::start("prime.profile"); + + let mut v = 0; + for i in 2..50000 { + if is_prime_number(i, &prime_numbers) { + v += 1; + } + } + + profiler::stop(); + + println!("Prime numbers: {}", v); +} diff --git a/components/profiler/src/lib.rs b/components/profiler/src/lib.rs new file mode 100644 index 00000000000..cd54fe45575 --- /dev/null +++ b/components/profiler/src/lib.rs @@ -0,0 +1,58 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +//! Profile a part of the code using CPU Profiler from gperftools or Callgrind. +//! Supports Linux and MacOS. +//! +//! ## Requirements +//! +//! 1. gperftools +//! +//! Linux: +//! +//! You can follow its [INSTALL manual](https://github.com/gperftools/gperftools/blob/master/INSTALL). +//! Roughly the instructions are the following: +//! +//! 1. Download packages from [release](https://github.com/gperftools/gperftools/releases) +//! 2. Run `./configure` +//! 3. Run `make install` +//! +//! MacOS: +//! +//! Simply `brew install gperftools`. +//! +//! ## Usage +//! +//! ```ignore +//! profiler::start("./app.profile"); +//! some_complex_code(); +//! profiler::stop(); +//! ``` +//! +//! Then, compile the code with `profiling` feature enabled. +//! +//! By default, a profile called `app.profile` will be generated by CPU Profiler. +//! You can then analyze the profile using [pprof](https://github.com/google/pprof). +//! +//! If the application is running in Callgrind, a Callgrind profile dump will be generated instead. +//! Notice that you should run Callgrind with command line option `--instr-atstart=no`, e.g.: +//! +//! ```bash +//! valgrind --tool=callgrind --instr-atstart=no ./my_example +//! ``` +//! +//! Also see `examples/prime.rs`. + +#[allow(unused_extern_crates)] +extern crate tikv_alloc; + +#[cfg(all(unix, feature = "profiling"))] +mod profiler_unix; + +#[cfg(all(unix, feature = "profiling"))] +pub use profiler_unix::*; + +#[cfg(not(all(unix, feature = "profiling")))] +mod profiler_dummy; + +#[cfg(not(all(unix, feature = "profiling")))] +pub use profiler_dummy::*; diff --git a/components/profiler/src/profiler_dummy.rs b/components/profiler/src/profiler_dummy.rs new file mode 100644 index 00000000000..deeb27ecab4 --- /dev/null +++ b/components/profiler/src/profiler_dummy.rs @@ -0,0 +1,15 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +/// Start profiling. Always returns false if `profiling` feature is not enabled. +#[inline] +pub fn start(_name: impl AsRef) -> bool { + // Do nothing + false +} + +/// Stop profiling. Always returns false if `profiling` feature is not enabled. +#[inline] +pub fn stop() -> bool { + // Do nothing + false +} diff --git a/components/profiler/src/profiler_unix.rs b/components/profiler/src/profiler_unix.rs new file mode 100644 index 00000000000..7b236369dbe --- /dev/null +++ b/components/profiler/src/profiler_unix.rs @@ -0,0 +1,72 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +use std::sync::Mutex; + +use callgrind::CallgrindClientRequest; + +#[derive(Debug, PartialEq)] +enum Profiler { + None, + GPerfTools, + CallGrind, +} + +lazy_static::lazy_static! { + #[derive(Debug)] + static ref ACTIVE_PROFILER: Mutex = Mutex::new(Profiler::None); +} + +/// Start profiling. Returns false if failed, i.e. there is already a profiling in progress. +/// +/// When `profiling` feature is not enabled, this function will do nothing and there is totally +/// zero cost. +/// +/// When running in Callgrind, Callgrind instrumentation will be started +/// (`CALLGRIND_START_INSTRUMENTATION`). Otherwise, the CPU Profiler will be started and profile +/// will be generated to the file specified by `name`. +// TODO: Better multi-thread support. +#[inline] +pub fn start(name: impl AsRef) -> bool { + let mut profiler = ACTIVE_PROFILER.lock().unwrap(); + + // Profiling in progress. + if *profiler != Profiler::None { + return false; + } + + if valgrind_request::running_on_valgrind() != 0 { + *profiler = Profiler::CallGrind; + CallgrindClientRequest::start(); + } else { + *profiler = Profiler::GPerfTools; + cpuprofiler::PROFILER + .lock() + .unwrap() + .start(name.as_ref()) + .unwrap(); + } + + true +} + +/// Stop profiling. Returns false if failed, i.e. there is no profiling in progress. +/// +/// When `profiling` feature is not enabled, this function will do nothing and there is totally +/// zero cost. +#[inline] +pub fn stop() -> bool { + let mut profiler = ACTIVE_PROFILER.lock().unwrap(); + match *profiler { + Profiler::None => false, + Profiler::CallGrind => { + CallgrindClientRequest::stop(None); + *profiler = Profiler::None; + true + } + Profiler::GPerfTools => { + cpuprofiler::PROFILER.lock().unwrap().stop().unwrap(); + *profiler = Profiler::None; + true + } + } +}