1*288bf522SAndroid Build Coastguard Worker /* 2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project 3*288bf522SAndroid Build Coastguard Worker * 4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*288bf522SAndroid Build Coastguard Worker * 8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*288bf522SAndroid Build Coastguard Worker * 10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*288bf522SAndroid Build Coastguard Worker * limitations under the License. 15*288bf522SAndroid Build Coastguard Worker */ 16*288bf522SAndroid Build Coastguard Worker 17*288bf522SAndroid Build Coastguard Worker #pragma once 18*288bf522SAndroid Build Coastguard Worker 19*288bf522SAndroid Build Coastguard Worker #include "ETMDecoder.h" 20*288bf522SAndroid Build Coastguard Worker #include "RegEx.h" 21*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h" 22*288bf522SAndroid Build Coastguard Worker #include "utils.h" 23*288bf522SAndroid Build Coastguard Worker 24*288bf522SAndroid Build Coastguard Worker namespace simpleperf { 25*288bf522SAndroid Build Coastguard Worker 26*288bf522SAndroid Build Coastguard Worker // When processing binary info in an input file, the binaries are identified by their path. 27*288bf522SAndroid Build Coastguard Worker // But this isn't sufficient when merging binary info from multiple input files. Because 28*288bf522SAndroid Build Coastguard Worker // binaries for the same path may be changed between generating input files. So after processing 29*288bf522SAndroid Build Coastguard Worker // each input file, we create BinaryKeys to identify binaries, which consider path, build_id and 30*288bf522SAndroid Build Coastguard Worker // kernel_start_addr (for vmlinux). kernel_start_addr affects how addresses in ETMBinary 31*288bf522SAndroid Build Coastguard Worker // are interpreted for vmlinux. 32*288bf522SAndroid Build Coastguard Worker struct BinaryKey { 33*288bf522SAndroid Build Coastguard Worker std::string path; 34*288bf522SAndroid Build Coastguard Worker BuildId build_id; 35*288bf522SAndroid Build Coastguard Worker uint64_t kernel_start_addr = 0; 36*288bf522SAndroid Build Coastguard Worker BinaryKeyBinaryKey37*288bf522SAndroid Build Coastguard Worker BinaryKey() {} 38*288bf522SAndroid Build Coastguard Worker BinaryKeyBinaryKey39*288bf522SAndroid Build Coastguard Worker BinaryKey(const std::string& path, BuildId build_id) : path(path), build_id(build_id) {} 40*288bf522SAndroid Build Coastguard Worker BinaryKeyBinaryKey41*288bf522SAndroid Build Coastguard Worker BinaryKey(const Dso* dso, uint64_t kernel_start_addr) : path(dso->Path()) { 42*288bf522SAndroid Build Coastguard Worker build_id = Dso::FindExpectedBuildIdForPath(dso->Path()); 43*288bf522SAndroid Build Coastguard Worker if (build_id.IsEmpty()) { 44*288bf522SAndroid Build Coastguard Worker GetBuildId(*dso, build_id); 45*288bf522SAndroid Build Coastguard Worker } 46*288bf522SAndroid Build Coastguard Worker if (dso->type() == DSO_KERNEL) { 47*288bf522SAndroid Build Coastguard Worker this->kernel_start_addr = kernel_start_addr; 48*288bf522SAndroid Build Coastguard Worker } 49*288bf522SAndroid Build Coastguard Worker } 50*288bf522SAndroid Build Coastguard Worker 51*288bf522SAndroid Build Coastguard Worker bool operator==(const BinaryKey& other) const { 52*288bf522SAndroid Build Coastguard Worker return path == other.path && build_id == other.build_id && 53*288bf522SAndroid Build Coastguard Worker kernel_start_addr == other.kernel_start_addr; 54*288bf522SAndroid Build Coastguard Worker } 55*288bf522SAndroid Build Coastguard Worker }; 56*288bf522SAndroid Build Coastguard Worker 57*288bf522SAndroid Build Coastguard Worker struct BinaryKeyHash { operatorBinaryKeyHash58*288bf522SAndroid Build Coastguard Worker size_t operator()(const BinaryKey& key) const noexcept { 59*288bf522SAndroid Build Coastguard Worker size_t seed = 0; 60*288bf522SAndroid Build Coastguard Worker HashCombine(seed, key.path); 61*288bf522SAndroid Build Coastguard Worker HashCombine(seed, key.build_id); 62*288bf522SAndroid Build Coastguard Worker if (key.kernel_start_addr != 0) { 63*288bf522SAndroid Build Coastguard Worker HashCombine(seed, key.kernel_start_addr); 64*288bf522SAndroid Build Coastguard Worker } 65*288bf522SAndroid Build Coastguard Worker return seed; 66*288bf522SAndroid Build Coastguard Worker } 67*288bf522SAndroid Build Coastguard Worker }; 68*288bf522SAndroid Build Coastguard Worker 69*288bf522SAndroid Build Coastguard Worker class BinaryFilter { 70*288bf522SAndroid Build Coastguard Worker public: BinaryFilter(const RegEx * binary_name_regex)71*288bf522SAndroid Build Coastguard Worker BinaryFilter(const RegEx* binary_name_regex) : binary_name_regex_(binary_name_regex) {} 72*288bf522SAndroid Build Coastguard Worker SetRegex(const RegEx * binary_name_regex)73*288bf522SAndroid Build Coastguard Worker void SetRegex(const RegEx* binary_name_regex) { 74*288bf522SAndroid Build Coastguard Worker binary_name_regex_ = binary_name_regex; 75*288bf522SAndroid Build Coastguard Worker dso_filter_cache_.clear(); 76*288bf522SAndroid Build Coastguard Worker } 77*288bf522SAndroid Build Coastguard Worker Filter(const Dso * dso)78*288bf522SAndroid Build Coastguard Worker bool Filter(const Dso* dso) { 79*288bf522SAndroid Build Coastguard Worker auto lookup = dso_filter_cache_.find(dso); 80*288bf522SAndroid Build Coastguard Worker if (lookup != dso_filter_cache_.end()) { 81*288bf522SAndroid Build Coastguard Worker return lookup->second; 82*288bf522SAndroid Build Coastguard Worker } 83*288bf522SAndroid Build Coastguard Worker bool match = Filter(dso->Path()); 84*288bf522SAndroid Build Coastguard Worker dso_filter_cache_.insert({dso, match}); 85*288bf522SAndroid Build Coastguard Worker return match; 86*288bf522SAndroid Build Coastguard Worker } 87*288bf522SAndroid Build Coastguard Worker Filter(const std::string & path)88*288bf522SAndroid Build Coastguard Worker bool Filter(const std::string& path) { 89*288bf522SAndroid Build Coastguard Worker return binary_name_regex_ == nullptr || binary_name_regex_->Search(path); 90*288bf522SAndroid Build Coastguard Worker } 91*288bf522SAndroid Build Coastguard Worker 92*288bf522SAndroid Build Coastguard Worker private: 93*288bf522SAndroid Build Coastguard Worker const RegEx* binary_name_regex_; 94*288bf522SAndroid Build Coastguard Worker std::unordered_map<const Dso*, bool> dso_filter_cache_; 95*288bf522SAndroid Build Coastguard Worker }; 96*288bf522SAndroid Build Coastguard Worker 97*288bf522SAndroid Build Coastguard Worker using UnorderedETMBranchMap = 98*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, std::unordered_map<std::vector<bool>, uint64_t>>; 99*288bf522SAndroid Build Coastguard Worker 100*288bf522SAndroid Build Coastguard Worker struct ETMBinary { 101*288bf522SAndroid Build Coastguard Worker DsoType dso_type; 102*288bf522SAndroid Build Coastguard Worker UnorderedETMBranchMap branch_map; 103*288bf522SAndroid Build Coastguard Worker MergeETMBinary104*288bf522SAndroid Build Coastguard Worker void Merge(const ETMBinary& other) { 105*288bf522SAndroid Build Coastguard Worker for (auto& other_p : other.branch_map) { 106*288bf522SAndroid Build Coastguard Worker auto it = branch_map.find(other_p.first); 107*288bf522SAndroid Build Coastguard Worker if (it == branch_map.end()) { 108*288bf522SAndroid Build Coastguard Worker branch_map[other_p.first] = std::move(other_p.second); 109*288bf522SAndroid Build Coastguard Worker } else { 110*288bf522SAndroid Build Coastguard Worker auto& map2 = it->second; 111*288bf522SAndroid Build Coastguard Worker for (auto& other_p2 : other_p.second) { 112*288bf522SAndroid Build Coastguard Worker auto it2 = map2.find(other_p2.first); 113*288bf522SAndroid Build Coastguard Worker if (it2 == map2.end()) { 114*288bf522SAndroid Build Coastguard Worker map2[other_p2.first] = other_p2.second; 115*288bf522SAndroid Build Coastguard Worker } else { 116*288bf522SAndroid Build Coastguard Worker OverflowSafeAdd(it2->second, other_p2.second); 117*288bf522SAndroid Build Coastguard Worker } 118*288bf522SAndroid Build Coastguard Worker } 119*288bf522SAndroid Build Coastguard Worker } 120*288bf522SAndroid Build Coastguard Worker } 121*288bf522SAndroid Build Coastguard Worker } 122*288bf522SAndroid Build Coastguard Worker GetOrderedBranchMapETMBinary123*288bf522SAndroid Build Coastguard Worker ETMBranchMap GetOrderedBranchMap() const { 124*288bf522SAndroid Build Coastguard Worker ETMBranchMap result; 125*288bf522SAndroid Build Coastguard Worker for (const auto& p : branch_map) { 126*288bf522SAndroid Build Coastguard Worker uint64_t addr = p.first; 127*288bf522SAndroid Build Coastguard Worker const auto& b_map = p.second; 128*288bf522SAndroid Build Coastguard Worker result[addr] = std::map<std::vector<bool>, uint64_t>(b_map.begin(), b_map.end()); 129*288bf522SAndroid Build Coastguard Worker } 130*288bf522SAndroid Build Coastguard Worker return result; 131*288bf522SAndroid Build Coastguard Worker } 132*288bf522SAndroid Build Coastguard Worker }; 133*288bf522SAndroid Build Coastguard Worker 134*288bf522SAndroid Build Coastguard Worker using ETMBinaryMap = std::unordered_map<BinaryKey, ETMBinary, BinaryKeyHash>; 135*288bf522SAndroid Build Coastguard Worker bool ETMBinaryMapToString(const ETMBinaryMap& binary_map, std::string& s); 136*288bf522SAndroid Build Coastguard Worker bool StringToETMBinaryMap(const std::string& s, ETMBinaryMap& binary_map); 137*288bf522SAndroid Build Coastguard Worker 138*288bf522SAndroid Build Coastguard Worker // Convert ETM data into branch lists while recording. 139*288bf522SAndroid Build Coastguard Worker class ETMBranchListGenerator { 140*288bf522SAndroid Build Coastguard Worker public: 141*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<ETMBranchListGenerator> Create(bool dump_maps_from_proc); 142*288bf522SAndroid Build Coastguard Worker 143*288bf522SAndroid Build Coastguard Worker virtual ~ETMBranchListGenerator(); 144*288bf522SAndroid Build Coastguard Worker virtual void SetExcludePid(pid_t pid) = 0; 145*288bf522SAndroid Build Coastguard Worker virtual void SetBinaryFilter(const RegEx* binary_name_regex) = 0; 146*288bf522SAndroid Build Coastguard Worker virtual bool ProcessRecord(const Record& r, bool& consumed) = 0; 147*288bf522SAndroid Build Coastguard Worker virtual ETMBinaryMap GetETMBinaryMap() = 0; 148*288bf522SAndroid Build Coastguard Worker }; 149*288bf522SAndroid Build Coastguard Worker 150*288bf522SAndroid Build Coastguard Worker struct LBRBranch { 151*288bf522SAndroid Build Coastguard Worker // If from_binary_id >= 1, it refers to LBRData.binaries[from_binary_id - 1]. Otherwise, it's 152*288bf522SAndroid Build Coastguard Worker // invalid. 153*288bf522SAndroid Build Coastguard Worker uint32_t from_binary_id = 0; 154*288bf522SAndroid Build Coastguard Worker // If to_binary_id >= 1, it refers to LBRData.binaries[to_binary_id - 1]. Otherwise, it's invalid. 155*288bf522SAndroid Build Coastguard Worker uint32_t to_binary_id = 0; 156*288bf522SAndroid Build Coastguard Worker uint64_t from_vaddr_in_file = 0; 157*288bf522SAndroid Build Coastguard Worker uint64_t to_vaddr_in_file = 0; 158*288bf522SAndroid Build Coastguard Worker }; 159*288bf522SAndroid Build Coastguard Worker 160*288bf522SAndroid Build Coastguard Worker struct LBRSample { 161*288bf522SAndroid Build Coastguard Worker // If binary_id >= 1, it refers to LBRData.binaries[binary_id - 1]. Otherwise, it's invalid. 162*288bf522SAndroid Build Coastguard Worker uint32_t binary_id = 0; 163*288bf522SAndroid Build Coastguard Worker uint64_t vaddr_in_file = 0; 164*288bf522SAndroid Build Coastguard Worker std::vector<LBRBranch> branches; 165*288bf522SAndroid Build Coastguard Worker }; 166*288bf522SAndroid Build Coastguard Worker 167*288bf522SAndroid Build Coastguard Worker struct LBRData { 168*288bf522SAndroid Build Coastguard Worker std::vector<LBRSample> samples; 169*288bf522SAndroid Build Coastguard Worker std::vector<BinaryKey> binaries; 170*288bf522SAndroid Build Coastguard Worker }; 171*288bf522SAndroid Build Coastguard Worker 172*288bf522SAndroid Build Coastguard Worker bool LBRDataToString(const LBRData& data, std::string& s); 173*288bf522SAndroid Build Coastguard Worker 174*288bf522SAndroid Build Coastguard Worker namespace proto { 175*288bf522SAndroid Build Coastguard Worker class BranchList; 176*288bf522SAndroid Build Coastguard Worker class ETMBinary; 177*288bf522SAndroid Build Coastguard Worker class LBRData; 178*288bf522SAndroid Build Coastguard Worker } // namespace proto 179*288bf522SAndroid Build Coastguard Worker 180*288bf522SAndroid Build Coastguard Worker class BranchListProtoWriter { 181*288bf522SAndroid Build Coastguard Worker private: 182*288bf522SAndroid Build Coastguard Worker // This value is choosen to prevent exceeding the 2GB size limit for a protobuf message. 183*288bf522SAndroid Build Coastguard Worker static constexpr size_t kMaxBranchesPerMessage = 100000000; 184*288bf522SAndroid Build Coastguard Worker 185*288bf522SAndroid Build Coastguard Worker public: 186*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<BranchListProtoWriter> CreateForFile( 187*288bf522SAndroid Build Coastguard Worker const std::string& output_filename, bool compress, 188*288bf522SAndroid Build Coastguard Worker size_t max_branches_per_message = kMaxBranchesPerMessage); 189*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<BranchListProtoWriter> CreateForString( 190*288bf522SAndroid Build Coastguard Worker std::string* output_str, bool compress, 191*288bf522SAndroid Build Coastguard Worker size_t max_branches_per_message = kMaxBranchesPerMessage); 192*288bf522SAndroid Build Coastguard Worker 193*288bf522SAndroid Build Coastguard Worker bool Write(const ETMBinaryMap& etm_data); 194*288bf522SAndroid Build Coastguard Worker bool Write(const LBRData& lbr_data); 195*288bf522SAndroid Build Coastguard Worker 196*288bf522SAndroid Build Coastguard Worker private: BranchListProtoWriter(const std::string & output_filename,std::string * output_str,bool compress,size_t max_branches_per_message)197*288bf522SAndroid Build Coastguard Worker BranchListProtoWriter(const std::string& output_filename, std::string* output_str, bool compress, 198*288bf522SAndroid Build Coastguard Worker size_t max_branches_per_message) 199*288bf522SAndroid Build Coastguard Worker : output_filename_(output_filename), 200*288bf522SAndroid Build Coastguard Worker compress_(compress), 201*288bf522SAndroid Build Coastguard Worker max_branches_per_message_(max_branches_per_message), 202*288bf522SAndroid Build Coastguard Worker output_fp_(nullptr, fclose), 203*288bf522SAndroid Build Coastguard Worker output_str_(output_str) {} 204*288bf522SAndroid Build Coastguard Worker 205*288bf522SAndroid Build Coastguard Worker bool WriteHeader(); 206*288bf522SAndroid Build Coastguard Worker bool WriteProtoBranchList(proto::BranchList& branch_list); 207*288bf522SAndroid Build Coastguard Worker bool WriteData(const void* data, size_t size); 208*288bf522SAndroid Build Coastguard Worker 209*288bf522SAndroid Build Coastguard Worker const std::string output_filename_; 210*288bf522SAndroid Build Coastguard Worker const bool compress_; 211*288bf522SAndroid Build Coastguard Worker const size_t max_branches_per_message_; 212*288bf522SAndroid Build Coastguard Worker std::unique_ptr<FILE, decltype(&fclose)> output_fp_; 213*288bf522SAndroid Build Coastguard Worker std::string* output_str_; 214*288bf522SAndroid Build Coastguard Worker }; 215*288bf522SAndroid Build Coastguard Worker 216*288bf522SAndroid Build Coastguard Worker class BranchListProtoReader { 217*288bf522SAndroid Build Coastguard Worker public: 218*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<BranchListProtoReader> CreateForFile(const std::string& input_filename); 219*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<BranchListProtoReader> CreateForString(const std::string& input_str); 220*288bf522SAndroid Build Coastguard Worker bool Read(ETMBinaryMap& etm_data, LBRData& lbr_data); 221*288bf522SAndroid Build Coastguard Worker 222*288bf522SAndroid Build Coastguard Worker private: BranchListProtoReader(const std::string & input_filename,const std::string & input_str)223*288bf522SAndroid Build Coastguard Worker BranchListProtoReader(const std::string& input_filename, const std::string& input_str) 224*288bf522SAndroid Build Coastguard Worker : input_filename_(input_filename), input_fp_(nullptr, fclose), input_str_(input_str) {} 225*288bf522SAndroid Build Coastguard Worker bool ReadProtoBranchList(uint32_t size, proto::BranchList& proto_branch_list); 226*288bf522SAndroid Build Coastguard Worker bool AddETMBinary(const proto::ETMBinary& proto_binary, ETMBinaryMap& etm_data); 227*288bf522SAndroid Build Coastguard Worker void AddLBRData(const proto::LBRData& proto_lbr_data, LBRData& lbr_data); 228*288bf522SAndroid Build Coastguard Worker void Rewind(); 229*288bf522SAndroid Build Coastguard Worker bool ReadData(void* data, size_t size); 230*288bf522SAndroid Build Coastguard Worker bool ReadOldFileFormat(ETMBinaryMap& etm_data, LBRData& lbr_data); 231*288bf522SAndroid Build Coastguard Worker 232*288bf522SAndroid Build Coastguard Worker const std::string input_filename_; 233*288bf522SAndroid Build Coastguard Worker std::unique_ptr<FILE, decltype(&fclose)> input_fp_; 234*288bf522SAndroid Build Coastguard Worker const std::string& input_str_; 235*288bf522SAndroid Build Coastguard Worker size_t input_str_pos_ = 0; 236*288bf522SAndroid Build Coastguard Worker bool compress_ = false; 237*288bf522SAndroid Build Coastguard Worker }; 238*288bf522SAndroid Build Coastguard Worker 239*288bf522SAndroid Build Coastguard Worker bool DumpBranchListFile(std::string filename); 240*288bf522SAndroid Build Coastguard Worker 241*288bf522SAndroid Build Coastguard Worker // for testing 242*288bf522SAndroid Build Coastguard Worker std::string ETMBranchToProtoString(const std::vector<bool>& branch); 243*288bf522SAndroid Build Coastguard Worker std::vector<bool> ProtoStringToETMBranch(const std::string& s, size_t bit_size); 244*288bf522SAndroid Build Coastguard Worker 245*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf 246