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::has_device_support() 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 record_scope = if binary_filter.contains("kernel") { 46 simpleperf_profcollect::RecordScope::BOTH 47 } else { 48 simpleperf_profcollect::RecordScope::USERSPACE 49 }; 50 51 simpleperf_profcollect::record(&trace_file, sampling_period, binary_filter, record_scope); 52 } 53 process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>54 fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> { 55 let is_etm_extension = |file: &PathBuf| { 56 file.extension() 57 .and_then(|f| f.to_str()) 58 .filter(|ext| ext == &ETM_TRACEFILE_EXTENSION) 59 .is_some() 60 }; 61 62 let process_trace_file = |trace_file: PathBuf| { 63 let mut profile_file = PathBuf::from(profile_dir); 64 profile_file.push( 65 trace_file 66 .file_name() 67 .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?, 68 ); 69 profile_file.set_extension(ETM_PROFILE_EXTENSION); 70 simpleperf_profcollect::process(&trace_file, &profile_file, binary_filter); 71 remove_file(&trace_file)?; 72 Ok(()) 73 }; 74 75 read_dir(trace_dir)? 76 .filter_map(|e| e.ok()) 77 .map(|e| e.path()) 78 .filter(|e| e.is_file()) 79 .filter(is_etm_extension) 80 .try_for_each(process_trace_file) 81 } 82 set_log_file(&self, filename: &Path)83 fn set_log_file(&self, filename: &Path) { 84 simpleperf_profcollect::set_log_file(filename); 85 } 86 reset_log_file(&self)87 fn reset_log_file(&self) { 88 simpleperf_profcollect::reset_log_file(); 89 } 90 } 91 92 impl SimpleperfEtmTraceProvider { supported() -> bool93 pub fn supported() -> bool { 94 simpleperf_profcollect::has_driver_support() 95 } 96 } 97