• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "ETMDecoder.h"
20 #include "RegEx.h"
21 #include "thread_tree.h"
22 #include "utils.h"
23 
24 namespace simpleperf {
25 
26 // When processing binary info in an input file, the binaries are identified by their path.
27 // But this isn't sufficient when merging binary info from multiple input files. Because
28 // binaries for the same path may be changed between generating input files. So after processing
29 // each input file, we create BinaryKeys to identify binaries, which consider path, build_id and
30 // kernel_start_addr (for vmlinux). kernel_start_addr affects how addresses in BranchListBinaryInfo
31 // are interpreted for vmlinux.
32 struct BinaryKey {
33   std::string path;
34   BuildId build_id;
35   uint64_t kernel_start_addr = 0;
36 
BinaryKeyBinaryKey37   BinaryKey() {}
38 
BinaryKeyBinaryKey39   BinaryKey(const std::string& path, BuildId build_id) : path(path), build_id(build_id) {}
40 
BinaryKeyBinaryKey41   BinaryKey(Dso* dso, uint64_t kernel_start_addr) : path(dso->Path()) {
42     build_id = Dso::FindExpectedBuildIdForPath(dso->Path());
43     if (dso->type() == DSO_KERNEL) {
44       this->kernel_start_addr = kernel_start_addr;
45     }
46   }
47 
48   bool operator==(const BinaryKey& other) const {
49     return path == other.path && build_id == other.build_id &&
50            kernel_start_addr == other.kernel_start_addr;
51   }
52 };
53 
54 struct BinaryKeyHash {
operatorBinaryKeyHash55   size_t operator()(const BinaryKey& key) const noexcept {
56     size_t seed = 0;
57     HashCombine(seed, key.path);
58     HashCombine(seed, key.build_id);
59     if (key.kernel_start_addr != 0) {
60       HashCombine(seed, key.kernel_start_addr);
61     }
62     return seed;
63   }
64 };
65 
66 using UnorderedBranchMap =
67     std::unordered_map<uint64_t, std::unordered_map<std::vector<bool>, uint64_t>>;
68 
69 struct BranchListBinaryInfo {
70   DsoType dso_type;
71   UnorderedBranchMap branch_map;
72 
MergeBranchListBinaryInfo73   void Merge(const BranchListBinaryInfo& other) {
74     for (auto& other_p : other.branch_map) {
75       auto it = branch_map.find(other_p.first);
76       if (it == branch_map.end()) {
77         branch_map[other_p.first] = std::move(other_p.second);
78       } else {
79         auto& map2 = it->second;
80         for (auto& other_p2 : other_p.second) {
81           auto it2 = map2.find(other_p2.first);
82           if (it2 == map2.end()) {
83             map2[other_p2.first] = other_p2.second;
84           } else {
85             OverflowSafeAdd(it2->second, other_p2.second);
86           }
87         }
88       }
89     }
90   }
91 
GetOrderedBranchMapBranchListBinaryInfo92   BranchMap GetOrderedBranchMap() const {
93     BranchMap result;
94     for (const auto& p : branch_map) {
95       uint64_t addr = p.first;
96       const auto& b_map = p.second;
97       result[addr] = std::map<std::vector<bool>, uint64_t>(b_map.begin(), b_map.end());
98     }
99     return result;
100   }
101 };
102 
103 using BranchListBinaryMap = std::unordered_map<BinaryKey, BranchListBinaryInfo, BinaryKeyHash>;
104 
105 bool BranchListBinaryMapToString(const BranchListBinaryMap& binary_map, std::string& s);
106 bool StringToBranchListBinaryMap(const std::string& s, BranchListBinaryMap& binary_map);
107 
108 class BinaryFilter {
109  public:
BinaryFilter(const RegEx * binary_name_regex)110   BinaryFilter(const RegEx* binary_name_regex) : binary_name_regex_(binary_name_regex) {}
111 
SetRegex(const RegEx * binary_name_regex)112   void SetRegex(const RegEx* binary_name_regex) {
113     binary_name_regex_ = binary_name_regex;
114     dso_filter_cache_.clear();
115   }
116 
Filter(Dso * dso)117   bool Filter(Dso* dso) {
118     auto lookup = dso_filter_cache_.find(dso);
119     if (lookup != dso_filter_cache_.end()) {
120       return lookup->second;
121     }
122     bool match = Filter(dso->Path());
123     dso_filter_cache_.insert({dso, match});
124     return match;
125   }
126 
Filter(const std::string & path)127   bool Filter(const std::string& path) {
128     return binary_name_regex_ == nullptr || binary_name_regex_->Search(path);
129   }
130 
131  private:
132   const RegEx* binary_name_regex_;
133   std::unordered_map<Dso*, bool> dso_filter_cache_;
134 };
135 
136 // Convert ETM data into branch lists while recording.
137 class ETMBranchListGenerator {
138  public:
139   static std::unique_ptr<ETMBranchListGenerator> Create(bool dump_maps_from_proc);
140 
141   virtual ~ETMBranchListGenerator();
142   virtual void SetExcludePid(pid_t pid) = 0;
143   virtual void SetBinaryFilter(const RegEx* binary_name_regex) = 0;
144   virtual bool ProcessRecord(const Record& r, bool& consumed) = 0;
145   virtual BranchListBinaryMap GetBranchListBinaryMap() = 0;
146 };
147 
148 // for testing
149 std::string BranchToProtoString(const std::vector<bool>& branch);
150 std::vector<bool> ProtoStringToBranch(const std::string& s, size_t bit_size);
151 
152 }  // namespace simpleperf
153