• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "profile_assistant.h"
18 
19 #include <sstream>
20 #include <string>
21 
22 #include "android-base/file.h"
23 #include "android-base/strings.h"
24 #include "art_method-inl.h"
25 #include "base/globals.h"
26 #include "base/unix_file/fd_file.h"
27 #include "base/utils.h"
28 #include "common_runtime_test.h"
29 #include "dex/descriptors_names.h"
30 #include "dex/dex_file_structs.h"
31 #include "dex/dex_instruction-inl.h"
32 #include "dex/dex_instruction_iterator.h"
33 #include "dex/type_reference.h"
34 #include "exec_utils.h"
35 #include "gtest/gtest.h"
36 #include "linear_alloc.h"
37 #include "mirror/class-inl.h"
38 #include "obj_ptr-inl.h"
39 #include "profile/profile_compilation_info.h"
40 #include "profile/profile_test_helper.h"
41 #include "profman/profman_result.h"
42 #include "scoped_thread_state_change-inl.h"
43 
44 namespace art {
45 
46 using TypeReferenceSet = std::set<TypeReference, TypeReferenceValueComparator>;
47 
48 // TODO(calin): These tests share a lot with the ProfileCompilationInfo tests.
49 // we should introduce a better abstraction to extract the common parts.
50 class ProfileAssistantTest : public CommonRuntimeTest, public ProfileTestHelper {
51  public:
PostRuntimeCreate()52   void PostRuntimeCreate() override {
53     allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
54 
55     dex1 = BuildDex("location1", /*location_checksum=*/ 1, "LUnique1;", /*num_method_ids=*/ 10001);
56     dex2 = BuildDex("location2", /*location_checksum=*/ 2, "LUnique2;", /*num_method_ids=*/ 10002);
57     dex3 = BuildDex("location3", /*location_checksum=*/ 3, "LUnique3;", /*num_method_ids=*/ 10003);
58     dex4 = BuildDex("location4", /*location_checksum=*/ 4, "LUnique4;", /*num_method_ids=*/ 10004);
59 
60     dex1_checksum_missmatch =
61         BuildDex("location1", /*location_checksum=*/ 12, "LUnique1;", /*num_method_ids=*/ 10001);
62   }
63 
64  protected:
SetupProfile(const DexFile * dex_file1,const DexFile * dex_file2,uint16_t number_of_methods,uint16_t number_of_classes,const ScratchFile & profile,ProfileCompilationInfo * info,uint16_t start_method_index=0,bool reverse_dex_write_order=false)65   void SetupProfile(const DexFile* dex_file1,
66                     const DexFile* dex_file2,
67                     uint16_t number_of_methods,
68                     uint16_t number_of_classes,
69                     const ScratchFile& profile,
70                     ProfileCompilationInfo* info,
71                     uint16_t start_method_index = 0,
72                     bool reverse_dex_write_order = false) {
73     for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
74       // reverse_dex_write_order controls the order in which the dex files will be added to
75       // the profile and thus written to disk.
76       std::vector<ProfileInlineCache> inline_caches =
77           GetTestInlineCaches(dex_file1, dex_file2, dex3);
78       Hotness::Flag flags =
79           static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagPostStartup);
80       if (reverse_dex_write_order) {
81         ASSERT_TRUE(AddMethod(info, dex_file2, i, inline_caches, flags));
82         ASSERT_TRUE(AddMethod(info, dex_file1, i, inline_caches, flags));
83       } else {
84         ASSERT_TRUE(AddMethod(info, dex_file1, i, inline_caches, flags));
85         ASSERT_TRUE(AddMethod(info, dex_file2, i, inline_caches, flags));
86       }
87     }
88     for (uint16_t i = 0; i < number_of_classes; i++) {
89       ASSERT_TRUE(AddClass(info, dex_file1, dex::TypeIndex(i)));
90     }
91 
92     ASSERT_TRUE(info->Save(GetFd(profile)));
93     ASSERT_EQ(0, profile.GetFile()->Flush());
94   }
95 
SetupBasicProfile(const DexFile * dex,const std::vector<uint32_t> & hot_methods,const std::vector<uint32_t> & startup_methods,const std::vector<uint32_t> & post_startup_methods,const ScratchFile & profile,ProfileCompilationInfo * info)96   void SetupBasicProfile(const DexFile* dex,
97                          const std::vector<uint32_t>& hot_methods,
98                          const std::vector<uint32_t>& startup_methods,
99                          const std::vector<uint32_t>& post_startup_methods,
100                          const ScratchFile& profile,
101                          ProfileCompilationInfo* info) {
102     for (uint32_t idx : hot_methods) {
103       AddMethod(info, dex, idx, Hotness::kFlagHot);
104     }
105     for (uint32_t idx : startup_methods) {
106       AddMethod(info, dex, idx, Hotness::kFlagStartup);
107     }
108     for (uint32_t idx : post_startup_methods) {
109       AddMethod(info, dex, idx, Hotness::kFlagPostStartup);
110     }
111     ASSERT_TRUE(info->Save(GetFd(profile)));
112     ASSERT_EQ(0, profile.GetFile()->Flush());
113   }
114 
115   // The dex1_substitute can be used to replace the default dex1 file.
GetTestInlineCaches(const DexFile * dex_file1,const DexFile * dex_file2,const DexFile * dex_file3)116   std::vector<ProfileInlineCache> GetTestInlineCaches(
117         const DexFile* dex_file1, const DexFile* dex_file2, const DexFile* dex_file3) {
118     std::vector<ProfileInlineCache> inline_caches;
119     // Monomorphic
120     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
121       std::vector<TypeReference> types = {TypeReference(dex_file1, dex::TypeIndex(0))};
122       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
123     }
124     // Polymorphic
125     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
126       std::vector<TypeReference> types = {
127           TypeReference(dex_file1, dex::TypeIndex(0)),
128           TypeReference(dex_file2, dex::TypeIndex(1)),
129           TypeReference(dex_file3, dex::TypeIndex(2))};
130       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
131     }
132     // Megamorphic
133     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
134       // we need 5 types to make the cache megamorphic
135       std::vector<TypeReference> types = {
136           TypeReference(dex_file1, dex::TypeIndex(0)),
137           TypeReference(dex_file1, dex::TypeIndex(1)),
138           TypeReference(dex_file1, dex::TypeIndex(2)),
139           TypeReference(dex_file1, dex::TypeIndex(3)),
140           TypeReference(dex_file1, dex::TypeIndex(4))};
141       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
142     }
143     // Missing types
144     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
145       std::vector<TypeReference> types;
146       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ true, types));
147     }
148 
149     return inline_caches;
150   }
151 
GetFd(const ScratchFile & file) const152   int GetFd(const ScratchFile& file) const {
153     return static_cast<int>(file.GetFd());
154   }
155 
CheckProfileInfo(ScratchFile & file,const ProfileCompilationInfo & info)156   void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
157     ProfileCompilationInfo file_info;
158     ASSERT_TRUE(file_info.Load(GetFd(file)));
159     ASSERT_TRUE(file_info.Equals(info));
160   }
161 
GetProfmanCmd()162   std::string GetProfmanCmd() {
163     std::string file_path = GetArtBinDir() + "/profman";
164     if (kIsDebugBuild) {
165       file_path += "d";
166     }
167     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
168     return file_path;
169   }
170 
171   // Runs test with given arguments.
ProcessProfiles(const std::vector<int> & profiles_fd,int reference_profile_fd,const std::vector<const std::string> & extra_args=std::vector<const std::string> ())172   int ProcessProfiles(
173       const std::vector<int>& profiles_fd,
174       int reference_profile_fd,
175       const std::vector<const std::string>& extra_args = std::vector<const std::string>()) {
176     std::string profman_cmd = GetProfmanCmd();
177     std::vector<std::string> argv_str;
178     argv_str.push_back(profman_cmd);
179     for (size_t k = 0; k < profiles_fd.size(); k++) {
180       argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
181     }
182     argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
183     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
184 
185     std::string error;
186     return ExecAndReturnCode(argv_str, &error);
187   }
188 
GenerateTestProfile(const std::string & filename)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 
GenerateTestProfileWithInputDex(const std::string & filename)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 
CreateProfile(const std::string & profile_file_contents,const std::string & filename,const std::string & dex_location,bool for_boot_image=false)210   bool CreateProfile(const std::string& profile_file_contents,
211                      const std::string& filename,
212                      const std::string& dex_location,
213                      bool for_boot_image = false) {
214     ScratchFile class_names_file;
215     File* file = class_names_file.GetFile();
216     EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
217     EXPECT_EQ(0, file->Flush());
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(for_boot_image ? "--output-profile-type=boot" : "--output-profile-type=app");
222     argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
223     argv_str.push_back("--reference-profile-file=" + filename);
224     argv_str.push_back("--apk=" + dex_location);
225     argv_str.push_back("--dex-location=" + dex_location);
226     std::string error;
227     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
228     return true;
229   }
230 
RunProfman(const std::string & filename,std::vector<std::string> & extra_args,std::string * output,std::string_view target_apk)231   bool RunProfman(const std::string& filename,
232                   std::vector<std::string>& extra_args,
233                   std::string* output,
234                   std::string_view target_apk) {
235     ScratchFile output_file;
236     std::string profman_cmd = GetProfmanCmd();
237     std::vector<std::string> argv_str;
238     argv_str.push_back(profman_cmd);
239     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
240     argv_str.push_back("--profile-file=" + filename);
241     argv_str.push_back(std::string("--apk=").append(target_apk));
242     argv_str.push_back(std::string("--dex-location=").append(target_apk));
243     argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
244     std::string error;
245     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
246     File* file = output_file.GetFile();
247     EXPECT_EQ(0, file->Flush());
248     int64_t length = file->GetLength();
249     std::unique_ptr<char[]> buf(new char[length]);
250     EXPECT_EQ(file->Read(buf.get(), length, 0), length);
251     *output = std::string(buf.get(), length);
252     return true;
253   }
254 
DumpClassesAndMethods(const std::string & filename,std::string * file_contents,std::optional<const std::string_view> target=std::nullopt)255   bool DumpClassesAndMethods(const std::string& filename,
256                              std::string* file_contents,
257                              std::optional<const std::string_view> target = std::nullopt) {
258     std::vector<std::string> extra_args;
259     extra_args.push_back("--dump-classes-and-methods");
260     return RunProfman(
261         filename, extra_args, file_contents, target.value_or(GetLibCoreDexFileNames()[0]));
262   }
263 
DumpOnly(const std::string & filename,std::string * file_contents)264   bool DumpOnly(const std::string& filename, std::string* file_contents) {
265     std::vector<std::string> extra_args;
266     extra_args.push_back("--dump-only");
267     return RunProfman(filename, extra_args, file_contents, GetLibCoreDexFileNames()[0]);
268   }
269 
CreateAndDump(const std::string & input_file_contents,std::string * output_file_contents,const std::optional<const std::string> & target=std::nullopt)270   bool CreateAndDump(const std::string& input_file_contents,
271                      std::string* output_file_contents,
272                      const std::optional<const std::string>& target = std::nullopt) {
273     ScratchFile profile_file;
274     EXPECT_TRUE(CreateProfile(input_file_contents,
275                               profile_file.GetFilename(),
276                               target.value_or(GetLibCoreDexFileNames()[0])));
277     EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents, target));
278     return true;
279   }
280 
GetClass(ScopedObjectAccess & soa,jobject class_loader,const std::string & clazz)281   ObjPtr<mirror::Class> GetClass(ScopedObjectAccess& soa,
282                                  jobject class_loader,
283                                  const std::string& clazz) REQUIRES_SHARED(Locks::mutator_lock_) {
284     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
285     StackHandleScope<1> hs(soa.Self());
286     Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
287         ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader))));
288     return class_linker->FindClass(soa.Self(), clazz.c_str(), h_loader);
289   }
290 
GetVirtualMethod(jobject class_loader,const std::string & clazz,const std::string & name)291   ArtMethod* GetVirtualMethod(jobject class_loader,
292                               const std::string& clazz,
293                               const std::string& name) {
294     ScopedObjectAccess soa(Thread::Current());
295     ObjPtr<mirror::Class> klass = GetClass(soa, class_loader, clazz);
296     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
297     const auto pointer_size = class_linker->GetImagePointerSize();
298     ArtMethod* method = nullptr;
299     for (auto& m : klass->GetVirtualMethods(pointer_size)) {
300       if (name == m.GetName()) {
301         EXPECT_TRUE(method == nullptr);
302         method = &m;
303       }
304     }
305     return method;
306   }
307 
MakeTypeReference(ObjPtr<mirror::Class> klass)308   static TypeReference MakeTypeReference(ObjPtr<mirror::Class> klass)
309       REQUIRES_SHARED(Locks::mutator_lock_) {
310     return TypeReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
311   }
312 
313   // Find the first dex-pc in the given method after 'start_pc' (if given) which
314   // contains a call to any method of 'klass'. If 'start_pc' is not given we
315   // will search from the first dex-pc.
GetDexPcOfCallTo(ArtMethod * method,Handle<mirror::Class> klass,std::optional<uint32_t> start_pc=std::nullopt)316   uint16_t GetDexPcOfCallTo(ArtMethod* method,
317                             Handle<mirror::Class> klass,
318                             std::optional<uint32_t> start_pc = std::nullopt)
319       REQUIRES_SHARED(Locks::mutator_lock_) {
320     const DexFile* dex_file = method->GetDexFile();
321     for (const DexInstructionPcPair& inst :
322          CodeItemInstructionAccessor(*dex_file, method->GetCodeItem())) {
323       if (start_pc && inst.DexPc() <= *start_pc) {
324         continue;
325       } else if (inst->IsInvoke()) {
326         const dex::MethodId& method_id = dex_file->GetMethodId(inst->VRegB());
327         std::string_view desc(
328             dex_file->GetTypeDescriptor(dex_file->GetTypeId(method_id.class_idx_)));
329         std::string scratch;
330         if (desc == klass->GetDescriptor(&scratch)) {
331           return inst.DexPc();
332         }
333       }
334     }
335     EXPECT_TRUE(false) << "Unable to find dex-pc in " << method->PrettyMethod() << " for call to "
336                        << klass->PrettyClass()
337                        << " after dexpc: " << (start_pc ? static_cast<int64_t>(*start_pc) : -1);
338     return -1;
339   }
340 
AssertInlineCaches(ArtMethod * method,uint16_t dex_pc,const TypeReferenceSet & expected_classes,const ProfileCompilationInfo & info,bool is_megamorphic,bool is_missing_types)341   void AssertInlineCaches(ArtMethod* method,
342                           uint16_t dex_pc,
343                           const TypeReferenceSet& expected_classes,
344                           const ProfileCompilationInfo& info,
345                           bool is_megamorphic,
346                           bool is_missing_types)
347       REQUIRES_SHARED(Locks::mutator_lock_) {
348     ProfileCompilationInfo::MethodHotness hotness =
349         info.GetMethodHotness(MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
350     ASSERT_TRUE(hotness.IsHot());
351     const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
352     ASSERT_TRUE(inline_caches->find(dex_pc) != inline_caches->end());
353     AssertInlineCaches(expected_classes,
354                        info,
355                        method,
356                        inline_caches->find(dex_pc)->second,
357                        is_megamorphic,
358                        is_missing_types);
359   }
AssertInlineCaches(ArtMethod * method,const TypeReferenceSet & expected_classes,const ProfileCompilationInfo & info,bool is_megamorphic,bool is_missing_types)360   void AssertInlineCaches(ArtMethod* method,
361                           const TypeReferenceSet& expected_classes,
362                           const ProfileCompilationInfo& info,
363                           bool is_megamorphic,
364                           bool is_missing_types)
365       REQUIRES_SHARED(Locks::mutator_lock_) {
366     ProfileCompilationInfo::MethodHotness hotness =
367         info.GetMethodHotness(MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
368     ASSERT_TRUE(hotness.IsHot());
369     const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
370     ASSERT_EQ(inline_caches->size(), 1u);
371     AssertInlineCaches(expected_classes,
372                        info,
373                        method,
374                        inline_caches->begin()->second,
375                        is_megamorphic,
376                        is_missing_types);
377   }
378 
AssertInlineCaches(const TypeReferenceSet & expected_clases,const ProfileCompilationInfo & info,ArtMethod * method,const ProfileCompilationInfo::DexPcData & dex_pc_data,bool is_megamorphic,bool is_missing_types)379   void AssertInlineCaches(const TypeReferenceSet& expected_clases,
380                           const ProfileCompilationInfo& info,
381                           ArtMethod* method,
382                           const ProfileCompilationInfo::DexPcData& dex_pc_data,
383                           bool is_megamorphic,
384                           bool is_missing_types)
385       REQUIRES_SHARED(Locks::mutator_lock_) {
386     ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
387     ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
388     ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
389     const DexFile* dex_file = method->GetDexFile();
390     size_t found = 0;
391     for (const TypeReference& type_ref : expected_clases) {
392       if (type_ref.dex_file == dex_file) {
393         CHECK_LT(type_ref.TypeIndex().index_, dex_file->NumTypeIds());
394         for (dex::TypeIndex type_index : dex_pc_data.classes) {
395           ASSERT_TRUE(type_index.IsValid());
396           if (type_ref.TypeIndex() == type_index) {
397             ++found;
398           }
399         }
400       } else {
401         // Match by descriptor.
402         const char* expected_descriptor =
403             type_ref.dex_file->GetTypeDescriptor(type_ref.TypeIndex());
404         for (dex::TypeIndex type_index : dex_pc_data.classes) {
405           ASSERT_TRUE(type_index.IsValid());
406           const char* descriptor = info.GetTypeDescriptor(dex_file, type_index);
407           if (strcmp(expected_descriptor, descriptor) == 0) {
408             ++found;
409           }
410         }
411       }
412     }
413 
414     ASSERT_EQ(expected_clases.size(), found);
415   }
416 
CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,uint16_t methods_in_ref_profile,const std::vector<const std::string> & extra_args=std::vector<const std::string> ())417   int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
418                                           uint16_t methods_in_ref_profile,
419                                           const std::vector<const std::string>& extra_args =
420                                               std::vector<const std::string>()) {
421     ScratchFile profile;
422     ScratchFile reference_profile;
423     std::vector<int> profile_fds({ GetFd(profile)});
424     int reference_profile_fd = GetFd(reference_profile);
425     std::vector<uint32_t> hot_methods_cur;
426     std::vector<uint32_t> hot_methods_ref;
427     std::vector<uint32_t> empty_vector;
428     for (size_t i = 0; i < methods_in_cur_profile; ++i) {
429       hot_methods_cur.push_back(i);
430     }
431     for (size_t i = 0; i < methods_in_ref_profile; ++i) {
432       hot_methods_ref.push_back(i);
433     }
434     ProfileCompilationInfo info1;
435     SetupBasicProfile(dex1, hot_methods_cur, empty_vector, empty_vector,
436         profile,  &info1);
437     ProfileCompilationInfo info2;
438     SetupBasicProfile(dex1, hot_methods_ref, empty_vector, empty_vector,
439         reference_profile,  &info2);
440     return ProcessProfiles(profile_fds, reference_profile_fd, extra_args);
441   }
442 
CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,uint16_t classes_in_ref_profile,const std::vector<const std::string> & extra_args=std::vector<const std::string> ())443   int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
444                                          uint16_t classes_in_ref_profile,
445                                          const std::vector<const std::string>& extra_args =
446                                              std::vector<const std::string>()) {
447     uint16_t max_classes = std::max(classes_in_cur_profile, classes_in_ref_profile);
448     const DexFile* dex1_x = BuildDex("location1_x",
449                                      /*location_checksum=*/ 0x101,
450                                      "LUnique1_x;",
451                                      /*num_method_ids=*/ 0,
452                                      max_classes);
453     const DexFile* dex2_x = BuildDex("location2_x",
454                                      /*location_checksum=*/ 0x102,
455                                      "LUnique2_x;",
456                                      /*num_method_ids=*/ 0,
457                                      max_classes);
458 
459     ScratchFile profile;
460     ScratchFile reference_profile;
461 
462     std::vector<int> profile_fds({ GetFd(profile)});
463     int reference_profile_fd = GetFd(reference_profile);
464 
465     ProfileCompilationInfo info1;
466     SetupProfile(dex1_x, dex2_x, 0, classes_in_cur_profile, profile,  &info1);
467     ProfileCompilationInfo info2;
468     SetupProfile(dex1_x, dex2_x, 0, classes_in_ref_profile, reference_profile, &info2);
469     return ProcessProfiles(profile_fds, reference_profile_fd, extra_args);
470   }
471 
472   std::unique_ptr<ArenaAllocator> allocator_;
473 
474   const DexFile* dex1;
475   const DexFile* dex2;
476   const DexFile* dex3;
477   const DexFile* dex4;
478   const DexFile* dex1_checksum_missmatch;
479 };
480 
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferences)481 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
482   ScratchFile profile1;
483   ScratchFile profile2;
484   ScratchFile reference_profile;
485 
486   std::vector<int> profile_fds({
487       GetFd(profile1),
488       GetFd(profile2)});
489   int reference_profile_fd = GetFd(reference_profile);
490 
491   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
492   ProfileCompilationInfo info1;
493   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
494   ProfileCompilationInfo info2;
495   SetupProfile(dex3, dex4, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
496 
497   // We should advise compilation.
498   ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd));
499   // The resulting compilation info must be equal to the merge of the inputs.
500   ProfileCompilationInfo result;
501   ASSERT_TRUE(result.Load(reference_profile_fd));
502 
503   ProfileCompilationInfo expected;
504   ASSERT_TRUE(expected.MergeWith(info1));
505   ASSERT_TRUE(expected.MergeWith(info2));
506   ASSERT_TRUE(expected.Equals(result));
507 
508   // The information from profiles must remain the same.
509   CheckProfileInfo(profile1, info1);
510   CheckProfileInfo(profile2, info2);
511 }
512 
513 // TODO(calin): Add more tests for classes.
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferencesBecauseOfClasses)514 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
515   const uint16_t kNumberOfClassesToEnableCompilation = 100;
516   const DexFile* dex1_100 = BuildDex("location1_100",
517                                      /*location_checksum=*/ 101,
518                                      "LUnique1_100;",
519                                      /*num_method_ids=*/ 0,
520                                      /*num_class_ids=*/ 100);
521   const DexFile* dex2_100 = BuildDex("location2_100",
522                                      /*location_checksum=*/ 102,
523                                      "LUnique2_100;",
524                                      /*num_method_ids=*/ 0,
525                                      /*num_class_ids=*/ 100);
526 
527   ScratchFile profile1;
528   ScratchFile reference_profile;
529 
530   std::vector<int> profile_fds({
531       GetFd(profile1)});
532   int reference_profile_fd = GetFd(reference_profile);
533 
534   ProfileCompilationInfo info1;
535   SetupProfile(dex1_100, dex2_100, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
536 
537   // We should advise compilation.
538   ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd));
539   // The resulting compilation info must be equal to the merge of the inputs.
540   ProfileCompilationInfo result;
541   ASSERT_TRUE(result.Load(reference_profile_fd));
542 
543   ProfileCompilationInfo expected;
544   ASSERT_TRUE(expected.MergeWith(info1));
545   ASSERT_TRUE(expected.Equals(result));
546 
547   // The information from profiles must remain the same.
548   CheckProfileInfo(profile1, info1);
549 }
550 
TEST_F(ProfileAssistantTest,AdviseCompilationNonEmptyReferences)551 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
552   ScratchFile profile1;
553   ScratchFile profile2;
554   ScratchFile reference_profile;
555 
556   std::vector<int> profile_fds({
557       GetFd(profile1),
558       GetFd(profile2)});
559   int reference_profile_fd = GetFd(reference_profile);
560 
561   // The new profile info will contain the methods with indices 0-100.
562   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
563   ProfileCompilationInfo info1;
564   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
565   ProfileCompilationInfo info2;
566   SetupProfile(dex3, dex4, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
567 
568 
569   // The reference profile info will contain the methods with indices 50-150.
570   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
571   ProfileCompilationInfo reference_info;
572   SetupProfile(dex1, dex2, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
573       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
574 
575   // We should advise compilation.
576   ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd));
577 
578   // The resulting compilation info must be equal to the merge of the inputs
579   ProfileCompilationInfo result;
580   ASSERT_TRUE(result.Load(reference_profile_fd));
581 
582   ProfileCompilationInfo expected;
583   ASSERT_TRUE(expected.MergeWith(info1));
584   ASSERT_TRUE(expected.MergeWith(info2));
585   ASSERT_TRUE(expected.MergeWith(reference_info));
586   ASSERT_TRUE(expected.Equals(result));
587 
588   // The information from profiles must remain the same.
589   CheckProfileInfo(profile1, info1);
590   CheckProfileInfo(profile2, info2);
591 }
592 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilationEmptyProfile)593 TEST_F(ProfileAssistantTest, DoNotAdviseCompilationEmptyProfile) {
594   ScratchFile profile1;
595   ScratchFile profile2;
596   ScratchFile reference_profile;
597 
598   std::vector<int> profile_fds({
599       GetFd(profile1),
600       GetFd(profile2)});
601   int reference_profile_fd = GetFd(reference_profile);
602 
603   ProfileCompilationInfo info1;
604   SetupProfile(dex1, dex2, /*number_of_methods=*/ 0, /*number_of_classes*/ 0, profile1, &info1);
605   ProfileCompilationInfo info2;
606   SetupProfile(dex3, dex4, /*number_of_methods=*/ 0, /*number_of_classes*/ 0, profile2, &info2);
607 
608   // We should not advise compilation.
609   ASSERT_EQ(ProfmanResult::kSkipCompilationEmptyProfiles,
610             ProcessProfiles(profile_fds, reference_profile_fd));
611 
612   // The information from profiles must remain the same.
613   ProfileCompilationInfo file_info1;
614   ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
615   ASSERT_TRUE(file_info1.Equals(info1));
616 
617   ProfileCompilationInfo file_info2;
618   ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
619   ASSERT_TRUE(file_info2.Equals(info2));
620 
621   // Reference profile files must remain empty.
622   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
623 
624   // The information from profiles must remain the same.
625   CheckProfileInfo(profile1, info1);
626   CheckProfileInfo(profile2, info2);
627 }
628 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilation)629 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
630   ScratchFile profile1;
631   ScratchFile profile2;
632   ScratchFile reference_profile;
633 
634   std::vector<int> profile_fds({
635       GetFd(profile1),
636       GetFd(profile2)});
637   int reference_profile_fd = GetFd(reference_profile);
638 
639   const uint16_t kNumberOfMethodsToSkipCompilation = 24;  // Threshold is 100.
640   ProfileCompilationInfo info1;
641   SetupProfile(dex1, dex2, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
642   ProfileCompilationInfo info2;
643   SetupProfile(dex3, dex4, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
644 
645   // We should not advise compilation.
646   ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta,
647             ProcessProfiles(profile_fds, reference_profile_fd));
648 
649   // The information from profiles must remain the same.
650   ProfileCompilationInfo file_info1;
651   ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
652   ASSERT_TRUE(file_info1.Equals(info1));
653 
654   ProfileCompilationInfo file_info2;
655   ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
656   ASSERT_TRUE(file_info2.Equals(info2));
657 
658   // Reference profile files must remain empty.
659   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
660 
661   // The information from profiles must remain the same.
662   CheckProfileInfo(profile1, info1);
663   CheckProfileInfo(profile2, info2);
664 }
665 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilationMethodPercentage)666 TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
667   const uint16_t kNumberOfMethodsInRefProfile = 6000;
668   const uint16_t kNumberOfMethodsInCurProfile = 6100;  // Threshold is 2%.
669   std::vector<const std::string> extra_args({"--min-new-methods-percent-change=2"});
670 
671   // We should not advise compilation.
672   ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta,
673             CheckCompilationMethodPercentChange(
674                 kNumberOfMethodsInCurProfile, kNumberOfMethodsInRefProfile, extra_args));
675 }
676 
TEST_F(ProfileAssistantTest,ShouldAdviseCompilationMethodPercentage)677 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
678   const uint16_t kNumberOfMethodsInRefProfile = 6000;
679   const uint16_t kNumberOfMethodsInCurProfile = 6200;  // Threshold is 2%.
680   std::vector<const std::string> extra_args({"--min-new-methods-percent-change=2"});
681 
682   // We should advise compilation.
683   ASSERT_EQ(ProfmanResult::kCompile,
684             CheckCompilationMethodPercentChange(
685                 kNumberOfMethodsInCurProfile, kNumberOfMethodsInRefProfile, extra_args));
686 }
687 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilationClassPercentage)688 TEST_F(ProfileAssistantTest, DoNotAdviseCompilationClassPercentage) {
689   const uint16_t kNumberOfClassesInRefProfile = 6000;
690   const uint16_t kNumberOfClassesInCurProfile = 6110;  // Threshold is 2%.
691   std::vector<const std::string> extra_args({"--min-new-classes-percent-change=2"});
692 
693   // We should not advise compilation.
694   ASSERT_EQ(ProfmanResult::kSkipCompilationSmallDelta,
695             CheckCompilationClassPercentChange(
696                 kNumberOfClassesInCurProfile, kNumberOfClassesInRefProfile, extra_args));
697 }
698 
TEST_F(ProfileAssistantTest,ShouldAdviseCompilationClassPercentage)699 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
700   const uint16_t kNumberOfClassesInRefProfile = 6000;
701   const uint16_t kNumberOfClassesInCurProfile = 6120;  // Threshold is 2%.
702   std::vector<const std::string> extra_args({"--min-new-classes-percent-change=2"});
703 
704   // We should advise compilation.
705   ASSERT_EQ(ProfmanResult::kCompile,
706             CheckCompilationClassPercentChange(
707                 kNumberOfClassesInCurProfile, kNumberOfClassesInRefProfile, extra_args));
708 }
709 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfProfiles)710 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
711   ScratchFile profile1;
712   ScratchFile profile2;
713   ScratchFile reference_profile;
714 
715   std::vector<int> profile_fds({
716       GetFd(profile1),
717       GetFd(profile2)});
718   int reference_profile_fd = GetFd(reference_profile);
719 
720   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
721   // Assign different hashes for the same dex file. This will make merging of information to fail.
722   ProfileCompilationInfo info1;
723   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
724   ProfileCompilationInfo info2;
725   SetupProfile(
726       dex1_checksum_missmatch, dex2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
727 
728   // We should fail processing.
729   ASSERT_EQ(ProfmanResult::kErrorBadProfiles, ProcessProfiles(profile_fds, reference_profile_fd));
730 
731   // The information from profiles must remain the same.
732   CheckProfileInfo(profile1, info1);
733   CheckProfileInfo(profile2, info2);
734 
735   // Reference profile files must still remain empty.
736   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
737 }
738 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfReferenceProfiles)739 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
740   ScratchFile profile1;
741   ScratchFile reference_profile;
742 
743   std::vector<int> profile_fds({
744       GetFd(profile1)});
745   int reference_profile_fd = GetFd(reference_profile);
746 
747   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
748   // Assign different hashes for the same dex file. This will make merging of information to fail.
749   ProfileCompilationInfo info1;
750   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
751   ProfileCompilationInfo reference_info;
752   SetupProfile(dex1_checksum_missmatch,
753                dex2,
754                kNumberOfMethodsToEnableCompilation,
755                0,
756                reference_profile,
757                &reference_info);
758 
759   // We should not advise compilation.
760   ASSERT_EQ(ProfmanResult::kErrorBadProfiles, ProcessProfiles(profile_fds, reference_profile_fd));
761 
762   // The information from profiles must remain the same.
763   CheckProfileInfo(profile1, info1);
764 }
765 
TEST_F(ProfileAssistantTest,TestProfileGeneration)766 TEST_F(ProfileAssistantTest, TestProfileGeneration) {
767   ScratchFile profile;
768   // Generate a test profile.
769   GenerateTestProfile(profile.GetFilename());
770 
771   // Verify that the generated profile is valid and can be loaded.
772   ProfileCompilationInfo info;
773   ASSERT_TRUE(info.Load(GetFd(profile)));
774 }
775 
TEST_F(ProfileAssistantTest,TestProfileGenerationWithIndexDex)776 TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
777   ScratchFile profile;
778   // Generate a test profile passing in a dex file as reference.
779   GenerateTestProfileWithInputDex(profile.GetFilename());
780 
781   // Verify that the generated profile is valid and can be loaded.
782   ProfileCompilationInfo info;
783   ASSERT_TRUE(info.Load(GetFd(profile)));
784 }
785 
TEST_F(ProfileAssistantTest,TestProfileCreationAllMatch)786 TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
787   // Class names put here need to be in sorted order.
788   std::vector<std::string> class_names = {
789     "HLjava/lang/Object;-><init>()V",
790     "Ljava/lang/Comparable;",
791     "Ljava/lang/Math;",
792     "Ljava/lang/Object;",
793     "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
794     "[[[[[[[[I",                   // No `TypeId`s in core-oj with this many array dimensions,
795     "[[[[[[[[Ljava/lang/Object;",  // "extra descriptors" shall be used for these array classes.
796   };
797   std::string file_contents;
798   for (std::string& class_name : class_names) {
799     file_contents += class_name + std::string("\n");
800   }
801   std::string output_file_contents;
802   ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
803   ASSERT_EQ(output_file_contents, file_contents);
804 }
805 
TEST_F(ProfileAssistantTest,TestArrayClass)806 TEST_F(ProfileAssistantTest, TestArrayClass) {
807   std::vector<std::string> class_names = {
808     "[Ljava/lang/Comparable;",
809   };
810   std::string file_contents;
811   for (std::string& class_name : class_names) {
812     file_contents += class_name + std::string("\n");
813   }
814   std::string output_file_contents;
815   ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
816   ASSERT_EQ(output_file_contents, file_contents);
817 }
818 
TEST_F(ProfileAssistantTest,TestProfileCreationGenerateMethods)819 TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
820   // Class names put here need to be in sorted order.
821   std::vector<std::string> class_names = {
822     "HLjava/lang/Math;->*",
823   };
824   std::string input_file_contents;
825   std::string expected_contents;
826   for (std::string& class_name : class_names) {
827     input_file_contents += class_name + std::string("\n");
828     expected_contents += DescriptorToDot(class_name.c_str()) +
829         std::string("\n");
830   }
831   std::string output_file_contents;
832   ScratchFile profile_file;
833   EXPECT_TRUE(CreateProfile(input_file_contents,
834                             profile_file.GetFilename(),
835                             GetLibCoreDexFileNames()[0]));
836   ProfileCompilationInfo info;
837   ASSERT_TRUE(info.Load(GetFd(profile_file)));
838   // Verify that the profile has matching methods.
839   ScopedObjectAccess soa(Thread::Current());
840   ObjPtr<mirror::Class> klass = GetClass(soa, /*class_loader=*/ nullptr, "Ljava/lang/Math;");
841   ASSERT_TRUE(klass != nullptr);
842   size_t method_count = 0;
843   for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
844     if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
845       ++method_count;
846       ProfileCompilationInfo::MethodHotness hotness =
847           info.GetMethodHotness(MethodReference(method.GetDexFile(), method.GetDexMethodIndex()));
848       ASSERT_TRUE(hotness.IsHot()) << method.PrettyMethod();
849     }
850   }
851   EXPECT_GT(method_count, 0u);
852 }
853 
JoinProfileLines(const std::vector<std::string> & lines)854 static std::string JoinProfileLines(const std::vector<std::string>& lines) {
855   std::string result = android::base::Join(lines, '\n');
856   return result + '\n';
857 }
858 
TEST_F(ProfileAssistantTest,TestBootImageProfile)859 TEST_F(ProfileAssistantTest, TestBootImageProfile) {
860   const std::string core_dex = GetLibCoreDexFileNames()[0];
861 
862   std::vector<ScratchFile> profiles;
863 
864   // In image with enough clean occurrences.
865   const std::string kCleanClass = "Ljava/lang/CharSequence;";
866   // In image with enough dirty occurrences.
867   const std::string kDirtyClass = "Ljava/lang/Object;";
868   // Not in image becauseof not enough occurrences.
869   const std::string kUncommonCleanClass = "Ljava/lang/Process;";
870   const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
871   // Method that is common and hot. Should end up in profile.
872   const std::string kCommonHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
873   // Uncommon method, should not end up in profile
874   const std::string kUncommonMethod = "Ljava/util/HashMap;-><init>()V";
875   // Method that gets marked as hot since it's in multiple profile and marked as startup.
876   const std::string kStartupMethodForUpgrade = "Ljava/util/ArrayList;->clear()V";
877   // Startup method used by a special package which will get a different threshold;
878   const std::string kSpecialPackageStartupMethod =
879       "Ljava/lang/Object;->toString()Ljava/lang/String;";
880   // Method used by a special package which will get a different threshold;
881   const std::string kUncommonSpecialPackageMethod = "Ljava/lang/Object;->hashCode()I";
882   // Denylisted class
883   const std::string kPreloadedDenylistedClass = "Ljava/lang/Thread;";
884 
885   // Thresholds for this test.
886   static const size_t kDirtyThreshold = 100;
887   static const size_t kCleanThreshold = 50;
888   static const size_t kPreloadedThreshold = 100;
889   static const size_t kMethodThreshold = 75;
890   static const size_t kSpecialThreshold = 50;
891   const std::string kSpecialPackage = "dex4";
892 
893   // Create boot profile content, attributing the classes and methods to different dex files.
894   std::vector<std::string> input_data = {
895       "{dex1}" + kCleanClass,
896       "{dex1}" + kDirtyClass,
897       "{dex1}" + kUncommonCleanClass,
898       "{dex1}H" + kCommonHotMethod,
899       "{dex1}P" + kStartupMethodForUpgrade,
900       "{dex1}" + kUncommonDirtyClass,
901       "{dex1}" + kPreloadedDenylistedClass,
902 
903       "{dex2}" + kCleanClass,
904       "{dex2}" + kDirtyClass,
905       "{dex2}P" + kCommonHotMethod,
906       "{dex2}P" + kStartupMethodForUpgrade,
907       "{dex2}" + kUncommonDirtyClass,
908       "{dex2}" + kPreloadedDenylistedClass,
909 
910       "{dex3}P" + kUncommonMethod,
911       "{dex3}PS" + kStartupMethodForUpgrade,
912       "{dex3}S" + kCommonHotMethod,
913       "{dex3}S" + kSpecialPackageStartupMethod,
914       "{dex3}" + kDirtyClass,
915       "{dex3}" + kPreloadedDenylistedClass,
916 
917       "{dex4}" + kDirtyClass,
918       "{dex4}P" + kCommonHotMethod,
919       "{dex4}S" + kSpecialPackageStartupMethod,
920       "{dex4}P" + kUncommonSpecialPackageMethod,
921       "{dex4}" + kPreloadedDenylistedClass,
922   };
923   std::string input_file_contents = JoinProfileLines(input_data);
924 
925   ScratchFile preloaded_class_denylist;
926   std::string denylist_content = DescriptorToDot(kPreloadedDenylistedClass.c_str());
927   EXPECT_TRUE(preloaded_class_denylist.GetFile()->WriteFully(
928       denylist_content.c_str(), denylist_content.length()));
929 
930   EXPECT_EQ(0, preloaded_class_denylist.GetFile()->Flush());
931   // Expected data
932   std::vector<std::string> expected_data = {
933       kCleanClass,
934       kDirtyClass,
935       kPreloadedDenylistedClass,
936       "HSP" + kCommonHotMethod,
937       "HS" + kSpecialPackageStartupMethod,
938       "HSP" + kStartupMethodForUpgrade
939   };
940   std::string expected_profile_content = JoinProfileLines(expected_data);
941 
942   std::vector<std::string> expected_preloaded_data = {
943        DescriptorToDot(kDirtyClass.c_str())
944   };
945   std::string expected_preloaded_content = JoinProfileLines(expected_preloaded_data);
946 
947   ScratchFile profile;
948   EXPECT_TRUE(CreateProfile(input_file_contents,
949                             profile.GetFilename(),
950                             core_dex,
951                             /*for_boot_image=*/ true));
952 
953   ProfileCompilationInfo bootProfile(/*for_boot_image=*/ true);
954   EXPECT_TRUE(bootProfile.Load(profile.GetFilename(), /*clear_if_invalid=*/ false));
955 
956   // Generate the boot profile.
957   ScratchFile out_profile;
958   ScratchFile out_preloaded_classes;
959   std::vector<std::string> args;
960   args.push_back(GetProfmanCmd());
961   args.push_back("--generate-boot-image-profile");
962   args.push_back("--class-threshold=" + std::to_string(kDirtyThreshold));
963   args.push_back("--clean-class-threshold=" + std::to_string(kCleanThreshold));
964   args.push_back("--method-threshold=" + std::to_string(kMethodThreshold));
965   args.push_back("--preloaded-class-threshold=" + std::to_string(kPreloadedThreshold));
966   args.push_back(
967       "--special-package=" + kSpecialPackage + ":" + std::to_string(kSpecialThreshold));
968   args.push_back("--profile-file=" + profile.GetFilename());
969   args.push_back("--out-profile-path=" + out_profile.GetFilename());
970   args.push_back("--out-preloaded-classes-path=" + out_preloaded_classes.GetFilename());
971   args.push_back("--apk=" + core_dex);
972   args.push_back("--dex-location=" + core_dex);
973   args.push_back("--preloaded-classes-denylist=" + preloaded_class_denylist.GetFilename());
974 
975   std::string error;
976   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error;
977 
978   // Verify the boot profile contents.
979   std::string output_profile_contents;
980   ASSERT_TRUE(android::base::ReadFileToString(
981       out_profile.GetFilename(), &output_profile_contents));
982   ASSERT_EQ(output_profile_contents, expected_profile_content);
983 
984     // Verify the preloaded classes content.
985   std::string output_preloaded_contents;
986   ASSERT_TRUE(android::base::ReadFileToString(
987       out_preloaded_classes.GetFilename(), &output_preloaded_contents));
988   ASSERT_EQ(output_preloaded_contents, expected_preloaded_content);
989 }
990 
TEST_F(ProfileAssistantTest,TestBootImageProfileWith2RawProfiles)991 TEST_F(ProfileAssistantTest, TestBootImageProfileWith2RawProfiles) {
992   const std::string core_dex = GetLibCoreDexFileNames()[0];
993 
994   std::vector<ScratchFile> profiles;
995 
996   const std::string kCommonClassUsedByDex1 = "Ljava/lang/CharSequence;";
997   const std::string kCommonClassUsedByDex1Dex2 = "Ljava/lang/Object;";
998   const std::string kUncommonClass = "Ljava/lang/Process;";
999   const std::string kCommonHotMethodUsedByDex1 =
1000       "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
1001   const std::string kCommonHotMethodUsedByDex1Dex2 = "Ljava/lang/Object;->hashCode()I";
1002   const std::string kUncommonHotMethod = "Ljava/util/HashMap;-><init>()V";
1003 
1004 
1005   // Thresholds for this test.
1006   static const size_t kDirtyThreshold = 100;
1007   static const size_t kCleanThreshold = 100;
1008   static const size_t kMethodThreshold = 100;
1009 
1010     // Create boot profile content, attributing the classes and methods to different dex files.
1011   std::vector<std::string> input_data1 = {
1012       "{dex1}" + kCommonClassUsedByDex1,
1013       "{dex1}" + kCommonClassUsedByDex1Dex2,
1014       "{dex1}" + kUncommonClass,
1015       "{dex1}H" + kCommonHotMethodUsedByDex1Dex2,
1016       "{dex1}" + kCommonHotMethodUsedByDex1,
1017   };
1018   std::vector<std::string> input_data2 = {
1019       "{dex1}" + kCommonClassUsedByDex1,
1020       "{dex2}" + kCommonClassUsedByDex1Dex2,
1021       "{dex1}H" + kCommonHotMethodUsedByDex1,
1022       "{dex2}" + kCommonHotMethodUsedByDex1Dex2,
1023       "{dex1}" + kUncommonHotMethod,
1024   };
1025   std::string input_file_contents1 = JoinProfileLines(input_data1);
1026   std::string input_file_contents2 = JoinProfileLines(input_data2);
1027 
1028   // Expected data
1029   std::vector<std::string> expected_data = {
1030       kCommonClassUsedByDex1,
1031       kCommonClassUsedByDex1Dex2,
1032       "H" + kCommonHotMethodUsedByDex1,
1033       "H" + kCommonHotMethodUsedByDex1Dex2
1034   };
1035   std::string expected_profile_content = JoinProfileLines(expected_data);
1036 
1037   ScratchFile profile1;
1038   ScratchFile profile2;
1039   EXPECT_TRUE(CreateProfile(input_file_contents1,
1040                             profile1.GetFilename(),
1041                             core_dex,
1042                             /*for_boot_image=*/ true));
1043   EXPECT_TRUE(CreateProfile(input_file_contents2,
1044                             profile2.GetFilename(),
1045                             core_dex,
1046                             /*for_boot_image=*/ true));
1047 
1048   ProfileCompilationInfo boot_profile1(/*for_boot_image=*/ true);
1049   ProfileCompilationInfo boot_profile2(/*for_boot_image=*/ true);
1050   EXPECT_TRUE(boot_profile1.Load(profile1.GetFilename(), /*clear_if_invalid=*/ false));
1051   EXPECT_TRUE(boot_profile2.Load(profile2.GetFilename(), /*clear_if_invalid=*/ false));
1052 
1053   // Generate the boot profile.
1054   ScratchFile out_profile;
1055   ScratchFile out_preloaded_classes;
1056   std::vector<std::string> args;
1057   args.push_back(GetProfmanCmd());
1058   args.push_back("--generate-boot-image-profile");
1059   args.push_back("--class-threshold=" + std::to_string(kDirtyThreshold));
1060   args.push_back("--clean-class-threshold=" + std::to_string(kCleanThreshold));
1061   args.push_back("--method-threshold=" + std::to_string(kMethodThreshold));
1062   args.push_back("--profile-file=" + profile1.GetFilename());
1063   args.push_back("--profile-file=" + profile2.GetFilename());
1064   args.push_back("--out-profile-path=" + out_profile.GetFilename());
1065   args.push_back("--out-preloaded-classes-path=" + out_preloaded_classes.GetFilename());
1066   args.push_back("--apk=" + core_dex);
1067   args.push_back("--dex-location=" + core_dex);
1068 
1069   std::string error;
1070   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error;
1071 
1072   // Verify the boot profile contents.
1073   std::string output_profile_contents;
1074   ASSERT_TRUE(android::base::ReadFileToString(
1075       out_profile.GetFilename(), &output_profile_contents));
1076   ASSERT_EQ(output_profile_contents, expected_profile_content);
1077 }
1078 
TEST_F(ProfileAssistantTest,TestProfileCreationOneNotMatched)1079 TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
1080   // Class names put here need to be in sorted order.
1081   std::vector<std::string> class_names = {
1082     "Ldoesnt/match/this/one;",
1083     "Ljava/lang/Comparable;",
1084     "Ljava/lang/Object;"
1085   };
1086   std::string input_file_contents;
1087   for (std::string& class_name : class_names) {
1088     input_file_contents += class_name + std::string("\n");
1089   }
1090   std::string output_file_contents;
1091   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
1092   std::string expected_contents =
1093       class_names[1] + std::string("\n") +
1094       class_names[2] + std::string("\n");
1095   ASSERT_EQ(output_file_contents, expected_contents);
1096 }
1097 
TEST_F(ProfileAssistantTest,TestProfileCreationNoneMatched)1098 TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
1099   // Class names put here need to be in sorted order.
1100   std::vector<std::string> class_names = {
1101     "Ldoesnt/match/this/one;",
1102     "Ldoesnt/match/this/one/either;",
1103     "Lnor/this/one;"
1104   };
1105   std::string input_file_contents;
1106   for (std::string& class_name : class_names) {
1107     input_file_contents += class_name + std::string("\n");
1108   }
1109   std::string output_file_contents;
1110   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
1111   std::string expected_contents("");
1112   ASSERT_EQ(output_file_contents, expected_contents);
1113 }
1114 
1115 // Test that we can dump profiles in a way they can be re-constituted.
1116 // Test goes 'txt -> prof -> txt -> prof' and then compares the two profs.
TEST_F(ProfileAssistantTest,TestProfileRoundTrip)1117 TEST_F(ProfileAssistantTest, TestProfileRoundTrip) {
1118   // Create the profile content.
1119   std::vector<std::string_view> methods = {
1120     "HLTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
1121     "HLTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
1122     "HLTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
1123     "HLTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
1124     "HLTestInline;->noInlineCache(LSuper;)I",
1125     "HLTestInline;->inlineMultiMonomorphic(LSuper;LSecret;)I+]LSuper;LSubA;]LSecret;LSubB;",
1126     "HLTestInline;->inlineMultiPolymorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1127     "HLTestInline;->inlineMultiMegamorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;,LSubD;,LSubE;]LSecret;megamorphic_types",
1128     "HLTestInline;->inlineMultiMissingTypes(LSuper;LSecret;)I+]LSuper;missing_types]LSecret;missing_types",
1129     "HLTestInline;->inlineTriplePolymorphic(LSuper;LSecret;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1130     "HLTestInline;->noInlineCacheMulti(LSuper;LSecret;)I",
1131   };
1132   std::ostringstream input_file_contents;
1133   for (const std::string_view& m : methods) {
1134     input_file_contents << m << "\n";
1135   }
1136 
1137   // Create the profile and save it to disk.
1138   ScratchFile profile_file;
1139   ASSERT_TRUE(CreateProfile(input_file_contents.str(),
1140                             profile_file.GetFilename(),
1141                             GetTestDexFileName("ProfileTestMultiDex")));
1142 
1143   // Dump the file back into text.
1144   std::string text_two;
1145   ASSERT_TRUE(DumpClassesAndMethods(
1146       profile_file.GetFilename(), &text_two, GetTestDexFileName("ProfileTestMultiDex")));
1147 
1148   // Create another profile and save it to the disk as well.
1149   ScratchFile profile_two;
1150   ASSERT_TRUE(CreateProfile(
1151       text_two, profile_two.GetFilename(), GetTestDexFileName("ProfileTestMultiDex")));
1152 
1153   // These two profiles should be bit-identical.
1154   // TODO We could compare the 'text_two' to the methods but since the order is
1155   // arbitrary for many parts and there are multiple 'correct' dumps we'd need
1156   // to basically parse everything and this is simply easier.
1157   std::string error;
1158   std::vector<std::string> args { kIsTargetBuild ? "/system/bin/cmp" : "/usr/bin/cmp",
1159                                   "-s",
1160                                   profile_file.GetFilename(),
1161                                   profile_two.GetFilename() };
1162   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error << " from " << text_two;
1163 }
1164 
1165 
1166 // Test that we can dump profiles in a way they can be re-constituted and
1167 // annotations don't interfere. Test goes 'txt -> ProfileWithAnnotations -> txt
1168 // -> prof' and then compares that to one that is 'txt ->
1169 // prof_without_annotations'.
TEST_F(ProfileAssistantTest,TestProfileRoundTripWithAnnotations)1170 TEST_F(ProfileAssistantTest, TestProfileRoundTripWithAnnotations) {
1171   // Create the profile content.
1172   std::vector<std::string_view> methods = {
1173     "HLTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
1174     "HLTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
1175     "HLTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
1176     "HLTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
1177     "HLTestInline;->noInlineCache(LSuper;)I",
1178     "HLTestInline;->inlineMultiMonomorphic(LSuper;LSecret;)I+]LSuper;LSubA;]LSecret;LSubB;",
1179     "HLTestInline;->inlineMultiPolymorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1180     "HLTestInline;->inlineMultiMegamorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;,LSubD;,LSubE;]LSecret;megamorphic_types",
1181     "HLTestInline;->inlineMultiMissingTypes(LSuper;LSecret;)I+]LSuper;missing_types]LSecret;missing_types",
1182     "HLTestInline;->inlineTriplePolymorphic(LSuper;LSecret;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1183     "HLTestInline;->noInlineCacheMulti(LSuper;LSecret;)I",
1184   };
1185   std::ostringstream no_annotation_input_file_contents;
1186   std::ostringstream with_annotation_input_file_contents;
1187   for (const std::string_view& m : methods) {
1188     no_annotation_input_file_contents << m << "\n";
1189     with_annotation_input_file_contents << "{foobar}" << m << "\n";
1190   }
1191 
1192   // Create the profile and save it to disk.
1193   ScratchFile with_annotation_profile_file;
1194   ASSERT_TRUE(CreateProfile(with_annotation_input_file_contents.str(),
1195                             with_annotation_profile_file.GetFilename(),
1196                             GetTestDexFileName("ProfileTestMultiDex")));
1197 
1198   ScratchFile no_annotation_profile_file;
1199   ASSERT_TRUE(CreateProfile(no_annotation_input_file_contents.str(),
1200                             no_annotation_profile_file.GetFilename(),
1201                             GetTestDexFileName("ProfileTestMultiDex")));
1202 
1203   // Dump the file back into text.
1204   std::string text_two;
1205   ASSERT_TRUE(DumpClassesAndMethods(with_annotation_profile_file.GetFilename(),
1206                                     &text_two,
1207                                     GetTestDexFileName("ProfileTestMultiDex")));
1208 
1209   // Create another profile and save it to the disk as well.
1210   ScratchFile profile_two;
1211   ASSERT_TRUE(CreateProfile(
1212       text_two, profile_two.GetFilename(), GetTestDexFileName("ProfileTestMultiDex")));
1213 
1214   // These two profiles should be bit-identical.
1215   // TODO We could compare the 'text_two' to the methods but since the order is
1216   // arbitrary for many parts and there are multiple 'correct' dumps we'd need
1217   // to basically parse everything and this is simply easier.
1218   std::string error;
1219   std::vector<std::string> args { kIsTargetBuild ? "/system/bin/cmp" : "/usr/bin/cmp",
1220                                   "-s",
1221                                   no_annotation_profile_file.GetFilename(),
1222                                   profile_two.GetFilename() };
1223   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error << " from " << text_two;
1224 }
1225 
TEST_F(ProfileAssistantTest,TestProfileCreateInlineCache)1226 TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
1227   // Create the profile content.
1228   std::vector<std::string_view> methods = {
1229     "HLTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
1230     "HLTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
1231     "HLTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
1232     "HLTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
1233     "HLTestInline;->noInlineCache(LSuper;)I",
1234     "HLTestInline;->inlineMultiMonomorphic(LSuper;LSecret;)I+]LSuper;LSubA;]LSecret;LSubB;",
1235     "HLTestInline;->inlineMultiPolymorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1236     "HLTestInline;->inlineMultiMegamorphic(LSuper;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;,LSubD;,LSubE;]LSecret;LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
1237     "HLTestInline;->inlineMultiMissingTypes(LSuper;LSecret;)I+]LSuper;missing_types]LSecret;missing_types",
1238     "HLTestInline;->inlineTriplePolymorphic(LSuper;LSecret;LSecret;)I+]LSuper;LSubA;,LSubB;,LSubC;]LSecret;LSubB;,LSubC;",
1239     "HLTestInline;->noInlineCacheMulti(LSuper;LSecret;)I",
1240   };
1241   std::ostringstream input_file_contents;
1242   for (const std::string_view& m : methods) {
1243     input_file_contents << m << "\n";
1244   }
1245 
1246   // Create the profile and save it to disk.
1247   ScratchFile profile_file;
1248   ASSERT_TRUE(CreateProfile(input_file_contents.str(),
1249                             profile_file.GetFilename(),
1250                             GetTestDexFileName("ProfileTestMultiDex")));
1251 
1252   // Load the profile from disk.
1253   ProfileCompilationInfo info;
1254   ASSERT_TRUE(info.Load(GetFd(profile_file)));
1255 
1256   // Load the dex files and verify that the profile contains the expected methods info.
1257   ScopedObjectAccess soa(Thread::Current());
1258   jobject class_loader = LoadDex("ProfileTestMultiDex");
1259   ASSERT_NE(class_loader, nullptr);
1260 
1261   StackHandleScope<5> hs(soa.Self());
1262   Handle<mirror::Class> super_klass = hs.NewHandle(GetClass(soa, class_loader, "LSuper;"));
1263   Handle<mirror::Class> secret_klass = hs.NewHandle(GetClass(soa, class_loader, "LSecret;"));
1264   Handle<mirror::Class> sub_a = hs.NewHandle(GetClass(soa, class_loader, "LSubA;"));
1265   Handle<mirror::Class> sub_b = hs.NewHandle(GetClass(soa, class_loader, "LSubB;"));
1266   Handle<mirror::Class> sub_c = hs.NewHandle(GetClass(soa, class_loader, "LSubC;"));
1267 
1268   ASSERT_TRUE(super_klass != nullptr);
1269   ASSERT_TRUE(secret_klass != nullptr);
1270   ASSERT_TRUE(sub_a != nullptr);
1271   ASSERT_TRUE(sub_b != nullptr);
1272   ASSERT_TRUE(sub_c != nullptr);
1273 
1274   {
1275     // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
1276     ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1277                                                      "LTestInline;",
1278                                                      "inlineMonomorphic");
1279     ASSERT_TRUE(inline_monomorphic != nullptr);
1280     TypeReferenceSet expected_monomorphic;
1281     expected_monomorphic.insert(MakeTypeReference(sub_a.Get()));
1282     AssertInlineCaches(inline_monomorphic,
1283                        expected_monomorphic,
1284                        info,
1285                        /*is_megamorphic=*/false,
1286                        /*is_missing_types=*/false);
1287   }
1288 
1289   {
1290     // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
1291     ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
1292                                                     "LTestInline;",
1293                                                     "inlinePolymorphic");
1294     ASSERT_TRUE(inline_polymorhic != nullptr);
1295     TypeReferenceSet expected_polymorphic;
1296     expected_polymorphic.insert(MakeTypeReference(sub_a.Get()));
1297     expected_polymorphic.insert(MakeTypeReference(sub_b.Get()));
1298     expected_polymorphic.insert(MakeTypeReference(sub_c.Get()));
1299     AssertInlineCaches(inline_polymorhic,
1300                        expected_polymorphic,
1301                        info,
1302                        /*is_megamorphic=*/false,
1303                        /*is_missing_types=*/false);
1304   }
1305 
1306   {
1307     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1308     ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
1309                                                      "LTestInline;",
1310                                                      "inlineMegamorphic");
1311     ASSERT_TRUE(inline_megamorphic != nullptr);
1312     TypeReferenceSet expected_megamorphic;
1313     AssertInlineCaches(inline_megamorphic,
1314                        expected_megamorphic,
1315                        info,
1316                        /*is_megamorphic=*/true,
1317                        /*is_missing_types=*/false);
1318   }
1319 
1320   {
1321     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1322     ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
1323                                                        "LTestInline;",
1324                                                        "inlineMissingTypes");
1325     ASSERT_TRUE(inline_missing_types != nullptr);
1326     TypeReferenceSet expected_missing_Types;
1327     AssertInlineCaches(inline_missing_types,
1328                        expected_missing_Types,
1329                        info,
1330                        /*is_megamorphic=*/false,
1331                        /*is_missing_types=*/true);
1332   }
1333 
1334   {
1335     // Verify that method noInlineCache has no inline caches in the profile.
1336     ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
1337     ASSERT_TRUE(no_inline_cache != nullptr);
1338     ProfileCompilationInfo::MethodHotness hotness_no_inline_cache = info.GetMethodHotness(
1339         MethodReference(no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex()));
1340     ASSERT_TRUE(hotness_no_inline_cache.IsHot());
1341     ASSERT_TRUE(hotness_no_inline_cache.GetInlineCacheMap()->empty());
1342   }
1343 
1344   {
1345     // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
1346     ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1347                                                      "LTestInline;",
1348                                                      "inlineMultiMonomorphic");
1349     ASSERT_TRUE(inline_monomorphic != nullptr);
1350     TypeReferenceSet expected_monomorphic_super;
1351     TypeReferenceSet expected_monomorphic_secret;
1352     expected_monomorphic_super.insert(MakeTypeReference(sub_a.Get()));
1353     expected_monomorphic_secret.insert(MakeTypeReference(sub_b.Get()));
1354     AssertInlineCaches(inline_monomorphic,
1355                        GetDexPcOfCallTo(inline_monomorphic, super_klass),
1356                        expected_monomorphic_super,
1357                        info,
1358                        /*is_megamorphic=*/false,
1359                        /*is_missing_types=*/false);
1360     AssertInlineCaches(inline_monomorphic,
1361                        GetDexPcOfCallTo(inline_monomorphic, secret_klass),
1362                        expected_monomorphic_secret,
1363                        info,
1364                        /*is_megamorphic=*/false,
1365                        /*is_missing_types=*/false);
1366   }
1367 
1368   {
1369     // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
1370     ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
1371                                                     "LTestInline;",
1372                                                     "inlineMultiPolymorphic");
1373     ASSERT_TRUE(inline_polymorhic != nullptr);
1374     TypeReferenceSet expected_polymorphic_super;
1375     expected_polymorphic_super.insert(MakeTypeReference(sub_a.Get()));
1376     expected_polymorphic_super.insert(MakeTypeReference(sub_b.Get()));
1377     expected_polymorphic_super.insert(MakeTypeReference(sub_c.Get()));
1378     TypeReferenceSet expected_polymorphic_secret;
1379     expected_polymorphic_secret.insert(MakeTypeReference(sub_b.Get()));
1380     expected_polymorphic_secret.insert(MakeTypeReference(sub_c.Get()));
1381     AssertInlineCaches(inline_polymorhic,
1382                        GetDexPcOfCallTo(inline_polymorhic, super_klass),
1383                        expected_polymorphic_super,
1384                        info,
1385                        /*is_megamorphic=*/false,
1386                        /*is_missing_types=*/false);
1387     AssertInlineCaches(inline_polymorhic,
1388                        GetDexPcOfCallTo(inline_polymorhic, secret_klass),
1389                        expected_polymorphic_secret,
1390                        info,
1391                        /*is_megamorphic=*/false,
1392                        /*is_missing_types=*/false);
1393   }
1394 
1395   {
1396     // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
1397     ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
1398                                                     "LTestInline;",
1399                                                     "inlineTriplePolymorphic");
1400     ASSERT_TRUE(inline_polymorhic != nullptr);
1401     TypeReferenceSet expected_polymorphic_super;
1402     expected_polymorphic_super.insert(MakeTypeReference(sub_a.Get()));
1403     expected_polymorphic_super.insert(MakeTypeReference(sub_b.Get()));
1404     expected_polymorphic_super.insert(MakeTypeReference(sub_c.Get()));
1405     TypeReferenceSet expected_polymorphic_secret;
1406     expected_polymorphic_secret.insert(MakeTypeReference(sub_b.Get()));
1407     expected_polymorphic_secret.insert(MakeTypeReference(sub_c.Get()));
1408     AssertInlineCaches(inline_polymorhic,
1409                        GetDexPcOfCallTo(inline_polymorhic, super_klass),
1410                        expected_polymorphic_super,
1411                        info,
1412                        /*is_megamorphic=*/false,
1413                        /*is_missing_types=*/false);
1414     uint16_t first_call = GetDexPcOfCallTo(inline_polymorhic, secret_klass);
1415     AssertInlineCaches(inline_polymorhic,
1416                        first_call,
1417                        expected_polymorphic_secret,
1418                        info,
1419                        /*is_megamorphic=*/false,
1420                        /*is_missing_types=*/false);
1421     uint16_t second_call = GetDexPcOfCallTo(inline_polymorhic, secret_klass, first_call);
1422     ASSERT_LT(first_call, second_call);
1423     AssertInlineCaches(inline_polymorhic,
1424                        second_call,
1425                        expected_polymorphic_secret,
1426                        info,
1427                        /*is_megamorphic=*/false,
1428                        /*is_missing_types=*/false);
1429   }
1430 
1431   {
1432     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1433     ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
1434                                                      "LTestInline;",
1435                                                      "inlineMultiMegamorphic");
1436     ASSERT_TRUE(inline_megamorphic != nullptr);
1437     TypeReferenceSet expected_megamorphic;
1438     AssertInlineCaches(inline_megamorphic,
1439                        GetDexPcOfCallTo(inline_megamorphic, super_klass),
1440                        expected_megamorphic,
1441                        info,
1442                        /*is_megamorphic=*/true,
1443                        /*is_missing_types=*/false);
1444     AssertInlineCaches(inline_megamorphic,
1445                        GetDexPcOfCallTo(inline_megamorphic, secret_klass),
1446                        expected_megamorphic,
1447                        info,
1448                        /*is_megamorphic=*/true,
1449                        /*is_missing_types=*/false);
1450   }
1451 
1452   {
1453     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1454     ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
1455                                                        "LTestInline;",
1456                                                        "inlineMultiMissingTypes");
1457     ASSERT_TRUE(inline_missing_types != nullptr);
1458     TypeReferenceSet expected_missing_Types;
1459     AssertInlineCaches(inline_missing_types,
1460                        GetDexPcOfCallTo(inline_missing_types, super_klass),
1461                        expected_missing_Types,
1462                        info,
1463                        /*is_megamorphic=*/false,
1464                        /*is_missing_types=*/true);
1465     AssertInlineCaches(inline_missing_types,
1466                        GetDexPcOfCallTo(inline_missing_types, secret_klass),
1467                        expected_missing_Types,
1468                        info,
1469                        /*is_megamorphic=*/false,
1470                        /*is_missing_types=*/true);
1471   }
1472 
1473   {
1474     // Verify that method noInlineCacheMulti has no inline caches in the profile.
1475     ArtMethod* no_inline_cache =
1476         GetVirtualMethod(class_loader, "LTestInline;", "noInlineCacheMulti");
1477     ASSERT_TRUE(no_inline_cache != nullptr);
1478     ProfileCompilationInfo::MethodHotness hotness_no_inline_cache = info.GetMethodHotness(
1479         MethodReference(no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex()));
1480     ASSERT_TRUE(hotness_no_inline_cache.IsHot());
1481     ASSERT_TRUE(hotness_no_inline_cache.GetInlineCacheMap()->empty());
1482   }
1483 }
1484 
TEST_F(ProfileAssistantTest,MergeProfilesWithDifferentDexOrder)1485 TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
1486   ScratchFile profile1;
1487   ScratchFile reference_profile;
1488 
1489   std::vector<int> profile_fds({GetFd(profile1)});
1490   int reference_profile_fd = GetFd(reference_profile);
1491 
1492   // The new profile info will contain the methods with indices 0-100.
1493   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1494   ProfileCompilationInfo info1;
1495   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1496       /*start_method_index=*/0, /*reverse_dex_write_order=*/false);
1497 
1498   // The reference profile info will contain the methods with indices 50-150.
1499   // When setting up the profile reverse the order in which the dex files
1500   // are added to the profile. This will verify that profman merges profiles
1501   // with a different dex order correctly.
1502   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1503   ProfileCompilationInfo reference_info;
1504   SetupProfile(dex1, dex2, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1505       &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order=*/true);
1506 
1507   // We should advise compilation.
1508   ASSERT_EQ(ProfmanResult::kCompile, ProcessProfiles(profile_fds, reference_profile_fd));
1509 
1510   // The resulting compilation info must be equal to the merge of the inputs.
1511   ProfileCompilationInfo result;
1512   ASSERT_TRUE(result.Load(reference_profile_fd));
1513 
1514   ProfileCompilationInfo expected;
1515   ASSERT_TRUE(expected.MergeWith(reference_info));
1516   ASSERT_TRUE(expected.MergeWith(info1));
1517   ASSERT_TRUE(expected.Equals(result));
1518 
1519   // The information from profile must remain the same.
1520   CheckProfileInfo(profile1, info1);
1521 }
1522 
TEST_F(ProfileAssistantTest,TestProfileCreateWithSubtype)1523 TEST_F(ProfileAssistantTest, TestProfileCreateWithSubtype) {
1524   // Create the profile content.
1525   std::vector<std::string> profile_methods = {
1526       "HLTestInlineSubtype;->inlineMonomorphic(LSuper;)I+]LSuper;LSubA;",
1527   };
1528   std::string input_file_contents;
1529   for (std::string& m : profile_methods) {
1530     input_file_contents += m + std::string("\n");
1531   }
1532 
1533   // Create the profile and save it to disk.
1534   ScratchFile profile_file;
1535   std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1536   ASSERT_TRUE(CreateProfile(input_file_contents, profile_file.GetFilename(), dex_filename));
1537 
1538   // Load the profile from disk.
1539   ProfileCompilationInfo info;
1540   ASSERT_TRUE(info.Load(GetFd(profile_file)));
1541   LOG(ERROR) << profile_file.GetFilename();
1542 
1543   // Load the dex files and verify that the profile contains the expected
1544   // methods info.
1545   ScopedObjectAccess soa(Thread::Current());
1546   jobject class_loader = LoadDex("ProfileTestMultiDex");
1547   ASSERT_NE(class_loader, nullptr);
1548 
1549   // NB This is the supertype of the declared line!
1550   ArtMethod* inline_monomorphic_super =
1551       GetVirtualMethod(class_loader, "LTestInline;", "inlineMonomorphic");
1552   const DexFile* dex_file = inline_monomorphic_super->GetDexFile();
1553 
1554   // Verify that the inline cache is present in the superclass
1555   ProfileCompilationInfo::MethodHotness hotness_super = info.GetMethodHotness(
1556       MethodReference(dex_file, inline_monomorphic_super->GetDexMethodIndex()));
1557   ASSERT_TRUE(hotness_super.IsHot());
1558   const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness_super.GetInlineCacheMap();
1559   ASSERT_EQ(inline_caches->size(), 1u);
1560   const ProfileCompilationInfo::DexPcData& dex_pc_data = inline_caches->begin()->second;
1561   dex::TypeIndex target_type_index(dex_file->GetIndexForTypeId(*dex_file->FindTypeId("LSubA;")));
1562   ASSERT_EQ(1u, dex_pc_data.classes.size());
1563   ASSERT_EQ(target_type_index, *dex_pc_data.classes.begin());
1564 
1565   // Verify that the method is present in subclass but there are no
1566   // inline-caches (since there is no code).
1567   const dex::MethodId& super_method_id =
1568       dex_file->GetMethodId(inline_monomorphic_super->GetDexMethodIndex());
1569   uint32_t sub_method_index = dex_file->GetIndexForMethodId(
1570       *dex_file->FindMethodId(*dex_file->FindTypeId("LTestInlineSubtype;"),
1571                               dex_file->GetStringId(super_method_id.name_idx_),
1572                               dex_file->GetProtoId(super_method_id.proto_idx_)));
1573   ProfileCompilationInfo::MethodHotness hotness_sub =
1574       info.GetMethodHotness(MethodReference(dex_file, sub_method_index));
1575   ASSERT_TRUE(hotness_sub.IsHot());
1576   ASSERT_EQ(hotness_sub.GetInlineCacheMap()->size(), 0u);
1577 }
1578 
TEST_F(ProfileAssistantTest,TestProfileCreateWithSubtypeAndDump)1579 TEST_F(ProfileAssistantTest, TestProfileCreateWithSubtypeAndDump) {
1580   // Create the profile content.
1581   std::vector<std::string> profile_methods = {
1582       "HLTestInlineSubtype;->inlineMonomorphic(LSuper;)I+]LSuper;LSubA;",
1583   };
1584   std::string input_file_contents;
1585   for (std::string& m : profile_methods) {
1586     input_file_contents += m + std::string("\n");
1587   }
1588 
1589   // Create the profile and save it to disk.
1590   ScratchFile profile_file;
1591   std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1592   ASSERT_TRUE(CreateProfile(input_file_contents, profile_file.GetFilename(), dex_filename));
1593 
1594   std::string dump_ic;
1595   ASSERT_TRUE(DumpClassesAndMethods(
1596       profile_file.GetFilename(), &dump_ic, GetTestDexFileName("ProfileTestMultiDex")));
1597 
1598   std::vector<std::string> lines;
1599   std::stringstream dump_stream(dump_ic);
1600   std::string cur;
1601   while (std::getline(dump_stream, cur, '\n')) {
1602     lines.push_back(std::move(cur));
1603   }
1604 
1605   EXPECT_EQ(lines.size(), 2u);
1606   EXPECT_TRUE(std::find(lines.cbegin(),
1607                         lines.cend(),
1608                         "HLTestInline;->inlineMonomorphic(LSuper;)I+]LSuper;LSubA;") !=
1609               lines.cend());
1610   EXPECT_TRUE(std::find(lines.cbegin(),
1611                         lines.cend(),
1612                         "HLTestInlineSubtype;->inlineMonomorphic(LSuper;)I") != lines.cend());
1613 }
1614 
TEST_F(ProfileAssistantTest,TestProfileCreateWithInvalidData)1615 TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1616   // Create the profile content.
1617   std::vector<std::string> profile_methods = {
1618     "HLTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",  // Invalid descriptor for IC.
1619     "HLTestInline;->invalid_method",  // Invalid method spec (no signature).
1620     "invalid_class",  // Invalid descriptor.
1621   };
1622   std::string input_file_contents;
1623   for (std::string& m : profile_methods) {
1624     input_file_contents += m + std::string("\n");
1625   }
1626 
1627   // Create the profile and save it to disk.
1628   ScratchFile profile_file;
1629   std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1630   ASSERT_TRUE(CreateProfile(input_file_contents,
1631                             profile_file.GetFilename(),
1632                             dex_filename));
1633 
1634   // Load the profile from disk.
1635   ProfileCompilationInfo info;
1636   ASSERT_TRUE(info.Load(GetFd(profile_file)));
1637 
1638   // Load the dex files and verify that the profile contains the expected methods info.
1639   ScopedObjectAccess soa(Thread::Current());
1640   jobject class_loader = LoadDex("ProfileTestMultiDex");
1641   ASSERT_NE(class_loader, nullptr);
1642 
1643   ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1644                                                    "LTestInline;",
1645                                                    "inlineMonomorphic");
1646   const DexFile* dex_file = inline_monomorphic->GetDexFile();
1647 
1648   // Invalid descriptor in IC results in rejection of the entire line.
1649   ProfileCompilationInfo::MethodHotness hotness =
1650       info.GetMethodHotness(MethodReference(dex_file, inline_monomorphic->GetDexMethodIndex()));
1651   ASSERT_FALSE(hotness.IsHot());
1652 
1653   // No data was recorded, so the dex file does not appear in the profile.
1654   // TODO: Record all dex files passed to `profman` in the profile. Note that
1655   // this makes sense only if there are no annotations, otherwise we do not
1656   // know what annotation to use with each dex file.
1657   std::set<dex::TypeIndex> classes;
1658   std::set<uint16_t> hot_methods;
1659   std::set<uint16_t> startup_methods;
1660   std::set<uint16_t> post_start_methods;
1661   ASSERT_FALSE(info.GetClassesAndMethods(*dex_file,
1662                                          &classes,
1663                                          &hot_methods,
1664                                          &startup_methods,
1665                                          &post_start_methods));
1666 }
1667 
TEST_F(ProfileAssistantTest,DumpOnly)1668 TEST_F(ProfileAssistantTest, DumpOnly) {
1669   ScratchFile profile;
1670 
1671   const uint32_t kNumberOfMethods = 64;
1672   std::vector<uint32_t> hot_methods;
1673   std::vector<uint32_t> startup_methods;
1674   std::vector<uint32_t> post_startup_methods;
1675   for (size_t i = 0; i < kNumberOfMethods; ++i) {
1676     if (i % 2 == 0) {
1677       hot_methods.push_back(i);
1678     }
1679     if (i % 3 == 1) {
1680       startup_methods.push_back(i);
1681     }
1682     if (i % 4 == 2) {
1683       post_startup_methods.push_back(i);
1684     }
1685   }
1686   EXPECT_GT(hot_methods.size(), 0u);
1687   EXPECT_GT(startup_methods.size(), 0u);
1688   EXPECT_GT(post_startup_methods.size(), 0u);
1689   ProfileCompilationInfo info1;
1690   SetupBasicProfile(dex1,
1691                     hot_methods,
1692                     startup_methods,
1693                     post_startup_methods,
1694                     profile,
1695                     &info1);
1696   std::string output;
1697   DumpOnly(profile.GetFilename(), &output);
1698   const size_t hot_offset = output.find("hot methods:");
1699   const size_t startup_offset = output.find("startup methods:");
1700   const size_t post_startup_offset = output.find("post startup methods:");
1701   const size_t classes_offset = output.find("classes:");
1702   ASSERT_NE(hot_offset, std::string::npos);
1703   ASSERT_NE(startup_offset, std::string::npos);
1704   ASSERT_NE(post_startup_offset, std::string::npos);
1705   ASSERT_LT(hot_offset, startup_offset);
1706   ASSERT_LT(startup_offset, post_startup_offset);
1707   // Check the actual contents of the dump by looking at the offsets of the methods.
1708   for (uint32_t m : hot_methods) {
1709     const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1710     ASSERT_NE(pos, std::string::npos) << output;
1711     EXPECT_LT(pos, startup_offset) << output;
1712   }
1713   for (uint32_t m : startup_methods) {
1714     const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1715     ASSERT_NE(pos, std::string::npos) << output;
1716     EXPECT_LT(pos, post_startup_offset) << output;
1717   }
1718   for (uint32_t m : post_startup_methods) {
1719     const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1720     ASSERT_NE(pos, std::string::npos) << output;
1721     EXPECT_LT(pos, classes_offset) << output;
1722   }
1723 }
1724 
TEST_F(ProfileAssistantTest,MergeProfilesWithFilter)1725 TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1726   ScratchFile profile1;
1727   ScratchFile profile2;
1728   ScratchFile reference_profile;
1729 
1730   std::vector<int> profile_fds({
1731       GetFd(profile1),
1732       GetFd(profile2)});
1733   int reference_profile_fd = GetFd(reference_profile);
1734 
1735   // Use a real dex file to generate profile test data.
1736   // The file will be used during merging to filter unwanted data.
1737   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1738   const DexFile& d1 = *dex_files[0];
1739   const DexFile& d2 = *dex_files[1];
1740   // The new profile info will contain the methods with indices 0-100.
1741   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1742   ProfileCompilationInfo info1;
1743   SetupProfile(&d1, dex1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1744   ProfileCompilationInfo info2;
1745   SetupProfile(&d2, dex2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1746 
1747 
1748   // The reference profile info will contain the methods with indices 50-150.
1749   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1750   ProfileCompilationInfo reference_info;
1751   SetupProfile(&d1, dex1,
1752       kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1753       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1754 
1755   // Run profman and pass the dex file with --apk-fd.
1756   android::base::unique_fd apk_fd(
1757       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));  // NOLINT
1758   ASSERT_GE(apk_fd.get(), 0);
1759 
1760   std::string profman_cmd = GetProfmanCmd();
1761   std::vector<std::string> argv_str;
1762   argv_str.push_back(profman_cmd);
1763   argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1764   argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1765   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1766   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1767   std::string error;
1768 
1769   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCompile) << error;
1770 
1771   // Verify that we can load the result.
1772 
1773   ProfileCompilationInfo result;
1774   ASSERT_TRUE(result.Load(reference_profile_fd));
1775 
1776   // Verify that the result filtered out data not belonging to the dex file.
1777   // This is equivalent to checking that the result is equal to the merging of
1778   // all profiles while filtering out data not belonging to the dex file.
1779 
1780   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1781       [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1782           return (dex_location == ProfileCompilationInfo::GetProfileDexFileBaseKey(d1.GetLocation())
1783               && checksum == d1.GetLocationChecksum())
1784               || (dex_location == ProfileCompilationInfo::GetProfileDexFileBaseKey(d2.GetLocation())
1785               && checksum == d2.GetLocationChecksum());
1786         };
1787 
1788   ProfileCompilationInfo info1_filter;
1789   ProfileCompilationInfo info2_filter;
1790   ProfileCompilationInfo expected;
1791 
1792   info2_filter.Load(profile1.GetFd(), /*merge_classes=*/ true, filter_fn);
1793   info2_filter.Load(profile2.GetFd(), /*merge_classes=*/ true, filter_fn);
1794   expected.Load(reference_profile.GetFd(), /*merge_classes=*/ true, filter_fn);
1795 
1796   ASSERT_TRUE(expected.MergeWith(info1_filter));
1797   ASSERT_TRUE(expected.MergeWith(info2_filter));
1798 
1799   ASSERT_TRUE(expected.Equals(result));
1800 }
1801 
TEST_F(ProfileAssistantTest,MergeProfilesNoProfile)1802 TEST_F(ProfileAssistantTest, MergeProfilesNoProfile) {
1803   ScratchFile reference_profile;
1804 
1805   // Use a real dex file to generate profile test data.
1806   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1807   const DexFile& d1 = *dex_files[0];
1808   const DexFile& d2 = *dex_files[0];
1809 
1810   // The reference profile info will contain the methods with indices 0-100.
1811   ProfileCompilationInfo reference_info;
1812   SetupProfile(&d1,
1813                &d2,
1814                /*number_of_methods=*/ 100,
1815                /*number_of_classes=*/ 0,
1816                reference_profile,
1817                &reference_info);
1818 
1819   std::string content_before;
1820   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before));
1821 
1822   // Run profman and pass the dex file with --apk-fd.
1823   android::base::unique_fd apk_fd(
1824       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
1825       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1826   ASSERT_GE(apk_fd.get(), 0);
1827 
1828   std::string profman_cmd = GetProfmanCmd();
1829   std::vector<std::string> argv_str;
1830   argv_str.push_back(profman_cmd);
1831   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1832   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1833 
1834   // Must return kSkipCompilationSmallDelta.
1835   std::string error;
1836   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationSmallDelta)
1837       << error;
1838 
1839   // Verify that the content has not changed.
1840   std::string content_after;
1841   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after));
1842   EXPECT_EQ(content_before, content_after);
1843 }
1844 
TEST_F(ProfileAssistantTest,MergeProfilesNoProfilePassByFilename)1845 TEST_F(ProfileAssistantTest, MergeProfilesNoProfilePassByFilename) {
1846   ScratchFile reference_profile;
1847 
1848   // Use a real dex file to generate profile test data.
1849   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1850   const DexFile& d1 = *dex_files[0];
1851   const DexFile& d2 = *dex_files[0];
1852 
1853   // The reference profile info will contain the methods with indices 0-100.
1854   ProfileCompilationInfo reference_info;
1855   SetupProfile(&d1,
1856                &d2,
1857                /*number_of_methods=*/100,
1858                /*number_of_classes=*/0,
1859                reference_profile,
1860                &reference_info);
1861 
1862   std::string content_before;
1863   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before));
1864 
1865   // Run profman and pass the dex file with --apk-fd.
1866   android::base::unique_fd apk_fd(
1867       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
1868       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1869   ASSERT_GE(apk_fd.get(), 0);
1870 
1871   std::string profman_cmd = GetProfmanCmd();
1872   std::vector<std::string> argv_str;
1873   argv_str.push_back(profman_cmd);
1874   argv_str.push_back("--reference-profile-file=" + reference_profile.GetFilename());
1875   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1876 
1877   // Must return kSkipCompilationSmallDelta.
1878   std::string error;
1879   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationSmallDelta)
1880       << error;
1881 
1882   // Verify that the content has not changed.
1883   std::string content_after;
1884   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after));
1885   EXPECT_EQ(content_before, content_after);
1886 }
1887 
TEST_F(ProfileAssistantTest,MergeProfilesNoProfileEmptyReferenceProfile)1888 TEST_F(ProfileAssistantTest, MergeProfilesNoProfileEmptyReferenceProfile) {
1889   ScratchFile reference_profile;
1890 
1891   // The reference profile info will only contain the header.
1892   ProfileCompilationInfo reference_info;
1893   SetupProfile(/*dex_file1=*/ nullptr,
1894                /*dex_file2=*/ nullptr,
1895                /*number_of_methods=*/ 0,
1896                /*number_of_classes=*/ 0,
1897                reference_profile,
1898                &reference_info);
1899 
1900   std::string content_before;
1901   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before));
1902 
1903   // Run profman and pass the dex file with --apk-fd.
1904   android::base::unique_fd apk_fd(
1905       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
1906       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1907   ASSERT_GE(apk_fd.get(), 0);
1908 
1909   std::string profman_cmd = GetProfmanCmd();
1910   std::vector<std::string> argv_str;
1911   argv_str.push_back(profman_cmd);
1912   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1913   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1914 
1915   // Must return kSkipCompilationEmptyProfiles.
1916   std::string error;
1917   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationEmptyProfiles)
1918       << error;
1919 
1920   // Verify that the content has not changed.
1921   std::string content_after;
1922   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after));
1923   EXPECT_EQ(content_before, content_after);
1924 }
1925 
TEST_F(ProfileAssistantTest,MergeProfilesNoProfileEmptyReferenceProfileAfterFiltering)1926 TEST_F(ProfileAssistantTest, MergeProfilesNoProfileEmptyReferenceProfileAfterFiltering) {
1927   ScratchFile reference_profile;
1928 
1929   // Use fake dex files to generate profile test data.
1930   // All the methods will be filtered out during the profman invocation.
1931   ProfileCompilationInfo reference_info;
1932   SetupProfile(dex1,
1933                dex2,
1934                /*number_of_methods=*/ 100,
1935                /*number_of_classes=*/ 0,
1936                reference_profile,
1937                &reference_info);
1938 
1939   std::string content_before;
1940   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_before));
1941 
1942   // Run profman and pass the real dex file with --apk-fd.
1943   android::base::unique_fd apk_fd(
1944       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
1945       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1946   ASSERT_GE(apk_fd.get(), 0);
1947 
1948   std::string profman_cmd = GetProfmanCmd();
1949   std::vector<std::string> argv_str;
1950   argv_str.push_back(profman_cmd);
1951   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1952   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1953 
1954   // Must return kSkipCompilationEmptyProfiles.
1955   std::string error;
1956   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSkipCompilationEmptyProfiles)
1957       << error;
1958 
1959   // Verify that the content has not changed.
1960   std::string content_after;
1961   ASSERT_TRUE(android::base::ReadFileToString(reference_profile.GetFilename(), &content_after));
1962   EXPECT_EQ(content_before, content_after);
1963 }
1964 
TEST_F(ProfileAssistantTest,CopyAndUpdateProfileKey)1965 TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1966   ScratchFile profile1;
1967   ScratchFile reference_profile;
1968 
1969   // Use a real dex file to generate profile test data. During the copy-and-update the
1970   // matching is done based on checksum so we have to match with the real thing.
1971   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1972   const DexFile& d1 = *dex_files[0];
1973   const DexFile& d2 = *dex_files[1];
1974 
1975   ProfileCompilationInfo info1;
1976   uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1977 
1978   const DexFile* dex_to_be_updated1 = BuildDex(
1979       "fake-location1", d1.GetLocationChecksum(), "LC;", d1.NumMethodIds(), d1.NumTypeIds());
1980   const DexFile* dex_to_be_updated2 = BuildDex(
1981       "fake-location2", d2.GetLocationChecksum(), "LC;", d2.NumMethodIds(), d2.NumTypeIds());
1982   SetupProfile(dex_to_be_updated1,
1983                dex_to_be_updated2,
1984                num_methods_to_add,
1985                /*number_of_classes=*/ 0,
1986                profile1,
1987                &info1);
1988 
1989   // Run profman and pass the dex file with --apk-fd.
1990   android::base::unique_fd apk_fd(
1991       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
1992       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1993   ASSERT_GE(apk_fd.get(), 0);
1994 
1995   std::string profman_cmd = GetProfmanCmd();
1996   std::vector<std::string> argv_str;
1997   argv_str.push_back(profman_cmd);
1998   argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1999   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
2000   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
2001   argv_str.push_back("--copy-and-update-profile-key");
2002   std::string error;
2003 
2004   // Must return kCopyAndUpdateSuccess.
2005   ASSERT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCopyAndUpdateSuccess) << error;
2006 
2007   // Verify that we can load the result.
2008   ProfileCompilationInfo result;
2009   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
2010 
2011   // Verify that the renaming was done.
2012   for (uint16_t i = 0; i < num_methods_to_add; i ++) {
2013     ASSERT_TRUE(result.GetMethodHotness(MethodReference(&d1, i)).IsHot()) << i;
2014     ASSERT_TRUE(result.GetMethodHotness(MethodReference(&d2, i)).IsHot()) << i;
2015 
2016     ASSERT_FALSE(result.GetMethodHotness(MethodReference(dex_to_be_updated1, i)).IsHot()) << i;
2017     ASSERT_FALSE(result.GetMethodHotness(MethodReference(dex_to_be_updated2, i)).IsHot()) << i;
2018   }
2019 }
2020 
TEST_F(ProfileAssistantTest,CopyAndUpdateProfileKeyNoUpdate)2021 TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKeyNoUpdate) {
2022   ScratchFile profile1;
2023   ScratchFile reference_profile;
2024 
2025   // Use fake dex files to generate profile test data.
2026   ProfileCompilationInfo info1;
2027   SetupProfile(dex1,
2028                dex2,
2029                /*number_of_methods=*/ 100,
2030                /*number_of_classes=*/ 0,
2031                profile1,
2032                &info1);
2033 
2034   // Run profman and pass the real dex file with --apk-fd. It won't match any entry in the profile.
2035   android::base::unique_fd apk_fd(
2036       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
2037       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
2038   ASSERT_GE(apk_fd.get(), 0);
2039 
2040   std::string profman_cmd = GetProfmanCmd();
2041   std::vector<std::string> argv_str;
2042   argv_str.push_back(profman_cmd);
2043   argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
2044   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
2045   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
2046   argv_str.push_back("--copy-and-update-profile-key");
2047   std::string error;
2048 
2049   // Must return kCopyAndUpdateNoMatch.
2050   ASSERT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kCopyAndUpdateNoMatch) << error;
2051 
2052   // Verify that the content is the same.
2053   ProfileCompilationInfo result;
2054   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
2055   EXPECT_TRUE(result.Equals(info1));
2056 }
2057 
TEST_F(ProfileAssistantTest,BootImageMerge)2058 TEST_F(ProfileAssistantTest, BootImageMerge) {
2059   ScratchFile profile1;
2060   ScratchFile profile2;
2061   ScratchFile profile3;
2062   ScratchFile output_profile;
2063   std::vector<uint32_t> hot_methods_1;
2064   std::vector<uint32_t> hot_methods_2;
2065   std::vector<uint32_t> hot_methods_3;
2066   for (size_t i = 0; i < 100; ++i) {
2067     hot_methods_1.push_back(i);
2068   }
2069   for (size_t i = 50; i < 150; ++i) {
2070     hot_methods_2.push_back(i);
2071   }
2072   for (size_t i = 100; i < 200; ++i) {
2073     hot_methods_3.push_back(i);
2074   }
2075   ProfileCompilationInfo info1(/*for_boot_image=*/false);
2076   SetupBasicProfile(
2077       dex1, hot_methods_1, /*startup_methods=*/{}, /*post_startup_methods=*/{}, profile1, &info1);
2078   ProfileCompilationInfo info2(/*for_boot_image=*/true);
2079   SetupBasicProfile(
2080       dex1, hot_methods_2, /*startup_methods=*/{}, /*post_startup_methods=*/{}, profile2, &info2);
2081   ProfileCompilationInfo info3(/*for_boot_image=*/true);
2082   SetupBasicProfile(
2083       dex1, hot_methods_3, /*startup_methods=*/{}, /*post_startup_methods=*/{}, profile3, &info3);
2084 
2085   {
2086     int return_code = ProcessProfiles({profile1.GetFd(), profile2.GetFd(), profile3.GetFd()},
2087                                       output_profile.GetFd(),
2088                                       {"--force-merge-and-analyze", "--boot-image-merge"});
2089     ASSERT_EQ(return_code, ProfmanResult::kCompile);
2090 
2091     // Verify the result: it should be equal to info2 union info3 since info1 is a regular profile
2092     // and should be ignored.
2093     ProfileCompilationInfo result(/*for_boot_image=*/true);
2094     ASSERT_TRUE(result.Load(output_profile.GetFd()));
2095     ASSERT_TRUE(info2.MergeWith(info3));
2096     ASSERT_TRUE(result.Equals(info2));
2097   }
2098 
2099   // Same for the legacy force merge mode.
2100   {
2101     int return_code = ProcessProfiles({profile1.GetFd(), profile2.GetFd(), profile3.GetFd()},
2102                                       output_profile.GetFd(),
2103                                       {"--force-merge", "--boot-image-merge"});
2104     ASSERT_EQ(return_code, ProfmanResult::kSuccess);
2105 
2106     // Verify the result: it should be equal to info2 union info3 since info1 is a regular profile
2107     // and should be ignored.
2108     ProfileCompilationInfo result(/*for_boot_image=*/true);
2109     ASSERT_TRUE(result.Load(output_profile.GetFd()));
2110     ASSERT_TRUE(info2.MergeWith(info3));
2111     ASSERT_TRUE(result.Equals(info2));
2112   }
2113 }
2114 
2115 // Under default behaviour we should not advice compilation
2116 // and the reference profile should not be updated.
2117 // However we pass --force-merge to force aggregation and in this case
2118 // we should see an update.
TEST_F(ProfileAssistantTest,ForceMerge)2119 TEST_F(ProfileAssistantTest, ForceMerge) {
2120   const uint16_t kNumberOfClassesInRefProfile = 6000;
2121   const uint16_t kNumberOfClassesInCurProfile = 6110;  // Threshold is 2%.
2122 
2123   const DexFile* dex1_7000 = BuildDex("location1_7000",
2124                                       /*location_checksum=*/ 7001,
2125                                       "LUnique1_7000;",
2126                                       /*num_method_ids=*/ 0,
2127                                       /*num_class_ids=*/ 7000);
2128   const DexFile* dex2_7000 = BuildDex("location2_7000",
2129                                       /*location_checksum=*/ 7002,
2130                                       "LUnique2_7000;",
2131                                       /*num_method_ids=*/ 0,
2132                                       /*num_class_ids=*/ 7000);
2133 
2134   ScratchFile profile;
2135   ScratchFile reference_profile;
2136 
2137   std::vector<int> profile_fds({ GetFd(profile)});
2138   int reference_profile_fd = GetFd(reference_profile);
2139 
2140   ProfileCompilationInfo info1;
2141   SetupProfile(dex1_7000, dex2_7000, 0, kNumberOfClassesInRefProfile, profile,  &info1);
2142   ProfileCompilationInfo info2;
2143   SetupProfile(dex1_7000, dex2_7000, 0, kNumberOfClassesInCurProfile, reference_profile, &info2);
2144 
2145   std::vector<const std::string> extra_args({"--force-merge"});
2146   int return_code = ProcessProfiles(profile_fds, reference_profile_fd, extra_args);
2147 
2148   ASSERT_EQ(return_code, ProfmanResult::kSuccess);
2149 
2150   // Check that the result is the aggregation.
2151   ProfileCompilationInfo result;
2152   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
2153   ASSERT_TRUE(info1.MergeWith(info2));
2154   ASSERT_TRUE(result.Equals(info1));
2155 }
2156 
TEST_F(ProfileAssistantTest,ForceMergeAndAnalyze)2157 TEST_F(ProfileAssistantTest, ForceMergeAndAnalyze) {
2158   const uint16_t kNumberOfMethodsInRefProfile = 600;
2159   const uint16_t kNumberOfMethodsInCurProfile = 601;
2160 
2161   ScratchFile ref_profile;
2162   ScratchFile cur_profile;
2163 
2164   ProfileCompilationInfo ref_info;
2165   SetupProfile(
2166       dex1, dex2, kNumberOfMethodsInRefProfile, /*number_of_classes=*/0, ref_profile, &ref_info);
2167   ProfileCompilationInfo cur_info;
2168   SetupProfile(
2169       dex1, dex2, kNumberOfMethodsInCurProfile, /*number_of_classes=*/0, cur_profile, &cur_info);
2170 
2171   std::vector<const std::string> extra_args({"--force-merge-and-analyze"});
2172   int return_code = ProcessProfiles({cur_profile.GetFd()}, ref_profile.GetFd(), extra_args);
2173 
2174   ASSERT_EQ(return_code, ProfmanResult::kCompile);
2175 
2176   // Check that the result is the aggregation.
2177   ProfileCompilationInfo result;
2178   ASSERT_TRUE(result.Load(ref_profile.GetFd()));
2179   ASSERT_TRUE(ref_info.MergeWith(cur_info));
2180   ASSERT_TRUE(result.Equals(ref_info));
2181 }
2182 
TEST_F(ProfileAssistantTest,ForceMergeAndAnalyzeNoDelta)2183 TEST_F(ProfileAssistantTest, ForceMergeAndAnalyzeNoDelta) {
2184   const uint16_t kNumberOfMethodsInRefProfile = 600;
2185   const uint16_t kNumberOfMethodsInCurProfile = 600;
2186 
2187   ScratchFile ref_profile;
2188   ScratchFile cur_profile;
2189 
2190   ProfileCompilationInfo ref_info;
2191   SetupProfile(
2192       dex1, dex2, kNumberOfMethodsInRefProfile, /*number_of_classes=*/0, ref_profile, &ref_info);
2193   ProfileCompilationInfo cur_info;
2194   SetupProfile(
2195       dex1, dex2, kNumberOfMethodsInCurProfile, /*number_of_classes=*/0, cur_profile, &cur_info);
2196 
2197   std::vector<const std::string> extra_args({"--force-merge-and-analyze"});
2198   int return_code = ProcessProfiles({cur_profile.GetFd()}, ref_profile.GetFd(), extra_args);
2199 
2200   ASSERT_EQ(return_code, ProfmanResult::kSkipCompilationSmallDelta);
2201 
2202   // Check that the reference profile is unchanged.
2203   ProfileCompilationInfo result;
2204   ASSERT_TRUE(result.Load(ref_profile.GetFd()));
2205   ASSERT_TRUE(result.Equals(ref_info));
2206 }
2207 
TEST_F(ProfileAssistantTest,ForceMergeAndAnalyzeEmptyProfiles)2208 TEST_F(ProfileAssistantTest, ForceMergeAndAnalyzeEmptyProfiles) {
2209   const uint16_t kNumberOfMethodsInRefProfile = 0;
2210   const uint16_t kNumberOfMethodsInCurProfile = 0;
2211 
2212   ScratchFile ref_profile;
2213   ScratchFile cur_profile;
2214 
2215   ProfileCompilationInfo ref_info;
2216   SetupProfile(
2217       dex1, dex2, kNumberOfMethodsInRefProfile, /*number_of_classes=*/0, ref_profile, &ref_info);
2218   ProfileCompilationInfo cur_info;
2219   SetupProfile(
2220       dex1, dex2, kNumberOfMethodsInCurProfile, /*number_of_classes=*/0, cur_profile, &cur_info);
2221 
2222   std::vector<const std::string> extra_args({"--force-merge-and-analyze"});
2223   int return_code = ProcessProfiles({cur_profile.GetFd()}, ref_profile.GetFd(), extra_args);
2224 
2225   ASSERT_EQ(return_code, ProfmanResult::kSkipCompilationEmptyProfiles);
2226 
2227   // Check that the reference profile is unchanged.
2228   ProfileCompilationInfo result;
2229   ASSERT_TRUE(result.Load(ref_profile.GetFd()));
2230   ASSERT_TRUE(result.Equals(ref_info));
2231 }
2232 
2233 // Test that we consider the annations when we merge boot image profiles.
TEST_F(ProfileAssistantTest,BootImageMergeWithAnnotations)2234 TEST_F(ProfileAssistantTest, BootImageMergeWithAnnotations) {
2235   ScratchFile profile;
2236   ScratchFile reference_profile;
2237 
2238   std::vector<int> profile_fds({GetFd(profile)});
2239   int reference_profile_fd = GetFd(reference_profile);
2240 
2241   // Use a real dex file to generate profile test data so that we can pass descriptors to profman.
2242   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
2243   const DexFile& d1 = *dex_files[0];
2244   const DexFile& d2 = *dex_files[1];
2245   // The new profile info will contain the methods with indices 0-100.
2246   ProfileCompilationInfo info(/*for_boot_image=*/ true);
2247   ProfileCompilationInfo::ProfileSampleAnnotation psa1("package1");
2248   ProfileCompilationInfo::ProfileSampleAnnotation psa2("package2");
2249 
2250   AddMethod(&info, &d1, 0, Hotness::kFlagHot, psa1);
2251   AddMethod(&info, &d2, 0, Hotness::kFlagHot, psa2);
2252   info.Save(profile.GetFd());
2253 
2254   // Run profman and pass the dex file with --apk-fd.
2255   android::base::unique_fd apk_fd(
2256       // NOLINTNEXTLINE - Profman needs file to be opened after fork() and exec()
2257       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
2258   ASSERT_GE(apk_fd.get(), 0);
2259 
2260   std::string profman_cmd = GetProfmanCmd();
2261   std::vector<std::string> argv_str;
2262   argv_str.push_back(profman_cmd);
2263   argv_str.push_back("--profile-file-fd=" + std::to_string(profile.GetFd()));
2264   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
2265   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
2266   argv_str.push_back("--force-merge");
2267   argv_str.push_back("--boot-image-merge");
2268   std::string error;
2269 
2270   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfmanResult::kSuccess) << error;
2271 
2272   // Verify that we can load the result and that it equals to what we saved.
2273   ProfileCompilationInfo result(/*for_boot_image=*/ true);
2274   ASSERT_TRUE(result.Load(reference_profile_fd));
2275   ASSERT_TRUE(info.Equals(result));
2276 }
2277 
TEST_F(ProfileAssistantTest,DifferentProfileVersions)2278 TEST_F(ProfileAssistantTest, DifferentProfileVersions) {
2279   ScratchFile profile1;
2280   ScratchFile profile2;
2281 
2282   ProfileCompilationInfo info1(/*for_boot_image=*/ false);
2283   info1.Save(profile1.GetFd());
2284 
2285   ProfileCompilationInfo info2(/*for_boot_image=*/ true);
2286   info2.Save(profile2.GetFd());
2287 
2288   std::vector<int> profile_fds({ GetFd(profile1)});
2289   int reference_profile_fd = GetFd(profile2);
2290   std::vector<const std::string> boot_image_args({"--boot-image-merge"});
2291   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, boot_image_args),
2292             ProfmanResult::kErrorDifferentVersions);
2293   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd), ProfmanResult::kErrorBadProfiles);
2294 
2295   // Reverse the order of the profiles to verify we get the same behaviour.
2296   profile_fds[0] = GetFd(profile2);
2297   reference_profile_fd = GetFd(profile1);
2298   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, boot_image_args),
2299             ProfmanResult::kErrorBadProfiles);
2300   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd),
2301             ProfmanResult::kErrorDifferentVersions);
2302 }
2303 
2304 // Under default behaviour we will abort if we cannot load a profile during a merge
2305 // operation. However, if we pass --force-merge to force aggregation we should
2306 // ignore files we cannot load
TEST_F(ProfileAssistantTest,ForceMergeIgnoreProfilesItCannotLoad)2307 TEST_F(ProfileAssistantTest, ForceMergeIgnoreProfilesItCannotLoad) {
2308   ScratchFile profile1;
2309   ScratchFile profile2;
2310 
2311   // Write corrupt data in the first file.
2312   std::string content = "giberish";
2313   ASSERT_TRUE(profile1.GetFile()->WriteFully(content.c_str(), content.length()));
2314 
2315   ProfileCompilationInfo info2(/*for_boot_image=*/true);
2316   info2.Save(profile2.GetFd());
2317 
2318   std::vector<int> profile_fds({GetFd(profile1)});
2319   int reference_profile_fd = GetFd(profile2);
2320 
2321   // With force-merge we should merge successfully.
2322   {
2323     ASSERT_EQ(
2324         ProcessProfiles(
2325             profile_fds, reference_profile_fd, {"--force-merge-and-analyze", "--boot-image-merge"}),
2326         ProfmanResult::kSkipCompilationEmptyProfiles);
2327 
2328     ProfileCompilationInfo result(/*for_boot_image=*/true);
2329     ASSERT_TRUE(result.Load(reference_profile_fd));
2330     ASSERT_TRUE(info2.Equals(result));
2331   }
2332 
2333   // Same for the legacy force merge mode.
2334   {
2335     ASSERT_EQ(
2336         ProcessProfiles(profile_fds, reference_profile_fd, {"--force-merge", "--boot-image-merge"}),
2337         ProfmanResult::kSuccess);
2338 
2339     ProfileCompilationInfo result(/*for_boot_image=*/true);
2340     ASSERT_TRUE(result.Load(reference_profile_fd));
2341     ASSERT_TRUE(info2.Equals(result));
2342   }
2343 
2344   // Without force-merge we should fail.
2345   {
2346     ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, {"--boot-image-merge"}),
2347               ProfmanResult::kErrorBadProfiles);
2348   }
2349 }
2350 
2351 }  // namespace art
2352