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