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 "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