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