xref: /aosp_15_r20/system/extras/profcollectd/libprofcollectd/trace_provider/simpleperf_etm.rs (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1 //
2 // Copyright (C) 2021 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 //! Trace provider backed by ARM Coresight ETM, using simpleperf tool.
18 
19 use anyhow::{anyhow, Result};
20 use std::fs::{read_dir, remove_file};
21 use std::path::{Path, PathBuf};
22 use std::time::Duration;
23 use trace_provider::TraceProvider;
24 
25 use crate::trace_provider;
26 
27 static ETM_TRACEFILE_EXTENSION: &str = "etmtrace";
28 static ETM_PROFILE_EXTENSION: &str = "data";
29 
30 pub struct SimpleperfEtmTraceProvider {}
31 
32 impl TraceProvider for SimpleperfEtmTraceProvider {
get_name(&self) -> &'static str33     fn get_name(&self) -> &'static str {
34         "simpleperf_etm"
35     }
36 
is_ready(&self) -> bool37     fn is_ready(&self) -> bool {
38         simpleperf_profcollect::is_etm_device_available()
39     }
40 
trace_system( &self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str, )41     fn trace_system(
42         &self,
43         trace_dir: &Path,
44         tag: &str,
45         sampling_period: &Duration,
46         binary_filter: &str,
47     ) {
48         let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION);
49         // Record ETM data for kernel space only when it's not filtered out by binary_filter. So we
50         // can get more ETM data for user space when ETM data for kernel space isn't needed.
51         let event_name = if binary_filter.contains("kernel") { "cs-etm" } else { "cs-etm:u" };
52         let duration: String = sampling_period.as_secs_f64().to_string();
53         let args: Vec<&str> = vec![
54             "-a",
55             "-e",
56             event_name,
57             "--duration",
58             &duration,
59             "-z",
60             "--binary",
61             binary_filter,
62             "--no-dump-build-id",
63             "--no-dump-symbols",
64             "--no-dump-kernel-symbols",
65             "-o",
66             trace_file.to_str().unwrap(),
67         ];
68         simpleperf_profcollect::run_record_cmd(&args);
69     }
70 
trace_process( &self, trace_dir: &Path, tag: &str, sampling_period: &Duration, processes: &str, )71     fn trace_process(
72         &self,
73         trace_dir: &Path,
74         tag: &str,
75         sampling_period: &Duration,
76         processes: &str,
77     ) {
78         let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION);
79         let event_name = "cs-etm:u";
80         let duration: String = sampling_period.as_secs_f64().to_string();
81         let args: Vec<&str> = vec![
82             "-p",
83             processes,
84             "-e",
85             event_name,
86             "--duration",
87             &duration,
88             "-z",
89             "--no-dump-symbols",
90             "-o",
91             trace_file.to_str().unwrap(),
92         ];
93         simpleperf_profcollect::run_record_cmd(&args);
94     }
95 
process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>96     fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> {
97         let is_etm_extension = |file: &PathBuf| {
98             file.extension()
99                 .and_then(|f| f.to_str())
100                 .filter(|ext| ext == &ETM_TRACEFILE_EXTENSION)
101                 .is_some()
102         };
103 
104         let process_trace_file = |trace_file: PathBuf| {
105             let mut profile_file = PathBuf::from(profile_dir);
106             profile_file.push(
107                 trace_file
108                     .file_name()
109                     .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?,
110             );
111             profile_file.set_extension(ETM_PROFILE_EXTENSION);
112 
113             let args: Vec<&str> = vec![
114                 "-i",
115                 trace_file.to_str().unwrap(),
116                 "-o",
117                 profile_file.to_str().unwrap(),
118                 "--output",
119                 "branch-list",
120                 "--binary",
121                 binary_filter,
122                 "--exclude-perf",
123             ];
124             simpleperf_profcollect::run_inject_cmd(&args);
125             remove_file(&trace_file)?;
126             Ok(())
127         };
128 
129         read_dir(trace_dir)?
130             .filter_map(|e| e.ok())
131             .map(|e| e.path())
132             .filter(|e| e.is_file())
133             .filter(is_etm_extension)
134             .try_for_each(process_trace_file)
135     }
136 
set_log_file(&self, filename: &Path)137     fn set_log_file(&self, filename: &Path) {
138         simpleperf_profcollect::set_log_file(filename);
139     }
140 
reset_log_file(&self)141     fn reset_log_file(&self) {
142         simpleperf_profcollect::reset_log_file();
143     }
144 }
145 
146 impl SimpleperfEtmTraceProvider {
supported() -> bool147     pub fn supported() -> bool {
148         simpleperf_profcollect::is_etm_driver_available()
149     }
150 }
151