summaryrefslogtreecommitdiff
path: root/profcollectd
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2022-02-09 18:09:59 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-02-09 18:09:59 +0000
commitd9d70c8fb612d61f990f6ae5be2b2f29e07bcc71 (patch)
treea8d5e6a1d53af37eaf5f3b8c49a21a7de1daab72 /profcollectd
parente3f9772919c1c6407f25300f17d0cf088a9201cc (diff)
parentf158a752cf96f9d710314731c6cdc407230a80f6 (diff)
downloadextras-d9d70c8fb612d61f990f6ae5be2b2f29e07bcc71.tar.gz
Diffstat (limited to 'profcollectd')
-rw-r--r--profcollectd/Android.bp1
-rw-r--r--profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl3
-rw-r--r--profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl22
-rw-r--r--profcollectd/libprofcollectd/lib.rs32
-rw-r--r--profcollectd/libprofcollectd/logging_trace_provider.rs4
-rw-r--r--profcollectd/libprofcollectd/scheduler.rs54
-rw-r--r--profcollectd/libprofcollectd/service.rs29
-rw-r--r--profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs6
-rw-r--r--profcollectd/libprofcollectd/trace_provider.rs1
9 files changed, 145 insertions, 7 deletions
diff --git a/profcollectd/Android.bp b/profcollectd/Android.bp
index f1723006..122e4f61 100644
--- a/profcollectd/Android.bp
+++ b/profcollectd/Android.bp
@@ -59,6 +59,7 @@ filegroup {
name: "profcollectd_aidl",
srcs: [
"binder/com/android/server/profcollect/IProfCollectd.aidl",
+ "binder/com/android/server/profcollect/IProviderStatusCallback.aidl",
],
path: "binder",
}
diff --git a/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl b/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl
index c8f33a1e..bfc24446 100644
--- a/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl
+++ b/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl
@@ -16,6 +16,8 @@
package com.android.server.profcollect;
+import com.android.server.profcollect.IProviderStatusCallback;
+
/** {@hide} */
interface IProfCollectd {
void schedule();
@@ -24,4 +26,5 @@ interface IProfCollectd {
void process();
@utf8InCpp String report();
@utf8InCpp String get_supported_provider();
+ void registerProviderStatusCallback(IProviderStatusCallback cb);
}
diff --git a/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl b/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl
new file mode 100644
index 00000000..b311cf91
--- /dev/null
+++ b/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package com.android.server.profcollect;
+
+/** {@hide} */
+oneway interface IProviderStatusCallback {
+ void onProviderReady();
+}
diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs
index abc11272..f95132f4 100644
--- a/profcollectd/libprofcollectd/lib.rs
+++ b/profcollectd/libprofcollectd/lib.rs
@@ -30,11 +30,34 @@ use anyhow::{Context, Result};
use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::{
self, BnProfCollectd,
};
+use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::{IProviderStatusCallback, BnProviderStatusCallback};
use profcollectd_aidl_interface::binder::{self, BinderFeatures};
-use service::ProfcollectdBinderService;
+use service::{err_to_binder_status, ProfcollectdBinderService};
+use std::time::{Duration, Instant};
const PROFCOLLECTD_SERVICE_NAME: &str = "profcollectd";
+struct ProviderStatusCallback {
+ service_start_time: Instant,
+}
+
+impl binder::Interface for ProviderStatusCallback {}
+
+impl IProviderStatusCallback for ProviderStatusCallback {
+ fn onProviderReady(&self) -> binder::Result<()> {
+ // If we have waited too long for the provider to be ready, then we have passed
+ // boot phase, and no need to collect boot profile.
+ // TODO: should we check boottime instead?
+ const TIMEOUT_TO_COLLECT_BOOT_PROFILE: Duration = Duration::from_secs(3);
+ let elapsed = Instant::now().duration_since(self.service_start_time);
+ if elapsed < TIMEOUT_TO_COLLECT_BOOT_PROFILE {
+ trace_once("boot").map_err(err_to_binder_status)?;
+ }
+ schedule().map_err(err_to_binder_status)?;
+ Ok(())
+ }
+}
+
/// Initialise profcollectd service.
/// * `schedule_now` - Immediately schedule collection after service is initialised.
pub fn init_service(schedule_now: bool) -> Result<()> {
@@ -49,8 +72,11 @@ pub fn init_service(schedule_now: bool) -> Result<()> {
.context("Failed to register service.")?;
if schedule_now {
- trace_once("boot")?;
- schedule()?;
+ let cb = BnProviderStatusCallback::new_binder(
+ ProviderStatusCallback { service_start_time: Instant::now() },
+ BinderFeatures::default(),
+ );
+ get_profcollectd_service()?.registerProviderStatusCallback(&cb)?;
}
binder::ProcessState::join_thread_pool();
diff --git a/profcollectd/libprofcollectd/logging_trace_provider.rs b/profcollectd/libprofcollectd/logging_trace_provider.rs
index 1325855d..fda4c66a 100644
--- a/profcollectd/libprofcollectd/logging_trace_provider.rs
+++ b/profcollectd/libprofcollectd/logging_trace_provider.rs
@@ -32,6 +32,10 @@ impl TraceProvider for LoggingTraceProvider {
"logging"
}
+ fn is_ready(&self) -> bool {
+ true
+ }
+
fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) {
let trace_file = trace_provider::get_path(trace_dir, tag, LOGGING_TRACEFILE_EXTENSION);
diff --git a/profcollectd/libprofcollectd/scheduler.rs b/profcollectd/libprofcollectd/scheduler.rs
index 31a495a5..f58c4995 100644
--- a/profcollectd/libprofcollectd/scheduler.rs
+++ b/profcollectd/libprofcollectd/scheduler.rs
@@ -17,11 +17,13 @@
//! ProfCollect tracing scheduler.
use std::fs;
+use std::mem;
use std::path::Path;
use std::sync::mpsc::{sync_channel, SyncSender};
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
+use std::time::{Duration, Instant};
use crate::config::{Config, PROFILE_OUTPUT_DIR, TRACE_OUTPUT_DIR};
use crate::trace_provider::{self, TraceProvider};
@@ -33,12 +35,17 @@ pub struct Scheduler {
termination_ch: Option<SyncSender<()>>,
/// The preferred trace provider for the system.
trace_provider: Arc<Mutex<dyn TraceProvider + Send>>,
+ provider_ready_callbacks: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>,
}
impl Scheduler {
pub fn new() -> Result<Self> {
let p = trace_provider::get_trace_provider()?;
- Ok(Scheduler { termination_ch: None, trace_provider: p })
+ Ok(Scheduler {
+ termination_ch: None,
+ trace_provider: p,
+ provider_ready_callbacks: Arc::new(Mutex::new(Vec::new())),
+ })
}
fn is_scheduled(&self) -> bool {
@@ -106,6 +113,51 @@ impl Scheduler {
pub fn get_trace_provider_name(&self) -> &'static str {
self.trace_provider.lock().unwrap().get_name()
}
+
+ pub fn is_provider_ready(&self) -> bool {
+ self.trace_provider.lock().unwrap().is_ready()
+ }
+
+ pub fn register_provider_ready_callback(&self, cb: Box<dyn FnOnce() + Send>) {
+ let mut locked_callbacks = self.provider_ready_callbacks.lock().unwrap();
+ locked_callbacks.push(cb);
+ if locked_callbacks.len() == 1 {
+ self.start_thread_waiting_for_provider_ready();
+ }
+ }
+
+ fn start_thread_waiting_for_provider_ready(&self) {
+ let provider = self.trace_provider.clone();
+ let callbacks = self.provider_ready_callbacks.clone();
+
+ thread::spawn(move || {
+ let start_time = Instant::now();
+ loop {
+ let elapsed = Instant::now().duration_since(start_time);
+ if provider.lock().unwrap().is_ready() {
+ break;
+ }
+ // Decide check period based on how long we have waited:
+ // For the first 10s waiting, check every 100ms (likely to work on EVT devices).
+ // For the first 10m waiting, check every 10s (likely to work on DVT devices).
+ // For others, check every 10m.
+ let sleep_duration = if elapsed < Duration::from_secs(10) {
+ Duration::from_millis(100)
+ } else if elapsed < Duration::from_secs(60 * 10) {
+ Duration::from_secs(10)
+ } else {
+ Duration::from_secs(60 * 10)
+ };
+ thread::sleep(sleep_duration);
+ }
+
+ let mut locked_callbacks = callbacks.lock().unwrap();
+ let v = mem::take(&mut *locked_callbacks);
+ for cb in v {
+ cb();
+ }
+ });
+ }
}
/// Run if space usage is under limit.
diff --git a/profcollectd/libprofcollectd/service.rs b/profcollectd/libprofcollectd/service.rs
index 0199c105..3f338024 100644
--- a/profcollectd/libprofcollectd/service.rs
+++ b/profcollectd/libprofcollectd/service.rs
@@ -18,8 +18,9 @@
use anyhow::{anyhow, Context, Error, Result};
use binder::Result as BinderResult;
-use binder::Status;
+use binder::{SpIBinder, Status};
use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd;
+use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::IProviderStatusCallback;
use std::ffi::CString;
use std::fs::{read_dir, read_to_string, remove_file, write};
use std::str::FromStr;
@@ -32,7 +33,7 @@ use crate::config::{
use crate::report::{get_report_ts, pack_report};
use crate::scheduler::Scheduler;
-fn err_to_binder_status(msg: Error) -> Status {
+pub fn err_to_binder_status(msg: Error) -> Status {
let msg = format!("{:#?}", msg);
let msg = CString::new(msg).expect("Failed to convert to CString");
Status::new_service_specific_error(1, Some(&msg))
@@ -89,6 +90,30 @@ impl IProfCollectd for ProfcollectdBinderService {
fn get_supported_provider(&self) -> BinderResult<String> {
Ok(self.lock().scheduler.get_trace_provider_name().to_string())
}
+
+ fn registerProviderStatusCallback(
+ &self,
+ cb: &binder::Strong<(dyn IProviderStatusCallback)>,
+ ) -> BinderResult<()> {
+ if self.lock().scheduler.is_provider_ready() {
+ if let Err(e) = cb.onProviderReady() {
+ log::error!("Failed to call ProviderStatusCallback {:?}", e);
+ }
+ return Ok(());
+ }
+
+ let cb_binder: SpIBinder = cb.as_binder();
+ self.lock().scheduler.register_provider_ready_callback(Box::new(move || {
+ if let Ok(cb) = cb_binder.into_interface::<dyn IProviderStatusCallback>() {
+ if let Err(e) = cb.onProviderReady() {
+ log::error!("Failed to call ProviderStatusCallback {:?}", e)
+ }
+ } else {
+ log::error!("SpIBinder is not a IProviderStatusCallback.");
+ }
+ }));
+ Ok(())
+ }
}
impl ProfcollectdBinderService {
diff --git a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
index 14fb7509..f25f5ffc 100644
--- a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
+++ b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
@@ -34,6 +34,10 @@ impl TraceProvider for SimpleperfEtmTraceProvider {
"simpleperf_etm"
}
+ fn is_ready(&self) -> bool {
+ simpleperf_profcollect::has_device_support()
+ }
+
fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) {
let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION);
@@ -76,6 +80,6 @@ impl TraceProvider for SimpleperfEtmTraceProvider {
impl SimpleperfEtmTraceProvider {
pub fn supported() -> bool {
- simpleperf_profcollect::has_support()
+ simpleperf_profcollect::has_driver_support()
}
}
diff --git a/profcollectd/libprofcollectd/trace_provider.rs b/profcollectd/libprofcollectd/trace_provider.rs
index 98cd5ec4..13059199 100644
--- a/profcollectd/libprofcollectd/trace_provider.rs
+++ b/profcollectd/libprofcollectd/trace_provider.rs
@@ -29,6 +29,7 @@ use crate::logging_trace_provider::LoggingTraceProvider;
pub trait TraceProvider {
fn get_name(&self) -> &'static str;
+ fn is_ready(&self) -> bool;
fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration);
fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>;
}