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