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 72 // Forward frame interning request. 73 // MappingTracker allows other trackers to register ranges of memory for 74 // which they need to control when a new frame is created. Jitted code can 75 // move in memory over time, so the same program counter might refer to 76 // different functions at different point in time. MappingTracker does 77 // not keep track of such moves but instead delegates the creation of jitted 78 // frames to a delegate. 79 // Returns frame_id, and whether a new row as created or not. 80 std::pair<FrameId, bool> InternFrame(VirtualMemoryMapping* mapping, 81 uint64_t rel_pc, 82 base::StringView function_name); 83 84 // Simpleperf does not emit mmap events for jitted ranges (actually for non 85 // file backed executable mappings). So have a way to generate a mapping on 86 // the fly for FindMapping requests in a jitted region with no associated 87 // mapping. 88 UserMemoryMapping& CreateMapping(); 89 90 private: 91 struct FrameKey { 92 tables::StackProfileMappingTable::Id mapping_id; 93 uint64_t rel_pc; 94 struct Hasher { operatorFrameKey::Hasher95 size_t operator()(const FrameKey& k) const { 96 return static_cast<size_t>( 97 base::Hasher::Combine(k.mapping_id.value, k.rel_pc)); 98 } 99 }; 100 bool operator==(const FrameKey& other) const { 101 return mapping_id == other.mapping_id && rel_pc == other.rel_pc; 102 } 103 }; 104 105 class JittedFunction { 106 public: JittedFunction(tables::JitCodeTable::Id jit_code_id,std::optional<uint32_t> symbol_set_id)107 JittedFunction(tables::JitCodeTable::Id jit_code_id, 108 std::optional<uint32_t> symbol_set_id) 109 : jit_code_id_(jit_code_id), symbol_set_id_(symbol_set_id) {} 110 jit_code_id()111 tables::JitCodeTable::Id jit_code_id() const { return jit_code_id_; } 112 113 std::pair<FrameId, bool> InternFrame(TraceProcessorContext* context, 114 FrameKey frame_key); 115 116 private: 117 const tables::JitCodeTable::Id jit_code_id_; 118 const std::optional<uint32_t> symbol_set_id_; 119 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> interned_frames_; 120 }; 121 122 StringId Base64Encode(const TraceBlobView& data); 123 124 TraceProcessorContext* const context_; 125 const std::string name_; 126 const UniquePid upid_; 127 const AddressRange range_; 128 AddressRangeMap<JittedFunction> functions_; 129 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> unknown_frames_; 130 }; 131 132 } // namespace trace_processor 133 } // namespace perfetto 134 135 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_JIT_CACHE_H_ 136