diff options
-rw-r--r-- | simpleperf/cmd_record.cpp | 11 | ||||
-rw-r--r-- | simpleperf/cmd_report.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_report_test.cpp | 13 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 11 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 1 | ||||
-rw-r--r-- | simpleperf/record.cpp | 25 | ||||
-rw-r--r-- | simpleperf/record.h | 1 | ||||
-rw-r--r-- | simpleperf/record_test.cpp | 30 |
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()); +} |