• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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