iai_callgrind_runner/runner/callgrind/
args.rs1use std::collections::VecDeque;
2use std::ffi::OsString;
3use std::path::PathBuf;
4use std::str::FromStr;
5
6use anyhow::Result;
7use log::{log_enabled, warn};
8
9use crate::api::RawArgs;
10use crate::error::Error;
11use crate::runner::tool;
12use crate::runner::tool::args::FairSched;
13use crate::util::{bool_to_yesno, yesno_to_bool};
14
15#[allow(clippy::struct_excessive_bools)]
16#[derive(Debug, Clone)]
17pub struct Args {
18 i1: String,
19 d1: String,
20 ll: String,
21 cache_sim: bool,
22 other: Vec<String>,
23 toggle_collect: VecDeque<String>,
24 compress_strings: bool,
25 compress_pos: bool,
26 verbose: bool,
27 dump_instr: bool,
28 dump_line: bool,
29 combine_dumps: bool,
31 callgrind_out_file: Option<PathBuf>,
32 log_arg: Option<OsString>,
33 trace_children: bool,
34 separate_threads: bool,
35 fair_sched: FairSched,
36}
37
38impl Args {
39 pub fn try_from_raw_args(args: &[&RawArgs]) -> Result<Self> {
40 let mut default = Self::default();
41 default.try_update(args.iter().flat_map(|s| &s.0))?;
42 Ok(default)
43 }
44
45 pub fn try_update<'a, T: Iterator<Item = &'a String>>(&mut self, args: T) -> Result<()> {
46 for arg in args {
47 match arg
48 .trim()
49 .split_once('=')
50 .map(|(k, v)| (k.trim(), v.trim()))
51 {
52 Some(("--I1", value)) => value.clone_into(&mut self.i1),
53 Some(("--D1", value)) => value.clone_into(&mut self.d1),
54 Some(("--LL", value)) => value.clone_into(&mut self.ll),
55 Some((key @ "--cache-sim", value)) => {
56 self.cache_sim = yesno_to_bool(value).ok_or_else(|| {
57 Error::InvalidBoolArgument((key.to_owned(), value.to_owned()))
58 })?;
59 }
60 Some(("--toggle-collect", value)) => {
61 self.toggle_collect.push_back(value.to_owned());
62 }
63 Some((key @ "--dump-instr", value)) => {
64 self.dump_instr = yesno_to_bool(value).ok_or_else(|| {
65 Error::InvalidBoolArgument((key.to_owned(), value.to_owned()))
66 })?;
67 }
68 Some((key @ "--dump-line", value)) => {
69 self.dump_line = yesno_to_bool(value).ok_or_else(|| {
70 Error::InvalidBoolArgument((key.to_owned(), value.to_owned()))
71 })?;
72 }
73 Some((key @ "--trace-children", value)) => {
74 self.trace_children = yesno_to_bool(value).ok_or_else(|| {
75 Error::InvalidBoolArgument((key.to_owned(), value.to_owned()))
76 })?;
77 }
78 Some((key @ "--separate-threads", value)) => {
79 self.separate_threads = yesno_to_bool(value).ok_or_else(|| {
80 Error::InvalidBoolArgument((key.to_owned(), value.to_owned()))
81 })?;
82 }
83 Some(("--fair-sched", value)) => {
84 self.fair_sched = FairSched::from_str(value)?;
85 }
86 Some((
87 key @ ("--combine-dumps"
88 | "--callgrind-out-file"
89 | "--compress-strings"
90 | "--compress-pos"
91 | "--log-file"
92 | "--log-fd"
93 | "--log-socket"
94 | "--xml"
95 | "--xml-file"
96 | "--xml-fd"
97 | "--xml-socket"
98 | "--xml-user-comment"
99 | "--tool"),
100 value,
101 )) => {
102 warn!("Ignoring callgrind argument: '{}={}'", key, value);
103 }
104 Some(_) => self.other.push(arg.clone()),
105 None if arg == "-v" || arg == "--verbose" => self.verbose = true,
106 None if matches!(
107 arg.trim(),
108 "-h" | "--help"
109 | "--help-dyn-options"
110 | "--help-debug"
111 | "--version"
112 | "-q"
113 | "--quiet"
114 ) =>
115 {
116 warn!("Ignoring callgrind argument: '{arg}'");
117 }
118 None if arg.starts_with('-') => self.other.push(arg.clone()),
119 None => {}
122 }
123 }
124 Ok(())
125 }
126
127 pub fn insert_toggle_collect(&mut self, arg: &str) {
131 self.toggle_collect.push_front(arg.to_owned());
132 }
133}
134
135impl Default for Args {
136 fn default() -> Self {
137 Self {
138 i1: String::from("32768,8,64"),
142 d1: String::from("32768,8,64"),
143 ll: String::from("8388608,16,64"),
144 cache_sim: true,
145 compress_pos: false,
146 compress_strings: false,
147 combine_dumps: false,
148 verbose: log_enabled!(log::Level::Debug),
149 dump_line: true,
150 dump_instr: false,
151 toggle_collect: VecDeque::default(),
152 callgrind_out_file: Option::default(),
153 log_arg: Option::default(),
154 other: Vec::default(),
155 trace_children: true,
156 separate_threads: true,
157 fair_sched: FairSched::Try,
158 }
159 }
160}
161
162impl From<Args> for tool::args::ToolArgs {
163 fn from(mut value: Args) -> Self {
164 let mut other = vec![
165 format!("--I1={}", &value.i1),
166 format!("--D1={}", &value.d1),
167 format!("--LL={}", &value.ll),
168 format!("--cache-sim={}", bool_to_yesno(value.cache_sim)),
169 format!(
170 "--compress-strings={}",
171 bool_to_yesno(value.compress_strings)
172 ),
173 format!("--compress-pos={}", bool_to_yesno(value.compress_pos)),
174 format!("--dump-line={}", bool_to_yesno(value.dump_line)),
175 format!("--dump-instr={}", bool_to_yesno(value.dump_instr)),
176 format!("--combine-dumps={}", bool_to_yesno(value.combine_dumps)),
177 format!(
178 "--separate-threads={}",
179 bool_to_yesno(value.separate_threads)
180 ),
181 ];
182 other.append(
183 &mut value
184 .toggle_collect
185 .iter()
186 .map(|s| format!("--toggle-collect={s}"))
187 .collect::<Vec<String>>(),
188 );
189 other.append(&mut value.other);
190
191 Self {
192 tool: tool::ValgrindTool::Callgrind,
193 output_paths: value
194 .callgrind_out_file
195 .map_or_else(Vec::new, |o| vec![o.into()]),
196 log_path: value.log_arg,
197 error_exitcode: "0".to_owned(),
198 verbose: value.verbose,
199 trace_children: value.trace_children,
200 fair_sched: value.fair_sched,
201 other,
202 }
203 }
204}