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