xref: /aosp_15_r20/external/perfetto/src/profiling/common/callstack_trie.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/callstack_trie.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
20*6dbdd20aSAndroid Build Coastguard Worker 
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_splitter.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/interner.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/unwind_support.h"
24*6dbdd20aSAndroid Build Coastguard Worker 
25*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
26*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
27*6dbdd20aSAndroid Build Coastguard Worker 
GetOrCreateChild(Node * self,const Interned<Frame> & loc)28*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie::Node* GlobalCallstackTrie::GetOrCreateChild(
29*6dbdd20aSAndroid Build Coastguard Worker     Node* self,
30*6dbdd20aSAndroid Build Coastguard Worker     const Interned<Frame>& loc) {
31*6dbdd20aSAndroid Build Coastguard Worker   Node* child = self->GetChild(loc);
32*6dbdd20aSAndroid Build Coastguard Worker   if (!child)
33*6dbdd20aSAndroid Build Coastguard Worker     child = self->AddChild(loc, ++next_callstack_id_, self);
34*6dbdd20aSAndroid Build Coastguard Worker   return child;
35*6dbdd20aSAndroid Build Coastguard Worker }
36*6dbdd20aSAndroid Build Coastguard Worker 
BuildInverseCallstack(const Node * node) const37*6dbdd20aSAndroid Build Coastguard Worker std::vector<Interned<Frame>> GlobalCallstackTrie::BuildInverseCallstack(
38*6dbdd20aSAndroid Build Coastguard Worker     const Node* node) const {
39*6dbdd20aSAndroid Build Coastguard Worker   std::vector<Interned<Frame>> res;
40*6dbdd20aSAndroid Build Coastguard Worker   while (node != &root_) {
41*6dbdd20aSAndroid Build Coastguard Worker     res.emplace_back(node->location_);
42*6dbdd20aSAndroid Build Coastguard Worker     node = node->parent_;
43*6dbdd20aSAndroid Build Coastguard Worker   }
44*6dbdd20aSAndroid Build Coastguard Worker   return res;
45*6dbdd20aSAndroid Build Coastguard Worker }
46*6dbdd20aSAndroid Build Coastguard Worker 
CreateCallsite(const std::vector<unwindstack::FrameData> & callstack,const std::vector<std::string> & build_ids)47*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie::Node* GlobalCallstackTrie::CreateCallsite(
48*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<unwindstack::FrameData>& callstack,
49*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<std::string>& build_ids) {
50*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(callstack.size() == build_ids.size());
51*6dbdd20aSAndroid Build Coastguard Worker   Node* node = &root_;
52*6dbdd20aSAndroid Build Coastguard Worker   // libunwindstack gives the frames top-first, but we want to bookkeep and
53*6dbdd20aSAndroid Build Coastguard Worker   // emit as bottom first.
54*6dbdd20aSAndroid Build Coastguard Worker   auto callstack_it = callstack.crbegin();
55*6dbdd20aSAndroid Build Coastguard Worker   auto build_id_it = build_ids.crbegin();
56*6dbdd20aSAndroid Build Coastguard Worker   for (; callstack_it != callstack.crend() && build_id_it != build_ids.crend();
57*6dbdd20aSAndroid Build Coastguard Worker        ++callstack_it, ++build_id_it) {
58*6dbdd20aSAndroid Build Coastguard Worker     const unwindstack::FrameData& loc = *callstack_it;
59*6dbdd20aSAndroid Build Coastguard Worker     const std::string& build_id = *build_id_it;
60*6dbdd20aSAndroid Build Coastguard Worker     node = GetOrCreateChild(node, InternCodeLocation(loc, build_id));
61*6dbdd20aSAndroid Build Coastguard Worker   }
62*6dbdd20aSAndroid Build Coastguard Worker   return node;
63*6dbdd20aSAndroid Build Coastguard Worker }
64*6dbdd20aSAndroid Build Coastguard Worker 
CreateCallsite(const std::vector<Interned<Frame>> & callstack)65*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie::Node* GlobalCallstackTrie::CreateCallsite(
66*6dbdd20aSAndroid Build Coastguard Worker     const std::vector<Interned<Frame>>& callstack) {
67*6dbdd20aSAndroid Build Coastguard Worker   Node* node = &root_;
68*6dbdd20aSAndroid Build Coastguard Worker   // libunwindstack gives the frames top-first, but we want to bookkeep and
69*6dbdd20aSAndroid Build Coastguard Worker   // emit as bottom first.
70*6dbdd20aSAndroid Build Coastguard Worker   for (auto it = callstack.crbegin(); it != callstack.crend(); ++it) {
71*6dbdd20aSAndroid Build Coastguard Worker     const Interned<Frame>& loc = *it;
72*6dbdd20aSAndroid Build Coastguard Worker     node = GetOrCreateChild(node, loc);
73*6dbdd20aSAndroid Build Coastguard Worker   }
74*6dbdd20aSAndroid Build Coastguard Worker   return node;
75*6dbdd20aSAndroid Build Coastguard Worker }
76*6dbdd20aSAndroid Build Coastguard Worker 
IncrementNode(Node * node)77*6dbdd20aSAndroid Build Coastguard Worker void GlobalCallstackTrie::IncrementNode(Node* node) {
78*6dbdd20aSAndroid Build Coastguard Worker   while (node != nullptr) {
79*6dbdd20aSAndroid Build Coastguard Worker     node->ref_count_ += 1;
80*6dbdd20aSAndroid Build Coastguard Worker     node = node->parent_;
81*6dbdd20aSAndroid Build Coastguard Worker   }
82*6dbdd20aSAndroid Build Coastguard Worker }
83*6dbdd20aSAndroid Build Coastguard Worker 
DecrementNode(Node * node)84*6dbdd20aSAndroid Build Coastguard Worker void GlobalCallstackTrie::DecrementNode(Node* node) {
85*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(node->ref_count_ >= 1);
86*6dbdd20aSAndroid Build Coastguard Worker 
87*6dbdd20aSAndroid Build Coastguard Worker   bool delete_prev = false;
88*6dbdd20aSAndroid Build Coastguard Worker   Node* prev = nullptr;
89*6dbdd20aSAndroid Build Coastguard Worker   while (node != nullptr) {
90*6dbdd20aSAndroid Build Coastguard Worker     if (delete_prev)
91*6dbdd20aSAndroid Build Coastguard Worker       node->RemoveChild(prev);
92*6dbdd20aSAndroid Build Coastguard Worker     node->ref_count_ -= 1;
93*6dbdd20aSAndroid Build Coastguard Worker     delete_prev = node->ref_count_ == 0;
94*6dbdd20aSAndroid Build Coastguard Worker     prev = node;
95*6dbdd20aSAndroid Build Coastguard Worker     node = node->parent_;
96*6dbdd20aSAndroid Build Coastguard Worker   }
97*6dbdd20aSAndroid Build Coastguard Worker }
98*6dbdd20aSAndroid Build Coastguard Worker 
InternCodeLocation(const unwindstack::FrameData & loc,const std::string & build_id)99*6dbdd20aSAndroid Build Coastguard Worker Interned<Frame> GlobalCallstackTrie::InternCodeLocation(
100*6dbdd20aSAndroid Build Coastguard Worker     const unwindstack::FrameData& loc,
101*6dbdd20aSAndroid Build Coastguard Worker     const std::string& build_id) {
102*6dbdd20aSAndroid Build Coastguard Worker   Mapping map(string_interner_.Intern(build_id));
103*6dbdd20aSAndroid Build Coastguard Worker   if (loc.map_info != nullptr) {
104*6dbdd20aSAndroid Build Coastguard Worker     map.exact_offset = loc.map_info->offset();
105*6dbdd20aSAndroid Build Coastguard Worker     map.start_offset = loc.map_info->elf_start_offset();
106*6dbdd20aSAndroid Build Coastguard Worker     map.start = loc.map_info->start();
107*6dbdd20aSAndroid Build Coastguard Worker     map.end = loc.map_info->end();
108*6dbdd20aSAndroid Build Coastguard Worker     map.load_bias = loc.map_info->GetLoadBias();
109*6dbdd20aSAndroid Build Coastguard Worker     base::StringSplitter sp(loc.map_info->GetFullName(), '/');
110*6dbdd20aSAndroid Build Coastguard Worker     while (sp.Next())
111*6dbdd20aSAndroid Build Coastguard Worker       map.path_components.emplace_back(string_interner_.Intern(sp.cur_token()));
112*6dbdd20aSAndroid Build Coastguard Worker   }
113*6dbdd20aSAndroid Build Coastguard Worker 
114*6dbdd20aSAndroid Build Coastguard Worker   Frame frame(mapping_interner_.Intern(std::move(map)),
115*6dbdd20aSAndroid Build Coastguard Worker               string_interner_.Intern(loc.function_name), loc.rel_pc);
116*6dbdd20aSAndroid Build Coastguard Worker 
117*6dbdd20aSAndroid Build Coastguard Worker   return frame_interner_.Intern(frame);
118*6dbdd20aSAndroid Build Coastguard Worker }
119*6dbdd20aSAndroid Build Coastguard Worker 
MakeRootFrame()120*6dbdd20aSAndroid Build Coastguard Worker Interned<Frame> GlobalCallstackTrie::MakeRootFrame() {
121*6dbdd20aSAndroid Build Coastguard Worker   Mapping map(string_interner_.Intern(""));
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker   Frame frame(mapping_interner_.Intern(std::move(map)),
124*6dbdd20aSAndroid Build Coastguard Worker               string_interner_.Intern(""), 0);
125*6dbdd20aSAndroid Build Coastguard Worker 
126*6dbdd20aSAndroid Build Coastguard Worker   return frame_interner_.Intern(frame);
127*6dbdd20aSAndroid Build Coastguard Worker }
128*6dbdd20aSAndroid Build Coastguard Worker 
AddChild(const Interned<Frame> & loc,uint64_t callstack_id,Node * parent)129*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie::Node* GlobalCallstackTrie::Node::AddChild(
130*6dbdd20aSAndroid Build Coastguard Worker     const Interned<Frame>& loc,
131*6dbdd20aSAndroid Build Coastguard Worker     uint64_t callstack_id,
132*6dbdd20aSAndroid Build Coastguard Worker     Node* parent) {
133*6dbdd20aSAndroid Build Coastguard Worker   auto it = children_.emplace(loc, callstack_id, parent);
134*6dbdd20aSAndroid Build Coastguard Worker   return const_cast<Node*>(&(*it.first));
135*6dbdd20aSAndroid Build Coastguard Worker }
RemoveChild(Node * node)136*6dbdd20aSAndroid Build Coastguard Worker void GlobalCallstackTrie::Node::RemoveChild(Node* node) {
137*6dbdd20aSAndroid Build Coastguard Worker   children_.erase(*node);
138*6dbdd20aSAndroid Build Coastguard Worker }
139*6dbdd20aSAndroid Build Coastguard Worker 
GetChild(const Interned<Frame> & loc)140*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie::Node* GlobalCallstackTrie::Node::GetChild(
141*6dbdd20aSAndroid Build Coastguard Worker     const Interned<Frame>& loc) {
142*6dbdd20aSAndroid Build Coastguard Worker   // This will be nicer with C++14 transparent comparators.
143*6dbdd20aSAndroid Build Coastguard Worker   // Then we will be able to look up by just the key using a sutiable
144*6dbdd20aSAndroid Build Coastguard Worker   // comparator.
145*6dbdd20aSAndroid Build Coastguard Worker   //
146*6dbdd20aSAndroid Build Coastguard Worker   // For now we need to allow to construct Node from the key.
147*6dbdd20aSAndroid Build Coastguard Worker   Node node(loc);
148*6dbdd20aSAndroid Build Coastguard Worker   auto it = children_.find(node);
149*6dbdd20aSAndroid Build Coastguard Worker   if (it == children_.end())
150*6dbdd20aSAndroid Build Coastguard Worker     return nullptr;
151*6dbdd20aSAndroid Build Coastguard Worker   return const_cast<Node*>(&(*it));
152*6dbdd20aSAndroid Build Coastguard Worker }
153*6dbdd20aSAndroid Build Coastguard Worker 
154*6dbdd20aSAndroid Build Coastguard Worker }  // namespace profiling
155*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
156