OSDN Git Service

am dc27fd22: am 47efd844: Merge "Simpleperf: separate ThreadTree from SampleTree."
[android-x86/system-extras.git] / simpleperf / sample_tree.cpp
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 <base/logging.h>
20
21 #include "environment.h"
22
23 SampleEntry* SampleTree::AddSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period,
24                                    bool in_kernel) {
25   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
26   const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
27   const SymbolEntry* symbol = thread_tree_->FindSymbol(map, ip);
28
29   SampleEntry value(ip, time, period, 0, 1, thread, map, symbol);
30
31   return InsertSample(value);
32 }
33
34 void SampleTree::AddBranchSample(int pid, int tid, uint64_t from_ip, uint64_t to_ip,
35                                  uint64_t branch_flags, uint64_t time, uint64_t period) {
36   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
37   const MapEntry* from_map = thread_tree_->FindMap(thread, from_ip, false);
38   if (from_map == thread_tree_->UnknownMap()) {
39     from_map = thread_tree_->FindMap(thread, from_ip, true);
40   }
41   const SymbolEntry* from_symbol = thread_tree_->FindSymbol(from_map, from_ip);
42   const MapEntry* to_map = thread_tree_->FindMap(thread, to_ip, false);
43   if (to_map == thread_tree_->UnknownMap()) {
44     to_map = thread_tree_->FindMap(thread, to_ip, true);
45   }
46   const SymbolEntry* to_symbol = thread_tree_->FindSymbol(to_map, to_ip);
47
48   SampleEntry value(to_ip, time, period, 0, 1, thread, to_map, to_symbol);
49   value.branch_from.ip = from_ip;
50   value.branch_from.map = from_map;
51   value.branch_from.symbol = from_symbol;
52   value.branch_from.flags = branch_flags;
53
54   InsertSample(value);
55 }
56
57 SampleEntry* SampleTree::AddCallChainSample(int pid, int tid, uint64_t ip, uint64_t time,
58                                             uint64_t period, bool in_kernel,
59                                             const std::vector<SampleEntry*>& callchain) {
60   const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
61   const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
62   const SymbolEntry* symbol = thread_tree_->FindSymbol(map, ip);
63
64   SampleEntry value(ip, time, 0, period, 0, thread, map, symbol);
65
66   auto it = sample_tree_.find(&value);
67   if (it != sample_tree_.end()) {
68     SampleEntry* sample = *it;
69     // Process only once for recursive function call.
70     if (std::find(callchain.begin(), callchain.end(), sample) != callchain.end()) {
71       return sample;
72     }
73   }
74   return InsertSample(value);
75 }
76
77 SampleEntry* SampleTree::InsertSample(SampleEntry& value) {
78   SampleEntry* result;
79   auto it = sample_tree_.find(&value);
80   if (it == sample_tree_.end()) {
81     result = AllocateSample(value);
82     auto pair = sample_tree_.insert(result);
83     CHECK(pair.second);
84   } else {
85     result = *it;
86     result->period += value.period;
87     result->accumulated_period += value.accumulated_period;
88     result->sample_count += value.sample_count;
89   }
90   total_samples_ += value.sample_count;
91   total_period_ += value.period;
92   return result;
93 }
94
95 SampleEntry* SampleTree::AllocateSample(SampleEntry& value) {
96   SampleEntry* sample = new SampleEntry(std::move(value));
97   sample_storage_.push_back(std::unique_ptr<SampleEntry>(sample));
98   return sample;
99 }
100
101 void SampleTree::InsertCallChainForSample(SampleEntry* sample,
102                                           const std::vector<SampleEntry*>& callchain,
103                                           uint64_t period) {
104   sample->callchain.AddCallChain(callchain, period);
105 }
106
107 void SampleTree::VisitAllSamples(std::function<void(const SampleEntry&)> callback) {
108   if (sorted_sample_tree_.size() != sample_tree_.size()) {
109     sorted_sample_tree_.clear();
110     for (auto& sample : sample_tree_) {
111       sample->callchain.SortByPeriod();
112       sorted_sample_tree_.insert(sample);
113     }
114   }
115   for (auto& sample : sorted_sample_tree_) {
116     callback(*sample);
117   }
118 }