summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2016-07-14 02:17:21 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-07-14 02:17:21 +0000
commite5b5cf07c7c092a178f25dadff8842e9000d0e1f (patch)
treedc33c5ced54dc2d16c0f794a0d33ee9f12f9807e
parent7a6b3fdff5ef275b19811c48d4e999c04106ad6a (diff)
parent0a072cda021e5dfbdbb39f4d8d30771a851b3c3a (diff)
downloadextras-n-iot-preview-2.tar.gz
-rw-r--r--simpleperf/cmd_record.cpp29
-rw-r--r--simpleperf/event_fd.cpp38
-rw-r--r--simpleperf/event_fd.h6
-rw-r--r--simpleperf/event_selection_set.cpp29
-rw-r--r--simpleperf/event_selection_set.h3
5 files changed, 71 insertions, 34 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 050ca854..9690e1d3 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -65,6 +65,11 @@ constexpr uint64_t DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT = 1;
// should be a multiply of 8, so MAX_DUMP_STACK_SIZE is 65528.
constexpr uint32_t MAX_DUMP_STACK_SIZE = 65528;
+// The max allowed pages in mapped buffer is decided by rlimit(RLIMIT_MEMLOCK).
+// Here 1024 is a desired value for pages in mapped buffer. If mapped
+// successfully, the buffer size = 1024 * 4K (page size) = 4M.
+constexpr size_t DESIRED_PAGES_IN_MAPPED_BUFFER = 1024;
+
class RecordCommand : public Command {
public:
RecordCommand()
@@ -117,9 +122,8 @@ class RecordCommand : public Command {
" This option requires at least one branch type among any, any_call,\n"
" any_ret, ind_call.\n"
"-m mmap_pages Set the size of the buffer used to receiving sample data from\n"
-" the kernel. It should be a power of 2. The default value for\n"
-" system wide profiling is 256. The default value for non system\n"
-" wide profiling is 128.\n"
+" the kernel. It should be a power of 2. If not set, the max\n"
+" possible value <= 1024 will be used.\n"
"--no-dump-kernel-symbols Don't dump kernel symbols in perf.data. By default\n"
" kernel symbols will be dumped when needed.\n"
"--no-inherit Don't record created child threads/processes.\n"
@@ -153,7 +157,7 @@ class RecordCommand : public Command {
child_inherit_(true),
can_dump_kernel_symbols_(true),
dump_symbols_(false),
- perf_mmap_pages_(0),
+ mmap_page_range_(std::make_pair(1, DESIRED_PAGES_IN_MAPPED_BUFFER)),
record_filename_("perf.data"),
sample_record_count_(0),
lost_record_count_(0) {
@@ -206,8 +210,7 @@ class RecordCommand : public Command {
std::vector<int> cpus_;
EventSelectionSet event_selection_set_;
- // mmap pages used by each perf event file, should be a power of 2.
- size_t perf_mmap_pages_;
+ std::pair<size_t, size_t> mmap_page_range_;
ThreadTree thread_tree_;
std::string record_filename_;
@@ -254,7 +257,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
event_selection_set_.SetEnableOnExec(true);
} else {
LOG(ERROR)
- << "No threads to monitor. Try `simpleperf help record` for help\n";
+ << "No threads to monitor. Try `simpleperf help record` for help";
return false;
}
}
@@ -272,7 +275,8 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
}
}
std::vector<pollfd> pollfds;
- if (!event_selection_set_.MmapEventFiles(perf_mmap_pages_, &pollfds)) {
+ if (!event_selection_set_.MmapEventFiles(mmap_page_range_.first,
+ mmap_page_range_.second, &pollfds)) {
return false;
}
@@ -335,7 +339,6 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
std::vector<std::string>* non_option_args) {
std::set<pid_t> tid_set;
- size_t mmap_pages = 0;
size_t i;
for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
if (args[i] == "-a") {
@@ -454,7 +457,7 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
LOG(ERROR) << "Invalid mmap_pages: '" << args[i] << "'";
return false;
}
- mmap_pages = pages;
+ mmap_page_range_.first = mmap_page_range_.second = pages;
} else if (args[i] == "--no-dump-kernel-symbols") {
can_dump_kernel_symbols_ = false;
} else if (args[i] == "--no-inherit") {
@@ -538,12 +541,6 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
can_dump_kernel_symbols_ = false;
}
- if (mmap_pages != 0) {
- perf_mmap_pages_ = mmap_pages;
- } else {
- perf_mmap_pages_ = (system_wide_collection_ ? 256 : 128);
- }
-
if (non_option_args != nullptr) {
non_option_args->clear();
for (; i < args.size(); ++i) {
diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp
index 2fd4d522..0002d02e 100644
--- a/simpleperf/event_fd.cpp
+++ b/simpleperf/event_fd.cpp
@@ -76,9 +76,7 @@ std::unique_ptr<EventFd> EventFd::OpenEventFile(const perf_event_attr& attr, pid
}
EventFd::~EventFd() {
- if (mmap_addr_ != nullptr) {
- munmap(mmap_addr_, mmap_len_);
- }
+ DestroyMappedBuffer();
close(perf_event_fd_);
}
@@ -115,19 +113,22 @@ bool EventFd::ReadCounter(PerfCounter* counter) const {
return true;
}
-bool EventFd::CreateMappedBuffer(size_t mmap_pages, pollfd* poll_fd) {
+bool EventFd::CreateMappedBuffer(size_t mmap_pages, pollfd* poll_fd, bool report_error) {
CHECK(IsPowerOfTwo(mmap_pages));
size_t page_size = sysconf(_SC_PAGE_SIZE);
size_t mmap_len = (mmap_pages + 1) * page_size;
void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, perf_event_fd_, 0);
if (mmap_addr == MAP_FAILED) {
bool is_perm_error = (errno == EPERM);
- PLOG(ERROR) << "mmap() failed for " << Name();
- if (is_perm_error) {
+ if (report_error) {
+ PLOG(ERROR) << "mmap(" << mmap_pages << ") failed for " << Name();
+ } else {
+ PLOG(DEBUG) << "mmap(" << mmap_pages << ") failed for " << Name();
+ }
+ if (report_error && is_perm_error) {
LOG(ERROR) << "It seems the kernel doesn't allow allocating enough "
- << "buffer for dumping samples, consider decreasing the number of "
- << "monitored threads(-t), or decreasing mmap pages(-m), or "
- << "decreasing the number of events(-e).";
+ << "buffer for dumping samples, consider decreasing mmap pages(-m), "
+ << "or decreasing the number of events(-e).";
}
return false;
}
@@ -145,18 +146,31 @@ bool EventFd::CreateMappedBuffer(size_t mmap_pages, pollfd* poll_fd) {
return true;
}
-bool EventFd::ShareMappedBuffer(const EventFd& event_fd) {
+bool EventFd::ShareMappedBuffer(const EventFd& event_fd, bool report_error) {
CHECK(!HasMappedBuffer());
CHECK(event_fd.HasMappedBuffer());
int result = ioctl(perf_event_fd_, PERF_EVENT_IOC_SET_OUTPUT, event_fd.perf_event_fd_);
if (result != 0) {
- PLOG(ERROR) << "failed to share mapped buffer of "
- << event_fd.perf_event_fd_ << " with " << perf_event_fd_;
+ if (report_error) {
+ PLOG(ERROR) << "failed to share mapped buffer of "
+ << event_fd.perf_event_fd_ << " with " << perf_event_fd_;
+ }
return false;
}
return true;
}
+void EventFd::DestroyMappedBuffer() {
+ if (HasMappedBuffer()) {
+ munmap(mmap_addr_, mmap_len_);
+ mmap_addr_ = nullptr;
+ mmap_len_ = 0;
+ mmap_metadata_page_ = nullptr;
+ mmap_data_buffer_ = nullptr;
+ mmap_data_buffer_size_ = 0;
+ }
+}
+
size_t EventFd::GetAvailableMmapData(char** pdata) {
if (!HasMappedBuffer()) {
return 0;
diff --git a/simpleperf/event_fd.h b/simpleperf/event_fd.h
index 651f3fd4..d33368cb 100644
--- a/simpleperf/event_fd.h
+++ b/simpleperf/event_fd.h
@@ -65,16 +65,18 @@ class EventFd {
// Create mapped buffer used to receive records sent by the kernel.
// mmap_pages should be power of 2. If created successfully, fill pollfd,
// which is used to poll() on available mapped data.
- bool CreateMappedBuffer(size_t mmap_pages, pollfd* poll_fd);
+ bool CreateMappedBuffer(size_t mmap_pages, pollfd* poll_fd, bool report_error);
// Share the mapped buffer used by event_fd. The two EventFds should monitor
// the same event on the same cpu, but have different thread ids.
- bool ShareMappedBuffer(const EventFd& event_fd);
+ bool ShareMappedBuffer(const EventFd& event_fd, bool report_error);
bool HasMappedBuffer() const {
return mmap_data_buffer_size_ != 0;
}
+ void DestroyMappedBuffer();
+
// When the kernel writes new sampled records to the mapped area, we can get them by returning
// the start address and size of the data.
size_t GetAvailableMmapData(char** pdata);
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 267f40d1..5a98fd28 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -335,7 +335,29 @@ bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
return true;
}
-bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, std::vector<pollfd>* pollfds) {
+bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages,
+ size_t max_mmap_pages,
+ std::vector<pollfd>* pollfds) {
+ for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) {
+ if (MmapEventFiles(i, pollfds, i == min_mmap_pages)) {
+ LOG(VERBOSE) << "Mapped buffer size is " << i << " pages.";
+ return true;
+ }
+ for (auto& group : groups_) {
+ for (auto& selection : group) {
+ for (auto& event_fd : selection.event_fds) {
+ event_fd->DestroyMappedBuffer();
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool EventSelectionSet::MmapEventFiles(size_t mmap_pages,
+ std::vector<pollfd>* pollfds,
+ bool report_error) {
+ pollfds->clear();
for (auto& group : groups_) {
for (auto& selection : group) {
// For each event, allocate a mapped buffer for each cpu.
@@ -343,12 +365,13 @@ bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, std::vector<pollfd>* p
for (auto& event_fd : selection.event_fds) {
auto it = cpu_map.find(event_fd->Cpu());
if (it != cpu_map.end()) {
- if (!event_fd->ShareMappedBuffer(*(it->second))) {
+ if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) {
return false;
}
} else {
pollfd poll_fd;
- if (!event_fd->CreateMappedBuffer(mmap_pages, &poll_fd)) {
+ if (!event_fd->CreateMappedBuffer(mmap_pages, &poll_fd,
+ report_error)) {
return false;
}
pollfds->push_back(poll_fd);
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 87bdeab7..5af8c0c1 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -88,7 +88,7 @@ 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);
- bool MmapEventFiles(size_t mmap_pages, std::vector<pollfd>* pollfds);
+ bool MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages, std::vector<pollfd>* pollfds);
void PrepareToReadMmapEventData(std::function<bool (Record*)> callback);
bool ReadMmapEventData();
bool FinishReadMmapEventData();
@@ -98,6 +98,7 @@ class EventSelectionSet {
EventSelection* selection);
void UnionSampleType();
bool OpenEventFiles(const std::vector<pid_t>& threads, const std::vector<int>& cpus);
+ bool MmapEventFiles(size_t mmap_pages, std::vector<pollfd>* pollfds, bool report_error);
bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, const perf_event_attr& attr,
bool* has_data);