summaryrefslogtreecommitdiff
path: root/profcollectd
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2023-12-13 11:04:40 -0800
committerYabin Cui <yabinc@google.com>2023-12-13 16:37:40 -0800
commitffc25f88e6ccc8f802d7ee9dd8e573164e42e9e9 (patch)
tree28d64b1d6493068a093e26f2975b185510733fcb /profcollectd
parentc554c23e26433d85c3d1523763fddcf26e3f67ca (diff)
downloadextras-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')
-rw-r--r--profcollectd/libprofcollectd/lib.rs1
-rw-r--r--profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs39
-rw-r--r--profcollectd/libprofcollectd/simpleperf_lbr_trace_provider.rs117
-rw-r--r--profcollectd/libprofcollectd/trace_provider.rs5
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() {