diff options
author | Yabin Cui <yabinc@google.com> | 2023-12-13 11:04:40 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2023-12-13 16:37:40 -0800 |
commit | ffc25f88e6ccc8f802d7ee9dd8e573164e42e9e9 (patch) | |
tree | 28d64b1d6493068a093e26f2975b185510733fcb /profcollectd | |
parent | c554c23e26433d85c3d1523763fddcf26e3f67ca (diff) | |
download | extras-ffc25f88e6ccc8f802d7ee9dd8e573164e42e9e9.tar.gz |
profcollectd: Support collecting LBR data
Modify simpleperf interface and add simpleperf_lbr_trace_provider
to record LBR data.
Bug: 293953824
Test: run profcollectd manually
Change-Id: I8586a4a2a0b15d51badc34ef0011f519735a4836
Diffstat (limited to 'profcollectd')
4 files changed, 153 insertions, 9 deletions
diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs index c0e12e32..9923737f 100644 --- a/profcollectd/libprofcollectd/lib.rs +++ b/profcollectd/libprofcollectd/lib.rs @@ -21,6 +21,7 @@ mod report; mod scheduler; mod service; mod simpleperf_etm_trace_provider; +mod simpleperf_lbr_trace_provider; mod trace_provider; #[cfg(feature = "test")] diff --git a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs index 2239a182..ecb9770e 100644 --- a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs +++ b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs @@ -35,20 +35,30 @@ impl TraceProvider for SimpleperfEtmTraceProvider { } fn is_ready(&self) -> bool { - simpleperf_profcollect::has_device_support() + simpleperf_profcollect::is_etm_device_available() } fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str) { let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION); // Record ETM data for kernel space only when it's not filtered out by binary_filter. So we // can get more ETM data for user space when ETM data for kernel space isn't needed. - let record_scope = if binary_filter.contains("kernel") { - simpleperf_profcollect::RecordScope::BOTH - } else { - simpleperf_profcollect::RecordScope::USERSPACE - }; + let event_name = if binary_filter.contains("kernel") { "cs-etm" } else { "cs-etm:u" }; + let duration: String = sampling_period.as_secs_f64().to_string(); + let args: Vec<&str> = vec![ + "-a", + "-e", + event_name, + "--duration", + &duration, + "--decode-etm", + "--exclude-perf", + "--binary", + binary_filter, + "-o", + trace_file.to_str().unwrap(), + ]; - simpleperf_profcollect::record(&trace_file, sampling_period, binary_filter, record_scope); + simpleperf_profcollect::run_record_cmd(&args); } fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> { @@ -67,7 +77,18 @@ impl TraceProvider for SimpleperfEtmTraceProvider { .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?, ); profile_file.set_extension(ETM_PROFILE_EXTENSION); - simpleperf_profcollect::process(&trace_file, &profile_file, binary_filter); + + let args: Vec<&str> = vec![ + "-i", + trace_file.to_str().unwrap(), + "-o", + profile_file.to_str().unwrap(), + "--output", + "branch-list", + "--binary", + binary_filter, + ]; + simpleperf_profcollect::run_inject_cmd(&args); remove_file(&trace_file)?; Ok(()) }; @@ -91,6 +112,6 @@ impl TraceProvider for SimpleperfEtmTraceProvider { impl SimpleperfEtmTraceProvider { pub fn supported() -> bool { - simpleperf_profcollect::has_driver_support() + simpleperf_profcollect::is_etm_driver_available() } } diff --git a/profcollectd/libprofcollectd/simpleperf_lbr_trace_provider.rs b/profcollectd/libprofcollectd/simpleperf_lbr_trace_provider.rs new file mode 100644 index 00000000..e1fc0086 --- /dev/null +++ b/profcollectd/libprofcollectd/simpleperf_lbr_trace_provider.rs @@ -0,0 +1,117 @@ +// +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +//! Trace provider backed by Intel LBR, using simpleperf tool. +use anyhow::{anyhow, Result}; +use std::fs::{read_dir, remove_file}; +use std::path::{Path, PathBuf}; +use std::time::Duration; +use trace_provider::TraceProvider; + +use crate::trace_provider; + +static LBR_TRACEFILE_EXTENSION: &str = "lbrtrace"; +static LBR_PROFILE_EXTENSION: &str = "data"; + +pub struct SimpleperfLbrTraceProvider {} + +impl TraceProvider for SimpleperfLbrTraceProvider { + fn get_name(&self) -> &'static str { + "simpleperf_lbr" + } + + fn is_ready(&self) -> bool { + true + } + + fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration, binary_filter: &str) { + let trace_file = trace_provider::get_path(trace_dir, tag, LBR_TRACEFILE_EXTENSION); + // Record ETM data for kernel space only when it's not filtered out by binary_filter. So we + // can get more ETM data for user space when ETM data for kernel space isn't needed. + let event_name = + if binary_filter.contains("kernel") { "cpu-cycles" } else { "cpu-cycles:u" }; + let duration: String = sampling_period.as_secs_f64().to_string(); + let args: Vec<&str> = vec![ + "-a", + "-e", + event_name, + "--duration", + &duration, + "-b", + "--exclude-perf", + "--binary", + binary_filter, + "-o", + trace_file.to_str().unwrap(), + ]; + + simpleperf_profcollect::run_record_cmd(&args); + } + + fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()> { + let is_lbr_extension = |file: &PathBuf| { + file.extension() + .and_then(|f| f.to_str()) + .filter(|ext| ext == &LBR_TRACEFILE_EXTENSION) + .is_some() + }; + + let process_trace_file = |trace_file: PathBuf| { + let mut profile_file = PathBuf::from(profile_dir); + profile_file.push( + trace_file + .file_name() + .ok_or_else(|| anyhow!("Malformed trace path: {}", trace_file.display()))?, + ); + profile_file.set_extension(LBR_PROFILE_EXTENSION); + + let args: Vec<&str> = vec![ + "-i", + trace_file.to_str().unwrap(), + "-o", + profile_file.to_str().unwrap(), + "--output", + "branch-list", + "--binary", + binary_filter, + ]; + simpleperf_profcollect::run_inject_cmd(&args); + remove_file(&trace_file)?; + Ok(()) + }; + + read_dir(trace_dir)? + .filter_map(|e| e.ok()) + .map(|e| e.path()) + .filter(|e| e.is_file()) + .filter(is_lbr_extension) + .try_for_each(process_trace_file) + } + + fn set_log_file(&self, filename: &Path) { + simpleperf_profcollect::set_log_file(filename); + } + + fn reset_log_file(&self) { + simpleperf_profcollect::reset_log_file(); + } +} + +impl SimpleperfLbrTraceProvider { + pub fn supported() -> bool { + simpleperf_profcollect::is_lbr_available() + } +} diff --git a/profcollectd/libprofcollectd/trace_provider.rs b/profcollectd/libprofcollectd/trace_provider.rs index 133fa5cb..20906219 100644 --- a/profcollectd/libprofcollectd/trace_provider.rs +++ b/profcollectd/libprofcollectd/trace_provider.rs @@ -23,6 +23,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use crate::simpleperf_etm_trace_provider::SimpleperfEtmTraceProvider; +use crate::simpleperf_lbr_trace_provider::SimpleperfLbrTraceProvider; #[cfg(feature = "test")] use crate::logging_trace_provider::LoggingTraceProvider; @@ -41,6 +42,10 @@ pub fn get_trace_provider() -> Result<Arc<Mutex<dyn TraceProvider + Send>>> { log::info!("simpleperf_etm trace provider registered."); return Ok(Arc::new(Mutex::new(SimpleperfEtmTraceProvider {}))); } + if SimpleperfLbrTraceProvider::supported() { + log::info!("simpleperf_lbr trace provider registered."); + return Ok(Arc::new(Mutex::new(SimpleperfLbrTraceProvider {}))); + } #[cfg(feature = "test")] if LoggingTraceProvider::supported() { |