diff options
author | Yabin Cui <yabinc@google.com> | 2023-12-04 16:50:37 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2023-12-05 10:10:58 -0800 |
commit | 7cba498ad45f250b433638ddd799907325f267f5 (patch) | |
tree | 6bc7df20335dca11488afadbc074cd16352271ea | |
parent | 544fa56bbe864550fcc4585901adba8179eeb4b1 (diff) | |
download | extras-7cba498ad45f250b433638ddd799907325f267f5.tar.gz |
simpleperf: inject cmd: Convert LBR profile to AutoFDO format
Bug: 293953824
Test: run simpleperf_unit_test
Change-Id: I58ae6a07eefd8dbbd73bbb4f7db40a8dd056a012
-rw-r--r-- | simpleperf/BranchListFile.h | 2 | ||||
-rw-r--r-- | simpleperf/cmd_inject.cpp | 92 | ||||
-rw-r--r-- | simpleperf/cmd_inject_test.cpp | 12 | ||||
-rw-r--r-- | simpleperf/testdata/lbr/inject_lbr.data | 11 | ||||
-rw-r--r-- | simpleperf/testdata/lbr/perf_lbr.data (renamed from simpleperf/testdata/perf_lbr.data) | bin | 23855 -> 23855 bytes |
5 files changed, 99 insertions, 18 deletions
diff --git a/simpleperf/BranchListFile.h b/simpleperf/BranchListFile.h index b2d51b12..031a026f 100644 --- a/simpleperf/BranchListFile.h +++ b/simpleperf/BranchListFile.h @@ -38,7 +38,7 @@ struct BinaryKey { BinaryKey(const std::string& path, BuildId build_id) : path(path), build_id(build_id) {} - BinaryKey(Dso* dso, uint64_t kernel_start_addr) : path(dso->Path()) { + BinaryKey(const Dso* dso, uint64_t kernel_start_addr) : path(dso->Path()) { build_id = Dso::FindExpectedBuildIdForPath(dso->Path()); if (dso->type() == DSO_KERNEL) { this->kernel_start_addr = kernel_start_addr; diff --git a/simpleperf/cmd_inject.cpp b/simpleperf/cmd_inject.cpp index 7eafe6da..be8f4173 100644 --- a/simpleperf/cmd_inject.cpp +++ b/simpleperf/cmd_inject.cpp @@ -56,9 +56,20 @@ enum class OutputFormat { struct AutoFDOBinaryInfo { uint64_t first_load_segment_addr = 0; + std::unordered_map<uint64_t, uint64_t> address_count_map; std::unordered_map<AddrPair, uint64_t, AddrPairHash> range_count_map; std::unordered_map<AddrPair, uint64_t, AddrPairHash> branch_count_map; + void AddAddress(uint64_t addr) { OverflowSafeAdd(address_count_map[addr], 1); } + + void AddRange(uint64_t begin, uint64_t end) { + OverflowSafeAdd(range_count_map[std::make_pair(begin, end)], 1); + } + + void AddBranch(uint64_t from, uint64_t to) { + OverflowSafeAdd(branch_count_map[std::make_pair(from, to)], 1); + } + void AddInstrRange(const ETMInstrRange& instr_range) { uint64_t total_count = instr_range.branch_taken_count; OverflowSafeAdd(total_count, instr_range.branch_not_taken_count); @@ -71,6 +82,12 @@ struct AutoFDOBinaryInfo { } void Merge(const AutoFDOBinaryInfo& other) { + for (const auto& p : other.address_count_map) { + auto res = address_count_map.emplace(p.first, p.second); + if (!res.second) { + OverflowSafeAdd(res.first->second, p.second); + } + } for (const auto& p : other.range_count_map) { auto res = range_count_map.emplace(p.first, p.second); if (!res.second) { @@ -90,7 +107,7 @@ using AutoFDOBinaryCallback = std::function<void(const BinaryKey&, AutoFDOBinary using ETMBinaryCallback = std::function<void(const BinaryKey&, ETMBinary&)>; using LBRDataCallback = std::function<void(LBRData&)>; -static uint64_t GetFirstLoadSegmentVaddr(Dso* dso) { +static uint64_t GetFirstLoadSegmentVaddr(const Dso* dso) { ElfStatus status; if (auto elf = ElfFile::Open(dso->GetDebugFilePath(), &status); elf) { for (const auto& segment : elf->GetProgramHeader()) { @@ -162,6 +179,15 @@ class PerfDataReader { virtual bool ProcessRecord(Record& r) = 0; virtual bool PostProcess() = 0; + void ProcessAutoFDOBinaryInfo() { + for (auto& p : autofdo_binary_map_) { + const Dso* dso = p.first; + AutoFDOBinaryInfo& binary = p.second; + binary.first_load_segment_addr = GetFirstLoadSegmentVaddr(dso); + autofdo_callback_(BinaryKey(dso, 0), binary); + } + } + const std::string data_type_; std::unique_ptr<RecordFileReader> reader_; bool exclude_perf_; @@ -171,7 +197,7 @@ class PerfDataReader { ThreadTree thread_tree_; AutoFDOBinaryCallback autofdo_callback_; // Store results for AutoFDO. - std::unordered_map<Dso*, AutoFDOBinaryInfo> autofdo_binary_map_; + std::unordered_map<const Dso*, AutoFDOBinaryInfo> autofdo_binary_map_; }; class ETMThreadTreeWithFilter : public ETMThreadTree { @@ -314,15 +340,6 @@ class ETMPerfDataReader : public PerfDataReader { ++branch_map[branch_list.addr][branch_list.branch]; } - void ProcessAutoFDOBinaryInfo() { - for (auto& p : autofdo_binary_map_) { - Dso* dso = p.first; - AutoFDOBinaryInfo& binary = p.second; - binary.first_load_segment_addr = GetFirstLoadSegmentVaddr(dso); - autofdo_callback_(BinaryKey(dso, 0), binary); - } - } - void ProcessETMBinary() { for (auto& p : etm_binary_map_) { Dso* dso = p.first; @@ -376,6 +393,7 @@ class LBRPerfDataReader : public PerfDataReader { LBRSample& sample = lbr_data_.samples.back(); std::pair<uint32_t, uint64_t> binary_addr = IpToBinaryAddr(*thread, sr.ip_data.ip); sample.binary_id = binary_addr.first; + bool has_valid_binary_id = sample.binary_id != 0; sample.vaddr_in_file = binary_addr.second; sample.branches.resize(stack.stack_nr); for (size_t i = 0; i < stack.stack_nr; ++i) { @@ -388,12 +406,24 @@ class LBRPerfDataReader : public PerfDataReader { binary_addr = IpToBinaryAddr(*thread, to_ip); branch.to_binary_id = binary_addr.first; branch.to_vaddr_in_file = binary_addr.second; + if (branch.from_binary_id != 0 || branch.to_binary_id != 0) { + has_valid_binary_id = true; + } + } + if (!has_valid_binary_id) { + lbr_data_.samples.pop_back(); } } return true; } - bool PostProcess() override { return true; } + bool PostProcess() override { + if (autofdo_callback_) { + ConvertLBRDataToAutoFDO(); + ProcessAutoFDOBinaryInfo(); + } + return true; + } std::pair<uint32_t, uint64_t> IpToBinaryAddr(ThreadEntry& thread, uint64_t ip) { const MapEntry* map = thread_tree_.FindMap(&thread, ip); @@ -415,6 +445,37 @@ class LBRPerfDataReader : public PerfDataReader { return binary_id; } + void ConvertLBRDataToAutoFDO() { + std::vector<AutoFDOBinaryInfo> binaries(dso_map_.size()); + for (const LBRSample& sample : lbr_data_.samples) { + if (sample.binary_id != 0) { + binaries[sample.binary_id - 1].AddAddress(sample.vaddr_in_file); + } + for (size_t i = 0; i < sample.branches.size(); ++i) { + const LBRBranch& branch = sample.branches[i]; + if (branch.from_binary_id == 0) { + continue; + } + if (branch.from_binary_id == branch.to_binary_id) { + binaries[branch.from_binary_id - 1].AddBranch(branch.from_vaddr_in_file, + branch.to_vaddr_in_file); + } + if (i > 0 && branch.from_binary_id == sample.branches[i - 1].to_binary_id) { + uint64_t begin = sample.branches[i - 1].to_vaddr_in_file; + uint64_t end = branch.from_vaddr_in_file; + // Use the same logic to skip bogus LBR data as AutoFDO. + if (end < begin || end - begin > (1 << 20)) { + continue; + } + binaries[branch.from_binary_id - 1].AddRange(begin, end); + } + } + } + for (const auto& [dso, binary_id] : dso_map_) { + autofdo_binary_map_[dso] = std::move(binaries[binary_id - 1]); + } + } + LBRDataCallback lbr_data_callback_; LBRData lbr_data_; // Map from dso to binary_id in lbr_data_. @@ -571,7 +632,12 @@ class AutoFDOWriter { } // Write addr_count_map. - fprintf(output_fp.get(), "0\n"); + std::map<uint64_t, uint64_t> address_count_map(binary.address_count_map.begin(), + binary.address_count_map.end()); + fprintf(output_fp.get(), "%zu\n", address_count_map.size()); + for (const auto& [addr, count] : address_count_map) { + fprintf(output_fp.get(), "%" PRIx64 ":%" PRIu64 "\n", to_offset(addr), count); + } // Write branch_count_map. std::map<AddrPair, uint64_t> branch_count_map(binary.branch_count_map.begin(), diff --git a/simpleperf/cmd_inject_test.cpp b/simpleperf/cmd_inject_test.cpp index 758f89b5..3b25553b 100644 --- a/simpleperf/cmd_inject_test.cpp +++ b/simpleperf/cmd_inject_test.cpp @@ -226,8 +226,12 @@ TEST(cmd_inject, accept_missing_aux_data) { } TEST(cmd_inject, read_lbr_data) { - std::string perf_data = GetTestData("perf_lbr.data"); - TemporaryFile tmpfile; - close(tmpfile.release()); - ASSERT_TRUE(RunInjectCmd({"-i", perf_data, "-o", tmpfile.path})); + std::string data; + ASSERT_TRUE(RunInjectCmd({"-i", GetTestData("lbr/perf_lbr.data")}, &data)); + data.erase(std::remove(data.begin(), data.end(), '\r'), data.end()); + + std::string expected_data; + ASSERT_TRUE(android::base::ReadFileToString( + GetTestData(std::string("lbr") + OS_PATH_SEPARATOR + "inject_lbr.data"), &expected_data)); + ASSERT_NE(data.find(expected_data), data.npos); } diff --git a/simpleperf/testdata/lbr/inject_lbr.data b/simpleperf/testdata/lbr/inject_lbr.data new file mode 100644 index 00000000..ffc9b5b5 --- /dev/null +++ b/simpleperf/testdata/lbr/inject_lbr.data @@ -0,0 +1,11 @@ +2 +1910-191b:31 +1940-194d:341 +4 +1914:1 +1940:3 +1944:4 +1948:11 +2 +191b->1910:32 +194d->1940:353 diff --git a/simpleperf/testdata/perf_lbr.data b/simpleperf/testdata/lbr/perf_lbr.data Binary files differindex 81fafe62..81fafe62 100644 --- a/simpleperf/testdata/perf_lbr.data +++ b/simpleperf/testdata/lbr/perf_lbr.data |