2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "sample_tree.h"
19 #include <base/logging.h>
21 #include "environment.h"
23 SampleEntry* SampleTree::AddSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period,
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);
29 SampleEntry value(ip, time, period, 0, 1, thread, map, symbol);
31 return InsertSample(value);
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);
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);
46 const SymbolEntry* to_symbol = thread_tree_->FindSymbol(to_map, to_ip);
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;
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);
64 SampleEntry value(ip, time, 0, period, 0, thread, map, symbol);
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()) {
74 return InsertSample(value);
77 SampleEntry* SampleTree::InsertSample(SampleEntry& value) {
79 auto it = sample_tree_.find(&value);
80 if (it == sample_tree_.end()) {
81 result = AllocateSample(value);
82 auto pair = sample_tree_.insert(result);
86 result->period += value.period;
87 result->accumulated_period += value.accumulated_period;
88 result->sample_count += value.sample_count;
90 total_samples_ += value.sample_count;
91 total_period_ += value.period;
95 SampleEntry* SampleTree::AllocateSample(SampleEntry& value) {
96 SampleEntry* sample = new SampleEntry(std::move(value));
97 sample_storage_.push_back(std::unique_ptr<SampleEntry>(sample));
101 void SampleTree::InsertCallChainForSample(SampleEntry* sample,
102 const std::vector<SampleEntry*>& callchain,
104 sample->callchain.AddCallChain(callchain, period);
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);
115 for (auto& sample : sorted_sample_tree_) {