Home | History | Annotate | Download | only in simpleperf
      1 /*
      2  * Copyright (C) 2015 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 #include "sample_tree.h"
     18 
     19 #include <android-base/logging.h>
     20 
     21 #include "environment.h"
     22 
     23 void SampleTree::SetFilters(const std::unordered_set<int>& pid_filter,
     24                             const std::unordered_set<int>& tid_filter,
     25                             const std::unordered_set<std::string>& comm_filter,
     26                             const std::unordered_set<std::string>& dso_filter) {
     27   pid_filter_ = pid_filter;
     28   tid_filter_ = tid_filter;
     29   comm_filter_ = comm_filter;
     30   dso_filter_ = dso_filter;
     31 }
     32 
     33 SampleEntry* SampleTree::AddSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period,
     34                                    bool in_kernel) {
     35   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
     36   const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
     37   const Symbol* symbol = thread_tree_->FindSymbol(map, ip);
     38 
     39   SampleEntry value(ip, time, period, 0, 1, thread, map, symbol);
     40 
     41   if (IsFilteredOut(value)) {
     42     return nullptr;
     43   }
     44   return InsertSample(value);
     45 }
     46 
     47 void SampleTree::AddBranchSample(int pid, int tid, uint64_t from_ip, uint64_t to_ip,
     48                                  uint64_t branch_flags, uint64_t time, uint64_t period) {
     49   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
     50   const MapEntry* from_map = thread_tree_->FindMap(thread, from_ip, false);
     51   if (from_map == thread_tree_->UnknownMap()) {
     52     from_map = thread_tree_->FindMap(thread, from_ip, true);
     53   }
     54   const Symbol* from_symbol = thread_tree_->FindSymbol(from_map, from_ip);
     55   const MapEntry* to_map = thread_tree_->FindMap(thread, to_ip, false);
     56   if (to_map == thread_tree_->UnknownMap()) {
     57     to_map = thread_tree_->FindMap(thread, to_ip, true);
     58   }
     59   const Symbol* to_symbol = thread_tree_->FindSymbol(to_map, to_ip);
     60 
     61   SampleEntry value(to_ip, time, period, 0, 1, thread, to_map, to_symbol);
     62   value.branch_from.ip = from_ip;
     63   value.branch_from.map = from_map;
     64   value.branch_from.symbol = from_symbol;
     65   value.branch_from.flags = branch_flags;
     66 
     67   if (IsFilteredOut(value)) {
     68     return;
     69   }
     70   InsertSample(value);
     71 }
     72 
     73 SampleEntry* SampleTree::AddCallChainSample(int pid, int tid, uint64_t ip, uint64_t time,
     74                                             uint64_t period, bool in_kernel,
     75                                             const std::vector<SampleEntry*>& callchain) {
     76   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
     77   const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
     78   const Symbol* symbol = thread_tree_->FindSymbol(map, ip);
     79 
     80   SampleEntry value(ip, time, 0, period, 0, thread, map, symbol);
     81 
     82   if (IsFilteredOut(value)) {
     83     // Store in callchain_sample_tree_ for use in other SampleEntry's callchain.
     84     auto it = callchain_sample_tree_.find(&value);
     85     if (it != callchain_sample_tree_.end()) {
     86       return *it;
     87     }
     88     SampleEntry* sample = AllocateSample(value);
     89     callchain_sample_tree_.insert(sample);
     90     return sample;
     91   }
     92 
     93   auto it = sample_tree_.find(&value);
     94   if (it != sample_tree_.end()) {
     95     SampleEntry* sample = *it;
     96     // Process only once for recursive function call.
     97     if (std::find(callchain.begin(), callchain.end(), sample) != callchain.end()) {
     98       return sample;
     99     }
    100   }
    101   return InsertSample(value);
    102 }
    103 
    104 bool SampleTree::IsFilteredOut(const SampleEntry& value) {
    105   if (!pid_filter_.empty() && pid_filter_.find(value.thread->pid) == pid_filter_.end()) {
    106     return true;
    107   }
    108   if (!tid_filter_.empty() && tid_filter_.find(value.thread->tid) == tid_filter_.end()) {
    109     return true;
    110   }
    111   if (!comm_filter_.empty() && comm_filter_.find(value.thread_comm) == comm_filter_.end()) {
    112     return true;
    113   }
    114   if (!dso_filter_.empty() && dso_filter_.find(value.map->dso->Path()) == dso_filter_.end()) {
    115     return true;
    116   }
    117   return false;
    118 }
    119 
    120 SampleEntry* SampleTree::InsertSample(SampleEntry& value) {
    121   SampleEntry* result;
    122   auto it = sample_tree_.find(&value);
    123   if (it == sample_tree_.end()) {
    124     result = AllocateSample(value);
    125     auto pair = sample_tree_.insert(result);
    126     CHECK(pair.second);
    127   } else {
    128     result = *it;
    129     result->period += value.period;
    130     result->accumulated_period += value.accumulated_period;
    131     result->sample_count += value.sample_count;
    132   }
    133   total_samples_ += value.sample_count;
    134   total_period_ += value.period;
    135   return result;
    136 }
    137 
    138 SampleEntry* SampleTree::AllocateSample(SampleEntry& value) {
    139   SampleEntry* sample = new SampleEntry(std::move(value));
    140   sample_storage_.push_back(std::unique_ptr<SampleEntry>(sample));
    141   return sample;
    142 }
    143 
    144 void SampleTree::InsertCallChainForSample(SampleEntry* sample,
    145                                           const std::vector<SampleEntry*>& callchain,
    146                                           uint64_t period) {
    147   sample->callchain.AddCallChain(callchain, period);
    148 }
    149 
    150 void SampleTree::VisitAllSamples(std::function<void(const SampleEntry&)> callback) {
    151   if (sorted_sample_tree_.size() != sample_tree_.size()) {
    152     sorted_sample_tree_.clear();
    153     for (auto& sample : sample_tree_) {
    154       sample->callchain.SortByPeriod();
    155       sorted_sample_tree_.insert(sample);
    156     }
    157   }
    158   for (auto& sample : sorted_sample_tree_) {
    159     callback(*sample);
    160   }
    161 }
    162