diff --git a/src/env_vars.ml b/src/env_vars.ml index 6fbdf9b82..68c83a61c 100644 --- a/src/env_vars.ml +++ b/src/env_vars.ml @@ -7,6 +7,10 @@ open Async files around. *) let perfetto_dir = Unix.getenv "MAGIC_TRACE_PERFETTO_DIR" +(** Override which [perf] to use. If this isn't set, magic-trace will use whatever's first + in $PATH. *) +let perf_path = Option.value ~default:"perf" (Unix.getenv "MAGIC_TRACE_PERF_PATH") + (* Whether [perf] should be considered privileged when running as not-root. Bypasses error checks around kernel tracing when not root. *) let perf_is_privileged = Option.is_some (Unix.getenv "MAGIC_TRACE_PERF_IS_PRIVILEGED") diff --git a/src/env_vars.mli b/src/env_vars.mli index a51d80c32..9bf742f65 100644 --- a/src/env_vars.mli +++ b/src/env_vars.mli @@ -2,6 +2,7 @@ open! Core val debug : bool val experimental : bool +val perf_path : string val perf_is_privileged : bool val perfetto_dir : string option val no_dlfilter : bool diff --git a/src/perf_capabilities.ml b/src/perf_capabilities.ml index ae444b7b0..ccbb995d2 100644 --- a/src/perf_capabilities.ml +++ b/src/perf_capabilities.ml @@ -100,7 +100,9 @@ let supports_snapshot_on_exit = kernel_version_at_least ~major:5 ~minor:4 let supports_dlfilter = kernel_version_at_least ~major:5 ~minor:14 let detect_exn () = - let%bind perf_version_proc = Process.create_exn ~prog:"perf" ~args:[ "--version" ] () in + let%bind perf_version_proc = + Process.create_exn ~prog:Env_vars.perf_path ~args:[ "--version" ] () + in let%map version_string = Reader.contents (Process.stdout perf_version_proc) in let version = Version.of_perf_version_string_exn version_string in let set_if bool flag cap = cap + if bool then flag else empty in diff --git a/src/perf_tool_backend.ml b/src/perf_tool_backend.ml index 11acbd12a..a3de02488 100644 --- a/src/perf_tool_backend.ml +++ b/src/perf_tool_backend.ml @@ -5,6 +5,7 @@ open! Async parent process alive even though it just failed. That, in turn, makes magic-trace stop responding to Ctrl+C. *) let perf_env = `Extend [ "PAGER", "cat" ] +let perf = Env_vars.perf_path module Record_opts = struct type t = @@ -377,7 +378,7 @@ module Recording = struct in let argv = List.concat - [ [ "perf"; "record"; "-o"; record_dir ^/ "perf.data"; "--timestamp" ] + [ [ perf; "record"; "-o"; record_dir ^/ "perf.data"; "--timestamp" ] ; event_opts ; overwrite_opts ; switch_opts @@ -391,7 +392,7 @@ module Recording = struct in if debug_print_perf_commands then Core.printf "%s\n%!" (String.concat ~sep:" " argv); (* Perf prints output we don't care about and --quiet doesn't work for some reason *) - let perf_pid = perf_fork_exec ~env:perf_env ~prog:"perf" ~argv () in + let perf_pid = perf_fork_exec ~env:perf_env ~prog:perf ~argv () in (* This detaches the perf process from our "process group" but not our session. This makes it so that when Ctrl-C is sent to magic_trace in the terminal to end an attach session, it doesn't also send SIGINT to the perf process, allowing us to send it a @@ -508,11 +509,11 @@ let decode_events ] in if debug_print_perf_commands - then Core.printf "perf %s\n%!" (String.concat ~sep:" " args); + then Core.printf "%s %s\n%!" perf (String.concat ~sep:" " args); (* CR-someday tbrindus: this should be switched over to using [perf_fork_exec] to avoid the [perf script] process from outliving the parent. *) - let%map perf_script_proc = Process.create_exn ~env:perf_env ~prog:"perf" ~args () in + let%map perf_script_proc = Process.create_exn ~env:perf_env ~prog:perf ~args () in let line_pipe = Process.stdout perf_script_proc |> Reader.lines in don't_wait_for (Reader.transfer diff --git a/src/trace.ml b/src/trace.ml index 92a68f83f..fd406fa3c 100644 --- a/src/trace.ml +++ b/src/trace.ml @@ -19,7 +19,7 @@ let supports_command command = ;; let supports_fzf = supports_command "fzf" -let supports_perf = supports_command "perf" +let supports_perf = supports_command Env_vars.perf_path let check_for_perf () = if force supports_perf