summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2023-04-17 22:18:01 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-04-17 22:18:01 +0000
commit5c3c372da8103f85c75590d0b328fa7b85f5d205 (patch)
tree16b603d2750fdcec01882fbfe3e1f999adb166c3
parentd9481184fff48d7cc8d70efb5e1bcbc4f849572e (diff)
parentfcca320717c7ab5e6cfd268dca389c410433479a (diff)
downloadextras-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.cpp2
-rw-r--r--simpleperf/cmd_debug_unwind.cpp7
-rw-r--r--simpleperf/cmd_dumprecord.cpp10
-rw-r--r--simpleperf/cmd_kmem.cpp5
-rw-r--r--simpleperf/cmd_merge.cpp8
-rw-r--r--simpleperf/cmd_monitor.cpp2
-rw-r--r--simpleperf/cmd_record.cpp46
-rw-r--r--simpleperf/cmd_record_test.cpp37
-rw-r--r--simpleperf/cmd_report.cpp5
-rw-r--r--simpleperf/cmd_report_sample.cpp6
-rw-r--r--simpleperf/cmd_stat_test.cpp8
-rw-r--r--simpleperf/cmd_trace_sched.cpp6
-rw-r--r--simpleperf/event_attr.cpp13
-rw-r--r--simpleperf/event_attr.h16
-rw-r--r--simpleperf/event_selection_set.cpp13
-rw-r--r--simpleperf/event_selection_set.h2
-rw-r--r--simpleperf/record.cpp4
-rw-r--r--simpleperf/record_file.h16
-rw-r--r--simpleperf/record_file_reader.cpp65
-rw-r--r--simpleperf/record_file_test.cpp26
-rw-r--r--simpleperf/record_file_writer.cpp6
-rw-r--r--simpleperf/record_test.cpp4
-rw-r--r--simpleperf/report_lib_interface.cpp6
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_) {