summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-04-06 01:15:22 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-04-06 01:15:22 +0000
commit0d47fe0430a0d6edc517486478f50b1fb2987106 (patch)
treef135bfaf77d12693399c6617cbcf61470944ccde
parent05e61bec49233712091be9d40ee46962170a118d (diff)
parent2d6efe4b167da4e6b77f168b1820239ee65599e2 (diff)
downloadextras-0d47fe0430a0d6edc517486478f50b1fb2987106.tar.gz
Merge "simpleperf: support reporting more than one event type."android-n-preview-2
-rw-r--r--simpleperf/cmd_record.cpp73
-rw-r--r--simpleperf/cmd_report.cpp46
-rw-r--r--simpleperf/cmd_report_test.cpp7
-rw-r--r--simpleperf/event_attr.cpp87
-rw-r--r--simpleperf/event_attr.h6
-rw-r--r--simpleperf/event_fd.cpp2
-rw-r--r--simpleperf/event_fd.h2
-rw-r--r--simpleperf/event_selection_set.cpp74
-rw-r--r--simpleperf/event_selection_set.h14
-rw-r--r--simpleperf/get_test_data.h3
-rw-r--r--simpleperf/record.cpp58
-rw-r--r--simpleperf/record.h16
-rw-r--r--simpleperf/record_file.h6
-rw-r--r--simpleperf/record_file_reader.cpp66
-rw-r--r--simpleperf/record_file_test.cpp6
-rw-r--r--simpleperf/record_test.cpp27
-rw-r--r--simpleperf/testdata/perf_with_two_event_types.databin0 -> 23168 bytes
17 files changed, 330 insertions, 163 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 1cea1734..85a28d46 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -135,17 +135,15 @@ class RecordCommand : public Command {
bool Run(const std::vector<std::string>& args);
- static bool ReadMmapDataCallback(const char* data, size_t size);
-
private:
bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* non_option_args);
bool AddMeasuredEventType(const std::string& event_type_name);
bool SetEventSelection();
bool CreateAndInitRecordFile();
std::unique_ptr<RecordFileWriter> CreateRecordFile(const std::string& filename);
- bool DumpKernelAndModuleMmaps();
- bool DumpThreadCommAndMmaps(bool all_threads, const std::vector<pid_t>& selected_threads);
- bool CollectRecordsFromKernel(const char* data, size_t size);
+ bool DumpKernelAndModuleMmaps(const perf_event_attr* attr, uint64_t event_id);
+ bool DumpThreadCommAndMmaps(const perf_event_attr* attr, uint64_t event_id,
+ bool all_threads, const std::vector<pid_t>& selected_threads);
bool ProcessRecord(Record* record);
void UpdateRecordForEmbeddedElfPath(Record* record);
void UnwindRecord(Record* record);
@@ -175,7 +173,6 @@ class RecordCommand : public Command {
// mmap pages used by each perf event file, should be a power of 2.
size_t perf_mmap_pages_;
- std::unique_ptr<RecordCache> record_cache_;
ThreadTree thread_tree_;
std::string record_filename_;
std::unique_ptr<RecordFileWriter> record_file_writer_;
@@ -236,7 +233,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
return false;
}
std::vector<pollfd> pollfds;
- event_selection_set_.PreparePollForEventFiles(&pollfds);
+ event_selection_set_.PrepareToPollForEventFiles(&pollfds);
// 4. Create perf.data.
if (!CreateAndInitRecordFile()) {
@@ -247,12 +244,10 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
if (workload != nullptr && !workload->Start()) {
return false;
}
- record_cache_.reset(
- new RecordCache(*event_selection_set_.FindEventAttrByType(measured_event_types_[0])));
- auto callback = std::bind(&RecordCommand::CollectRecordsFromKernel, this, std::placeholders::_1,
- std::placeholders::_2);
+ auto callback = std::bind(&RecordCommand::ProcessRecord, this, std::placeholders::_1);
+ event_selection_set_.PrepareToReadMmapEventData(callback);
while (true) {
- if (!event_selection_set_.ReadMmapEventData(callback)) {
+ if (!event_selection_set_.ReadMmapEventData()) {
return false;
}
if (signaled) {
@@ -260,12 +255,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
}
poll(&pollfds[0], pollfds.size(), -1);
}
- std::vector<std::unique_ptr<Record>> records = record_cache_->PopAll();
- for (auto& r : records) {
- if (!ProcessRecord(r.get())) {
- return false;
- }
- }
+ event_selection_set_.FinishReadMmapEventData();
// 6. Dump additional features, and close record file.
if (!DumpAdditionalFeatures(args)) {
@@ -491,10 +481,15 @@ bool RecordCommand::CreateAndInitRecordFile() {
if (record_file_writer_ == nullptr) {
return false;
}
- if (!DumpKernelAndModuleMmaps()) {
+ // Use first perf_event_attr and first event id to dump mmap and comm records.
+ const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
+ const std::vector<std::unique_ptr<EventFd>>* fds =
+ event_selection_set_.FindEventFdsByType(measured_event_types_[0]);
+ uint64_t event_id = (*fds)[0]->Id();
+ if (!DumpKernelAndModuleMmaps(attr, event_id)) {
return false;
}
- if (!DumpThreadCommAndMmaps(system_wide_collection_, monitored_threads_)) {
+ if (!DumpThreadCommAndMmaps(attr, event_id, system_wide_collection_, monitored_threads_)) {
return false;
}
return true;
@@ -525,21 +520,19 @@ std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(const std::str
return writer;
}
-bool RecordCommand::DumpKernelAndModuleMmaps() {
+bool RecordCommand::DumpKernelAndModuleMmaps(const perf_event_attr* attr, uint64_t event_id) {
KernelMmap kernel_mmap;
std::vector<KernelMmap> module_mmaps;
GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
- const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
- CHECK(attr != nullptr);
MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
- kernel_mmap.len, 0, kernel_mmap.filepath);
+ kernel_mmap.len, 0, kernel_mmap.filepath, event_id);
if (!ProcessRecord(&mmap_record)) {
return false;
}
for (auto& module_mmap : module_mmaps) {
MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, module_mmap.start_addr,
- module_mmap.len, 0, module_mmap.filepath);
+ module_mmap.len, 0, module_mmap.filepath, event_id);
if (!ProcessRecord(&mmap_record)) {
return false;
}
@@ -547,7 +540,8 @@ bool RecordCommand::DumpKernelAndModuleMmaps() {
return true;
}
-bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
+bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr* attr, uint64_t event_id,
+ bool all_threads,
const std::vector<pid_t>& selected_threads) {
std::vector<ThreadComm> thread_comms;
if (!GetThreadComms(&thread_comms)) {
@@ -565,9 +559,6 @@ bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
}
}
- const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
- CHECK(attr != nullptr);
-
// Dump processes.
for (auto& thread : thread_comms) {
if (thread.pid != thread.tid) {
@@ -576,7 +567,7 @@ bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
if (!all_threads && dump_processes.find(thread.pid) == dump_processes.end()) {
continue;
}
- CommRecord record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
+ CommRecord record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm, event_id);
if (!ProcessRecord(&record)) {
return false;
}
@@ -591,7 +582,7 @@ bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
}
MmapRecord record =
CreateMmapRecord(*attr, false, thread.pid, thread.tid, thread_mmap.start_addr,
- thread_mmap.len, thread_mmap.pgoff, thread_mmap.name);
+ thread_mmap.len, thread_mmap.pgoff, thread_mmap.name, event_id);
if (!ProcessRecord(&record)) {
return false;
}
@@ -606,11 +597,13 @@ bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
if (!all_threads && dump_threads.find(thread.tid) == dump_threads.end()) {
continue;
}
- ForkRecord fork_record = CreateForkRecord(*attr, thread.pid, thread.tid, thread.pid, thread.pid);
+ ForkRecord fork_record = CreateForkRecord(*attr, thread.pid, thread.tid, thread.pid,
+ thread.pid, event_id);
if (!ProcessRecord(&fork_record)) {
return false;
}
- CommRecord comm_record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
+ CommRecord comm_record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm,
+ event_id);
if (!ProcessRecord(&comm_record)) {
return false;
}
@@ -618,20 +611,6 @@ bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
return true;
}
-bool RecordCommand::CollectRecordsFromKernel(const char* data, size_t size) {
- record_cache_->Push(data, size);
- while (true) {
- std::unique_ptr<Record> r = record_cache_->Pop();
- if (r == nullptr) {
- break;
- }
- if (!ProcessRecord(r.get())) {
- return false;
- }
- }
- return true;
-}
-
bool RecordCommand::ProcessRecord(Record* record) {
UpdateRecordForEmbeddedElfPath(record);
BuildThreadTree(*record, &thread_tree_);
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index b9c3d6f7..db7f8a35 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -306,7 +306,7 @@ class ReportCommand : public Command {
std::string record_filename_;
ArchType record_file_arch_;
std::unique_ptr<RecordFileReader> record_file_reader_;
- perf_event_attr event_attr_;
+ std::vector<perf_event_attr> event_attrs_;
std::vector<std::unique_ptr<Displayable>> displayable_items_;
std::vector<Comparable*> comparable_items_;
ThreadTree thread_tree_;
@@ -515,15 +515,22 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
}
bool ReportCommand::ReadEventAttrFromRecordFile() {
- const std::vector<PerfFileFormat::FileAttr>& attrs = record_file_reader_->AttrSection();
- if (attrs.size() != 1) {
- LOG(ERROR) << "record file contains " << attrs.size() << " attrs";
- return false;
- }
- event_attr_ = attrs[0].attr;
- if (use_branch_address_ && (event_attr_.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) {
- LOG(ERROR) << record_filename_ << " is not recorded with branch stack sampling option.";
- return false;
+ const std::vector<PerfFileFormat::FileAttr>& file_attrs = record_file_reader_->AttrSection();
+ for (const auto& attr : file_attrs) {
+ event_attrs_.push_back(attr.attr);
+ }
+ if (use_branch_address_) {
+ bool has_branch_stack = true;
+ for (const auto& attr : event_attrs_) {
+ if ((attr.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) {
+ has_branch_stack = false;
+ break;
+ }
+ }
+ if (!has_branch_stack) {
+ LOG(ERROR) << record_filename_ << " is not recorded with branch stack sampling option.";
+ return false;
+ }
}
return true;
}
@@ -706,19 +713,18 @@ bool ReportCommand::PrintReport() {
}
void ReportCommand::PrintReportContext() {
- const EventType* event_type = FindEventTypeByConfig(event_attr_.type, event_attr_.config);
- std::string event_type_name;
- if (event_type != nullptr) {
- event_type_name = event_type->name;
- } else {
- event_type_name =
- android::base::StringPrintf("(type %u, config %llu)", event_attr_.type, event_attr_.config);
- }
if (!record_cmdline_.empty()) {
fprintf(report_fp_, "Cmdline: %s\n", record_cmdline_.c_str());
}
- fprintf(report_fp_, "Samples: %" PRIu64 " of event '%s'\n", sample_tree_->TotalSamples(),
- event_type_name.c_str());
+ for (const auto& attr : event_attrs_) {
+ const EventType* event_type = FindEventTypeByConfig(attr.type, attr.config);
+ std::string name;
+ if (event_type != nullptr) {
+ name = event_type->name;
+ }
+ fprintf(report_fp_, "Event: %s (type %u, config %llu)\n", name.c_str(), attr.type, attr.config);
+ }
+ fprintf(report_fp_, "Samples: %" PRIu64 "\n", sample_tree_->TotalSamples());
fprintf(report_fp_, "Event count: %" PRIu64 "\n\n", sample_tree_->TotalPeriod());
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index a4bd6f39..4c2b4978 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -267,6 +267,13 @@ TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
ASSERT_NE(content.find("Func2"), std::string::npos);
}
+TEST_F(ReportCommandTest, report_more_than_one_event_types) {
+ Report(PERF_DATA_WITH_TWO_EVENT_TYPES);
+ ASSERT_TRUE(success);
+ ASSERT_NE(content.find("cpu-cycles"), std::string::npos);
+ ASSERT_NE(content.find("cpu-clock"), std::string::npos);
+}
+
#if defined(__linux__)
static std::unique_ptr<Command> RecordCmd() {
diff --git a/simpleperf/event_attr.cpp b/simpleperf/event_attr.cpp
index c9449b14..92226335 100644
--- a/simpleperf/event_attr.cpp
+++ b/simpleperf/event_attr.cpp
@@ -87,8 +87,8 @@ perf_event_attr CreateDefaultPerfEventAttr(const EventType& event_type) {
// PerfCounter in event_fd.h.
attr.read_format =
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID;
- attr.sample_type |=
- PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CPU;
+ attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_PERIOD |
+ PERF_SAMPLE_CPU | PERF_SAMPLE_ID;
if (attr.type == PERF_TYPE_TRACEPOINT) {
attr.sample_freq = 0;
@@ -145,3 +145,86 @@ void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent) {
PrintIndented(indent + 1, "sample_regs_user 0x%" PRIx64 "\n", attr.sample_regs_user);
PrintIndented(indent + 1, "sample_stack_user 0x%" PRIx64 "\n", attr.sample_stack_user);
}
+
+bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& 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
+ // in each record to decide current record should use which attr. So
+ // 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);
+ }
+ // First determine event_id_pos_in_sample_records.
+ // If PERF_SAMPLE_IDENTIFIER is enabled, it is just after perf_event_header.
+ // If PERF_SAMPLE_ID is enabled, then PERF_SAMPLE_IDENTIFIER | IP | TID | TIME | ADDR
+ // should also be the same.
+ bool identifier_enabled = true;
+ bool id_enabled = true;
+ uint64_t flags_before_id_mask = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | PERF_SAMPLE_TID |
+ PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR;
+ uint64_t flags_before_id = sample_types[0] & flags_before_id_mask;
+ bool flags_before_id_are_the_same = true;
+ for (auto type : sample_types) {
+ identifier_enabled &= (type & PERF_SAMPLE_IDENTIFIER) != 0;
+ id_enabled &= (type & PERF_SAMPLE_ID) != 0;
+ flags_before_id_are_the_same &= (type & flags_before_id_mask) == flags_before_id;
+ }
+ if (identifier_enabled) {
+ *event_id_pos_in_sample_records = sizeof(perf_event_header);
+ } else if (id_enabled && flags_before_id_are_the_same) {
+ uint64_t pos = sizeof(perf_event_header);
+ while (flags_before_id != 0) {
+ // Each flags takes 8 bytes in sample records.
+ flags_before_id &= flags_before_id - 1;
+ pos += 8;
+ }
+ *event_id_pos_in_sample_records = pos;
+ } else {
+ LOG(ERROR) << "perf_event_attrs don't have a common event id position in sample records";
+ return false;
+ }
+
+ // Secondly determine event_id_reverse_pos_in_non_sample_record.
+ // If sample_id_all is not enabled, there is no event id in non sample records.
+ // If PERF_SAMPLE_IDENTIFIER is enabled, it is at the last 8 bytes of the record.
+ // If PERF_SAMPLE_ID is enabled, then PERF_SAMPLE_IDENTIFIER | CPU | STREAM_ID should
+ // also be the same.
+ bool sample_id_all_enabled = true;
+ for (const auto& attr : attrs) {
+ if (attr.sample_id_all == 0) {
+ sample_id_all_enabled = false;
+ }
+ }
+ if (!sample_id_all_enabled) {
+ LOG(ERROR) << "there are perf_event_attrs not enabling sample_id_all, so can't determine "
+ << "perf_event_attr for non sample records";
+ return false;
+ }
+ uint64_t flags_after_id_mask = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID;
+ uint64_t flags_after_id = sample_types[0] & flags_after_id_mask;
+ bool flags_after_id_are_the_same = true;
+ for (auto type : sample_types) {
+ flags_after_id_are_the_same &= (type & flags_after_id_mask) == flags_after_id;
+ }
+ if (identifier_enabled) {
+ *event_id_reverse_pos_in_non_sample_records = 8;
+ } else if (id_enabled && flags_after_id_are_the_same) {
+ uint64_t pos = 8;
+ while (flags_after_id != 0) {
+ // Each flag takes 8 bytes in sample_id of non sample records.
+ flags_after_id &= flags_after_id - 1;
+ pos += 8;
+ }
+ *event_id_reverse_pos_in_non_sample_records = pos;
+ } else {
+ LOG(ERROR) << "perf_event_attrs don't have a common event id reverse position in non sample records";
+ return false;
+ }
+ return true;
+}
+
+bool IsTimestampSupported(const perf_event_attr& attr) {
+ return attr.sample_id_all && (attr.sample_type & PERF_SAMPLE_TIME);
+}
diff --git a/simpleperf/event_attr.h b/simpleperf/event_attr.h
index 79d3df45..df97c2fe 100644
--- a/simpleperf/event_attr.h
+++ b/simpleperf/event_attr.h
@@ -19,11 +19,17 @@
#include <stddef.h>
+#include <vector>
+
#include "perf_event.h"
struct EventType;
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,
+ 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);
#endif // SIMPLE_PERF_EVENT_ATTR_H_
diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp
index 808639bd..83c5e26d 100644
--- a/simpleperf/event_fd.cpp
+++ b/simpleperf/event_fd.cpp
@@ -177,7 +177,7 @@ void EventFd::DiscardMmapData(size_t discard_size) {
mmap_metadata_page_->data_tail += discard_size;
}
-void EventFd::PreparePollForMmapData(pollfd* poll_fd) {
+void EventFd::PrepareToPollForMmapData(pollfd* poll_fd) {
memset(poll_fd, 0, sizeof(pollfd));
poll_fd->fd = perf_event_fd_;
poll_fd->events = POLLIN;
diff --git a/simpleperf/event_fd.h b/simpleperf/event_fd.h
index c1a7d753..878ae718 100644
--- a/simpleperf/event_fd.h
+++ b/simpleperf/event_fd.h
@@ -65,7 +65,7 @@ class EventFd {
size_t GetAvailableMmapData(char** pdata);
// Prepare pollfd for poll() to wait on available mmap_data.
- void PreparePollForMmapData(pollfd* poll_fd);
+ void PrepareToPollForMmapData(pollfd* poll_fd);
private:
EventFd(int perf_event_fd, const std::string& event_name, pid_t tid, int cpu)
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index fad8b1e1..f8b759cc 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -250,11 +250,11 @@ bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
return true;
}
-void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
+void EventSelectionSet::PrepareToPollForEventFiles(std::vector<pollfd>* pollfds) {
for (auto& selection : selections_) {
for (auto& event_fd : selection.event_fds) {
pollfd poll_fd;
- event_fd->PreparePollForMmapData(&poll_fd);
+ event_fd->PrepareToPollForMmapData(&poll_fd);
pollfds->push_back(poll_fd);
}
}
@@ -271,41 +271,73 @@ bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
return true;
}
-static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
- std::function<bool(const char*, size_t)> callback,
- bool* have_data) {
- *have_data = false;
- while (true) {
- char* data;
- size_t size = event_fd->GetAvailableMmapData(&data);
- if (size == 0) {
+void EventSelectionSet::PrepareToReadMmapEventData(std::function<bool (Record*)> callback) {
+ record_callback_ = callback;
+ bool has_timestamp = true;
+ for (const auto& selection : selections_) {
+ if (!IsTimestampSupported(selection.event_attr)) {
+ has_timestamp = false;
break;
}
- if (!callback(data, size)) {
- return false;
+ }
+ record_cache_.reset(new RecordCache(has_timestamp));
+
+ for (const auto& selection : selections_) {
+ for (const auto& event_fd : selection.event_fds) {
+ int event_id = event_fd->Id();
+ event_id_to_attr_map_[event_id] = &selection.event_attr;
}
- *have_data = true;
}
- return true;
}
-bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
+bool EventSelectionSet::ReadMmapEventData() {
for (auto& selection : selections_) {
for (auto& event_fd : selection.event_fds) {
- while (true) {
- bool have_data;
- if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
+ bool has_data = true;
+ while (has_data) {
+ if (!ReadMmapEventDataForFd(event_fd, selection.event_attr, &has_data)) {
return false;
}
- if (!have_data) {
- break;
- }
}
}
}
return true;
}
+bool EventSelectionSet::ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
+ const perf_event_attr& attr,
+ bool* has_data) {
+ *has_data = false;
+ while (true) {
+ char* data;
+ size_t size = event_fd->GetAvailableMmapData(&data);
+ if (size == 0) {
+ break;
+ }
+ std::vector<std::unique_ptr<Record>> records = ReadRecordsFromBuffer(attr, data, size);
+ record_cache_->Push(std::move(records));
+ std::unique_ptr<Record> r = record_cache_->Pop();
+ while (r != nullptr) {
+ if (!record_callback_(r.get())) {
+ return false;
+ }
+ r = record_cache_->Pop();
+ }
+ *has_data = true;
+ }
+ return true;
+}
+
+bool EventSelectionSet::FinishReadMmapEventData() {
+ std::vector<std::unique_ptr<Record>> records = record_cache_->PopAll();
+ for (auto& r : records) {
+ if (!record_callback_(r.get())) {
+ return false;
+ }
+ }
+ return true;
+}
+
EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
const EventTypeAndModifier& event_type_modifier) {
for (auto& selection : selections_) {
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 746abfa7..d2e2511a 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -19,6 +19,7 @@
#include <functional>
#include <map>
+#include <unordered_map>
#include <vector>
#include <android-base/macros.h>
@@ -26,6 +27,7 @@
#include "event_fd.h"
#include "event_type.h"
#include "perf_event.h"
+#include "record.h"
struct CountersInfo {
const EventTypeAndModifier* event_type;
@@ -72,9 +74,11 @@ class EventSelectionSet {
bool OpenEventFilesForCpus(const std::vector<int>& cpus);
bool OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads, std::vector<int> cpus);
bool ReadCounters(std::vector<CountersInfo>* counters);
- void PreparePollForEventFiles(std::vector<pollfd>* pollfds);
+ void PrepareToPollForEventFiles(std::vector<pollfd>* pollfds);
bool MmapEventFiles(size_t mmap_pages);
- bool ReadMmapEventData(std::function<bool(const char*, size_t)> callback);
+ void PrepareToReadMmapEventData(std::function<bool (Record*)> callback);
+ bool ReadMmapEventData();
+ bool FinishReadMmapEventData();
const perf_event_attr* FindEventAttrByType(const EventTypeAndModifier& event_type_modifier);
const std::vector<std::unique_ptr<EventFd>>* FindEventFdsByType(
@@ -83,6 +87,8 @@ class EventSelectionSet {
private:
void UnionSampleType();
bool OpenEventFiles(const std::vector<pid_t>& threads, const std::vector<int>& cpus);
+ bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, const perf_event_attr& attr,
+ bool* has_data);
struct EventSelection {
EventTypeAndModifier event_type_modifier;
@@ -93,6 +99,10 @@ class EventSelectionSet {
std::vector<EventSelection> selections_;
+ std::function<bool (Record*)> record_callback_;
+ std::unique_ptr<RecordCache> record_cache_;
+ std::unordered_map<uint64_t, const perf_event_attr*> event_id_to_attr_map_;
+
DISALLOW_COPY_AND_ASSIGN(EventSelectionSet);
};
diff --git a/simpleperf/get_test_data.h b/simpleperf/get_test_data.h
index 57a6e646..4c21d39e 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -65,4 +65,7 @@ constexpr size_t NATIVELIB_SIZE_IN_APK = 0x1678;
static BuildId native_lib_build_id("8ed5755a7fdc07586ca228b8ee21621bce2c7a97");
+// perf_with_two_event_types.data is generated by sampling using -e cpu-cycles,cpu-clock option.
+static const std::string PERF_DATA_WITH_TWO_EVENT_TYPES = "perf_with_two_event_types.data";
+
#endif // SIMPLE_PERF_GET_TEST_DATA_H_
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index d97ba811..02162753 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -69,9 +69,10 @@ SampleId::SampleId() {
}
// Return sample_id size in binary format.
-size_t SampleId::CreateContent(const perf_event_attr& attr) {
+size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
sample_id_all = attr.sample_id_all;
sample_type = attr.sample_type;
+ id_data.id = event_id;
// Other data are not necessary. TODO: Set missing SampleId data.
return Size();
}
@@ -132,7 +133,7 @@ void SampleId::Dump(size_t indent) const {
PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
}
if (sample_type & PERF_SAMPLE_ID) {
- PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", id_data.id);
+ PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
}
if (sample_type & PERF_SAMPLE_STREAM_ID) {
PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", stream_id_data.stream_id);
@@ -576,8 +577,8 @@ std::vector<char> UnknownRecord::BinaryFormat() const {
void UnknownRecord::DumpData(size_t) const {
}
-static std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
- const perf_event_header* pheader) {
+std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
+ const perf_event_header* pheader) {
switch (pheader->type) {
case PERF_RECORD_MMAP:
return std::unique_ptr<Record>(new MmapRecord(attr, pheader));
@@ -611,25 +612,9 @@ std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(const perf_event_attr
return result;
}
-std::unique_ptr<Record> ReadRecordFromFile(const perf_event_attr& attr, FILE* fp) {
- std::vector<char> buf(sizeof(perf_event_header));
- perf_event_header* header = reinterpret_cast<perf_event_header*>(&buf[0]);
- if (fread(header, sizeof(perf_event_header), 1, fp) != 1) {
- PLOG(ERROR) << "Failed to read record file";
- return nullptr;
- }
- buf.resize(header->size);
- header = reinterpret_cast<perf_event_header*>(&buf[0]);
- if (fread(&buf[sizeof(perf_event_header)], buf.size() - sizeof(perf_event_header), 1, fp) != 1) {
- PLOG(ERROR) << "Failed to read record file";
- return nullptr;
- }
- return ReadRecordFromBuffer(attr, header);
-}
-
MmapRecord CreateMmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
uint64_t addr, uint64_t len, uint64_t pgoff,
- const std::string& filename) {
+ const std::string& filename, uint64_t event_id) {
MmapRecord record;
record.header.type = PERF_RECORD_MMAP;
record.header.misc = (in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
@@ -639,28 +624,28 @@ MmapRecord CreateMmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_
record.data.len = len;
record.data.pgoff = pgoff;
record.filename = filename;
- size_t sample_id_size = record.sample_id.CreateContent(attr);
+ size_t sample_id_size = record.sample_id.CreateContent(attr, event_id);
record.header.size = sizeof(record.header) + sizeof(record.data) +
ALIGN(record.filename.size() + 1, 8) + sample_id_size;
return record;
}
CommRecord CreateCommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
- const std::string& comm) {
+ const std::string& comm, uint64_t event_id) {
CommRecord record;
record.header.type = PERF_RECORD_COMM;
record.header.misc = 0;
record.data.pid = pid;
record.data.tid = tid;
record.comm = comm;
- size_t sample_id_size = record.sample_id.CreateContent(attr);
+ size_t sample_id_size = record.sample_id.CreateContent(attr, event_id);
record.header.size = sizeof(record.header) + sizeof(record.data) +
ALIGN(record.comm.size() + 1, 8) + sample_id_size;
return record;
}
ForkRecord CreateForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, uint32_t ppid,
- uint32_t ptid) {
+ uint32_t ptid, uint64_t event_id) {
ForkRecord record;
record.header.type = PERF_RECORD_FORK;
record.header.misc = 0;
@@ -669,7 +654,7 @@ ForkRecord CreateForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t
record.data.tid = tid;
record.data.ptid = ptid;
record.data.time = 0;
- size_t sample_id_size = record.sample_id.CreateContent(attr);
+ size_t sample_id_size = record.sample_id.CreateContent(attr, event_id);
record.header.size = sizeof(record.header) + sizeof(record.data) + sample_id_size;
return record;
}
@@ -710,10 +695,8 @@ bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
return r2.IsHappensBefore(r1);
}
-RecordCache::RecordCache(const perf_event_attr& attr, size_t min_cache_size,
- uint64_t min_time_diff_in_ns)
- : attr_(attr),
- has_timestamp_(attr.sample_id_all && (attr.sample_type & PERF_SAMPLE_TIME)),
+RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size, uint64_t min_time_diff_in_ns)
+ : has_timestamp_(has_timestamp),
min_cache_size_(min_cache_size),
min_time_diff_in_ns_(min_time_diff_in_ns),
last_time_(0),
@@ -725,22 +708,19 @@ RecordCache::~RecordCache() {
PopAll();
}
-void RecordCache::Push(const char* data, size_t size) {
- std::vector<std::unique_ptr<Record>> records = ReadRecordsFromBuffer(attr_, data, size);
+void RecordCache::Push(std::unique_ptr<Record> record) {
if (has_timestamp_) {
- for (const auto& r : records) {
- last_time_ = std::max(last_time_, r->Timestamp());
- }
+ last_time_ = std::max(last_time_, record->Timestamp());
}
+ queue_.push(CreateRecordWithSeq(record.release()));
+}
+
+void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
for (auto& r : records) {
queue_.push(CreateRecordWithSeq(r.release()));
}
}
-void RecordCache::Push(std::unique_ptr<Record> record) {
- queue_.push(CreateRecordWithSeq(record.release()));
-}
-
std::unique_ptr<Record> RecordCache::Pop() {
if (queue_.size() < min_cache_size_) {
return nullptr;
diff --git a/simpleperf/record.h b/simpleperf/record.h
index a94a9179..8b17bc10 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -117,7 +117,7 @@ struct SampleId {
SampleId();
// Create the content of sample_id. It depends on the attr we use.
- size_t CreateContent(const perf_event_attr& attr);
+ size_t CreateContent(const perf_event_attr& attr, uint64_t event_id);
// Parse sample_id from binary format in the buffer pointed by p.
void ReadFromBinaryFormat(const perf_event_attr& attr, const char* p, const char* end);
@@ -322,11 +322,11 @@ struct UnknownRecord : public Record {
// we are not likely to receive a record for time (t - min_time_diff) or earlier.
class RecordCache {
public:
- RecordCache(const perf_event_attr& attr, size_t min_cache_size = 1000u,
+ RecordCache(bool has_timestamp, size_t min_cache_size = 1000u,
uint64_t min_time_diff_in_ns = 1000000u);
~RecordCache();
- void Push(const char* data, size_t size);
void Push(std::unique_ptr<Record> record);
+ void Push(std::vector<std::unique_ptr<Record>> records);
std::unique_ptr<Record> Pop();
std::vector<std::unique_ptr<Record>> PopAll();
@@ -344,7 +344,6 @@ class RecordCache {
RecordWithSeq CreateRecordWithSeq(Record *r);
- const perf_event_attr attr_;
bool has_timestamp_;
size_t min_cache_size_;
uint64_t min_time_diff_in_ns_;
@@ -354,16 +353,17 @@ class RecordCache {
RecordComparator> queue_;
};
+std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
+ const perf_event_header* pheader);
std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(const perf_event_attr& attr,
const char* buf, size_t buf_size);
-std::unique_ptr<Record> ReadRecordFromFile(const perf_event_attr& attr, FILE* fp);
MmapRecord CreateMmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
uint64_t addr, uint64_t len, uint64_t pgoff,
- const std::string& filename);
+ const std::string& filename, uint64_t event_id);
CommRecord CreateCommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
- const std::string& comm);
+ const std::string& comm, uint64_t event_id);
ForkRecord CreateForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, uint32_t ppid,
- uint32_t ptid);
+ uint32_t ptid, uint64_t event_id);
BuildIdRecord CreateBuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
const std::string& filename);
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index c0f53b16..3005dee6 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -23,6 +23,7 @@
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include <android-base/macros.h>
@@ -124,14 +125,19 @@ class RecordFileReader {
bool ReadAttrSection();
bool ReadFeatureSectionDescriptors();
bool ReadFeatureSection(int feature, std::vector<char>* data);
+ std::unique_ptr<Record> ReadRecord();
const std::string filename_;
FILE* record_fp_;
PerfFileFormat::FileHeader header_;
std::vector<PerfFileFormat::FileAttr> file_attrs_;
+ std::unordered_map<uint64_t, perf_event_attr*> event_id_to_attr_map_;
std::map<int, PerfFileFormat::SectionDesc> feature_section_descriptors_;
+ size_t event_id_pos_in_sample_records_;
+ size_t event_id_reverse_pos_in_non_sample_records_;
+
DISALLOW_COPY_AND_ASSIGN(RecordFileReader);
};
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index f126a6b7..1165494c 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -23,7 +23,7 @@
#include <android-base/logging.h>
-#include "perf_event.h"
+#include "event_attr.h"
#include "record.h"
#include "utils.h"
@@ -45,7 +45,8 @@ std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::st
}
RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
- : filename_(filename), record_fp_(fp) {
+ : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
+ event_id_reverse_pos_in_non_sample_records_(0) {
}
RecordFileReader::~RecordFileReader() {
@@ -102,6 +103,25 @@ bool RecordFileReader::ReadAttrSection() {
memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
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_,
+ &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)) {
+ return false;
+ }
+ for (auto id : ids) {
+ event_id_to_attr_map_[id] = &file_attrs_[i].attr;
+ }
+ }
return true;
}
@@ -150,9 +170,16 @@ bool RecordFileReader::ReadDataSection(std::function<bool(std::unique_ptr<Record
PLOG(ERROR) << "failed to fseek()";
return false;
}
- RecordCache cache(file_attrs_[0].attr);
+ bool has_timestamp = true;
+ for (const auto& attr : file_attrs_) {
+ if (!IsTimestampSupported(attr.attr)) {
+ has_timestamp = false;
+ break;
+ }
+ }
+ RecordCache cache(has_timestamp);
for (size_t nbytes_read = 0; nbytes_read < header_.data.size;) {
- std::unique_ptr<Record> record = ReadRecordFromFile(file_attrs_[0].attr, record_fp_);
+ std::unique_ptr<Record> record = ReadRecord();
if (record == nullptr) {
return false;
}
@@ -180,6 +207,37 @@ bool RecordFileReader::ReadDataSection(std::function<bool(std::unique_ptr<Record
return true;
}
+std::unique_ptr<Record> RecordFileReader::ReadRecord() {
+ std::vector<char> buf(sizeof(perf_event_header));
+ if (fread(buf.data(), sizeof(perf_event_header), 1, record_fp_) != 1) {
+ PLOG(ERROR) << "failed to read file " << filename_;
+ return nullptr;
+ }
+ perf_event_header* header = reinterpret_cast<perf_event_header*>(&buf[0]);
+ if (buf.size() < header->size) {
+ buf.resize(header->size);
+ header = reinterpret_cast<perf_event_header*>(&buf[0]);
+ }
+ if (fread(&buf[sizeof(perf_event_header)], buf.size() - sizeof(perf_event_header), 1, record_fp_) != 1) {
+ PLOG(ERROR) << "failed to read file " << filename_;
+ return nullptr;
+ }
+ const perf_event_attr* attr = &file_attrs_[0].attr;
+ if (file_attrs_.size() > 1) {
+ uint64_t event_id;
+ if (header->type == PERF_RECORD_SAMPLE) {
+ event_id = *reinterpret_cast<uint64_t*>(&buf[event_id_pos_in_sample_records_]);
+ } else {
+ event_id = *reinterpret_cast<uint64_t*>(
+ &buf[header->size - event_id_reverse_pos_in_non_sample_records_]);
+ }
+ auto it = event_id_to_attr_map_.find(event_id);
+ CHECK(it != event_id_to_attr_map_.end());
+ attr = it->second;
+ }
+ return ReadRecordFromBuffer(*attr, header);
+}
+
bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
auto it = section_map.find(feature);
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 4648a649..96d1e53f 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -38,6 +38,7 @@ class RecordFileTest : public ::testing::Test {
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)));
AttrWithId attr_id;
attr_id.attr = attrs_.back().get();
@@ -61,7 +62,7 @@ TEST_F(RecordFileTest, smoke) {
// Write data section.
MmapRecord mmap_record = CreateMmapRecord(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000,
- 0x3000, "mmap_record_example");
+ 0x3000, "mmap_record_example", attr_ids_[0].ids[0]);
ASSERT_TRUE(writer->WriteData(mmap_record.BinaryFormat()));
// Write feature section.
@@ -111,7 +112,8 @@ TEST_F(RecordFileTest, records_sorted_by_time) {
// Write data section.
MmapRecord r1 =
- CreateMmapRecord(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1");
+ CreateMmapRecord(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
+ attr_ids_[0].ids[0]);
MmapRecord r2 = r1;
MmapRecord r3 = r1;
r1.sample_id.time_data.time = 2;
diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp
index 76eebe98..32d73336 100644
--- a/simpleperf/record_test.cpp
+++ b/simpleperf/record_test.cpp
@@ -46,20 +46,20 @@ void RecordTest::CheckRecordMatchBinary(const RecordType& record) {
TEST_F(RecordTest, MmapRecordMatchBinary) {
MmapRecord record =
- CreateMmapRecord(event_attr, true, 1, 2, 0x1000, 0x2000, 0x3000, "MmapRecord");
+ CreateMmapRecord(event_attr, true, 1, 2, 0x1000, 0x2000, 0x3000, "MmapRecord", 0);
CheckRecordMatchBinary(record);
}
TEST_F(RecordTest, CommRecordMatchBinary) {
- CommRecord record = CreateCommRecord(event_attr, 1, 2, "CommRecord");
+ CommRecord record = CreateCommRecord(event_attr, 1, 2, "CommRecord", 0);
CheckRecordMatchBinary(record);
}
TEST_F(RecordTest, RecordCache_smoke) {
event_attr.sample_id_all = 1;
event_attr.sample_type |= PERF_SAMPLE_TIME;
- RecordCache cache(event_attr, 2, 2);
- MmapRecord r1 = CreateMmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300, "mmap_record1");
+ RecordCache cache(true, 2, 2);
+ MmapRecord r1 = CreateMmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300, "mmap_record1", 0);
MmapRecord r2 = r1;
MmapRecord r3 = r1;
MmapRecord r4 = r1;
@@ -67,25 +67,21 @@ TEST_F(RecordTest, RecordCache_smoke) {
r2.sample_id.time_data.time = 1;
r3.sample_id.time_data.time = 4;
r4.sample_id.time_data.time = 6;
- std::vector<char> buf1 = r1.BinaryFormat();
- std::vector<char> buf2 = r2.BinaryFormat();
- std::vector<char> buf3 = r3.BinaryFormat();
- std::vector<char> buf4 = r4.BinaryFormat();
// Push r1.
- cache.Push(buf1.data(), buf1.size());
+ cache.Push(std::unique_ptr<Record>(new MmapRecord(r1)));
ASSERT_EQ(nullptr, cache.Pop());
// Push r2.
- cache.Push(buf2.data(), buf2.size());
+ cache.Push(std::unique_ptr<Record>(new MmapRecord(r2)));
// Pop r2.
std::unique_ptr<Record> popped_r = cache.Pop();
ASSERT_TRUE(popped_r != nullptr);
CheckRecordEqual(r2, *popped_r);
ASSERT_EQ(nullptr, cache.Pop());
// Push r3.
- cache.Push(buf3.data(), buf3.size());
+ cache.Push(std::unique_ptr<Record>(new MmapRecord(r3)));
ASSERT_EQ(nullptr, cache.Pop());
// Push r4.
- cache.Push(buf4.data(), buf4.size());
+ cache.Push(std::unique_ptr<Record>(new MmapRecord(r4)));
// Pop r1.
popped_r = cache.Pop();
ASSERT_TRUE(popped_r != nullptr);
@@ -104,13 +100,12 @@ TEST_F(RecordTest, RecordCache_smoke) {
TEST_F(RecordTest, RecordCache_FIFO) {
event_attr.sample_id_all = 1;
event_attr.sample_type |= PERF_SAMPLE_TIME;
- RecordCache cache(event_attr, 2, 2);
+ RecordCache cache(true, 2, 2);
std::vector<MmapRecord> records;
for (size_t i = 0; i < 10; ++i) {
- MmapRecord r = CreateMmapRecord(event_attr, true, 1, i, 0x100, 0x200, 0x300, "mmap_record1");
+ MmapRecord r = CreateMmapRecord(event_attr, true, 1, i, 0x100, 0x200, 0x300, "mmap_record1", 0);
records.push_back(r);
- std::vector<char> buf = r.BinaryFormat();
- cache.Push(buf.data(), buf.size());
+ cache.Push(std::unique_ptr<Record>(new MmapRecord(r)));
}
std::vector<std::unique_ptr<Record>> out_records = cache.PopAll();
ASSERT_EQ(records.size(), out_records.size());
diff --git a/simpleperf/testdata/perf_with_two_event_types.data b/simpleperf/testdata/perf_with_two_event_types.data
new file mode 100644
index 00000000..ba9a6063
--- /dev/null
+++ b/simpleperf/testdata/perf_with_two_event_types.data
Binary files differ