• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetFilters(const std::unordered_set<int> & pid_filter,const std::unordered_set<int> & tid_filter,const std::unordered_set<std::string> & comm_filter,const std::unordered_set<std::string> & dso_filter)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 
AddSample(int pid,int tid,uint64_t ip,uint64_t time,uint64_t period,bool in_kernel)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 
AddBranchSample(int pid,int tid,uint64_t from_ip,uint64_t to_ip,uint64_t branch_flags,uint64_t time,uint64_t period)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 
AddCallChainSample(int pid,int tid,uint64_t ip,uint64_t time,uint64_t period,bool in_kernel,const std::vector<SampleEntry * > & callchain)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 
IsFilteredOut(const SampleEntry & value)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 
InsertSample(SampleEntry & value)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 
AllocateSample(SampleEntry & value)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 
InsertCallChainForSample(SampleEntry * sample,const std::vector<SampleEntry * > & callchain,uint64_t period)144 void SampleTree::InsertCallChainForSample(SampleEntry* sample,
145                                           const std::vector<SampleEntry*>& callchain,
146                                           uint64_t period) {
147   sample->callchain.AddCallChain(callchain, period);
148 }
149 
VisitAllSamples(std::function<void (const SampleEntry &)> callback)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