### macOS Xctrace Initial Command Setup (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Configures and prepares the 'xctrace' command for profiling on macOS. It validates frequency and custom command arguments, sets the trace file path, and constructs the command based on the workload (Command or Pid). It calls a `run` function to execute the command. ```rust pub(crate) fn initial_command( workload: Workload, sudo: Option>, freq: u32, _compress_level: Option, custom_cmd: Option, verbose: bool, ignore_status: bool, ) -> anyhow::Result> { if freq != 997 { bail!("xctrace doesn't support custom frequency"); } if custom_cmd.is_some() { bail!("xctrace doesn't support custom command"); } let xctrace = env::var("XCTRACE").unwrap_or_else(|_| "xctrace".to_string()); let trace_file = PathBuf::from("cargo-flamegraph.trace"); let mut command = sudo_command(&xctrace, sudo); command .arg("record") .arg("--template") .arg("Time Profiler") .arg("--output") .arg(&trace_file); match workload { Workload::Command(args) => { command .arg("--target-stdout") .arg("-") .arg("--launch") .arg("--") .args(args); } Workload::Pid(pid) => { match &*pid { [pid] => { // xctrace could accept multiple --attach arguments, // but it will only profile the last pid provided. command.arg("--attach").arg(pid.to_string()); } _ => { bail!("xctrace only supports profiling a single process at a time"); } } } Workload::ReadPerf(_) => {} } run(command, verbose, ignore_status); Ok(Some(trace_file)) } ``` -------------------------------- ### Get Perf Script Output (Linux) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs This Rust code retrieves the output of the `perf script` command, which processes perf data to generate a human-readable format. It handles sudo commands to access privileged kernel symbols and supports options like `--no-inline` for detailed stack traces. ```rust 134 pub fn output( 135 perf_output: Option, 136 script_no_inline: bool, 137 sudo: Option>, 138 ) -> anyhow::Result> { 139 // We executed `perf record` with sudo, and will be executing `perf script` with sudo, 140 // so that we can resolve privileged kernel symbols from /proc/kallsyms. 141 let perf = env::var("PERF").unwrap_or_else(|_| "perf".to_string()); 142 let mut command = sudo_command(&perf, sudo); 143 144 command.arg("script"); 145 146 // Force reading perf.data owned by another uid if it happened to be created earlier. 147 command.arg("--force"); 148 149 if script_no_inline { 150 command.arg("--no-inline"); 151 } 152 153 if let Some(perf_output) = perf_output { 154 command.arg("-i"); 155 command.arg(perf_output); 156 } ``` -------------------------------- ### Get Default Frequency in Rust Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Retrieves the frequency setting from the `Options` struct. If the frequency is not explicitly set, it defaults to 997. ```Rust impl Options { pub fn frequency(&self) -> u32 { self.frequency.unwrap_or(997) } } ``` -------------------------------- ### Implement FromArgMatches for Options (Rust) Source: https://docs.rs/flamegraph/latest/flamegraph/struct.Options Implements the `FromArgMatches` trait for the `Options` struct, allowing the creation of an `Options` instance from command-line arguments parsed by clap. This includes methods for both initial instantiation and updating existing instances. ```rust impl FromArgMatches for Options { fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error> fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error> } ``` -------------------------------- ### Initial DTrace Command Construction Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Constructs the initial dtrace command for profiling. It sets up script arguments, stack frame options, output file, and handles different workload types (executing a command or attaching to a PID). ```rust pub(crate) fn initial_command( workload: Workload, sudo: Option>, freq: u32, _compress_level: Option, custom_cmd: Option, verbose: bool, ignore_status: bool, ) -> anyhow::Result> { let mut command = base_dtrace_command(sudo); let dtrace_script = custom_cmd.unwrap_or(format!( "profile-{freq} /pid == $target/ \ { @[ustack(100)] = count(); }", )); command.arg("-x"); command.arg("ustackframes=100"); command.arg("-n"); command.arg(&dtrace_script); command.arg("-o"); command.arg("cargo-flamegraph.stacks"); match workload { Workload::Command(c) => { let mut escaped = String::new(); for (i, arg) in c.iter().enumerate() { if i > 0 { escaped.push(' '); } escaped.push_str(&arg.replace(' ', "\\ ")); } command.arg("-c"); command.arg(&escaped); #[cfg(target_os = "windows")] { let mut help_test = crate::arch::base_dtrace_command(None); let dtrace_found = help_test .arg("--help") .stderr(Stdio::null()) .stdout(Stdio::null()) .status() .is_ok(); if !dtrace_found { let mut command_builder = Command::new(&c[0]); command_builder.args(&c[1..]); print_command(&command_builder, verbose); let trace = blondie::trace_command(command_builder, false) .map_err(|err| anyhow!("could not find dtrace and could not profile using blondie: {err:?}"))?; let f = std::fs::File::create("./cargo-flamegraph.stacks") .context("unable to create temporary file 'cargo-flamegraph.stacks'")?; let mut f = std::io::BufWriter::new(f); trace.write_dtrace(&mut f).map_err(|err| { anyhow!("unable to write dtrace output to 'cargo-flamegraph.stacks': {err:?}") })?; return Ok(None); } } } Workload::Pid(p) => { for p in p { command.arg("-p"); command.arg(p.to_string()); } } Workload::ReadPerf(_) => (), } run(command, verbose, ignore_status); Ok(None) } ``` -------------------------------- ### FlamegraphOptions Implementations Source: https://docs.rs/flamegraph/latest/flamegraph/struct.FlamegraphOptions Provides implementations for the FlamegraphOptions struct, including a method to convert it into Inferno Options and implementations for argument parsing and debugging traits. ```rust impl FlamegraphOptions { pub fn into_inferno(self) -> Options<'static> } impl Args for FlamegraphOptions { fn group_id() -> Option fn augment_args<'b>(__clap_app: Command) -> Command fn augment_args_for_update<'b>(__clap_app: Command) -> Command } impl Debug for FlamegraphOptions { fn fmt(&self, f: &mut Formatter<'_>) -> Result } impl FromArgMatches for FlamegraphOptions { fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error> fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error> } ``` -------------------------------- ### Struct Options Source: https://docs.rs/flamegraph/latest/flamegraph/struct.Options Represents the configuration options for generating flamegraphs. ```APIDOC ## Struct Options ### Description Represents the configuration options for generating flamegraphs. ### Fields - **`verbose`** (bool) - Print extra output to help debug problems. - **`root`** (Option>) - Run with root privileges (using `sudo`). Accepts an optional argument containing command line options which will be passed to sudo. ### Implementations #### `impl Options` ##### `pub fn check(&self) -> Result<()>` Checks the validity of the options. ##### `pub fn frequency(&self) -> u32` Returns the sampling frequency. #### `impl Args for Options` ##### `fn group_id() -> Option` Report the `ArgGroup::id` for this set of arguments. ##### `fn augment_args<'b>(__clap_app: Command) -> Command` Append to `Command` so it can instantiate `Self` via `FromArgMatches::from_arg_matches_mut`. ##### `fn augment_args_for_update<'b>(__clap_app: Command) -> Command` Append to `Command` so it can instantiate `self` via `FromArgMatches::update_from_arg_matches_mut`. #### `impl Debug for Options` ##### `fn fmt(&self, f: &mut Formatter<'_>) -> Result` Formats the value using the given formatter. #### `impl FromArgMatches for Options` ##### `fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result` Instantiate `Self` from `ArgMatches`, parsing the arguments as needed. ##### `fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result` Instantiate `Self` from `ArgMatches`, parsing the arguments as needed. ##### `fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error>` Assign values from `ArgMatches` to `self`. ##### `fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error>` Assign values from `ArgMatches` to `self`. ### Auto Trait Implementations - `Freeze` for `Options` - `RefUnwindSafe` for `Options` - `Send` for `Options` - `Sync` for `Options` - `Unpin` for `Options` - `UnwindSafe` for `Options` ### Blanket Implementations - `impl Any for T` - `impl Borrow for T` - `impl BorrowMut for T` - `impl From for T` - `impl Into for T` - `impl TryFrom for T` - `impl TryInto for T` ``` -------------------------------- ### Create Sudo Command Wrapper (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Constructs a `std::process::Command` instance, optionally prepending 'sudo' and custom arguments. This allows for executing commands with elevated privileges when needed. It handles cases where sudo is not specified or requires arguments. ```rust fn sudo_command(command: &str, sudo: Option>) -> Command { let sudo = match sudo { Some(sudo) => sudo, None => return Command::new(command), }; let mut c = Command::new("sudo"); if let Some(sudo_args) = sudo { c.arg(sudo_args); } c.arg(command); c } ``` -------------------------------- ### Generate Flamegraph for Workload with Options (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Orchestrates the flamegraph generation process based on the provided workload and options. It handles signal registration for SIGINT on Unix, determines the profiling command (e.g., perf), and invokes the output generation logic. ```rust pub fn generate_flamegraph_for_workload(workload: Workload, opts: Options) -> anyhow::Result<()> { #[cfg(unix)] let handler = unsafe { signal_hook::low_level::register(SIGINT, || {}).expect("cannot register signal handler") }; let sudo = opts.root.as_ref().map(|inner| inner.as_deref()); let perf_output = if let Workload::ReadPerf(perf_file) = workload { Some(perf_file) } else { #[cfg(target_os = "linux")] let compression = opts.compression_level; #[cfg(not(target_os = "linux"))] let compression = None; arch::initial_command( workload, sudo, opts.frequency(), compression, opts.custom_cmd, opts.verbose, opts.ignore_status, )? }; #[cfg(unix)] signal_hook::low_level::unregister(handler); let output = arch::output(perf_output, opts.script_no_inline, sudo)?; // ... rest of the function Ok(()) } ``` -------------------------------- ### Define Flamegraph Options Struct (Rust) Source: https://docs.rs/flamegraph/latest/flamegraph/struct.Options Defines the `Options` struct for configuring flamegraph generation. It includes a boolean for verbose output and an optional string for specifying the root directory or sudo command. Private fields are also indicated but not detailed. ```rust pub struct Options { pub verbose: bool, pub root: Option>, /* private fields */ } ``` -------------------------------- ### Implement Args Trait for Options (Rust) Source: https://docs.rs/flamegraph/latest/flamegraph/struct.Options Implements the `Args` trait for the `Options` struct, enabling argument parsing for the flamegraph tool. This includes methods to group arguments and append them to a clap `Command` for instantiation. ```rust impl Args for Options { fn group_id() -> Option fn augment_args<'b>(__clap_app: Command) -> Command fn augment_args_for_update<'b>(__clap_app: Command) -> Command } ``` -------------------------------- ### Flamegraph Options Configuration Source: https://docs.rs/flamegraph/latest/flamegraph/struct.FlamegraphOptions This section details the available options for configuring flamegraph generation. These options can be used to customize the appearance and behavior of the generated flamegraph. ```APIDOC ## FlamegraphOptions ### Description Represents the configuration options for generating a flamegraph. ### Fields * **title** (`Option`) * Description: Set title text in SVG. * **subtitle** (`Option`) * Description: Set second level title text in SVG. * **deterministic** (`bool`) * Description: Colors are selected such that the color of a function does not change between runs. * **inverted** (`bool`) * Description: Plot the flame graph up-side-down. * **reverse** (`bool`) * Description: Generate stack-reversed flame graph. * **notes** (`Option`) * Description: Set embedded notes in SVG. * **min_width** (`f64`) * Description: Omit functions smaller than pixels. * **image_width** (`Option`) * Description: Image width in pixels. * **palette** (`Option`) * Description: Color palette. * **skip_after** (`Vec`) * Description: Cut off stack frames below; may be repeated. * **flame_chart** (`bool`) * Description: Produce a flame chart (sort by time, do not merge stacks). ### Methods * **into_inferno** (`pub fn into_inferno(self) -> Options<'static>`) * Description: Converts `FlamegraphOptions` into `Options` for Inferno. ### Implementations * **Args** * `group_id() -> Option`: Report the `ArgGroup::id` for this set of arguments. * `augment_args<'b>(__clap_app: Command) -> Command`: Append to `Command` so it can instantiate `Self` via `FromArgMatches::from_arg_matches_mut`. * `augment_args_for_update<'b>(__clap_app: Command) -> Command`: Append to `Command` so it can instantiate `self` via `FromArgMatches::update_from_arg_matches_mut`. * **Debug** * `fmt(&self, f: &mut Formatter<'_>) -> Result`: Formats the value using the given formatter. * **FromArgMatches** * `from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result`: Instantiate `Self` from `ArgMatches`, parsing the arguments as needed. * `from_arg_matches_mut(__clap_arg_matches: &mut ArgMatches) -> Result`: Instantiate `Self` from `ArgMatches`, parsing the arguments as needed. * `update_from_arg_matches(&mut self, __clap_arg_matches: &ArgMatches) -> Result<(), Error>`: Assign values from `ArgMatches` to `self`. * `update_from_arg_matches_mut(&mut self, __clap_arg_matches: &mut ArgMatches) -> Result<(), Error>`: Assign values from `ArgMatches` to `self`. ### Auto Trait Implementations * `Freeze` * `RefUnwindSafe` * `Send` * `Sync` * `Unpin` * `UnwindSafe` ### Blanket Implementations * **Any** * `type_id(&self) -> TypeId`: Gets the `TypeId` of `self`. * **Borrow** * `borrow(&self) -> &T`: Immutably borrows from an owned value. * **BorrowMut** * `borrow_mut(&mut self) -> &mut T`: Mutably borrows from an owned value. * **From** * `from(t: T) -> T`: Returns the argument unchanged. * **Into** * `into(self) -> U`: Calls `U::from(self)`. * **TryFrom** * `type Error = Infallible` * `try_from(value: U) -> Result>::Error>`: Performs the conversion. * **TryInto** * `type Error = >::Error` * `try_into(self) -> Result>::Error>`: Performs the conversion. ``` -------------------------------- ### Run Perf Script with Spinner (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Executes the 'perf script' command, displaying a progress spinner to the user while it runs. It handles command execution, captures output, and reports errors if the command fails. Dependencies include ProgressBar and std::time::Duration. ```rust // perf script can take a long time to run. Notify the user that it is running // by using a spinner. Note that if this function exits before calling // spinner.finish(), then the spinner will be completely removed from the terminal. let spinner = ProgressBar::new_spinner().with_prefix("Running perf script"); spinner.set_style( ProgressStyle::with_template("{prefix} [{elapsed}]: {spinner:.green}").unwrap(), ); spinner.enable_steady_tick(Duration::from_millis(500)); let result = command.output().context("unable to call perf script"); spinner.finish(); let output = result?; if !output.status.success() { bail!( "unable to run 'perf script': ({}) {}", output.status, std::str::from_utf8(&output.stderr)? ); } Ok(output.stdout) ``` -------------------------------- ### Configure Perf Command (Linux) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs This Rust code snippet configures and executes the `perf` command on Linux systems to collect performance data. It handles command-line arguments, sudo privileges, and output file management. The function supports capturing data from commands, PIDs, or reading from a pre-existing perf data file, and manages error handling. ```rust 51 pub(crate) fn initial_command( 52 workload: Workload, 53 sudo: Option>, 54 freq: u32, 55 compress_level: Option, 56 custom_cmd: Option, 57 verbose: bool, 58 ignore_status: bool, 59 ) -> anyhow::Result> { 60 let perf = if let Ok(path) = env::var("PERF") { 61 path 62 } else { 63 if Command::new("perf") 64 .arg("--help") 65 .stderr(Stdio::null()) 66 .stdout(Stdio::null()) 67 .status() 68 .is_err() 69 { 70 bail!("perf is not installed or not present in $PATH"); 71 } 72 73 String::from("perf") 74 }; 75 let mut command = sudo_command(&perf, sudo); 76 77 let args = custom_cmd.unwrap_or_else(|| { 78 let mut args = format!("record -F {freq} --call-graph dwarf,64000 -g"); 79 if let Some(z) = compress_level { 80 _ = write!(args, " -z={z}"); 81 } 82 args 83 }); 84 85 let mut perf_output = None; 86 let mut args = args.split_whitespace(); 87 while let Some(arg) = args.next() { 88 command.arg(arg); 89 90 // Detect if user is setting `perf record` 91 // output file with `-o`. If so, save it in 92 // order to correctly compute perf's output in 93 // `Self::output`. 94 if arg == "-o" { 95 let next_arg = args.next().context("missing '-o' argument")?; 96 command.arg(next_arg); 97 perf_output = Some(PathBuf::from(next_arg)); 98 } 99 } 100 101 let perf_output = match perf_output { 102 Some(path) => path, 103 None => { 104 command.arg("-o"); 105 command.arg("perf.data"); 106 PathBuf::from("perf.data") 107 } 108 }; 109 110 match workload { 111 Workload::Command(c) => { 112 command.args(&c); 113 } 114 Workload::Pid(p) => { 115 if let Some((first, pids)) = p.split_first() { 116 let mut arg = first.to_string(); 117 118 for pid in pids { 119 arg.push(','); 120 arg.push_str(&pid.to_string()); 121 } 122 123 command.arg("-p"); 124 command.arg(arg); 125 } 126 } 127 Workload::ReadPerf(_) => (), 128 } 129 130 run(command, verbose, ignore_status); 131 Ok(Some(perf_output)) 132 } ``` -------------------------------- ### Print Command Details Verbose (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Prints the command details to standard output if the `verbose` flag is set. This aids in debugging by showing the exact commands being executed during the flamegraph generation process. ```rust fn print_command(cmd: &Command, verbose: bool) { if verbose { println!("command {:?}", cmd); } } ``` -------------------------------- ### Demangle and Collapse Stack Data (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs This Rust code snippet demangles raw profiling output and then collapses it into a format suitable for flamegraph generation. It handles potential errors during demangling and collapsing, and includes platform-specific logic for initializing the 'folder' used in collapsing. ```rust let mut demangled_output = vec![]; demangle_stream(&mut Cursor::new(output), &mut demangled_output, false) .context("unable to demangle")?; let perf_reader = BufReader::new(&*demangled_output); let mut collapsed = vec![]; let collapsed_writer = BufWriter::new(&mut collapsed); #[cfg(target_os = "linux")] let mut folder = { let mut collapse_options = CollapseOptions::default(); collapse_options.skip_after = opts.flamegraph_options.skip_after.clone(); Folder::from(collapse_options) }; #[cfg(target_os = "macos")] let mut folder = Folder::default(); #[cfg(not(any(target_os = "linux", target_os = "macos")))] let mut folder = { let collapse_options = CollapseOptions::default(); Folder::from(collapse_options) }; folder .collapse(perf_reader, collapsed_writer) .context("unable to collapse generated profile data")?; ``` -------------------------------- ### Run Command and Handle Exit Status (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Executes a given `std::process::Command` and waits for its completion. It provides options for verbose output and ignoring non-zero exit statuses, which is useful for profiling scenarios where certain command failures might be acceptable. ```rust fn run(mut command: Command, verbose: bool, ignore_status: bool) { print_command(&command, verbose); let mut recorder = command.spawn().expect(arch::SPAWN_ERROR); let exit_status = recorder.wait().expect(arch::WAIT_ERROR); if !ignore_status && terminated_by_error(exit_status) { eprintln!( "failed to sample program, exited with code: {:?}", exit_status.code() ); exit(1); } } ``` -------------------------------- ### FlamegraphOptions Struct Definition Source: https://docs.rs/flamegraph/latest/flamegraph/struct.FlamegraphOptions Defines the configuration options for generating flame graphs. It includes fields for setting titles, controlling color determinism, inversion, reversing the stack, omitting small functions, specifying image dimensions, choosing a color palette, and skipping stack frames. ```rust pub struct FlamegraphOptions { pub title: Option, pub subtitle: Option, pub deterministic: bool, pub inverted: bool, pub reverse: bool, pub notes: Option, pub min_width: f64, pub image_width: Option, pub palette: Option, pub skip_after: Vec, pub flame_chart: bool, } ``` -------------------------------- ### Base DTrace Command for Non-macOS Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Generates a base dtrace command for systems other than macOS. It simply uses the 'dtrace' executable, potentially with sudo privileges, and respects the DTRACE environment variable. ```rust #[cfg(not(target_os = "macos"))] fn base_dtrace_command(sudo: Option>) -> Command { let dtrace = env::var("DTRACE").unwrap_or_else(|_| "dtrace".to_string()); sudo_command(&dtrace, sudo) } ``` -------------------------------- ### macOS DTrace Command Generation with Architecture Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Generates a base dtrace command, wrapping it with 'arch -64' or 'arch -32' on macOS to ensure compatibility with the compiled binary's architecture. This addresses potential issues with cross-architecture tracing. ```rust fn base_dtrace_command(sudo: Option>) -> Command { // on an ARM mac, it will fail to trace the child process with a confusing syntax error in its stdlib .d file. // If the flamegraph binary, or the cargo binary, have been compiled as x86, this can cause all tracing to fail. // To work around that, we unconditionally wrap dtrace on MacOS in the "arch -64/-32" wrapper so it's always // running in the native architecture matching the bit width (32 oe 64) with which "flamegraph" was compiled. // NOTE that dtrace-as-x86 won't trace a deliberately-cross-compiled x86 binary running under Rosetta regardless // of "arch" wrapping; attempts to do that will fail with "DTrace cannot instrument translated processes". // NOTE that using the ARCHPREFERENCE environment variable documented here // (https://www.unix.com/man-page/osx/1/arch/) would be a much simpler solution to this issue, but it does not // seem to have any effect on dtrace when set (via Command::env, shell export, or std::env in the spawning // process). let mut command = sudo_command("arch", sudo); #[cfg(target_pointer_width = "64")] command.arg("-64".to_string()); #[cfg(target_pointer_width = "32")] command.arg("-32".to_string()); command.arg(env::var("DTRACE").unwrap_or_else(|_| "dtrace".to_string())); command } ``` -------------------------------- ### Convert Flamegraph Options to Inferno Options in Rust Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Converts custom `FlamegraphOptions` into the `inferno::flamegraph::Options` format. This function maps various configuration parameters like title, subtitle, color settings, and stack order to the corresponding fields in the `inferno` library's options struct. ```Rust impl FlamegraphOptions { pub fn into_inferno(self) -> inferno::flamegraph::Options<'static> { let mut options = inferno::flamegraph::Options::default(); if let Some(title) = self.title { options.title = title; } options.subtitle = self.subtitle; options.deterministic = self.deterministic; if self.inverted { options.direction = inferno::flamegraph::Direction::Inverted; } options.reverse_stack_order = self.reverse; options.notes = self.notes.unwrap_or_default(); options.min_width = self.min_width; options.image_width = self.image_width; if let Some(palette) = self.palette { options.colors = palette; } options.flame_chart = self.flame_chart; options } } ``` -------------------------------- ### Execute Post-Process Command (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs This Rust code snippet executes an external command for post-processing the collapsed stack data. It parses the command string, spawns a child process, pipes the collapsed data into its stdin, and captures its stdout. Error handling is included for command parsing, execution, and data transfer. ```rust if let Some(command) = opts.post_process { let command_vec = shlex::split(&command) .ok_or_else(|| anyhow!("unable to parse post-process command"))?; let mut child = Command::new( command_vec .first() .ok_or_else(|| anyhow!("unable to parse post-process command"))?, ) .args(command_vec.get(1..).unwrap_or(&[])) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .with_context(|| format!("unable to execute {:?}", command_vec))?; let mut stdin = child .stdin .take() .ok_or_else(|| anyhow::anyhow!("unable to capture post-process stdin"))?; let mut stdout = child .stdout .take() .ok_or_else(|| anyhow::anyhow!("unable to capture post-process stdout"))?; let thread_handle = std::thread::spawn(move || -> anyhow::Result<_> { let mut collapsed_processed = Vec::new(); stdout.read_to_end(&mut collapsed_processed).context( "unable to read the processed stacks from the stdout of the post-process process", )?; Ok(collapsed_processed) }); stdin .write_all(&collapsed) .context("unable to write the raw stacks to the stdin of the post-process process")?; drop(stdin); anyhow::ensure!( child.wait()?.success(), "post-process exited with a non zero exit code" ); collapsed = thread_handle.join().unwrap()?; } ``` -------------------------------- ### Generate Flamegraph SVG (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs This Rust code snippet generates the final flamegraph SVG file from the processed and collapsed stack data. It creates the output file, configures 'inferno' options, and writes the flamegraph using the 'from_reader' function. It also includes logic to optionally open the generated file. ```rust let collapsed_reader = BufReader::new(&*collapsed); let flamegraph_filename = opts.output; println!("writing flamegraph to {:?}", flamegraph_filename); let flamegraph_file = File::create(&flamegraph_filename) .context("unable to create flamegraph.svg output file")?; let flamegraph_writer = BufWriter::new(flamegraph_file); let mut inferno_opts = opts.flamegraph_options.into_inferno(); from_reader(&mut inferno_opts, collapsed_reader, flamegraph_writer) .context("unable to generate a flamegraph from the collapsed stack data")?; if opts.open { opener::open(&flamegraph_filename).context(format!( "failed to open '{}'", flamegraph_filename.display() ))?; } Ok(()) ``` -------------------------------- ### Implement Debug Trait for Options (Rust) Source: https://docs.rs/flamegraph/latest/flamegraph/struct.Options Implements the `Debug` trait for the `Options` struct, enabling the struct to be formatted for debugging purposes. This allows developers to print the state of `Options` during runtime. ```rust impl Debug for Options { fn fmt(&self, f: &mut Formatter<'_>) -> Result } ``` -------------------------------- ### macOS Xctrace Export Output (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Exports profiling data from an 'xctrace' file to a specific XML format suitable for flamegraph generation. It checks for platform compatibility, constructs the 'xctrace export' command, and handles file cleanup. Errors during export or cleanup are reported. ```rust pub fn output( trace_file: Option, script_no_inline: bool, _sudo: Option>, ) -> anyhow::Result> { if script_no_inline { bail!("--no-inline is only supported on Linux"); } let xctrace = env::var("XCTRACE").unwrap_or_else(|_| "xctrace".to_string()); let trace_file = trace_file.context("no trace file found.")?; let output = Command::new(xctrace) .arg("export") .arg("--input") .arg(&trace_file) .arg("--xpath") .arg(r#"/trace-toc/*/data/table[@schema=\"time-profile\"]"#) .output() .context("run xctrace export failed.")?; std::fs::remove_dir_all(&trace_file) .with_context(|| anyhow!("remove trace({})", trace_file.to_string_lossy()))?; if !output.status.success() { bail!( "unable to run 'xctrace export': ({}) {}", output.status, String::from_utf8_lossy(&output.stderr) ); } Ok(output.stdout) } ``` -------------------------------- ### Implement Blanket Traits for Workload in Rust Source: https://docs.rs/flamegraph/latest/flamegraph/enum.Workload Details the Blanket Implementations for the 'Workload' enum in Rust. This includes generic implementations of traits like 'Any', 'Borrow', 'BorrowMut', 'From', 'Into', 'TryFrom', and 'TryInto', providing fundamental type conversions and introspection capabilities. ```rust impl Any for T where T: 'static + ?Sized fn type_id(&self) -> TypeId impl Borrow for T where T: ?Sized fn borrow(&self) -> &T impl BorrowMut for T where T: ?Sized fn borrow_mut(&mut self) -> &mut T impl From for T fn from(t: T) -> T impl Into for T where U: From fn into(self) -> U impl TryFrom for T where U: Into type Error = Infallible fn try_from(value: U) -> Result>::Error> impl TryInto for T where U: TryFrom type Error = >::Error fn try_into(self) -> Result>::Error> ``` -------------------------------- ### Check Option Conflicts in Rust Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Manually checks for conflicting command-line options in Rust to prevent panics during shell completion generation. It specifically checks if both a custom command and a frequency are provided, returning an error if they are. ```Rust impl Options { pub fn check(&self) -> anyhow::Result<()> { // Manually checking conflict because structopts `conflicts_with` leads // to a panic in completion generation for zsh at the moment (see #158) match self.frequency.is_some() && self.custom_cmd.is_some() { true => Err(anyhow!( "Cannot pass both a custom command and a frequency." )), false => Ok(()), } } } ``` -------------------------------- ### Handle DTrace Output File Reading and UTF-8 Conversion (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Reads data from 'cargo-flamegraph.stacks', handles potential invalid UTF-8 by lossy re-encoding, and cleans up the temporary file. It returns the processed byte buffer. This function is crucial for parsing profiling data from DTrace. ```rust fn dtrace_output(sudo: Option>, script_no_inline: bool) -> Result, anyhow::Error> { if script_no_inline && cfg!(target_os = "linux") { bail!("--no-inline is only supported on Linux"); } if sudo.is_some() { #[cfg(unix)] if let Ok(user) = env::var("USER") { Command::new("sudo") .args(["chown", user.as_str(), "cargo-flamegraph.stacks"]) .spawn() .expect(arch::SPAWN_ERROR) .wait() .expect(arch::WAIT_ERROR); } } let mut buf = vec![]; let mut f = File::open("cargo-flamegraph.stacks") .context("failed to open dtrace output file 'cargo-flamegraph.stacks'")?; f.read_to_end(&mut buf) .context("failed to read dtrace expected output file 'cargo-flamegraph.stacks'")?; std::fs::remove_file("cargo-flamegraph.stacks") .context("unable to remove temporary file 'cargo-flamegraph.stacks'")?; let string = String::from_utf8_lossy(&buf); let reencoded_buf = string.as_bytes().to_owned(); if reencoded_buf != buf { println!("Lossily converted invalid utf-8 found in cargo-flamegraph.stacks"); } Ok(reencoded_buf) } ``` -------------------------------- ### Define DTrace Constants for Non-Linux/macOS (Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Defines constants for error messages related to 'dtrace' command execution on platforms other than Linux and macOS. These constants are used to provide specific error information when 'dtrace' commands fail. ```rust pub const SPAWN_ERROR: &str = "could not spawn dtrace"; pub const WAIT_ERROR: &str = "unable to wait for dtrace child command to exit"; ``` -------------------------------- ### Implement Auto Traits for Workload in Rust Source: https://docs.rs/flamegraph/latest/flamegraph/enum.Workload Shows the Auto Trait implementations for the 'Workload' enum in Rust. These traits, such as Send, Sync, and UnwindSafe, indicate thread safety and memory safety guarantees, crucial for concurrent programming. ```rust impl Freeze for Workload impl RefUnwindSafe for Workload impl Send for Workload impl Sync for Workload impl Unpin for Workload impl UnwindSafe for Workload ``` -------------------------------- ### Check for Non-Success Process Termination (Unix-specific, Rust) Source: https://docs.rs/flamegraph/latest/src/flamegraph/lib.rs Determines if a process terminated due to an error, excluding specific signals like SIGINT and SIGTERM, which might indicate user interruption. This function is platform-dependent, with a simplified version for non-Unix systems. ```rust #[cfg(unix)] fn terminated_by_error(status: ExitStatus) -> bool { status .signal() .map_or(true, |code| code != SIGINT && code != SIGTERM) && !status.success() && !(cfg!(target_os = "macos") && status.code() == Some(54)) } ``` ```rust #[cfg(not(unix))] fn terminated_by_error(status: ExitStatus) -> bool { !status.success() } ``` -------------------------------- ### Define Workload Enum in Rust Source: https://docs.rs/flamegraph/latest/flamegraph/enum.Workload Defines the 'Workload' enum used to specify the source for generating flamegraphs. It supports commands, process IDs, and reading from performance data files. This enum is central to configuring flamegraph generation. ```rust pub enum Workload { Command(Vec), Pid(Vec), ReadPerf(PathBuf), } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.