summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-09 01:27:57 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-05-09 01:27:57 +0000
commit3496d6c5434dad561f3d4d74476d5b4984bd93db (patch)
tree9ea1c4097580c8fe5def8cd29c9bbbc40ea033ca
parent237da28ac8952f156b1b54b00b302872559cf1e9 (diff)
parentdf683620b1dceef648391d94b31577bd154e7761 (diff)
downloadextras-sdk-release.tar.gz
Merge "Snap for 11819063 from e04e4a20c8d4fb1de37123bf7ff2957f9b41e4b7 to sdk-release" into sdk-releasesdk-release
-rw-r--r--simpleperf/RecordReadThread.cpp12
-rw-r--r--simpleperf/RecordReadThread.h1
-rw-r--r--simpleperf/cmd_record.cpp31
-rw-r--r--simpleperf/cmd_record_impl.h2
-rw-r--r--simpleperf/cmd_record_test.cpp12
-rw-r--r--simpleperf/event_selection_set.cpp70
-rw-r--r--simpleperf/event_selection_set.h6
7 files changed, 126 insertions, 8 deletions
diff --git a/simpleperf/RecordReadThread.cpp b/simpleperf/RecordReadThread.cpp
index 2ab61278..2d034bc1 100644
--- a/simpleperf/RecordReadThread.cpp
+++ b/simpleperf/RecordReadThread.cpp
@@ -408,6 +408,7 @@ bool RecordReadThread::HandleAddEventFds(IOEventLoop& loop,
success = false;
break;
}
+ has_etm_events_ = true;
}
cpu_map[fd->Cpu()] = fd;
} else {
@@ -620,6 +621,9 @@ void RecordReadThread::PushRecordToRecordBuffer(KernelRecordReader* kernel_recor
}
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 @@ void RecordReadThread::ReadAuxDataFromKernelBuffer(bool* has_data) {
}
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 c104b083..893f8234 100644
--- a/simpleperf/RecordReadThread.h
+++ b/simpleperf/RecordReadThread.h
@@ -211,6 +211,7 @@ class RecordReadThread {
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 40582045..e08b153b 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 DEFAULT_CALL_CHAIN_JOINER_CACHE_SIZE = 8 * kMegabyte;
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_FILTER_OPTION_HELP_MSG_FOR_RECORDING
"--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 @@ RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING
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 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
} 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 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
}
}
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 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
// 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 @@ bool RecordCommand::DoRecording(Workload* workload) {
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 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
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)) {
+ 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 29f44809..e8561636 100644
--- a/simpleperf/cmd_record_impl.h
+++ b/simpleperf/cmd_record_impl.h
@@ -51,6 +51,8 @@ inline const OptionFormatMap& GetRecordCmdOptionFormats() {
{"--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 131f6da4..898d8756 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -1196,8 +1196,7 @@ TEST(record_cmd, cycle_threshold) {
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 @@ TEST(record_cmd, binary_option) {
}
// @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 c75f8049..1a7cdef8 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -233,6 +233,8 @@ bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_nam
// 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 @@ void EventSelectionSet::SetEnableCondition(bool enable_on_open, bool enable_on_e
}
}
+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 @@ bool EventSelectionSet::SetEnableEvents(bool enable) {
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 e046035b..a892d51e 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -122,6 +122,7 @@ class EventSelectionSet {
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 @@ class EventSelectionSet {
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 @@ class EventSelectionSet {
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);
};