xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/jit_cache.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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