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