1 /* 2 * Copyright (C) 2016 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 <gtest/gtest.h> 18 19 #include "android-base/strings.h" 20 #include "art_method-inl.h" 21 #include "base/unix_file/fd_file.h" 22 #include "base/utils.h" 23 #include "common_runtime_test.h" 24 #include "dex/descriptors_names.h" 25 #include "exec_utils.h" 26 #include "jit/profile_compilation_info.h" 27 #include "linear_alloc.h" 28 #include "mirror/class-inl.h" 29 #include "obj_ptr-inl.h" 30 #include "profile_assistant.h" 31 #include "scoped_thread_state_change-inl.h" 32 33 namespace art { 34 35 using Hotness = ProfileCompilationInfo::MethodHotness; 36 37 static constexpr size_t kMaxMethodIds = 65535; 38 39 class ProfileAssistantTest : public CommonRuntimeTest { 40 public: 41 void PostRuntimeCreate() OVERRIDE { 42 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); 43 } 44 45 protected: 46 void SetupProfile(const std::string& id, 47 uint32_t checksum, 48 uint16_t number_of_methods, 49 uint16_t number_of_classes, 50 const ScratchFile& profile, 51 ProfileCompilationInfo* info, 52 uint16_t start_method_index = 0, 53 bool reverse_dex_write_order = false) { 54 std::string dex_location1 = "location1" + id; 55 uint32_t dex_location_checksum1 = checksum; 56 std::string dex_location2 = "location2" + id; 57 uint32_t dex_location_checksum2 = 10 * checksum; 58 SetupProfile(dex_location1, 59 dex_location_checksum1, 60 dex_location2, 61 dex_location_checksum2, 62 number_of_methods, 63 number_of_classes, 64 profile, 65 info, 66 start_method_index, 67 reverse_dex_write_order); 68 } 69 70 void SetupProfile(const std::string& dex_location1, 71 uint32_t dex_location_checksum1, 72 const std::string& dex_location2, 73 uint32_t dex_location_checksum2, 74 uint16_t number_of_methods, 75 uint16_t number_of_classes, 76 const ScratchFile& profile, 77 ProfileCompilationInfo* info, 78 uint16_t start_method_index = 0, 79 bool reverse_dex_write_order = false, 80 uint32_t number_of_methods1 = kMaxMethodIds, 81 uint32_t number_of_methods2 = kMaxMethodIds) { 82 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) { 83 // reverse_dex_write_order controls the order in which the dex files will be added to 84 // the profile and thus written to disk. 85 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = 86 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1, 87 dex_location2, dex_location_checksum2, 88 number_of_methods1, number_of_methods2); 89 Hotness::Flag flags = Hotness::kFlagPostStartup; 90 if (reverse_dex_write_order) { 91 ASSERT_TRUE(info->AddMethod( 92 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags)); 93 ASSERT_TRUE(info->AddMethod( 94 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags)); 95 } else { 96 ASSERT_TRUE(info->AddMethod( 97 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags)); 98 ASSERT_TRUE(info->AddMethod( 99 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags)); 100 } 101 } 102 for (uint16_t i = 0; i < number_of_classes; i++) { 103 ASSERT_TRUE(info->AddClassIndex(dex_location1, 104 dex_location_checksum1, 105 dex::TypeIndex(i), 106 number_of_methods1)); 107 } 108 109 ASSERT_TRUE(info->Save(GetFd(profile))); 110 ASSERT_EQ(0, profile.GetFile()->Flush()); 111 ASSERT_TRUE(profile.GetFile()->ResetOffset()); 112 } 113 114 void SetupBasicProfile(const std::string& id, 115 uint32_t checksum, 116 uint16_t number_of_methods, 117 const std::vector<uint32_t> hot_methods, 118 const std::vector<uint32_t> startup_methods, 119 const std::vector<uint32_t> post_startup_methods, 120 const ScratchFile& profile, 121 ProfileCompilationInfo* info) { 122 std::string dex_location = "location1" + id; 123 for (uint32_t idx : hot_methods) { 124 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods); 125 } 126 for (uint32_t idx : startup_methods) { 127 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods); 128 } 129 for (uint32_t idx : post_startup_methods) { 130 info->AddMethodIndex(Hotness::kFlagPostStartup, 131 dex_location, 132 checksum, 133 idx, 134 number_of_methods); 135 } 136 ASSERT_TRUE(info->Save(GetFd(profile))); 137 ASSERT_EQ(0, profile.GetFile()->Flush()); 138 ASSERT_TRUE(profile.GetFile()->ResetOffset()); 139 } 140 141 // Creates an inline cache which will be destructed at the end of the test. 142 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { 143 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( 144 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); 145 return used_inline_caches.back().get(); 146 } 147 148 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo( 149 const std::string& dex_location1, uint32_t dex_checksum1, 150 const std::string& dex_location2, uint32_t dex_checksum2, 151 uint32_t number_of_methods1 = kMaxMethodIds, uint32_t number_of_methods2 = kMaxMethodIds) { 152 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); 153 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map); 154 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, number_of_methods1); 155 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, number_of_methods2); 156 157 // Monomorphic 158 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { 159 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); 160 dex_pc_data.AddClass(0, dex::TypeIndex(0)); 161 ic_map->Put(dex_pc, dex_pc_data); 162 } 163 // Polymorphic 164 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { 165 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); 166 dex_pc_data.AddClass(0, dex::TypeIndex(0)); 167 dex_pc_data.AddClass(1, dex::TypeIndex(1)); 168 169 ic_map->Put(dex_pc, dex_pc_data); 170 } 171 // Megamorphic 172 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { 173 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); 174 dex_pc_data.SetIsMegamorphic(); 175 ic_map->Put(dex_pc, dex_pc_data); 176 } 177 // Missing types 178 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { 179 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get()); 180 dex_pc_data.SetIsMissingTypes(); 181 ic_map->Put(dex_pc, dex_pc_data); 182 } 183 184 return pmi; 185 } 186 187 int GetFd(const ScratchFile& file) const { 188 return static_cast<int>(file.GetFd()); 189 } 190 191 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) { 192 ProfileCompilationInfo file_info; 193 ASSERT_TRUE(file.GetFile()->ResetOffset()); 194 ASSERT_TRUE(file_info.Load(GetFd(file))); 195 ASSERT_TRUE(file_info.Equals(info)); 196 } 197 198 std::string GetProfmanCmd() { 199 std::string file_path = GetTestAndroidRoot(); 200 file_path += "/bin/profman"; 201 if (kIsDebugBuild) { 202 file_path += "d"; 203 } 204 EXPECT_TRUE(OS::FileExists(file_path.c_str())) 205 << file_path << " should be a valid file path"; 206 return file_path; 207 } 208 209 // Runs test with given arguments. 210 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) { 211 std::string profman_cmd = GetProfmanCmd(); 212 std::vector<std::string> argv_str; 213 argv_str.push_back(profman_cmd); 214 for (size_t k = 0; k < profiles_fd.size(); k++) { 215 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k])); 216 } 217 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd)); 218 219 std::string error; 220 return ExecAndReturnCode(argv_str, &error); 221 } 222 223 bool GenerateTestProfile(const std::string& filename) { 224 std::string profman_cmd = GetProfmanCmd(); 225 std::vector<std::string> argv_str; 226 argv_str.push_back(profman_cmd); 227 argv_str.push_back("--generate-test-profile=" + filename); 228 std::string error; 229 return ExecAndReturnCode(argv_str, &error); 230 } 231 232 bool GenerateTestProfileWithInputDex(const std::string& filename) { 233 std::string profman_cmd = GetProfmanCmd(); 234 std::vector<std::string> argv_str; 235 argv_str.push_back(profman_cmd); 236 argv_str.push_back("--generate-test-profile=" + filename); 237 argv_str.push_back("--generate-test-profile-seed=0"); 238 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]); 239 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]); 240 std::string error; 241 return ExecAndReturnCode(argv_str, &error); 242 } 243 244 bool CreateProfile(const std::string& profile_file_contents, 245 const std::string& filename, 246 const std::string& dex_location) { 247 ScratchFile class_names_file; 248 File* file = class_names_file.GetFile(); 249 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length())); 250 EXPECT_EQ(0, file->Flush()); 251 EXPECT_TRUE(file->ResetOffset()); 252 std::string profman_cmd = GetProfmanCmd(); 253 std::vector<std::string> argv_str; 254 argv_str.push_back(profman_cmd); 255 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename()); 256 argv_str.push_back("--reference-profile-file=" + filename); 257 argv_str.push_back("--apk=" + dex_location); 258 argv_str.push_back("--dex-location=" + dex_location); 259 std::string error; 260 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0); 261 return true; 262 } 263 264 bool RunProfman(const std::string& filename, 265 std::vector<std::string>& extra_args, 266 std::string* output) { 267 ScratchFile output_file; 268 std::string profman_cmd = GetProfmanCmd(); 269 std::vector<std::string> argv_str; 270 argv_str.push_back(profman_cmd); 271 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end()); 272 argv_str.push_back("--profile-file=" + filename); 273 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]); 274 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]); 275 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file))); 276 std::string error; 277 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0); 278 File* file = output_file.GetFile(); 279 EXPECT_EQ(0, file->Flush()); 280 EXPECT_TRUE(file->ResetOffset()); 281 int64_t length = file->GetLength(); 282 std::unique_ptr<char[]> buf(new char[length]); 283 EXPECT_EQ(file->Read(buf.get(), length, 0), length); 284 *output = std::string(buf.get(), length); 285 return true; 286 } 287 288 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) { 289 std::vector<std::string> extra_args; 290 extra_args.push_back("--dump-classes-and-methods"); 291 return RunProfman(filename, extra_args, file_contents); 292 } 293 294 bool DumpOnly(const std::string& filename, std::string* file_contents) { 295 std::vector<std::string> extra_args; 296 extra_args.push_back("--dump-only"); 297 return RunProfman(filename, extra_args, file_contents); 298 } 299 300 bool CreateAndDump(const std::string& input_file_contents, 301 std::string* output_file_contents) { 302 ScratchFile profile_file; 303 EXPECT_TRUE(CreateProfile(input_file_contents, 304 profile_file.GetFilename(), 305 GetLibCoreDexFileNames()[0])); 306 profile_file.GetFile()->ResetOffset(); 307 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents)); 308 return true; 309 } 310 311 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) { 312 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 313 Thread* self = Thread::Current(); 314 ScopedObjectAccess soa(self); 315 StackHandleScope<1> hs(self); 316 Handle<mirror::ClassLoader> h_loader( 317 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader)))); 318 return class_linker->FindClass(self, clazz.c_str(), h_loader); 319 } 320 321 ArtMethod* GetVirtualMethod(jobject class_loader, 322 const std::string& clazz, 323 const std::string& name) { 324 mirror::Class* klass = GetClass(class_loader, clazz); 325 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 326 const auto pointer_size = class_linker->GetImagePointerSize(); 327 ArtMethod* method = nullptr; 328 Thread* self = Thread::Current(); 329 ScopedObjectAccess soa(self); 330 for (auto& m : klass->GetVirtualMethods(pointer_size)) { 331 if (name == m.GetName()) { 332 EXPECT_TRUE(method == nullptr); 333 method = &m; 334 } 335 } 336 return method; 337 } 338 339 // Verify that given method has the expected inline caches and nothing else. 340 void AssertInlineCaches(ArtMethod* method, 341 const std::set<mirror::Class*>& expected_clases, 342 const ProfileCompilationInfo& info, 343 bool is_megamorphic, 344 bool is_missing_types) 345 REQUIRES_SHARED(Locks::mutator_lock_) { 346 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = 347 info.GetMethod(method->GetDexFile()->GetLocation(), 348 method->GetDexFile()->GetLocationChecksum(), 349 method->GetDexMethodIndex()); 350 ASSERT_TRUE(pmi != nullptr); 351 ASSERT_EQ(pmi->inline_caches->size(), 1u); 352 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second; 353 354 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic); 355 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types); 356 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size()); 357 size_t found = 0; 358 for (mirror::Class* it : expected_clases) { 359 for (const auto& class_ref : dex_pc_data.classes) { 360 ProfileCompilationInfo::DexReference dex_ref = 361 pmi->dex_references[class_ref.dex_profile_index]; 362 if (dex_ref.MatchesDex(&(it->GetDexFile())) && 363 class_ref.type_index == it->GetDexTypeIndex()) { 364 found++; 365 } 366 } 367 } 368 369 ASSERT_EQ(expected_clases.size(), found); 370 } 371 372 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile, 373 uint16_t methods_in_ref_profile) { 374 ScratchFile profile; 375 ScratchFile reference_profile; 376 std::vector<int> profile_fds({ GetFd(profile)}); 377 int reference_profile_fd = GetFd(reference_profile); 378 std::vector<uint32_t> hot_methods_cur; 379 std::vector<uint32_t> hot_methods_ref; 380 std::vector<uint32_t> empty_vector; 381 for (size_t i = 0; i < methods_in_cur_profile; ++i) { 382 hot_methods_cur.push_back(i); 383 } 384 for (size_t i = 0; i < methods_in_ref_profile; ++i) { 385 hot_methods_ref.push_back(i); 386 } 387 ProfileCompilationInfo info1; 388 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile); 389 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector, 390 profile, &info1); 391 ProfileCompilationInfo info2; 392 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector, 393 reference_profile, &info2); 394 return ProcessProfiles(profile_fds, reference_profile_fd); 395 } 396 397 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile, 398 uint16_t classes_in_ref_profile) { 399 ScratchFile profile; 400 ScratchFile reference_profile; 401 402 std::vector<int> profile_fds({ GetFd(profile)}); 403 int reference_profile_fd = GetFd(reference_profile); 404 405 ProfileCompilationInfo info1; 406 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1); 407 ProfileCompilationInfo info2; 408 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2); 409 return ProcessProfiles(profile_fds, reference_profile_fd); 410 } 411 412 std::unique_ptr<ArenaAllocator> allocator_; 413 414 // Cache of inline caches generated during tests. 415 // This makes it easier to pass data between different utilities and ensure that 416 // caches are destructed at the end of the test. 417 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; 418 }; 419 420 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) { 421 ScratchFile profile1; 422 ScratchFile profile2; 423 ScratchFile reference_profile; 424 425 std::vector<int> profile_fds({ 426 GetFd(profile1), 427 GetFd(profile2)}); 428 int reference_profile_fd = GetFd(reference_profile); 429 430 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 431 ProfileCompilationInfo info1; 432 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1); 433 ProfileCompilationInfo info2; 434 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); 435 436 // We should advise compilation. 437 ASSERT_EQ(ProfileAssistant::kCompile, 438 ProcessProfiles(profile_fds, reference_profile_fd)); 439 // The resulting compilation info must be equal to the merge of the inputs. 440 ProfileCompilationInfo result; 441 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 442 ASSERT_TRUE(result.Load(reference_profile_fd)); 443 444 ProfileCompilationInfo expected; 445 ASSERT_TRUE(expected.MergeWith(info1)); 446 ASSERT_TRUE(expected.MergeWith(info2)); 447 ASSERT_TRUE(expected.Equals(result)); 448 449 // The information from profiles must remain the same. 450 CheckProfileInfo(profile1, info1); 451 CheckProfileInfo(profile2, info2); 452 } 453 454 // TODO(calin): Add more tests for classes. 455 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) { 456 ScratchFile profile1; 457 ScratchFile reference_profile; 458 459 std::vector<int> profile_fds({ 460 GetFd(profile1)}); 461 int reference_profile_fd = GetFd(reference_profile); 462 463 const uint16_t kNumberOfClassesToEnableCompilation = 100; 464 ProfileCompilationInfo info1; 465 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1); 466 467 // We should advise compilation. 468 ASSERT_EQ(ProfileAssistant::kCompile, 469 ProcessProfiles(profile_fds, reference_profile_fd)); 470 // The resulting compilation info must be equal to the merge of the inputs. 471 ProfileCompilationInfo result; 472 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 473 ASSERT_TRUE(result.Load(reference_profile_fd)); 474 475 ProfileCompilationInfo expected; 476 ASSERT_TRUE(expected.MergeWith(info1)); 477 ASSERT_TRUE(expected.Equals(result)); 478 479 // The information from profiles must remain the same. 480 CheckProfileInfo(profile1, info1); 481 } 482 483 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) { 484 ScratchFile profile1; 485 ScratchFile profile2; 486 ScratchFile reference_profile; 487 488 std::vector<int> profile_fds({ 489 GetFd(profile1), 490 GetFd(profile2)}); 491 int reference_profile_fd = GetFd(reference_profile); 492 493 // The new profile info will contain the methods with indices 0-100. 494 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 495 ProfileCompilationInfo info1; 496 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1); 497 ProfileCompilationInfo info2; 498 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); 499 500 501 // The reference profile info will contain the methods with indices 50-150. 502 const uint16_t kNumberOfMethodsAlreadyCompiled = 100; 503 ProfileCompilationInfo reference_info; 504 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile, 505 &reference_info, kNumberOfMethodsToEnableCompilation / 2); 506 507 // We should advise compilation. 508 ASSERT_EQ(ProfileAssistant::kCompile, 509 ProcessProfiles(profile_fds, reference_profile_fd)); 510 511 // The resulting compilation info must be equal to the merge of the inputs 512 ProfileCompilationInfo result; 513 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 514 ASSERT_TRUE(result.Load(reference_profile_fd)); 515 516 ProfileCompilationInfo expected; 517 ASSERT_TRUE(expected.MergeWith(info1)); 518 ASSERT_TRUE(expected.MergeWith(info2)); 519 ASSERT_TRUE(expected.MergeWith(reference_info)); 520 ASSERT_TRUE(expected.Equals(result)); 521 522 // The information from profiles must remain the same. 523 CheckProfileInfo(profile1, info1); 524 CheckProfileInfo(profile2, info2); 525 } 526 527 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) { 528 ScratchFile profile1; 529 ScratchFile profile2; 530 ScratchFile reference_profile; 531 532 std::vector<int> profile_fds({ 533 GetFd(profile1), 534 GetFd(profile2)}); 535 int reference_profile_fd = GetFd(reference_profile); 536 537 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100. 538 ProfileCompilationInfo info1; 539 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1); 540 ProfileCompilationInfo info2; 541 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2); 542 543 // We should not advise compilation. 544 ASSERT_EQ(ProfileAssistant::kSkipCompilation, 545 ProcessProfiles(profile_fds, reference_profile_fd)); 546 547 // The information from profiles must remain the same. 548 ProfileCompilationInfo file_info1; 549 ASSERT_TRUE(profile1.GetFile()->ResetOffset()); 550 ASSERT_TRUE(file_info1.Load(GetFd(profile1))); 551 ASSERT_TRUE(file_info1.Equals(info1)); 552 553 ProfileCompilationInfo file_info2; 554 ASSERT_TRUE(profile2.GetFile()->ResetOffset()); 555 ASSERT_TRUE(file_info2.Load(GetFd(profile2))); 556 ASSERT_TRUE(file_info2.Equals(info2)); 557 558 // Reference profile files must remain empty. 559 ASSERT_EQ(0, reference_profile.GetFile()->GetLength()); 560 561 // The information from profiles must remain the same. 562 CheckProfileInfo(profile1, info1); 563 CheckProfileInfo(profile2, info2); 564 } 565 566 TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) { 567 const uint16_t kNumberOfMethodsInRefProfile = 6000; 568 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%. 569 // We should not advise compilation. 570 ASSERT_EQ(ProfileAssistant::kSkipCompilation, 571 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile, 572 kNumberOfMethodsInRefProfile)); 573 } 574 575 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) { 576 const uint16_t kNumberOfMethodsInRefProfile = 6000; 577 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%. 578 // We should advise compilation. 579 ASSERT_EQ(ProfileAssistant::kCompile, 580 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile, 581 kNumberOfMethodsInRefProfile)); 582 } 583 584 TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) { 585 const uint16_t kNumberOfClassesInRefProfile = 6000; 586 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%. 587 // We should not advise compilation. 588 ASSERT_EQ(ProfileAssistant::kSkipCompilation, 589 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile, 590 kNumberOfClassesInRefProfile)); 591 } 592 593 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) { 594 const uint16_t kNumberOfClassesInRefProfile = 6000; 595 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%. 596 // We should advise compilation. 597 ASSERT_EQ(ProfileAssistant::kCompile, 598 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile, 599 kNumberOfClassesInRefProfile)); 600 } 601 602 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) { 603 ScratchFile profile1; 604 ScratchFile profile2; 605 ScratchFile reference_profile; 606 607 std::vector<int> profile_fds({ 608 GetFd(profile1), 609 GetFd(profile2)}); 610 int reference_profile_fd = GetFd(reference_profile); 611 612 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 613 // Assign different hashes for the same dex file. This will make merging of information to fail. 614 ProfileCompilationInfo info1; 615 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1); 616 ProfileCompilationInfo info2; 617 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); 618 619 // We should fail processing. 620 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, 621 ProcessProfiles(profile_fds, reference_profile_fd)); 622 623 // The information from profiles must remain the same. 624 CheckProfileInfo(profile1, info1); 625 CheckProfileInfo(profile2, info2); 626 627 // Reference profile files must still remain empty. 628 ASSERT_EQ(0, reference_profile.GetFile()->GetLength()); 629 } 630 631 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) { 632 ScratchFile profile1; 633 ScratchFile reference_profile; 634 635 std::vector<int> profile_fds({ 636 GetFd(profile1)}); 637 int reference_profile_fd = GetFd(reference_profile); 638 639 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 640 // Assign different hashes for the same dex file. This will make merging of information to fail. 641 ProfileCompilationInfo info1; 642 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1); 643 ProfileCompilationInfo reference_info; 644 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info); 645 646 // We should not advise compilation. 647 ASSERT_TRUE(profile1.GetFile()->ResetOffset()); 648 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 649 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles, 650 ProcessProfiles(profile_fds, reference_profile_fd)); 651 652 // The information from profiles must remain the same. 653 CheckProfileInfo(profile1, info1); 654 } 655 656 TEST_F(ProfileAssistantTest, TestProfileGeneration) { 657 ScratchFile profile; 658 // Generate a test profile. 659 GenerateTestProfile(profile.GetFilename()); 660 661 // Verify that the generated profile is valid and can be loaded. 662 ASSERT_TRUE(profile.GetFile()->ResetOffset()); 663 ProfileCompilationInfo info; 664 ASSERT_TRUE(info.Load(GetFd(profile))); 665 } 666 667 TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) { 668 ScratchFile profile; 669 // Generate a test profile passing in a dex file as reference. 670 GenerateTestProfileWithInputDex(profile.GetFilename()); 671 672 // Verify that the generated profile is valid and can be loaded. 673 ASSERT_TRUE(profile.GetFile()->ResetOffset()); 674 ProfileCompilationInfo info; 675 ASSERT_TRUE(info.Load(GetFd(profile))); 676 } 677 678 TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) { 679 // Class names put here need to be in sorted order. 680 std::vector<std::string> class_names = { 681 "HLjava/lang/Object;-><init>()V", 682 "Ljava/lang/Comparable;", 683 "Ljava/lang/Math;", 684 "Ljava/lang/Object;", 685 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I", 686 }; 687 std::string file_contents; 688 for (std::string& class_name : class_names) { 689 file_contents += class_name + std::string("\n"); 690 } 691 std::string output_file_contents; 692 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents)); 693 ASSERT_EQ(output_file_contents, file_contents); 694 } 695 696 TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) { 697 // Class names put here need to be in sorted order. 698 std::vector<std::string> class_names = { 699 "Ljava/lang/Math;->*", 700 }; 701 std::string input_file_contents; 702 std::string expected_contents; 703 for (std::string& class_name : class_names) { 704 input_file_contents += class_name + std::string("\n"); 705 expected_contents += DescriptorToDot(class_name.c_str()) + 706 std::string("\n"); 707 } 708 std::string output_file_contents; 709 ScratchFile profile_file; 710 EXPECT_TRUE(CreateProfile(input_file_contents, 711 profile_file.GetFilename(), 712 GetLibCoreDexFileNames()[0])); 713 ProfileCompilationInfo info; 714 profile_file.GetFile()->ResetOffset(); 715 ASSERT_TRUE(info.Load(GetFd(profile_file))); 716 // Verify that the profile has matching methods. 717 ScopedObjectAccess soa(Thread::Current()); 718 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;"); 719 ASSERT_TRUE(klass != nullptr); 720 size_t method_count = 0; 721 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) { 722 if (!method.IsCopied() && method.GetCodeItem() != nullptr) { 723 ++method_count; 724 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = 725 info.GetMethod(method.GetDexFile()->GetLocation(), 726 method.GetDexFile()->GetLocationChecksum(), 727 method.GetDexMethodIndex()); 728 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod(); 729 } 730 } 731 EXPECT_GT(method_count, 0u); 732 } 733 734 TEST_F(ProfileAssistantTest, TestBootImageProfile) { 735 const std::string core_dex = GetLibCoreDexFileNames()[0]; 736 737 std::vector<ScratchFile> profiles; 738 739 // In image with enough clean occurrences. 740 const std::string kCleanClass = "Ljava/lang/CharSequence;"; 741 // In image with enough dirty occurrences. 742 const std::string kDirtyClass = "Ljava/lang/Object;"; 743 // Not in image becauseof not enough occurrences. 744 const std::string kUncommonCleanClass = "Ljava/lang/Process;"; 745 const std::string kUncommonDirtyClass = "Ljava/lang/Package;"; 746 // Method that is hot. 747 // Also adds the class through inference since it is in each dex. 748 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I"; 749 // Method that doesn't add the class since its only in one profile. Should still show up in the 750 // boot profile. 751 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V"; 752 // Method that gets marked as hot since it's in multiple profiles. 753 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V"; 754 755 // Thresholds for this test. 756 static const size_t kDirtyThreshold = 3; 757 static const size_t kCleanThreshold = 2; 758 static const size_t kMethodThreshold = 2; 759 760 // Create a bunch of boot profiles. 761 std::string dex1 = 762 kCleanClass + "\n" + 763 kDirtyClass + "\n" + 764 kUncommonCleanClass + "\n" + 765 "H" + kHotMethod + "\n" + 766 kUncommonDirtyClass; 767 profiles.emplace_back(ScratchFile()); 768 EXPECT_TRUE(CreateProfile( 769 dex1, profiles.back().GetFilename(), core_dex)); 770 771 // Create a bunch of boot profiles. 772 std::string dex2 = 773 kCleanClass + "\n" + 774 kDirtyClass + "\n" + 775 "P" + kHotMethod + "\n" + 776 "P" + kMultiMethod + "\n" + 777 kUncommonDirtyClass; 778 profiles.emplace_back(ScratchFile()); 779 EXPECT_TRUE(CreateProfile( 780 dex2, profiles.back().GetFilename(), core_dex)); 781 782 // Create a bunch of boot profiles. 783 std::string dex3 = 784 "S" + kHotMethod + "\n" + 785 "P" + kOtherMethod + "\n" + 786 "P" + kMultiMethod + "\n" + 787 kDirtyClass + "\n"; 788 profiles.emplace_back(ScratchFile()); 789 EXPECT_TRUE(CreateProfile( 790 dex3, profiles.back().GetFilename(), core_dex)); 791 792 // Generate the boot profile. 793 ScratchFile out_profile; 794 std::vector<std::string> args; 795 args.push_back(GetProfmanCmd()); 796 args.push_back("--generate-boot-image-profile"); 797 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold)); 798 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold)); 799 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold)); 800 args.push_back("--reference-profile-file=" + out_profile.GetFilename()); 801 args.push_back("--apk=" + core_dex); 802 args.push_back("--dex-location=" + core_dex); 803 for (const ScratchFile& profile : profiles) { 804 args.push_back("--profile-file=" + profile.GetFilename()); 805 } 806 std::string error; 807 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error; 808 ASSERT_EQ(0, out_profile.GetFile()->Flush()); 809 ASSERT_TRUE(out_profile.GetFile()->ResetOffset()); 810 811 // Verify the boot profile contents. 812 std::string output_file_contents; 813 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents)); 814 // Common classes, should be in the classes of the profile. 815 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos) 816 << output_file_contents; 817 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos) 818 << output_file_contents; 819 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile. 820 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos) 821 << output_file_contents; 822 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos) 823 << output_file_contents; 824 // Inferred class from a method common to all three profiles. 825 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos) 826 << output_file_contents; 827 // Aggregated methods hotness information. 828 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos) 829 << output_file_contents; 830 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos) 831 << output_file_contents; 832 // Not inferred class, method is only in one profile. 833 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos) 834 << output_file_contents; 835 // Test the sampled methods that became hot. 836 // Other method is in only one profile, it should not become hot. 837 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos) 838 << output_file_contents; 839 // Multi method is in at least two profiles, it should become hot. 840 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos) 841 << output_file_contents; 842 } 843 844 TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) { 845 // Class names put here need to be in sorted order. 846 std::vector<std::string> class_names = { 847 "Ldoesnt/match/this/one;", 848 "Ljava/lang/Comparable;", 849 "Ljava/lang/Object;" 850 }; 851 std::string input_file_contents; 852 for (std::string& class_name : class_names) { 853 input_file_contents += class_name + std::string("\n"); 854 } 855 std::string output_file_contents; 856 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents)); 857 std::string expected_contents = 858 class_names[1] + std::string("\n") + 859 class_names[2] + std::string("\n"); 860 ASSERT_EQ(output_file_contents, expected_contents); 861 } 862 863 TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) { 864 // Class names put here need to be in sorted order. 865 std::vector<std::string> class_names = { 866 "Ldoesnt/match/this/one;", 867 "Ldoesnt/match/this/one/either;", 868 "Lnor/this/one;" 869 }; 870 std::string input_file_contents; 871 for (std::string& class_name : class_names) { 872 input_file_contents += class_name + std::string("\n"); 873 } 874 std::string output_file_contents; 875 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents)); 876 std::string expected_contents(""); 877 ASSERT_EQ(output_file_contents, expected_contents); 878 } 879 880 TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { 881 // Create the profile content. 882 std::vector<std::string> methods = { 883 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;", 884 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;", 885 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;", 886 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types", 887 "LTestInline;->noInlineCache(LSuper;)I" 888 }; 889 std::string input_file_contents; 890 for (std::string& m : methods) { 891 input_file_contents += m + std::string("\n"); 892 } 893 894 // Create the profile and save it to disk. 895 ScratchFile profile_file; 896 ASSERT_TRUE(CreateProfile(input_file_contents, 897 profile_file.GetFilename(), 898 GetTestDexFileName("ProfileTestMultiDex"))); 899 900 // Load the profile from disk. 901 ProfileCompilationInfo info; 902 profile_file.GetFile()->ResetOffset(); 903 ASSERT_TRUE(info.Load(GetFd(profile_file))); 904 905 // Load the dex files and verify that the profile contains the expected methods info. 906 ScopedObjectAccess soa(Thread::Current()); 907 jobject class_loader = LoadDex("ProfileTestMultiDex"); 908 ASSERT_NE(class_loader, nullptr); 909 910 mirror::Class* sub_a = GetClass(class_loader, "LSubA;"); 911 mirror::Class* sub_b = GetClass(class_loader, "LSubB;"); 912 mirror::Class* sub_c = GetClass(class_loader, "LSubC;"); 913 914 ASSERT_TRUE(sub_a != nullptr); 915 ASSERT_TRUE(sub_b != nullptr); 916 ASSERT_TRUE(sub_c != nullptr); 917 918 { 919 // Verify that method inlineMonomorphic has the expected inline caches and nothing else. 920 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader, 921 "LTestInline;", 922 "inlineMonomorphic"); 923 ASSERT_TRUE(inline_monomorphic != nullptr); 924 std::set<mirror::Class*> expected_monomorphic; 925 expected_monomorphic.insert(sub_a); 926 AssertInlineCaches(inline_monomorphic, 927 expected_monomorphic, 928 info, 929 /*megamorphic*/false, 930 /*missing_types*/false); 931 } 932 933 { 934 // Verify that method inlinePolymorphic has the expected inline caches and nothing else. 935 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader, 936 "LTestInline;", 937 "inlinePolymorphic"); 938 ASSERT_TRUE(inline_polymorhic != nullptr); 939 std::set<mirror::Class*> expected_polymorphic; 940 expected_polymorphic.insert(sub_a); 941 expected_polymorphic.insert(sub_b); 942 expected_polymorphic.insert(sub_c); 943 AssertInlineCaches(inline_polymorhic, 944 expected_polymorphic, 945 info, 946 /*megamorphic*/false, 947 /*missing_types*/false); 948 } 949 950 { 951 // Verify that method inlineMegamorphic has the expected inline caches and nothing else. 952 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader, 953 "LTestInline;", 954 "inlineMegamorphic"); 955 ASSERT_TRUE(inline_megamorphic != nullptr); 956 std::set<mirror::Class*> expected_megamorphic; 957 AssertInlineCaches(inline_megamorphic, 958 expected_megamorphic, 959 info, 960 /*megamorphic*/true, 961 /*missing_types*/false); 962 } 963 964 { 965 // Verify that method inlineMegamorphic has the expected inline caches and nothing else. 966 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader, 967 "LTestInline;", 968 "inlineMissingTypes"); 969 ASSERT_TRUE(inline_missing_types != nullptr); 970 std::set<mirror::Class*> expected_missing_Types; 971 AssertInlineCaches(inline_missing_types, 972 expected_missing_Types, 973 info, 974 /*megamorphic*/false, 975 /*missing_types*/true); 976 } 977 978 { 979 // Verify that method noInlineCache has no inline caches in the profile. 980 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache"); 981 ASSERT_TRUE(no_inline_cache != nullptr); 982 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache = 983 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(), 984 no_inline_cache->GetDexFile()->GetLocationChecksum(), 985 no_inline_cache->GetDexMethodIndex()); 986 ASSERT_TRUE(pmi_no_inline_cache != nullptr); 987 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty()); 988 } 989 } 990 991 TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) { 992 ScratchFile profile1; 993 ScratchFile reference_profile; 994 995 std::vector<int> profile_fds({GetFd(profile1)}); 996 int reference_profile_fd = GetFd(reference_profile); 997 998 // The new profile info will contain the methods with indices 0-100. 999 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 1000 ProfileCompilationInfo info1; 1001 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1, 1002 /*start_method_index*/0, /*reverse_dex_write_order*/false); 1003 1004 // The reference profile info will contain the methods with indices 50-150. 1005 // When setting up the profile reverse the order in which the dex files 1006 // are added to the profile. This will verify that profman merges profiles 1007 // with a different dex order correctly. 1008 const uint16_t kNumberOfMethodsAlreadyCompiled = 100; 1009 ProfileCompilationInfo reference_info; 1010 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile, 1011 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true); 1012 1013 // We should advise compilation. 1014 ASSERT_EQ(ProfileAssistant::kCompile, 1015 ProcessProfiles(profile_fds, reference_profile_fd)); 1016 1017 // The resulting compilation info must be equal to the merge of the inputs. 1018 ProfileCompilationInfo result; 1019 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 1020 ASSERT_TRUE(result.Load(reference_profile_fd)); 1021 1022 ProfileCompilationInfo expected; 1023 ASSERT_TRUE(expected.MergeWith(reference_info)); 1024 ASSERT_TRUE(expected.MergeWith(info1)); 1025 ASSERT_TRUE(expected.Equals(result)); 1026 1027 // The information from profile must remain the same. 1028 CheckProfileInfo(profile1, info1); 1029 } 1030 1031 TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) { 1032 // Create the profile content. 1033 std::vector<std::string> profile_methods = { 1034 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class", 1035 "LTestInline;->invalid_method", 1036 "invalid_class" 1037 }; 1038 std::string input_file_contents; 1039 for (std::string& m : profile_methods) { 1040 input_file_contents += m + std::string("\n"); 1041 } 1042 1043 // Create the profile and save it to disk. 1044 ScratchFile profile_file; 1045 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex"); 1046 ASSERT_TRUE(CreateProfile(input_file_contents, 1047 profile_file.GetFilename(), 1048 dex_filename)); 1049 1050 // Load the profile from disk. 1051 ProfileCompilationInfo info; 1052 profile_file.GetFile()->ResetOffset(); 1053 ASSERT_TRUE(info.Load(GetFd(profile_file))); 1054 1055 // Load the dex files and verify that the profile contains the expected methods info. 1056 ScopedObjectAccess soa(Thread::Current()); 1057 jobject class_loader = LoadDex("ProfileTestMultiDex"); 1058 ASSERT_NE(class_loader, nullptr); 1059 1060 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader, 1061 "LTestInline;", 1062 "inlineMonomorphic"); 1063 const DexFile* dex_file = inline_monomorphic->GetDexFile(); 1064 1065 // Verify that the inline cache contains the invalid type. 1066 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi = 1067 info.GetMethod(dex_file->GetLocation(), 1068 dex_file->GetLocationChecksum(), 1069 inline_monomorphic->GetDexMethodIndex()); 1070 ASSERT_TRUE(pmi != nullptr); 1071 ASSERT_EQ(pmi->inline_caches->size(), 1u); 1072 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second; 1073 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1); 1074 ASSERT_EQ(1u, dex_pc_data.classes.size()); 1075 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index); 1076 1077 // Verify that the start-up classes contain the invalid class. 1078 std::set<dex::TypeIndex> classes; 1079 std::set<uint16_t> hot_methods; 1080 std::set<uint16_t> startup_methods; 1081 std::set<uint16_t> post_start_methods; 1082 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file, 1083 &classes, 1084 &hot_methods, 1085 &startup_methods, 1086 &post_start_methods)); 1087 ASSERT_EQ(1u, classes.size()); 1088 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end()); 1089 1090 // Verify that the invalid method did not get in the profile. 1091 ASSERT_EQ(1u, hot_methods.size()); 1092 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1; 1093 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end()); 1094 } 1095 1096 TEST_F(ProfileAssistantTest, DumpOnly) { 1097 ScratchFile profile; 1098 1099 const uint32_t kNumberOfMethods = 64; 1100 std::vector<uint32_t> hot_methods; 1101 std::vector<uint32_t> startup_methods; 1102 std::vector<uint32_t> post_startup_methods; 1103 for (size_t i = 0; i < kNumberOfMethods; ++i) { 1104 if (i % 2 == 0) { 1105 hot_methods.push_back(i); 1106 } 1107 if (i % 3 == 1) { 1108 startup_methods.push_back(i); 1109 } 1110 if (i % 4 == 2) { 1111 post_startup_methods.push_back(i); 1112 } 1113 } 1114 EXPECT_GT(hot_methods.size(), 0u); 1115 EXPECT_GT(startup_methods.size(), 0u); 1116 EXPECT_GT(post_startup_methods.size(), 0u); 1117 ProfileCompilationInfo info1; 1118 SetupBasicProfile("p1", 1119 1, 1120 kNumberOfMethods, 1121 hot_methods, 1122 startup_methods, 1123 post_startup_methods, 1124 profile, 1125 &info1); 1126 std::string output; 1127 DumpOnly(profile.GetFilename(), &output); 1128 const size_t hot_offset = output.find("hot methods:"); 1129 const size_t startup_offset = output.find("startup methods:"); 1130 const size_t post_startup_offset = output.find("post startup methods:"); 1131 const size_t classes_offset = output.find("classes:"); 1132 ASSERT_NE(hot_offset, std::string::npos); 1133 ASSERT_NE(startup_offset, std::string::npos); 1134 ASSERT_NE(post_startup_offset, std::string::npos); 1135 ASSERT_LT(hot_offset, startup_offset); 1136 ASSERT_LT(startup_offset, post_startup_offset); 1137 // Check the actual contents of the dump by looking at the offsets of the methods. 1138 for (uint32_t m : hot_methods) { 1139 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset); 1140 ASSERT_NE(pos, std::string::npos); 1141 EXPECT_LT(pos, startup_offset); 1142 } 1143 for (uint32_t m : startup_methods) { 1144 const size_t pos = output.find(std::to_string(m) + ",", startup_offset); 1145 ASSERT_NE(pos, std::string::npos); 1146 EXPECT_LT(pos, post_startup_offset); 1147 } 1148 for (uint32_t m : post_startup_methods) { 1149 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset); 1150 ASSERT_NE(pos, std::string::npos); 1151 EXPECT_LT(pos, classes_offset); 1152 } 1153 } 1154 1155 TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) { 1156 ScratchFile profile1; 1157 ScratchFile profile2; 1158 ScratchFile reference_profile; 1159 1160 std::vector<int> profile_fds({ 1161 GetFd(profile1), 1162 GetFd(profile2)}); 1163 int reference_profile_fd = GetFd(reference_profile); 1164 1165 // Use a real dex file to generate profile test data. 1166 // The file will be used during merging to filter unwanted data. 1167 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex"); 1168 const DexFile& d1 = *dex_files[0]; 1169 const DexFile& d2 = *dex_files[1]; 1170 // The new profile info will contain the methods with indices 0-100. 1171 const uint16_t kNumberOfMethodsToEnableCompilation = 100; 1172 ProfileCompilationInfo info1; 1173 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1, 1174 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1); 1175 ProfileCompilationInfo info2; 1176 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2, 1177 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2); 1178 1179 1180 // The reference profile info will contain the methods with indices 50-150. 1181 const uint16_t kNumberOfMethodsAlreadyCompiled = 100; 1182 ProfileCompilationInfo reference_info; 1183 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1, 1184 kNumberOfMethodsAlreadyCompiled, 0, reference_profile, 1185 &reference_info, kNumberOfMethodsToEnableCompilation / 2); 1186 1187 // Run profman and pass the dex file with --apk-fd. 1188 android::base::unique_fd apk_fd( 1189 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); 1190 ASSERT_GE(apk_fd.get(), 0); 1191 1192 std::string profman_cmd = GetProfmanCmd(); 1193 std::vector<std::string> argv_str; 1194 argv_str.push_back(profman_cmd); 1195 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd())); 1196 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd())); 1197 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); 1198 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); 1199 std::string error; 1200 1201 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error; 1202 1203 // Verify that we can load the result. 1204 1205 ProfileCompilationInfo result; 1206 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 1207 ASSERT_TRUE(result.Load(reference_profile_fd)); 1208 1209 1210 ASSERT_TRUE(profile1.GetFile()->ResetOffset()); 1211 ASSERT_TRUE(profile2.GetFile()->ResetOffset()); 1212 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 1213 1214 // Verify that the result filtered out data not belonging to the dex file. 1215 // This is equivalent to checking that the result is equal to the merging of 1216 // all profiles while filtering out data not belonging to the dex file. 1217 1218 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn = 1219 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool { 1220 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation()) 1221 && checksum == d1.GetLocationChecksum()) 1222 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation()) 1223 && checksum == d2.GetLocationChecksum()); 1224 }; 1225 1226 ProfileCompilationInfo info1_filter; 1227 ProfileCompilationInfo info2_filter; 1228 ProfileCompilationInfo expected; 1229 1230 info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn); 1231 info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn); 1232 expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn); 1233 1234 ASSERT_TRUE(expected.MergeWith(info1_filter)); 1235 ASSERT_TRUE(expected.MergeWith(info2_filter)); 1236 1237 ASSERT_TRUE(expected.Equals(result)); 1238 } 1239 1240 TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) { 1241 ScratchFile profile1; 1242 ScratchFile reference_profile; 1243 1244 // Use a real dex file to generate profile test data. During the copy-and-update the 1245 // matching is done based on checksum so we have to match with the real thing. 1246 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex"); 1247 const DexFile& d1 = *dex_files[0]; 1248 const DexFile& d2 = *dex_files[1]; 1249 1250 ProfileCompilationInfo info1; 1251 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds()); 1252 SetupProfile("fake-location1", 1253 d1.GetLocationChecksum(), 1254 "fake-location2", 1255 d2.GetLocationChecksum(), 1256 num_methods_to_add, 1257 /*num_classes*/ 0, 1258 profile1, 1259 &info1, 1260 /*start_method_index*/ 0, 1261 /*reverse_dex_write_order*/ false, 1262 /*number_of_methods1*/ d1.NumMethodIds(), 1263 /*number_of_methods2*/ d2.NumMethodIds()); 1264 1265 // Run profman and pass the dex file with --apk-fd. 1266 android::base::unique_fd apk_fd( 1267 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); 1268 ASSERT_GE(apk_fd.get(), 0); 1269 1270 std::string profman_cmd = GetProfmanCmd(); 1271 std::vector<std::string> argv_str; 1272 argv_str.push_back(profman_cmd); 1273 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd())); 1274 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd())); 1275 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get())); 1276 argv_str.push_back("--copy-and-update-profile-key"); 1277 std::string error; 1278 1279 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error; 1280 1281 // Verify that we can load the result. 1282 ProfileCompilationInfo result; 1283 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset()); 1284 ASSERT_TRUE(result.Load(reference_profile.GetFd())); 1285 1286 // Verify that the renaming was done. 1287 for (uint16_t i = 0; i < num_methods_to_add; i ++) { 1288 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi; 1289 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i; 1290 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i; 1291 1292 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr); 1293 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr); 1294 } 1295 } 1296 1297 } // namespace art 1298