Skip to content

Commit b235140

Browse files
committed
automate the generation of the memory flamegraph
Signed-off-by: William Johnson <[email protected]>
1 parent 7866065 commit b235140

File tree

5 files changed

+121
-81
lines changed

5 files changed

+121
-81
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
6+
pull_request:
7+
types: [opened, reopened, edited, synchronize]
8+
9+
defaults:
10+
run:
11+
shell: bash -eux {0}
12+
13+
jobs:
14+
generate_memory_flamegraph:
15+
name: Create flamegraph for scrape_flamegraph
16+
permissions:
17+
checks: write
18+
pull-requests: write
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: actions/checkout@v4
24+
with:
25+
repository: rust-lang/rustc-demangle
26+
path: rustc-demangle
27+
28+
- uses: actions/checkout@v4
29+
with:
30+
repository: KDE/heaptrack
31+
path: heaptrack
32+
33+
- uses: actions/checkout@v4
34+
with:
35+
repository: brendangregg/FlameGraph
36+
path: FlameGraph
37+
38+
- name: Install Rust
39+
uses: actions-rust-lang/setup-rust-toolchain@v1
40+
with:
41+
rustflags: ""
42+
43+
- name: Install dependencies
44+
run: |
45+
sudo apt-get update
46+
sudo apt-get install -y \
47+
build-essential libssl-dev pkg-config curl git \
48+
cmake g++ libboost-dev libboost-iostreams-dev \
49+
libboost-program-options-dev libdw-dev libelf-dev \
50+
elfutils libunwind-dev zlib1g-dev binutils-dev \
51+
libiberty-dev libdebuginfod-dev libboost-system-dev \
52+
libboost-filesystem-dev libboost-thread-dev libboost-regex-dev
53+
cargo install rustfilt
54+
55+
- name: Build and install librustc_demangle.so
56+
run: |
57+
cd rustc-demangle
58+
cargo build -p rustc-demangle-capi --release
59+
sudo mv target/release/librustc_demangle.so /usr/lib
60+
61+
- name: Build and install heaptrack
62+
run: |
63+
cd heaptrack
64+
mkdir build && cd build
65+
66+
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr/local -DHEAPTRACK_USE_LIBUNWIND=ON -DHEAPTRACK_BUILD_PRINT_TRACES=ON
67+
68+
make -j$(nproc)
69+
sudo make install
70+
71+
- name: Build flamegraph
72+
run: |
73+
cargo build --profile profiling --test flamegraph_test
74+
env:
75+
RUSTFLAGS: "-C force-frame-pointers=yes -C symbol-mangling-version=v0"
76+
CARGO_PROFILE_RELEASE_DEBUG: true
77+
78+
- name: Build heaptrack data
79+
run: |
80+
export TEST_BINARY=$(find "$GITHUB_WORKSPACE/target/profiling/deps" -name "flamegraph_test-*" -type f -executable | head -1)
81+
82+
if [ -z "$TEST_BINARY" ]; then
83+
echo "Error: Could not find test binary"
84+
exit 1
85+
fi
86+
87+
"$TEST_BINARY" profile_with_flamegraph --ignored --no-capture | head -100
88+
89+
heaptrack --output heaptrack-data "$TEST_BINARY" --ignored profile_with_flamegraph
90+
env:
91+
CARGO_MANIFEST_DIR: "$GITHUB_WORKSPACE/lustrefs-exporter"
92+
93+
- name: Generate flamegraph
94+
run: |
95+
heaptrack_print --version
96+
HEAPTRACK_FILE=$(ls heaptrack-data.* | head -1)
97+
98+
echo "Writing flamegraph data to flamegraph-data.txt"
99+
heaptrack_print "$HEAPTRACK_FILE" -F flamegraph-data.txt > /dev/null
100+
echo "Done writing flamegraph data to flamegraph-data.txt: $?"
101+
102+
rustfilt < flamegraph-data.txt > demangled-flamegraph.txt
103+
ls -lah demangled-flamegraph.txt
104+
awk '$NF > 1000' demangled-flamegraph.txt > significant_stacks.txt
105+
ls -lah significant_stacks.txt
106+
FlameGraph/flamegraph.pl --colors mem --countname allocations < significant_stacks.txt > flamegraph.svg
107+
ls -lah flamegraph.svg
108+
109+
- name: Upload flamegraph
110+
uses: actions/upload-artifact@v4
111+
with:
112+
name: flamegraph
113+
path: |
114+
flamegraph.svg
115+
cpu-flamegraph.svg
116+
heaptrack-data.*

.github/workflows/scrape-memory-metrics-bench-flame.yml

Lines changed: 0 additions & 31 deletions
This file was deleted.

Cargo.lock

Lines changed: 1 addition & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lustrefs-exporter/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ regex = { version = "1", default-features = false, features = [
1717
"std",
1818
"perf-dfa-full",
1919
] }
20+
rustc-demangle.workspace = true
2021
serde = { version = "1", features = ["derive"] }
2122
thiserror.workspace = true
2223
tokio = { workspace = true, features = [

lustrefs-exporter/tests/flamegraph_test.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
// #[global_allocator]
2-
// static ALLOC: dhat::Alloc = dhat::Alloc;
3-
41
use commandeer_test::commandeer;
52
use pprof::ProfilerGuardBuilder;
63
use serial_test::serial;
7-
use tokio::task::JoinSet;
84
use std::time::{Duration, Instant};
5+
use tokio::task::JoinSet;
96

107
#[commandeer(Replay, "lctl", "lnetctl")]
118
#[tokio::test]
129
#[serial]
10+
#[ignore]
1311
async fn profile_with_flamegraph() {
14-
// Start memory profiling
15-
//let _mem_profiler = dhat::Profiler::new_heap();
16-
1712
// Start CPU profiling
1813
let cpu_guard = ProfilerGuardBuilder::default()
1914
.frequency(100)
@@ -35,9 +30,7 @@ async fn profile_with_flamegraph() {
3530
tokio::time::sleep(Duration::from_millis(100)).await;
3631

3732
// Run your load test once
38-
println!("Running load test...");
39-
let duration = load_test_concurrent(1, 1).await;
40-
println!("Load test completed in {:?}", duration);
33+
let _duration = load_test_concurrent(10, 10).await;
4134

4235
// Generate CPU flamegraph
4336
if let Ok(report) = cpu_guard.report().build() {
@@ -49,11 +42,6 @@ async fn profile_with_flamegraph() {
4942

5043
// dhat automatically saves to dhat-heap.json when _mem_profiler drops
5144
println!("Memory profile saved to dhat-heap.json");
52-
53-
// Get memory stats
54-
// let stats = dhat::HeapStats::get();
55-
// println!("Peak memory: {} MB", stats.max_bytes / 1_000_000);
56-
// println!("Total allocations: {}", stats.total_blocks);
5745
}
5846

5947
// Create a single request using `oneshot`. This is equivalent to hitting the

0 commit comments

Comments
 (0)