• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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/importers/common/jit_cache.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 #include <optional>
24 #include <string>
25 #include <utility>
26 
27 #include "perfetto/base/logging.h"
28 #include "perfetto/ext/base/base64.h"
29 #include "perfetto/ext/base/string_utils.h"
30 #include "perfetto/ext/base/string_view.h"
31 #include "perfetto/trace_processor/trace_blob_view.h"
32 #include "src/trace_processor/importers/common/address_range.h"
33 #include "src/trace_processor/importers/common/mapping_tracker.h"
34 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
35 #include "src/trace_processor/storage/stats.h"
36 #include "src/trace_processor/storage/trace_storage.h"
37 #include "src/trace_processor/tables/jit_tables_py.h"
38 #include "src/trace_processor/tables/metadata_tables_py.h"
39 #include "src/trace_processor/tables/profiler_tables_py.h"
40 #include "src/trace_processor/types/trace_processor_context.h"
41 
42 namespace perfetto {
43 namespace trace_processor {
44 
InternFrame(TraceProcessorContext * context,FrameKey frame_key)45 std::pair<FrameId, bool> JitCache::JittedFunction::InternFrame(
46     TraceProcessorContext* context,
47     FrameKey frame_key) {
48   if (FrameId* id = interned_frames_.Find(frame_key); id) {
49     return {*id, false};
50   }
51 
52   FrameId frame_id =
53       context->storage->mutable_stack_profile_frame_table()
54           ->Insert({context->storage->jit_code_table()
55                         .FindById(jit_code_id_)
56                         ->function_name(),
57                     frame_key.mapping_id,
58                     static_cast<int64_t>(frame_key.rel_pc), symbol_set_id_})
59           .id;
60   interned_frames_.Insert(frame_key, frame_id);
61   context->stack_profile_tracker->OnFrameCreated(frame_id);
62 
63   context->storage->mutable_jit_frame_table()->Insert({jit_code_id_, frame_id});
64 
65   return {frame_id, true};
66 }
67 
LoadCode(int64_t timestamp,UniqueTid utid,AddressRange code_range,StringId function_name,std::optional<SourceLocation> source_location,TraceBlobView native_code)68 tables::JitCodeTable::Id JitCache::LoadCode(
69     int64_t timestamp,
70     UniqueTid utid,
71     AddressRange code_range,
72     StringId function_name,
73     std::optional<SourceLocation> source_location,
74     TraceBlobView native_code) {
75   PERFETTO_CHECK(range_.Contains(code_range));
76   PERFETTO_CHECK(context_->storage->thread_table()
77                      .FindById(tables::ThreadTable::Id(utid))
78                      ->upid() == upid_);
79 
80   PERFETTO_CHECK(native_code.size() == 0 ||
81                  native_code.size() == code_range.size());
82 
83   std::optional<uint32_t> symbol_set_id;
84   if (source_location.has_value()) {
85     // TODO(carlscab): Remove duplication via new SymbolTracker class
86     symbol_set_id = context_->storage->symbol_table().row_count();
87     context_->storage->mutable_symbol_table()->Insert(
88         {*symbol_set_id, function_name, source_location->file_name,
89          source_location->line_number});
90   }
91 
92   auto* jit_code_table = context_->storage->mutable_jit_code_table();
93   const auto jit_code_id =
94       jit_code_table
95           ->Insert({timestamp, std::nullopt, utid,
96                     static_cast<int64_t>(code_range.start()),
97                     static_cast<int64_t>(code_range.size()), function_name,
98                     Base64Encode(native_code)})
99           .id;
100 
101   functions_.DeleteOverlapsAndEmplace(
102       [&](std::pair<const AddressRange, JittedFunction>& entry) {
103         jit_code_table->FindById(entry.second.jit_code_id())
104             ->set_estimated_delete_ts(timestamp);
105       },
106       code_range, jit_code_id, symbol_set_id);
107 
108   return jit_code_id;
109 }
110 
MoveCode(int64_t timestamp,UniqueTid,uint64_t from_code_start,uint64_t to_code_start)111 tables::JitCodeTable::Id JitCache::MoveCode(int64_t timestamp,
112                                             UniqueTid,
113                                             uint64_t from_code_start,
114                                             uint64_t to_code_start) {
115   auto* jit_code_table = context_->storage->mutable_jit_code_table();
116 
117   auto it = functions_.Find(from_code_start);
118   AddressRange old_code_range = it->first;
119   JittedFunction func = std::move(it->second);
120   functions_.erase(it);
121 
122   auto code_id = func.jit_code_id();
123   AddressRange new_code_range(to_code_start, old_code_range.size());
124 
125   functions_.DeleteOverlapsAndEmplace(
126       [&](std::pair<const AddressRange, JittedFunction>& entry) {
127         jit_code_table->FindById(entry.second.jit_code_id())
128             ->set_estimated_delete_ts(timestamp);
129       },
130       new_code_range, std::move(func));
131 
132   return code_id;
133 }
134 
InternFrame(VirtualMemoryMapping * mapping,uint64_t rel_pc,base::StringView function_name)135 std::pair<FrameId, bool> JitCache::InternFrame(VirtualMemoryMapping* mapping,
136                                                uint64_t rel_pc,
137                                                base::StringView function_name) {
138   FrameKey key{mapping->mapping_id(), rel_pc};
139 
140   if (auto it = functions_.Find(mapping->ToAddress(rel_pc));
141       it != functions_.end()) {
142     return it->second.InternFrame(context_, key);
143   }
144 
145   if (FrameId* id = unknown_frames_.Find(key); id) {
146     return {*id, false};
147   }
148 
149   context_->storage->IncrementStats(stats::jit_unknown_frame);
150 
151   FrameId id =
152       context_->storage->mutable_stack_profile_frame_table()
153           ->Insert({context_->storage->InternString(
154                         function_name.empty()
155                             ? base::StringView(
156                                   "[+" + base::Uint64ToHexString(rel_pc) + "]")
157                             : function_name),
158                     key.mapping_id, static_cast<int64_t>(rel_pc)})
159           .id;
160   unknown_frames_.Insert(key, id);
161   return {id, true};
162 }
163 
CreateMapping()164 UserMemoryMapping& JitCache::CreateMapping() {
165   CreateMappingParams params;
166   params.memory_range = range_;
167   params.name = "[jit: " + name_ + "]";
168   return context_->mapping_tracker->CreateUserMemoryMapping(upid_,
169                                                             std::move(params));
170 }
171 
Base64Encode(const TraceBlobView & data)172 StringId JitCache::Base64Encode(const TraceBlobView& data) {
173   return context_->storage->InternString(
174       base::StringView(base::Base64Encode(data.data(), data.size())));
175 }
176 
177 }  // namespace trace_processor
178 }  // namespace perfetto
179