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(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str)41 fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str) { 42 let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION); 43 // Record ETM data for kernel space only when it's not filtered out by binary_filter. So we 44 // can get more ETM data for user space when ETM data for kernel space isn't needed. 45 let event_name = if binary_filter.contains("kernel") { "cs-etm" } else { "cs-etm:u" }; 46 let duration: String = sampling_period.as_secs_f64().to_string(); 47 let args: Vec<&str> = vec![ 48 "-a", 49 "-e", 50 event_name, 51 "--duration", 52 &duration, 53 "--decode-etm", 54 "--exclude-perf", 55 "--binary", 56 binary_filter, 57 "--no-dump-symbols", 58 "--no-dump-kernel-symbols", 59 "-o", 60 trace_file.to_str().unwrap(), 61 ]; 62 63 simpleperf_profcollect::run_record_cmd(&args); 64 } 65 process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>66 fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> { 67 let is_etm_extension = |file: &PathBuf| { 68 file.extension() 69 .and_then(|f| f.to_str()) 70 .filter(|ext| ext == &ETM_TRACEFILE_EXTENSION) 71 .is_some() 72 }; 73 74 let process_trace_file = |trace_file: PathBuf| { 75 let mut profile_file = PathBuf::from(profile_dir); 76 profile_file.push( 77 trace_file 78 .file_name() 79 .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?, 80 ); 81 profile_file.set_extension(ETM_PROFILE_EXTENSION); 82 83 let args: Vec<&str> = vec![ 84 "-i", 85 trace_file.to_str().unwrap(), 86 "-o", 87 profile_file.to_str().unwrap(), 88 "--output", 89 "branch-list", 90 "--binary", 91 binary_filter, 92 ]; 93 simpleperf_profcollect::run_inject_cmd(&args); 94 remove_file(&trace_file)?; 95 Ok(()) 96 }; 97 98 read_dir(trace_dir)? 99 .filter_map(|e| e.ok()) 100 .map(|e| e.path()) 101 .filter(|e| e.is_file()) 102 .filter(is_etm_extension) 103 .try_for_each(process_trace_file) 104 } 105 set_log_file(&self, filename: &Path)106 fn set_log_file(&self, filename: &Path) { 107 simpleperf_profcollect::set_log_file(filename); 108 } 109 reset_log_file(&self)110 fn reset_log_file(&self) { 111 simpleperf_profcollect::reset_log_file(); 112 } 113 } 114 115 impl SimpleperfEtmTraceProvider { supported() -> bool116 pub fn supported() -> bool { 117 simpleperf_profcollect::is_etm_driver_available() 118 } 119 } 120