1 2 /* 3 * Copyright (C) 2024 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 19 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 20 21 #include <cstddef> 22 #include <cstdint> 23 #include <optional> 24 #include <string> 25 #include <vector> 26 27 #include "perfetto/ext/base/flat_hash_map.h" 28 #include "perfetto/ext/base/hash.h" 29 #include "perfetto/ext/base/string_view.h" 30 #include "src/trace_processor/importers/common/address_range.h" 31 #include "src/trace_processor/importers/common/create_mapping_params.h" 32 #include "src/trace_processor/storage/trace_storage.h" 33 #include "src/trace_processor/types/trace_processor_context.h" 34 #include "src/trace_processor/util/build_id.h" 35 36 namespace perfetto { 37 namespace trace_processor { 38 39 // TODO(carlscab): Reconsider whether jit is the best abstraction here. All we 40 // really care is about mapping a `rel_pc` to a symbol (aka symbolization) and 41 // whether is this is constant. 42 class JitCache; 43 44 // Represents a mapping in virtual memory. 45 class VirtualMemoryMapping { 46 public: 47 virtual ~VirtualMemoryMapping(); 48 // Range of virtual memory this mapping covers. memory_range()49 AddressRange memory_range() const { return memory_range_; } mapping_id()50 MappingId mapping_id() const { return mapping_id_; } 51 // This name could be the path of the underlying file mapped into memory. name()52 const std::string& name() const { return name_; } 53 // For file mappings, this is the offset into the file for the first byte in 54 // the mapping offset()55 uint64_t offset() const { return offset_; } 56 // If the mapped file is an executable or shared library this will return the 57 // load bias, if known. Returns 0 otherwise. load_bias()58 uint64_t load_bias() const { return load_bias_; } 59 // If the mapped file is an executable or shared library this will return its 60 // build id, if known. build_id()61 const std::optional<BuildId>& build_id() const { return build_id_; } 62 63 // Whether this maps to a region that holds jitted code. is_jitted()64 bool is_jitted() const { return jit_cache_ != nullptr; } 65 66 // Converts an absolute address into a relative one. ToRelativePc(uint64_t address)67 uint64_t ToRelativePc(uint64_t address) const { 68 return address - memory_range_.start() + offset_ + load_bias_; 69 } 70 71 // Converts a relative address to an absolute one. ToAddress(uint64_t rel_pc)72 uint64_t ToAddress(uint64_t rel_pc) const { 73 return rel_pc + (memory_range_.start() - offset_ - load_bias_); 74 } 75 76 // Creates a frame for the given `rel_pc`. Note that if the mapping 77 // `is_jitted()` same `rel_pc` values can return different mappings (as jitted 78 // functions can be created and deleted over time.) So for such mappings the 79 // returned `FrameId` should not be cached. 80 FrameId InternFrame(uint64_t rel_pc, base::StringView function_name); 81 82 // Returns all frames ever created in this mapping for the given `rel_pc`. 83 std::vector<FrameId> FindFrameIds(uint64_t rel_pc) const; 84 85 protected: 86 VirtualMemoryMapping(TraceProcessorContext* context, 87 CreateMappingParams params); 88 context()89 TraceProcessorContext* context() const { return context_; } 90 91 private: 92 friend class MappingTracker; 93 94 std::pair<FrameId, bool> InternFrameImpl(uint64_t rel_pc, 95 base::StringView function_name); 96 SetJitCache(JitCache * jit_cache)97 void SetJitCache(JitCache* jit_cache) { jit_cache_ = jit_cache; } 98 99 TraceProcessorContext* const context_; 100 const MappingId mapping_id_; 101 const AddressRange memory_range_; 102 const uint64_t offset_; 103 const uint64_t load_bias_; 104 const std::string name_; 105 std::optional<BuildId> const build_id_; 106 JitCache* jit_cache_ = nullptr; 107 108 struct FrameKey { 109 uint64_t rel_pc; 110 // It doesn't seem to make too much sense to key on name, as for the same 111 // mapping and same rel_pc the name should always be the same. But who knows 112 // how producers behave. 113 StringId name_id; 114 115 bool operator==(const FrameKey& o) const { 116 return rel_pc == o.rel_pc && name_id == o.name_id; 117 } 118 119 struct Hasher { operatorFrameKey::Hasher120 size_t operator()(const FrameKey& k) const { 121 return static_cast<size_t>( 122 base::Hasher::Combine(k.rel_pc, k.name_id.raw_id())); 123 } 124 }; 125 }; 126 base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> interned_frames_; 127 base::FlatHashMap<uint64_t, std::vector<FrameId>> frames_by_rel_pc_; 128 }; 129 130 class KernelMemoryMapping : public VirtualMemoryMapping { 131 public: 132 ~KernelMemoryMapping() override; 133 134 private: 135 friend class MappingTracker; 136 KernelMemoryMapping(TraceProcessorContext* context, 137 CreateMappingParams params); 138 }; 139 140 class UserMemoryMapping : public VirtualMemoryMapping { 141 public: 142 ~UserMemoryMapping() override; upid()143 UniquePid upid() const { return upid_; } 144 145 private: 146 friend class MappingTracker; 147 UserMemoryMapping(TraceProcessorContext* context, 148 UniquePid upid, 149 CreateMappingParams params); 150 151 const UniquePid upid_; 152 }; 153 154 // Dummy mapping to be able to create frames when we have no real pc addresses 155 // or real mappings. 156 class DummyMemoryMapping : public VirtualMemoryMapping { 157 public: 158 ~DummyMemoryMapping() override; 159 160 // Interns a frame based solely on function name and source file. This is 161 // useful for profilers that do not emit an address nor a mapping. 162 FrameId InternDummyFrame(base::StringView function_name, 163 base::StringView source_file); 164 165 private: 166 friend class MappingTracker; 167 DummyMemoryMapping(TraceProcessorContext* context, 168 CreateMappingParams params); 169 170 struct DummyFrameKey { 171 StringId function_name_id; 172 StringId source_file_id; 173 174 bool operator==(const DummyFrameKey& o) const { 175 return function_name_id == o.function_name_id && 176 source_file_id == o.source_file_id; 177 } 178 179 struct Hasher { operatorDummyFrameKey::Hasher180 size_t operator()(const DummyFrameKey& k) const { 181 return static_cast<size_t>(base::Hasher::Combine( 182 k.function_name_id.raw_id(), k.source_file_id.raw_id())); 183 } 184 }; 185 }; 186 base::FlatHashMap<DummyFrameKey, FrameId, DummyFrameKey::Hasher> 187 interned_dummy_frames_; 188 }; 189 190 } // namespace trace_processor 191 } // namespace perfetto 192 193 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_ 194