Skip to content

Commit 4901782

Browse files
fix(tools): fixed profiling support for rust asap-query-engine (#343)
1 parent e092705 commit 4901782

9 files changed

Lines changed: 94 additions & 13 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ datafusion_summary_library = { path = "asap-common/dependencies/rs/datafusion_su
3838
elastic_dsl_utilities = { path = "asap-common/dependencies/rs/elastic_dsl_utilities" }
3939
asap_planner = { path = "asap-planner-rs" }
4040
indexmap = { version = "2.0", features = ["serde"] }
41+
42+
[profile.release]
43+
debug = 1 # line table + symbol names for flamegraph; no effect on codegen or runtime perf

asap-query-engine/src/engine_config.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ pub struct EngineConfig {
4747
pub log_level: String,
4848
pub prometheus_scrape_interval: u64,
4949
pub streaming_engine: StreamingEngine,
50-
pub do_profiling: bool,
5150
pub http_server: HttpServerSettings,
5251
pub backend: BackendConfig,
5352
pub store: StoreSettings,
@@ -66,7 +65,6 @@ impl Default for EngineConfig {
6665
log_level: "INFO".to_string(),
6766
prometheus_scrape_interval: 15,
6867
streaming_engine: StreamingEngine::Precompute,
69-
do_profiling: false,
7068
http_server: HttpServerSettings::default(),
7169
backend: BackendConfig::default(),
7270
store: StoreSettings::default(),

asap-tools/experiments/config/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ logging:
1818

1919
# Profiling options
2020
profiling:
21-
query_engine: false
21+
query_engine: false # Rust query engine only; requires use_container.query_engine: false
2222
prometheus_time: null # Optional[int]
2323
flink: false
2424
arroyo: false

asap-tools/experiments/experiment_utils/config.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,18 @@ def validate_config(cfg: DictConfig, script_name: str = "experiment_run_e2e"):
521521
"--no_teardown can only be used with a single experiment mode"
522522
)
523523

524+
# Profiling the Rust query engine requires bare-metal mode (debug symbols unavailable in container)
525+
if (
526+
hasattr(cfg, "profiling")
527+
and cfg.profiling.get("query_engine", False)
528+
and hasattr(cfg, "use_container")
529+
and cfg.use_container.get("query_engine", True)
530+
):
531+
raise ValueError(
532+
"profiling.query_engine=true requires use_container.query_engine=false. "
533+
"Container builds discard debug symbols, making flamegraph output unreadable."
534+
)
535+
524536
# Validate aggregate cleanup policy
525537
valid_policies = ["circular_buffer", "read_based", "no_cleanup"]
526538
if hasattr(cfg, "aggregate_cleanup") and hasattr(cfg.aggregate_cleanup, "policy"):

asap-tools/experiments/experiment_utils/services/query_engine.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ def _build_engine_config(
106106
should match streaming.remote_write.base_port in the Hydra config
107107
dump_precomputes: Whether to dump received precomputes to output_dir for debugging
108108
lock_strategy: Lock strategy for SimpleMapStore ('global' or 'per-key')
109-
profile_query_engine: Whether to enable do_profiling in the engine
110109
kafka_broker: Kafka broker address, e.g. '10.10.1.1:9092' (arroyo only)
111110
112111
Returns:
@@ -138,7 +137,6 @@ def _build_engine_config(
138137
"log_level": log_level,
139138
"prometheus_scrape_interval": prometheus_scrape_interval,
140139
"streaming_engine": streaming_engine,
141-
"do_profiling": profile_query_engine,
142140
"http_server": {"port": http_port},
143141
"backend": backend, # already fully resolved by caller
144142
"store": {"lock_strategy": lock_strategy},

asap-tools/experiments/remote_monitor.py

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,56 @@ def stop_profiling_arroyo_pids(
162162
logger.debug("Stopped profiling for arroyo pids")
163163

164164

165+
def start_profiling_query_engine_pids(qe_pids, experiment_output_dir):
166+
qe_perf_procs = []
167+
qe_profiles_dir = os.path.join(experiment_output_dir, "query_engine_profiles")
168+
os.makedirs(qe_profiles_dir, exist_ok=True)
169+
170+
for pid in qe_pids:
171+
output_file = os.path.join(qe_profiles_dir, f"perf_{pid}.data")
172+
cmd = [
173+
"perf",
174+
"record",
175+
"-g",
176+
"--call-graph",
177+
"dwarf",
178+
"-F",
179+
"997",
180+
"-o",
181+
output_file,
182+
"--pid",
183+
str(pid),
184+
]
185+
logger.debug(f"Starting perf record for PID {pid} with command: {cmd}")
186+
proc = subprocess.Popen(cmd)
187+
qe_perf_procs.append(proc)
188+
189+
logger.debug(
190+
f"Started perf record processes with PIDs: {[p.pid for p in qe_perf_procs]}"
191+
)
192+
return qe_perf_procs
193+
194+
195+
def stop_profiling_query_engine_pids(qe_perf_procs, store: bool):
196+
for proc in qe_perf_procs:
197+
try:
198+
os.kill(proc.pid, signal.SIGTERM)
199+
logger.debug(f"Stopped perf record process PID: {proc.pid}")
200+
except ProcessLookupError:
201+
logger.debug(f"Perf record process PID {proc.pid} already terminated")
202+
for proc in qe_perf_procs:
203+
try:
204+
proc.wait(timeout=60)
205+
logger.debug(
206+
f"Perf record process PID {proc.pid} exited with code {proc.returncode}"
207+
)
208+
except subprocess.TimeoutExpired:
209+
logger.debug(
210+
f"Perf record process PID {proc.pid} did not terminate within 60s"
211+
)
212+
logger.debug("Stopped profiling for query engine pids")
213+
214+
165215
# TODO Provide some way of specifying which hooks will be used
166216
def get_process_monitor_hooks(
167217
export_cost: bool, provider, node_offset: int
@@ -233,14 +283,23 @@ def main(args):
233283
logger.error("No matching processes found.")
234284
return
235285

236-
profile_query_engine_pid = None
286+
profile_query_engine_pid = (
287+
None # unused for Rust QE; kept for PrometheusClientService compat
288+
)
289+
qe_flamegraph_procs = None
237290
if args.profile_query_engine:
238-
if (
239-
constants.QUERY_ENGINE_RS_PROCESS_KEYWORD in args.keywords
240-
or constants.QUERY_ENGINE_RS_CONTAINER_NAME in args.keywords
241-
):
242-
raise NotImplementedError(
243-
"Profiling for Rust query engine is not implemented yet"
291+
if constants.QUERY_ENGINE_RS_CONTAINER_NAME in args.keywords:
292+
raise ValueError(
293+
"Rust query engine profiling requires bare-metal mode. "
294+
"Set use_container.query_engine: false in config."
295+
)
296+
if constants.QUERY_ENGINE_RS_PROCESS_KEYWORD in args.keywords:
297+
qe_pids = get_pids(constants.QUERY_ENGINE_RS_PROCESS_KEYWORD)
298+
stop_profiling_query_engine_pids(
299+
[], store=False
300+
) # clear any stale profilers
301+
qe_flamegraph_procs = start_profiling_query_engine_pids(
302+
qe_pids, args.experiment_output_dir
244303
)
245304

246305
logger.debug("Starting process monitors")
@@ -345,6 +404,10 @@ def main(args):
345404
arroyo_flamegraph_pids, args.experiment_output_dir, store=True
346405
)
347406

407+
if qe_flamegraph_procs:
408+
logger.debug("Stopping profiling for query engine pids")
409+
stop_profiling_query_engine_pids(qe_flamegraph_procs, store=True)
410+
348411
logger.debug("Stopping process monitors")
349412
monitor_info = process_monitor.stop_monitor(monitor, control_pipe, monitor_pipe)
350413

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
cargo install flamegraph
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
sudo apt-get install -y linux-tools-common "linux-tools-$(uname -r)"
4+
sudo sh -c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'

asap-tools/installation/install_external_components.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

33
# PREDEFINED_COMPONENTS=("benchmarks" "exporters" "flink" "grafana" "kafka" "prometheus" "prometheus_kafka_adapter" "asprof")
4-
PREDEFINED_COMPONENTS=("benchmarks" "exporters" "flink" "grafana" "kafka" "prometheus" "asprof" "arroyo")
4+
PREDEFINED_COMPONENTS=("benchmarks" "exporters" "flink" "grafana" "kafka" "prometheus" "asprof" "arroyo" "flamegraph")
55

66
if [ "$#" -lt 2 ]; then
77
echo "Usage: $0 <install_dir> <component1> [<component2> ...]"

0 commit comments

Comments
 (0)