summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_record.cpp11
-rw-r--r--simpleperf/cmd_report.cpp2
-rw-r--r--simpleperf/cmd_report_test.cpp13
-rw-r--r--simpleperf/event_selection_set.cpp11
-rw-r--r--simpleperf/event_selection_set.h1
-rw-r--r--simpleperf/record.cpp25
-rw-r--r--simpleperf/record.h1
-rw-r--r--simpleperf/record_test.cpp30
8 files changed, 91 insertions, 3 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 4e7276ce..bb1fc0f7 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -182,7 +182,8 @@ class RecordCommand : public Command {
lost_record_count_(0),
start_profiling_fd_(-1),
in_app_context_(false),
- trace_offcpu_(false) {
+ trace_offcpu_(false),
+ exclude_kernel_callchain_(false) {
// Stop profiling if parent exits.
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
app_package_name_ = GetDefaultAppPackageName();
@@ -245,6 +246,7 @@ class RecordCommand : public Command {
std::string app_package_name_;
bool in_app_context_;
bool trace_offcpu_;
+ bool exclude_kernel_callchain_;
};
bool RecordCommand::Run(const std::vector<std::string>& args) {
@@ -271,6 +273,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
return false;
}
}
+ exclude_kernel_callchain_ = event_selection_set_.ExcludeKernel();
if (trace_offcpu_ && !TraceOffCpu()) {
return false;
}
@@ -890,6 +893,12 @@ bool RecordCommand::ProcessRecord(Record* record) {
}
}
if (record->type() == PERF_RECORD_SAMPLE) {
+ if (record->InKernel() && exclude_kernel_callchain_) {
+ if (static_cast<SampleRecord*>(record)->ExcludeKernelCallChain() == 0u) {
+ // If current record contains no user callchain, skip it.
+ return true;
+ }
+ }
sample_record_count_++;
} else if (record->type() == PERF_RECORD_LOST) {
lost_record_count_ += static_cast<LostRecord*>(record)->lost;
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index 5965e635..cc622858 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -771,7 +771,6 @@ bool ReportCommand::ReadMetaInfoFromRecordFile() {
bool ReportCommand::ReadEventAttrFromRecordFile() {
std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
- LOG(ERROR) << "attrs.size() = " << attrs.size();
for (const auto& attr_with_id : attrs) {
EventAttrWithName attr;
attr.attr = *attr_with_id.attr;
@@ -795,7 +794,6 @@ bool ReportCommand::ReadEventAttrFromRecordFile() {
if (trace_offcpu_) {
size_t i;
for (i = 0; i < event_attrs_.size(); ++i) {
- LOG(ERROR) << "event_attrs[" << i << "].name = " << event_attrs_[i].name;
if (event_attrs_[i].name == "sched:sched_switch") {
break;
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index f1a9eb66..703ca8f3 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -521,4 +521,17 @@ TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
}
}
+TEST_F(ReportCommandTest, exclude_kernel_callchain) {
+ TEST_REQUIRE_HOST_ROOT();
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(RecordCmd()->Run({"--trace-offcpu", "-e", "cpu-cycles:u", "-p", pid,
+ "--duration", "2", "-o", tmpfile.path, "-g"}));
+ ReportRaw(tmpfile.path, {"-g"});
+ ASSERT_TRUE(success);
+ ASSERT_EQ(content.find("[kernel.kallsyms]"), std::string::npos);
+}
+
#endif
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 5f8cf5cb..de04d3d1 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -189,6 +189,17 @@ std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const {
return result;
}
+bool EventSelectionSet::ExcludeKernel() const {
+ for (const auto& group : groups_) {
+ for (const auto& selection : group) {
+ if (!selection.event_type_modifier.exclude_kernel) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
bool EventSelectionSet::HasInplaceSampler() const {
for (const auto& group : groups_) {
for (const auto& sel : group) {
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index f5cb53ab..3a3bd460 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -75,6 +75,7 @@ class EventSelectionSet {
bool AddEventGroup(const std::vector<std::string>& event_names);
std::vector<const EventType*> GetEvents() const;
std::vector<const EventType*> GetTracepointEvents() const;
+ bool ExcludeKernel() const;
bool HasInplaceSampler() const;
std::vector<EventAttrWithId> GetEventAttrWithId() const;
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 65e98ea6..f3548150 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -594,6 +594,31 @@ void SampleRecord::ReplaceRegAndStackWithCallChain(
*reinterpret_cast<uint64_t*>(p) = callchain_data.ip_nr;
}
+size_t SampleRecord::ExcludeKernelCallChain() {
+ size_t user_callchain_length = 0u;
+ if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+ size_t i;
+ for (i = 0; i < callchain_data.ip_nr; ++i) {
+ if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
+ i++;
+ if (i < callchain_data.ip_nr) {
+ ip_data.ip = callchain_data.ips[i];
+ if (sample_type & PERF_SAMPLE_IP) {
+ *reinterpret_cast<uint64_t*>(const_cast<char*>(binary_ + header_size())) = ip_data.ip;
+ }
+ header.misc = (header.misc & ~PERF_RECORD_MISC_KERNEL) | PERF_RECORD_MISC_USER;
+ reinterpret_cast<perf_event_header*>(const_cast<char*>(binary_))->misc = header.misc;
+ }
+ break;
+ } else {
+ const_cast<uint64_t*>(callchain_data.ips)[i] = PERF_CONTEXT_USER;
+ }
+ }
+ user_callchain_length = callchain_data.ip_nr - i;
+ }
+ return user_callchain_length;
+}
+
void SampleRecord::DumpData(size_t indent) const {
PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
if (sample_type & PERF_SAMPLE_IP) {
diff --git a/simpleperf/record.h b/simpleperf/record.h
index d6ee2ce5..1f8e5b7d 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -387,6 +387,7 @@ struct SampleRecord : public Record {
uint64_t period, const std::vector<uint64_t>& ips);
void ReplaceRegAndStackWithCallChain(const std::vector<uint64_t>& ips);
+ size_t ExcludeKernelCallChain();
uint64_t Timestamp() const override;
uint32_t Cpu() const override;
uint64_t Id() const override;
diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp
index c6f8e9ce..5004ae95 100644
--- a/simpleperf/record_test.cpp
+++ b/simpleperf/record_test.cpp
@@ -142,3 +142,33 @@ TEST_F(RecordTest, RecordCache_PushRecordVector) {
ASSERT_EQ(1u, last_records.size());
ASSERT_EQ(r2, last_records[0].get());
}
+
+TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) {
+ SampleRecord r(event_attr, 0, 1, 0, 0, 0, 0, 0, {});
+ ASSERT_EQ(0u, r.ExcludeKernelCallChain());
+
+ event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
+ SampleRecord r1(event_attr, 0, 1, 0, 0, 0, 0, 0, {PERF_CONTEXT_USER, 2});
+ ASSERT_EQ(1u, r1.ExcludeKernelCallChain());
+ ASSERT_EQ(2u, r1.ip_data.ip);
+ SampleRecord r2(event_attr, r1.Binary());
+ ASSERT_EQ(1u, r.ip_data.ip);
+ ASSERT_EQ(2u, r2.callchain_data.ip_nr);
+ ASSERT_EQ(PERF_CONTEXT_USER, r2.callchain_data.ips[0]);
+ ASSERT_EQ(2u, r2.callchain_data.ips[1]);
+
+ SampleRecord r3(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, PERF_CONTEXT_USER, 2});
+ ASSERT_EQ(1u, r3.ExcludeKernelCallChain());
+ ASSERT_EQ(2u, r3.ip_data.ip);
+ SampleRecord r4(event_attr, r3.Binary());
+ ASSERT_EQ(2u, r4.ip_data.ip);
+ ASSERT_EQ(3u, r4.callchain_data.ip_nr);
+ ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[0]);
+ ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[1]);
+ ASSERT_EQ(2u, r4.callchain_data.ips[2]);
+
+ SampleRecord r5(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, 2});
+ ASSERT_EQ(0u, r5.ExcludeKernelCallChain());
+ SampleRecord r6(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, 2, PERF_CONTEXT_USER});
+ ASSERT_EQ(0u, r6.ExcludeKernelCallChain());
+}