/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "sample_tree.h" #include #include "environment.h" void SampleTree::SetFilters(const std::unordered_set& pid_filter, const std::unordered_set& tid_filter, const std::unordered_set& comm_filter, const std::unordered_set& dso_filter) { pid_filter_ = pid_filter; tid_filter_ = tid_filter; comm_filter_ = comm_filter; dso_filter_ = dso_filter; } SampleEntry* SampleTree::AddSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period, bool in_kernel) { const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid); const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel); const Symbol* symbol = thread_tree_->FindSymbol(map, ip); SampleEntry value(ip, time, period, 0, 1, thread, map, symbol); if (IsFilteredOut(value)) { return nullptr; } return InsertSample(value); } void SampleTree::AddBranchSample(int pid, int tid, uint64_t from_ip, uint64_t to_ip, uint64_t branch_flags, uint64_t time, uint64_t period) { const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid); const MapEntry* from_map = thread_tree_->FindMap(thread, from_ip, false); if (from_map == thread_tree_->UnknownMap()) { from_map = thread_tree_->FindMap(thread, from_ip, true); } const Symbol* from_symbol = thread_tree_->FindSymbol(from_map, from_ip); const MapEntry* to_map = thread_tree_->FindMap(thread, to_ip, false); if (to_map == thread_tree_->UnknownMap()) { to_map = thread_tree_->FindMap(thread, to_ip, true); } const Symbol* to_symbol = thread_tree_->FindSymbol(to_map, to_ip); SampleEntry value(to_ip, time, period, 0, 1, thread, to_map, to_symbol); value.branch_from.ip = from_ip; value.branch_from.map = from_map; value.branch_from.symbol = from_symbol; value.branch_from.flags = branch_flags; if (IsFilteredOut(value)) { return; } InsertSample(value); } SampleEntry* SampleTree::AddCallChainSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period, bool in_kernel, const std::vector& callchain) { const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid); const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel); const Symbol* symbol = thread_tree_->FindSymbol(map, ip); SampleEntry value(ip, time, 0, period, 0, thread, map, symbol); if (IsFilteredOut(value)) { // Store in callchain_sample_tree_ for use in other SampleEntry's callchain. auto it = callchain_sample_tree_.find(&value); if (it != callchain_sample_tree_.end()) { return *it; } SampleEntry* sample = AllocateSample(value); callchain_sample_tree_.insert(sample); return sample; } auto it = sample_tree_.find(&value); if (it != sample_tree_.end()) { SampleEntry* sample = *it; // Process only once for recursive function call. if (std::find(callchain.begin(), callchain.end(), sample) != callchain.end()) { return sample; } } return InsertSample(value); } bool SampleTree::IsFilteredOut(const SampleEntry& value) { if (!pid_filter_.empty() && pid_filter_.find(value.thread->pid) == pid_filter_.end()) { return true; } if (!tid_filter_.empty() && tid_filter_.find(value.thread->tid) == tid_filter_.end()) { return true; } if (!comm_filter_.empty() && comm_filter_.find(value.thread_comm) == comm_filter_.end()) { return true; } if (!dso_filter_.empty() && dso_filter_.find(value.map->dso->Path()) == dso_filter_.end()) { return true; } return false; } SampleEntry* SampleTree::InsertSample(SampleEntry& value) { SampleEntry* result; auto it = sample_tree_.find(&value); if (it == sample_tree_.end()) { result = AllocateSample(value); auto pair = sample_tree_.insert(result); CHECK(pair.second); } else { result = *it; result->period += value.period; result->accumulated_period += value.accumulated_period; result->sample_count += value.sample_count; } total_samples_ += value.sample_count; total_period_ += value.period; return result; } SampleEntry* SampleTree::AllocateSample(SampleEntry& value) { SampleEntry* sample = new SampleEntry(std::move(value)); sample_storage_.push_back(std::unique_ptr(sample)); return sample; } void SampleTree::InsertCallChainForSample(SampleEntry* sample, const std::vector& callchain, uint64_t period) { sample->callchain.AddCallChain(callchain, period); } void SampleTree::VisitAllSamples(std::function callback) { if (sorted_sample_tree_.size() != sample_tree_.size()) { sorted_sample_tree_.clear(); for (auto& sample : sample_tree_) { sample->callchain.SortByPeriod(); sorted_sample_tree_.insert(sample); } } for (auto& sample : sorted_sample_tree_) { callback(*sample); } }