1 // 2 // Copyright (C) 2023 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 Intel LBR, using simpleperf tool. 18 use anyhow::{anyhow, Result}; 19 use std::fs::{read_dir, remove_file}; 20 use std::path::{Path, PathBuf}; 21 use std::time::Duration; 22 use trace_provider::TraceProvider; 23 24 use crate::trace_provider; 25 26 static LBR_TRACEFILE_EXTENSION: &str = "lbrtrace"; 27 static LBR_PROFILE_EXTENSION: &str = "data"; 28 // Use a prime value to make sure that there are no weird interactions with e.g. short loops. 29 static LBR_SAMPLE_PERIOD: &str = "500009"; 30 31 pub struct SimpleperfLbrTraceProvider {} 32 33 impl TraceProvider for SimpleperfLbrTraceProvider { get_name(&self) -> &'static str34 fn get_name(&self) -> &'static str { 35 "simpleperf_lbr" 36 } 37 is_ready(&self) -> bool38 fn is_ready(&self) -> bool { 39 true 40 } 41 trace_system( &self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str, )42 fn trace_system( 43 &self, 44 trace_dir: &Path, 45 tag: &str, 46 sampling_period: &Duration, 47 binary_filter: &str, 48 ) { 49 let trace_file = trace_provider::get_path(trace_dir, tag, LBR_TRACEFILE_EXTENSION); 50 // Record ETM data for kernel space only when it's not filtered out by binary_filter. So we 51 // can get more ETM data for user space when ETM data for kernel space isn't needed. 52 let event_name = if binary_filter.contains("kernel") { 53 "BR_INST_RETIRED.NEAR_TAKEN" 54 } else { 55 "BR_INST_RETIRED.NEAR_TAKEN:u" 56 }; 57 let duration: String = sampling_period.as_secs_f64().to_string(); 58 let args: Vec<&str> = vec![ 59 "-a", 60 "-e", 61 event_name, 62 "-c", 63 LBR_SAMPLE_PERIOD, 64 "--duration", 65 &duration, 66 "-b", 67 "--exclude-perf", 68 "--binary", 69 binary_filter, 70 "--no-dump-symbols", 71 "--no-dump-kernel-symbols", 72 "-o", 73 trace_file.to_str().unwrap(), 74 ]; 75 simpleperf_profcollect::run_record_cmd(&args); 76 } 77 trace_process( &self, trace_dir: &Path, tag: &str, sampling_period: &Duration, processes: &str, )78 fn trace_process( 79 &self, 80 trace_dir: &Path, 81 tag: &str, 82 sampling_period: &Duration, 83 processes: &str, 84 ) { 85 let trace_file = trace_provider::get_path(trace_dir, tag, LBR_TRACEFILE_EXTENSION); 86 let event_name = "BR_INST_RETIRED.NEAR_TAKEN:u"; 87 let duration: String = sampling_period.as_secs_f64().to_string(); 88 let args: Vec<&str> = vec![ 89 "-p", 90 processes, 91 "-e", 92 event_name, 93 "-c", 94 LBR_SAMPLE_PERIOD, 95 "--duration", 96 &duration, 97 "-b", 98 "--no-dump-symbols", 99 "-o", 100 trace_file.to_str().unwrap(), 101 ]; 102 simpleperf_profcollect::run_record_cmd(&args); 103 } 104 process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>105 fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> { 106 let is_lbr_extension = |file: &PathBuf| { 107 file.extension() 108 .and_then(|f| f.to_str()) 109 .filter(|ext| ext == &LBR_TRACEFILE_EXTENSION) 110 .is_some() 111 }; 112 113 let process_trace_file = |trace_file: PathBuf| { 114 let mut profile_file = PathBuf::from(profile_dir); 115 profile_file.push( 116 trace_file 117 .file_name() 118 .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?, 119 ); 120 profile_file.set_extension(LBR_PROFILE_EXTENSION); 121 122 let args: Vec<&str> = vec![ 123 "-i", 124 trace_file.to_str().unwrap(), 125 "-o", 126 profile_file.to_str().unwrap(), 127 "--output", 128 "branch-list", 129 "--binary", 130 binary_filter, 131 ]; 132 simpleperf_profcollect::run_inject_cmd(&args); 133 remove_file(&trace_file)?; 134 Ok(()) 135 }; 136 137 read_dir(trace_dir)? 138 .filter_map(|e| e.ok()) 139 .map(|e| e.path()) 140 .filter(|e| e.is_file()) 141 .filter(is_lbr_extension) 142 .try_for_each(process_trace_file) 143 } 144 set_log_file(&self, filename: &Path)145 fn set_log_file(&self, filename: &Path) { 146 simpleperf_profcollect::set_log_file(filename); 147 } 148 reset_log_file(&self)149 fn reset_log_file(&self) { 150 simpleperf_profcollect::reset_log_file(); 151 } 152 } 153 154 impl SimpleperfLbrTraceProvider { supported() -> bool155 pub fn supported() -> bool { 156 simpleperf_profcollect::is_lbr_available() 157 } 158 } 159