Merge "Replace impl ToString with impl Display" into main
diff --git a/profcollectd/libprofcollectd/config.rs b/profcollectd/libprofcollectd/config.rs
index cdf1487..cbc5b7c 100644
--- a/profcollectd/libprofcollectd/config.rs
+++ b/profcollectd/libprofcollectd/config.rs
@@ -166,3 +166,11 @@
remove_files(&REPORT_OUTPUT_DIR)?;
Ok(())
}
+pub fn clear_processed_files() -> Result<()> {
+ read_dir(&PROFILE_OUTPUT_DIR as &Path)?
+ .filter_map(|e| e.ok())
+ .map(|e| e.path())
+ .filter(|e| e.is_file() && e != (&CONFIG_FILE as &Path))
+ .try_for_each(remove_file)?;
+ Ok(())
+}
diff --git a/profcollectd/libprofcollectd/report.rs b/profcollectd/libprofcollectd/report.rs
index e0f2ec8..60410c1 100644
--- a/profcollectd/libprofcollectd/report.rs
+++ b/profcollectd/libprofcollectd/report.rs
@@ -29,7 +29,7 @@
use zip::CompressionMethod::Deflated;
use zip::ZipWriter;
-use crate::config::Config;
+use crate::config::{clear_processed_files, Config};
pub const NO_USAGE_SETTING: i32 = -1;
@@ -80,6 +80,7 @@
zip.write_all(usage_setting.to_string().as_bytes())?;
}
zip.finish()?;
+ clear_processed_files()?;
Ok(report_filename)
}
diff --git a/simpleperf/RecordReadThread.cpp b/simpleperf/RecordReadThread.cpp
index 2ab6127..2d034bc 100644
--- a/simpleperf/RecordReadThread.cpp
+++ b/simpleperf/RecordReadThread.cpp
@@ -408,6 +408,7 @@
success = false;
break;
}
+ has_etm_events_ = true;
}
cpu_map[fd->Cpu()] = fd;
} else {
@@ -620,6 +621,9 @@
}
void RecordReadThread::ReadAuxDataFromKernelBuffer(bool* has_data) {
+ if (!has_etm_events_) {
+ return;
+ }
for (auto& reader : kernel_record_readers_) {
EventFd* event_fd = reader.GetEventFd();
if (event_fd->HasAuxBuffer()) {
@@ -659,6 +663,14 @@
}
bool RecordReadThread::SendDataNotificationToMainThread() {
+ if (has_etm_events_) {
+ // For ETM recording, the default buffer size is large enough to hold ETM data for several
+ // seconds. To reduce impact of processing ETM data (especially when --decode-etm is used),
+ // delay processing ETM data until the buffer is half full.
+ if (record_buffer_.GetFreeSize() >= record_buffer_.size() / 2) {
+ return true;
+ }
+ }
if (!has_data_notification_.load(std::memory_order_relaxed)) {
has_data_notification_ = true;
char unused = 0;
diff --git a/simpleperf/RecordReadThread.h b/simpleperf/RecordReadThread.h
index c104b08..893f823 100644
--- a/simpleperf/RecordReadThread.h
+++ b/simpleperf/RecordReadThread.h
@@ -211,6 +211,7 @@
std::unique_ptr<std::thread> read_thread_;
std::vector<KernelRecordReader> kernel_record_readers_;
pid_t exclude_pid_ = -1;
+ bool has_etm_events_ = false;
std::unordered_set<EventFd*> event_fds_disabled_by_kernel_;
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 4058204..cb9ad88 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -22,6 +22,7 @@
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
+#include <chrono>
#include <filesystem>
#include <optional>
#include <set>
@@ -111,8 +112,8 @@
static constexpr size_t kDefaultAuxBufferSize = 4 * kMegabyte;
// On Pixel 3, it takes about 1ms to enable ETM, and 16-40ms to disable ETM and copy 4M ETM data.
-// So make default period to 100ms.
-static constexpr double kDefaultEtmDataFlushPeriodInSec = 0.1;
+// So make default interval to 100ms.
+static constexpr uint32_t kDefaultEtmDataFlushIntervalInMs = 100;
struct TimeStat {
uint64_t prepare_recording_time = 0;
@@ -316,6 +317,8 @@
"--record-timestamp Generate timestamp packets in ETM stream.\n"
"--record-cycles Generate cycle count packets in ETM stream.\n"
"--cycle-threshold <threshold> Set cycle count counter threshold for ETM cycle count packets.\n"
+"--etm-flush-interval <interval> Set the interval between ETM data flushes from the ETR buffer\n"
+" to the perf event buffer (in milliseconds). Default is 100 ms.\n"
"\n"
"Other options:\n"
"--exit-with-parent Stop recording when the thread starting simpleperf dies.\n"
@@ -480,6 +483,7 @@
std::unique_ptr<ETMBranchListGenerator> etm_branch_list_generator_;
std::unique_ptr<RegEx> binary_name_regex_;
+ std::chrono::milliseconds etm_flush_interval_{kDefaultEtmDataFlushIntervalInMs};
};
std::string RecordCommand::LongHelpString() const {
@@ -631,7 +635,7 @@
} else {
need_to_check_targets = true;
}
- if (delay_in_ms_ != 0) {
+ if (delay_in_ms_ != 0 || event_selection_set_.HasAuxTrace()) {
event_selection_set_.SetEnableCondition(false, false);
}
@@ -755,6 +759,12 @@
}
}
if (event_selection_set_.HasAuxTrace()) {
+ // ETM events can only be enabled successfully after MmapEventFiles().
+ if (delay_in_ms_ == 0 && !event_selection_set_.IsEnabledOnExec()) {
+ if (!event_selection_set_.EnableETMEvents()) {
+ return false;
+ }
+ }
// ETM data is dumped to kernel buffer only when there is no thread traced by ETM. It happens
// either when all monitored threads are scheduled off cpu, or when all etm perf events are
// disabled.
@@ -762,10 +772,9 @@
// makes less than expected data, especially in system wide recording. So add a periodic event
// to flush etm data by temporarily disable all perf events.
auto etm_flush = [this]() {
- return event_selection_set_.SetEnableEvents(false) &&
- event_selection_set_.SetEnableEvents(true);
+ return event_selection_set_.DisableETMEvents() && event_selection_set_.EnableETMEvents();
};
- if (!loop->AddPeriodicEvent(SecondToTimeval(kDefaultEtmDataFlushPeriodInSec), etm_flush)) {
+ if (!loop->AddPeriodicEvent(SecondToTimeval(etm_flush_interval_.count() / 1000.0), etm_flush)) {
return false;
}
@@ -800,6 +809,12 @@
return false;
}
time_stat_.stop_recording_time = GetSystemClock();
+ if (event_selection_set_.HasAuxTrace()) {
+ // Disable ETM events to flush the last ETM data.
+ if (!event_selection_set_.DisableETMEvents()) {
+ return false;
+ }
+ }
if (!event_selection_set_.SyncKernelBuffer()) {
return false;
}
@@ -1041,6 +1056,10 @@
if (options.PullBoolValue("--decode-etm")) {
etm_branch_list_generator_ = ETMBranchListGenerator::Create(system_wide_collection_);
}
+ uint32_t interval = 0;
+ if (options.PullUintValue("--etm-flush-interval", &interval) && interval != 0) {
+ etm_flush_interval_ = std::chrono::milliseconds(interval);
+ }
if (options.PullBoolValue("--record-timestamp")) {
ETMRecorder& recorder = ETMRecorder::GetInstance();
diff --git a/simpleperf/cmd_record_impl.h b/simpleperf/cmd_record_impl.h
index 29f4480..e856163 100644
--- a/simpleperf/cmd_record_impl.h
+++ b/simpleperf/cmd_record_impl.h
@@ -51,6 +51,8 @@
{"--cycle-threshold", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--decode-etm", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--delay", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
+ {"--etm-flush-interval",
+ {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--record-timestamp", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--record-cycles", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--duration", {OptionValueType::DOUBLE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 131f6da..898d875 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -1196,8 +1196,7 @@
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
return;
}
- ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-cycles",
- "--cycle-threshold", "8"}));
+ ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-cycles", "--cycle-threshold", "8"}));
}
// @CddTest = 6.1/C-0-2
@@ -1210,6 +1209,15 @@
}
// @CddTest = 6.1/C-0-2
+TEST(record_cmd, etm_flush_interval_option) {
+ if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
+ GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
+ return;
+ }
+ ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--etm-flush-interval", "10"}));
+}
+
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, pmu_event_option) {
TEST_REQUIRE_PMU_COUNTER();
TEST_REQUIRE_HW_COUNTER();
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index c75f804..1a7cdef 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -233,6 +233,8 @@
// enabling/disabling etm devices. So don't adjust frequency by default.
selection->event_attr.freq = 0;
selection->event_attr.sample_period = 1;
+ // An ETM event can't be enabled without mmap aux buffer. So disable it by default.
+ selection->event_attr.disabled = 1;
} else {
selection->event_attr.freq = 1;
// Set default sample freq here may print msg "Adjust sample freq to max allowed sample
@@ -461,6 +463,17 @@
}
}
+bool EventSelectionSet::IsEnabledOnExec() const {
+ for (const auto& group : groups_) {
+ for (const auto& selection : group.selections) {
+ if (!selection.event_attr.enable_on_exec) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
void EventSelectionSet::SampleIdAll() {
for (auto& group : groups_) {
for (auto& selection : group.selections) {
@@ -939,4 +952,61 @@
return true;
}
+bool EventSelectionSet::EnableETMEvents() {
+ for (auto& group : groups_) {
+ for (auto& sel : group.selections) {
+ if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
+ continue;
+ }
+ for (auto& fd : sel.event_fds) {
+ if (!fd->SetEnableEvent(true)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool EventSelectionSet::DisableETMEvents() {
+ for (auto& group : groups_) {
+ for (auto& sel : group.selections) {
+ if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
+ continue;
+ }
+ // When using ETR, ETM data is flushed to the aux buffer of the last cpu disabling ETM events.
+ // To avoid overflowing the aux buffer for one cpu, rotate the last cpu disabling ETM events.
+ if (etm_event_cpus_.empty()) {
+ for (const auto& fd : sel.event_fds) {
+ etm_event_cpus_.insert(fd->Cpu());
+ }
+ if (etm_event_cpus_.empty()) {
+ continue;
+ }
+ etm_event_cpus_it_ = etm_event_cpus_.begin();
+ }
+ int last_disabled_cpu = *etm_event_cpus_it_;
+ if (++etm_event_cpus_it_ == etm_event_cpus_.end()) {
+ etm_event_cpus_it_ = etm_event_cpus_.begin();
+ }
+
+ for (auto& fd : sel.event_fds) {
+ if (fd->Cpu() != last_disabled_cpu) {
+ if (!fd->SetEnableEvent(false)) {
+ return false;
+ }
+ }
+ }
+ for (auto& fd : sel.event_fds) {
+ if (fd->Cpu() == last_disabled_cpu) {
+ if (!fd->SetEnableEvent(false)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
} // namespace simpleperf
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index e046035..a892d51 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -122,6 +122,7 @@
std::map<int, size_t> GetHardwareCountersForCpus() const;
void SetEnableCondition(bool enable_on_open, bool enable_on_exec);
+ bool IsEnabledOnExec() const;
void SampleIdAll();
// Only set sample rate for events that haven't set sample rate.
void SetSampleRateForNewEvents(const SampleRate& rate);
@@ -179,6 +180,8 @@
double check_interval_in_sec = DEFAULT_PERIOD_TO_CHECK_MONITORED_TARGETS_IN_SEC);
bool SetEnableEvents(bool enable);
+ bool EnableETMEvents();
+ bool DisableETMEvents();
private:
struct EventSelection {
@@ -232,6 +235,9 @@
std::optional<SampleRate> sample_rate_;
std::optional<std::vector<int>> cpus_;
+ std::set<int> etm_event_cpus_;
+ std::set<int>::const_iterator etm_event_cpus_it_;
+
DISALLOW_COPY_AND_ASSIGN(EventSelectionSet);
};
diff --git a/tools/check_elf_alignment.sh b/tools/check_elf_alignment.sh
index ba82eb7..b74f34a 100755
--- a/tools/check_elf_alignment.sh
+++ b/tools/check_elf_alignment.sh
@@ -40,12 +40,12 @@
exit 1
fi
-if [[ ${dir} == *.apk ]]; then
+if [[ "${dir}" == *.apk ]]; then
trap 'cleanup_trap' EXIT
if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then
echo "=== APK zip-alignment ==="
- zipalign -v -c -P 16 4 ${dir} | egrep 'lib/arm64-v8a|lib/x86_64|Verification'
+ zipalign -v -c -P 16 4 "${dir}" | egrep 'lib/arm64-v8a|lib/x86_64|Verification'
echo "========================="
else
echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher."
@@ -55,10 +55,10 @@
echo " sdkmanager \"build-tools;35.0.0-rc3\""
fi
- dir_filename=$(basename ${dir})
- tmp=$(mktemp -d -t ${dir_filename%.apk}_out_XXXXX)
- unzip ${dir} lib/arm64-v8a/* lib/x86_64/* -d ${tmp} >/dev/null 2>&1
- dir=${tmp}
+ dir_filename=$(basename "${dir}")
+ tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX")
+ unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1
+ dir="${tmp}"
fi
RED="\e[31m"
@@ -70,7 +70,7 @@
echo
echo "=== ELF alignment ==="
-matches="$(find ${dir} -name "*.so" -type f)"
+matches="$(find "${dir}" -name "*.so" -type f)"
IFS=$'\n'
for match in $matches; do
res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)"
@@ -78,12 +78,12 @@
echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
else
echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
- unaligned_libs+=(${match})
+ unaligned_libs+=("${match}")
fi
done
if [ ${#unaligned_libs[@]} -gt 0 ]; then
- echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs${ENDCOLOR}"
+ echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}"
elif [ -n "${dir_filename}" ]; then
echo -e "ELF Verification Successful"
fi