diff options
-rw-r--r-- | simpleperf/cmd_dumprecord.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_kmem.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 87 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 4 | ||||
-rw-r--r-- | simpleperf/cmd_report.cpp | 3 | ||||
-rw-r--r-- | simpleperf/cmd_report_test.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_stat.cpp | 19 | ||||
-rw-r--r-- | simpleperf/environment.cpp | 1 | ||||
-rw-r--r-- | simpleperf/environment.h | 15 | ||||
-rw-r--r-- | simpleperf/event_attr.h | 5 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 114 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 49 | ||||
-rw-r--r-- | simpleperf/perf_clock.cpp | 30 | ||||
-rw-r--r-- | simpleperf/perf_clock.h | 2 | ||||
-rw-r--r-- | simpleperf/record_file.h | 12 | ||||
-rw-r--r-- | simpleperf/record_file_test.cpp | 8 | ||||
-rw-r--r-- | simpleperf/record_file_writer.cpp | 2 | ||||
-rw-r--r-- | simpleperf/report_lib_interface.cpp | 2 | ||||
-rw-r--r-- | simpleperf/thread_tree.cpp | 9 | ||||
-rw-r--r-- | simpleperf/thread_tree.h | 6 |
20 files changed, 192 insertions, 182 deletions
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp index 3e89b827..047bfa23 100644 --- a/simpleperf/cmd_dumprecord.cpp +++ b/simpleperf/cmd_dumprecord.cpp @@ -157,7 +157,7 @@ static const std::string GetFeatureName(int feature) { } void DumpRecordCommand::DumpAttrSection() { - std::vector<AttrWithId> attrs = record_file_reader_->AttrSection(); + std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); for (size_t i = 0; i < attrs.size(); ++i) { const auto& attr = attrs[i]; printf("attr %zu:\n", i + 1); diff --git a/simpleperf/cmd_kmem.cpp b/simpleperf/cmd_kmem.cpp index 16559a29..3cfb93e6 100644 --- a/simpleperf/cmd_kmem.cpp +++ b/simpleperf/cmd_kmem.cpp @@ -552,7 +552,7 @@ bool KmemCommand::PrepareToBuildSampleTree() { } void KmemCommand::ReadEventAttrsFromRecordFile() { - std::vector<AttrWithId> attrs = record_file_reader_->AttrSection(); + std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); for (const auto& attr_with_id : attrs) { EventAttrWithName attr; attr.attr = *attr_with_id.attr; diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 07e14687..a076778d 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -56,9 +56,6 @@ static std::unordered_map<std::string, uint64_t> branch_sampling_type_map = { {"ind_call", PERF_SAMPLE_BRANCH_IND_CALL}, }; -constexpr uint64_t DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT = 4000; -constexpr uint64_t DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT = 1; - // The max size of records dumped by kernel is 65535, and dump stack size // should be a multiply of 8, so MAX_DUMP_STACK_SIZE is 65528. constexpr uint32_t MAX_DUMP_STACK_SIZE = 65528; @@ -306,9 +303,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) { // 6. Write records in mapped buffers of perf_event_files to output file while // workload is running. - if (!GetPerfClock(&start_sampling_time_in_ns_)) { - return false; - } + start_sampling_time_in_ns_ = GetPerfClock(); LOG(VERBOSE) << "start_sampling_time is " << start_sampling_time_in_ns_ << " ns"; if (workload != nullptr && !workload->Start()) { @@ -581,23 +576,12 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args, } bool RecordCommand::SetEventSelectionFlags() { - for (const auto& group : event_selection_set_.groups()) { - for (const auto& selection : group) { - if (use_sample_freq_) { - event_selection_set_.SetSampleFreq(selection, sample_freq_); - } else if (use_sample_period_) { - event_selection_set_.SetSamplePeriod(selection, sample_period_); - } else { - if (selection.event_type_modifier.event_type.type == - PERF_TYPE_TRACEPOINT) { - event_selection_set_.SetSamplePeriod( - selection, DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT); - } else { - event_selection_set_.SetSampleFreq( - selection, DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT); - } - } - } + if (use_sample_freq_) { + event_selection_set_.SetSampleFreq(sample_freq_); + } else if (use_sample_period_) { + event_selection_set_.SetSamplePeriod(sample_period_); + } else { + event_selection_set_.UseDefaultSampleFreq(); } event_selection_set_.SampleIdAll(); if (!event_selection_set_.SetBranchSampling(branch_sampling_)) { @@ -626,20 +610,17 @@ bool RecordCommand::CreateAndInitRecordFile() { return false; } // Use first perf_event_attr and first event id to dump mmap and comm records. - const EventSelection& selection = event_selection_set_.groups()[0][0]; - const perf_event_attr& attr = selection.event_attr; - const std::vector<std::unique_ptr<EventFd>>& fds = selection.event_fds; - uint64_t event_id = fds[0]->Id(); + EventAttrWithId attr_id = event_selection_set_.GetEventAttrWithId()[0]; if (!DumpKernelSymbol()) { return false; } if (!DumpTracingData()) { return false; } - if (!DumpKernelAndModuleMmaps(attr, event_id)) { + if (!DumpKernelAndModuleMmaps(*attr_id.attr, attr_id.ids[0])) { return false; } - if (!DumpThreadCommAndMmaps(attr, event_id)) { + if (!DumpThreadCommAndMmaps(*attr_id.attr, attr_id.ids[0])) { return false; } return true; @@ -653,20 +634,7 @@ std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile( return nullptr; } - std::vector<AttrWithId> attr_ids; - for (const auto& group : event_selection_set_.groups()) { - for (const auto& selection : group) { - AttrWithId attr_id; - attr_id.attr = &selection.event_attr; - CHECK(attr_id.attr != nullptr); - const std::vector<std::unique_ptr<EventFd>>& fds = selection.event_fds; - for (const auto& fd : fds) { - attr_id.ids.push_back(fd->Id()); - } - attr_ids.push_back(attr_id); - } - } - if (!writer->WriteAttrSection(attr_ids)) { + if (!writer->WriteAttrSection(event_selection_set_.GetEventAttrWithId())) { return nullptr; } return writer; @@ -675,39 +643,24 @@ std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile( bool RecordCommand::DumpKernelSymbol() { if (can_dump_kernel_symbols_) { std::string kallsyms; - bool need_kernel_symbol = false; - for (const auto& group : event_selection_set_.groups()) { - for (const auto& selection : group) { - if (!selection.event_type_modifier.exclude_kernel) { - need_kernel_symbol = true; - } - } - } - if (need_kernel_symbol && CheckKernelSymbolAddresses()) { + if (event_selection_set_.NeedKernelSymbol() && + CheckKernelSymbolAddresses()) { if (!android::base::ReadFileToString("/proc/kallsyms", &kallsyms)) { PLOG(ERROR) << "failed to read /proc/kallsyms"; return false; } - } - KernelSymbolRecord r(kallsyms); - if (!ProcessRecord(&r)) { - return false; + KernelSymbolRecord r(kallsyms); + if (!ProcessRecord(&r)) { + return false; + } } } return true; } bool RecordCommand::DumpTracingData() { - std::vector<const EventType*> tracepoint_event_types; - for (const auto& group : event_selection_set_.groups()) { - for (const auto& selection : group) { - if (selection.event_type_modifier.event_type.type == - PERF_TYPE_TRACEPOINT) { - tracepoint_event_types.push_back( - &selection.event_type_modifier.event_type); - } - } - } + std::vector<const EventType*> tracepoint_event_types = + event_selection_set_.GetTracepointEvents(); if (tracepoint_event_types.empty()) { return true; // No need to dump tracing data. } @@ -816,7 +769,7 @@ bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr, } bool RecordCommand::ProcessRecord(Record* record) { - if (record->type() == PERF_RECORD_SAMPLE) { + if (system_wide_collection_ && record->type() == PERF_RECORD_SAMPLE) { auto& r = *static_cast<SampleRecord*>(record); // Omit samples get before start sampling time. if (r.time_data.time < start_sampling_time_in_ns_) { diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index 97299041..07cf9302 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -29,6 +29,7 @@ #include "record.h" #include "record_file.h" #include "test_util.h" +#include "thread_tree.h" using namespace PerfFileFormat; @@ -223,7 +224,8 @@ static void CheckKernelSymbol(const std::string& path, bool need_kallsyms, has_kernel_symbol_records = true; } } - ASSERT_EQ(need_kallsyms, has_kernel_symbol_records); + bool require_kallsyms = need_kallsyms && CheckKernelSymbolAddresses(); + ASSERT_EQ(require_kallsyms, has_kernel_symbol_records); *success = true; } diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp index fe93dbc3..830ec130 100644 --- a/simpleperf/cmd_report.cpp +++ b/simpleperf/cmd_report.cpp @@ -31,7 +31,6 @@ #include "command.h" #include "dwarf_unwind.h" -#include "environment.h" #include "event_attr.h" #include "event_type.h" #include "perf_regs.h" @@ -582,7 +581,7 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { } bool ReportCommand::ReadEventAttrFromRecordFile() { - std::vector<AttrWithId> attrs = record_file_reader_->AttrSection(); + std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); for (const auto& attr_with_id : attrs) { EventAttrWithName attr; attr.attr = *attr_with_id.attr; diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp index a8897758..704076a4 100644 --- a/simpleperf/cmd_report_test.cpp +++ b/simpleperf/cmd_report_test.cpp @@ -24,7 +24,6 @@ #include <android-base/test_utils.h> #include "command.h" -#include "event_selection_set.h" #include "get_test_data.h" #include "perf_regs.h" #include "read_apk.h" @@ -417,6 +416,7 @@ TEST_F(ReportCommandTest, report_data_generated_by_linux_perf) { } #if defined(__linux__) +#include "event_selection_set.h" static std::unique_ptr<Command> RecordCmd() { return CreateCommandInstance("record"); diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp index b8153c71..9c5cf8fa 100644 --- a/simpleperf/cmd_stat.cpp +++ b/simpleperf/cmd_stat.cpp @@ -571,21 +571,21 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters, if (verbose_mode_) { for (auto& counters_info : counters) { - const EventTypeAndModifier& event_type = - counters_info.selection->event_type_modifier; for (auto& counter_info : counters_info.counters) { if (csv_) { fprintf(fp, "%s,tid,%d,cpu,%d,count,%" PRIu64 ",time_enabled,%" PRIu64 ",time running,%" PRIu64 ",id,%" PRIu64 ",\n", - event_type.name.c_str(), counter_info.tid, counter_info.cpu, - counter_info.counter.value, counter_info.counter.time_enabled, + counters_info.event_name.c_str(), counter_info.tid, + counter_info.cpu, counter_info.counter.value, + counter_info.counter.time_enabled, counter_info.counter.time_running, counter_info.counter.id); } else { fprintf(fp, "%s(tid %d, cpu %d): count %" PRIu64 ", time_enabled %" PRIu64 ", time running %" PRIu64 ", id %" PRIu64 "\n", - event_type.name.c_str(), counter_info.tid, counter_info.cpu, - counter_info.counter.value, counter_info.counter.time_enabled, + counters_info.event_name.c_str(), counter_info.tid, + counter_info.cpu, counter_info.counter.value, + counter_info.counter.time_enabled, counter_info.counter.time_running, counter_info.counter.id); } } @@ -606,10 +606,9 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters, if (time_running_sum < time_enabled_sum && time_running_sum != 0) { scale = static_cast<double>(time_enabled_sum) / time_running_sum; } - summaries.AddSummary(CounterSummary( - counters_info.selection->event_type_modifier.event_type.name, - counters_info.selection->event_type_modifier.modifier, - counters_info.selection->group_id, value_sum, scale, false, csv_)); + summaries.AddSummary( + CounterSummary(counters_info.event_name, counters_info.event_modifier, + counters_info.group_id, value_sum, scale, false, csv_)); } summaries.AutoGenerateSummaries(); summaries.GenerateComments(duration_in_sec); diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp index b7b03557..d65b0dfb 100644 --- a/simpleperf/environment.cpp +++ b/simpleperf/environment.cpp @@ -36,6 +36,7 @@ #endif #include "read_elf.h" +#include "thread_tree.h" #include "utils.h" class LineReader { diff --git a/simpleperf/environment.h b/simpleperf/environment.h index 97467202..a6082ff4 100644 --- a/simpleperf/environment.h +++ b/simpleperf/environment.h @@ -18,6 +18,7 @@ #define SIMPLE_PERF_ENVIRONMENT_H_ #include <sys/types.h> +#include <time.h> #include <functional> #include <set> @@ -29,8 +30,6 @@ std::vector<int> GetOnlineCpus(); std::vector<int> GetCpusFromString(const std::string& s); -constexpr char DEFAULT_KERNEL_MMAP_NAME[] = "[kernel.kallsyms]"; - struct KernelMmap { std::string name; uint64_t start_addr; @@ -46,8 +45,7 @@ struct ThreadComm { }; bool GetThreadComms(std::vector<ThreadComm>* thread_comms); - -constexpr char DEFAULT_EXECNAME_FOR_THREAD_MMAP[] = "//anon"; +bool GetProcessIdForThread(pid_t tid, pid_t* pid); struct ThreadMmap { uint64_t start_addr; @@ -71,4 +69,13 @@ bool CheckPerfEventLimit(); bool CheckSampleFrequency(uint64_t sample_freq); bool CheckKernelSymbolAddresses(); +#if defined(__linux__) +static inline uint64_t GetSystemClock() { + timespec ts; + // Assume clock_gettime() doesn't fail. + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} +#endif + #endif // SIMPLE_PERF_ENVIRONMENT_H_ diff --git a/simpleperf/event_attr.h b/simpleperf/event_attr.h index 9182bb9d..2d140241 100644 --- a/simpleperf/event_attr.h +++ b/simpleperf/event_attr.h @@ -26,6 +26,11 @@ struct EventType; +struct EventAttrWithId { + const perf_event_attr* attr; + std::vector<uint64_t> ids; +}; + perf_event_attr CreateDefaultPerfEventAttr(const EventType& event_type); void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent = 0); bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& attrs, diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index d6b1fe68..9202bfad 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -25,6 +25,9 @@ #include "perf_regs.h" #include "utils.h" +constexpr uint64_t DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT = 4000; +constexpr uint64_t DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT = 1; + bool IsBranchSamplingSupported() { const EventType* type = FindEventTypeByName("cpu-cycles"); if (type == nullptr) { @@ -106,8 +109,6 @@ bool EventSelectionSet::AddEventGroup( if (!BuildAndCheckEventSelection(event_name, &selection)) { return false; } - selection.selection_id = group.size(); - selection.group_id = groups_.size(); group.push_back(std::move(selection)); } groups_.push_back(std::move(group)); @@ -115,6 +116,34 @@ bool EventSelectionSet::AddEventGroup( return true; } +std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const { + std::vector<const EventType*> result; + for (const auto& group : groups_) { + for (const auto& selection : group) { + if (selection.event_type_modifier.event_type.type == + PERF_TYPE_TRACEPOINT) { + result.push_back(&selection.event_type_modifier.event_type); + } + } + } + return result; +} + +std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const { + std::vector<EventAttrWithId> result; + for (const auto& group : groups_) { + for (const auto& selection : group) { + EventAttrWithId attr_id; + attr_id.attr = &selection.event_attr; + for (const auto& fd : selection.event_fds) { + attr_id.ids.push_back(fd->Id()); + } + result.push_back(attr_id); + } + } + return result; +} + // Union the sample type of different event attrs can make reading sample // records in perf.data easier. void EventSelectionSet::UnionSampleType() { @@ -169,18 +198,39 @@ void EventSelectionSet::SampleIdAll() { } } -void EventSelectionSet::SetSampleFreq(const EventSelection& selection, - uint64_t sample_freq) { - EventSelection& sel = groups_[selection.group_id][selection.selection_id]; - sel.event_attr.freq = 1; - sel.event_attr.sample_freq = sample_freq; +void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { + for (auto& group : groups_) { + for (auto& selection : group) { + selection.event_attr.freq = 1; + selection.event_attr.sample_freq = sample_freq; + } + } } -void EventSelectionSet::SetSamplePeriod(const EventSelection& selection, - uint64_t sample_period) { - EventSelection& sel = groups_[selection.group_id][selection.selection_id]; - sel.event_attr.freq = 0; - sel.event_attr.sample_period = sample_period; +void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { + for (auto& group : groups_) { + for (auto& selection : group) { + selection.event_attr.freq = 0; + selection.event_attr.sample_period = sample_period; + } + } +} + +void EventSelectionSet::UseDefaultSampleFreq() { + for (auto& group : groups_) { + for (auto& selection : group) { + if (selection.event_type_modifier.event_type.type == + PERF_TYPE_TRACEPOINT) { + selection.event_attr.freq = 0; + selection.event_attr.sample_period = + DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT; + } else { + selection.event_attr.freq = 1; + selection.event_attr.sample_freq = + DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT; + } + } + } } bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { @@ -253,6 +303,17 @@ void EventSelectionSet::SetLowWatermark() { } } +bool EventSelectionSet::NeedKernelSymbol() const { + for (const auto& group : groups_) { + for (const auto& selection : group) { + if (!selection.event_type_modifier.exclude_kernel) { + return true; + } + } + } + return false; +} + static bool CheckIfCpusOnline(const std::vector<int>& cpus) { std::vector<int> online_cpus = GetOnlineCpus(); for (const auto& cpu : cpus) { @@ -265,16 +326,14 @@ static bool CheckIfCpusOnline(const std::vector<int>& cpus) { return true; } -static bool OpenEventFile(EventSelectionGroup& group, pid_t tid, int cpu, - std::string* failed_event_type) { +bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, + pid_t tid, int cpu, + std::string* failed_event_type) { std::vector<std::unique_ptr<EventFd>> event_fds; // Given a tid and cpu, events on the same group should be all opened // successfully or all failed to open. + EventFd* group_fd = nullptr; for (auto& selection : group) { - EventFd* group_fd = nullptr; - if (selection.selection_id != 0) { - group_fd = event_fds[0].get(); - } std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd); if (event_fd != nullptr) { @@ -286,6 +345,9 @@ static bool OpenEventFile(EventSelectionGroup& group, pid_t tid, int cpu, return false; } } + if (group_fd == nullptr) { + group_fd = event_fd.get(); + } } for (size_t i = 0; i < group.size(); ++i) { group[i].event_fds.push_back(std::move(event_fds[i])); @@ -319,13 +381,13 @@ bool EventSelectionSet::OpenEventFiles(const std::vector<int>& on_cpus) { size_t success_cpu_count = 0; std::string failed_event_type; for (const auto& cpu : cpus) { - if (OpenEventFile(group, tid, cpu, &failed_event_type)) { + if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { success_cpu_count++; } } // As the online cpus can be enabled or disabled at runtime, we may not - // open event file for all cpus successfully. But we should open at least - // one cpu successfully. + // open event file for all cpus successfully. But we should open at + // least one cpu successfully. if (success_cpu_count == 0) { PLOG(ERROR) << "failed to open perf event file for event_type " << failed_event_type << " for " @@ -350,10 +412,12 @@ static bool ReadCounter(const EventFd* event_fd, CounterInfo* counter) { bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { counters->clear(); - for (auto& group : groups_) { - for (auto& selection : group) { + for (size_t i = 0; i < groups_.size(); ++i) { + for (auto& selection : groups_[i]) { CountersInfo counters_info; - counters_info.selection = &selection; + counters_info.group_id = i; + counters_info.event_name = selection.event_type_modifier.event_type.name; + counters_info.event_modifier = selection.event_type_modifier.modifier; counters_info.counters = selection.hotplugged_counters; for (auto& event_fd : selection.event_fds) { CounterInfo counter; @@ -550,7 +614,7 @@ bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) { for (auto& group : groups_) { for (const auto& tid : threads) { std::string failed_event_type; - if (!OpenEventFile(group, tid, cpu, &failed_event_type)) { + if (!OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { // If failed to open event files, maybe the cpu has been offlined. PLOG(WARNING) << "failed to open perf event file for event_type " << failed_event_type << " for " diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h index 53c8edda..32904c12 100644 --- a/simpleperf/event_selection_set.h +++ b/simpleperf/event_selection_set.h @@ -25,6 +25,7 @@ #include <android-base/macros.h> +#include "event_attr.h" #include "event_fd.h" #include "event_type.h" #include "perf_event.h" @@ -38,25 +39,13 @@ struct CounterInfo { PerfCounter counter; }; -struct EventSelection; - struct CountersInfo { - const EventSelection* selection; - std::vector<CounterInfo> counters; -}; - -struct EventSelection { uint32_t group_id; - uint32_t selection_id; - EventTypeAndModifier event_type_modifier; - perf_event_attr event_attr; - std::vector<std::unique_ptr<EventFd>> event_fds; - // counters for event files closed for cpu hotplug events - std::vector<CounterInfo> hotplugged_counters; + std::string event_name; + std::string event_modifier; + std::vector<CounterInfo> counters; }; -typedef std::vector<EventSelection> EventSelectionGroup; - class IOEventLoop; // EventSelectionSet helps to monitor events. It is used in following steps: @@ -81,21 +70,23 @@ class EventSelectionSet { bool empty() const { return groups_.empty(); } - const std::vector<EventSelectionGroup>& groups() { return groups_; } - bool AddEventType(const std::string& event_name); bool AddEventGroup(const std::vector<std::string>& event_names); + std::vector<const EventType*> GetTracepointEvents() const; + std::vector<EventAttrWithId> GetEventAttrWithId() const; void SetEnableOnExec(bool enable); bool GetEnableOnExec(); void SampleIdAll(); - void SetSampleFreq(const EventSelection& selection, uint64_t sample_freq); - void SetSamplePeriod(const EventSelection& selection, uint64_t sample_period); + void SetSampleFreq(uint64_t sample_freq); + void SetSamplePeriod(uint64_t sample_period); + void UseDefaultSampleFreq(); bool SetBranchSampling(uint64_t branch_sample_type); void EnableFpCallChainSampling(); bool EnableDwarfCallChainSampling(uint32_t dump_stack_size); void SetInherit(bool enable); void SetLowWatermark(); + bool NeedKernelSymbol() const; void AddMonitoredProcesses(const std::set<pid_t>& processes) { processes_.insert(processes.begin(), processes.end()); @@ -105,13 +96,9 @@ class EventSelectionSet { threads_.insert(threads.begin(), threads.end()); } - const std::set<pid_t>& GetMonitoredProcesses() const { - return processes_; - } + const std::set<pid_t>& GetMonitoredProcesses() const { return processes_; } - const std::set<pid_t>& GetMonitoredThreads() const { - return threads_; - } + const std::set<pid_t>& GetMonitoredThreads() const { return threads_; } bool HasMonitoredTarget() const { return !processes_.empty() || !threads_.empty(); @@ -131,9 +118,21 @@ class EventSelectionSet { DEFAULT_PERIOD_TO_DETECT_CPU_HOTPLUG_EVENTS_IN_SEC); private: + struct EventSelection { + EventTypeAndModifier event_type_modifier; + perf_event_attr event_attr; + std::vector<std::unique_ptr<EventFd>> event_fds; + // counters for event files closed for cpu hotplug events + std::vector<CounterInfo> hotplugged_counters; + }; + typedef std::vector<EventSelection> EventSelectionGroup; + bool BuildAndCheckEventSelection(const std::string& event_name, EventSelection* selection); void UnionSampleType(); + bool OpenEventFilesOnGroup(EventSelectionGroup& group, pid_t tid, int cpu, + std::string* failed_event_type); + bool MmapEventFiles(size_t mmap_pages, bool report_error); bool ReadMmapEventDataForFd(EventFd* event_fd); diff --git a/simpleperf/perf_clock.cpp b/simpleperf/perf_clock.cpp index 9ce41344..f6f65110 100644 --- a/simpleperf/perf_clock.cpp +++ b/simpleperf/perf_clock.cpp @@ -25,6 +25,7 @@ #include <android-base/logging.h> +#include "environment.h" #include "event_attr.h" #include "event_fd.h" #include "event_type.h" @@ -41,16 +42,6 @@ struct ThreadArg { std::atomic<bool> has_error; }; -static bool GetSystemClock(uint64_t* time_in_ns) { - timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - PLOG(ERROR) << "clock_gettime() failed"; - return false; - } - *time_in_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec; - return true; -} - static void ThreadA(ThreadArg* thread_arg) { thread_arg->thread_a_tid = syscall(SYS_gettid); while (!thread_arg->start_mmap) { @@ -69,10 +60,7 @@ static void ThreadA(ThreadArg* thread_arg) { // In case current thread is preempted by other threads, we run mmap() // multiple times and use the one with the smallest time interval. for (size_t i = 0; i < TRY_MMAP_COUNT; ++i) { - if (!GetSystemClock(&array[i].start_system_time_in_ns)) { - thread_arg->has_error = true; - return; - } + array[i].start_system_time_in_ns = GetSystemClock(); array[i].mmap_start_addr = mmap(NULL, 4096, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (array[i].mmap_start_addr == MAP_FAILED) { @@ -81,10 +69,7 @@ static void ThreadA(ThreadArg* thread_arg) { return; } - if (!GetSystemClock(&array[i].end_system_time_in_ns)) { - thread_arg->has_error = true; - return; - } + array[i].end_system_time_in_ns = GetSystemClock(); } size_t best_index = 0; uint64_t min_duration_in_ns = UINT64_MAX; @@ -177,12 +162,7 @@ bool InitPerfClock() { return true; } -bool GetPerfClock(uint64_t* time_in_ns) { +uint64_t GetPerfClock() { CHECK(perf_clock_initialized); - uint64_t system_time_in_ns; - if (!GetSystemClock(&system_time_in_ns)) { - return false; - } - *time_in_ns = system_time_in_ns + perf_clock_and_system_clock_diff_in_ns; - return true; + return GetSystemClock() + perf_clock_and_system_clock_diff_in_ns; } diff --git a/simpleperf/perf_clock.h b/simpleperf/perf_clock.h index 9bd5db9c..b4168e2c 100644 --- a/simpleperf/perf_clock.h +++ b/simpleperf/perf_clock.h @@ -26,6 +26,6 @@ // InitPerfClock() must be called before GetPerfClock(). bool InitPerfClock(); -bool GetPerfClock(uint64_t* time_in_ns); +uint64_t GetPerfClock(); #endif // SIMPLE_PERF_PERF_CLOCK_H_ diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h index 92775705..2d62343e 100644 --- a/simpleperf/record_file.h +++ b/simpleperf/record_file.h @@ -28,15 +28,11 @@ #include <android-base/macros.h> +#include "event_attr.h" #include "perf_event.h" #include "record.h" #include "record_file_format.h" -struct AttrWithId { - const perf_event_attr* attr; - std::vector<uint64_t> ids; -}; - // RecordFileWriter writes to a perf record file, like perf.data. class RecordFileWriter { public: @@ -44,7 +40,7 @@ class RecordFileWriter { ~RecordFileWriter(); - bool WriteAttrSection(const std::vector<AttrWithId>& attr_ids); + bool WriteAttrSection(const std::vector<EventAttrWithId>& attr_ids); bool WriteRecord(const Record& record); bool SortDataSection(); @@ -100,8 +96,8 @@ class RecordFileReader { return header_; } - std::vector<AttrWithId> AttrSection() const { - std::vector<AttrWithId> result(file_attrs_.size()); + std::vector<EventAttrWithId> AttrSection() const { + std::vector<EventAttrWithId> result(file_attrs_.size()); for (size_t i = 0; i < file_attrs_.size(); ++i) { result[i].attr = &file_attrs_[i].attr; result[i].ids = event_ids_for_file_attrs_[i]; diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp index f67894d9..2d619a2f 100644 --- a/simpleperf/record_file_test.cpp +++ b/simpleperf/record_file_test.cpp @@ -40,7 +40,7 @@ class RecordFileTest : public ::testing::Test { perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); attr.sample_id_all = 1; attrs_.push_back(std::unique_ptr<perf_event_attr>(new perf_event_attr(attr))); - AttrWithId attr_id; + EventAttrWithId attr_id; attr_id.attr = attrs_.back().get(); attr_id.ids.push_back(attrs_.size()); // Fake id. attr_ids_.push_back(attr_id); @@ -48,7 +48,7 @@ class RecordFileTest : public ::testing::Test { TemporaryFile tmpfile_; std::vector<std::unique_ptr<perf_event_attr>> attrs_; - std::vector<AttrWithId> attr_ids_; + std::vector<EventAttrWithId> attr_ids_; }; TEST_F(RecordFileTest, smoke) { @@ -80,7 +80,7 @@ TEST_F(RecordFileTest, smoke) { // Read from a record file. std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path); ASSERT_TRUE(reader != nullptr); - std::vector<AttrWithId> attrs = reader->AttrSection(); + std::vector<EventAttrWithId> attrs = reader->AttrSection(); ASSERT_EQ(1u, attrs.size()); ASSERT_EQ(0, memcmp(attrs[0].attr, attr_ids_[0].attr, sizeof(perf_event_attr))); ASSERT_EQ(attrs[0].ids, attr_ids_[0].ids); @@ -149,7 +149,7 @@ TEST_F(RecordFileTest, record_more_than_one_attr) { // Read from a record file. std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path); ASSERT_TRUE(reader != nullptr); - std::vector<AttrWithId> attrs = reader->AttrSection(); + std::vector<EventAttrWithId> attrs = reader->AttrSection(); ASSERT_EQ(3u, attrs.size()); for (size_t i = 0; i < attrs.size(); ++i) { ASSERT_EQ(0, memcmp(attrs[i].attr, attr_ids_[i].attr, sizeof(perf_event_attr))); diff --git a/simpleperf/record_file_writer.cpp b/simpleperf/record_file_writer.cpp index 94de4a74..8b57e836 100644 --- a/simpleperf/record_file_writer.cpp +++ b/simpleperf/record_file_writer.cpp @@ -68,7 +68,7 @@ RecordFileWriter::~RecordFileWriter() { } } -bool RecordFileWriter::WriteAttrSection(const std::vector<AttrWithId>& attr_ids) { +bool RecordFileWriter::WriteAttrSection(const std::vector<EventAttrWithId>& attr_ids) { if (attr_ids.empty()) { return false; } diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp index 096cf496..8522f39f 100644 --- a/simpleperf/report_lib_interface.cpp +++ b/simpleperf/report_lib_interface.cpp @@ -188,7 +188,7 @@ Sample* ReportLib::GetCurrentSample() { Event* ReportLib::GetEventOfCurrentSample() { if (!(update_flag_ & UPDATE_FLAG_OF_EVENT)) { if (event_attrs_.empty()) { - std::vector<AttrWithId> attrs = record_file_reader_->AttrSection(); + std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); for (const auto& attr_with_id : attrs) { EventAttrWithName attr; attr.attr = *attr_with_id.attr; diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp index 981a5dd2..56e5fbfb 100644 --- a/simpleperf/thread_tree.cpp +++ b/simpleperf/thread_tree.cpp @@ -23,7 +23,6 @@ #include <android-base/logging.h> #include <android-base/stringprintf.h> -#include "environment.h" #include "perf_event.h" #include "record.h" @@ -59,9 +58,11 @@ void ThreadTree::AddThread(int pid, int tid, const std::string& comm) { CHECK(pair.second); it = pair.first; } - thread_comm_storage_.push_back( - std::unique_ptr<std::string>(new std::string(comm))); - it->second->comm = thread_comm_storage_.back()->c_str(); + if (comm != it->second->comm) { + thread_comm_storage_.push_back( + std::unique_ptr<std::string>(new std::string(comm))); + it->second->comm = thread_comm_storage_.back()->c_str(); + } } void ThreadTree::ForkThread(int pid, int tid, int ppid, int ptid) { diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h index da32da16..703bc88a 100644 --- a/simpleperf/thread_tree.h +++ b/simpleperf/thread_tree.h @@ -24,10 +24,14 @@ #include <set> #include "dso.h" -#include "environment.h" +//#include "environment.h" struct Record; +constexpr char DEFAULT_KERNEL_MMAP_NAME[] = "[kernel.kallsyms]"; + +constexpr char DEFAULT_EXECNAME_FOR_THREAD_MMAP[] = "//anon"; + namespace simpleperf { struct MapEntry { |