22# Copyright (C) 2024 Vrije Universiteit Brussel. All rights reserved.
33# SPDX-License-Identifier: MIT
44
5- from benchmarks .sleep import SleepBench
5+ """
6+ Flamegraph test campaign.
67
7- from benchkit .campaign import CampaignIterateVariables
8- from benchkit .commandwrappers .perf import PerfReportWrap , enable_non_sudo_perf
9- from benchkit .platforms import get_current_platform
10- from benchkit .utils .dir import caller_dir
11- from benchkit .utils .git import clone_repo
8+ Two sub-campaigns exercise perf-based flame graph generation:
129
10+ 1. **sleep** — a workload that produces zero CPU samples.
11+ Validates the graceful no-samples path (warning instead of crash).
1312
14- def main () -> None :
15- platform = get_current_platform ()
16- enable_non_sudo_perf ( comm_layer = platform . comm )
13+ 2. **dd** — a CPU-intensive workload (dd if=/dev/urandom of=/dev/null).
14+ Validates actual flamegraph SVG generation with real perf data.
15+ """
1716
18- flamegraph_path = caller_dir () / "deps/FlameGraph"
19- clone_repo (
20- repo_url = "https://github.com/brendangregg/FlameGraph.git" ,
21- repo_src_dir = flamegraph_path ,
22- commit = "cd9ee4c4449775a2f867acf31c84b7fe4b132ad5" ,
23- )
17+ from benchkit import CampaignCartesianProduct
18+ from benchkit .benches .small .dd import DDBench
19+ from benchkit .benches .small .sleep import SleepBench
20+ from benchkit .campaign import CampaignSuite
21+ from benchkit .commandwrappers .perf import PerfReportWrap , enable_non_sudo_perf
22+ from benchkit .platforms import get_current_platform
23+ from benchkit .utils .dir import get_tools_dir
2424
25- perf_wrapper = PerfReportWrap (
26- freq = 99 ,
27- # freq=10,
28- report_interactive = False ,
29- report_file = True ,
30- flamegraph_path = flamegraph_path ,
31- )
3225
33- def flame_post_hook (
26+ def _make_flame_post_hook (perf_wrapper ):
27+ """Return a post-run hook that generates a flame graph for each run."""
28+
29+ def hook (
3430 experiment_results_lines ,
3531 record_data_dir ,
3632 write_record_file_fun ,
@@ -43,35 +39,60 @@ def flame_post_hook(
4339 flamegraph_fontsize = 14 ,
4440 )
4541
46- campaign = CampaignIterateVariables (
47- name = "flame" ,
48- benchmark = SleepBench (
49- command_wrappers = [perf_wrapper ],
50- post_run_hooks = [
51- perf_wrapper .post_run_hook_report ,
52- flame_post_hook ,
53- ],
54- ),
42+ return hook
43+
44+
45+ def main () -> None :
46+ platform = get_current_platform ()
47+ enable_non_sudo_perf (comm_layer = platform .comm )
48+
49+ flamegraph_dir = get_tools_dir (None ) / "FlameGraph"
50+
51+ # --- shared perf wrapper (one instance is fine for sequential campaigns) ---
52+ perf_wrapper = PerfReportWrap (
53+ freq = 99 ,
54+ report_interactive = False ,
55+ report_file = True ,
56+ flamegraph_path = flamegraph_dir ,
57+ )
58+ perf_wrapper .fetch_flamegraph ()
59+
60+ flame_hook = _make_flame_post_hook (perf_wrapper )
61+
62+ # --- Campaign 1: sleep (no CPU samples → graceful skip) ---
63+ campaign_sleep = CampaignCartesianProduct (
64+ name = "flame_sleep" ,
65+ benchmark = SleepBench (),
66+ variables = {
67+ "duration_seconds" : [1 ],
68+ },
5569 nb_runs = 1 ,
56- variables = [
57- {
58- "duration_seconds" : 1 ,
59- },
60- {
61- "duration_seconds" : 2 ,
62- },
70+ command_wrappers = [perf_wrapper ],
71+ post_run_hooks = [
72+ perf_wrapper .post_run_hook_report ,
73+ flame_hook ,
6374 ],
64- constants = None ,
65- debug = False ,
66- gdb = False ,
67- enable_data_dir = True ,
75+ platform = platform ,
6876 )
6977
70- campaign .run ()
78+ # --- Campaign 2: dd (CPU-intensive → real flamegraph) ---
79+ campaign_dd = CampaignCartesianProduct (
80+ name = "flame_dd" ,
81+ benchmark = DDBench (),
82+ variables = {
83+ "block_count" : [50 ],
84+ },
85+ nb_runs = 1 ,
86+ command_wrappers = [perf_wrapper ],
87+ post_run_hooks = [
88+ perf_wrapper .post_run_hook_report ,
89+ flame_hook ,
90+ ],
91+ platform = platform ,
92+ )
7193
72- results_path = campaign .base_data_dir ()
73- perf_wrapper .fzf_report (search_dir = results_path )
74- perf_wrapper .fzf_flamegraph (search_dir = results_path )
94+ suite = CampaignSuite (campaigns = [campaign_sleep , campaign_dd ])
95+ suite .run_suite ()
7596
7697
7798if __name__ == "__main__" :
0 commit comments