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