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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_JIT_CACHE_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_JIT_CACHE_H_ 19 20 #include <cstdint> 21 #include <optional> 22 23 #include "perfetto/ext/base/flat_hash_map.h" 24 #include "perfetto/ext/base/string_view.h" 25 #include "perfetto/trace_processor/trace_blob_view.h" 26 #include "src/trace_processor/importers/common/address_range.h" 27 #include "src/trace_processor/importers/common/stack_profile_tracker.h" 28 #include "src/trace_processor/storage/trace_storage.h" 29 #include "src/trace_processor/tables/jit_tables_py.h" 30 #include "src/trace_processor/tables/profiler_tables_py.h" 31 #include "src/trace_processor/types/trace_processor_context.h" 32 33 namespace perfetto { 34 namespace trace_processor { 35 36 class VirtualMemoryMapping; 37 class UserMemoryMapping; 38 39 // JitCache represents a container of jit code generated by the same VM. Jitted 40 // functions can be "added" to the cache and stack frames added to the 41 // StackFrameTracker that lie in the code range for such a function will 42 // automatically be resolved (associate function name and source location). 43 // 44 // Jitted functions can also be deleted from the cache by overwriting existing 45 // ones. 46 class JitCache { 47 public: 48 struct SourceLocation { 49 StringId file_name; 50 uint32_t line_number; 51 }; 52 JitCache(TraceProcessorContext * context,std::string name,UniquePid upid,AddressRange range)53 JitCache(TraceProcessorContext* context, 54 std::string name, 55 UniquePid upid, 56 AddressRange range) 57 : context_(context), name_(std::move(name)), upid_(upid), range_(range) {} 58 59 // Notify the cache that a jitted function was loaded at the given address 60 // range. Any existing function that fully or partially overlaps with the new 61 // function will be deleted. 62 // The passed in listener will be notified each time a new Frame is created 63 // for this function. 64 tables::JitCodeTable::Id LoadCode( 65 int64_t timestamp, 66 UniqueTid utid, 67 AddressRange code_range, 68 StringId function_name, 69 std::optional<SourceLocation> source_location, 70 TraceBlobView native_code); 71 tables::JitCodeTable::Id MoveCode(int64_t timestamp, 72 UniqueTid utid, 73 uint64_t from_code_start, 74 uint64_t to_code_start); 75 76 // Forward frame interning request. 77 // MappingTracker allows other trackers to register ranges of memory for 78 // which they need to control when a new frame is created. Jitted code can 79 // move in memory over time, so the same program counter might refer to 80 // different functions at different point in time. MappingTracker does 81 // not keep track of such moves but instead delegates the creation of jitted 82 // frames to a delegate. 83 // Returns frame_id, and whether a new row as created or not. 84 std::pair<FrameId, bool> InternFrame(VirtualMemoryMapping* mapping, 85 uint64_t rel_pc, 86 base::StringView function_name); 87 88 // Simpleperf does not emit mmap events for jitted ranges (actually for non 89 // file backed executable mappings). So have a way to generate a mapping on 90 // the fly for FindMapping requests in a jitted region with no associated 91 // mapping. 92 UserMemoryMapping& CreateMapping(); 93 94 private: 95 struct FrameKey { 96 tables::StackProfileMappingTable::Id mapping_id; 97 uint64_t rel_pc; 98 struct Hasher { operatorFrameKey::Hasher99 size_t operator()(const FrameKey& k) const { 100 return static_cast<size_t>( 101 base::Hasher::Combine(k.mapping_id.value, k.rel_pc)); 102 } 103 }; 104 bool operator==(const FrameKey& other) const { 105 return mapping_id == other.mapping_id && rel_pc == other.rel_pc; 106 } 107 }; 108 109 class JittedFunction { 110 public: JittedFunction(tables::JitCodeTable::Id jit_code_id,std::optional<uint32_t> symbol_set_id)111 JittedFunction(tables::JitCodeTable::Id jit_code_id, 112 std::optional<uint32_t> symbol_set_id) 113 : jit_code_id_(jit_code_id), symbol_set_id_(symbol_set_id) {} 114 jit_code_id()115 tables::JitCodeTable::Id jit_code_id() const { return jit_code_id_; } 116 117 std::pair<FrameId, bool> InternFrame(TraceProcessorContext* context, 118 FrameKey frame_key); 119 120 private: 121 const tables::JitCodeTable::Id jit_code_id_; 122 const std::optional<uint32_t> symbol_set_id_; 123 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> interned_frames_; 124 }; 125 126 StringId Base64Encode(const TraceBlobView& data); 127 128 TraceProcessorContext* const context_; 129 const std::string name_; 130 const UniquePid upid_; 131 const AddressRange range_; 132 AddressRangeMap<JittedFunction> functions_; 133 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> unknown_frames_; 134 }; 135 136 } // namespace trace_processor 137 } // namespace perfetto 138 139 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_JIT_CACHE_H_ 140