Merge "Simpleperf: add signal handler for SIGCHLD, SIGINT, SIGTERM."
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index fe4beac..7cd7ec8 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -64,6 +64,7 @@
" to find all possible event names.\n"
" -f freq Set event sample frequency.\n"
" -F freq Same as '-f freq'.\n"
+ " -g Enables call-graph recording.\n"
" -j branch_filter1,branch_filter2,...\n"
" Enable taken branch stack sampling. Each sample\n"
" captures a series of consecutive taken branches.\n"
@@ -81,6 +82,7 @@
sample_freq_(1000),
system_wide_collection_(false),
branch_sampling_(0),
+ callchain_sampling_(false),
measured_event_type_(nullptr),
perf_mmap_pages_(256),
record_filename_("perf.data") {
@@ -109,6 +111,7 @@
bool system_wide_collection_;
uint64_t branch_sampling_;
+ bool callchain_sampling_;
const EventType* measured_event_type_;
EventSelectionSet event_selection_set_;
@@ -249,6 +252,8 @@
return false;
}
use_sample_freq_ = true;
+ } else if (args[i] == "-g") {
+ callchain_sampling_ = true;
} else if (args[i] == "-j") {
if (!NextArgumentOrError(args, &i)) {
return false;
@@ -302,6 +307,9 @@
if (!event_selection_set_.SetBranchSampling(branch_sampling_)) {
return false;
}
+ if (callchain_sampling_) {
+ event_selection_set_.EnableCallChainSampling();
+ }
return true;
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index c513e2e..4a2f3f7 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -99,3 +99,7 @@
<< "This test does nothing as branch stack sampling is not supported on this device.";
}
}
+
+TEST(record_cmd, callchain_sampling) {
+ ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", "1"}));
+}
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 644938c..b1618bd 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -92,6 +92,12 @@
return true;
}
+void EventSelectionSet::EnableCallChainSampling() {
+ for (auto& selection : selections_) {
+ selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
+ }
+}
+
bool EventSelectionSet::OpenEventFilesForAllCpus() {
std::vector<int> cpus = GetOnlineCpus();
if (cpus.empty()) {
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index e764e0b..dabef14 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -54,6 +54,7 @@
void SetSampleFreq(uint64_t sample_freq);
void SetSamplePeriod(uint64_t sample_period);
bool SetBranchSampling(uint64_t branch_sample_type);
+ void EnableCallChainSampling();
bool OpenEventFilesForAllCpus();
bool OpenEventFilesForProcess(pid_t pid);
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 4a1edb4..f25c98f 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -270,6 +270,12 @@
if (sample_type & PERF_SAMPLE_PERIOD) {
MoveFromBinaryFormat(period_data, p);
}
+ if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+ uint64_t nr;
+ MoveFromBinaryFormat(nr, p);
+ callchain_data.ips.resize(nr);
+ MoveFromBinaryFormat(callchain_data.ips.data(), nr, p);
+ }
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
uint64_t nr;
MoveFromBinaryFormat(nr, p);
@@ -309,6 +315,12 @@
if (sample_type & PERF_SAMPLE_PERIOD) {
PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
}
+ if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+ PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ips.size());
+ for (auto& ip : callchain_data.ips) {
+ PrintIndented(indent + 1, "0x%" PRIx64 "\n", ip);
+ }
+ }
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n", branch_stack_data.stack.size());
for (auto& item : branch_stack_data.stack) {
diff --git a/simpleperf/record.h b/simpleperf/record.h
index bbcd7d0..25b91ec 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -68,6 +68,10 @@
uint64_t period;
};
+struct PerfSampleCallChainType {
+ std::vector<uint64_t> ips;
+};
+
struct PerfSampleBranchStackType {
struct BranchStackItemType {
uint64_t from;
@@ -186,6 +190,7 @@
PerfSampleCpuType cpu_data; // Valid if PERF_SAMPLE_CPU.
PerfSamplePeriodType period_data; // Valid if PERF_SAMPLE_PERIOD.
+ PerfSampleCallChainType callchain_data; // Valid if PERF_SAMPLE_CALLCHAIN.
PerfSampleBranchStackType branch_stack_data; // Valid if PERF_SAMPLE_BRANCH_STACK.
SampleRecord(const perf_event_attr& attr, const perf_event_header* pheader);