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