xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/jit_tracker_unittest.cc (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 #include "src/trace_processor/importers/proto/jit_tracker.h"
18 
19 #include <cstdint>
20 #include <optional>
21 #include <string>
22 
23 #include "perfetto/ext/base/string_view.h"
24 #include "perfetto/trace_processor/trace_blob_view.h"
25 #include "src/trace_processor/importers/common/address_range.h"
26 #include "src/trace_processor/importers/common/jit_cache.h"
27 #include "src/trace_processor/importers/common/mapping_tracker.h"
28 #include "src/trace_processor/importers/common/process_tracker.h"
29 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
30 #include "src/trace_processor/storage/stats.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 #include "src/trace_processor/tables/jit_tables_py.h"
33 #include "src/trace_processor/util/build_id.h"
34 #include "test/gtest_and_gmock.h"
35 
36 namespace perfetto {
37 namespace trace_processor {
38 namespace {
39 
40 using ::testing::_;
41 using ::testing::DoAll;
42 using ::testing::Eq;
43 using ::testing::FieldsAre;
44 using ::testing::IsEmpty;
45 using ::testing::Ne;
46 using ::testing::Optional;
47 using ::testing::SaveArg;
48 
49 class JitTrackerTest : public testing::Test {
50  public:
JitTrackerTest()51   JitTrackerTest() {
52     context_.storage.reset(new TraceStorage());
53     context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
54     context_.mapping_tracker.reset(new MappingTracker(&context_));
55     context_.process_tracker.reset(new ProcessTracker(&context_));
56     jit_tracker_ = JitTracker::GetOrCreate(&context_);
57   }
58 
59  protected:
AddMapping(UniquePid upid,AddressRange range,uint64_t exact_offset=0,uint64_t load_bias=0)60   UserMemoryMapping& AddMapping(UniquePid upid,
61                                 AddressRange range,
62                                 uint64_t exact_offset = 0,
63                                 uint64_t load_bias = 0) {
64     uint32_t id = context_.storage->stack_profile_mapping_table().row_count();
65     CreateMappingParams params;
66     params.memory_range = range;
67     params.build_id =
68         BuildId::FromRaw(reinterpret_cast<const uint8_t*>(&id), sizeof(id));
69     params.exact_offset = exact_offset;
70     params.start_offset = exact_offset;
71     params.load_bias = load_bias;
72     params.name = "Mapping ";
73     params.name += std::to_string(id);
74     return context_.mapping_tracker->CreateUserMemoryMapping(upid,
75                                                              std::move(params));
76   }
77 
78   TraceProcessorContext context_;
79   JitTracker* jit_tracker_;
80 };
81 
TEST_F(JitTrackerTest,BasicFunctionality)82 TEST_F(JitTrackerTest, BasicFunctionality) {
83   const UniquePid upid = context_.process_tracker->GetOrCreateProcess(1234);
84   const UniqueTid utid = context_.process_tracker->UpdateThread(4321, 1234);
85   const AddressRange jit_range(0, 1000);
86   auto& mapping = AddMapping(upid, jit_range);
87   JitCache* cache = jit_tracker_->CreateJitCache("name", upid, jit_range);
88 
89   const StringId function_name = context_.storage->InternString("Function 1");
90   const StringId source_file = context_.storage->InternString("SourceFile");
91   const int64_t create_ts = 12345;
92   const AddressRange code_range(0, 100);
93 
94   auto code_id = cache->LoadCode(create_ts, utid, code_range, function_name,
95                                  JitCache::SourceLocation{source_file, 10},
96                                  TraceBlobView());
97 
98   auto code = *context_.storage->jit_code_table().FindById(code_id);
99   EXPECT_THAT(code.create_ts(), Eq(create_ts));
100   EXPECT_THAT(code.estimated_delete_ts(), Eq(std::nullopt));
101   EXPECT_THAT(code.utid(), Eq(utid));
102   EXPECT_THAT(code.start_address(),
103               Eq(static_cast<int64_t>(code_range.start())));
104   EXPECT_THAT(code.size(), Eq(static_cast<int64_t>(code_range.size())));
105   EXPECT_THAT(code.function_name(), Eq(function_name));
106 
107   auto frame_id = mapping.InternFrame(50, "");
108 
109   auto frame =
110       *context_.storage->stack_profile_frame_table().FindById(frame_id);
111   EXPECT_THAT(frame.name(), Eq(function_name));
112 
113   auto row = context_.storage->jit_frame_table().FindById(
114       tables::JitFrameTable::Id(0));
115   ASSERT_THAT(row, Ne(std::nullopt));
116 
117   EXPECT_THAT(row->jit_code_id(), Eq(code_id));
118   EXPECT_THAT(row->frame_id(), Eq(frame_id));
119 }
120 
TEST_F(JitTrackerTest,FunctionOverlapUpdatesDeleteTs)121 TEST_F(JitTrackerTest, FunctionOverlapUpdatesDeleteTs) {
122   const UniquePid upid = context_.process_tracker->GetOrCreateProcess(1234);
123   const UniqueTid utid = context_.process_tracker->UpdateThread(4321, 1234);
124   const AddressRange jit_range(0, 1000);
125   auto& mapping = AddMapping(upid, jit_range);
126   JitCache* cache = jit_tracker_->CreateJitCache("name", upid, jit_range);
127 
128   const StringId function_name_1 = context_.storage->InternString("Function 1");
129   const StringId function_name_2 = context_.storage->InternString("Function 2");
130   const StringId source_file = context_.storage->InternString("SourceFile");
131   const int64_t create_ts_1 = 12345;
132   const int64_t create_ts_2 = 23456;
133   const AddressRange code_range_1(0, 100);
134   const AddressRange code_range_2(50, 200);
135 
136   auto code_id_1 = cache->LoadCode(
137       create_ts_1, utid, code_range_1, function_name_1,
138       JitCache::SourceLocation{source_file, 10}, TraceBlobView());
139   auto code_id_2 = cache->LoadCode(
140       create_ts_2, utid, code_range_2, function_name_2,
141       JitCache::SourceLocation{source_file, 10}, TraceBlobView());
142   EXPECT_THAT(code_id_1, Ne(code_id_2));
143 
144   auto code_1 = *context_.storage->jit_code_table().FindById(code_id_1);
145   auto code_2 = *context_.storage->jit_code_table().FindById(code_id_2);
146 
147   // Code 1 has been deleted
148   EXPECT_THAT(code_1.create_ts(), Eq(create_ts_1));
149   EXPECT_THAT(code_1.estimated_delete_ts(), Eq(create_ts_2));
150 
151   // The only active code is 2 at this point.
152   EXPECT_THAT(code_2.create_ts(), Eq(create_ts_2));
153   EXPECT_THAT(code_2.estimated_delete_ts(), Eq(std::nullopt));
154 
155   // No frame should mention code 1
156   FrameId frame_id = mapping.InternFrame(50, "");
157   auto frame_a =
158       *context_.storage->stack_profile_frame_table().FindById(frame_id);
159   EXPECT_THAT(frame_a.name(), Eq(function_name_2));
160   ASSERT_THAT(context_.storage->jit_frame_table().row_count(), Eq(1u));
161   auto row = context_.storage->jit_frame_table().FindById(
162       tables::JitFrameTable::Id(0));
163   EXPECT_THAT(row->jit_code_id(), Eq(code_id_2));
164   EXPECT_THAT(row->frame_id(), Eq(frame_id));
165 
166   // Frames for the old code 1 must fail to resolve to a jitted function but
167   // still generate a frame.
168   EXPECT_THAT(context_.storage->stats().at(stats::jit_unknown_frame).value,
169               Eq(0));
170   frame_id = mapping.InternFrame(0, "custom");
171   EXPECT_THAT(context_.storage->stats().at(stats::jit_unknown_frame).value,
172               Eq(1));
173   auto frame_b =
174       *context_.storage->stack_profile_frame_table().FindById(frame_id);
175   EXPECT_THAT(frame_a.id(), Ne(frame_b.id()));
176   EXPECT_THAT(context_.storage->GetString(frame_b.name()), Eq("custom"));
177   EXPECT_THAT(context_.storage->jit_frame_table().row_count(), Eq(1u));
178 }
179 
180 }  // namespace
181 
182 }  // namespace trace_processor
183 }  // namespace perfetto
184