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