xref: /aosp_15_r20/system/core/init/libprefetch/prefetch/src/args/args_argh.rs (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::{option::Option, path::PathBuf, result::Result::Ok, str::FromStr};
16 
17 use argh::FromArgs;
18 use serde::Deserialize;
19 
20 use crate::args::DEFAULT_EXIT_ON_ERROR;
21 use crate::args::DEFAULT_IO_DEPTH;
22 use crate::args::DEFAULT_MAX_FDS;
23 use crate::Error;
24 
25 /// prefetch-rs
26 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
27 pub struct MainArgs {
28     /// subcommands
29     #[argh(subcommand)]
30     pub nested: SubCommands,
31 }
32 
33 /// Sub commands for prefetch functions
34 #[derive(Eq, PartialEq, Debug, FromArgs)]
35 #[argh(subcommand)]
36 pub enum SubCommands {
37     /// Records prefetch data.
38     Record(RecordArgs),
39     /// Replays from prefetch data
40     Replay(ReplayArgs),
41     /// Dump prefetch data in human readable format
42     Dump(DumpArgs),
43     /// Start prefetch service if possible
44     /// If the pack file is present, then prefetch replay is started
45     /// If the pack file is absent or if the build fingerprint
46     /// of the current pack file is different, then prefetch record is started.
47     #[cfg(target_os = "android")]
48     Start(StartArgs),
49 }
50 
51 #[cfg(target_os = "android")]
default_ready_path() -> PathBuf52 fn default_ready_path() -> PathBuf {
53     PathBuf::from("/metadata/prefetch/prefetch_ready")
54 }
55 
56 #[cfg(target_os = "android")]
default_build_finger_print_path() -> PathBuf57 fn default_build_finger_print_path() -> PathBuf {
58     PathBuf::from("/metadata/prefetch/build_finger_print")
59 }
60 
61 #[cfg(target_os = "android")]
62 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
63 /// Start prefetch service based on if pack file is present.
64 #[argh(subcommand, name = "start")]
65 pub struct StartArgs {
66     /// file path to check if prefetch_ready is present.
67     ///
68     /// A new file is created at the given path if it's not present.
69     #[argh(option, default = "default_ready_path()")]
70     pub path: PathBuf,
71 
72     /// file path where build fingerprint is stored
73     #[argh(option, default = "default_build_finger_print_path()")]
74     pub build_fingerprint_path: PathBuf,
75 }
76 
77 impl Default for SubCommands {
default() -> Self78     fn default() -> Self {
79         Self::Dump(DumpArgs::default())
80     }
81 }
82 
default_path() -> PathBuf83 fn default_path() -> PathBuf {
84     PathBuf::from("/metadata/prefetch/prefetch.pack")
85 }
86 
parse_tracing_instance(value: &str) -> Result<Option<String>, String>87 fn parse_tracing_instance(value: &str) -> Result<Option<String>, String> {
88     Ok(Some(value.to_string()))
89 }
90 
91 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
92 /// Records prefect data.
93 #[argh(subcommand, name = "record")]
94 pub struct RecordArgs {
95     /// duration in seconds to record the data
96     ///
97     /// On Android, if duration count is set to zero, recording
98     /// will continue until the property sys.boot_completed = 1.
99     #[argh(option)]
100     pub duration: u16,
101 
102     /// file path where the records will be written to
103     ///
104     /// A new file is created at the given path. If the path exists, it
105     /// will be overwritten
106     #[argh(option, default = "default_path()")]
107     pub path: PathBuf,
108 
109     /// when set an intermediate file will be created that provides more information
110     /// about collected data.
111     #[argh(option, default = "false")]
112     pub debug: bool,
113 
114     /// file path where the intermediate file will be written to
115     ///
116     /// A new file is created at the given path. Errors out if the file
117     /// already exists.
118     #[argh(option)]
119     pub int_path: Option<PathBuf>,
120 
121     /// size of the trace buffer which holds trace events. We need larger
122     /// buffer on a system that has faster disks or has large number of events
123     /// enabled. Defaults to TRACE_BUFFER_SIZE_KIB KiB.
124     #[argh(option, long = "trace-buffer-size")]
125     pub trace_buffer_size_kib: Option<u64>,
126 
127     /// trace subsystem to use. "mem" subsystem is set by default.
128     #[argh(option, default = "Default::default()")]
129     pub tracing_subsystem: TracerType,
130 
131     /// if true enables all the needed trace events. And at the end it restores
132     /// the values of those events.
133     /// If false, assumes that user has setup the needed trace events.
134     #[argh(option, default = "true")]
135     pub setup_tracing: bool,
136 
137     /// if specified, works on a tracing instance (like /sys/kernel/tracing/instance/my_instance)
138     /// rather than using on shared global instance (i.e. /sys/kernel/tracing)."
139     #[argh(
140         option,
141         default = "Some(\"prefetch\".to_string())",
142         from_str_fn(parse_tracing_instance)
143     )]
144     pub tracing_instance: Option<String>,
145 
146     #[cfg(target_os = "android")]
147     /// store build_finger_print to tie the pack format
148     #[argh(option, default = "default_build_finger_print_path()")]
149     pub build_fingerprint_path: PathBuf,
150 }
151 
152 /// Type of tracing subsystem to use.
153 #[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
154 pub enum TracerType {
155     /// mem tracing subsystem relies on when a file's in-memory page gets added to the fs cache.
156     Mem,
157 }
158 
159 impl FromStr for TracerType {
160     type Err = Error;
from_str(s: &str) -> std::result::Result<Self, Self::Err>161     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
162         Ok(match s.to_lowercase().as_str() {
163             "mem" => Self::Mem,
164             _ => {
165                 return Err(Error::InvalidArgs {
166                     arg_name: "tracing_subsystem".to_owned(),
167                     arg_value: s.to_owned(),
168                     error: "unknown value".to_owned(),
169                 })
170             }
171         })
172     }
173 }
174 
175 impl Default for TracerType {
default() -> Self176     fn default() -> Self {
177         Self::Mem
178     }
179 }
180 
181 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
182 /// Prefetch data from the recorded file.
183 #[argh(subcommand, name = "replay")]
184 pub struct ReplayArgs {
185     /// file path from where the records will be read
186     #[argh(option, default = "default_path()")]
187     pub path: PathBuf,
188 
189     /// IO depth. Number of IO that can go in parallel.
190     #[argh(option, long = "io-depth", default = "DEFAULT_IO_DEPTH")]
191     pub io_depth: u16,
192 
193     /// max number of open fds to cache
194     #[argh(option, arg_name = "max-fds", default = "DEFAULT_MAX_FDS")]
195     pub max_fds: u16,
196 
197     /// if true, command exits on encountering any error.
198     ///
199     /// This defaults to false as there is not harm prefetching if we encounter
200     /// non-fatal errors.
201     #[argh(option, default = "DEFAULT_EXIT_ON_ERROR")]
202     pub exit_on_error: bool,
203 
204     /// file path from where the prefetch config file will be read
205     #[argh(option, default = "PathBuf::new()")]
206     pub config_path: PathBuf,
207 }
208 
209 /// dump records file in given format
210 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
211 #[argh(subcommand, name = "dump")]
212 pub struct DumpArgs {
213     /// file path from where the records will be read
214     #[argh(option)]
215     pub path: PathBuf,
216     /// output format. One of json or csv.
217     /// Note: In csv format, few fields are excluded from the output.
218     #[argh(option)]
219     pub format: OutputFormat,
220 }
221 
222 #[derive(Deserialize, Eq, PartialEq, Debug)]
223 pub enum OutputFormat {
224     Json,
225     Csv,
226 }
227 
228 impl FromStr for OutputFormat {
229     type Err = Error;
from_str(s: &str) -> std::result::Result<Self, Self::Err>230     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
231         Ok(match s.to_lowercase().as_str() {
232             "csv" => Self::Csv,
233             "json" => Self::Json,
234             _ => {
235                 return Err(Error::InvalidArgs {
236                     arg_name: "format".to_owned(),
237                     arg_value: s.to_owned(),
238                     error: "unknown value".to_owned(),
239                 })
240             }
241         })
242     }
243 }
244 
245 impl Default for OutputFormat {
default() -> Self246     fn default() -> Self {
247         Self::Json
248     }
249 }
250 
251 /// Build args struct from command line arguments
args_from_env() -> MainArgs252 pub fn args_from_env() -> MainArgs {
253     argh::from_env()
254 }
255