xref: /aosp_15_r20/art/libprofile/profile/profile_test_helper.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <memory>
21*795d594fSAndroid Build Coastguard Worker #include <vector>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "dex/test_dex_file_builder.h"
24*795d594fSAndroid Build Coastguard Worker #include "profile/profile_compilation_info.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art {
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker class ProfileTestHelper {
29*795d594fSAndroid Build Coastguard Worker  public:
30*795d594fSAndroid Build Coastguard Worker   ProfileTestHelper() = default;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker   using Hotness = ProfileCompilationInfo::MethodHotness;
33*795d594fSAndroid Build Coastguard Worker   using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache;
34*795d594fSAndroid Build Coastguard Worker   using ProfileSampleAnnotation = ProfileCompilationInfo::ProfileSampleAnnotation;
35*795d594fSAndroid Build Coastguard Worker   using ProfileIndexType = ProfileCompilationInfo::ProfileIndexType;
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker   static bool AddMethod(
38*795d594fSAndroid Build Coastguard Worker       ProfileCompilationInfo* info,
39*795d594fSAndroid Build Coastguard Worker       const DexFile* dex,
40*795d594fSAndroid Build Coastguard Worker       uint16_t method_idx,
41*795d594fSAndroid Build Coastguard Worker       const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
42*795d594fSAndroid Build Coastguard Worker     return AddMethod(info, dex, method_idx, Hotness::kFlagHot, annotation);
43*795d594fSAndroid Build Coastguard Worker   }
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker   static bool AddMethod(
46*795d594fSAndroid Build Coastguard Worker       ProfileCompilationInfo* info,
47*795d594fSAndroid Build Coastguard Worker       const DexFile* dex,
48*795d594fSAndroid Build Coastguard Worker       uint16_t method_idx,
49*795d594fSAndroid Build Coastguard Worker       Hotness::Flag flags,
50*795d594fSAndroid Build Coastguard Worker       const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
51*795d594fSAndroid Build Coastguard Worker     return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx)),
52*795d594fSAndroid Build Coastguard Worker                            flags,
53*795d594fSAndroid Build Coastguard Worker                            annotation,
54*795d594fSAndroid Build Coastguard Worker                            /*is_test=*/ true);
55*795d594fSAndroid Build Coastguard Worker   }
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker   static bool AddMethod(
58*795d594fSAndroid Build Coastguard Worker       ProfileCompilationInfo* info,
59*795d594fSAndroid Build Coastguard Worker       const DexFile* dex,
60*795d594fSAndroid Build Coastguard Worker       uint16_t method_idx,
61*795d594fSAndroid Build Coastguard Worker       const std::vector<ProfileInlineCache>& inline_caches,
62*795d594fSAndroid Build Coastguard Worker       const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
63*795d594fSAndroid Build Coastguard Worker     return AddMethod(info, dex, method_idx, inline_caches, Hotness::kFlagHot, annotation);
64*795d594fSAndroid Build Coastguard Worker   }
65*795d594fSAndroid Build Coastguard Worker 
66*795d594fSAndroid Build Coastguard Worker   static bool AddMethod(
67*795d594fSAndroid Build Coastguard Worker       ProfileCompilationInfo* info,
68*795d594fSAndroid Build Coastguard Worker       const DexFile* dex,
69*795d594fSAndroid Build Coastguard Worker       uint16_t method_idx,
70*795d594fSAndroid Build Coastguard Worker       const std::vector<ProfileInlineCache>& inline_caches,
71*795d594fSAndroid Build Coastguard Worker       Hotness::Flag flags,
72*795d594fSAndroid Build Coastguard Worker       const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
73*795d594fSAndroid Build Coastguard Worker     return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches),
74*795d594fSAndroid Build Coastguard Worker                            flags,
75*795d594fSAndroid Build Coastguard Worker                            annotation,
76*795d594fSAndroid Build Coastguard Worker                            /*is_test=*/ true);
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   static bool AddClass(ProfileCompilationInfo* info,
80*795d594fSAndroid Build Coastguard Worker                        const DexFile* dex,
81*795d594fSAndroid Build Coastguard Worker                        dex::TypeIndex type_index,
82*795d594fSAndroid Build Coastguard Worker                        const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
83*795d594fSAndroid Build Coastguard Worker     return info->AddClass(*dex, type_index, annotation);
84*795d594fSAndroid Build Coastguard Worker   }
85*795d594fSAndroid Build Coastguard Worker 
ProfileIndexMatchesDexFile(const ProfileCompilationInfo & info,ProfileIndexType profile_index,const DexFile * dex_file)86*795d594fSAndroid Build Coastguard Worker   static bool ProfileIndexMatchesDexFile(const ProfileCompilationInfo& info,
87*795d594fSAndroid Build Coastguard Worker                                          ProfileIndexType profile_index,
88*795d594fSAndroid Build Coastguard Worker                                          const DexFile* dex_file) {
89*795d594fSAndroid Build Coastguard Worker     DCHECK(dex_file != nullptr);
90*795d594fSAndroid Build Coastguard Worker     std::array<const DexFile*, 1u> dex_files{dex_file};
91*795d594fSAndroid Build Coastguard Worker     return dex_file == info.FindDexFileForProfileIndex(profile_index, dex_files);
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker   // Compare different representations of inline caches for equality.
EqualInlineCaches(const std::vector<ProfileMethodInfo::ProfileInlineCache> & expected,const DexFile * dex_file,const ProfileCompilationInfo::MethodHotness & actual_hotness,const ProfileCompilationInfo & info)95*795d594fSAndroid Build Coastguard Worker   static bool EqualInlineCaches(const std::vector<ProfileMethodInfo::ProfileInlineCache>& expected,
96*795d594fSAndroid Build Coastguard Worker                                 const DexFile* dex_file,
97*795d594fSAndroid Build Coastguard Worker                                 const ProfileCompilationInfo::MethodHotness& actual_hotness,
98*795d594fSAndroid Build Coastguard Worker                                 const ProfileCompilationInfo& info) {
99*795d594fSAndroid Build Coastguard Worker     CHECK(actual_hotness.IsHot());
100*795d594fSAndroid Build Coastguard Worker     CHECK(actual_hotness.GetInlineCacheMap() != nullptr);
101*795d594fSAndroid Build Coastguard Worker     const ProfileCompilationInfo::InlineCacheMap& actual = *actual_hotness.GetInlineCacheMap();
102*795d594fSAndroid Build Coastguard Worker     if (expected.size() != actual.size()) {
103*795d594fSAndroid Build Coastguard Worker       return false;
104*795d594fSAndroid Build Coastguard Worker     }
105*795d594fSAndroid Build Coastguard Worker     // The `expected` data should be sorted by dex pc.
106*795d594fSAndroid Build Coastguard Worker     CHECK(std::is_sorted(expected.begin(),
107*795d594fSAndroid Build Coastguard Worker                          expected.end(),
108*795d594fSAndroid Build Coastguard Worker                          [](auto&& lhs, auto&& rhs) { return lhs.dex_pc < rhs.dex_pc; }));
109*795d594fSAndroid Build Coastguard Worker     // The `actual` data is a map sorted by dex pc, so we can just iterate over both.
110*795d594fSAndroid Build Coastguard Worker     auto expected_it = expected.begin();
111*795d594fSAndroid Build Coastguard Worker     for (auto it = actual.begin(), end = actual.end(); it != end; ++it, ++expected_it) {
112*795d594fSAndroid Build Coastguard Worker       uint32_t dex_pc = it->first;
113*795d594fSAndroid Build Coastguard Worker       const ProfileCompilationInfo::DexPcData& dex_pc_data = it->second;
114*795d594fSAndroid Build Coastguard Worker       if (dex_pc != expected_it->dex_pc) {
115*795d594fSAndroid Build Coastguard Worker         return false;
116*795d594fSAndroid Build Coastguard Worker       }
117*795d594fSAndroid Build Coastguard Worker       if (dex_pc_data.is_missing_types != expected_it->is_missing_types) {
118*795d594fSAndroid Build Coastguard Worker         return false;
119*795d594fSAndroid Build Coastguard Worker       } else if (dex_pc_data.is_missing_types) {
120*795d594fSAndroid Build Coastguard Worker         continue;  // The classes do not matter if we're missing some types.
121*795d594fSAndroid Build Coastguard Worker       }
122*795d594fSAndroid Build Coastguard Worker       // The `expected_it->is_megamorphic` is not initialized. Check the number of classes.
123*795d594fSAndroid Build Coastguard Worker       bool expected_is_megamorphic =
124*795d594fSAndroid Build Coastguard Worker           (expected_it->classes.size() >= ProfileCompilationInfo::kIndividualInlineCacheSize);
125*795d594fSAndroid Build Coastguard Worker       if (dex_pc_data.is_megamorphic != expected_is_megamorphic) {
126*795d594fSAndroid Build Coastguard Worker         return false;
127*795d594fSAndroid Build Coastguard Worker       } else if (dex_pc_data.is_megamorphic) {
128*795d594fSAndroid Build Coastguard Worker         continue;  // The classes do not matter if the inline cache is megamorphic.
129*795d594fSAndroid Build Coastguard Worker       }
130*795d594fSAndroid Build Coastguard Worker       if (dex_pc_data.classes.size() != expected_it->classes.size()) {
131*795d594fSAndroid Build Coastguard Worker         return false;
132*795d594fSAndroid Build Coastguard Worker       }
133*795d594fSAndroid Build Coastguard Worker       for (dex::TypeIndex type_index : dex_pc_data.classes) {
134*795d594fSAndroid Build Coastguard Worker         if (std::none_of(expected_it->classes.begin(),
135*795d594fSAndroid Build Coastguard Worker                          expected_it->classes.end(),
136*795d594fSAndroid Build Coastguard Worker                          [&](const TypeReference& type_ref) {
137*795d594fSAndroid Build Coastguard Worker                            if (type_ref.dex_file == dex_file) {
138*795d594fSAndroid Build Coastguard Worker                              return type_index == type_ref.TypeIndex();
139*795d594fSAndroid Build Coastguard Worker                            } else {
140*795d594fSAndroid Build Coastguard Worker                              const char* expected_descriptor =
141*795d594fSAndroid Build Coastguard Worker                                  type_ref.dex_file->GetTypeDescriptor(type_ref.TypeIndex());
142*795d594fSAndroid Build Coastguard Worker                              const char* descriptor = info.GetTypeDescriptor(dex_file, type_index);
143*795d594fSAndroid Build Coastguard Worker                              return strcmp(expected_descriptor, descriptor) == 0;
144*795d594fSAndroid Build Coastguard Worker                            }
145*795d594fSAndroid Build Coastguard Worker                          })) {
146*795d594fSAndroid Build Coastguard Worker           return false;
147*795d594fSAndroid Build Coastguard Worker         }
148*795d594fSAndroid Build Coastguard Worker       }
149*795d594fSAndroid Build Coastguard Worker     }
150*795d594fSAndroid Build Coastguard Worker     return true;
151*795d594fSAndroid Build Coastguard Worker   }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker  protected:
154*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kNumSharedTypes = 10u;
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   const DexFile* BuildDex(const std::string& location,
157*795d594fSAndroid Build Coastguard Worker                           uint32_t location_checksum,
158*795d594fSAndroid Build Coastguard Worker                           const std::string& class_descriptor,
159*795d594fSAndroid Build Coastguard Worker                           size_t num_method_ids,
160*795d594fSAndroid Build Coastguard Worker                           size_t num_class_ids = kNumSharedTypes + 1u) {
161*795d594fSAndroid Build Coastguard Worker     TestDexFileBuilder builder;
162*795d594fSAndroid Build Coastguard Worker     builder.AddType(class_descriptor);
163*795d594fSAndroid Build Coastguard Worker     CHECK_NE(num_class_ids, 0u);
164*795d594fSAndroid Build Coastguard Worker     size_t num_shared_ids = std::min(num_class_ids - 1u, kNumSharedTypes);
165*795d594fSAndroid Build Coastguard Worker     for (size_t shared_type_index = 0; shared_type_index != num_shared_ids; ++shared_type_index) {
166*795d594fSAndroid Build Coastguard Worker       builder.AddType("LSharedType" + std::to_string(shared_type_index) + ";");
167*795d594fSAndroid Build Coastguard Worker     }
168*795d594fSAndroid Build Coastguard Worker     for (size_t i = 1u + num_shared_ids; i < num_class_ids; ++i) {
169*795d594fSAndroid Build Coastguard Worker       builder.AddType("LFiller" + std::to_string(i) + ";");
170*795d594fSAndroid Build Coastguard Worker     }
171*795d594fSAndroid Build Coastguard Worker     for (size_t method_index = 0; method_index != num_method_ids; ++method_index) {
172*795d594fSAndroid Build Coastguard Worker       // Some tests add the maximum number of methods (`num_method_ids` is 2^16) and we
173*795d594fSAndroid Build Coastguard Worker       // do not want to waste memory with that many unique name strings (with identical
174*795d594fSAndroid Build Coastguard Worker       // proto id). So create up to num_shared_ids^2 proto ids and only
175*795d594fSAndroid Build Coastguard Worker       // num_method_ids/num_shared_ids^2 names.
176*795d594fSAndroid Build Coastguard Worker       size_t return_type_index = method_index % num_shared_ids;
177*795d594fSAndroid Build Coastguard Worker       size_t arg_type_index = (method_index / num_shared_ids) % num_shared_ids;
178*795d594fSAndroid Build Coastguard Worker       size_t method_name_index = (method_index / num_shared_ids) / num_shared_ids;
179*795d594fSAndroid Build Coastguard Worker       std::string return_type = "LSharedType" + std::to_string(return_type_index) + ";";
180*795d594fSAndroid Build Coastguard Worker       std::string arg_type = "LSharedType" + std::to_string(arg_type_index) + ";";
181*795d594fSAndroid Build Coastguard Worker       std::string signature = ART_FORMAT("({}){}", arg_type, return_type);
182*795d594fSAndroid Build Coastguard Worker       builder.AddMethod(class_descriptor, signature, "m" + std::to_string(method_name_index));
183*795d594fSAndroid Build Coastguard Worker     }
184*795d594fSAndroid Build Coastguard Worker     storage.push_back(builder.Build(location, location_checksum));
185*795d594fSAndroid Build Coastguard Worker     return storage.back().get();
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker 
188*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const DexFile>> storage;
189*795d594fSAndroid Build Coastguard Worker };
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker }  // namespace art
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBPROFILE_PROFILE_PROFILE_TEST_HELPER_H_
194