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 }
44
45 #[cfg(target_os = "android")]
default_ready_path() -> PathBuf46 fn default_ready_path() -> PathBuf {
47 PathBuf::from("/metadata/prefetch/prefetch_ready")
48 }
49
50 #[cfg(target_os = "android")]
default_build_finger_print_path() -> PathBuf51 fn default_build_finger_print_path() -> PathBuf {
52 PathBuf::from("/metadata/prefetch/build_finger_print")
53 }
54
55 impl Default for SubCommands {
default() -> Self56 fn default() -> Self {
57 Self::Dump(DumpArgs::default())
58 }
59 }
60
default_path() -> PathBuf61 fn default_path() -> PathBuf {
62 PathBuf::from("/metadata/prefetch/prefetch.pack")
63 }
64
parse_tracing_instance(value: &str) -> Result<Option<String>, String>65 fn parse_tracing_instance(value: &str) -> Result<Option<String>, String> {
66 Ok(Some(value.to_string()))
67 }
68
69 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
70 /// Records prefect data.
71 #[argh(subcommand, name = "record")]
72 pub struct RecordArgs {
73 /// duration in seconds to record the data
74 ///
75 /// On Android, if duration count is set to zero, recording
76 /// will continue until the property sys.boot_completed = 1.
77 #[argh(option)]
78 pub duration: u16,
79
80 /// file path where the records will be written to
81 ///
82 /// A new file is created at the given path. If the path exists, it
83 /// will be overwritten
84 #[argh(option, default = "default_path()")]
85 pub path: PathBuf,
86
87 /// when set an intermediate file will be created that provides more information
88 /// about collected data.
89 #[argh(option, default = "false")]
90 pub debug: bool,
91
92 /// file path where the intermediate file will be written to
93 ///
94 /// A new file is created at the given path. Errors out if the file
95 /// already exists.
96 #[argh(option)]
97 pub int_path: Option<PathBuf>,
98
99 /// size of the trace buffer which holds trace events. We need larger
100 /// buffer on a system that has faster disks or has large number of events
101 /// enabled. Defaults to TRACE_BUFFER_SIZE_KIB KiB.
102 #[argh(option, long = "trace-buffer-size")]
103 pub trace_buffer_size_kib: Option<u64>,
104
105 /// trace subsystem to use. "mem" subsystem is set by default.
106 #[argh(option, default = "Default::default()")]
107 pub tracing_subsystem: TracerType,
108
109 /// if true enables all the needed trace events. And at the end it restores
110 /// the values of those events.
111 /// If false, assumes that user has setup the needed trace events.
112 #[argh(option, default = "true")]
113 pub setup_tracing: bool,
114
115 /// if specified, works on a tracing instance (like /sys/kernel/tracing/instance/my_instance)
116 /// rather than using on shared global instance (i.e. /sys/kernel/tracing)."
117 #[argh(
118 option,
119 default = "Some(\"prefetch\".to_string())",
120 from_str_fn(parse_tracing_instance)
121 )]
122 pub tracing_instance: Option<String>,
123
124 #[cfg(target_os = "android")]
125 /// store build_finger_print to tie the pack format
126 #[argh(option, default = "default_build_finger_print_path()")]
127 pub build_fingerprint_path: PathBuf,
128
129 #[cfg(target_os = "android")]
130 /// file path to check if prefetch_ready is present.
131 ///
132 /// A new file is created at the given path if it's not present.
133 #[argh(option, default = "default_ready_path()")]
134 pub ready_path: PathBuf,
135 }
136
137 /// Type of tracing subsystem to use.
138 #[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
139 pub enum TracerType {
140 /// mem tracing subsystem relies on when a file's in-memory page gets added to the fs cache.
141 Mem,
142 }
143
144 impl FromStr for TracerType {
145 type Err = Error;
from_str(s: &str) -> std::result::Result<Self, Self::Err>146 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
147 Ok(match s.to_lowercase().as_str() {
148 "mem" => Self::Mem,
149 _ => {
150 return Err(Error::InvalidArgs {
151 arg_name: "tracing_subsystem".to_owned(),
152 arg_value: s.to_owned(),
153 error: "unknown value".to_owned(),
154 })
155 }
156 })
157 }
158 }
159
160 impl Default for TracerType {
default() -> Self161 fn default() -> Self {
162 Self::Mem
163 }
164 }
165
166 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
167 /// Prefetch data from the recorded file.
168 #[argh(subcommand, name = "replay")]
169 pub struct ReplayArgs {
170 /// file path from where the records will be read
171 #[argh(option, default = "default_path()")]
172 pub path: PathBuf,
173
174 /// IO depth. Number of IO that can go in parallel.
175 #[argh(option, long = "io-depth", default = "DEFAULT_IO_DEPTH")]
176 pub io_depth: u16,
177
178 /// max number of open fds to cache
179 #[argh(option, arg_name = "max-fds", default = "DEFAULT_MAX_FDS")]
180 pub max_fds: u16,
181
182 /// if true, command exits on encountering any error.
183 ///
184 /// This defaults to false as there is not harm prefetching if we encounter
185 /// non-fatal errors.
186 #[argh(option, default = "DEFAULT_EXIT_ON_ERROR")]
187 pub exit_on_error: bool,
188
189 /// file path from where the prefetch config file will be read
190 #[argh(option, default = "PathBuf::new()")]
191 pub config_path: PathBuf,
192
193 #[cfg(target_os = "android")]
194 /// store build_finger_print to tie the pack format
195 #[argh(option, default = "default_build_finger_print_path()")]
196 pub build_fingerprint_path: PathBuf,
197 }
198
199 /// dump records file in given format
200 #[derive(Eq, PartialEq, Debug, Default, FromArgs)]
201 #[argh(subcommand, name = "dump")]
202 pub struct DumpArgs {
203 /// file path from where the records will be read
204 #[argh(option)]
205 pub path: PathBuf,
206 /// output format. One of json or csv.
207 /// Note: In csv format, few fields are excluded from the output.
208 #[argh(option)]
209 pub format: OutputFormat,
210 }
211
212 #[derive(Deserialize, Eq, PartialEq, Debug)]
213 pub enum OutputFormat {
214 Json,
215 Csv,
216 }
217
218 impl FromStr for OutputFormat {
219 type Err = Error;
from_str(s: &str) -> std::result::Result<Self, Self::Err>220 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
221 Ok(match s.to_lowercase().as_str() {
222 "csv" => Self::Csv,
223 "json" => Self::Json,
224 _ => {
225 return Err(Error::InvalidArgs {
226 arg_name: "format".to_owned(),
227 arg_value: s.to_owned(),
228 error: "unknown value".to_owned(),
229 })
230 }
231 })
232 }
233 }
234
235 impl Default for OutputFormat {
default() -> Self236 fn default() -> Self {
237 Self::Json
238 }
239 }
240
241 /// Build args struct from command line arguments
args_from_env() -> MainArgs242 pub fn args_from_env() -> MainArgs {
243 argh::from_env()
244 }
245