xref: /aosp_15_r20/system/extras/simpleperf/sample_tree.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 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 #ifndef SIMPLE_PERF_SAMPLE_TREE_H_
18*288bf522SAndroid Build Coastguard Worker #define SIMPLE_PERF_SAMPLE_TREE_H_
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
21*288bf522SAndroid Build Coastguard Worker 
22*288bf522SAndroid Build Coastguard Worker #include "OfflineUnwinder.h"
23*288bf522SAndroid Build Coastguard Worker #include "SampleComparator.h"
24*288bf522SAndroid Build Coastguard Worker #include "SampleDisplayer.h"
25*288bf522SAndroid Build Coastguard Worker #include "callchain.h"
26*288bf522SAndroid Build Coastguard Worker #include "perf_regs.h"
27*288bf522SAndroid Build Coastguard Worker #include "record.h"
28*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
29*288bf522SAndroid Build Coastguard Worker 
30*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
31*288bf522SAndroid Build Coastguard Worker 
32*288bf522SAndroid Build Coastguard Worker // A SampleTree is a collection of samples. A profiling report is mainly about
33*288bf522SAndroid Build Coastguard Worker // constructing a SampleTree and display it. There are three steps involved:
34*288bf522SAndroid Build Coastguard Worker // build the tree, sort the tree, and display it. For example, if we want to
35*288bf522SAndroid Build Coastguard Worker // show how many cpu-cycles are spent in different functions, we should do as
36*288bf522SAndroid Build Coastguard Worker // follows:
37*288bf522SAndroid Build Coastguard Worker // 1. Build a SampleTree from SampleRecords with each sample containing
38*288bf522SAndroid Build Coastguard Worker //    (cpu-cycles, function name). When building the tree, we should merge
39*288bf522SAndroid Build Coastguard Worker //    samples containing the same function name.
40*288bf522SAndroid Build Coastguard Worker // 2. Sort the SampleTree by cpu-cycles in the sample. As we want to display the
41*288bf522SAndroid Build Coastguard Worker //    samples in a decreasing order of cpu-cycles, we should sort it like this.
42*288bf522SAndroid Build Coastguard Worker // 3. Display the SampleTree, each sample prints its (cpu-cycles, function name)
43*288bf522SAndroid Build Coastguard Worker //    pair.
44*288bf522SAndroid Build Coastguard Worker //
45*288bf522SAndroid Build Coastguard Worker // We represent the three steps with three template classes.
46*288bf522SAndroid Build Coastguard Worker // 1. A SampleTree is built by SampleTreeBuilder. The comparator passed in
47*288bf522SAndroid Build Coastguard Worker //    SampleTreeBuilder's constructor decides the property of samples should be
48*288bf522SAndroid Build Coastguard Worker //    merged together.
49*288bf522SAndroid Build Coastguard Worker // 2. After a SampleTree is built and got from SampleTreeBuilder, it should be
50*288bf522SAndroid Build Coastguard Worker //    sorted by SampleTreeSorter. The sort result decides the order to show
51*288bf522SAndroid Build Coastguard Worker //    samples.
52*288bf522SAndroid Build Coastguard Worker // 3. At last, the sorted SampleTree is passed to SampleTreeDisplayer, which
53*288bf522SAndroid Build Coastguard Worker //    displays each sample in the SampleTree.
54*288bf522SAndroid Build Coastguard Worker 
55*288bf522SAndroid Build Coastguard Worker template <typename EntryT, typename AccumulateInfoT>
56*288bf522SAndroid Build Coastguard Worker class SampleTreeBuilder {
57*288bf522SAndroid Build Coastguard Worker  public:
SampleTreeBuilder(const SampleComparator<EntryT> & comparator)58*288bf522SAndroid Build Coastguard Worker   explicit SampleTreeBuilder(const SampleComparator<EntryT>& comparator)
59*288bf522SAndroid Build Coastguard Worker       : sample_set_(comparator),
60*288bf522SAndroid Build Coastguard Worker         accumulate_callchain_(false),
61*288bf522SAndroid Build Coastguard Worker         sample_comparator_(comparator),
62*288bf522SAndroid Build Coastguard Worker         filtered_sample_set_(comparator),
63*288bf522SAndroid Build Coastguard Worker         use_branch_address_(false),
64*288bf522SAndroid Build Coastguard Worker         build_callchain_(false),
65*288bf522SAndroid Build Coastguard Worker         use_caller_as_callchain_root_(false) {}
66*288bf522SAndroid Build Coastguard Worker 
~SampleTreeBuilder()67*288bf522SAndroid Build Coastguard Worker   virtual ~SampleTreeBuilder() {}
68*288bf522SAndroid Build Coastguard Worker 
SetBranchSampleOption(bool use_branch_address)69*288bf522SAndroid Build Coastguard Worker   void SetBranchSampleOption(bool use_branch_address) { use_branch_address_ = use_branch_address; }
70*288bf522SAndroid Build Coastguard Worker 
SetCallChainSampleOptions(bool accumulate_callchain,bool build_callchain,bool use_caller_as_callchain_root)71*288bf522SAndroid Build Coastguard Worker   void SetCallChainSampleOptions(bool accumulate_callchain, bool build_callchain,
72*288bf522SAndroid Build Coastguard Worker                                  bool use_caller_as_callchain_root) {
73*288bf522SAndroid Build Coastguard Worker     accumulate_callchain_ = accumulate_callchain;
74*288bf522SAndroid Build Coastguard Worker     build_callchain_ = build_callchain;
75*288bf522SAndroid Build Coastguard Worker     use_caller_as_callchain_root_ = use_caller_as_callchain_root;
76*288bf522SAndroid Build Coastguard Worker     if (accumulate_callchain_) {
77*288bf522SAndroid Build Coastguard Worker       offline_unwinder_ = OfflineUnwinder::Create(false);
78*288bf522SAndroid Build Coastguard Worker     }
79*288bf522SAndroid Build Coastguard Worker   }
80*288bf522SAndroid Build Coastguard Worker 
GetUnwinder()81*288bf522SAndroid Build Coastguard Worker   OfflineUnwinder* GetUnwinder() { return offline_unwinder_.get(); }
82*288bf522SAndroid Build Coastguard Worker 
ProcessSampleRecord(const SampleRecord & r)83*288bf522SAndroid Build Coastguard Worker   void ProcessSampleRecord(const SampleRecord& r) {
84*288bf522SAndroid Build Coastguard Worker     if (use_branch_address_ && (r.sample_type & PERF_SAMPLE_BRANCH_STACK)) {
85*288bf522SAndroid Build Coastguard Worker       for (uint64_t i = 0; i < r.branch_stack_data.stack_nr; ++i) {
86*288bf522SAndroid Build Coastguard Worker         auto& item = r.branch_stack_data.stack[i];
87*288bf522SAndroid Build Coastguard Worker         if (item.from != 0 && item.to != 0) {
88*288bf522SAndroid Build Coastguard Worker           CreateBranchSample(r, item);
89*288bf522SAndroid Build Coastguard Worker         }
90*288bf522SAndroid Build Coastguard Worker       }
91*288bf522SAndroid Build Coastguard Worker       return;
92*288bf522SAndroid Build Coastguard Worker     }
93*288bf522SAndroid Build Coastguard Worker     bool in_kernel = r.InKernel();
94*288bf522SAndroid Build Coastguard Worker     AccumulateInfoT acc_info;
95*288bf522SAndroid Build Coastguard Worker     EntryT* sample = CreateSample(r, in_kernel, &acc_info);
96*288bf522SAndroid Build Coastguard Worker     if (sample == nullptr) {
97*288bf522SAndroid Build Coastguard Worker       return;
98*288bf522SAndroid Build Coastguard Worker     }
99*288bf522SAndroid Build Coastguard Worker     if (accumulate_callchain_) {
100*288bf522SAndroid Build Coastguard Worker       std::vector<uint64_t> ips;
101*288bf522SAndroid Build Coastguard Worker       if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
102*288bf522SAndroid Build Coastguard Worker         ips.insert(ips.end(), r.callchain_data.ips, r.callchain_data.ips + r.callchain_data.ip_nr);
103*288bf522SAndroid Build Coastguard Worker       }
104*288bf522SAndroid Build Coastguard Worker       const ThreadEntry* thread = GetThreadOfSample(sample);
105*288bf522SAndroid Build Coastguard Worker       // Use stack_user_data.data.size() instead of stack_user_data.dyn_size, to
106*288bf522SAndroid Build Coastguard Worker       // make up for the missing kernel patch in N9. See b/22612370.
107*288bf522SAndroid Build Coastguard Worker       if (thread != nullptr && (r.sample_type & PERF_SAMPLE_REGS_USER) &&
108*288bf522SAndroid Build Coastguard Worker           (r.regs_user_data.reg_mask != 0) && (r.sample_type & PERF_SAMPLE_STACK_USER) &&
109*288bf522SAndroid Build Coastguard Worker           (r.GetValidStackSize() > 0)) {
110*288bf522SAndroid Build Coastguard Worker         RegSet regs(r.regs_user_data.abi, r.regs_user_data.reg_mask, r.regs_user_data.regs);
111*288bf522SAndroid Build Coastguard Worker         std::vector<uint64_t> user_ips;
112*288bf522SAndroid Build Coastguard Worker         std::vector<uint64_t> sps;
113*288bf522SAndroid Build Coastguard Worker         if (offline_unwinder_->UnwindCallChain(*thread, regs, r.stack_user_data.data,
114*288bf522SAndroid Build Coastguard Worker                                                r.GetValidStackSize(), &user_ips, &sps)) {
115*288bf522SAndroid Build Coastguard Worker           ips.push_back(PERF_CONTEXT_USER);
116*288bf522SAndroid Build Coastguard Worker           ips.insert(ips.end(), user_ips.begin(), user_ips.end());
117*288bf522SAndroid Build Coastguard Worker         }
118*288bf522SAndroid Build Coastguard Worker       }
119*288bf522SAndroid Build Coastguard Worker 
120*288bf522SAndroid Build Coastguard Worker       std::vector<EntryT*> callchain;
121*288bf522SAndroid Build Coastguard Worker       callchain.push_back(sample);
122*288bf522SAndroid Build Coastguard Worker 
123*288bf522SAndroid Build Coastguard Worker       bool first_ip = true;
124*288bf522SAndroid Build Coastguard Worker       for (auto& ip : ips) {
125*288bf522SAndroid Build Coastguard Worker         if (ip >= PERF_CONTEXT_MAX) {
126*288bf522SAndroid Build Coastguard Worker           switch (ip) {
127*288bf522SAndroid Build Coastguard Worker             case PERF_CONTEXT_KERNEL:
128*288bf522SAndroid Build Coastguard Worker               in_kernel = true;
129*288bf522SAndroid Build Coastguard Worker               break;
130*288bf522SAndroid Build Coastguard Worker             case PERF_CONTEXT_USER:
131*288bf522SAndroid Build Coastguard Worker               in_kernel = false;
132*288bf522SAndroid Build Coastguard Worker               break;
133*288bf522SAndroid Build Coastguard Worker             default:
134*288bf522SAndroid Build Coastguard Worker               LOG(DEBUG) << "Unexpected perf_context in callchain: " << ip;
135*288bf522SAndroid Build Coastguard Worker           }
136*288bf522SAndroid Build Coastguard Worker         } else {
137*288bf522SAndroid Build Coastguard Worker           if (first_ip) {
138*288bf522SAndroid Build Coastguard Worker             first_ip = false;
139*288bf522SAndroid Build Coastguard Worker             // Remove duplication with sampled ip.
140*288bf522SAndroid Build Coastguard Worker             if (ip == r.ip_data.ip) {
141*288bf522SAndroid Build Coastguard Worker               continue;
142*288bf522SAndroid Build Coastguard Worker             }
143*288bf522SAndroid Build Coastguard Worker           }
144*288bf522SAndroid Build Coastguard Worker           EntryT* callchain_sample =
145*288bf522SAndroid Build Coastguard Worker               CreateCallChainSample(thread, sample, ip, in_kernel, callchain, acc_info);
146*288bf522SAndroid Build Coastguard Worker           if (callchain_sample == nullptr) {
147*288bf522SAndroid Build Coastguard Worker             break;
148*288bf522SAndroid Build Coastguard Worker           }
149*288bf522SAndroid Build Coastguard Worker           callchain.push_back(callchain_sample);
150*288bf522SAndroid Build Coastguard Worker         }
151*288bf522SAndroid Build Coastguard Worker       }
152*288bf522SAndroid Build Coastguard Worker 
153*288bf522SAndroid Build Coastguard Worker       if (build_callchain_) {
154*288bf522SAndroid Build Coastguard Worker         std::set<EntryT*> added_set;
155*288bf522SAndroid Build Coastguard Worker         if (use_caller_as_callchain_root_) {
156*288bf522SAndroid Build Coastguard Worker           std::reverse(callchain.begin(), callchain.end());
157*288bf522SAndroid Build Coastguard Worker         }
158*288bf522SAndroid Build Coastguard Worker         EntryT* parent = nullptr;
159*288bf522SAndroid Build Coastguard Worker         while (callchain.size() >= 2) {
160*288bf522SAndroid Build Coastguard Worker           EntryT* sample = callchain[0];
161*288bf522SAndroid Build Coastguard Worker           callchain.erase(callchain.begin());
162*288bf522SAndroid Build Coastguard Worker           // Add only once for recursive calls on callchain.
163*288bf522SAndroid Build Coastguard Worker           if (added_set.find(sample) != added_set.end()) {
164*288bf522SAndroid Build Coastguard Worker             continue;
165*288bf522SAndroid Build Coastguard Worker           }
166*288bf522SAndroid Build Coastguard Worker           added_set.insert(sample);
167*288bf522SAndroid Build Coastguard Worker           InsertCallChainForSample(sample, callchain, acc_info);
168*288bf522SAndroid Build Coastguard Worker           UpdateCallChainParentInfo(sample, parent);
169*288bf522SAndroid Build Coastguard Worker           parent = sample;
170*288bf522SAndroid Build Coastguard Worker         }
171*288bf522SAndroid Build Coastguard Worker       }
172*288bf522SAndroid Build Coastguard Worker     }
173*288bf522SAndroid Build Coastguard Worker   }
174*288bf522SAndroid Build Coastguard Worker 
GetSamples()175*288bf522SAndroid Build Coastguard Worker   std::vector<EntryT*> GetSamples() const {
176*288bf522SAndroid Build Coastguard Worker     std::vector<EntryT*> result;
177*288bf522SAndroid Build Coastguard Worker     for (auto& entry : sample_set_) {
178*288bf522SAndroid Build Coastguard Worker       result.push_back(entry);
179*288bf522SAndroid Build Coastguard Worker     }
180*288bf522SAndroid Build Coastguard Worker     return result;
181*288bf522SAndroid Build Coastguard Worker   }
182*288bf522SAndroid Build Coastguard Worker 
183*288bf522SAndroid Build Coastguard Worker  protected:
184*288bf522SAndroid Build Coastguard Worker   virtual EntryT* CreateSample(const SampleRecord& r, bool in_kernel,
185*288bf522SAndroid Build Coastguard Worker                                AccumulateInfoT* acc_info) = 0;
186*288bf522SAndroid Build Coastguard Worker   virtual EntryT* CreateBranchSample(const SampleRecord& r, const BranchStackItemType& item) = 0;
187*288bf522SAndroid Build Coastguard Worker   virtual EntryT* CreateCallChainSample(const ThreadEntry* thread, const EntryT* sample,
188*288bf522SAndroid Build Coastguard Worker                                         uint64_t ip, bool in_kernel,
189*288bf522SAndroid Build Coastguard Worker                                         const std::vector<EntryT*>& callchain,
190*288bf522SAndroid Build Coastguard Worker                                         const AccumulateInfoT& acc_info) = 0;
191*288bf522SAndroid Build Coastguard Worker   virtual const ThreadEntry* GetThreadOfSample(EntryT*) = 0;
192*288bf522SAndroid Build Coastguard Worker   virtual uint64_t GetPeriodForCallChain(const AccumulateInfoT& acc_info) = 0;
FilterSample(const EntryT *)193*288bf522SAndroid Build Coastguard Worker   virtual bool FilterSample(const EntryT*) { return true; }
194*288bf522SAndroid Build Coastguard Worker 
UpdateSummary(const EntryT *)195*288bf522SAndroid Build Coastguard Worker   virtual void UpdateSummary(const EntryT*) {}
196*288bf522SAndroid Build Coastguard Worker 
197*288bf522SAndroid Build Coastguard Worker   virtual void MergeSample(EntryT* sample1, EntryT* sample2) = 0;
198*288bf522SAndroid Build Coastguard Worker 
InsertSample(std::unique_ptr<EntryT> sample)199*288bf522SAndroid Build Coastguard Worker   EntryT* InsertSample(std::unique_ptr<EntryT> sample) {
200*288bf522SAndroid Build Coastguard Worker     if (sample == nullptr) {
201*288bf522SAndroid Build Coastguard Worker       return nullptr;
202*288bf522SAndroid Build Coastguard Worker     }
203*288bf522SAndroid Build Coastguard Worker     if (!FilterSample(sample.get())) {
204*288bf522SAndroid Build Coastguard Worker       // Store in filtered_sample_set_ for use in other EntryT's callchain.
205*288bf522SAndroid Build Coastguard Worker       auto it = filtered_sample_set_.find(sample.get());
206*288bf522SAndroid Build Coastguard Worker       if (it != filtered_sample_set_.end()) {
207*288bf522SAndroid Build Coastguard Worker         return *it;
208*288bf522SAndroid Build Coastguard Worker       }
209*288bf522SAndroid Build Coastguard Worker       EntryT* result = sample.get();
210*288bf522SAndroid Build Coastguard Worker       filtered_sample_set_.insert(sample.get());
211*288bf522SAndroid Build Coastguard Worker       sample_storage_.push_back(std::move(sample));
212*288bf522SAndroid Build Coastguard Worker       return result;
213*288bf522SAndroid Build Coastguard Worker     }
214*288bf522SAndroid Build Coastguard Worker     UpdateSummary(sample.get());
215*288bf522SAndroid Build Coastguard Worker     EntryT* result;
216*288bf522SAndroid Build Coastguard Worker     auto it = sample_set_.find(sample.get());
217*288bf522SAndroid Build Coastguard Worker     if (it == sample_set_.end()) {
218*288bf522SAndroid Build Coastguard Worker       result = sample.get();
219*288bf522SAndroid Build Coastguard Worker       sample_set_.insert(sample.get());
220*288bf522SAndroid Build Coastguard Worker       sample_storage_.push_back(std::move(sample));
221*288bf522SAndroid Build Coastguard Worker     } else {
222*288bf522SAndroid Build Coastguard Worker       result = *it;
223*288bf522SAndroid Build Coastguard Worker       MergeSample(*it, sample.get());
224*288bf522SAndroid Build Coastguard Worker     }
225*288bf522SAndroid Build Coastguard Worker     return result;
226*288bf522SAndroid Build Coastguard Worker   }
227*288bf522SAndroid Build Coastguard Worker 
InsertCallChainSample(std::unique_ptr<EntryT> sample,const std::vector<EntryT * > & callchain)228*288bf522SAndroid Build Coastguard Worker   EntryT* InsertCallChainSample(std::unique_ptr<EntryT> sample,
229*288bf522SAndroid Build Coastguard Worker                                 const std::vector<EntryT*>& callchain) {
230*288bf522SAndroid Build Coastguard Worker     if (sample == nullptr) {
231*288bf522SAndroid Build Coastguard Worker       return nullptr;
232*288bf522SAndroid Build Coastguard Worker     }
233*288bf522SAndroid Build Coastguard Worker     auto it = sample_set_.find(sample.get());
234*288bf522SAndroid Build Coastguard Worker     if (it != sample_set_.end()) {
235*288bf522SAndroid Build Coastguard Worker       EntryT* sample = *it;
236*288bf522SAndroid Build Coastguard Worker       // Process only once for recursive function call.
237*288bf522SAndroid Build Coastguard Worker       if (std::find(callchain.begin(), callchain.end(), sample) != callchain.end()) {
238*288bf522SAndroid Build Coastguard Worker         return sample;
239*288bf522SAndroid Build Coastguard Worker       }
240*288bf522SAndroid Build Coastguard Worker     }
241*288bf522SAndroid Build Coastguard Worker     return InsertSample(std::move(sample));
242*288bf522SAndroid Build Coastguard Worker   }
243*288bf522SAndroid Build Coastguard Worker 
InsertCallChainForSample(EntryT * sample,const std::vector<EntryT * > & callchain,const AccumulateInfoT & acc_info)244*288bf522SAndroid Build Coastguard Worker   void InsertCallChainForSample(EntryT* sample, const std::vector<EntryT*>& callchain,
245*288bf522SAndroid Build Coastguard Worker                                 const AccumulateInfoT& acc_info) {
246*288bf522SAndroid Build Coastguard Worker     uint64_t period = GetPeriodForCallChain(acc_info);
247*288bf522SAndroid Build Coastguard Worker     sample->callchain.AddCallChain(callchain, period, [&](const EntryT* s1, const EntryT* s2) {
248*288bf522SAndroid Build Coastguard Worker       return sample_comparator_.IsSameSample(s1, s2);
249*288bf522SAndroid Build Coastguard Worker     });
250*288bf522SAndroid Build Coastguard Worker   }
251*288bf522SAndroid Build Coastguard Worker 
AddCallChainDuplicateInfo()252*288bf522SAndroid Build Coastguard Worker   void AddCallChainDuplicateInfo() {
253*288bf522SAndroid Build Coastguard Worker     if (build_callchain_) {
254*288bf522SAndroid Build Coastguard Worker       for (EntryT* sample : sample_set_) {
255*288bf522SAndroid Build Coastguard Worker         auto it = callchain_parent_map_.find(sample);
256*288bf522SAndroid Build Coastguard Worker         if (it != callchain_parent_map_.end() && !it->second.has_multiple_parents) {
257*288bf522SAndroid Build Coastguard Worker           sample->callchain.duplicated = true;
258*288bf522SAndroid Build Coastguard Worker         }
259*288bf522SAndroid Build Coastguard Worker       }
260*288bf522SAndroid Build Coastguard Worker     }
261*288bf522SAndroid Build Coastguard Worker   }
262*288bf522SAndroid Build Coastguard Worker 
263*288bf522SAndroid Build Coastguard Worker   std::set<EntryT*, SampleComparator<EntryT>> sample_set_;
264*288bf522SAndroid Build Coastguard Worker   bool accumulate_callchain_;
265*288bf522SAndroid Build Coastguard Worker 
266*288bf522SAndroid Build Coastguard Worker  private:
UpdateCallChainParentInfo(EntryT * sample,EntryT * parent)267*288bf522SAndroid Build Coastguard Worker   void UpdateCallChainParentInfo(EntryT* sample, EntryT* parent) {
268*288bf522SAndroid Build Coastguard Worker     if (parent == nullptr) {
269*288bf522SAndroid Build Coastguard Worker       return;
270*288bf522SAndroid Build Coastguard Worker     }
271*288bf522SAndroid Build Coastguard Worker     auto it = callchain_parent_map_.find(sample);
272*288bf522SAndroid Build Coastguard Worker     if (it == callchain_parent_map_.end()) {
273*288bf522SAndroid Build Coastguard Worker       CallChainParentInfo info;
274*288bf522SAndroid Build Coastguard Worker       info.parent = parent;
275*288bf522SAndroid Build Coastguard Worker       info.has_multiple_parents = false;
276*288bf522SAndroid Build Coastguard Worker       callchain_parent_map_[sample] = info;
277*288bf522SAndroid Build Coastguard Worker     } else if (it->second.parent != parent) {
278*288bf522SAndroid Build Coastguard Worker       it->second.has_multiple_parents = true;
279*288bf522SAndroid Build Coastguard Worker     }
280*288bf522SAndroid Build Coastguard Worker   }
281*288bf522SAndroid Build Coastguard Worker 
282*288bf522SAndroid Build Coastguard Worker   const SampleComparator<EntryT> sample_comparator_;
283*288bf522SAndroid Build Coastguard Worker   // If a Sample/CallChainSample is filtered out, it is stored in filtered_sample_set_,
284*288bf522SAndroid Build Coastguard Worker   // and only used in other EntryT's callchain.
285*288bf522SAndroid Build Coastguard Worker   std::set<EntryT*, SampleComparator<EntryT>> filtered_sample_set_;
286*288bf522SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<EntryT>> sample_storage_;
287*288bf522SAndroid Build Coastguard Worker 
288*288bf522SAndroid Build Coastguard Worker   struct CallChainParentInfo {
289*288bf522SAndroid Build Coastguard Worker     EntryT* parent;
290*288bf522SAndroid Build Coastguard Worker     bool has_multiple_parents;
291*288bf522SAndroid Build Coastguard Worker   };
292*288bf522SAndroid Build Coastguard Worker   std::unordered_map<EntryT*, CallChainParentInfo> callchain_parent_map_;
293*288bf522SAndroid Build Coastguard Worker 
294*288bf522SAndroid Build Coastguard Worker   bool use_branch_address_;
295*288bf522SAndroid Build Coastguard Worker   bool build_callchain_;
296*288bf522SAndroid Build Coastguard Worker   bool use_caller_as_callchain_root_;
297*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<OfflineUnwinder> offline_unwinder_;
298*288bf522SAndroid Build Coastguard Worker };
299*288bf522SAndroid Build Coastguard Worker 
300*288bf522SAndroid Build Coastguard Worker template <typename EntryT>
301*288bf522SAndroid Build Coastguard Worker class SampleTreeSorter {
302*288bf522SAndroid Build Coastguard Worker  public:
SampleTreeSorter(SampleComparator<EntryT> comparator)303*288bf522SAndroid Build Coastguard Worker   explicit SampleTreeSorter(SampleComparator<EntryT> comparator) : comparator_(comparator) {}
304*288bf522SAndroid Build Coastguard Worker 
~SampleTreeSorter()305*288bf522SAndroid Build Coastguard Worker   virtual ~SampleTreeSorter() {}
306*288bf522SAndroid Build Coastguard Worker 
Sort(std::vector<EntryT * > & v,bool sort_callchain)307*288bf522SAndroid Build Coastguard Worker   void Sort(std::vector<EntryT*>& v, bool sort_callchain) {
308*288bf522SAndroid Build Coastguard Worker     if (sort_callchain) {
309*288bf522SAndroid Build Coastguard Worker       for (auto& sample : v) {
310*288bf522SAndroid Build Coastguard Worker         SortCallChain(sample);
311*288bf522SAndroid Build Coastguard Worker       }
312*288bf522SAndroid Build Coastguard Worker     }
313*288bf522SAndroid Build Coastguard Worker     if (!comparator_.empty()) {
314*288bf522SAndroid Build Coastguard Worker       std::sort(v.begin(), v.end(),
315*288bf522SAndroid Build Coastguard Worker                 [this](const EntryT* s1, const EntryT* s2) { return comparator_(s1, s2); });
316*288bf522SAndroid Build Coastguard Worker     }
317*288bf522SAndroid Build Coastguard Worker   }
318*288bf522SAndroid Build Coastguard Worker 
319*288bf522SAndroid Build Coastguard Worker  protected:
SortCallChain(EntryT * sample)320*288bf522SAndroid Build Coastguard Worker   void SortCallChain(EntryT* sample) { sample->callchain.SortByPeriod(); }
321*288bf522SAndroid Build Coastguard Worker 
322*288bf522SAndroid Build Coastguard Worker  private:
323*288bf522SAndroid Build Coastguard Worker   SampleComparator<EntryT> comparator_;
324*288bf522SAndroid Build Coastguard Worker };
325*288bf522SAndroid Build Coastguard Worker 
326*288bf522SAndroid Build Coastguard Worker template <typename EntryT, typename InfoT>
327*288bf522SAndroid Build Coastguard Worker class SampleTreeDisplayer {
328*288bf522SAndroid Build Coastguard Worker  public:
SampleTreeDisplayer(SampleDisplayer<EntryT,InfoT> displayer)329*288bf522SAndroid Build Coastguard Worker   explicit SampleTreeDisplayer(SampleDisplayer<EntryT, InfoT> displayer) : displayer_(displayer) {}
330*288bf522SAndroid Build Coastguard Worker 
~SampleTreeDisplayer()331*288bf522SAndroid Build Coastguard Worker   virtual ~SampleTreeDisplayer() {}
332*288bf522SAndroid Build Coastguard Worker 
DisplaySamples(FILE * fp,const std::vector<EntryT * > & samples,const InfoT * info)333*288bf522SAndroid Build Coastguard Worker   void DisplaySamples(FILE* fp, const std::vector<EntryT*>& samples, const InfoT* info) {
334*288bf522SAndroid Build Coastguard Worker     displayer_.SetInfo(info);
335*288bf522SAndroid Build Coastguard Worker     for (const auto& sample : samples) {
336*288bf522SAndroid Build Coastguard Worker       displayer_.AdjustWidth(sample);
337*288bf522SAndroid Build Coastguard Worker     }
338*288bf522SAndroid Build Coastguard Worker     displayer_.PrintNames(fp);
339*288bf522SAndroid Build Coastguard Worker     for (const auto& sample : samples) {
340*288bf522SAndroid Build Coastguard Worker       displayer_.PrintSample(fp, sample);
341*288bf522SAndroid Build Coastguard Worker     }
342*288bf522SAndroid Build Coastguard Worker   }
343*288bf522SAndroid Build Coastguard Worker 
344*288bf522SAndroid Build Coastguard Worker  private:
345*288bf522SAndroid Build Coastguard Worker   SampleDisplayer<EntryT, InfoT> displayer_;
346*288bf522SAndroid Build Coastguard Worker };
347*288bf522SAndroid Build Coastguard Worker 
348*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
349*288bf522SAndroid Build Coastguard Worker 
350*288bf522SAndroid Build Coastguard Worker #endif  // SIMPLE_PERF_SAMPLE_TREE_H_
351