diff options
author | Yabin Cui <yabinc@google.com> | 2023-04-17 22:18:01 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-04-17 22:18:01 +0000 |
commit | 5c3c372da8103f85c75590d0b328fa7b85f5d205 (patch) | |
tree | 16b603d2750fdcec01882fbfe3e1f999adb166c3 | |
parent | d9481184fff48d7cc8d70efb5e1bcbc4f849572e (diff) | |
parent | fcca320717c7ab5e6cfd268dca389c410433479a (diff) | |
download | extras-5c3c372da8103f85c75590d0b328fa7b85f5d205.tar.gz |
Merge changes Ie05c683e,I47026cac
* changes:
simpleperf: Remove stack and reg fields in samples after unwinding
simpleperf: Store perf_event_attr value in EventAttrWithId
-rw-r--r-- | simpleperf/RecordReadThread_test.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_debug_unwind.cpp | 7 | ||||
-rw-r--r-- | simpleperf/cmd_dumprecord.cpp | 10 | ||||
-rw-r--r-- | simpleperf/cmd_kmem.cpp | 5 | ||||
-rw-r--r-- | simpleperf/cmd_merge.cpp | 8 | ||||
-rw-r--r-- | simpleperf/cmd_monitor.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 46 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 37 | ||||
-rw-r--r-- | simpleperf/cmd_report.cpp | 5 | ||||
-rw-r--r-- | simpleperf/cmd_report_sample.cpp | 6 | ||||
-rw-r--r-- | simpleperf/cmd_stat_test.cpp | 8 | ||||
-rw-r--r-- | simpleperf/cmd_trace_sched.cpp | 6 | ||||
-rw-r--r-- | simpleperf/event_attr.cpp | 13 | ||||
-rw-r--r-- | simpleperf/event_attr.h | 16 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 13 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 2 | ||||
-rw-r--r-- | simpleperf/record.cpp | 4 | ||||
-rw-r--r-- | simpleperf/record_file.h | 16 | ||||
-rw-r--r-- | simpleperf/record_file_reader.cpp | 65 | ||||
-rw-r--r-- | simpleperf/record_file_test.cpp | 26 | ||||
-rw-r--r-- | simpleperf/record_file_writer.cpp | 6 | ||||
-rw-r--r-- | simpleperf/record_test.cpp | 4 | ||||
-rw-r--r-- | simpleperf/report_lib_interface.cpp | 6 |
23 files changed, 174 insertions, 139 deletions
diff --git a/simpleperf/RecordReadThread_test.cpp b/simpleperf/RecordReadThread_test.cpp index 2589d3a3..9917c650 100644 --- a/simpleperf/RecordReadThread_test.cpp +++ b/simpleperf/RecordReadThread_test.cpp @@ -77,7 +77,7 @@ TEST(RecordParser, smoke) { std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(GetTestData(PERF_DATA_NO_UNWIND)); ASSERT_TRUE(reader); - RecordParser parser(*reader->AttrSection()[0].attr); + RecordParser parser(reader->AttrSection()[0].attr); auto process_record = [&](std::unique_ptr<Record> record) { if (record->type() == PERF_RECORD_MMAP || record->type() == PERF_RECORD_COMM || record->type() == PERF_RECORD_FORK || record->type() == PERF_RECORD_SAMPLE) { diff --git a/simpleperf/cmd_debug_unwind.cpp b/simpleperf/cmd_debug_unwind.cpp index 3eb3a0c7..52d3c96c 100644 --- a/simpleperf/cmd_debug_unwind.cpp +++ b/simpleperf/cmd_debug_unwind.cpp @@ -403,12 +403,13 @@ class TestFileGenerator : public RecordFileProcessor { bool WriteMapsForSample(const SampleRecord& r) { ThreadEntry* thread = thread_tree_.FindThread(r.tid_data.tid); if (thread != nullptr && thread->maps) { - auto attr = reader_->AttrSection()[0].attr; - auto event_id = reader_->AttrSection()[0].ids[0]; + const EventAttrIds& attrs = reader_->AttrSection(); + const perf_event_attr& attr = attrs[0].attr; + uint64_t event_id = attrs[0].ids[0]; for (const auto& p : thread->maps->maps) { const MapEntry* map = p.second; - Mmap2Record map_record(*attr, false, r.tid_data.pid, r.tid_data.tid, map->start_addr, + Mmap2Record map_record(attr, false, r.tid_data.pid, r.tid_data.tid, map->start_addr, map->len, map->pgoff, map->flags, map->dso->Path(), event_id, r.Timestamp()); if (!writer_->WriteRecord(map_record)) { diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp index 89e56b67..9a71182f 100644 --- a/simpleperf/cmd_dumprecord.cpp +++ b/simpleperf/cmd_dumprecord.cpp @@ -306,11 +306,11 @@ void DumpRecordCommand::DumpFileHeader() { } void DumpRecordCommand::DumpAttrSection() { - std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); + const EventAttrIds& 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); - DumpPerfEventAttr(*attr.attr, 1); + DumpPerfEventAttr(attr.attr, 1); if (!attr.ids.empty()) { printf(" ids:"); for (const auto& id : attr.ids) { @@ -440,16 +440,16 @@ bool DumpRecordCommand::ProcessTracingData(const TracingDataRecord& r) { if (!tracing) { return false; } - std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); + const EventAttrIds& attrs = record_file_reader_->AttrSection(); events_.resize(attrs.size()); for (size_t i = 0; i < attrs.size(); i++) { auto& attr = attrs[i].attr; auto& event = events_[i]; - if (attr->type != PERF_TYPE_TRACEPOINT) { + if (attr.type != PERF_TYPE_TRACEPOINT) { continue; } - TracingFormat format = tracing->GetTracingFormatHavingId(attr->config); + TracingFormat format = tracing->GetTracingFormatHavingId(attr.config); event.tp_fields = format.fields; // Decide dump function for each field. for (size_t j = 0; j < event.tp_fields.size(); j++) { diff --git a/simpleperf/cmd_kmem.cpp b/simpleperf/cmd_kmem.cpp index 81746ba5..febc6518 100644 --- a/simpleperf/cmd_kmem.cpp +++ b/simpleperf/cmd_kmem.cpp @@ -532,10 +532,9 @@ bool KmemCommand::PrepareToBuildSampleTree() { } void KmemCommand::ReadEventAttrsFromRecordFile() { - std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); - for (const auto& attr_with_id : attrs) { + for (const EventAttrWithId& attr_with_id : record_file_reader_->AttrSection()) { EventAttrWithName attr; - attr.attr = *attr_with_id.attr; + attr.attr = attr_with_id.attr; attr.event_ids = attr_with_id.ids; attr.name = GetEventNameByAttr(attr.attr); event_attrs_.push_back(attr); diff --git a/simpleperf/cmd_merge.cpp b/simpleperf/cmd_merge.cpp index 6f9bc20c..1bf9833f 100644 --- a/simpleperf/cmd_merge.cpp +++ b/simpleperf/cmd_merge.cpp @@ -255,16 +255,16 @@ class MergeCommand : public Command { // Check attr sections to know if recorded event types are the same. bool CheckAttrSection() { - std::vector<EventAttrWithId> attrs0 = readers_[0]->AttrSection(); + const EventAttrIds& attrs0 = readers_[0]->AttrSection(); for (size_t i = 1; i < readers_.size(); i++) { - std::vector<EventAttrWithId> attrs = readers_[i]->AttrSection(); + const EventAttrIds& attrs = readers_[i]->AttrSection(); if (attrs.size() != attrs0.size()) { LOG(ERROR) << input_files_[0] << " and " << input_files_[i] << " are not mergeable for recording different event types"; return false; } for (size_t attr_id = 0; attr_id < attrs.size(); attr_id++) { - if (memcmp(attrs[attr_id].attr, attrs0[attr_id].attr, sizeof(perf_event_attr)) != 0) { + if (attrs[attr_id].attr != attrs0[attr_id].attr) { LOG(ERROR) << input_files_[0] << " and " << input_files_[i] << " are not mergeable for recording different event types"; return false; @@ -300,7 +300,7 @@ class MergeCommand : public Command { // map event_ids in readers_[next_read_id] to event attrs. The map info is put into an // EventIdRecord. const std::unordered_map<uint64_t, size_t>& cur_map = readers_[prev_reader_id]->EventIdMap(); - std::vector<EventAttrWithId> attrs = readers_[next_reader_id]->AttrSection(); + const EventAttrIds& attrs = readers_[next_reader_id]->AttrSection(); std::vector<uint64_t> event_id_data; for (size_t attr_id = 0; attr_id < attrs.size(); attr_id++) { for (size_t event_id : attrs[attr_id].ids) { diff --git a/simpleperf/cmd_monitor.cpp b/simpleperf/cmd_monitor.cpp index 437127d1..2ef9cbca 100644 --- a/simpleperf/cmd_monitor.cpp +++ b/simpleperf/cmd_monitor.cpp @@ -252,7 +252,7 @@ bool MonitorCommand::PrepareMonitoring() { // Use first perf_event_attr and first event id to dump mmap and comm records. EventAttrWithId dumping_attr_id = event_selection_set_.GetEventAttrWithId()[0]; - map_record_reader_.emplace(*dumping_attr_id.attr, dumping_attr_id.ids[0], + map_record_reader_.emplace(dumping_attr_id.attr, dumping_attr_id.ids[0], event_selection_set_.RecordNotExecutableMaps()); map_record_reader_->SetCallback([this](Record* r) { return ProcessRecord(r); }); diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index cfb01cd8..912d3e77 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -373,8 +373,8 @@ RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING bool TraceOffCpu(); bool SetEventSelectionFlags(); bool CreateAndInitRecordFile(); - std::unique_ptr<RecordFileWriter> CreateRecordFile( - const std::string& filename, const std::vector<EventAttrWithId>& override_attrs); + std::unique_ptr<RecordFileWriter> CreateRecordFile(const std::string& filename, + const EventAttrIds& attrs); bool DumpKernelSymbol(); bool DumpTracingData(); bool DumpMaps(); @@ -1370,32 +1370,35 @@ bool RecordCommand::SetEventSelectionFlags() { } bool RecordCommand::CreateAndInitRecordFile() { - record_file_writer_ = - CreateRecordFile(record_filename_, event_selection_set_.GetEventAttrWithId()); + EventAttrIds attrs = event_selection_set_.GetEventAttrWithId(); + bool remove_regs_and_stacks = unwind_dwarf_callchain_ && !post_unwind_; + if (remove_regs_and_stacks) { + for (auto& attr : attrs) { + ReplaceRegAndStackWithCallChain(attr.attr); + } + } + record_file_writer_ = CreateRecordFile(record_filename_, attrs); if (record_file_writer_ == nullptr) { return false; } // Use first perf_event_attr and first event id to dump mmap and comm records. - dumping_attr_id_ = event_selection_set_.GetEventAttrWithId()[0]; + CHECK(!attrs.empty()); + dumping_attr_id_ = attrs[0]; CHECK(!dumping_attr_id_.ids.empty()); - map_record_reader_.emplace(*dumping_attr_id_.attr, dumping_attr_id_.ids[0], + map_record_reader_.emplace(dumping_attr_id_.attr, dumping_attr_id_.ids[0], event_selection_set_.RecordNotExecutableMaps()); map_record_reader_->SetCallback([this](Record* r) { return ProcessRecord(r); }); return DumpKernelSymbol() && DumpTracingData() && DumpMaps() && DumpAuxTraceInfo(); } -std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile( - const std::string& filename, const std::vector<EventAttrWithId>& attrs) { +std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(const std::string& filename, + const EventAttrIds& attrs) { std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(filename); - if (writer == nullptr) { - return nullptr; - } - - if (!writer->WriteAttrSection(attrs)) { - return nullptr; + if (writer != nullptr && writer->WriteAttrSection(attrs)) { + return writer; } - return writer; + return nullptr; } bool RecordCommand::DumpKernelSymbol() { @@ -1603,7 +1606,7 @@ bool RecordCommand::ProcessJITDebugInfo(const std::vector<JITDebugInfo>& debug_i if (info.type == JITDebugInfo::JIT_DEBUG_JIT_CODE) { uint64_t timestamp = jit_debug_reader_->SyncWithRecords() ? info.timestamp : last_record_timestamp_; - Mmap2Record record(*dumping_attr_id_.attr, false, info.pid, info.pid, info.jit_code_addr, + Mmap2Record record(dumping_attr_id_.attr, false, info.pid, info.pid, info.jit_code_addr, info.jit_code_len, info.file_offset, map_flags::PROT_JIT_SYMFILE_MAP, info.file_path, dumping_attr_id_.ids[0], timestamp); if (!ProcessRecord(&record)) { @@ -1614,7 +1617,7 @@ bool RecordCommand::ProcessJITDebugInfo(const std::vector<JITDebugInfo>& debug_i ThreadMmap& map = *info.extracted_dex_file_map; uint64_t timestamp = jit_debug_reader_->SyncWithRecords() ? info.timestamp : last_record_timestamp_; - Mmap2Record record(*dumping_attr_id_.attr, false, info.pid, info.pid, map.start_addr, + Mmap2Record record(dumping_attr_id_.attr, false, info.pid, info.pid, map.start_addr, map.len, map.pgoff, map.prot, map.name, dumping_attr_id_.ids[0], timestamp); if (!ProcessRecord(&record)) { @@ -1844,6 +1847,15 @@ bool RecordCommand::PostUnwindRecords() { if (!reader) { return false; } + // Write new event attrs without regs and stacks fields. + EventAttrIds attrs = reader->AttrSection(); + for (auto& attr : attrs) { + ReplaceRegAndStackWithCallChain(attr.attr); + } + if (!record_file_writer_->WriteAttrSection(attrs)) { + return false; + } + sample_record_count_ = 0; auto callback = [this](std::unique_ptr<Record> record) { return SaveRecordAfterUnwinding(record.get()); diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index dfe8694e..395bfd19 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -98,15 +98,15 @@ static void CheckEventType(const std::string& record_file, const std::string& ev ASSERT_TRUE(type != nullptr); std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(record_file); ASSERT_TRUE(reader); - std::vector<EventAttrWithId> attrs = reader->AttrSection(); - for (auto& attr : attrs) { - if (attr.attr->type == type->type && attr.attr->config == type->config) { - if (attr.attr->freq == 0) { - ASSERT_EQ(sample_period, attr.attr->sample_period); + for (const auto& attr_with_id : reader->AttrSection()) { + const perf_event_attr& attr = attr_with_id.attr; + if (attr.type == type->type && attr.config == type->config) { + if (attr.freq == 0) { + ASSERT_EQ(sample_period, attr.sample_period); ASSERT_EQ(sample_freq, 0u); } else { ASSERT_EQ(sample_period, 0u); - ASSERT_EQ(sample_freq, attr.attr->sample_freq); + ASSERT_EQ(sample_freq, attr.sample_freq); } return; } @@ -204,10 +204,10 @@ TEST(record_cmd, rN_event) { ASSERT_TRUE(RunRecordCmd({"-e", event_name}, tmpfile.path)); std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path); ASSERT_TRUE(reader); - std::vector<EventAttrWithId> attrs = reader->AttrSection(); + const EventAttrIds& attrs = reader->AttrSection(); ASSERT_EQ(1u, attrs.size()); - ASSERT_EQ(PERF_TYPE_RAW, attrs[0].attr->type); - ASSERT_EQ(event_number, attrs[0].attr->config); + ASSERT_EQ(PERF_TYPE_RAW, attrs[0].attr.type); + ASSERT_EQ(event_number, attrs[0].attr.config); } TEST(record_cmd, branch_sampling) { @@ -257,7 +257,16 @@ TEST(record_cmd, dwarf_callchain_sampling) { ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf"})); ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,16384"})); ASSERT_FALSE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,65536"})); - ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"})); + TemporaryFile tmpfile; + ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}, tmpfile.path)); + auto reader = RecordFileReader::CreateInstance(tmpfile.path); + ASSERT_TRUE(reader); + const EventAttrIds& attrs = reader->AttrSection(); + ASSERT_GT(attrs.size(), 0); + // Check that reg and stack fields are removed after unwinding. + for (const auto& attr : attrs) { + ASSERT_EQ(attr.attr.sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER), 0); + } } TEST(record_cmd, system_wide_dwarf_callchain_sampling) { @@ -552,7 +561,7 @@ TEST(record_cmd, trace_offcpu_option) { auto info_map = reader->GetMetaInfoFeature(); ASSERT_EQ(info_map["trace_offcpu"], "true"); if (IsSwitchRecordSupported()) { - ASSERT_EQ(reader->AttrSection()[0].attr->context_switch, 1); + ASSERT_EQ(reader->AttrSection()[0].attr.context_switch, 1); } // Release recording environment in perf.data, to avoid affecting tests below. reader.reset(); @@ -944,9 +953,9 @@ TEST(record_cmd, cs_etm_event) { // cs-etm uses sample period instead of sample freq. ASSERT_EQ(reader->AttrSection().size(), 1u); - const perf_event_attr* attr = reader->AttrSection()[0].attr; - ASSERT_EQ(attr->freq, 0); - ASSERT_EQ(attr->sample_period, 1); + const perf_event_attr& attr = reader->AttrSection()[0].attr; + ASSERT_EQ(attr.freq, 0); + ASSERT_EQ(attr.sample_period, 1); bool has_auxtrace_info = false; bool has_auxtrace = false; diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp index 2f2dab10..2ab98548 100644 --- a/simpleperf/cmd_report.cpp +++ b/simpleperf/cmd_report.cpp @@ -856,9 +856,8 @@ bool ReportCommand::ReadMetaInfoFromRecordFile() { } bool ReportCommand::ReadEventAttrFromRecordFile() { - std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); - for (const auto& attr_with_id : attrs) { - const perf_event_attr& attr = *attr_with_id.attr; + for (const EventAttrWithId& attr_with_id : record_file_reader_->AttrSection()) { + const perf_event_attr& attr = attr_with_id.attr; attr_names_.emplace_back(GetEventNameByAttr(attr)); // There are no samples for events added by --add-counter. So skip them. diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp index 1026dbbe..12e3ed61 100644 --- a/simpleperf/cmd_report_sample.cpp +++ b/simpleperf/cmd_report_sample.cpp @@ -522,7 +522,7 @@ bool ReportSampleCommand::OpenRecordFile() { if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) { trace_offcpu_ = it->second == "true"; if (trace_offcpu_) { - std::string event_name = GetEventNameByAttr(*record_file_reader_->AttrSection()[0].attr); + std::string event_name = GetEventNameByAttr(record_file_reader_->AttrSection()[0].attr); if (!android::base::StartsWith(event_name, "cpu-clock") && !android::base::StartsWith(event_name, "task-clock")) { LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. " @@ -537,8 +537,8 @@ bool ReportSampleCommand::OpenRecordFile() { if (!record_filter_.CheckClock(record_file_reader_->GetClockId())) { return false; } - for (EventAttrWithId& attr : record_file_reader_->AttrSection()) { - event_types_.push_back(GetEventNameByAttr(*attr.attr)); + for (const EventAttrWithId& attr : record_file_reader_->AttrSection()) { + event_types_.push_back(GetEventNameByAttr(attr.attr)); } return true; } diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp index dff42a21..53ff0d48 100644 --- a/simpleperf/cmd_stat_test.cpp +++ b/simpleperf/cmd_stat_test.cpp @@ -233,12 +233,12 @@ TEST(stat_cmd, sample_speed_should_be_zero) { ASSERT_TRUE(set.AddEventType("cpu-cycles")); set.AddMonitoredProcesses({getpid()}); ASSERT_TRUE(set.OpenEventFiles({-1})); - std::vector<EventAttrWithId> attrs = set.GetEventAttrWithId(); + const EventAttrIds& attrs = set.GetEventAttrWithId(); ASSERT_GT(attrs.size(), 0u); for (auto& attr : attrs) { - ASSERT_EQ(attr.attr->sample_period, 0u); - ASSERT_EQ(attr.attr->sample_freq, 0u); - ASSERT_EQ(attr.attr->freq, 0u); + ASSERT_EQ(attr.attr.sample_period, 0u); + ASSERT_EQ(attr.attr.sample_freq, 0u); + ASSERT_EQ(attr.attr.freq, 0u); } } diff --git a/simpleperf/cmd_trace_sched.cpp b/simpleperf/cmd_trace_sched.cpp index 607fb2a4..d02495a9 100644 --- a/simpleperf/cmd_trace_sched.cpp +++ b/simpleperf/cmd_trace_sched.cpp @@ -192,9 +192,9 @@ bool TraceSchedCommand::ParseSchedEvents(const std::string& record_file_path) { return false; } const EventType* event = FindEventTypeByName("sched:sched_stat_runtime"); - std::vector<EventAttrWithId> attrs = reader->AttrSection(); - if (attrs.size() != 1u || attrs[0].attr->type != event->type || - attrs[0].attr->config != event->config) { + const EventAttrIds& attrs = reader->AttrSection(); + if (attrs.size() != 1u || attrs[0].attr.type != event->type || + attrs[0].attr.config != event->config) { LOG(ERROR) << "sched:sched_stat_runtime isn't recorded in " << record_file_path; return false; } diff --git a/simpleperf/event_attr.cpp b/simpleperf/event_attr.cpp index dea77a94..b8acc341 100644 --- a/simpleperf/event_attr.cpp +++ b/simpleperf/event_attr.cpp @@ -145,7 +145,7 @@ void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent) { PrintIndented(indent + 1, "sample_stack_user 0x%" PRIx64 "\n", attr.sample_stack_user); } -bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& attrs, +bool GetCommonEventIdPositionsForAttrs(const EventAttrIds& attrs, size_t* event_id_pos_in_sample_records, size_t* event_id_reverse_pos_in_non_sample_records) { // When there are more than one perf_event_attrs, we need to read event id @@ -153,7 +153,7 @@ bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& attrs, // we need to determine the event id position in a record here. std::vector<uint64_t> sample_types; for (const auto& attr : attrs) { - sample_types.push_back(attr.sample_type); + sample_types.push_back(attr.attr.sample_type); } // First determine event_id_pos_in_sample_records. // If PERF_SAMPLE_IDENTIFIER is enabled, it is just after perf_event_header. @@ -192,7 +192,7 @@ bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& attrs, // also be the same. bool sample_id_all_enabled = true; for (const auto& attr : attrs) { - if (attr.sample_id_all == 0) { + if (attr.attr.sample_id_all == 0) { sample_id_all_enabled = false; } } @@ -254,4 +254,11 @@ std::string GetEventNameByAttr(const perf_event_attr& attr) { return name; } +void ReplaceRegAndStackWithCallChain(perf_event_attr& attr) { + attr.sample_type &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER); + attr.exclude_callchain_user = 0; + attr.sample_regs_user = 0; + attr.sample_stack_user = 0; +} + } // namespace simpleperf diff --git a/simpleperf/event_attr.h b/simpleperf/event_attr.h index a9d8bba7..5521f328 100644 --- a/simpleperf/event_attr.h +++ b/simpleperf/event_attr.h @@ -18,6 +18,7 @@ #define SIMPLE_PERF_EVENT_ATTR_H_ #include <stddef.h> +#include <string.h> #include <string> #include <vector> @@ -29,15 +30,17 @@ namespace simpleperf { struct EventType; struct EventAttrWithId { - const perf_event_attr* attr; + perf_event_attr attr; std::vector<uint64_t> ids; }; +using EventAttrIds = std::vector<EventAttrWithId>; + inline constexpr uint64_t INFINITE_SAMPLE_PERIOD = 1ULL << 62; 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, +bool GetCommonEventIdPositionsForAttrs(const EventAttrIds& attrs, size_t* event_id_pos_in_sample_records, size_t* event_id_reverse_pos_in_non_sample_records); bool IsTimestampSupported(const perf_event_attr& attr); @@ -45,6 +48,15 @@ bool IsCpuSupported(const perf_event_attr& attr); // Return event name with modifier if the event is found, otherwise return "unknown". // This function is slow for using linear search, so only used when reporting. std::string GetEventNameByAttr(const perf_event_attr& attr); +void ReplaceRegAndStackWithCallChain(perf_event_attr& attr); + +inline bool operator==(const perf_event_attr& attr1, const perf_event_attr& attr2) { + return memcmp(&attr1, &attr2, sizeof(perf_event_attr)) == 0; +} + +inline bool operator!=(const perf_event_attr& attr1, const perf_event_attr& attr2) { + return !(attr1 == attr2); +} } // namespace simpleperf diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index 58b4b956..2fdb88f5 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -367,16 +367,17 @@ bool EventSelectionSet::ExcludeKernel() const { return true; } -std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const { - std::vector<EventAttrWithId> result; +EventAttrIds EventSelectionSet::GetEventAttrWithId() const { + EventAttrIds result; for (const auto& group : groups_) { for (const auto& selection : group) { - EventAttrWithId attr_id; - attr_id.attr = &selection.event_attr; + std::vector<uint64_t> ids; for (const auto& fd : selection.event_fds) { - attr_id.ids.push_back(fd->Id()); + ids.push_back(fd->Id()); } - result.push_back(attr_id); + result.resize(result.size() + 1); + result.back().attr = selection.event_attr; + result.back().ids = std::move(ids); } } return result; diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h index 07754fd2..757034dc 100644 --- a/simpleperf/event_selection_set.h +++ b/simpleperf/event_selection_set.h @@ -115,7 +115,7 @@ class EventSelectionSet { std::vector<const EventType*> GetTracepointEvents() const; bool ExcludeKernel() const; bool HasAuxTrace() const { return has_aux_trace_; } - std::vector<EventAttrWithId> GetEventAttrWithId() const; + EventAttrIds GetEventAttrWithId() const; std::unordered_map<uint64_t, std::string> GetEventNamesById() const; void SetEnableOnExec(bool enable); diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp index 40d3287a..c364b2fc 100644 --- a/simpleperf/record.cpp +++ b/simpleperf/record.cpp @@ -713,8 +713,10 @@ SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id, uint64_t ip void SampleRecord::ReplaceRegAndStackWithCallChain(const std::vector<uint64_t>& ips) { uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1); uint32_t size_reduced_in_reg_stack = - regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size + sizeof(uint64_t); + (regs_user_data.reg_nr + 1) * sizeof(uint64_t) + stack_user_data.size + sizeof(uint64_t) * 2; + uint32_t new_size = size() + size_added_in_callchain - size_reduced_in_reg_stack; + sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER); BuildBinaryWithNewCallChain(new_size, ips); } diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h index 6daae288..51c7b245 100644 --- a/simpleperf/record_file.h +++ b/simpleperf/record_file.h @@ -81,7 +81,7 @@ class RecordFileWriter { RecordFileWriter(const std::string& filename, FILE* fp, bool own_fp); ~RecordFileWriter(); - bool WriteAttrSection(const std::vector<EventAttrWithId>& attr_ids); + bool WriteAttrSection(const EventAttrIds& attr_ids); bool WriteRecord(const Record& record); bool WriteData(const void* buf, size_t len); @@ -141,14 +141,7 @@ class RecordFileReader { const PerfFileFormat::FileHeader& FileHeader() const { return header_; } - 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]; - } - return result; - } + const EventAttrIds& AttrSection() const { return event_attrs_; } const std::unordered_map<uint64_t, size_t>& EventIdMap() const { return event_id_to_attr_map_; } @@ -208,7 +201,7 @@ class RecordFileReader { bool CheckSectionDesc(const PerfFileFormat::SectionDesc& desc, uint64_t min_offset, uint64_t alignment = 1); bool ReadAttrSection(); - bool ReadIdsForAttr(const PerfFileFormat::FileAttr& attr, std::vector<uint64_t>* ids); + bool ReadIdSection(const PerfFileFormat::SectionDesc& section, std::vector<uint64_t>* ids); bool ReadFeatureSectionDescriptors(); bool ReadFileV1Feature(uint64_t& read_pos, uint64_t max_size, FileFeature& file); bool ReadFileV2Feature(uint64_t& read_pos, uint64_t max_size, FileFeature& file); @@ -224,8 +217,7 @@ class RecordFileReader { uint64_t file_size_; PerfFileFormat::FileHeader header_; - std::vector<PerfFileFormat::FileAttr> file_attrs_; - std::vector<std::vector<uint64_t>> event_ids_for_file_attrs_; + EventAttrIds event_attrs_; std::unordered_map<uint64_t, size_t> event_id_to_attr_map_; std::map<int, PerfFileFormat::SectionDesc> feature_section_descriptors_; diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp index 166917c8..d7f1d5eb 100644 --- a/simpleperf/record_file_reader.cpp +++ b/simpleperf/record_file_reader.cpp @@ -166,42 +166,42 @@ bool RecordFileReader::ReadAttrSection() { PLOG(ERROR) << "fseek() failed"; return false; } + event_attrs_.resize(attr_count); + std::vector<SectionDesc> id_sections(attr_count); + size_t attr_size_in_file = header_.attr_size - sizeof(SectionDesc); for (size_t i = 0; i < attr_count; ++i) { std::vector<char> buf(header_.attr_size); if (!Read(buf.data(), buf.size())) { return false; } - // The size of perf_event_attr is changing between different linux kernel versions. - // Make sure we copy correct data to memory. - FileAttr attr; - memset(&attr, 0, sizeof(attr)); - size_t section_desc_size = sizeof(attr.ids); - size_t perf_event_attr_size = header_.attr_size - section_desc_size; - memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size)); - memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size); - if (!CheckSectionDesc(attr.ids, 0, sizeof(uint64_t))) { + // The struct perf_event_attr is defined in a Linux header file. It can be extended in newer + // kernel versions with more fields and a bigger size. To disable these extensions, set their + // values to zero. So to copy perf_event_attr from file to memory safely, ensure the copy + // doesn't overflow the file or memory, and set the values of any extra fields in memory to + // zero. + if (attr_size_in_file >= sizeof(perf_event_attr)) { + memcpy(&event_attrs_[i].attr, &buf[0], sizeof(perf_event_attr)); + } else { + memset(&event_attrs_[i].attr, 0, sizeof(perf_event_attr)); + memcpy(&event_attrs_[i].attr, &buf[0], attr_size_in_file); + } + memcpy(&id_sections[i], &buf[attr_size_in_file], sizeof(SectionDesc)); + if (!CheckSectionDesc(id_sections[i], 0, sizeof(uint64_t))) { LOG(ERROR) << "invalid attr section in " << filename_; return false; } - file_attrs_.push_back(attr); } - if (file_attrs_.size() > 1) { - std::vector<perf_event_attr> attrs; - for (const auto& file_attr : file_attrs_) { - attrs.push_back(file_attr.attr); - } - if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_, + if (event_attrs_.size() > 1) { + if (!GetCommonEventIdPositionsForAttrs(event_attrs_, &event_id_pos_in_sample_records_, &event_id_reverse_pos_in_non_sample_records_)) { return false; } } - for (size_t i = 0; i < file_attrs_.size(); ++i) { - std::vector<uint64_t> ids; - if (!ReadIdsForAttr(file_attrs_[i], &ids)) { + for (size_t i = 0; i < attr_count; ++i) { + if (!ReadIdSection(id_sections[i], &event_attrs_[i].ids)) { return false; } - event_ids_for_file_attrs_.push_back(ids); - for (auto id : ids) { + for (auto id : event_attrs_[i].ids) { event_id_to_attr_map_[id] = i; } } @@ -237,14 +237,14 @@ bool RecordFileReader::ReadFeatureSectionDescriptors() { return true; } -bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) { - size_t id_count = attr.ids.size / sizeof(uint64_t); - if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) { +bool RecordFileReader::ReadIdSection(const SectionDesc& section, std::vector<uint64_t>* ids) { + size_t id_count = section.size / sizeof(uint64_t); + if (fseek(record_fp_, section.offset, SEEK_SET) != 0) { PLOG(ERROR) << "fseek() failed"; return false; } ids->resize(id_count); - if (!Read(ids->data(), attr.ids.size)) { + if (!Read(ids->data(), section.size)) { return false; } return true; @@ -342,8 +342,8 @@ std::unique_ptr<Record> RecordFileReader::ReadRecord() { read_record_size_ += header.size; } - const perf_event_attr* attr = &file_attrs_[0].attr; - if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) { + const perf_event_attr* attr = &event_attrs_[0].attr; + if (event_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) { bool has_event_id = false; uint64_t event_id; if (header.type == PERF_RECORD_SAMPLE) { @@ -361,7 +361,7 @@ std::unique_ptr<Record> RecordFileReader::ReadRecord() { if (has_event_id) { auto it = event_id_to_attr_map_.find(event_id); if (it != event_id_to_attr_map_.end()) { - attr = &file_attrs_[it->second].attr; + attr = &event_attrs_[it->second].attr; } } } @@ -401,8 +401,9 @@ bool RecordFileReader::ReadAtOffset(uint64_t offset, void* buf, size_t len) { void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) { for (size_t i = 0; i < r.count; ++i) { - event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id); - event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id; + const auto& data = r.data[i]; + event_attrs_[data.attr_id].ids.push_back(data.event_id); + event_id_to_attr_map_[data.event_id] = data.attr_id; } } @@ -489,7 +490,7 @@ std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() { memcpy(binary.get(), p, header->size); p += header->size; BuildIdRecord record; - if (!record.Parse(file_attrs_[0].attr, binary.get(), binary.get() + header->size)) { + if (!record.Parse(event_attrs_[0].attr, binary.get(), binary.get() + header->size)) { return {}; } binary.release(); @@ -811,7 +812,7 @@ bool RecordFileReader::BuildAuxDataLocation() { return false; } AuxTraceRecord auxtrace; - if (!auxtrace.Parse(file_attrs_[0].attr, buf.get(), buf.get() + AuxTraceRecord::Size())) { + if (!auxtrace.Parse(event_attrs_[0].attr, buf.get(), buf.get() + AuxTraceRecord::Size())) { return false; } AuxDataLocation location(auxtrace.data->offset, auxtrace.data->aux_size, diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp index 395b6603..e43e4bdf 100644 --- a/simpleperf/record_file_test.cpp +++ b/simpleperf/record_file_test.cpp @@ -40,20 +40,18 @@ class RecordFileTest : public ::testing::Test { void SetUp() override { close(tmpfile_.release()); } void AddEventType(const std::string& event_type_str) { + uint64_t fake_id = attr_ids_.size(); + attr_ids_.resize(attr_ids_.size() + 1); + EventAttrWithId& attr_id = attr_ids_.back(); std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_str); ASSERT_TRUE(event_type_modifier != nullptr); - 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))); - EventAttrWithId attr_id; - attr_id.attr = attrs_.back().get(); - attr_id.ids.push_back(attrs_.size()); // Fake id. - attr_ids_.push_back(attr_id); + attr_id.attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); + attr_id.attr.sample_id_all = 1; + attr_id.ids.push_back(fake_id); } TemporaryFile tmpfile_; - std::vector<std::unique_ptr<perf_event_attr>> attrs_; - std::vector<EventAttrWithId> attr_ids_; + EventAttrIds attr_ids_; }; TEST_F(RecordFileTest, smoke) { @@ -66,7 +64,7 @@ TEST_F(RecordFileTest, smoke) { ASSERT_TRUE(writer->WriteAttrSection(attr_ids_)); // Write data section. - MmapRecord mmap_record(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000, 0x3000, + MmapRecord mmap_record(attr_ids_[0].attr, true, 1, 1, 0x1000, 0x2000, 0x3000, "mmap_record_example", attr_ids_[0].ids[0]); ASSERT_TRUE(writer->WriteRecord(mmap_record)); @@ -86,9 +84,9 @@ TEST_F(RecordFileTest, smoke) { // Read from a record file. std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path); ASSERT_TRUE(reader != nullptr); - std::vector<EventAttrWithId> attrs = reader->AttrSection(); + const EventAttrIds& 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(0, memcmp(&attrs[0].attr, &attr_ids_[0].attr, sizeof(perf_event_attr))); ASSERT_EQ(attrs[0].ids, attr_ids_[0].ids); // Read and check data section. @@ -120,10 +118,10 @@ 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<EventAttrWithId> attrs = reader->AttrSection(); + const EventAttrIds& 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))); + ASSERT_EQ(0, memcmp(&attrs[i].attr, &attr_ids_[i].attr, sizeof(perf_event_attr))); ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids); } } diff --git a/simpleperf/record_file_writer.cpp b/simpleperf/record_file_writer.cpp index bcc26a33..ed94e398 100644 --- a/simpleperf/record_file_writer.cpp +++ b/simpleperf/record_file_writer.cpp @@ -74,7 +74,7 @@ RecordFileWriter::~RecordFileWriter() { } } -bool RecordFileWriter::WriteAttrSection(const std::vector<EventAttrWithId>& attr_ids) { +bool RecordFileWriter::WriteAttrSection(const EventAttrIds& attr_ids) { if (attr_ids.empty()) { return false; } @@ -102,7 +102,7 @@ bool RecordFileWriter::WriteAttrSection(const std::vector<EventAttrWithId>& attr } for (auto& attr_id : attr_ids) { FileAttr file_attr; - file_attr.attr = *attr_id.attr; + file_attr.attr = attr_id.attr; file_attr.ids.offset = id_section_offset; file_attr.ids.size = attr_id.ids.size() * sizeof(uint64_t); id_section_offset += file_attr.ids.size; @@ -121,7 +121,7 @@ bool RecordFileWriter::WriteAttrSection(const std::vector<EventAttrWithId>& attr data_section_offset_ = data_section_offset; // Save event_attr for use when reading records. - event_attr_ = *attr_ids[0].attr; + event_attr_ = attr_ids[0].attr; return true; } diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp index ddecc9bd..8d9d151a 100644 --- a/simpleperf/record_test.cpp +++ b/simpleperf/record_test.cpp @@ -104,11 +104,13 @@ TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) { } TEST_F(RecordTest, SampleRecord_ReplaceRegAndStackWithCallChain) { - event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; + event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, PERF_CONTEXT_USER, 2, 3, 4, 5}, {}, 0); for (size_t stack_size : {8, 1024}) { + event_attr.sample_type |= PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1}, std::vector<char>(stack_size), 10); + event_attr.sample_type &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER); r.ReplaceRegAndStackWithCallChain({2, 3, 4, 5}); CheckRecordMatchBinary(r); CheckRecordEqual(r, expected); diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp index d94d6a76..3654c57e 100644 --- a/simpleperf/report_lib_interface.cpp +++ b/simpleperf/report_lib_interface.cpp @@ -332,7 +332,7 @@ bool ReportLib::OpenRecordFileIfNecessary() { auto& meta_info = record_file_reader_->GetMetaInfoFeature(); if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end() && it->second == "true") { // If recorded with --trace-offcpu, default is to report on-off-cpu samples. - std::string event_name = GetEventNameByAttr(*record_file_reader_->AttrSection()[0].attr); + std::string event_name = GetEventNameByAttr(record_file_reader_->AttrSection()[0].attr); if (!android::base::StartsWith(event_name, "cpu-clock") && !android::base::StartsWith(event_name, "task-clock")) { LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. " @@ -517,10 +517,10 @@ const EventInfo* ReportLib::FindEventOfCurrentSample() { } void ReportLib::CreateEvents() { - std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); + const EventAttrIds& attrs = record_file_reader_->AttrSection(); events_.resize(attrs.size()); for (size_t i = 0; i < attrs.size(); ++i) { - events_[i].attr = *attrs[i].attr; + events_[i].attr = attrs[i].attr; events_[i].name = GetEventNameByAttr(events_[i].attr); EventInfo::TracingInfo& tracing_info = events_[i].tracing_info; if (events_[i].attr.type == PERF_TYPE_TRACEPOINT && tracing_) { |