mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
feat: replace jemalloc with mimalloc (#4174)
* feat: replace jemalloc with mimalloc * docs: record allocator rounds5 retest * fix(replication): satisfy clippy unwrap lints * docs: keep allocator migration plan local only * feat(profiling): rely on pyroscope cpu profiling * refactor(profiling): centralize unsupported pprof responses * chore(deps): update s3s revision
This commit is contained in:
Generated
+72
-480
@@ -1659,12 +1659,6 @@ version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
@@ -2172,15 +2166,6 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpp_demangle"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpubits"
|
||||
version = "0.1.1"
|
||||
@@ -3619,7 +3604,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3901,26 +3886,6 @@ dependencies = [
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
|
||||
dependencies = [
|
||||
"env_filter",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
@@ -3963,7 +3928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4901,15 +4866,6 @@ dependencies = [
|
||||
"digest 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.4.2"
|
||||
@@ -5246,46 +5202,6 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inferno"
|
||||
version = "0.11.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"indexmap 2.14.0",
|
||||
"is-terminal",
|
||||
"itoa",
|
||||
"log",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"quick-xml 0.26.0",
|
||||
"rgb",
|
||||
"str_stack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inferno"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90807d610575744524d9bdc69f3885d96f0e6c3354565b0828354a7ff2a262b8"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"clap",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-utils",
|
||||
"dashmap",
|
||||
"env_logger",
|
||||
"indexmap 2.14.0",
|
||||
"itoa",
|
||||
"log",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"quick-xml 0.39.4",
|
||||
"rgb",
|
||||
"str_stack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
@@ -5373,17 +5289,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_debug"
|
||||
version = "1.1.0"
|
||||
@@ -5429,23 +5334,6 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jemalloc_pprof"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a0d44c349cfe2654897fadcb9de4f0bfbf48288ec344f700b2bd59f152dd209"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"mappings",
|
||||
"once_cell",
|
||||
"pprof_util",
|
||||
"tempfile",
|
||||
"tikv-jemalloc-ctl",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.31"
|
||||
@@ -6022,19 +5910,6 @@ dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mappings"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bab1e61a4b76757edb59cd81fcaa7f3ba9018d43b527d9abfad877b4c6c60f2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pprof_util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.2.0"
|
||||
@@ -6088,15 +5963,6 @@ version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.11"
|
||||
@@ -6615,7 +6481,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6627,20 +6493,6 @@ dependencies = [
|
||||
"rand 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -6683,16 +6535,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
||||
|
||||
[[package]]
|
||||
name = "num-format"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
@@ -6713,17 +6555,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -6788,7 +6619,7 @@ version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"base64 0.21.7",
|
||||
"chrono",
|
||||
"getrandom 0.2.17",
|
||||
"http 1.4.2",
|
||||
@@ -6867,16 +6698,6 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.37.3"
|
||||
@@ -6886,6 +6707,17 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.39.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"memchr",
|
||||
"ruzstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object_store"
|
||||
version = "0.13.2"
|
||||
@@ -7734,48 +7566,6 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24"
|
||||
|
||||
[[package]]
|
||||
name = "pprof-pyroscope-fork"
|
||||
version = "0.1500.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "228f0967ab4c785d2daa6afdecd844a85a08227b19bfe14f1cf3f7819bf42f43"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"backtrace",
|
||||
"cfg-if",
|
||||
"findshlibs",
|
||||
"framehop",
|
||||
"inferno 0.11.21",
|
||||
"libc",
|
||||
"log",
|
||||
"memmap2 0.5.10",
|
||||
"nix 0.26.4",
|
||||
"object 0.29.0",
|
||||
"once_cell",
|
||||
"protobuf",
|
||||
"protobuf-codegen",
|
||||
"smallvec",
|
||||
"spin 0.10.0",
|
||||
"symbolic-demangle",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pprof_util"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eea0cc524de808a6d98d192a3d99fe95617031ad4a52ec0a0f987ef4432e8fe1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"flate2",
|
||||
"inferno 0.12.6",
|
||||
"num",
|
||||
"paste",
|
||||
"prost 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
@@ -7959,7 +7749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@@ -7979,7 +7769,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
"multimap",
|
||||
"petgraph 0.8.3",
|
||||
@@ -8000,7 +7790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
@@ -8013,7 +7803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
@@ -8037,57 +7827,6 @@ dependencies = [
|
||||
"prost 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "3.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"protobuf-support",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-codegen"
|
||||
version = "3.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d3976825c0014bbd2f3b34f0001876604fe87e0c86cd8fa54251530f1544ace"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"once_cell",
|
||||
"protobuf",
|
||||
"protobuf-parse",
|
||||
"regex",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-parse"
|
||||
version = "3.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap 2.14.0",
|
||||
"log",
|
||||
"protobuf",
|
||||
"protobuf-support",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-support"
|
||||
version = "3.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-protocol"
|
||||
version = "0.5.0"
|
||||
@@ -8161,19 +7900,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyroscope"
|
||||
version = "2.0.5"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01ebd83db08e07a69b4291e7043f5f2ca964c8869e0bd0b6d09b8b062de775bd"
|
||||
checksum = "b6869e0f2cae5cef10281c57d5a260f91372d7f190a7f717eb1a54f643d92151"
|
||||
dependencies = [
|
||||
"jemalloc_pprof",
|
||||
"aligned-vec",
|
||||
"backtrace",
|
||||
"findshlibs",
|
||||
"framehop",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"libflate",
|
||||
"log",
|
||||
"pprof-pyroscope-fork",
|
||||
"memmap2",
|
||||
"nix 0.26.4",
|
||||
"object 0.39.1",
|
||||
"once_cell",
|
||||
"prost 0.14.4",
|
||||
"reqwest",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"spin 0.12.1",
|
||||
"symbolic-demangle",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"url",
|
||||
"uuid",
|
||||
@@ -8206,34 +7955,6 @@ version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.39.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.40.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
@@ -8299,7 +8020,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8728,15 +8449,6 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -9076,7 +8788,6 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"insta",
|
||||
"jemalloc_pprof",
|
||||
"jiff",
|
||||
"libc",
|
||||
"libmimalloc-sys",
|
||||
@@ -9090,7 +8801,6 @@ dependencies = [
|
||||
"opentelemetry_sdk",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"pprof-pyroscope-fork",
|
||||
"proptest",
|
||||
"rand 0.10.1",
|
||||
"rcgen",
|
||||
@@ -9153,8 +8863,6 @@ dependencies = [
|
||||
"temp-env",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"tikv-jemalloc-ctl",
|
||||
"tikv-jemallocator",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
@@ -9333,7 +9041,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"md-5 0.11.0",
|
||||
"memmap2 0.9.11",
|
||||
"memmap2",
|
||||
"metrics",
|
||||
"moka",
|
||||
"num_cpus",
|
||||
@@ -9343,7 +9051,7 @@ dependencies = [
|
||||
"path-absolutize",
|
||||
"pin-project-lite",
|
||||
"proptest",
|
||||
"quick-xml 0.41.0",
|
||||
"quick-xml",
|
||||
"rand 0.10.1",
|
||||
"ratelimit",
|
||||
"rcgen",
|
||||
@@ -9524,7 +9232,7 @@ name = "rustfs-io-core"
|
||||
version = "1.0.0-beta.8"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memmap2 0.9.11",
|
||||
"memmap2",
|
||||
"rustfs-io-metrics",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
@@ -9696,7 +9404,7 @@ dependencies = [
|
||||
"hashbrown 0.17.1",
|
||||
"metrics",
|
||||
"percent-encoding",
|
||||
"quick-xml 0.41.0",
|
||||
"quick-xml",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"rustfs-config",
|
||||
@@ -9745,7 +9453,6 @@ dependencies = [
|
||||
"dial9-tokio-telemetry",
|
||||
"flate2",
|
||||
"glob",
|
||||
"jemalloc_pprof",
|
||||
"jiff",
|
||||
"metrics",
|
||||
"num_cpus",
|
||||
@@ -9835,7 +9542,7 @@ dependencies = [
|
||||
"md5",
|
||||
"percent-encoding",
|
||||
"proptest",
|
||||
"quick-xml 0.41.0",
|
||||
"quick-xml",
|
||||
"regex",
|
||||
"russh",
|
||||
"russh-sftp",
|
||||
@@ -10303,7 +10010,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10377,7 +10084,7 @@ dependencies = [
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10416,6 +10123,15 @@ dependencies = [
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruzstd"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8"
|
||||
dependencies = [
|
||||
"twox-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.23"
|
||||
@@ -10425,7 +10141,7 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||
[[package]]
|
||||
name = "s3s"
|
||||
version = "0.14.0"
|
||||
source = "git+https://github.com/rustfs/s3s?rev=300c657fb895b87e01e30b06e41a7996e57191f9#300c657fb895b87e01e30b06e41a7996e57191f9"
|
||||
source = "git+https://github.com/rustfs/s3s?rev=921e9c5911951ae9efb91dc237e11be9f2f10a14#921e9c5911951ae9efb91dc237e11be9f2f10a14"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"arrayvec",
|
||||
@@ -10452,7 +10168,7 @@ dependencies = [
|
||||
"nom 8.0.0",
|
||||
"numeric_cast",
|
||||
"pin-project-lite",
|
||||
"quick-xml 0.40.1",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
@@ -11142,15 +10858,15 @@ name = "spin"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd5231412d905519dca6a5deb0327d407be68d6c941feec004533401d3a0a715"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
@@ -11316,12 +11032,6 @@ dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "str_stack"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f446288b699d66d0fd2e30d1cfe7869194312524b3b9252594868ed26ef056a"
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.5"
|
||||
@@ -11404,23 +11114,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "symbolic-common"
|
||||
version = "12.18.3"
|
||||
version = "13.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd"
|
||||
checksum = "82bfbe03a011e4d3e2a94f03e054c33b101767f6905ec2a608dd85aa0cd71c97"
|
||||
dependencies = [
|
||||
"debugid",
|
||||
"memmap2 0.9.11",
|
||||
"memmap2",
|
||||
"stable_deref_trait",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symbolic-demangle"
|
||||
version = "12.18.3"
|
||||
version = "13.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471"
|
||||
checksum = "f9d2ed98c0fd513dd4788554e1a62d9736f3642f8aaf7923644ec647158c1ded"
|
||||
dependencies = [
|
||||
"cpp_demangle",
|
||||
"rustc-demangle",
|
||||
"symbolic-common",
|
||||
]
|
||||
@@ -11561,7 +11270,7 @@ dependencies = [
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11655,37 +11364,6 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-ctl"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "661f1f6a57b3a36dc9174a2c10f19513b4866816e13425d3e418b11cc37bc24c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"paste",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-sys"
|
||||
version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemallocator"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.53"
|
||||
@@ -12625,18 +12303,6 @@ dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "2.1.2"
|
||||
@@ -12687,7 +12353,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12814,7 +12480,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12823,16 +12489,7 @@ version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12850,31 +12507,14 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
"windows_i686_gnullvm 0.53.1",
|
||||
"windows_i686_msvc 0.53.1",
|
||||
"windows_x86_64_gnu 0.53.1",
|
||||
"windows_x86_64_gnullvm 0.53.1",
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12892,96 +12532,48 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.3"
|
||||
|
||||
+2
-14
@@ -279,7 +279,7 @@ redis = { version = "1.3.0", features = ["connection-manager", "tokio-rustls-com
|
||||
rustix = { version = "1.1.4", features = ["fs"] }
|
||||
rust-embed = { version = "8.11.0" }
|
||||
rustc-hash = { version = "2.1.2" }
|
||||
s3s = { git = "https://github.com/rustfs/s3s", rev = "300c657fb895b87e01e30b06e41a7996e57191f9", features = ["minio"] }
|
||||
s3s = { git = "https://github.com/rustfs/s3s", rev = "921e9c5911951ae9efb91dc237e11be9f2f10a14", features = ["minio"] }
|
||||
serial_test = "3.5.0"
|
||||
shadow-rs = { version = "2.0.0", default-features = false }
|
||||
siphasher = "1.0.3"
|
||||
@@ -320,7 +320,7 @@ opentelemetry-otlp = { version = "0.32.0", features = ["gzip-http", "reqwest-rus
|
||||
opentelemetry_sdk = { version = "0.32.1", features = ["rt-tokio"] }
|
||||
opentelemetry-semantic-conventions = { version = "0.32.1", features = ["semconv_experimental"] }
|
||||
opentelemetry-stdout = { version = "0.32.0" }
|
||||
pyroscope = { version = "=2.0.5", features = ["backend-pprof-rs", "backend-jemalloc"] }
|
||||
pyroscope = { version = "2.0.6", features = ["backend-pprof-rs"] }
|
||||
|
||||
# FTP and SFTP
|
||||
libunftp = { version = "0.23.0", features = ["experimental"] }
|
||||
@@ -335,20 +335,8 @@ dav-server = "0.11.0"
|
||||
|
||||
# Performance Analysis and Memory Profiling
|
||||
mimalloc = "0.1"
|
||||
# Use tikv-jemallocator as memory allocator and enable performance analysis
|
||||
tikv-jemallocator = { version = "0.6", features = ["profiling", "stats", "unprefixed_malloc_on_supported_platforms", "background_threads"] }
|
||||
# Used to control and obtain statistics for jemalloc at runtime
|
||||
tikv-jemalloc-ctl = { version = "0.6", features = ["use_std", "stats", "profiling"] }
|
||||
# Snapshot testing for output format regression detection
|
||||
insta = { version = "1.48", features = ["yaml", "json"] }
|
||||
# Used to generate pprof-compatible memory profiling data and support symbolization and flame graphs
|
||||
jemalloc_pprof = { version = "0.8.2", features = ["symbolize", "flamegraph"] }
|
||||
# Used to generate CPU performance analysis data and flame diagrams
|
||||
# pprof = { version = "0.15.0", features = ["flamegraph", "protobuf-codec"] }
|
||||
# Use pprof-pyroscope-fork to match pyroscope 2.0.5's internal pprof dependency (v0.1500.4).
|
||||
# Cargo unifies them into a single instance, avoiding duplicate perf_signal_handler symbols.
|
||||
# NOTE: Do NOT upgrade pyroscope to >=2.0.6 — it vendors pprof-rs internally, causing symbol collision.
|
||||
pprof = { package = "pprof-pyroscope-fork", version = "0.1500.4", features = ["flamegraph", "protobuf-codec"] }
|
||||
|
||||
[workspace.metadata.cargo-shear]
|
||||
ignored = ["rustfs"]
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
/// Profiler related environment variable names and default values
|
||||
pub const ENV_ENABLE_PROFILING: &str = "RUSTFS_ENABLE_PROFILING";
|
||||
|
||||
// CPU profiling
|
||||
// Legacy local CPU pprof controls. Local pprof dumps are currently unsupported;
|
||||
// Pyroscope export is configured through observability settings.
|
||||
pub const ENV_CPU_MODE: &str = "RUSTFS_PROF_CPU_MODE"; // off|continuous|periodic
|
||||
/// Frequency of CPU profiling samples
|
||||
pub const ENV_CPU_FREQ: &str = "RUSTFS_PROF_CPU_FREQ";
|
||||
@@ -24,7 +25,7 @@ pub const ENV_CPU_INTERVAL_SECS: &str = "RUSTFS_PROF_CPU_INTERVAL_SECS";
|
||||
/// Duration of each CPU profiling session (for periodic mode)
|
||||
pub const ENV_CPU_DURATION_SECS: &str = "RUSTFS_PROF_CPU_DURATION_SECS";
|
||||
|
||||
/// Memory profiling (jemalloc)
|
||||
/// Periodic memory pprof dumps (currently unsupported with mimalloc)
|
||||
pub const ENV_MEM_PERIODIC: &str = "RUSTFS_PROF_MEM_PERIODIC";
|
||||
/// Interval between memory profiling snapshots (for periodic mode)
|
||||
pub const ENV_MEM_INTERVAL_SECS: &str = "RUSTFS_PROF_MEM_INTERVAL_SECS";
|
||||
@@ -34,7 +35,7 @@ pub const ENV_OUTPUT_DIR: &str = "RUSTFS_PROF_OUTPUT_DIR";
|
||||
|
||||
/// Defaults for profiler settings
|
||||
pub const DEFAULT_ENABLE_PROFILING: bool = false;
|
||||
/// CPU profiling
|
||||
/// Legacy local CPU pprof mode
|
||||
pub const DEFAULT_CPU_MODE: &str = "off";
|
||||
/// Frequency of CPU profiling samples
|
||||
pub const DEFAULT_CPU_FREQ: usize = 100;
|
||||
@@ -42,7 +43,7 @@ pub const DEFAULT_CPU_FREQ: usize = 100;
|
||||
pub const DEFAULT_CPU_INTERVAL_SECS: u64 = 300;
|
||||
/// Duration of each CPU profiling session (for periodic mode)
|
||||
pub const DEFAULT_CPU_DURATION_SECS: u64 = 60;
|
||||
/// Memory profiling (jemalloc)
|
||||
/// Periodic memory pprof dumps (currently unsupported with mimalloc)
|
||||
pub const DEFAULT_MEM_PERIODIC: bool = false;
|
||||
/// Interval between memory profiling snapshots (for periodic mode)
|
||||
pub const DEFAULT_MEM_INTERVAL_SECS: u64 = 300;
|
||||
|
||||
@@ -782,7 +782,7 @@ mod tests {
|
||||
let contract = OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![
|
||||
profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true),
|
||||
profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true),
|
||||
profiler_backend("memory_pprof", OpsProfilerBackendStatus::Disabled, false),
|
||||
profiler_backend("ebpf", OpsProfilerBackendStatus::Unsupported, false),
|
||||
profiler_backend("future_kernel_profiler", OpsProfilerBackendStatus::Unknown, false),
|
||||
@@ -803,7 +803,7 @@ mod tests {
|
||||
fn ops_profiler_schema_serializes_stable_json_shape() {
|
||||
let contract = OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
};
|
||||
|
||||
let value = serde_json::to_value(contract).expect("ops profiler schema should serialize");
|
||||
@@ -813,7 +813,7 @@ mod tests {
|
||||
json!({
|
||||
"mode": "capability_description",
|
||||
"backends": [{
|
||||
"backend": "cpu_pprof",
|
||||
"backend": "pyroscope",
|
||||
"status": "enabled",
|
||||
"supports_profile_export": true,
|
||||
"redaction_required": ["secret", "token", "local_path", "host"],
|
||||
@@ -860,7 +860,7 @@ mod tests {
|
||||
contract: OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![
|
||||
profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true),
|
||||
profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true),
|
||||
profiler_backend("memory_pprof", OpsProfilerBackendStatus::Disabled, false),
|
||||
profiler_backend("ebpf", OpsProfilerBackendStatus::Unsupported, false),
|
||||
],
|
||||
@@ -898,7 +898,7 @@ mod tests {
|
||||
},
|
||||
contract: OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -916,7 +916,7 @@ mod tests {
|
||||
"contract": {
|
||||
"mode": "capability_description",
|
||||
"backends": [{
|
||||
"backend": "cpu_pprof",
|
||||
"backend": "pyroscope",
|
||||
"status": "enabled",
|
||||
"supports_profile_export": true,
|
||||
"redaction_required": ["secret", "token", "local_path", "host"],
|
||||
@@ -942,7 +942,7 @@ mod tests {
|
||||
},
|
||||
contract: OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -976,7 +976,7 @@ mod tests {
|
||||
fn rejects_ops_profiler_execution_requests_and_empty_backends() {
|
||||
let mut contract = OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::ExecutionRequest,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
@@ -998,7 +998,7 @@ mod tests {
|
||||
let err = serde_json::from_value::<OpsProfilerContract>(json!({
|
||||
"mode": "capability_description",
|
||||
"backends": [{
|
||||
"backend": "cpu_pprof",
|
||||
"backend": "pyroscope",
|
||||
"status": "enabled",
|
||||
"supports_profile_export": true,
|
||||
"redaction_required": ["local_path"]
|
||||
@@ -1014,7 +1014,7 @@ mod tests {
|
||||
let err = serde_json::from_value::<OpsProfilerContract>(json!({
|
||||
"mode": "capability_description",
|
||||
"backends": [{
|
||||
"backend": "cpu_pprof",
|
||||
"backend": "pyroscope",
|
||||
"status": "enabled",
|
||||
"supports_profile_export": true,
|
||||
"redaction_required": ["local_path"],
|
||||
@@ -1035,7 +1035,7 @@ mod tests {
|
||||
fn rejects_ops_profiler_invalid_backend_and_redaction_shape() {
|
||||
let mut contract = OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
};
|
||||
contract.backends[0].backend = OpsProfilerBackendName::new(" ");
|
||||
|
||||
@@ -1044,15 +1044,15 @@ mod tests {
|
||||
ExtensionContractError::EmptyOpsProfilerBackend
|
||||
);
|
||||
|
||||
contract.backends[0] = profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true);
|
||||
contract.backends[0] = profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true);
|
||||
contract
|
||||
.backends
|
||||
.push(profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Disabled, false));
|
||||
.push(profiler_backend("pyroscope", OpsProfilerBackendStatus::Disabled, false));
|
||||
|
||||
assert_eq!(
|
||||
validate_ops_profiler_contract(&contract).expect_err("duplicate backends should fail validation"),
|
||||
ExtensionContractError::DuplicateOpsProfilerBackend {
|
||||
backend: "cpu_pprof".to_string()
|
||||
backend: "pyroscope".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1062,7 +1062,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
validate_ops_profiler_contract(&contract).expect_err("duplicate redaction fields should fail validation"),
|
||||
ExtensionContractError::DuplicateOpsProfilerRedactionField {
|
||||
backend: "cpu_pprof".to_string(),
|
||||
backend: "pyroscope".to_string(),
|
||||
field: OpsProfilerRedactionField::Host
|
||||
}
|
||||
);
|
||||
@@ -1072,7 +1072,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
validate_ops_profiler_contract(&contract).expect_err("profile export requires local path redaction"),
|
||||
ExtensionContractError::OpsProfilerMissingLocalPathRedaction {
|
||||
backend: "cpu_pprof".to_string()
|
||||
backend: "pyroscope".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1081,14 +1081,14 @@ mod tests {
|
||||
fn rejects_ops_profiler_missing_provenance_boundary() {
|
||||
let mut contract = OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true)],
|
||||
backends: vec![profiler_backend("pyroscope", OpsProfilerBackendStatus::Enabled, true)],
|
||||
};
|
||||
contract.backends[0].provenance.source = " ".to_string();
|
||||
|
||||
assert_eq!(
|
||||
validate_ops_profiler_contract(&contract).expect_err("provenance source should be required"),
|
||||
ExtensionContractError::EmptyOpsProfilerProvenanceSource {
|
||||
backend: "cpu_pprof".to_string()
|
||||
backend: "pyroscope".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1098,7 +1098,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
validate_ops_profiler_contract(&contract).expect_err("collection boundary should be required"),
|
||||
ExtensionContractError::EmptyOpsProfilerCollectionBoundary {
|
||||
backend: "cpu_pprof".to_string()
|
||||
backend: "pyroscope".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ documentation = "https://docs.rs/rustfs-obs/latest/rustfs_obs/"
|
||||
[features]
|
||||
default = []
|
||||
gpu = ["dep:nvml-wrapper"]
|
||||
pyroscope = ["dep:jemalloc_pprof", "dep:pyroscope"]
|
||||
pyroscope = ["dep:pyroscope"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -83,7 +83,6 @@ nvml-wrapper = { workspace = true, optional = true }
|
||||
|
||||
[target.'cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))'.dependencies]
|
||||
pyroscope = { workspace = true, features = ["backend-pprof-rs"], optional = true }
|
||||
jemalloc_pprof = { workspace = true, optional = true }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -39,10 +39,6 @@ pub(crate) type ProfilingAgent = pyroscope::PyroscopeAgent<pyroscope::pyroscope:
|
||||
any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))
|
||||
)))]
|
||||
pub(crate) type ProfilingAgent = ();
|
||||
#[cfg(all(feature = "pyroscope", target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
pub(crate) type MemoryProfilingAgent = pyroscope::PyroscopeAgent<pyroscope::pyroscope::PyroscopeAgentRunning>;
|
||||
#[cfg(not(all(feature = "pyroscope", target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
pub(crate) type MemoryProfilingAgent = ();
|
||||
|
||||
const LOG_COMPONENT_OBS: &str = "obs";
|
||||
const LOG_SUBSYSTEM_GUARD: &str = "guard";
|
||||
@@ -67,7 +63,6 @@ pub struct OtelGuard {
|
||||
/// Optional logger provider for OTLP log export.
|
||||
pub(crate) logger_provider: Option<SdkLoggerProvider>,
|
||||
pub(crate) profiling_agent: Option<ProfilingAgent>,
|
||||
pub(crate) memory_profiling_agent: Option<MemoryProfilingAgent>,
|
||||
/// Handle to the background log-cleanup task; aborted on drop.
|
||||
pub(crate) cleanup_handle: Option<tokio::task::JoinHandle<()>>,
|
||||
/// Worker guard that keeps the non-blocking `tracing_appender` thread
|
||||
@@ -84,7 +79,6 @@ impl std::fmt::Debug for OtelGuard {
|
||||
.field("meter_provider", &self.meter_provider.is_some())
|
||||
.field("logger_provider", &self.logger_provider.is_some())
|
||||
.field("profiling_agent", &self.profiling_agent.is_some())
|
||||
.field("memory_profiling_agent", &self.memory_profiling_agent.is_some())
|
||||
.field("cleanup_handle", &self.cleanup_handle.is_some())
|
||||
.field("tracing_guard", &self.tracing_guard.is_some())
|
||||
.field("stdout_guard", &self.stdout_guard.is_some())
|
||||
@@ -161,30 +155,6 @@ impl Drop for OtelGuard {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "pyroscope", target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
if let Some(agent) = self.memory_profiling_agent.take() {
|
||||
match agent.stop() {
|
||||
Err(err) => {
|
||||
if tracing::dispatcher::has_been_set() {
|
||||
error!(
|
||||
event = EVENT_OBS_GUARD_SHUTDOWN,
|
||||
component = LOG_COMPONENT_OBS,
|
||||
subsystem = LOG_SUBSYSTEM_GUARD,
|
||||
resource = "memory_profiling_agent",
|
||||
result = "shutdown_failed",
|
||||
error = %err,
|
||||
"observability guard shutdown failed"
|
||||
);
|
||||
} else {
|
||||
eprintln!("{}", format_guard_shutdown_stderr_message("memory_profiling_agent", err));
|
||||
}
|
||||
}
|
||||
Ok(stopped) => {
|
||||
stopped.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(handle) = self.cleanup_handle.take() {
|
||||
debug!(
|
||||
event = EVENT_OBS_GUARD_SHUTDOWN,
|
||||
|
||||
@@ -271,7 +271,6 @@ fn init_stdout_only(_config: &OtelConfig, logger_level: &str, is_production: boo
|
||||
meter_provider: None,
|
||||
logger_provider: None,
|
||||
profiling_agent: None,
|
||||
memory_profiling_agent: None,
|
||||
tracing_guard: Some(guard),
|
||||
stdout_guard: None,
|
||||
cleanup_handle: None,
|
||||
@@ -389,7 +388,6 @@ fn init_file_logging_internal(
|
||||
meter_provider: None,
|
||||
logger_provider: None,
|
||||
profiling_agent: None,
|
||||
memory_profiling_agent: None,
|
||||
tracing_guard: Some(guard),
|
||||
stdout_guard,
|
||||
cleanup_handle: Some(cleanup_handle),
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::cleaner::types::FileMatchMode;
|
||||
use crate::config::OtelConfig;
|
||||
use crate::global::set_observability_metric_enabled;
|
||||
use crate::telemetry::filter::build_env_filter;
|
||||
use crate::telemetry::guard::{MemoryProfilingAgent, OtelGuard, ProfilingAgent};
|
||||
use crate::telemetry::guard::{OtelGuard, ProfilingAgent};
|
||||
use crate::telemetry::local::{build_json_log_layer, spawn_cleanup_task};
|
||||
use crate::telemetry::recorder::Recorder;
|
||||
use crate::telemetry::resource::build_resource;
|
||||
@@ -173,7 +173,6 @@ pub(super) fn init_observability_http(
|
||||
let meter_provider = build_meter_provider(&metric_ep, config, res.clone(), &service_name, use_stdout)?;
|
||||
|
||||
let profiling_agent = init_profiler(config);
|
||||
let memory_profiling_agent = init_memory_profiler(config);
|
||||
|
||||
// ── Logger Logic ──────────────────────────────────────────────────────────
|
||||
// Logging is the only signal that may intentionally route to either OTLP
|
||||
@@ -317,7 +316,6 @@ pub(super) fn init_observability_http(
|
||||
meter_provider,
|
||||
logger_provider,
|
||||
profiling_agent,
|
||||
memory_profiling_agent,
|
||||
tracing_guard,
|
||||
stdout_guard,
|
||||
cleanup_handle,
|
||||
@@ -563,65 +561,6 @@ fn init_profiler(_config: &OtelConfig) -> Option<ProfilingAgent> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Initialise a Pyroscope agent for continuous **memory** profiling via jemalloc.
|
||||
///
|
||||
/// This is only available on `linux + gnu + x86_64` where tikv-jemallocator
|
||||
/// is the global allocator and `jemalloc_pprof::PROF_CTL` is accessible.
|
||||
///
|
||||
/// Returns `None` when profiling export is disabled, the endpoint is missing,
|
||||
/// jemalloc profiling is not activated, or the agent fails to build/start.
|
||||
#[cfg(all(feature = "pyroscope", target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
fn init_memory_profiler(config: &OtelConfig) -> Option<MemoryProfilingAgent> {
|
||||
use pyroscope::backend::jemalloc_backend;
|
||||
use pyroscope::pyroscope::PyroscopeAgentBuilder;
|
||||
use rustfs_config::VERSION;
|
||||
|
||||
if !config
|
||||
.profiling_export_enabled
|
||||
.unwrap_or(rustfs_config::DEFAULT_OBS_PROFILING_EXPORT_ENABLED)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let endpoint = config.profiling_endpoint.as_ref()?.as_str();
|
||||
if endpoint.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Verify jemalloc profiling is available and activated
|
||||
{
|
||||
let prof_ctl = jemalloc_pprof::PROF_CTL.as_ref()?;
|
||||
let ctl = prof_ctl.try_lock().ok()?;
|
||||
if !ctl.activated() {
|
||||
eprintln!("Memory profiling skipped: jemalloc profiling is not activated");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let backend = jemalloc_backend();
|
||||
let service_name = config.service_name.as_deref().unwrap_or(APP_NAME);
|
||||
let version = config.service_version.as_deref().unwrap_or(VERSION);
|
||||
let sample_rate = 100;
|
||||
|
||||
let agent = PyroscopeAgentBuilder::new(endpoint, service_name, sample_rate, "pyroscope-rs", "1.0.1", backend)
|
||||
.tags(vec![("version", version), ("profile_type", "memory")])
|
||||
.build()
|
||||
.ok()?;
|
||||
|
||||
match agent.start() {
|
||||
Ok(agent) => Some(agent),
|
||||
Err(err) => {
|
||||
eprintln!("Memory profiling agent start error: {err:?}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "pyroscope", target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
fn init_memory_profiler(_config: &OtelConfig) -> Option<MemoryProfilingAgent> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Create a stdout periodic metrics reader for the given interval.
|
||||
///
|
||||
/// This helper is primarily used for local development and diagnostics when
|
||||
|
||||
@@ -123,8 +123,8 @@ pub fn builtin_ops_profiler_contract() -> OpsProfilerContract {
|
||||
OpsProfilerContract {
|
||||
mode: OpsProfilerContractMode::CapabilityDescription,
|
||||
backends: vec![
|
||||
builtin_ops_profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Enabled, true),
|
||||
builtin_ops_profiler_backend("memory_pprof", OpsProfilerBackendStatus::Disabled, true),
|
||||
builtin_ops_profiler_backend("cpu_pprof", OpsProfilerBackendStatus::Unsupported, false),
|
||||
builtin_ops_profiler_backend("memory_pprof", OpsProfilerBackendStatus::Unsupported, false),
|
||||
builtin_ops_profiler_backend("ebpf", OpsProfilerBackendStatus::Unsupported, false),
|
||||
],
|
||||
}
|
||||
@@ -391,8 +391,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
backends,
|
||||
vec![
|
||||
("cpu_pprof", OpsProfilerBackendStatus::Enabled, true),
|
||||
("memory_pprof", OpsProfilerBackendStatus::Disabled, true),
|
||||
("cpu_pprof", OpsProfilerBackendStatus::Unsupported, false),
|
||||
("memory_pprof", OpsProfilerBackendStatus::Unsupported, false),
|
||||
("ebpf", OpsProfilerBackendStatus::Unsupported, false),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -172,13 +172,13 @@ mod tests {
|
||||
assert_eq!(registry.registered_backend_count(), contract.backends.len());
|
||||
assert_eq!(
|
||||
registry.registration_for("cpu_pprof").map(|registration| registration.status),
|
||||
Some(OpsProfilerBackendStatus::Enabled)
|
||||
Some(OpsProfilerBackendStatus::Unsupported)
|
||||
);
|
||||
assert_eq!(
|
||||
registry
|
||||
.registration_for("memory_pprof")
|
||||
.map(|registration| registration.supports_profile_export),
|
||||
Some(true)
|
||||
Some(false)
|
||||
);
|
||||
assert_eq!(
|
||||
registry.authorize_read(OpsProfilerReadRequest {
|
||||
|
||||
+2
-11
@@ -186,25 +186,16 @@ opentelemetry = { workspace = true }
|
||||
tracing-opentelemetry = { workspace = true }
|
||||
# Data structures
|
||||
hashbrown = { workspace = true }
|
||||
mimalloc = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libsystemd.workspace = true
|
||||
# io-uring is Linux-only. Scope the feature to Linux targets.
|
||||
tokio = { workspace = true, features = ["io-uring"] }
|
||||
|
||||
[target.'cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))'.dependencies]
|
||||
mimalloc = { workspace = true }
|
||||
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
||||
libmimalloc-sys = { version = "0.1.49", features = ["extended"] }
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
pprof = { workspace = true }
|
||||
|
||||
# jemalloc-based allocator and memory profiling are only enabled on validated linux-gnu-x86_64 targets.
|
||||
[target.'cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))'.dependencies]
|
||||
tikv-jemallocator = { workspace = true }
|
||||
tikv-jemalloc-ctl = { workspace = true }
|
||||
jemalloc_pprof = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
uuid = { workspace = true, features = ["v4"] }
|
||||
serial_test = { workspace = true }
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
use crate::admin::{auth::validate_admin_request, router::Operation};
|
||||
use crate::auth::{check_key_valid, get_session_token};
|
||||
use crate::server::RemoteAddr;
|
||||
#[cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
use http::HeaderMap;
|
||||
use http::StatusCode;
|
||||
#[cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
use http::header::CONTENT_TYPE;
|
||||
use matchit::Params;
|
||||
use rustfs_policy::policy::action::{Action, AdminAction};
|
||||
use s3s::{Body, S3Request, S3Response, S3Result, s3_error};
|
||||
@@ -45,6 +41,10 @@ pub(super) async fn authorize_profile_request(req: &S3Request<Body>) -> S3Result
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) fn profile_not_implemented_response(message: String) -> S3Response<(StatusCode, Body)> {
|
||||
S3Response::new((StatusCode::NOT_IMPLEMENTED, Body::from(message)))
|
||||
}
|
||||
|
||||
pub struct TriggerProfileCPU {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for TriggerProfileCPU {
|
||||
@@ -52,30 +52,8 @@ impl Operation for TriggerProfileCPU {
|
||||
authorize_profile_request(&req).await?;
|
||||
info!("Triggering CPU profile dump via S3 request...");
|
||||
|
||||
#[cfg(not(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))))]
|
||||
{
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
Body::from(
|
||||
crate::profiling::dump_cpu_pprof_for(std::time::Duration::from_secs(0))
|
||||
.await
|
||||
.unwrap_err(),
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
{
|
||||
let dur = std::time::Duration::from_secs(60);
|
||||
match crate::profiling::dump_cpu_pprof_for(dur).await {
|
||||
Ok(path) => {
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "text/html".parse().expect("operation should succeed"));
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(path.display().to_string())), header))
|
||||
}
|
||||
Err(e) => Err(s3s::s3_error!(InternalError, "{}", format!("Failed to dump CPU profile: {e}"))),
|
||||
}
|
||||
}
|
||||
crate::profiling::log_cpu_pprof_dump_skipped();
|
||||
Ok(profile_not_implemented_response(crate::profiling::local_cpu_pprof_unsupported_message()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,25 +64,8 @@ impl Operation for TriggerProfileMemory {
|
||||
authorize_profile_request(&req).await?;
|
||||
info!("Triggering Memory profile dump via S3 request...");
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
{
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
Body::from(crate::profiling::dump_memory_pprof_now().await.unwrap_err()),
|
||||
)));
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
{
|
||||
match crate::profiling::dump_memory_pprof_now().await {
|
||||
Ok(path) => {
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "text/html".parse().expect("operation should succeed"));
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(path.display().to_string())), header))
|
||||
}
|
||||
Err(e) => Err(s3s::s3_error!(InternalError, "{}", format!("Failed to dump Memory profile: {e}"))),
|
||||
}
|
||||
}
|
||||
crate::profiling::log_memory_pprof_dump_skipped();
|
||||
Ok(profile_not_implemented_response(crate::profiling::memory_pprof_unsupported_message()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,28 +12,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::profile::authorize_profile_request;
|
||||
use super::profile::{authorize_profile_request, profile_not_implemented_response};
|
||||
use crate::admin::router::{AdminOperation, Operation, S3Router};
|
||||
use crate::server::ADMIN_PREFIX;
|
||||
use http::{HeaderMap, HeaderValue, Uri};
|
||||
use http::{HeaderMap, HeaderValue};
|
||||
use hyper::{Method, StatusCode};
|
||||
use matchit::Params;
|
||||
use s3s::header::CONTENT_TYPE;
|
||||
use s3s::{Body, S3Request, S3Response, S3Result};
|
||||
use std::collections::HashMap;
|
||||
use serde::Serialize;
|
||||
use tracing::error;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn extract_query_params(uri: &Uri) -> HashMap<String, String> {
|
||||
let mut params = HashMap::new();
|
||||
|
||||
if let Some(query) = uri.query() {
|
||||
for (key, value) in url::form_urlencoded::parse(query.as_bytes()) {
|
||||
params.insert(key.into_owned(), value.into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
params
|
||||
#[derive(Serialize)]
|
||||
struct ProfileStatus {
|
||||
enabled: &'static str,
|
||||
status: &'static str,
|
||||
platform: &'static str,
|
||||
message: &'static str,
|
||||
}
|
||||
|
||||
pub fn register_profiling_route(r: &mut S3Router<AdminOperation>) -> std::io::Result<()> {
|
||||
@@ -54,114 +49,17 @@ pub fn register_profiling_route(r: &mut S3Router<AdminOperation>) -> std::io::Re
|
||||
|
||||
pub struct ProfileHandler {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn map_cpu_profile_collect_error_message(err: &str) -> (StatusCode, String) {
|
||||
if err.contains("start running cpu profiler error") {
|
||||
return (
|
||||
StatusCode::CONFLICT,
|
||||
"CPU profiler is already running. Disable RUSTFS_OBS_PROFILING_EXPORT_ENABLED or retry later.".to_string(),
|
||||
);
|
||||
}
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to collect CPU profile: {err}"))
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for ProfileHandler {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
authorize_profile_request(&req).await?;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))))]
|
||||
{
|
||||
let requested_url = req.uri.to_string();
|
||||
let target_os = std::env::consts::OS;
|
||||
let target_arch = std::env::consts::ARCH;
|
||||
let target_env = option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown");
|
||||
let msg = format!(
|
||||
"CPU profiling is not supported on this platform. target_os={target_os}, target_env={target_env}, target_arch={target_arch}, requested_url={requested_url}"
|
||||
);
|
||||
return Ok(S3Response::new((StatusCode::NOT_IMPLEMENTED, Body::from(msg))));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
{
|
||||
use rustfs_config::{DEFAULT_CPU_FREQ, ENV_CPU_FREQ};
|
||||
use rustfs_utils::get_env_usize;
|
||||
|
||||
let queries = extract_query_params(&req.uri);
|
||||
let seconds = queries.get("seconds").and_then(|s| s.parse::<u64>().ok()).unwrap_or(30);
|
||||
let format = queries.get("format").cloned().unwrap_or_else(|| "protobuf".to_string());
|
||||
|
||||
if seconds > 300 {
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::BAD_REQUEST,
|
||||
Body::from("Profile duration cannot exceed 300 seconds".to_string()),
|
||||
)));
|
||||
}
|
||||
|
||||
match format.as_str() {
|
||||
"protobuf" | "pb" => match crate::profiling::dump_cpu_pprof_for(std::time::Duration::from_secs(seconds)).await {
|
||||
Ok(path) => match tokio::fs::read(&path).await {
|
||||
Ok(bytes) => {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"));
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(bytes)), headers))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to read profile file {}: {}", path.display(), e);
|
||||
Ok(S3Response::new((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Body::from(format!("Failed to read profile file: {e}")),
|
||||
)))
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let (status, message) = map_cpu_profile_collect_error_message(&e);
|
||||
error!("CPU protobuf profile collection failed: {}", e);
|
||||
Ok(S3Response::new((status, Body::from(message))))
|
||||
}
|
||||
},
|
||||
"flamegraph" | "svg" => {
|
||||
let freq = get_env_usize(ENV_CPU_FREQ, DEFAULT_CPU_FREQ) as i32;
|
||||
let guard = match pprof::ProfilerGuard::new(freq) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Body::from(format!("Failed to create profiler: {e}")),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_secs(seconds)).await;
|
||||
|
||||
let report = match guard.report().build() {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Body::from(format!("Failed to build profile report: {e}")),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
let mut flamegraph_buf = Vec::new();
|
||||
if let Err(e) = report.flamegraph(&mut flamegraph_buf) {
|
||||
return Ok(S3Response::new((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Body::from(format!("Failed to generate flamegraph: {e}")),
|
||||
)));
|
||||
}
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(CONTENT_TYPE, HeaderValue::from_static("image/svg+xml"));
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(flamegraph_buf)), headers))
|
||||
}
|
||||
_ => Ok(S3Response::new((
|
||||
StatusCode::BAD_REQUEST,
|
||||
Body::from("Unsupported format. Use 'protobuf' or 'flamegraph'".to_string()),
|
||||
))),
|
||||
}
|
||||
}
|
||||
let requested_url = req.uri.to_string();
|
||||
crate::profiling::log_cpu_pprof_dump_skipped();
|
||||
Ok(profile_not_implemented_response(format!(
|
||||
"{}; requested_url={requested_url}",
|
||||
crate::profiling::local_cpu_pprof_unsupported_message()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,37 +70,11 @@ impl Operation for ProfileStatusHandler {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
authorize_profile_request(&req).await?;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))))]
|
||||
let message = format!("CPU profiling is not supported on {} platform", std::env::consts::OS);
|
||||
#[cfg(not(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))))]
|
||||
let status = HashMap::from([
|
||||
("enabled", "false"),
|
||||
("status", "not_supported"),
|
||||
("platform", std::env::consts::OS),
|
||||
("message", message.as_str()),
|
||||
]);
|
||||
|
||||
#[cfg(any(target_os = "macos", all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
let status = {
|
||||
use rustfs_config::{DEFAULT_ENABLE_PROFILING, ENV_ENABLE_PROFILING};
|
||||
use rustfs_utils::get_env_bool;
|
||||
|
||||
let enabled = get_env_bool(ENV_ENABLE_PROFILING, DEFAULT_ENABLE_PROFILING);
|
||||
if enabled {
|
||||
HashMap::from([
|
||||
("enabled", "true"),
|
||||
("status", "running"),
|
||||
("supported_formats", "protobuf, flamegraph"),
|
||||
("max_duration_seconds", "300"),
|
||||
("endpoint", "/rustfs/admin/debug/pprof/profile"),
|
||||
])
|
||||
} else {
|
||||
HashMap::from([
|
||||
("enabled", "false"),
|
||||
("status", "disabled"),
|
||||
("message", "Set RUSTFS_ENABLE_PROFILING=true to enable profiling"),
|
||||
])
|
||||
}
|
||||
let status = ProfileStatus {
|
||||
enabled: "false",
|
||||
status: "not_supported",
|
||||
platform: std::env::consts::OS,
|
||||
message: crate::profiling::LOCAL_CPU_PPROF_UNSUPPORTED_SUMMARY,
|
||||
};
|
||||
|
||||
match serde_json::to_string(&status) {
|
||||
@@ -224,11 +96,10 @@ impl Operation for ProfileStatusHandler {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{ProfileHandler, ProfileStatusHandler, extract_query_params};
|
||||
use super::{ProfileHandler, ProfileStatusHandler};
|
||||
use crate::admin::router::Operation;
|
||||
use http::{Extensions, HeaderMap, Uri};
|
||||
use hyper::Method;
|
||||
use hyper::StatusCode;
|
||||
use matchit::Params;
|
||||
use s3s::{Body, S3ErrorCode, S3Request};
|
||||
|
||||
@@ -246,17 +117,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_query_params_decodes_percent_encoded_values() {
|
||||
let uri: Uri = "/rustfs/admin/debug/pprof/profile?format=flamegraph¬e=a%2Bb+value"
|
||||
.parse()
|
||||
.expect("uri should parse");
|
||||
let params = extract_query_params(&uri);
|
||||
|
||||
assert_eq!(params.get("format"), Some(&"flamegraph".to_string()));
|
||||
assert_eq!(params.get("note"), Some(&"a+b value".to_string()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn profile_handler_rejects_missing_credentials() {
|
||||
let result = ProfileHandler {}
|
||||
@@ -284,12 +144,4 @@ mod tests {
|
||||
assert_eq!(err.code(), &S3ErrorCode::AccessDenied);
|
||||
assert_eq!(err.message(), Some("Signature is required"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cpu_profile_collect_error_maps_profiler_conflict_to_409() {
|
||||
let (status, message) =
|
||||
super::map_cpu_profile_collect_error_message("create profiler failed: start running cpu profiler error");
|
||||
assert_eq!(status, StatusCode::CONFLICT);
|
||||
assert!(message.contains("CPU profiler is already running"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,15 +111,7 @@ impl AllocatorReclaimController {
|
||||
}
|
||||
|
||||
pub fn allocator_backend() -> &'static str {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
{
|
||||
"jemalloc"
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
not(target_os = "windows"),
|
||||
not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))
|
||||
))]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
"mimalloc"
|
||||
}
|
||||
@@ -206,7 +198,7 @@ fn configured_allocator_reclaim_interval_secs() -> u64 {
|
||||
}
|
||||
|
||||
fn effective_allocator_reclaim_force(backend: &str, configured_force: bool) -> bool {
|
||||
configured_force && backend != "jemalloc"
|
||||
configured_force && backend != "mimalloc-windows"
|
||||
}
|
||||
|
||||
fn build_allocator_reclaim_desired_snapshot(
|
||||
@@ -302,10 +294,7 @@ pub fn allocator_reclaim_controller_snapshot(ctx: &CancellationToken) -> Allocat
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
not(target_os = "windows"),
|
||||
not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))
|
||||
))]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[allow(unsafe_code)]
|
||||
fn collect_allocator_memory(force: bool) -> Result<(), String> {
|
||||
// SAFETY: `mi_collect` is provided by the active global allocator backend
|
||||
@@ -317,13 +306,6 @@ fn collect_allocator_memory(force: bool) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
fn collect_allocator_memory(_force: bool) -> Result<(), String> {
|
||||
let _ = tikv_jemalloc_ctl::background_thread::write(true);
|
||||
tikv_jemalloc_ctl::epoch::advance().map_err(|err| err.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn collect_allocator_memory(_force: bool) -> Result<(), String> {
|
||||
Err("allocator reclaim is not supported on Windows".to_string())
|
||||
@@ -368,13 +350,6 @@ pub fn init_allocator_reclaim(ctx: CancellationToken) {
|
||||
}
|
||||
|
||||
let configured_force = configured_allocator_reclaim_force();
|
||||
if backend == "jemalloc" && configured_force {
|
||||
warn!(
|
||||
backend,
|
||||
env = rustfs_config::ENV_ALLOCATOR_RECLAIM_FORCE,
|
||||
"allocator reclaim force mode is not supported on jemalloc backend; ignoring configured force flag"
|
||||
);
|
||||
}
|
||||
let force = effective_allocator_reclaim_force(backend, configured_force);
|
||||
let idle_intervals = configured_allocator_reclaim_idle_intervals();
|
||||
let interval = Duration::from_secs(configured_allocator_reclaim_interval_secs());
|
||||
@@ -473,8 +448,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocator_reclaim_force_preserves_jemalloc_override() {
|
||||
assert!(!effective_allocator_reclaim_force("jemalloc", true));
|
||||
fn allocator_reclaim_force_is_disabled_only_on_windows_backend() {
|
||||
assert!(!effective_allocator_reclaim_force("mimalloc-windows", true));
|
||||
assert!(effective_allocator_reclaim_force("mimalloc", true));
|
||||
assert!(!effective_allocator_reclaim_force("mimalloc", false));
|
||||
}
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
|
||||
+73
-638
@@ -12,647 +12,82 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
mod unsupported_impl {
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info};
|
||||
|
||||
const LOG_COMPONENT_PROFILING: &str = "profiling";
|
||||
const LOG_SUBSYSTEM_PLATFORM: &str = "platform";
|
||||
const LOG_COMPONENT_PROFILING: &str = "profiling";
|
||||
const LOG_SUBSYSTEM_CPU: &str = "cpu";
|
||||
const LOG_SUBSYSTEM_MEMORY: &str = "memory";
|
||||
const LOG_SUBSYSTEM_RUNTIME: &str = "runtime";
|
||||
const LOCAL_CPU_PPROF_UNSUPPORTED_REASON: &str = "local_cpu_pprof_unsupported";
|
||||
const MEMORY_PPROF_UNSUPPORTED_REASON: &str = "mimalloc_memory_pprof_unsupported";
|
||||
pub const LOCAL_CPU_PPROF_UNSUPPORTED_SUMMARY: &str = "local CPU pprof dumps are not supported; use Pyroscope export instead";
|
||||
pub const MEMORY_PPROF_UNSUPPORTED_SUMMARY: &str = "memory pprof dumps are not supported with the mimalloc allocator";
|
||||
|
||||
pub async fn init_from_env() {
|
||||
let target_env = option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown");
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_PLATFORM,
|
||||
event = "profiling_runtime_skipped",
|
||||
reason = "unsupported_platform",
|
||||
target_os = std::env::consts::OS,
|
||||
target_env,
|
||||
target_arch = std::env::consts::ARCH,
|
||||
"Profiling runtime skipped"
|
||||
);
|
||||
}
|
||||
|
||||
/// Stop all background profiling tasks
|
||||
pub fn shutdown_profiling() {
|
||||
let target_env = option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown");
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_PLATFORM,
|
||||
event = "profiling_shutdown_skipped",
|
||||
reason = "unsupported_platform",
|
||||
target_os = std::env::consts::OS,
|
||||
target_env,
|
||||
target_arch = std::env::consts::ARCH,
|
||||
"Profiling shutdown skipped"
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn dump_cpu_pprof_for(_duration: Duration) -> Result<PathBuf, String> {
|
||||
Err(unsupported_message("CPU profiling"))
|
||||
}
|
||||
|
||||
pub async fn dump_memory_pprof_now() -> Result<PathBuf, String> {
|
||||
Err(unsupported_message("Memory profiling"))
|
||||
}
|
||||
|
||||
fn unsupported_message(feature: &str) -> String {
|
||||
let target_env = option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown");
|
||||
format!(
|
||||
"{feature} is only supported on linux x86_64 gnu. target_os={}, target_env={target_env}, target_arch={}",
|
||||
std::env::consts::OS,
|
||||
std::env::consts::ARCH
|
||||
)
|
||||
}
|
||||
pub async fn init_from_env() {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_RUNTIME,
|
||||
event = "profiling_runtime_skipped",
|
||||
reason = LOCAL_CPU_PPROF_UNSUPPORTED_REASON,
|
||||
target_os = std::env::consts::OS,
|
||||
target_env = target_env(),
|
||||
target_arch = std::env::consts::ARCH,
|
||||
"Local pprof profiling runtime skipped"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
pub use unsupported_impl::{dump_cpu_pprof_for, dump_memory_pprof_now, init_from_env, shutdown_profiling};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod linux_impl {
|
||||
use pprof::protos::Message;
|
||||
use rustfs_config::{
|
||||
DEFAULT_CPU_DURATION_SECS, DEFAULT_CPU_FREQ, DEFAULT_CPU_INTERVAL_SECS, DEFAULT_CPU_MODE, DEFAULT_ENABLE_PROFILING,
|
||||
DEFAULT_MEM_INTERVAL_SECS, DEFAULT_MEM_PERIODIC, DEFAULT_OUTPUT_DIR, ENV_CPU_DURATION_SECS, ENV_CPU_FREQ,
|
||||
ENV_CPU_INTERVAL_SECS, ENV_CPU_MODE, ENV_ENABLE_PROFILING, ENV_MEM_INTERVAL_SECS, ENV_MEM_PERIODIC, ENV_OUTPUT_DIR,
|
||||
};
|
||||
use rustfs_utils::{get_env_bool, get_env_str, get_env_u64, get_env_usize};
|
||||
use std::fs::{File, create_dir_all};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::sleep;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
const LOG_COMPONENT_PROFILING: &str = "profiling";
|
||||
const LOG_SUBSYSTEM_CPU: &str = "cpu";
|
||||
const LOG_SUBSYSTEM_MEMORY: &str = "memory";
|
||||
const LOG_SUBSYSTEM_JEMALLOC: &str = "jemalloc";
|
||||
const LOG_SUBSYSTEM_RUNTIME: &str = "runtime";
|
||||
|
||||
static CPU_CONT_GUARD: OnceLock<Arc<Mutex<Option<pprof::ProfilerGuard<'static>>>>> = OnceLock::new();
|
||||
static PROFILING_CANCEL_TOKEN: OnceLock<CancellationToken> = OnceLock::new();
|
||||
|
||||
/// CPU profiling mode
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum CpuMode {
|
||||
Off,
|
||||
Continuous,
|
||||
Periodic,
|
||||
}
|
||||
|
||||
/// Get or create output directory
|
||||
fn output_dir() -> PathBuf {
|
||||
let dir = get_env_str(ENV_OUTPUT_DIR, DEFAULT_OUTPUT_DIR);
|
||||
let p = PathBuf::from(dir);
|
||||
if let Err(e) = create_dir_all(&p) {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_RUNTIME,
|
||||
event = "profiling_output_dir_fallback",
|
||||
path = %p.display(),
|
||||
error = %e,
|
||||
fallback = ".",
|
||||
"Profiling output directory fallback applied"
|
||||
);
|
||||
return PathBuf::from(".");
|
||||
}
|
||||
p
|
||||
}
|
||||
|
||||
/// Read CPU profiling mode from env
|
||||
fn read_cpu_mode() -> CpuMode {
|
||||
match get_env_str(ENV_CPU_MODE, DEFAULT_CPU_MODE).to_lowercase().as_str() {
|
||||
"continuous" => CpuMode::Continuous,
|
||||
"periodic" => CpuMode::Periodic,
|
||||
_ => CpuMode::Off,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate timestamp string for filenames
|
||||
fn ts() -> String {
|
||||
jiff::Zoned::now().strftime("%Y%m%dT%H%M%S").to_string()
|
||||
}
|
||||
|
||||
/// Write pprof report to file in protobuf format
|
||||
fn write_pprof_report_pb(report: &pprof::Report, path: &Path) -> Result<(), String> {
|
||||
let profile = report.pprof().map_err(|e| format!("pprof() failed: {e}"))?;
|
||||
let mut buf = Vec::with_capacity(512 * 1024);
|
||||
profile.write_to_vec(&mut buf).map_err(|e| format!("encode failed: {e}"))?;
|
||||
let mut f = File::create(path).map_err(|e| format!("create file failed: {e}"))?;
|
||||
f.write_all(&buf).map_err(|e| format!("write file failed: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Internal: dump CPU pprof from existing guard
|
||||
async fn dump_cpu_with_guard(guard: &pprof::ProfilerGuard<'_>) -> Result<PathBuf, String> {
|
||||
let report = guard.report().build().map_err(|e| format!("build report failed: {e}"))?;
|
||||
let out = output_dir().join(format!("cpu_profile_{}.pb", ts()));
|
||||
write_pprof_report_pb(&report, &out)?;
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_dump_exported",
|
||||
profile_type = "cpu",
|
||||
path = %out.display(),
|
||||
"Profiling dump exported"
|
||||
);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
// Public API: dump CPU for a duration; if continuous guard exists, snapshot immediately.
|
||||
pub async fn dump_cpu_pprof_for(duration: Duration) -> Result<PathBuf, String> {
|
||||
if let Some(cell) = CPU_CONT_GUARD.get() {
|
||||
let guard_slot = cell.lock().await;
|
||||
if let Some(ref guard) = *guard_slot {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_dump_source",
|
||||
profile_type = "cpu",
|
||||
source = "continuous_guard",
|
||||
"Using continuous CPU profiling guard for dump"
|
||||
);
|
||||
return dump_cpu_with_guard(guard).await;
|
||||
}
|
||||
}
|
||||
|
||||
let freq = get_env_usize(ENV_CPU_FREQ, DEFAULT_CPU_FREQ) as i32;
|
||||
let guard = pprof::ProfilerGuard::new(freq).map_err(|e| format!("create profiler failed: {e}"))?;
|
||||
sleep(duration).await;
|
||||
|
||||
dump_cpu_with_guard(&guard).await
|
||||
}
|
||||
|
||||
// Public API: dump memory pprof now (jemalloc)
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
pub async fn dump_memory_pprof_now() -> Result<PathBuf, String> {
|
||||
let out = output_dir().join(format!("mem_profile_{}.pb", ts()));
|
||||
let mut f = File::create(&out).map_err(|e| format!("create file failed: {e}"))?;
|
||||
|
||||
let prof_ctl_cell = jemalloc_pprof::PROF_CTL
|
||||
.as_ref()
|
||||
.ok_or_else(|| "jemalloc profiling control not available".to_string())?;
|
||||
let mut prof_ctl = prof_ctl_cell.lock().await;
|
||||
|
||||
if !prof_ctl.activated() {
|
||||
return Err("jemalloc profiling is not active".to_string());
|
||||
}
|
||||
|
||||
let bytes = prof_ctl.dump_pprof().map_err(|e| format!("dump pprof failed: {e}"))?;
|
||||
f.write_all(&bytes).map_err(|e| format!("write file failed: {e}"))?;
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_exported",
|
||||
profile_type = "memory",
|
||||
path = %out.display(),
|
||||
"Profiling dump exported"
|
||||
);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
pub async fn dump_memory_pprof_now() -> Result<PathBuf, String> {
|
||||
Err(memory_profiling_unsupported_message())
|
||||
}
|
||||
|
||||
// Jemalloc status check (No forced placement, only status observation)
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
pub async fn check_jemalloc_profiling() {
|
||||
use tikv_jemalloc_ctl::{config, epoch, stats};
|
||||
|
||||
if let Err(e) = epoch::advance() {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_epoch_advance_failed",
|
||||
error = %e,
|
||||
"Jemalloc profiling state changed"
|
||||
);
|
||||
}
|
||||
|
||||
match config::malloc_conf::read() {
|
||||
Ok(conf) => debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_malloc_conf",
|
||||
result = "ok",
|
||||
malloc_conf = %conf,
|
||||
"Jemalloc profiling state checked"
|
||||
),
|
||||
Err(e) => debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_malloc_conf",
|
||||
result = "read_failed",
|
||||
error = %e,
|
||||
"Jemalloc profiling state checked"
|
||||
),
|
||||
}
|
||||
|
||||
match std::env::var("MALLOC_CONF") {
|
||||
Ok(v) => debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_malloc_conf_env",
|
||||
state = "set",
|
||||
malloc_conf = %v,
|
||||
"Jemalloc profiling state checked"
|
||||
),
|
||||
Err(_) => debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_malloc_conf_env",
|
||||
state = "unset",
|
||||
"Jemalloc profiling state checked"
|
||||
),
|
||||
}
|
||||
|
||||
if let Some(lock) = jemalloc_pprof::PROF_CTL.as_ref() {
|
||||
let ctl = lock.lock().await;
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_profiling_status",
|
||||
activated = ctl.activated(),
|
||||
"Jemalloc profiling status checked"
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_profiling_status",
|
||||
state = "unavailable",
|
||||
"Jemalloc profiling status checked"
|
||||
);
|
||||
}
|
||||
|
||||
let _ = epoch::advance();
|
||||
macro_rules! show {
|
||||
($name:literal, $reader:expr) => {
|
||||
match $reader {
|
||||
Ok(v) => debug!(concat!($name, "={}"), v),
|
||||
Err(e) => debug!(concat!($name, " read failed: {}"), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
show!("allocated", stats::allocated::read());
|
||||
show!("resident", stats::resident::read());
|
||||
show!("mapped", stats::mapped::read());
|
||||
show!("metadata", stats::metadata::read());
|
||||
show!("active", stats::active::read());
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
pub async fn check_jemalloc_profiling() {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_JEMALLOC,
|
||||
event = "jemalloc_profiling_status",
|
||||
result = "skipped",
|
||||
reason = "unsupported_target",
|
||||
"Jemalloc profiling status checked"
|
||||
);
|
||||
}
|
||||
|
||||
// Internal: start continuous CPU profiling
|
||||
async fn start_cpu_continuous(freq_hz: i32) {
|
||||
let cell = CPU_CONT_GUARD.get_or_init(|| Arc::new(Mutex::new(None))).clone();
|
||||
let mut slot = cell.lock().await;
|
||||
if slot.is_some() {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_continuous",
|
||||
state = "already_running",
|
||||
"CPU profiling already running"
|
||||
);
|
||||
return;
|
||||
}
|
||||
match pprof::ProfilerGuardBuilder::default()
|
||||
.frequency(freq_hz)
|
||||
.blocklist(&["libc", "libgcc", "pthread", "vdso"])
|
||||
.build()
|
||||
{
|
||||
Ok(guard) => {
|
||||
*slot = Some(guard);
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_continuous",
|
||||
state = "started",
|
||||
freq_hz,
|
||||
"CPU profiling started"
|
||||
);
|
||||
}
|
||||
Err(e) => warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_continuous",
|
||||
state = "start_failed",
|
||||
error = %e,
|
||||
"CPU profiling failed to start"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Internal: start periodic CPU sampling loop
|
||||
async fn start_cpu_periodic(freq_hz: i32, interval: Duration, duration: Duration, token: CancellationToken) {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_periodic",
|
||||
state = "started",
|
||||
freq_hz,
|
||||
?interval,
|
||||
?duration,
|
||||
"Periodic CPU profiling started"
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = token.cancelled() => {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_periodic",
|
||||
state = "cancelled",
|
||||
"Periodic CPU profiling cancelled"
|
||||
);
|
||||
break;
|
||||
}
|
||||
_ = sleep(interval) => {}
|
||||
}
|
||||
|
||||
if token.is_cancelled() {
|
||||
break;
|
||||
}
|
||||
|
||||
let guard = match pprof::ProfilerGuard::new(freq_hz) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_capture_failed",
|
||||
profile_type = "cpu_periodic",
|
||||
stage = "create_guard",
|
||||
error = %e,
|
||||
"Profiling capture failed"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
tokio::select! {
|
||||
_ = token.cancelled() => {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_state",
|
||||
profile_type = "cpu_periodic",
|
||||
state = "cancelled_during_capture",
|
||||
"Periodic CPU profiling cancelled during capture"
|
||||
);
|
||||
break;
|
||||
}
|
||||
_ = sleep(duration) => {}
|
||||
}
|
||||
|
||||
match guard.report().build() {
|
||||
Ok(report) => {
|
||||
let out = output_dir().join(format!("cpu_profile_{}.pb", ts()));
|
||||
if let Err(e) = write_pprof_report_pb(&report, &out) {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_dump_failed",
|
||||
profile_type = "cpu_periodic",
|
||||
stage = "write_dump",
|
||||
path = %out.display(),
|
||||
error = %e,
|
||||
"Periodic CPU dump write failed"
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_dump_exported",
|
||||
profile_type = "cpu_periodic",
|
||||
path = %out.display(),
|
||||
"Profiling dump exported"
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => warn!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_capture_failed",
|
||||
profile_type = "cpu_periodic",
|
||||
stage = "build_report",
|
||||
error = %e,
|
||||
"Profiling capture failed"
|
||||
),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Internal: start periodic memory dump when jemalloc profiling is active
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))]
|
||||
async fn start_memory_periodic(interval: Duration, token: CancellationToken) {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_state",
|
||||
profile_type = "memory_periodic",
|
||||
state = "started",
|
||||
?interval,
|
||||
"Periodic memory profiling started"
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = token.cancelled() => {
|
||||
info!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_state",
|
||||
profile_type = "memory_periodic",
|
||||
state = "cancelled",
|
||||
"Periodic memory profiling cancelled"
|
||||
);
|
||||
break;
|
||||
}
|
||||
_ = sleep(interval) => {}
|
||||
}
|
||||
|
||||
let Some(lock) = jemalloc_pprof::PROF_CTL.as_ref() else {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_skipped",
|
||||
profile_type = "memory_periodic",
|
||||
reason = "prof_ctl_unavailable",
|
||||
"Profiling dump skipped"
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut ctl = lock.lock().await;
|
||||
if !ctl.activated() {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_skipped",
|
||||
profile_type = "memory_periodic",
|
||||
reason = "jemalloc_inactive",
|
||||
"Profiling dump skipped"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let out = output_dir().join(format!("mem_profile_periodic_{}.pb", ts()));
|
||||
match File::create(&out) {
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_failed",
|
||||
profile_type = "memory_periodic",
|
||||
stage = "create_file",
|
||||
path = %out.display(),
|
||||
error = %e,
|
||||
"Periodic memory dump file creation failed"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Ok(mut f) => match ctl.dump_pprof() {
|
||||
Ok(bytes) => {
|
||||
if let Err(e) = f.write_all(&bytes) {
|
||||
tracing::error!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_failed",
|
||||
profile_type = "memory_periodic",
|
||||
stage = "write_dump",
|
||||
path = %out.display(),
|
||||
error = %e,
|
||||
"Periodic memory dump write failed"
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_exported",
|
||||
profile_type = "memory_periodic",
|
||||
path = %out.display(),
|
||||
"Profiling dump exported"
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => tracing::error!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_failed",
|
||||
profile_type = "memory_periodic",
|
||||
stage = "dump_pprof",
|
||||
error = %e,
|
||||
"Periodic memory dump export failed"
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
async fn start_memory_periodic(_interval: Duration, _token: CancellationToken) {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_runtime_skipped",
|
||||
profile_type = "memory_periodic",
|
||||
reason = "unsupported_target",
|
||||
"Profiling runtime skipped"
|
||||
);
|
||||
}
|
||||
|
||||
// Public: unified init entry, avoid duplication/conflict
|
||||
pub async fn init_from_env() {
|
||||
let enabled = get_env_bool(ENV_ENABLE_PROFILING, DEFAULT_ENABLE_PROFILING);
|
||||
if !enabled {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_RUNTIME,
|
||||
event = "profiling_runtime_disabled",
|
||||
reason = "env_flag",
|
||||
"Profiling runtime disabled"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Jemalloc state check once (no dump)
|
||||
check_jemalloc_profiling().await;
|
||||
|
||||
// Initialize cancellation token
|
||||
let token = PROFILING_CANCEL_TOKEN.get_or_init(CancellationToken::new).clone();
|
||||
|
||||
// CPU
|
||||
let cpu_mode = read_cpu_mode();
|
||||
let cpu_freq = get_env_usize(ENV_CPU_FREQ, DEFAULT_CPU_FREQ) as i32;
|
||||
let cpu_interval = Duration::from_secs(get_env_u64(ENV_CPU_INTERVAL_SECS, DEFAULT_CPU_INTERVAL_SECS));
|
||||
let cpu_duration = Duration::from_secs(get_env_u64(ENV_CPU_DURATION_SECS, DEFAULT_CPU_DURATION_SECS));
|
||||
|
||||
match cpu_mode {
|
||||
CpuMode::Off => debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_mode_selected",
|
||||
profile_type = "cpu",
|
||||
state = "off",
|
||||
"Profiling mode selected"
|
||||
),
|
||||
CpuMode::Continuous => start_cpu_continuous(cpu_freq).await,
|
||||
CpuMode::Periodic => start_cpu_periodic(cpu_freq, cpu_interval, cpu_duration, token.clone()).await,
|
||||
}
|
||||
|
||||
// Memory
|
||||
let mem_periodic = get_env_bool(ENV_MEM_PERIODIC, DEFAULT_MEM_PERIODIC);
|
||||
let mem_interval = Duration::from_secs(get_env_u64(ENV_MEM_INTERVAL_SECS, DEFAULT_MEM_INTERVAL_SECS));
|
||||
if mem_periodic {
|
||||
start_memory_periodic(mem_interval, token).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))]
|
||||
fn memory_profiling_unsupported_message() -> String {
|
||||
let target_env = option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown");
|
||||
format!(
|
||||
"Memory profiling is only supported on linux x86_64 gnu. target_os={}, target_env={target_env}, target_arch={}",
|
||||
std::env::consts::OS,
|
||||
std::env::consts::ARCH
|
||||
)
|
||||
}
|
||||
|
||||
/// Stop all background profiling tasks
|
||||
pub fn shutdown_profiling() {
|
||||
if let Some(token) = PROFILING_CANCEL_TOKEN.get() {
|
||||
token.cancel();
|
||||
}
|
||||
}
|
||||
pub fn shutdown_profiling() {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_RUNTIME,
|
||||
event = "profiling_shutdown_skipped",
|
||||
reason = LOCAL_CPU_PPROF_UNSUPPORTED_REASON,
|
||||
target_os = std::env::consts::OS,
|
||||
target_env = target_env(),
|
||||
target_arch = std::env::consts::ARCH,
|
||||
"Local pprof profiling shutdown skipped"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub use linux_impl::{dump_cpu_pprof_for, dump_memory_pprof_now, init_from_env, shutdown_profiling};
|
||||
pub fn log_cpu_pprof_dump_skipped() {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_CPU,
|
||||
event = "profiling_dump_skipped",
|
||||
profile_type = "cpu",
|
||||
reason = LOCAL_CPU_PPROF_UNSUPPORTED_REASON,
|
||||
"Local CPU pprof dump skipped"
|
||||
);
|
||||
}
|
||||
|
||||
pub fn log_memory_pprof_dump_skipped() {
|
||||
debug!(
|
||||
component = LOG_COMPONENT_PROFILING,
|
||||
subsystem = LOG_SUBSYSTEM_MEMORY,
|
||||
event = "profiling_dump_skipped",
|
||||
profile_type = "memory",
|
||||
reason = MEMORY_PPROF_UNSUPPORTED_REASON,
|
||||
"Memory pprof dump skipped"
|
||||
);
|
||||
}
|
||||
|
||||
pub fn local_cpu_pprof_unsupported_message() -> String {
|
||||
unsupported_message(LOCAL_CPU_PPROF_UNSUPPORTED_SUMMARY)
|
||||
}
|
||||
|
||||
pub fn memory_pprof_unsupported_message() -> String {
|
||||
unsupported_message(MEMORY_PPROF_UNSUPPORTED_SUMMARY)
|
||||
}
|
||||
|
||||
fn unsupported_message(summary: &str) -> String {
|
||||
format!(
|
||||
"{summary}. target_os={}, target_env={}, target_arch={}",
|
||||
std::env::consts::OS,
|
||||
target_env(),
|
||||
std::env::consts::ARCH
|
||||
)
|
||||
}
|
||||
|
||||
fn target_env() -> &'static str {
|
||||
option_env!("CARGO_CFG_TARGET_ENV").unwrap_or("unknown")
|
||||
}
|
||||
|
||||
@@ -143,11 +143,7 @@ fn target_env_name() -> Option<&'static str> {
|
||||
}
|
||||
|
||||
fn cpu_profiling_status() -> CapabilityStatus {
|
||||
if cfg!(any(target_os = "linux", target_os = "macos")) {
|
||||
CapabilityStatus::supported()
|
||||
} else {
|
||||
CapabilityStatus::unsupported().with_reason("userspace CPU profiling supports linux and macos targets")
|
||||
}
|
||||
CapabilityStatus::unsupported().with_reason(crate::profiling::LOCAL_CPU_PPROF_UNSUPPORTED_SUMMARY)
|
||||
}
|
||||
|
||||
fn ebpf_status() -> CapabilityStatus {
|
||||
@@ -167,11 +163,7 @@ fn numa_status() -> CapabilityStatus {
|
||||
}
|
||||
|
||||
fn memory_profiling_status() -> CapabilityStatus {
|
||||
if cfg!(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")) {
|
||||
CapabilityStatus::supported().with_reason("jemalloc memory profiling target")
|
||||
} else {
|
||||
CapabilityStatus::unsupported().with_reason("memory profiling supports linux gnu x86_64 targets")
|
||||
}
|
||||
CapabilityStatus::unsupported().with_reason(crate::profiling::MEMORY_PPROF_UNSUPPORTED_SUMMARY)
|
||||
}
|
||||
|
||||
fn cgroup_memory_status() -> CapabilityStatus {
|
||||
|
||||
Reference in New Issue
Block a user