diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-05-09 01:27:57 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-05-09 01:27:57 +0000 |
commit | 3496d6c5434dad561f3d4d74476d5b4984bd93db (patch) | |
tree | 9ea1c4097580c8fe5def8cd29c9bbbc40ea033ca | |
parent | 237da28ac8952f156b1b54b00b302872559cf1e9 (diff) | |
parent | df683620b1dceef648391d94b31577bd154e7761 (diff) | |
download | extras-sdk-release.tar.gz |
Merge "Snap for 11819063 from e04e4a20c8d4fb1de37123bf7ff2957f9b41e4b7 to sdk-release" into sdk-releasesdk-release
-rw-r--r-- | simpleperf/RecordReadThread.cpp | 12 | ||||
-rw-r--r-- | simpleperf/RecordReadThread.h | 1 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 31 | ||||
-rw-r--r-- | simpleperf/cmd_record_impl.h | 2 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 12 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 70 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 6 |
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); }; |