Skip to content

Commit afff9b4

Browse files
committed
feat: support heap profiling
Support the generation of pprof profiles of heap usage by using jemalloc facilities. Signed-off-by: Flavio Castelli <fcastelli@suse.com>
1 parent 8034501 commit afff9b4

File tree

7 files changed

+185
-11
lines changed

7 files changed

+185
-11
lines changed

Cargo.lock

+81-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ axum = { version = "0.7.5", features = ["macros", "query"] }
4848
axum-server = { version = "0.6", features = ["tls-rustls"] }
4949
tower-http = { version = "0.5.2", features = ["trace"] }
5050
tikv-jemallocator = { version = "0.5.4", features = [
51+
"profiling",
5152
"unprefixed_malloc_on_supported_platforms",
5253
] }
54+
jemalloc_pprof = "0.1.0"
5355

5456
[dev-dependencies]
5557
mockall = "0.12"

PROFILING.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Profiling
2+
3+
Ensure the `policy-server` is running with the `--enable-pprof` flag. This can also be set with the `KUBEWARDEN_ENABLE_PPROF=1` environment variable.
4+
5+
## CPU
6+
7+
1. Port-forward policy-server port (8443):
8+
9+
```sh
10+
kubectl port-forward -n kubewarden service/policy-server-default 8443:8443
11+
```
12+
13+
1. Download the CPU profile using `curl`:
14+
15+
```sh
16+
curl --insecure https://localhost:8443/debug/pprof/cpu -o cpu_profile.prof
17+
```
18+
19+
1. Use [`pprof`](https://github.com/google/pprof) to analyze the profile:
20+
21+
```sh
22+
pprof -http=:8080 cpu_profile.prof
23+
```
24+
25+
## Memory
26+
27+
1. Port-forward policy-server port (8443):
28+
29+
```sh
30+
kubectl port-forward -n kubewarden service/policy-server-default 8443:8443
31+
```
32+
33+
1. Download the CPU profile using `curl`:
34+
35+
```sh
36+
curl --insecure https://localhost:8443/debug/pprof/heap -o heap_profile.prof
37+
```
38+
39+
1. Use [`pprof`](https://github.com/google/pprof) to analyze the profile:
40+
41+
```sh
42+
pprof -http=:8080 heap_profile.prof
43+
```
44+
45+
**Warning:** do not use the `pprof` tool from the `go tool` binary, it cannot handle the memory profile generated by Policy Server.

src/api/handlers.rs

+44
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,50 @@ pub(crate) async fn readiness_handler() -> StatusCode {
221221
StatusCode::OK
222222
}
223223

224+
// Generate a pprof heap profile using google's pprof format
225+
// The report is generated and sent to the user as binary data
226+
pub(crate) async fn pprof_get_heap(
227+
) -> Result<impl axum::response::IntoResponse, (StatusCode, ApiError)> {
228+
let mut prof_ctl = jemalloc_pprof::PROF_CTL
229+
.as_ref()
230+
.ok_or(handle_pprof_error(
231+
ReportGenerationError::HeapProfilingNotEnabled,
232+
))?
233+
.lock()
234+
.await;
235+
require_profiling_activated(&prof_ctl).map_err(handle_pprof_error)?;
236+
let pprof = prof_ctl
237+
.dump_pprof()
238+
.map_err(|e| handle_pprof_error(ReportGenerationError::JemallocError(e.to_string())))?;
239+
240+
let mut headers = header::HeaderMap::new();
241+
headers.insert(
242+
header::CONTENT_DISPOSITION,
243+
r#"attachment; filename="heap_profile"#.parse().unwrap(),
244+
);
245+
headers.insert(
246+
header::CONTENT_LENGTH,
247+
pprof.len().to_string().parse().unwrap(),
248+
);
249+
headers.insert(
250+
header::CONTENT_TYPE,
251+
mime::APPLICATION_OCTET_STREAM.to_string().parse().unwrap(),
252+
);
253+
254+
Ok((headers, pprof))
255+
}
256+
257+
/// Checks whether jemalloc profiling is activated an returns an error response if not.
258+
fn require_profiling_activated(
259+
prof_ctl: &jemalloc_pprof::JemallocProfCtl,
260+
) -> Result<(), ReportGenerationError> {
261+
if prof_ctl.activated() {
262+
Ok(())
263+
} else {
264+
Err(ReportGenerationError::HeapProfilingNotEnabled)
265+
}
266+
}
267+
224268
async fn acquire_semaphore_and_evaluate(
225269
state: Arc<ApiServerState>,
226270
policy_id: String,

src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use tokio::{
3838
use tower_http::trace::{self, TraceLayer};
3939

4040
use crate::api::handlers::{
41-
audit_handler, pprof_get_cpu, readiness_handler, validate_handler, validate_raw_handler,
41+
audit_handler, pprof_get_cpu, pprof_get_heap, readiness_handler, validate_handler,
42+
validate_raw_handler,
4243
};
4344
use crate::api::state::ApiServerState;
4445
use crate::evaluation::{
@@ -211,7 +212,9 @@ impl PolicyServer {
211212
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
212213
);
213214
if config.enable_pprof {
214-
let pprof_router = Router::new().route("/debug/pprof/cpu", get(pprof_get_cpu));
215+
let pprof_router = Router::new()
216+
.route("/debug/pprof/cpu", get(pprof_get_cpu))
217+
.route("/debug/pprof/heap", get(pprof_get_heap));
215218
router = Router::new().merge(router).merge(pprof_router);
216219
}
217220

src/main.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ static GLOBAL: Jemalloc = Jemalloc;
1717

1818
#[allow(non_upper_case_globals)]
1919
#[export_name = "malloc_conf"]
20-
pub static malloc_conf: &[u8] = b"background_thread:true,tcache_max:4096,dirty_decay_ms:5000,muzzy_decay_ms:5000,abort_conf:true\0";
20+
/// Prioritize memory usage, then enable features request by pprof
21+
pub static malloc_conf: &[u8] = b"background_thread:true,tcache_max:4096,dirty_decay_ms:5000,muzzy_decay_ms:5000,abort_conf:true,prof:true,prof_active:true,lg_prof_sample:19\0";
2122

2223
#[tokio::main]
2324
async fn main() -> Result<()> {

src/profiling.rs

+6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ pub enum ReportGenerationError {
2929

3030
#[error("cannot encode report to pprof format: {0}")]
3131
EncodeError(String),
32+
33+
#[error("failed to dump the profile: {0}")]
34+
JemallocError(String),
35+
36+
#[error("heap profiling is not activated")]
37+
HeapProfilingNotEnabled,
3238
}
3339

3440
/// Default frequency of sampling. 99Hz to avoid coincide with special periods

0 commit comments

Comments
 (0)