summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xboottime_tools/bootanalyze/bootanalyze.py132
-rw-r--r--boottime_tools/bootanalyze/config.yaml2
-rw-r--r--profcollectd/libprofcollectd/Android.bp3
-rw-r--r--profcollectd/libprofcollectd/config.rs25
-rw-r--r--profcollectd/libprofcollectd/lib.rs14
-rw-r--r--profcollectd/libprofcollectd/logging_trace_provider.rs56
-rw-r--r--profcollectd/libprofcollectd/scheduler.rs36
-rw-r--r--profcollectd/libprofcollectd/service.rs13
-rw-r--r--profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs6
-rw-r--r--profcollectd/libprofcollectd/trace_provider.rs19
-rw-r--r--profcollectd/profcollectctl.rs7
-rw-r--r--profcollectd/profcollectd.rc18
-rw-r--r--simpleperf/test_util.cpp1
13 files changed, 253 insertions, 79 deletions
diff --git a/boottime_tools/bootanalyze/bootanalyze.py b/boottime_tools/bootanalyze/bootanalyze.py
index 7eea05b9..5bed9f29 100755
--- a/boottime_tools/bootanalyze/bootanalyze.py
+++ b/boottime_tools/bootanalyze/bootanalyze.py
@@ -35,7 +35,6 @@ import yaml
from datetime import datetime, date
-
TIME_DMESG = r"\[\s*(\d+\.\d+)\]"
TIME_LOGCAT = r"[0-9]+\.?[0-9]*"
KERNEL_TIME_KEY = "kernel"
@@ -46,6 +45,7 @@ LAUNCHER_START = "LauncherStart"
BOOT_TIME_TOO_BIG = 200.0
MAX_RETRIES = 5
DEBUG = False
+DEBUG_PATTERN = False
ADB_CMD = "adb"
TIMING_THRESHOLD = 5.0
BOOT_PROP = r"\[ro\.boottime\.([^\]]+)\]:\s+\[(\d+)\]"
@@ -99,6 +99,8 @@ def main():
for key, pattern in cfg['timings'].items()}
shutdown_events_pattern = {key: re.compile(pattern)
for key, pattern in cfg['shutdown_events'].items()}
+ if DEBUG_PATTERN:
+ print("search event:{} timing event:{}".format(search_events_pattern, timing_events_pattern))
data_points = {}
kernel_timing_points = collections.OrderedDict()
@@ -301,6 +303,13 @@ def handle_reboot_log(capture_log_on_error, shutdown_events_pattern, components_
print('{0:30}: {1:<7.5}'.format(item[0], item[1]))
return shutdown_events, shutdown_timing_events
+def collect_dmesg_events(search_events_pattern, timings_pattern, results):
+ dmesg_events, kernel_timing_events = collect_events(search_events_pattern, ADB_CMD +\
+ ' shell su root dmesg -w', timings_pattern,\
+ [KERNEL_BOOT_COMPLETE], True)
+ results.append(dmesg_events)
+ results.append(kernel_timing_events)
+
def iterate(args, search_events_pattern, timings_pattern, shutdown_events_pattern, cfg, error_time,\
components_to_monitor):
shutdown_events = None
@@ -315,16 +324,22 @@ def iterate(args, search_events_pattern, timings_pattern, shutdown_events_patter
components_to_monitor)
t.join()
- dmesg_events, kernel_timing_events = collect_events(search_events_pattern, ADB_CMD +\
- ' shell su root dmesg -w', timings_pattern,\
- [KERNEL_BOOT_COMPLETE], True)
+ results = []
+ t = threading.Thread(target=collect_dmesg_events, args=(search_events_pattern,\
+ timings_pattern, results))
+ t.start()
- logcat_stop_events = [LOGCAT_BOOT_COMPLETE, KERNEL_BOOT_COMPLETE, LAUNCHER_START]
+ logcat_stop_events = [LOGCAT_BOOT_COMPLETE, LAUNCHER_START]
if args.fs_check:
logcat_stop_events.append("FsStat")
logcat_events, logcat_timing_events = collect_events(
search_events_pattern, ADB_CMD + ' logcat -b all -v epoch', timings_pattern,\
logcat_stop_events, False)
+
+ t.join()
+ dmesg_events = results[0]
+ kernel_timing_events = results[1]
+
logcat_event_time = extract_time(logcat_events, TIME_LOGCAT, float)
logcat_original_time = extract_time(logcat_events, TIME_LOGCAT, str);
dmesg_event_time = extract_time(dmesg_events, TIME_DMESG, float);
@@ -352,11 +367,12 @@ def iterate(args, search_events_pattern, timings_pattern, shutdown_events_patter
v = v + time_correction_delta
debug("correcting event to event[{0}, {1}]".format(k, v))
- if logcat_event_time.get(KERNEL_TIME_KEY) is None:
- print("kernel time not captured in logcat, cannot get time diff")
- return None, None, None, None, None, None
diffs = []
- diffs.append((logcat_event_time[KERNEL_TIME_KEY], logcat_event_time[KERNEL_TIME_KEY]))
+ if logcat_event_time.get(KERNEL_TIME_KEY) is None:
+ print("kernel time not captured in logcat")
+ else:
+ diffs.append((logcat_event_time[KERNEL_TIME_KEY], logcat_event_time[KERNEL_TIME_KEY]))
+
if logcat_event_time.get(BOOT_ANIM_END_TIME_KEY) and dmesg_event_time.get(BOOT_ANIM_END_TIME_KEY):
diffs.append((logcat_event_time[BOOT_ANIM_END_TIME_KEY],\
logcat_event_time[BOOT_ANIM_END_TIME_KEY] -\
@@ -364,6 +380,7 @@ def iterate(args, search_events_pattern, timings_pattern, shutdown_events_patter
if not dmesg_event_time.get(KERNEL_BOOT_COMPLETE):
print("BootAnimEnd time or BootComplete-kernel not captured in both log" +\
", cannot get time diff")
+ print("dmesg {} logcat {}".format(dmesg_event_time, logcat_event_time))
return None, None, None, None, None, None
diffs.append((logcat_event_time[LOGCAT_BOOT_COMPLETE],\
logcat_event_time[LOGCAT_BOOT_COMPLETE] - dmesg_event_time[KERNEL_BOOT_COMPLETE]))
@@ -631,56 +648,79 @@ def collect_logcat_for_shutdown(capture_log_on_error, shutdown_events_pattern,\
f.write('\n'.join(lines))
return events, timing_events
+def log_timeout(time_left, stop_events, events, timing_events):
+ print("timeout waiting for event, continue", time_left)
+ print(" remaininig events {}, event {} timing events {}".\
+ format(stop_events, events, timing_events))
def collect_events(search_events, command, timings, stop_events, disable_timing_after_zygote):
events = collections.OrderedDict()
timing_events = {}
- process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+
data_available = stop_events is None
zygote_pids = []
start_time = time.time()
zygote_found = False
-
line = None
- read_poll = select.poll()
- read_poll.register(process.stdout, select.POLLIN)
+ print("remaining stop_events:", stop_events)
+ init = True
while True:
+ if init:
+ process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+ read_poll = select.poll()
+ read_poll.register(process.stdout, select.POLLIN)
+ init = False
+ if len(stop_events) == 0:
+ break
time_left = start_time + max_wait_time - time.time()
if time_left <= 0:
- print("timeout waiting for event, continue", time_left)
+ log_timeout(time_left, stop_events, events, timing_events)
break
- read_r = read_poll.poll(time_left * 1000.0)
- if len(read_r) > 0 and read_r[0][1] == select.POLLIN:
- line = process.stdout.readline().decode('utf-8', 'ignore')
- else:
- print("poll timeout waiting for event, continue", time_left)
+ polled_events = read_poll.poll(time_left * 1000.0)
+ if len(polled_events) == 0:
+ log_timeout(time_left, stop_events, events, timing_events)
break
- if not data_available:
- print("Collecting data samples from '%s'. Please wait...\n" % command)
- data_available = True
- event = get_boot_event(line, search_events)
- if event:
- debug("event[{0}] captured: {1}".format(event, line))
- if event == "starting_zygote":
- events[event] = line
- zygote_found = True
- elif event.startswith("zygote"):
- handle_zygote_event(zygote_pids, events, event, line)
+ for polled_event in polled_events:
+ if polled_event[1] == select.POLLIN:
+ line = process.stdout.readline().decode('utf-8', 'ignore')
else:
- new_event = update_name_if_already_exist(events, event)
- events[new_event] = line
- if event in stop_events:
- stop_events.remove(event)
- print("remaining stop_events:", stop_events)
- if len(stop_events) == 0:
+ if polled_event[1] == select.POLLHUP:
+ if len(stop_events) == 0:
+ break;
+ # adb connection lost
+ print("poll error waiting for event, adb lost?")
+ if time_left > 0:
+ print("retry adb")
+ run_adb_cmd('wait-for-device')
+ print(" reconnected")
+ init = True
+ continue
+ else:
break
-
- timing_event = get_boot_event(line, timings)
- if timing_event and (not disable_timing_after_zygote or not zygote_found):
- if timing_event not in timing_events:
- timing_events[timing_event] = []
- timing_events[timing_event].append(line)
- debug("timing_event[{0}] captured: {1}".format(timing_event, line))
+ if not data_available:
+ print("Collecting data samples from '%s'. Please wait...\n" % command)
+ data_available = True
+ event = get_boot_event(line, search_events)
+ if event:
+ debug("event[{0}] captured: {1}".format(event, line))
+ if event == "starting_zygote":
+ events[event] = line
+ zygote_found = True
+ elif event.startswith("zygote"):
+ handle_zygote_event(zygote_pids, events, event, line)
+ else:
+ new_event = update_name_if_already_exist(events, event)
+ events[new_event] = line
+ if event in stop_events:
+ stop_events.remove(event)
+ print("remaining stop_events:", stop_events)
+
+ timing_event = get_boot_event(line, timings)
+ if timing_event and (not disable_timing_after_zygote or not zygote_found):
+ if timing_event not in timing_events:
+ timing_events[timing_event] = []
+ timing_events[timing_event].append(line)
+ debug("timing_event[{0}] captured: {1}".format(timing_event, line))
process.terminate()
return events, timing_events
@@ -743,7 +783,10 @@ def extract_time(events, pattern, date_transform_function):
def do_reboot(serial, use_adb_reboot):
- original_devices = subprocess.check_output("adb devices", shell=True)
+ # do not update time
+ run_adb_cmd('shell settings put global auto_time 0')
+ run_adb_cmd('shell settings put global auto_time_zone 0')
+ original_devices = subprocess.check_output("adb devices", shell=True).decode('utf-8', 'ignore')
if use_adb_reboot:
print('Rebooting the device using adb reboot')
run_adb_cmd('reboot')
@@ -780,6 +823,7 @@ def reboot(serial, use_stressfs, permissive, use_adb_reboot, adb_buffersize=None
print('Waiting the device')
run_adb_cmd('wait-for-device')
+ print(' found a device')
if adb_buffersize is not None:
# increase the buffer size
diff --git a/boottime_tools/bootanalyze/config.yaml b/boottime_tools/bootanalyze/config.yaml
index d6590fdb..83c1bcd8 100644
--- a/boottime_tools/bootanalyze/config.yaml
+++ b/boottime_tools/bootanalyze/config.yaml
@@ -61,7 +61,7 @@ events:
KeyguardShown: KeyguardServiceDelegate.*\*\*\*\* SHOWN CALLED \*\*\*\*
BootComplete: Starting phase 1000
BootComplete_kernel: processing action \(sys\.boot_completed=1\)
- LauncherStart: START.*HOME.*(NexusLauncherActivity|GEL|LensPickerTrampolineActivity|SetupWizard|CarLauncher)
+ LauncherStart: START.*HOME.*(NexusLauncherActivity|GEL|LensPickerTrampolineActivity|SetupWizard|CarLauncher|launcher.*Launcher)
FsStat: fs_stat, partition:userdata stat:(0x\S+)
shutdown_events:
ShutdownStart: ShutdownThread:\sNotifying thread to start shutdown
diff --git a/profcollectd/libprofcollectd/Android.bp b/profcollectd/libprofcollectd/Android.bp
index 2e37af9e..7fb1b567 100644
--- a/profcollectd/libprofcollectd/Android.bp
+++ b/profcollectd/libprofcollectd/Android.bp
@@ -60,4 +60,7 @@ rust_library {
"libsimpleperf_profcollect_rust",
],
shared_libs: ["libsimpleperf_profcollect"],
+
+ // Enable 'test' feature for more verbose logging and the logging trace provider.
+ // features: ["test"],
}
diff --git a/profcollectd/libprofcollectd/config.rs b/profcollectd/libprofcollectd/config.rs
index e8afb37f..902b5b5e 100644
--- a/profcollectd/libprofcollectd/config.rs
+++ b/profcollectd/libprofcollectd/config.rs
@@ -22,6 +22,7 @@ use macaddr::MacAddr6;
use rand::Rng;
use serde::{Deserialize, Serialize};
use std::error::Error;
+use std::fs::{read_dir, remove_file};
use std::path::Path;
use std::str::FromStr;
use std::time::Duration;
@@ -31,6 +32,7 @@ const PROFCOLLECT_NODE_ID_PROPERTY: &str = "persist.profcollectd.node_id";
pub const REPORT_RETENTION_SECS: u64 = 14 * 24 * 60 * 60; // 14 days.
+// Static configs that cannot be changed.
lazy_static! {
pub static ref TRACE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/trace/");
pub static ref PROFILE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/output/");
@@ -42,6 +44,7 @@ lazy_static! {
Path::new("/data/misc/profcollectd/output/config.json");
}
+/// Dynamic configs, stored in config.json.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct Config {
/// Version of config file scheme, always equals to 1.
@@ -56,6 +59,8 @@ pub struct Config {
pub sampling_period: Duration,
/// An optional filter to limit which binaries to or not to profile.
pub binary_filter: String,
+ /// Maximum size of the trace directory.
+ pub max_trace_limit: u64,
}
impl Config {
@@ -70,6 +75,10 @@ impl Config {
)?),
sampling_period: Duration::from_millis(get_device_config("sampling_period", 500)?),
binary_filter: get_device_config("binary_filter", "".to_string())?,
+ max_trace_limit: get_device_config(
+ "max_trace_limit",
+ /* 512MB */ 512 * 1024 * 1024,
+ )?,
})
}
}
@@ -138,3 +147,19 @@ fn generate_random_node_id() -> MacAddr6 {
node_id[0] |= 0x1;
MacAddr6::from(node_id)
}
+
+pub fn clear_data() -> Result<()> {
+ fn remove_files(path: &Path) -> Result<()> {
+ read_dir(path)?
+ .filter_map(|e| e.ok())
+ .map(|e| e.path())
+ .filter(|e| e.is_file())
+ .try_for_each(remove_file)?;
+ Ok(())
+ }
+
+ remove_files(&TRACE_OUTPUT_DIR)?;
+ remove_files(&PROFILE_OUTPUT_DIR)?;
+ remove_files(&REPORT_OUTPUT_DIR)?;
+ Ok(())
+}
diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs
index aacbf8e3..5892e259 100644
--- a/profcollectd/libprofcollectd/lib.rs
+++ b/profcollectd/libprofcollectd/lib.rs
@@ -23,6 +23,9 @@ mod service;
mod simpleperf_etm_trace_provider;
mod trace_provider;
+#[cfg(feature = "test")]
+mod logging_trace_provider;
+
use anyhow::{Context, Result};
use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::{
self, BnProfCollectd,
@@ -88,11 +91,16 @@ pub fn report() -> Result<String> {
Ok(get_profcollectd_service()?.report()?)
}
+/// Clear all local data.
+pub fn reset() -> Result<()> {
+ config::clear_data()?;
+ Ok(())
+}
+
/// Inits logging for Android
pub fn init_logging() {
+ let min_log_level = if cfg!(feature = "test") { log::Level::Info } else { log::Level::Error };
android_logger::init_once(
- android_logger::Config::default()
- .with_tag("profcollectd")
- .with_min_level(log::Level::Error),
+ android_logger::Config::default().with_tag("profcollectd").with_min_level(min_log_level),
);
}
diff --git a/profcollectd/libprofcollectd/logging_trace_provider.rs b/profcollectd/libprofcollectd/logging_trace_provider.rs
new file mode 100644
index 00000000..1325855d
--- /dev/null
+++ b/profcollectd/libprofcollectd/logging_trace_provider.rs
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2021 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.
+//
+
+//! Logging trace provider for development and testing purposes.
+
+use anyhow::Result;
+use std::path::Path;
+use std::time::Duration;
+use trace_provider::TraceProvider;
+
+use crate::trace_provider;
+
+static LOGGING_TRACEFILE_EXTENSION: &str = "loggingtrace";
+
+pub struct LoggingTraceProvider {}
+
+impl TraceProvider for LoggingTraceProvider {
+ fn get_name(&self) -> &'static str {
+ "logging"
+ }
+
+ fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) {
+ let trace_file = trace_provider::get_path(trace_dir, tag, LOGGING_TRACEFILE_EXTENSION);
+
+ log::info!(
+ "Trace event triggered, tag {}, sampling for {}ms, saving to {}",
+ tag,
+ sampling_period.as_millis(),
+ trace_file.display()
+ );
+ }
+
+ fn process(&self, _trace_dir: &Path, _profile_dir: &Path) -> Result<()> {
+ log::info!("Process event triggered");
+ Ok(())
+ }
+}
+
+impl LoggingTraceProvider {
+ pub fn supported() -> bool {
+ true
+ }
+}
diff --git a/profcollectd/libprofcollectd/scheduler.rs b/profcollectd/libprofcollectd/scheduler.rs
index cfd0381f..b83bc457 100644
--- a/profcollectd/libprofcollectd/scheduler.rs
+++ b/profcollectd/libprofcollectd/scheduler.rs
@@ -16,6 +16,8 @@
//! ProfCollect tracing scheduler.
+use std::fs;
+use std::path::Path;
use std::sync::mpsc::{sync_channel, SyncSender};
use std::sync::Arc;
use std::sync::Mutex;
@@ -59,11 +61,13 @@ impl Scheduler {
Ok(_) => break,
Err(_) => {
// Did not receive a termination signal, initiate trace event.
- trace_provider.lock().unwrap().trace(
- &TRACE_OUTPUT_DIR,
- "periodic",
- &config.sampling_period,
- );
+ if check_space_limit(*TRACE_OUTPUT_DIR, &config).unwrap() {
+ trace_provider.lock().unwrap().trace(
+ &TRACE_OUTPUT_DIR,
+ "periodic",
+ &config.sampling_period,
+ );
+ }
}
}
}
@@ -83,7 +87,9 @@ impl Scheduler {
pub fn one_shot(&self, config: &Config, tag: &str) -> Result<()> {
let trace_provider = self.trace_provider.clone();
- trace_provider.lock().unwrap().trace(&TRACE_OUTPUT_DIR, tag, &config.sampling_period);
+ if check_space_limit(*TRACE_OUTPUT_DIR, config)? {
+ trace_provider.lock().unwrap().trace(&TRACE_OUTPUT_DIR, tag, &config.sampling_period);
+ }
Ok(())
}
@@ -106,3 +112,21 @@ impl Scheduler {
self.trace_provider.lock().unwrap().get_name()
}
}
+
+/// Run if space usage is under limit.
+fn check_space_limit(path: &Path, config: &Config) -> Result<bool> {
+ let ret = dir_size(path)? <= config.max_trace_limit;
+ if !ret {
+ log::error!("trace storage exhausted.");
+ }
+ Ok(ret)
+}
+
+/// Returns the size of a directory, non-recursive.
+fn dir_size(path: &Path) -> Result<u64> {
+ fs::read_dir(path)?.try_fold(0, |acc, file| {
+ let metadata = file?.metadata()?;
+ let size = if metadata.is_file() { metadata.len() } else { 0 };
+ Ok(acc + size)
+ })
+}
diff --git a/profcollectd/libprofcollectd/service.rs b/profcollectd/libprofcollectd/service.rs
index 04f30f89..a7fdce73 100644
--- a/profcollectd/libprofcollectd/service.rs
+++ b/profcollectd/libprofcollectd/service.rs
@@ -21,15 +21,15 @@ use binder::public_api::Result as BinderResult;
use binder::Status;
use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd;
use std::ffi::CString;
-use std::fs::{copy, create_dir, read_dir, read_to_string, remove_dir_all, remove_file, write};
+use std::fs::{copy, read_dir, read_to_string, remove_file, write};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Mutex, MutexGuard};
use std::time::Duration;
use crate::config::{
- Config, BETTERBUG_CACHE_DIR_PREFIX, BETTERBUG_CACHE_DIR_SUFFIX, CONFIG_FILE,
- PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS, TRACE_OUTPUT_DIR,
+ clear_data, Config, BETTERBUG_CACHE_DIR_PREFIX, BETTERBUG_CACHE_DIR_SUFFIX, CONFIG_FILE,
+ PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS,
};
use crate::report::{get_report_ts, pack_report};
use crate::scheduler::Scheduler;
@@ -147,11 +147,8 @@ impl ProfcollectdBinderService {
.is_none();
if config_changed {
- log::info!("Config change detected, clearing traces.");
- remove_dir_all(*PROFILE_OUTPUT_DIR)?;
- remove_dir_all(*TRACE_OUTPUT_DIR)?;
- create_dir(*PROFILE_OUTPUT_DIR)?;
- create_dir(*TRACE_OUTPUT_DIR)?;
+ log::info!("Config change detected, resetting profcollect.");
+ clear_data()?;
write(*CONFIG_FILE, &new_config.to_string())?;
}
diff --git a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
index 2038a5be..d3baaa36 100644
--- a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
+++ b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs
@@ -35,12 +35,10 @@ impl TraceProvider for SimpleperfEtmTraceProvider {
}
fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) {
- let mut trace_file = PathBuf::from(trace_dir);
- trace_file.push(trace_provider::construct_file_name(tag));
- trace_file.set_extension(ETM_TRACEFILE_EXTENSION);
+ let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION);
simpleperf_profcollect::record(
- &trace_file,
+ &*trace_file,
sampling_period,
simpleperf_profcollect::RecordScope::BOTH,
);
diff --git a/profcollectd/libprofcollectd/trace_provider.rs b/profcollectd/libprofcollectd/trace_provider.rs
index ed0d56f5..44d4cee9 100644
--- a/profcollectd/libprofcollectd/trace_provider.rs
+++ b/profcollectd/libprofcollectd/trace_provider.rs
@@ -18,12 +18,15 @@
use anyhow::{anyhow, Result};
use chrono::Utc;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use crate::simpleperf_etm_trace_provider::SimpleperfEtmTraceProvider;
+#[cfg(feature = "test")]
+use crate::logging_trace_provider::LoggingTraceProvider;
+
pub trait TraceProvider {
fn get_name(&self) -> &'static str;
fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration);
@@ -36,9 +39,19 @@ pub fn get_trace_provider() -> Result<Arc<Mutex<dyn TraceProvider + Send>>> {
return Ok(Arc::new(Mutex::new(SimpleperfEtmTraceProvider {})));
}
+ #[cfg(feature = "test")]
+ if LoggingTraceProvider::supported() {
+ log::info!("logging trace provider registered.");
+ return Ok(Arc::new(Mutex::new(LoggingTraceProvider {})));
+ }
+
Err(anyhow!("No trace provider found for this device."))
}
-pub fn construct_file_name(tag: &str) -> String {
- format!("{}_{}", Utc::now().format("%Y%m%d-%H%M%S"), tag)
+pub fn get_path(dir: &Path, tag: &str, ext: &str) -> Box<Path> {
+ let filename = format!("{}_{}", Utc::now().format("%Y%m%d-%H%M%S"), tag);
+ let mut trace_file = PathBuf::from(dir);
+ trace_file.push(filename);
+ trace_file.set_extension(ext);
+ trace_file.into_boxed_path()
}
diff --git a/profcollectd/profcollectctl.rs b/profcollectd/profcollectctl.rs
index c825f550..6778465e 100644
--- a/profcollectd/profcollectctl.rs
+++ b/profcollectd/profcollectctl.rs
@@ -29,8 +29,9 @@ command:
stop Terminate periodic collection.
once Request an one-off trace.
process Convert traces to perf profiles.
- report Create a report containing all profiles.
reconfig Refresh configuration.
+ report Create a report containing all profiles.
+ reset Clear all local data.
help Print this message.
"#;
@@ -65,6 +66,10 @@ fn main() -> Result<()> {
let path = libprofcollectd::report().context("Failed to create profile report.")?;
println!("Report created at: {}", &path);
}
+ "reset" => {
+ libprofcollectd::reset().context("Failed to reset.")?;
+ println!("Reset done.");
+ }
"help" => println!("{}", &HELP_MSG),
arg => bail!("Unknown argument: {}\n{}", &arg, &HELP_MSG),
}
diff --git a/profcollectd/profcollectd.rc b/profcollectd/profcollectd.rc
index d1dbd9ef..b92fccba 100644
--- a/profcollectd/profcollectd.rc
+++ b/profcollectd/profcollectd.rc
@@ -6,15 +6,15 @@ service profcollectd /system/bin/profcollectd
group root wakelock
writepid /dev/cpuset/system-background/tasks
-on property:persist.device_config.profcollect_native_boot.enabled=true
- start profcollectd
+on post-fs-data
+ # Create directory for profcollectd.
+ mkdir /data/misc/profcollectd 0770 shell shell
+ mkdir /data/misc/profcollectd/trace 0770 shell shell
+ mkdir /data/misc/profcollectd/output 0770 shell shell
+ mkdir /data/misc/profcollectd/report 0770 shell shell
-on property:persist.profcollectd.enabled_override=true
+on boot && property:persist.device_config.profcollect_native_boot.enabled=true
start profcollectd
-on post-fs-data
- # Create directory for profcollectd.
- mkdir /data/misc/profcollectd 0770 root system
- mkdir /data/misc/profcollectd/trace 0770 root system
- mkdir /data/misc/profcollectd/output 0770 root system
- mkdir /data/misc/profcollectd/report 0770 root system
+on boot && property:persist.device_config.profcollect_native_boot.enabled=
+ exec_background - root shell -- /system/bin/profcollectctl reset
diff --git a/simpleperf/test_util.cpp b/simpleperf/test_util.cpp
index d85294f5..fcbdf98f 100644
--- a/simpleperf/test_util.cpp
+++ b/simpleperf/test_util.cpp
@@ -78,6 +78,7 @@ bool HasHardwareCounter() {
auto arch = GetBuildArch();
std::string fingerprint = android::base::GetProperty("ro.system.build.fingerprint", "");
bool is_emulator = android::base::StartsWith(fingerprint, "google/sdk_gphone") ||
+ android::base::StartsWith(fingerprint, "google/sdk_gpc") ||
android::base::StartsWith(fingerprint, "generic/cf");
if (arch == ARCH_X86_64 || arch == ARCH_X86_32 || is_emulator) {