diff --git a/docs/parca-agent-language-support.md b/docs/parca-agent-language-support.md index 9137a1a..dc70843 100644 --- a/docs/parca-agent-language-support.md +++ b/docs/parca-agent-language-support.md @@ -11,6 +11,7 @@ All AOT compiled languages with [debug info](./symbolization#what-can-be-symboli - [C++](https://github.com/parca-dev/parca-demo/tree/main/cpp) - [Go](https://github.com/parca-dev/parca-demo/tree/main/go) (with [extended support](./symbolization#go)) - [Rust](https://github.com/parca-dev/parca-demo/tree/main/rust) +- [Rust heap usage](/docs/rust-jemalloc-support) - And more ## Just-in-time (JIT) compilation diff --git a/docs/rust-jemalloc-support.md b/docs/rust-jemalloc-support.md new file mode 100644 index 0000000..71b2adc --- /dev/null +++ b/docs/rust-jemalloc-support.md @@ -0,0 +1,106 @@ +# Profiling Rust Memory Usage with Jemalloc + +Our jemalloc integration makes it possible to profile heap usage of +Rust programs, as long as you are willing to use the jemalloc +allocator. + +# Setup Instructions + +## Using jemalloc and rust-jemalloc-pprof + +Add the +[jemalloc_pprof](https://crates.io/crates/jemalloc-pprof) +and [tikv-jemallocator](https://crates.io/crates/tikv-jemallocator) +packages to your project. Make sure the latter has the `profiling` and +`unprefixed_malloc_on_supported_platforms` features: + +``` bash +cargo add jemalloc_pprof +cargo add tikv-jemallocator --features profiling,unprefixed_malloc_on_supported_platforms +``` + +Then, in your program's `main.rs` set your global allocator to +jemalloc and configure it with the special `malloc_conf` symbol: + +``` rust +#[global_allocator] +static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +#[unsafe(export_name = "malloc_conf")] +#[allow(non_upper_case_globals)] +pub static malloc_conf: &[u8] = b"prof:true,prof_active:true,lg_prof_sample:19\0"; +``` + +## Exposing pprof profiles with http: + +Call the `dump_pprof` method to dump profiles to memory. We +recommending exposing an HTTP interface for these profiles that can be +scraped by Parca. + +Here is how to do so using Axum: + +``` rust +async fn handle_get_heap() -> Result { + let mut prof_ctl = jemalloc_pprof::PROF_CTL + .as_ref() + .ok_or(( + StatusCode::INTERNAL_SERVER_ERROR, + "Profiling not available".to_string(), + ))? + .lock() + .await; + + let pprof = prof_ctl + .dump_pprof() + .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?; + + Ok(pprof) +} + +fn main() { + let app = Router::new().route("/debug/pprof/heap", get(handle_get_heap)); + + let rt = Runtime::new().unwrap(); + + rt.spawn(async { + let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") + .await + .expect("Failed to bind to port 3000"); + axum::serve(listener, app).await.expect("Server failed"); + }); +} + +``` + +## Uploading symbols with `parca-debuginfo` (only if not using +`parca-agent`). + +If you are already using `parca-agent`, all relevant symbols will be +found and uploaded to the backend automatically. Otherwise, you will +need to manually upload them using the `parca-debuginfo` CLI. For example, +assuming Parca is running on localhost: + +``` bash +parca-debuginfo upload --store-address=localhost:7070 --insecure path/to/your/binary +``` + +## Scraping with Parca + +In order to continually scrape the endpoint, add a stanza like the +following to your `parca.yaml`, assuming (as in the example above) the +profiles are being served via HTTP on `127.0.0.1:3000`: + +``` yaml +scrape_configs: + - job_name: "rjemp" + scrape_interval: "10s" + static_configs: + - targets: [ '127.0.0.1:3000' ] + profiling_config: + pprof_config: + heap: + enabled: true + path: /debug/pprof/heap +``` + +This should cause profiles to appear in the Parca UI. diff --git a/sidebars.js b/sidebars.js index be7cafd..03341cd 100644 --- a/sidebars.js +++ b/sidebars.js @@ -84,7 +84,7 @@ module.exports = { type: "category", label: "Language Support", link: { type: "doc", id: "parca-agent-language-support" }, - items: ["java-support"], + items: ["java-support", "rust-jemalloc-support"], }, "parca-agent-security", ], diff --git a/wordlist.txt b/wordlist.txt index 9fad5cd..2e9d55d 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -5,6 +5,8 @@ addr agentpath ainur Akkoyun +ALLOC +allocator amd Andrii annotationpresent @@ -54,6 +56,7 @@ CodeQL CodeReady colima Colima +conf config ConfigPath configs @@ -69,6 +72,8 @@ cpu cpuflamegraphs CRI cri +ctl +CTL datacenter Datasource datasource @@ -120,6 +125,7 @@ filesystem flamegraph FlameGraphs flamegraphs +fn frontend FrostDB fs @@ -129,6 +135,7 @@ ghrc github githubusercontent GitLab +globals googlegroups goroutine Goroutines @@ -157,6 +164,9 @@ ip iterateLong iterateShort Jaeger +Jemalloc +jemalloc +jemallocator JIT jit jitdump @@ -201,6 +211,7 @@ lxc mainc MAINPID maintainership +malloc Manoj matcher matchers @@ -213,6 +224,7 @@ Metastore metastore minikube msg +mut Mutex mutex mynode @@ -235,6 +247,7 @@ oidc OpenShift openshift OpenTelemetry +ok otlp parallelizing params @@ -320,6 +333,7 @@ stacktrace stacktraces StandardError StandardOutput +StatusCode stmt strp submodule @@ -342,6 +356,7 @@ TBD testdata Thakkar Thanos +tikv TLS tls tmp