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
InternFrame(VirtualMemoryMapping * mapping,uint64_t rel_pc,base::StringView function_name)111 std::pair<FrameId, bool> JitCache::InternFrame(VirtualMemoryMapping* mapping,
112 uint64_t rel_pc,
113 base::StringView function_name) {
114 FrameKey key{mapping->mapping_id(), rel_pc};
115
116 if (auto it = functions_.Find(mapping->ToAddress(rel_pc));
117 it != functions_.end()) {
118 return it->second.InternFrame(context_, key);
119 }
120
121 if (FrameId* id = unknown_frames_.Find(key); id) {
122 return {*id, false};
123 }
124
125 context_->storage->IncrementStats(stats::jit_unknown_frame);
126
127 FrameId id =
128 context_->storage->mutable_stack_profile_frame_table()
129 ->Insert({context_->storage->InternString(
130 function_name.empty()
131 ? base::StringView(
132 "[+" + base::Uint64ToHexString(rel_pc) + "]")
133 : function_name),
134 key.mapping_id, static_cast<int64_t>(rel_pc)})
135 .id;
136 unknown_frames_.Insert(key, id);
137 return {id, true};
138 }
139
CreateMapping()140 UserMemoryMapping& JitCache::CreateMapping() {
141 CreateMappingParams params;
142 params.memory_range = range_;
143 params.name = "[jit: " + name_ + "]";
144 return context_->mapping_tracker->CreateUserMemoryMapping(upid_,
145 std::move(params));
146 }
147
Base64Encode(const TraceBlobView & data)148 StringId JitCache::Base64Encode(const TraceBlobView& data) {
149 return context_->storage->InternString(
150 base::StringView(base::Base64Encode(data.data(), data.size())));
151 }
152
153 } // namespace trace_processor
154 } // namespace perfetto
155