1 /*
2  * Copyright (C) 2019 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 "src/trace_processor/heap_profile_tracker.h"
18 
19 #include "src/trace_processor/trace_processor_context.h"
20 
21 #include "perfetto/base/logging.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 
HeapProfileTracker(TraceProcessorContext * context)26 HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
27     : context_(context), empty_(context_->storage->InternString({"", 0})) {}
28 
29 HeapProfileTracker::~HeapProfileTracker() = default;
30 
AddString(ProfileIndex pidx,SourceStringId id,StringId str)31 void HeapProfileTracker::AddString(ProfileIndex pidx,
32                                    SourceStringId id,
33                                    StringId str) {
34   string_map_.emplace(std::make_pair(pidx, id), str);
35 }
36 
AddMapping(ProfileIndex pidx,SourceMappingId id,const SourceMapping & mapping)37 void HeapProfileTracker::AddMapping(ProfileIndex pidx,
38                                     SourceMappingId id,
39                                     const SourceMapping& mapping) {
40   auto opt_name_id = FindString(pidx, mapping.name_id);
41   if (!opt_name_id)
42     return;
43   const StringId name_id = opt_name_id.value();
44 
45   auto opt_build_id = FindString(pidx, mapping.build_id);
46   if (!opt_build_id)
47     return;
48   const StringId build_id = opt_build_id.value();
49 
50   TraceStorage::HeapProfileMappings::Row row{
51       build_id,
52       static_cast<int64_t>(mapping.offset),
53       static_cast<int64_t>(mapping.start),
54       static_cast<int64_t>(mapping.end),
55       static_cast<int64_t>(mapping.load_bias),
56       name_id};
57 
58   int64_t cur_row;
59   auto it = mapping_idx_.find(row);
60   if (it != mapping_idx_.end()) {
61     cur_row = it->second;
62   } else {
63     cur_row = context_->storage->mutable_heap_profile_mappings()->Insert(row);
64     mapping_idx_.emplace(row, cur_row);
65   }
66   mappings_.emplace(std::make_pair(pidx, id), cur_row);
67 }
68 
AddFrame(ProfileIndex pidx,SourceFrameId id,const SourceFrame & frame)69 void HeapProfileTracker::AddFrame(ProfileIndex pidx,
70                                   SourceFrameId id,
71                                   const SourceFrame& frame) {
72   auto opt_str_id = FindString(pidx, frame.name_id);
73   if (!opt_str_id)
74     return;
75   const StringId& str_id = opt_str_id.value();
76 
77   auto mapping_it = mappings_.find({pidx, frame.mapping_id});
78   if (mapping_it == mappings_.end()) {
79     context_->storage->IncrementStats(stats::heapprofd_invalid_mapping_id);
80     PERFETTO_DFATAL("Invalid mapping.");
81     return;
82   }
83   int64_t mapping_row = mapping_it->second;
84 
85   TraceStorage::HeapProfileFrames::Row row{str_id, mapping_row,
86                                            static_cast<int64_t>(frame.rel_pc)};
87 
88   int64_t cur_row;
89   auto it = frame_idx_.find(row);
90   if (it != frame_idx_.end()) {
91     cur_row = it->second;
92   } else {
93     cur_row = context_->storage->mutable_heap_profile_frames()->Insert(row);
94     frame_idx_.emplace(row, cur_row);
95   }
96   frames_.emplace(std::make_pair(pidx, id), cur_row);
97 }
98 
AddCallstack(ProfileIndex pidx,SourceCallstackId id,const SourceCallstack & frame_ids)99 void HeapProfileTracker::AddCallstack(ProfileIndex pidx,
100                                       SourceCallstackId id,
101                                       const SourceCallstack& frame_ids) {
102   int64_t parent_id = 0;
103   for (size_t depth = 0; depth < frame_ids.size(); ++depth) {
104     std::vector<uint64_t> frame_subset = frame_ids;
105     frame_subset.resize(depth + 1);
106     auto self_it = callstacks_from_frames_.find({pidx, frame_subset});
107     if (self_it != callstacks_from_frames_.end()) {
108       parent_id = self_it->second;
109       continue;
110     }
111 
112     uint64_t frame_id = frame_ids[depth];
113     auto it = frames_.find({pidx, frame_id});
114     if (it == frames_.end()) {
115       context_->storage->IncrementStats(stats::heapprofd_invalid_frame_id);
116       PERFETTO_DFATAL("Unknown frames.");
117       return;
118     }
119     int64_t frame_row = it->second;
120 
121     TraceStorage::HeapProfileCallsites::Row row{static_cast<int64_t>(depth),
122                                                 parent_id, frame_row};
123 
124     int64_t self_id;
125     auto callsite_it = callsite_idx_.find(row);
126     if (callsite_it != callsite_idx_.end()) {
127       self_id = callsite_it->second;
128     } else {
129       self_id =
130           context_->storage->mutable_heap_profile_callsites()->Insert(row);
131       callsite_idx_.emplace(row, self_id);
132     }
133     parent_id = self_id;
134   }
135   callstacks_.emplace(std::make_pair(pidx, id), parent_id);
136 }
137 
AddAllocation(ProfileIndex pidx,const SourceAllocation & alloc)138 void HeapProfileTracker::AddAllocation(ProfileIndex pidx,
139                                        const SourceAllocation& alloc) {
140   auto it = callstacks_.find({pidx, alloc.callstack_id});
141   if (it == callstacks_.end()) {
142     context_->storage->IncrementStats(stats::heapprofd_invalid_callstack_id);
143     PERFETTO_DFATAL("Unknown callstack %" PRIu64 " : %zu", alloc.callstack_id,
144                     callstacks_.size());
145     return;
146   }
147 
148   TraceStorage::HeapProfileAllocations::Row alloc_row{
149       static_cast<int64_t>(alloc.timestamp), static_cast<int64_t>(alloc.pid),
150       static_cast<int64_t>(it->second), static_cast<int64_t>(alloc.alloc_count),
151       static_cast<int64_t>(alloc.self_allocated)};
152 
153   TraceStorage::HeapProfileAllocations::Row free_row{
154       static_cast<int64_t>(alloc.timestamp), static_cast<int64_t>(alloc.pid),
155       static_cast<int64_t>(it->second), -static_cast<int64_t>(alloc.free_count),
156       -static_cast<int64_t>(alloc.self_freed)};
157 
158   context_->storage->mutable_heap_profile_allocations()->Insert(alloc_row);
159   context_->storage->mutable_heap_profile_allocations()->Insert(free_row);
160 }
161 
StoreAllocation(ProfileIndex pidx,SourceAllocation alloc)162 void HeapProfileTracker::StoreAllocation(ProfileIndex pidx,
163                                          SourceAllocation alloc) {
164   pending_allocs_.emplace_back(pidx, std::move(alloc));
165 }
166 
ApplyAllAllocations()167 void HeapProfileTracker::ApplyAllAllocations() {
168   for (const auto& p : pending_allocs_)
169     AddAllocation(p.first, p.second);
170 }
171 
GetDatabaseFrameIdForTesting(ProfileIndex pidx,SourceFrameId frame_id)172 int64_t HeapProfileTracker::GetDatabaseFrameIdForTesting(
173     ProfileIndex pidx,
174     SourceFrameId frame_id) {
175   auto it = frames_.find({pidx, frame_id});
176   if (it == frames_.end()) {
177     PERFETTO_DFATAL("Invalid frame.");
178     return -1;
179   }
180   return it->second;
181 }
182 
FindString(ProfileIndex pidx,SourceStringId id)183 base::Optional<StringId> HeapProfileTracker::FindString(ProfileIndex pidx,
184                                                         SourceStringId id) {
185   base::Optional<StringId> res;
186   if (id == 0) {
187     res = empty_;
188     return res;
189   }
190 
191   auto it = string_map_.find({pidx, id});
192   if (it == string_map_.end()) {
193     context_->storage->IncrementStats(stats::heapprofd_invalid_string_id);
194     PERFETTO_DFATAL("Invalid string.");
195     return res;
196   }
197   res = it->second;
198   return res;
199 }
200 
201 }  // namespace trace_processor
202 }  // namespace perfetto
203