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