1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include "android-base/file.h"
20 #include "android-base/strings.h"
21 #include "art_method-inl.h"
22 #include "base/unix_file/fd_file.h"
23 #include "base/utils.h"
24 #include "common_runtime_test.h"
25 #include "dex/descriptors_names.h"
26 #include "dex/type_reference.h"
27 #include "exec_utils.h"
28 #include "linear_alloc.h"
29 #include "mirror/class-inl.h"
30 #include "obj_ptr-inl.h"
31 #include "profile/profile_compilation_info.h"
32 #include "profile_assistant.h"
33 #include "scoped_thread_state_change-inl.h"
34 
35 namespace art {
36 
37 using Hotness = ProfileCompilationInfo::MethodHotness;
38 using TypeReferenceSet = std::set<TypeReference, TypeReferenceValueComparator>;
39 using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache;
40 
41 // TODO(calin): These tests share a lot with the ProfileCompilationInfo tests.
42 // we should introduce a better abstraction to extract the common parts.
43 class ProfileAssistantTest : public CommonRuntimeTest {
44  public:
PostRuntimeCreate()45   void PostRuntimeCreate() override {
46     allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
47 
48     dex1 = fake_dex_storage.AddFakeDex("location1", /* checksum= */ 1, /* num_method_ids= */ 10001);
49     dex2 = fake_dex_storage.AddFakeDex("location2", /* checksum= */ 2, /* num_method_ids= */ 10002);
50     dex3 = fake_dex_storage.AddFakeDex("location3", /* checksum= */ 3, /* num_method_ids= */ 10003);
51     dex4 = fake_dex_storage.AddFakeDex("location4", /* checksum= */ 4, /* num_method_ids= */ 10004);
52 
53     dex1_checksum_missmatch = fake_dex_storage.AddFakeDex(
54         "location1", /* checksum= */ 12, /* num_method_ids= */ 10001);
55   }
56 
57  protected:
AddMethod(ProfileCompilationInfo * info,const DexFile * dex,uint16_t method_idx,const std::vector<ProfileInlineCache> & inline_caches,Hotness::Flag flags)58   bool AddMethod(ProfileCompilationInfo* info,
59                 const DexFile* dex,
60                 uint16_t method_idx,
61                 const std::vector<ProfileInlineCache>& inline_caches,
62                 Hotness::Flag flags) {
63     return info->AddMethod(
64         ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches), flags);
65   }
66 
AddMethod(ProfileCompilationInfo * info,const DexFile * dex,uint16_t method_idx,Hotness::Flag flags,const ProfileCompilationInfo::ProfileSampleAnnotation & annotation=ProfileCompilationInfo::ProfileSampleAnnotation::kNone)67   bool AddMethod(ProfileCompilationInfo* info,
68                  const DexFile* dex,
69                  uint16_t method_idx,
70                  Hotness::Flag flags,
71                  const ProfileCompilationInfo::ProfileSampleAnnotation& annotation
72                     = ProfileCompilationInfo::ProfileSampleAnnotation::kNone) {
73     return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx)),
74                            flags,
75                            annotation);
76   }
77 
AddClass(ProfileCompilationInfo * info,const DexFile * dex,dex::TypeIndex type_index)78   bool AddClass(ProfileCompilationInfo* info,
79                 const DexFile* dex,
80                 dex::TypeIndex type_index) {
81     std::vector<dex::TypeIndex> classes = {type_index};
82     return info->AddClassesForDex(dex, classes.begin(), classes.end());
83   }
84 
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)85   void SetupProfile(const DexFile* dex_file1,
86                     const DexFile* dex_file2,
87                     uint16_t number_of_methods,
88                     uint16_t number_of_classes,
89                     const ScratchFile& profile,
90                     ProfileCompilationInfo* info,
91                     uint16_t start_method_index = 0,
92                     bool reverse_dex_write_order = false) {
93     for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
94       // reverse_dex_write_order controls the order in which the dex files will be added to
95       // the profile and thus written to disk.
96       std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches(dex_file1 , dex_file2, dex3);
97       Hotness::Flag flags = static_cast<Hotness::Flag>(
98           Hotness::kFlagHot | Hotness::kFlagPostStartup);
99       if (reverse_dex_write_order) {
100         ASSERT_TRUE(AddMethod(info, dex_file2, i, inline_caches, flags));
101         ASSERT_TRUE(AddMethod(info, dex_file1, i, inline_caches, flags));
102       } else {
103         ASSERT_TRUE(AddMethod(info, dex_file1, i, inline_caches, flags));
104         ASSERT_TRUE(AddMethod(info, dex_file2, i, inline_caches, flags));
105       }
106     }
107     for (uint16_t i = 0; i < number_of_classes; i++) {
108       ASSERT_TRUE(AddClass(info, dex_file1, dex::TypeIndex(i)));
109     }
110 
111     ASSERT_TRUE(info->Save(GetFd(profile)));
112     ASSERT_EQ(0, profile.GetFile()->Flush());
113     ASSERT_TRUE(profile.GetFile()->ResetOffset());
114   }
115 
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)116   void SetupBasicProfile(const DexFile* dex,
117                          const std::vector<uint32_t>& hot_methods,
118                          const std::vector<uint32_t>& startup_methods,
119                          const std::vector<uint32_t>& post_startup_methods,
120                          const ScratchFile& profile,
121                          ProfileCompilationInfo* info) {
122     for (uint32_t idx : hot_methods) {
123       AddMethod(info, dex, idx, Hotness::kFlagHot);
124     }
125     for (uint32_t idx : startup_methods) {
126       AddMethod(info, dex, idx, Hotness::kFlagStartup);
127     }
128     for (uint32_t idx : post_startup_methods) {
129       AddMethod(info, dex, idx, Hotness::kFlagPostStartup);
130     }
131     ASSERT_TRUE(info->Save(GetFd(profile)));
132     ASSERT_EQ(0, profile.GetFile()->Flush());
133     ASSERT_TRUE(profile.GetFile()->ResetOffset());
134   }
135 
136   // 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)137   std::vector<ProfileInlineCache> GetTestInlineCaches(
138         const DexFile* dex_file1, const DexFile* dex_file2, const DexFile* dex_file3) {
139     std::vector<ProfileInlineCache> inline_caches;
140     // Monomorphic
141     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
142       std::vector<TypeReference> types = {TypeReference(dex_file1, dex::TypeIndex(0))};
143       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
144     }
145     // Polymorphic
146     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
147       std::vector<TypeReference> types = {
148           TypeReference(dex_file1, dex::TypeIndex(0)),
149           TypeReference(dex_file2, dex::TypeIndex(1)),
150           TypeReference(dex_file3, dex::TypeIndex(2))};
151       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
152     }
153     // Megamorphic
154     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
155       // we need 5 types to make the cache megamorphic
156       std::vector<TypeReference> types = {
157           TypeReference(dex_file1, dex::TypeIndex(0)),
158           TypeReference(dex_file1, dex::TypeIndex(1)),
159           TypeReference(dex_file1, dex::TypeIndex(2)),
160           TypeReference(dex_file1, dex::TypeIndex(3)),
161           TypeReference(dex_file1, dex::TypeIndex(4))};
162       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
163     }
164     // Missing types
165     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
166       std::vector<TypeReference> types;
167       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ true, types));
168     }
169 
170     return inline_caches;
171   }
172 
GetFd(const ScratchFile & file) const173   int GetFd(const ScratchFile& file) const {
174     return static_cast<int>(file.GetFd());
175   }
176 
CheckProfileInfo(ScratchFile & file,const ProfileCompilationInfo & info)177   void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
178     ProfileCompilationInfo file_info;
179     ASSERT_TRUE(file.GetFile()->ResetOffset());
180     ASSERT_TRUE(file_info.Load(GetFd(file)));
181     ASSERT_TRUE(file_info.Equals(info));
182   }
183 
GetProfmanCmd()184   std::string GetProfmanCmd() {
185     std::string file_path = GetArtBinDir() + "/profman";
186     if (kIsDebugBuild) {
187       file_path += "d";
188     }
189     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
190     return file_path;
191   }
192 
193   // 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> ())194   int ProcessProfiles(
195       const std::vector<int>& profiles_fd,
196       int reference_profile_fd,
197       const std::vector<const std::string>& extra_args = std::vector<const std::string>()) {
198     std::string profman_cmd = GetProfmanCmd();
199     std::vector<std::string> argv_str;
200     argv_str.push_back(profman_cmd);
201     for (size_t k = 0; k < profiles_fd.size(); k++) {
202       argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
203     }
204     argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
205     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
206 
207     std::string error;
208     return ExecAndReturnCode(argv_str, &error);
209   }
210 
GenerateTestProfile(const std::string & filename)211   bool GenerateTestProfile(const std::string& filename) {
212     std::string profman_cmd = GetProfmanCmd();
213     std::vector<std::string> argv_str;
214     argv_str.push_back(profman_cmd);
215     argv_str.push_back("--generate-test-profile=" + filename);
216     std::string error;
217     return ExecAndReturnCode(argv_str, &error);
218   }
219 
GenerateTestProfileWithInputDex(const std::string & filename)220   bool GenerateTestProfileWithInputDex(const std::string& filename) {
221     std::string profman_cmd = GetProfmanCmd();
222     std::vector<std::string> argv_str;
223     argv_str.push_back(profman_cmd);
224     argv_str.push_back("--generate-test-profile=" + filename);
225     argv_str.push_back("--generate-test-profile-seed=0");
226     argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
227     argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
228     std::string error;
229     return ExecAndReturnCode(argv_str, &error);
230   }
231 
CreateProfile(const std::string & profile_file_contents,const std::string & filename,const std::string & dex_location)232   bool CreateProfile(const std::string& profile_file_contents,
233                      const std::string& filename,
234                      const std::string& dex_location) {
235     ScratchFile class_names_file;
236     File* file = class_names_file.GetFile();
237     EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
238     EXPECT_EQ(0, file->Flush());
239     EXPECT_TRUE(file->ResetOffset());
240     std::string profman_cmd = GetProfmanCmd();
241     std::vector<std::string> argv_str;
242     argv_str.push_back(profman_cmd);
243     argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
244     argv_str.push_back("--reference-profile-file=" + filename);
245     argv_str.push_back("--apk=" + dex_location);
246     argv_str.push_back("--dex-location=" + dex_location);
247     std::string error;
248     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
249     return true;
250   }
251 
RunProfman(const std::string & filename,std::vector<std::string> & extra_args,std::string * output)252   bool RunProfman(const std::string& filename,
253                   std::vector<std::string>& extra_args,
254                   std::string* output) {
255     ScratchFile output_file;
256     std::string profman_cmd = GetProfmanCmd();
257     std::vector<std::string> argv_str;
258     argv_str.push_back(profman_cmd);
259     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
260     argv_str.push_back("--profile-file=" + filename);
261     argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
262     argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
263     argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
264     std::string error;
265     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
266     File* file = output_file.GetFile();
267     EXPECT_EQ(0, file->Flush());
268     EXPECT_TRUE(file->ResetOffset());
269     int64_t length = file->GetLength();
270     std::unique_ptr<char[]> buf(new char[length]);
271     EXPECT_EQ(file->Read(buf.get(), length, 0), length);
272     *output = std::string(buf.get(), length);
273     return true;
274   }
275 
DumpClassesAndMethods(const std::string & filename,std::string * file_contents)276   bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
277     std::vector<std::string> extra_args;
278     extra_args.push_back("--dump-classes-and-methods");
279     return RunProfman(filename, extra_args, file_contents);
280   }
281 
DumpOnly(const std::string & filename,std::string * file_contents)282   bool DumpOnly(const std::string& filename, std::string* file_contents) {
283     std::vector<std::string> extra_args;
284     extra_args.push_back("--dump-only");
285     return RunProfman(filename, extra_args, file_contents);
286   }
287 
CreateAndDump(const std::string & input_file_contents,std::string * output_file_contents)288   bool CreateAndDump(const std::string& input_file_contents,
289                      std::string* output_file_contents) {
290     ScratchFile profile_file;
291     EXPECT_TRUE(CreateProfile(input_file_contents,
292                               profile_file.GetFilename(),
293                               GetLibCoreDexFileNames()[0]));
294     profile_file.GetFile()->ResetOffset();
295     EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
296     return true;
297   }
298 
GetClass(ScopedObjectAccess & soa,jobject class_loader,const std::string & clazz)299   ObjPtr<mirror::Class> GetClass(ScopedObjectAccess& soa,
300                                  jobject class_loader,
301                                  const std::string& clazz) REQUIRES_SHARED(Locks::mutator_lock_) {
302     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
303     StackHandleScope<1> hs(soa.Self());
304     Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
305         ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader))));
306     return class_linker->FindClass(soa.Self(), clazz.c_str(), h_loader);
307   }
308 
GetVirtualMethod(jobject class_loader,const std::string & clazz,const std::string & name)309   ArtMethod* GetVirtualMethod(jobject class_loader,
310                               const std::string& clazz,
311                               const std::string& name) {
312     ScopedObjectAccess soa(Thread::Current());
313     ObjPtr<mirror::Class> klass = GetClass(soa, class_loader, clazz);
314     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
315     const auto pointer_size = class_linker->GetImagePointerSize();
316     ArtMethod* method = nullptr;
317     for (auto& m : klass->GetVirtualMethods(pointer_size)) {
318       if (name == m.GetName()) {
319         EXPECT_TRUE(method == nullptr);
320         method = &m;
321       }
322     }
323     return method;
324   }
325 
MakeTypeReference(ObjPtr<mirror::Class> klass)326   static TypeReference MakeTypeReference(ObjPtr<mirror::Class> klass)
327       REQUIRES_SHARED(Locks::mutator_lock_) {
328     return TypeReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
329   }
330 
331   // Verify that given method has the expected inline caches and nothing else.
AssertInlineCaches(ArtMethod * method,const TypeReferenceSet & expected_clases,const ProfileCompilationInfo & info,bool is_megamorphic,bool is_missing_types)332   void AssertInlineCaches(ArtMethod* method,
333                           const TypeReferenceSet& expected_clases,
334                           const ProfileCompilationInfo& info,
335                           bool is_megamorphic,
336                           bool is_missing_types)
337       REQUIRES_SHARED(Locks::mutator_lock_) {
338     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
339         info.GetHotMethodInfo(MethodReference(
340             method->GetDexFile(), method->GetDexMethodIndex()));
341     ASSERT_TRUE(pmi != nullptr);
342     ASSERT_EQ(pmi->inline_caches->size(), 1u);
343     const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
344 
345     ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
346     ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
347     ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
348     size_t found = 0;
349     for (const TypeReference& type_ref : expected_clases) {
350       for (const auto& class_ref : dex_pc_data.classes) {
351         ProfileCompilationInfo::DexReference dex_ref =
352             pmi->dex_references[class_ref.dex_profile_index];
353         if (dex_ref.MatchesDex(type_ref.dex_file) && class_ref.type_index == type_ref.TypeIndex()) {
354           found++;
355         }
356       }
357     }
358 
359     ASSERT_EQ(expected_clases.size(), found);
360   }
361 
CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,uint16_t methods_in_ref_profile)362   int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
363                                           uint16_t methods_in_ref_profile) {
364     ScratchFile profile;
365     ScratchFile reference_profile;
366     std::vector<int> profile_fds({ GetFd(profile)});
367     int reference_profile_fd = GetFd(reference_profile);
368     std::vector<uint32_t> hot_methods_cur;
369     std::vector<uint32_t> hot_methods_ref;
370     std::vector<uint32_t> empty_vector;
371     for (size_t i = 0; i < methods_in_cur_profile; ++i) {
372       hot_methods_cur.push_back(i);
373     }
374     for (size_t i = 0; i < methods_in_ref_profile; ++i) {
375       hot_methods_ref.push_back(i);
376     }
377     ProfileCompilationInfo info1;
378     SetupBasicProfile(dex1, hot_methods_cur, empty_vector, empty_vector,
379         profile,  &info1);
380     ProfileCompilationInfo info2;
381     SetupBasicProfile(dex1, hot_methods_ref, empty_vector, empty_vector,
382         reference_profile,  &info2);
383     return ProcessProfiles(profile_fds, reference_profile_fd);
384   }
385 
CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,uint16_t classes_in_ref_profile)386   int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
387                                          uint16_t classes_in_ref_profile) {
388     ScratchFile profile;
389     ScratchFile reference_profile;
390 
391     std::vector<int> profile_fds({ GetFd(profile)});
392     int reference_profile_fd = GetFd(reference_profile);
393 
394     ProfileCompilationInfo info1;
395     SetupProfile(dex1, dex2, 0, classes_in_cur_profile, profile,  &info1);
396     ProfileCompilationInfo info2;
397     SetupProfile(dex1, dex2, 0, classes_in_ref_profile, reference_profile, &info2);
398     return ProcessProfiles(profile_fds, reference_profile_fd);
399   }
400 
401   std::unique_ptr<ArenaAllocator> allocator_;
402 
403   const DexFile* dex1;
404   const DexFile* dex2;
405   const DexFile* dex3;
406   const DexFile* dex4;
407   const DexFile* dex1_checksum_missmatch;
408   FakeDexStorage fake_dex_storage;
409 };
410 
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferences)411 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
412   ScratchFile profile1;
413   ScratchFile profile2;
414   ScratchFile reference_profile;
415 
416   std::vector<int> profile_fds({
417       GetFd(profile1),
418       GetFd(profile2)});
419   int reference_profile_fd = GetFd(reference_profile);
420 
421   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
422   ProfileCompilationInfo info1;
423   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
424   ProfileCompilationInfo info2;
425   SetupProfile(dex3, dex4, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
426 
427   // We should advise compilation.
428   ASSERT_EQ(ProfileAssistant::kCompile,
429             ProcessProfiles(profile_fds, reference_profile_fd));
430   // The resulting compilation info must be equal to the merge of the inputs.
431   ProfileCompilationInfo result;
432   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
433   ASSERT_TRUE(result.Load(reference_profile_fd));
434 
435   ProfileCompilationInfo expected;
436   ASSERT_TRUE(expected.MergeWith(info1));
437   ASSERT_TRUE(expected.MergeWith(info2));
438   ASSERT_TRUE(expected.Equals(result));
439 
440   // The information from profiles must remain the same.
441   CheckProfileInfo(profile1, info1);
442   CheckProfileInfo(profile2, info2);
443 }
444 
445 // TODO(calin): Add more tests for classes.
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferencesBecauseOfClasses)446 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
447   ScratchFile profile1;
448   ScratchFile reference_profile;
449 
450   std::vector<int> profile_fds({
451       GetFd(profile1)});
452   int reference_profile_fd = GetFd(reference_profile);
453 
454   const uint16_t kNumberOfClassesToEnableCompilation = 100;
455   ProfileCompilationInfo info1;
456   SetupProfile(dex1, dex2, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
457 
458   // We should advise compilation.
459   ASSERT_EQ(ProfileAssistant::kCompile,
460             ProcessProfiles(profile_fds, reference_profile_fd));
461   // The resulting compilation info must be equal to the merge of the inputs.
462   ProfileCompilationInfo result;
463   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
464   ASSERT_TRUE(result.Load(reference_profile_fd));
465 
466   ProfileCompilationInfo expected;
467   ASSERT_TRUE(expected.MergeWith(info1));
468   ASSERT_TRUE(expected.Equals(result));
469 
470   // The information from profiles must remain the same.
471   CheckProfileInfo(profile1, info1);
472 }
473 
TEST_F(ProfileAssistantTest,AdviseCompilationNonEmptyReferences)474 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
475   ScratchFile profile1;
476   ScratchFile profile2;
477   ScratchFile reference_profile;
478 
479   std::vector<int> profile_fds({
480       GetFd(profile1),
481       GetFd(profile2)});
482   int reference_profile_fd = GetFd(reference_profile);
483 
484   // The new profile info will contain the methods with indices 0-100.
485   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
486   ProfileCompilationInfo info1;
487   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
488   ProfileCompilationInfo info2;
489   SetupProfile(dex3, dex4, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
490 
491 
492   // The reference profile info will contain the methods with indices 50-150.
493   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
494   ProfileCompilationInfo reference_info;
495   SetupProfile(dex1, dex2, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
496       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
497 
498   // We should advise compilation.
499   ASSERT_EQ(ProfileAssistant::kCompile,
500             ProcessProfiles(profile_fds, reference_profile_fd));
501 
502   // The resulting compilation info must be equal to the merge of the inputs
503   ProfileCompilationInfo result;
504   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
505   ASSERT_TRUE(result.Load(reference_profile_fd));
506 
507   ProfileCompilationInfo expected;
508   ASSERT_TRUE(expected.MergeWith(info1));
509   ASSERT_TRUE(expected.MergeWith(info2));
510   ASSERT_TRUE(expected.MergeWith(reference_info));
511   ASSERT_TRUE(expected.Equals(result));
512 
513   // The information from profiles must remain the same.
514   CheckProfileInfo(profile1, info1);
515   CheckProfileInfo(profile2, info2);
516 }
517 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilation)518 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
519   ScratchFile profile1;
520   ScratchFile profile2;
521   ScratchFile reference_profile;
522 
523   std::vector<int> profile_fds({
524       GetFd(profile1),
525       GetFd(profile2)});
526   int reference_profile_fd = GetFd(reference_profile);
527 
528   const uint16_t kNumberOfMethodsToSkipCompilation = 24;  // Threshold is 100.
529   ProfileCompilationInfo info1;
530   SetupProfile(dex1, dex2, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
531   ProfileCompilationInfo info2;
532   SetupProfile(dex3, dex4, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
533 
534   // We should not advise compilation.
535   ASSERT_EQ(ProfileAssistant::kSkipCompilation,
536             ProcessProfiles(profile_fds, reference_profile_fd));
537 
538   // The information from profiles must remain the same.
539   ProfileCompilationInfo file_info1;
540   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
541   ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
542   ASSERT_TRUE(file_info1.Equals(info1));
543 
544   ProfileCompilationInfo file_info2;
545   ASSERT_TRUE(profile2.GetFile()->ResetOffset());
546   ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
547   ASSERT_TRUE(file_info2.Equals(info2));
548 
549   // Reference profile files must remain empty.
550   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
551 
552   // The information from profiles must remain the same.
553   CheckProfileInfo(profile1, info1);
554   CheckProfileInfo(profile2, info2);
555 }
556 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilationMethodPercentage)557 TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
558   const uint16_t kNumberOfMethodsInRefProfile = 6000;
559   const uint16_t kNumberOfMethodsInCurProfile = 6100;  // Threshold is 2%.
560   // We should not advise compilation.
561   ASSERT_EQ(ProfileAssistant::kSkipCompilation,
562             CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
563                                                 kNumberOfMethodsInRefProfile));
564 }
565 
TEST_F(ProfileAssistantTest,ShouldAdviseCompilationMethodPercentage)566 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
567   const uint16_t kNumberOfMethodsInRefProfile = 6000;
568   const uint16_t kNumberOfMethodsInCurProfile = 6200;  // Threshold is 2%.
569   // We should advise compilation.
570   ASSERT_EQ(ProfileAssistant::kCompile,
571             CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
572                                                 kNumberOfMethodsInRefProfile));
573 }
574 
TEST_F(ProfileAssistantTest,DoNotdviseCompilationClassPercentage)575 TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
576   const uint16_t kNumberOfClassesInRefProfile = 6000;
577   const uint16_t kNumberOfClassesInCurProfile = 6110;  // Threshold is 2%.
578   // We should not advise compilation.
579   ASSERT_EQ(ProfileAssistant::kSkipCompilation,
580             CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
581                                                kNumberOfClassesInRefProfile));
582 }
583 
TEST_F(ProfileAssistantTest,ShouldAdviseCompilationClassPercentage)584 TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
585   const uint16_t kNumberOfClassesInRefProfile = 6000;
586   const uint16_t kNumberOfClassesInCurProfile = 6120;  // Threshold is 2%.
587   // We should advise compilation.
588   ASSERT_EQ(ProfileAssistant::kCompile,
589             CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
590                                                kNumberOfClassesInRefProfile));
591 }
592 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfProfiles)593 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
594   ScratchFile profile1;
595   ScratchFile profile2;
596   ScratchFile reference_profile;
597 
598   std::vector<int> profile_fds({
599       GetFd(profile1),
600       GetFd(profile2)});
601   int reference_profile_fd = GetFd(reference_profile);
602 
603   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
604   // Assign different hashes for the same dex file. This will make merging of information to fail.
605   ProfileCompilationInfo info1;
606   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
607   ProfileCompilationInfo info2;
608   SetupProfile(
609       dex1_checksum_missmatch, dex2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
610 
611   // We should fail processing.
612   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
613             ProcessProfiles(profile_fds, reference_profile_fd));
614 
615   // The information from profiles must remain the same.
616   CheckProfileInfo(profile1, info1);
617   CheckProfileInfo(profile2, info2);
618 
619   // Reference profile files must still remain empty.
620   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
621 }
622 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfReferenceProfiles)623 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
624   ScratchFile profile1;
625   ScratchFile reference_profile;
626 
627   std::vector<int> profile_fds({
628       GetFd(profile1)});
629   int reference_profile_fd = GetFd(reference_profile);
630 
631   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
632   // Assign different hashes for the same dex file. This will make merging of information to fail.
633   ProfileCompilationInfo info1;
634   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
635   ProfileCompilationInfo reference_info;
636   SetupProfile(
637       dex1_checksum_missmatch, dex2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
638 
639   // We should not advise compilation.
640   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
641   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
642   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
643             ProcessProfiles(profile_fds, reference_profile_fd));
644 
645   // The information from profiles must remain the same.
646   CheckProfileInfo(profile1, info1);
647 }
648 
TEST_F(ProfileAssistantTest,TestProfileGeneration)649 TEST_F(ProfileAssistantTest, TestProfileGeneration) {
650   ScratchFile profile;
651   // Generate a test profile.
652   GenerateTestProfile(profile.GetFilename());
653 
654   // Verify that the generated profile is valid and can be loaded.
655   ASSERT_TRUE(profile.GetFile()->ResetOffset());
656   ProfileCompilationInfo info;
657   ASSERT_TRUE(info.Load(GetFd(profile)));
658 }
659 
TEST_F(ProfileAssistantTest,TestProfileGenerationWithIndexDex)660 TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
661   ScratchFile profile;
662   // Generate a test profile passing in a dex file as reference.
663   GenerateTestProfileWithInputDex(profile.GetFilename());
664 
665   // Verify that the generated profile is valid and can be loaded.
666   ASSERT_TRUE(profile.GetFile()->ResetOffset());
667   ProfileCompilationInfo info;
668   ASSERT_TRUE(info.Load(GetFd(profile)));
669 }
670 
TEST_F(ProfileAssistantTest,TestProfileCreationAllMatch)671 TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
672   // Class names put here need to be in sorted order.
673   std::vector<std::string> class_names = {
674     "HLjava/lang/Object;-><init>()V",
675     "Ljava/lang/Comparable;",
676     "Ljava/lang/Math;",
677     "Ljava/lang/Object;",
678     "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
679   };
680   std::string file_contents;
681   for (std::string& class_name : class_names) {
682     file_contents += class_name + std::string("\n");
683   }
684   std::string output_file_contents;
685   ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
686   ASSERT_EQ(output_file_contents, file_contents);
687 }
688 
TEST_F(ProfileAssistantTest,TestArrayClass)689 TEST_F(ProfileAssistantTest, TestArrayClass) {
690   std::vector<std::string> class_names = {
691     "[Ljava/lang/Comparable;",
692   };
693   std::string file_contents;
694   for (std::string& class_name : class_names) {
695     file_contents += class_name + std::string("\n");
696   }
697   std::string output_file_contents;
698   ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
699   ASSERT_EQ(output_file_contents, file_contents);
700 }
701 
TEST_F(ProfileAssistantTest,TestProfileCreationGenerateMethods)702 TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
703   // Class names put here need to be in sorted order.
704   std::vector<std::string> class_names = {
705     "HLjava/lang/Math;->*",
706   };
707   std::string input_file_contents;
708   std::string expected_contents;
709   for (std::string& class_name : class_names) {
710     input_file_contents += class_name + std::string("\n");
711     expected_contents += DescriptorToDot(class_name.c_str()) +
712         std::string("\n");
713   }
714   std::string output_file_contents;
715   ScratchFile profile_file;
716   EXPECT_TRUE(CreateProfile(input_file_contents,
717                             profile_file.GetFilename(),
718                             GetLibCoreDexFileNames()[0]));
719   ProfileCompilationInfo info;
720   profile_file.GetFile()->ResetOffset();
721   ASSERT_TRUE(info.Load(GetFd(profile_file)));
722   // Verify that the profile has matching methods.
723   ScopedObjectAccess soa(Thread::Current());
724   ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader= */ nullptr, "Ljava/lang/Math;");
725   ASSERT_TRUE(klass != nullptr);
726   size_t method_count = 0;
727   for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
728     if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
729       ++method_count;
730       std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
731           info.GetHotMethodInfo(MethodReference(method.GetDexFile(), method.GetDexMethodIndex()));
732       ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
733     }
734   }
735   EXPECT_GT(method_count, 0u);
736 }
737 
JoinProfileLines(const std::vector<std::string> & lines)738 static std::string JoinProfileLines(const std::vector<std::string>& lines) {
739   std::string result = android::base::Join(lines, '\n');
740   return result + '\n';
741 }
742 
TEST_F(ProfileAssistantTest,TestBootImageProfile)743 TEST_F(ProfileAssistantTest, TestBootImageProfile) {
744   const std::string core_dex = GetLibCoreDexFileNames()[0];
745 
746   std::vector<ScratchFile> profiles;
747 
748   // In image with enough clean occurrences.
749   const std::string kCleanClass = "Ljava/lang/CharSequence;";
750   // In image with enough dirty occurrences.
751   const std::string kDirtyClass = "Ljava/lang/Object;";
752   // Not in image becauseof not enough occurrences.
753   const std::string kUncommonCleanClass = "Ljava/lang/Process;";
754   const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
755   // Method that is common and hot. Should end up in profile.
756   const std::string kCommonHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
757   // Uncommon method, should not end up in profile
758   const std::string kUncommonMethod = "Ljava/util/HashMap;-><init>()V";
759   // Method that gets marked as hot since it's in multiple profile and marked as startup.
760   const std::string kStartupMethodForUpgrade = "Ljava/util/ArrayList;->clear()V";
761   // Startup method used by a special package which will get a different threshold;
762   const std::string kSpecialPackageStartupMethod =
763       "Ljava/lang/Object;->toString()Ljava/lang/String;";
764   // Method used by a special package which will get a different threshold;
765   const std::string kUncommonSpecialPackageMethod = "Ljava/lang/Object;->hashCode()I";
766   // Blacklisted class
767   const std::string kPreloadedBlacklistedClass = "Ljava/lang/Thread;";
768 
769   // Thresholds for this test.
770   static const size_t kDirtyThreshold = 100;
771   static const size_t kCleanThreshold = 50;
772   static const size_t kPreloadedThreshold = 100;
773   static const size_t kMethodThreshold = 75;
774   static const size_t kSpecialThreshold = 50;
775   const std::string kSpecialPackage = "dex4";
776 
777   // Create boot profile content, attributing the classes and methods to different dex files.
778   std::vector<std::string> input_data = {
779       "{dex1}" + kCleanClass,
780       "{dex1}" + kDirtyClass,
781       "{dex1}" + kUncommonCleanClass,
782       "{dex1}H" + kCommonHotMethod,
783       "{dex1}P" + kStartupMethodForUpgrade,
784       "{dex1}" + kUncommonDirtyClass,
785       "{dex1}" + kPreloadedBlacklistedClass,
786 
787       "{dex2}" + kCleanClass,
788       "{dex2}" + kDirtyClass,
789       "{dex2}P" + kCommonHotMethod,
790       "{dex2}P" + kStartupMethodForUpgrade,
791       "{dex2}" + kUncommonDirtyClass,
792       "{dex2}" + kPreloadedBlacklistedClass,
793 
794       "{dex3}P" + kUncommonMethod,
795       "{dex3}PS" + kStartupMethodForUpgrade,
796       "{dex3}S" + kCommonHotMethod,
797       "{dex3}S" + kSpecialPackageStartupMethod,
798       "{dex3}" + kDirtyClass,
799       "{dex3}" + kPreloadedBlacklistedClass,
800 
801       "{dex4}" + kDirtyClass,
802       "{dex4}P" + kCommonHotMethod,
803       "{dex4}S" + kSpecialPackageStartupMethod,
804       "{dex4}P" + kUncommonSpecialPackageMethod,
805       "{dex4}" + kPreloadedBlacklistedClass,
806   };
807   std::string input_file_contents = JoinProfileLines(input_data);
808 
809   ScratchFile preloaded_class_blacklist;
810   std::string blacklist_content = DescriptorToDot(kPreloadedBlacklistedClass.c_str());
811   EXPECT_TRUE(preloaded_class_blacklist.GetFile()->WriteFully(
812       blacklist_content.c_str(), blacklist_content.length()));
813 
814   EXPECT_EQ(0, preloaded_class_blacklist.GetFile()->Flush());
815   EXPECT_TRUE(preloaded_class_blacklist.GetFile()->ResetOffset());
816   // Expected data
817   std::vector<std::string> expected_data = {
818       kCleanClass,
819       kDirtyClass,
820       kPreloadedBlacklistedClass,
821       "HSP" + kCommonHotMethod,
822       "HS" + kSpecialPackageStartupMethod,
823       "HSP" + kStartupMethodForUpgrade
824   };
825   std::string expected_profile_content = JoinProfileLines(expected_data);
826 
827   std::vector<std::string> expected_preloaded_data = {
828        DescriptorToDot(kDirtyClass.c_str())
829   };
830   std::string expected_preloaded_content = JoinProfileLines(expected_preloaded_data);
831 
832   ScratchFile profile;
833   EXPECT_TRUE(CreateProfile(input_file_contents, profile.GetFilename(), core_dex));
834 
835   ProfileCompilationInfo bootProfile;
836   bootProfile.Load(profile.GetFilename(), /*for_boot_image*/ true);
837 
838   // Generate the boot profile.
839   ScratchFile out_profile;
840   ScratchFile out_preloaded_classes;
841   ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
842   ASSERT_TRUE(out_preloaded_classes.GetFile()->ResetOffset());
843   std::vector<std::string> args;
844   args.push_back(GetProfmanCmd());
845   args.push_back("--generate-boot-image-profile");
846   args.push_back("--class-threshold=" + std::to_string(kDirtyThreshold));
847   args.push_back("--clean-class-threshold=" + std::to_string(kCleanThreshold));
848   args.push_back("--method-threshold=" + std::to_string(kMethodThreshold));
849   args.push_back("--preloaded-class-threshold=" + std::to_string(kPreloadedThreshold));
850   args.push_back(
851       "--special-package=" + kSpecialPackage + ":" + std::to_string(kSpecialThreshold));
852   args.push_back("--profile-file=" + profile.GetFilename());
853   args.push_back("--out-profile-path=" + out_profile.GetFilename());
854   args.push_back("--out-preloaded-classes-path=" + out_preloaded_classes.GetFilename());
855   args.push_back("--apk=" + core_dex);
856   args.push_back("--dex-location=" + core_dex);
857   args.push_back("--preloaded-classes-blacklist=" + preloaded_class_blacklist.GetFilename());
858 
859   std::string error;
860   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error;
861   ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
862 
863   // Verify the boot profile contents.
864   std::string output_profile_contents;
865   ASSERT_TRUE(android::base::ReadFileToString(
866       out_profile.GetFilename(), &output_profile_contents));
867   ASSERT_EQ(output_profile_contents, expected_profile_content);
868 
869     // Verify the preloaded classes content.
870   std::string output_preloaded_contents;
871   ASSERT_TRUE(android::base::ReadFileToString(
872       out_preloaded_classes.GetFilename(), &output_preloaded_contents));
873   ASSERT_EQ(output_preloaded_contents, expected_preloaded_content);
874 }
875 
TEST_F(ProfileAssistantTest,TestBootImageProfileWith2RawProfiles)876 TEST_F(ProfileAssistantTest, TestBootImageProfileWith2RawProfiles) {
877   const std::string core_dex = GetLibCoreDexFileNames()[0];
878 
879   std::vector<ScratchFile> profiles;
880 
881   const std::string kCommonClassUsedByDex1 = "Ljava/lang/CharSequence;";
882   const std::string kCommonClassUsedByDex1Dex2 = "Ljava/lang/Object;";
883   const std::string kUncommonClass = "Ljava/lang/Process;";
884   const std::string kCommonHotMethodUsedByDex1 =
885       "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
886   const std::string kCommonHotMethodUsedByDex1Dex2 = "Ljava/lang/Object;->hashCode()I";
887   const std::string kUncommonHotMethod = "Ljava/util/HashMap;-><init>()V";
888 
889 
890   // Thresholds for this test.
891   static const size_t kDirtyThreshold = 100;
892   static const size_t kCleanThreshold = 100;
893   static const size_t kMethodThreshold = 100;
894 
895     // Create boot profile content, attributing the classes and methods to different dex files.
896   std::vector<std::string> input_data1 = {
897       "{dex1}" + kCommonClassUsedByDex1,
898       "{dex1}" + kCommonClassUsedByDex1Dex2,
899       "{dex1}" + kUncommonClass,
900       "{dex1}H" + kCommonHotMethodUsedByDex1Dex2,
901       "{dex1}" + kCommonHotMethodUsedByDex1,
902   };
903   std::vector<std::string> input_data2 = {
904       "{dex1}" + kCommonClassUsedByDex1,
905       "{dex2}" + kCommonClassUsedByDex1Dex2,
906       "{dex1}H" + kCommonHotMethodUsedByDex1,
907       "{dex2}" + kCommonHotMethodUsedByDex1Dex2,
908       "{dex1}" + kUncommonHotMethod,
909   };
910   std::string input_file_contents1 = JoinProfileLines(input_data1);
911   std::string input_file_contents2 = JoinProfileLines(input_data2);
912 
913   // Expected data
914   std::vector<std::string> expected_data = {
915       kCommonClassUsedByDex1,
916       kCommonClassUsedByDex1Dex2,
917       "H" + kCommonHotMethodUsedByDex1,
918       "H" + kCommonHotMethodUsedByDex1Dex2
919   };
920   std::string expected_profile_content = JoinProfileLines(expected_data);
921 
922   ScratchFile profile1;
923   ScratchFile profile2;
924   EXPECT_TRUE(CreateProfile(input_file_contents1, profile1.GetFilename(), core_dex));
925   EXPECT_TRUE(CreateProfile(input_file_contents2, profile2.GetFilename(), core_dex));
926 
927   ProfileCompilationInfo boot_profile1;
928   ProfileCompilationInfo boot_profile2;
929   boot_profile1.Load(profile1.GetFilename(), /*for_boot_image*/ true);
930   boot_profile2.Load(profile2.GetFilename(), /*for_boot_image*/ true);
931 
932   // Generate the boot profile.
933   ScratchFile out_profile;
934   ScratchFile out_preloaded_classes;
935   ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
936   ASSERT_TRUE(out_preloaded_classes.GetFile()->ResetOffset());
937   std::vector<std::string> args;
938   args.push_back(GetProfmanCmd());
939   args.push_back("--generate-boot-image-profile");
940   args.push_back("--class-threshold=" + std::to_string(kDirtyThreshold));
941   args.push_back("--clean-class-threshold=" + std::to_string(kCleanThreshold));
942   args.push_back("--method-threshold=" + std::to_string(kMethodThreshold));
943   args.push_back("--profile-file=" + profile1.GetFilename());
944   args.push_back("--profile-file=" + profile2.GetFilename());
945   args.push_back("--out-profile-path=" + out_profile.GetFilename());
946   args.push_back("--out-preloaded-classes-path=" + out_preloaded_classes.GetFilename());
947   args.push_back("--apk=" + core_dex);
948   args.push_back("--dex-location=" + core_dex);
949 
950   std::string error;
951   ASSERT_EQ(ExecAndReturnCode(args, &error), 0) << error;
952   ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
953 
954   // Verify the boot profile contents.
955   std::string output_profile_contents;
956   ASSERT_TRUE(android::base::ReadFileToString(
957       out_profile.GetFilename(), &output_profile_contents));
958   ASSERT_EQ(output_profile_contents, expected_profile_content);
959 }
960 
TEST_F(ProfileAssistantTest,TestProfileCreationOneNotMatched)961 TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
962   // Class names put here need to be in sorted order.
963   std::vector<std::string> class_names = {
964     "Ldoesnt/match/this/one;",
965     "Ljava/lang/Comparable;",
966     "Ljava/lang/Object;"
967   };
968   std::string input_file_contents;
969   for (std::string& class_name : class_names) {
970     input_file_contents += class_name + std::string("\n");
971   }
972   std::string output_file_contents;
973   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
974   std::string expected_contents =
975       class_names[1] + std::string("\n") +
976       class_names[2] + std::string("\n");
977   ASSERT_EQ(output_file_contents, expected_contents);
978 }
979 
TEST_F(ProfileAssistantTest,TestProfileCreationNoneMatched)980 TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
981   // Class names put here need to be in sorted order.
982   std::vector<std::string> class_names = {
983     "Ldoesnt/match/this/one;",
984     "Ldoesnt/match/this/one/either;",
985     "Lnor/this/one;"
986   };
987   std::string input_file_contents;
988   for (std::string& class_name : class_names) {
989     input_file_contents += class_name + std::string("\n");
990   }
991   std::string output_file_contents;
992   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
993   std::string expected_contents("");
994   ASSERT_EQ(output_file_contents, expected_contents);
995 }
996 
TEST_F(ProfileAssistantTest,TestProfileCreateInlineCache)997 TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
998   // Create the profile content.
999   std::vector<std::string> methods = {
1000     "HLTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
1001     "HLTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
1002     "HLTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
1003     "HLTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
1004     "HLTestInline;->noInlineCache(LSuper;)I"
1005   };
1006   std::string input_file_contents;
1007   for (std::string& m : methods) {
1008     input_file_contents += m + std::string("\n");
1009   }
1010 
1011   // Create the profile and save it to disk.
1012   ScratchFile profile_file;
1013   ASSERT_TRUE(CreateProfile(input_file_contents,
1014                             profile_file.GetFilename(),
1015                             GetTestDexFileName("ProfileTestMultiDex")));
1016 
1017   // Load the profile from disk.
1018   ProfileCompilationInfo info;
1019   profile_file.GetFile()->ResetOffset();
1020   ASSERT_TRUE(info.Load(GetFd(profile_file)));
1021 
1022   // Load the dex files and verify that the profile contains the expected methods info.
1023   ScopedObjectAccess soa(Thread::Current());
1024   jobject class_loader = LoadDex("ProfileTestMultiDex");
1025   ASSERT_NE(class_loader, nullptr);
1026 
1027   StackHandleScope<3> hs(soa.Self());
1028   Handle<mirror::Class> sub_a = hs.NewHandle(GetClass(soa, class_loader, "LSubA;"));
1029   Handle<mirror::Class> sub_b = hs.NewHandle(GetClass(soa, class_loader, "LSubB;"));
1030   Handle<mirror::Class> sub_c = hs.NewHandle(GetClass(soa, class_loader, "LSubC;"));
1031 
1032   ASSERT_TRUE(sub_a != nullptr);
1033   ASSERT_TRUE(sub_b != nullptr);
1034   ASSERT_TRUE(sub_c != nullptr);
1035 
1036   {
1037     // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
1038     ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1039                                                      "LTestInline;",
1040                                                      "inlineMonomorphic");
1041     ASSERT_TRUE(inline_monomorphic != nullptr);
1042     TypeReferenceSet expected_monomorphic;
1043     expected_monomorphic.insert(MakeTypeReference(sub_a.Get()));
1044     AssertInlineCaches(inline_monomorphic,
1045                        expected_monomorphic,
1046                        info,
1047                        /*is_megamorphic=*/false,
1048                        /*is_missing_types=*/false);
1049   }
1050 
1051   {
1052     // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
1053     ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
1054                                                     "LTestInline;",
1055                                                     "inlinePolymorphic");
1056     ASSERT_TRUE(inline_polymorhic != nullptr);
1057     TypeReferenceSet expected_polymorphic;
1058     expected_polymorphic.insert(MakeTypeReference(sub_a.Get()));
1059     expected_polymorphic.insert(MakeTypeReference(sub_b.Get()));
1060     expected_polymorphic.insert(MakeTypeReference(sub_c.Get()));
1061     AssertInlineCaches(inline_polymorhic,
1062                        expected_polymorphic,
1063                        info,
1064                        /*is_megamorphic=*/false,
1065                        /*is_missing_types=*/false);
1066   }
1067 
1068   {
1069     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1070     ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
1071                                                      "LTestInline;",
1072                                                      "inlineMegamorphic");
1073     ASSERT_TRUE(inline_megamorphic != nullptr);
1074     TypeReferenceSet expected_megamorphic;
1075     AssertInlineCaches(inline_megamorphic,
1076                        expected_megamorphic,
1077                        info,
1078                        /*is_megamorphic=*/true,
1079                        /*is_missing_types=*/false);
1080   }
1081 
1082   {
1083     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
1084     ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
1085                                                        "LTestInline;",
1086                                                        "inlineMissingTypes");
1087     ASSERT_TRUE(inline_missing_types != nullptr);
1088     TypeReferenceSet expected_missing_Types;
1089     AssertInlineCaches(inline_missing_types,
1090                        expected_missing_Types,
1091                        info,
1092                        /*is_megamorphic=*/false,
1093                        /*is_missing_types=*/true);
1094   }
1095 
1096   {
1097     // Verify that method noInlineCache has no inline caches in the profile.
1098     ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
1099     ASSERT_TRUE(no_inline_cache != nullptr);
1100     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
1101         info.GetHotMethodInfo(MethodReference(
1102             no_inline_cache->GetDexFile(), no_inline_cache->GetDexMethodIndex()));
1103     ASSERT_TRUE(pmi_no_inline_cache != nullptr);
1104     ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
1105   }
1106 }
1107 
TEST_F(ProfileAssistantTest,MergeProfilesWithDifferentDexOrder)1108 TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
1109   ScratchFile profile1;
1110   ScratchFile reference_profile;
1111 
1112   std::vector<int> profile_fds({GetFd(profile1)});
1113   int reference_profile_fd = GetFd(reference_profile);
1114 
1115   // The new profile info will contain the methods with indices 0-100.
1116   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1117   ProfileCompilationInfo info1;
1118   SetupProfile(dex1, dex2, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1119       /*start_method_index=*/0, /*reverse_dex_write_order=*/false);
1120 
1121   // The reference profile info will contain the methods with indices 50-150.
1122   // When setting up the profile reverse the order in which the dex files
1123   // are added to the profile. This will verify that profman merges profiles
1124   // with a different dex order correctly.
1125   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1126   ProfileCompilationInfo reference_info;
1127   SetupProfile(dex1, dex2, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1128       &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order=*/true);
1129 
1130   // We should advise compilation.
1131   ASSERT_EQ(ProfileAssistant::kCompile,
1132             ProcessProfiles(profile_fds, reference_profile_fd));
1133 
1134   // The resulting compilation info must be equal to the merge of the inputs.
1135   ProfileCompilationInfo result;
1136   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1137   ASSERT_TRUE(result.Load(reference_profile_fd));
1138 
1139   ProfileCompilationInfo expected;
1140   ASSERT_TRUE(expected.MergeWith(reference_info));
1141   ASSERT_TRUE(expected.MergeWith(info1));
1142   ASSERT_TRUE(expected.Equals(result));
1143 
1144   // The information from profile must remain the same.
1145   CheckProfileInfo(profile1, info1);
1146 }
1147 
TEST_F(ProfileAssistantTest,TestProfileCreateWithInvalidData)1148 TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1149   // Create the profile content.
1150   std::vector<std::string> profile_methods = {
1151     "HLTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1152     "HLTestInline;->invalid_method",
1153     "invalid_class"
1154   };
1155   std::string input_file_contents;
1156   for (std::string& m : profile_methods) {
1157     input_file_contents += m + std::string("\n");
1158   }
1159 
1160   // Create the profile and save it to disk.
1161   ScratchFile profile_file;
1162   std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1163   ASSERT_TRUE(CreateProfile(input_file_contents,
1164                             profile_file.GetFilename(),
1165                             dex_filename));
1166 
1167   // Load the profile from disk.
1168   ProfileCompilationInfo info;
1169   profile_file.GetFile()->ResetOffset();
1170   ASSERT_TRUE(info.Load(GetFd(profile_file)));
1171 
1172   // Load the dex files and verify that the profile contains the expected methods info.
1173   ScopedObjectAccess soa(Thread::Current());
1174   jobject class_loader = LoadDex("ProfileTestMultiDex");
1175   ASSERT_NE(class_loader, nullptr);
1176 
1177   ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1178                                                    "LTestInline;",
1179                                                    "inlineMonomorphic");
1180   const DexFile* dex_file = inline_monomorphic->GetDexFile();
1181 
1182   // Verify that the inline cache contains the invalid type.
1183   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1184       info.GetHotMethodInfo(MethodReference(dex_file, inline_monomorphic->GetDexMethodIndex()));
1185   ASSERT_TRUE(pmi != nullptr);
1186   ASSERT_EQ(pmi->inline_caches->size(), 1u);
1187   const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1188   dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1189   ASSERT_EQ(1u, dex_pc_data.classes.size());
1190   ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1191 
1192   // Verify that the start-up classes contain the invalid class.
1193   std::set<dex::TypeIndex> classes;
1194   std::set<uint16_t> hot_methods;
1195   std::set<uint16_t> startup_methods;
1196   std::set<uint16_t> post_start_methods;
1197   ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1198                                         &classes,
1199                                         &hot_methods,
1200                                         &startup_methods,
1201                                         &post_start_methods));
1202   ASSERT_EQ(1u, classes.size());
1203   ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1204 
1205   // Verify that the invalid method did not get in the profile.
1206   ASSERT_EQ(1u, hot_methods.size());
1207   uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
1208   ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
1209 }
1210 
TEST_F(ProfileAssistantTest,DumpOnly)1211 TEST_F(ProfileAssistantTest, DumpOnly) {
1212   ScratchFile profile;
1213 
1214   const uint32_t kNumberOfMethods = 64;
1215   std::vector<uint32_t> hot_methods;
1216   std::vector<uint32_t> startup_methods;
1217   std::vector<uint32_t> post_startup_methods;
1218   for (size_t i = 0; i < kNumberOfMethods; ++i) {
1219     if (i % 2 == 0) {
1220       hot_methods.push_back(i);
1221     }
1222     if (i % 3 == 1) {
1223       startup_methods.push_back(i);
1224     }
1225     if (i % 4 == 2) {
1226       post_startup_methods.push_back(i);
1227     }
1228   }
1229   EXPECT_GT(hot_methods.size(), 0u);
1230   EXPECT_GT(startup_methods.size(), 0u);
1231   EXPECT_GT(post_startup_methods.size(), 0u);
1232   ProfileCompilationInfo info1;
1233   SetupBasicProfile(dex1,
1234                     hot_methods,
1235                     startup_methods,
1236                     post_startup_methods,
1237                     profile,
1238                     &info1);
1239   std::string output;
1240   DumpOnly(profile.GetFilename(), &output);
1241   const size_t hot_offset = output.find("hot methods:");
1242   const size_t startup_offset = output.find("startup methods:");
1243   const size_t post_startup_offset = output.find("post startup methods:");
1244   const size_t classes_offset = output.find("classes:");
1245   ASSERT_NE(hot_offset, std::string::npos);
1246   ASSERT_NE(startup_offset, std::string::npos);
1247   ASSERT_NE(post_startup_offset, std::string::npos);
1248   ASSERT_LT(hot_offset, startup_offset);
1249   ASSERT_LT(startup_offset, post_startup_offset);
1250   // Check the actual contents of the dump by looking at the offsets of the methods.
1251   for (uint32_t m : hot_methods) {
1252     const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1253     ASSERT_NE(pos, std::string::npos) << output;
1254     EXPECT_LT(pos, startup_offset) << output;
1255   }
1256   for (uint32_t m : startup_methods) {
1257     const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1258     ASSERT_NE(pos, std::string::npos) << output;
1259     EXPECT_LT(pos, post_startup_offset) << output;
1260   }
1261   for (uint32_t m : post_startup_methods) {
1262     const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1263     ASSERT_NE(pos, std::string::npos) << output;
1264     EXPECT_LT(pos, classes_offset) << output;
1265   }
1266 }
1267 
TEST_F(ProfileAssistantTest,MergeProfilesWithFilter)1268 TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1269   ScratchFile profile1;
1270   ScratchFile profile2;
1271   ScratchFile reference_profile;
1272 
1273   std::vector<int> profile_fds({
1274       GetFd(profile1),
1275       GetFd(profile2)});
1276   int reference_profile_fd = GetFd(reference_profile);
1277 
1278   // Use a real dex file to generate profile test data.
1279   // The file will be used during merging to filter unwanted data.
1280   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1281   const DexFile& d1 = *dex_files[0];
1282   const DexFile& d2 = *dex_files[1];
1283   // The new profile info will contain the methods with indices 0-100.
1284   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1285   ProfileCompilationInfo info1;
1286   SetupProfile(&d1, dex1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1287   ProfileCompilationInfo info2;
1288   SetupProfile(&d2, dex2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1289 
1290 
1291   // The reference profile info will contain the methods with indices 50-150.
1292   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1293   ProfileCompilationInfo reference_info;
1294   SetupProfile(&d1, dex1,
1295       kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1296       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1297 
1298   // Run profman and pass the dex file with --apk-fd.
1299   android::base::unique_fd apk_fd(
1300       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));  // NOLINT
1301   ASSERT_GE(apk_fd.get(), 0);
1302 
1303   std::string profman_cmd = GetProfmanCmd();
1304   std::vector<std::string> argv_str;
1305   argv_str.push_back(profman_cmd);
1306   argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1307   argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1308   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1309   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1310   std::string error;
1311 
1312   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfileAssistant::kCompile) << error;
1313 
1314   // Verify that we can load the result.
1315 
1316   ProfileCompilationInfo result;
1317   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1318   ASSERT_TRUE(result.Load(reference_profile_fd));
1319 
1320 
1321   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1322   ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1323   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1324 
1325   // Verify that the result filtered out data not belonging to the dex file.
1326   // This is equivalent to checking that the result is equal to the merging of
1327   // all profiles while filtering out data not belonging to the dex file.
1328 
1329   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1330       [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1331           return (dex_location == ProfileCompilationInfo::GetProfileDexFileBaseKey(d1.GetLocation())
1332               && checksum == d1.GetLocationChecksum())
1333               || (dex_location == ProfileCompilationInfo::GetProfileDexFileBaseKey(d2.GetLocation())
1334               && checksum == d2.GetLocationChecksum());
1335         };
1336 
1337   ProfileCompilationInfo info1_filter;
1338   ProfileCompilationInfo info2_filter;
1339   ProfileCompilationInfo expected;
1340 
1341   info2_filter.Load(profile1.GetFd(), /*merge_classes=*/ true, filter_fn);
1342   info2_filter.Load(profile2.GetFd(), /*merge_classes=*/ true, filter_fn);
1343   expected.Load(reference_profile.GetFd(), /*merge_classes=*/ true, filter_fn);
1344 
1345   ASSERT_TRUE(expected.MergeWith(info1_filter));
1346   ASSERT_TRUE(expected.MergeWith(info2_filter));
1347 
1348   ASSERT_TRUE(expected.Equals(result));
1349 }
1350 
TEST_F(ProfileAssistantTest,CopyAndUpdateProfileKey)1351 TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1352   ScratchFile profile1;
1353   ScratchFile reference_profile;
1354 
1355   // Use a real dex file to generate profile test data. During the copy-and-update the
1356   // matching is done based on checksum so we have to match with the real thing.
1357   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1358   const DexFile& d1 = *dex_files[0];
1359   const DexFile& d2 = *dex_files[1];
1360 
1361   ProfileCompilationInfo info1;
1362   uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1363 
1364   FakeDexStorage local_storage;
1365   const DexFile* dex_to_be_updated1 = local_storage.AddFakeDex(
1366       "fake-location1", d1.GetLocationChecksum(), d1.NumMethodIds());
1367   const DexFile* dex_to_be_updated2 = local_storage.AddFakeDex(
1368       "fake-location2", d2.GetLocationChecksum(), d2.NumMethodIds());
1369   SetupProfile(dex_to_be_updated1,
1370                dex_to_be_updated2,
1371                num_methods_to_add,
1372                /*number_of_classes=*/ 0,
1373                profile1,
1374                &info1);
1375 
1376   // Run profman and pass the dex file with --apk-fd.
1377   android::base::unique_fd apk_fd(
1378       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));  // NOLINT
1379   ASSERT_GE(apk_fd.get(), 0);
1380 
1381   std::string profman_cmd = GetProfmanCmd();
1382   std::vector<std::string> argv_str;
1383   argv_str.push_back(profman_cmd);
1384   argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1385   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1386   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1387   argv_str.push_back("--copy-and-update-profile-key");
1388   std::string error;
1389 
1390   ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1391 
1392   // Verify that we can load the result.
1393   ProfileCompilationInfo result;
1394   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1395   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1396 
1397   // Verify that the renaming was done.
1398   for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1399     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1400     ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(&d1, i)) != nullptr) << i;
1401     ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(&d2, i)) != nullptr) << i;
1402 
1403     ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(dex_to_be_updated1, i)) == nullptr);
1404     ASSERT_TRUE(result.GetHotMethodInfo(MethodReference(dex_to_be_updated2, i)) == nullptr);
1405   }
1406 }
1407 
TEST_F(ProfileAssistantTest,BootImageMerge)1408 TEST_F(ProfileAssistantTest, BootImageMerge) {
1409   ScratchFile profile;
1410   ScratchFile reference_profile;
1411   std::vector<int> profile_fds({GetFd(profile)});
1412   int reference_profile_fd = GetFd(reference_profile);
1413   std::vector<uint32_t> hot_methods_cur;
1414   std::vector<uint32_t> hot_methods_ref;
1415   std::vector<uint32_t> empty_vector;
1416   size_t num_methods = 100;
1417   for (size_t i = 0; i < num_methods; ++i) {
1418     hot_methods_cur.push_back(i);
1419   }
1420   for (size_t i = 0; i < num_methods; ++i) {
1421     hot_methods_ref.push_back(i);
1422   }
1423   ProfileCompilationInfo info1;
1424   SetupBasicProfile(dex1, hot_methods_cur, empty_vector, empty_vector,
1425       profile, &info1);
1426   ProfileCompilationInfo info2(/*for_boot_image=*/true);
1427   SetupBasicProfile(dex1, hot_methods_ref, empty_vector, empty_vector,
1428       reference_profile, &info2);
1429 
1430   std::vector<const std::string> extra_args({"--force-merge", "--boot-image-merge"});
1431 
1432   int return_code = ProcessProfiles(profile_fds, reference_profile_fd, extra_args);
1433 
1434   ASSERT_EQ(return_code, ProfileAssistant::kSuccess);
1435 
1436   // Verify the result: it should be equal to info2 since info1 is a regular profile
1437   // and should be ignored.
1438   ProfileCompilationInfo result;
1439   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1440   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1441   ASSERT_TRUE(result.Equals(info2));
1442 }
1443 
1444 // Under default behaviour we should not advice compilation
1445 // and the reference profile should not be updated.
1446 // However we pass --force-merge to force aggregation and in this case
1447 // we should see an update.
TEST_F(ProfileAssistantTest,ForceMerge)1448 TEST_F(ProfileAssistantTest, ForceMerge) {
1449   const uint16_t kNumberOfClassesInRefProfile = 6000;
1450   const uint16_t kNumberOfClassesInCurProfile = 6110;  // Threshold is 2%.
1451 
1452   ScratchFile profile;
1453   ScratchFile reference_profile;
1454 
1455   std::vector<int> profile_fds({ GetFd(profile)});
1456   int reference_profile_fd = GetFd(reference_profile);
1457 
1458   ProfileCompilationInfo info1;
1459   SetupProfile(dex1, dex2, 0, kNumberOfClassesInRefProfile, profile,  &info1);
1460   ProfileCompilationInfo info2;
1461   SetupProfile(dex1, dex2, 0, kNumberOfClassesInCurProfile, reference_profile, &info2);
1462 
1463   std::vector<const std::string> extra_args({"--force-merge"});
1464   int return_code = ProcessProfiles(profile_fds, reference_profile_fd, extra_args);
1465 
1466   ASSERT_EQ(return_code, ProfileAssistant::kSuccess);
1467 
1468   // Check that the result is the aggregation.
1469   ProfileCompilationInfo result;
1470   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1471   ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1472   ASSERT_TRUE(info1.MergeWith(info2));
1473   ASSERT_TRUE(result.Equals(info1));
1474 }
1475 
1476 // Test that we consider the annations when we merge boot image profiles.
TEST_F(ProfileAssistantTest,BootImageMergeWithAnnotations)1477 TEST_F(ProfileAssistantTest, BootImageMergeWithAnnotations) {
1478   ScratchFile profile;
1479   ScratchFile reference_profile;
1480 
1481   std::vector<int> profile_fds({GetFd(profile)});
1482   int reference_profile_fd = GetFd(reference_profile);
1483 
1484   // Use a real dex file to generate profile test data so that we can pass descriptors to profman.
1485   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1486   const DexFile& d1 = *dex_files[0];
1487   const DexFile& d2 = *dex_files[1];
1488   // The new profile info will contain the methods with indices 0-100.
1489   ProfileCompilationInfo info(/*for_boot_image*/ true);
1490   ProfileCompilationInfo::ProfileSampleAnnotation psa1("package1");
1491   ProfileCompilationInfo::ProfileSampleAnnotation psa2("package2");
1492 
1493   AddMethod(&info, &d1, 0, Hotness::kFlagHot, psa1);
1494   AddMethod(&info, &d2, 0, Hotness::kFlagHot, psa2);
1495   info.Save(profile.GetFd());
1496   profile.GetFile()->ResetOffset();
1497 
1498   // Run profman and pass the dex file with --apk-fd.
1499   android::base::unique_fd apk_fd(
1500       open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));  // NOLINT
1501   ASSERT_GE(apk_fd.get(), 0);
1502 
1503   std::string profman_cmd = GetProfmanCmd();
1504   std::vector<std::string> argv_str;
1505   argv_str.push_back(profman_cmd);
1506   argv_str.push_back("--profile-file-fd=" + std::to_string(profile.GetFd()));
1507   argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1508   argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1509   argv_str.push_back("--force-merge");
1510   argv_str.push_back("--boot-image-merge");
1511   std::string error;
1512 
1513   EXPECT_EQ(ExecAndReturnCode(argv_str, &error), ProfileAssistant::kSuccess) << error;
1514 
1515   // Verify that we can load the result and that it equals to what we saved.
1516   ProfileCompilationInfo result;
1517   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1518   ASSERT_TRUE(result.Load(reference_profile_fd));
1519   ASSERT_TRUE(info.Equals(result));
1520 }
1521 
TEST_F(ProfileAssistantTest,DifferentProfileVersions)1522 TEST_F(ProfileAssistantTest, DifferentProfileVersions) {
1523   ScratchFile profile1;
1524   ScratchFile profile2;
1525 
1526   ProfileCompilationInfo info1(/*for_boot_image*/ false);
1527   info1.Save(profile1.GetFd());
1528   profile1.GetFile()->ResetOffset();
1529 
1530   ProfileCompilationInfo info2(/*for_boot_image*/ true);
1531   info2.Save(profile2.GetFd());
1532   profile2.GetFile()->ResetOffset();
1533 
1534   std::vector<int> profile_fds({ GetFd(profile1)});
1535   int reference_profile_fd = GetFd(profile2);
1536   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd),
1537             ProfileAssistant::kErrorDifferentVersions);
1538 
1539   // Reverse the order of the profiles to verify we get the same behaviour.
1540   profile_fds[0] = GetFd(profile2);
1541   reference_profile_fd = GetFd(profile1);
1542   profile1.GetFile()->ResetOffset();
1543   profile2.GetFile()->ResetOffset();
1544   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd),
1545             ProfileAssistant::kErrorDifferentVersions);
1546 }
1547 
1548 // Under default behaviour we will abort if we cannot load a profile during a merge
1549 // operation. However, if we pass --force-merge to force aggregation we should
1550 // ignore files we cannot load
TEST_F(ProfileAssistantTest,ForceMergeIgnoreProfilesItCannotLoad)1551 TEST_F(ProfileAssistantTest, ForceMergeIgnoreProfilesItCannotLoad) {
1552   ScratchFile profile1;
1553   ScratchFile profile2;
1554 
1555   // Write corrupt data in the first file.
1556   std::string content = "giberish";
1557   ASSERT_TRUE(profile1.GetFile()->WriteFully(content.c_str(), content.length()));
1558   profile1.GetFile()->ResetOffset();
1559 
1560   ProfileCompilationInfo info2(/*for_boot_image*/ true);
1561   info2.Save(profile2.GetFd());
1562   profile2.GetFile()->ResetOffset();
1563 
1564   std::vector<int> profile_fds({ GetFd(profile1)});
1565   int reference_profile_fd = GetFd(profile2);
1566 
1567   // With force-merge we should merge successfully.
1568   std::vector<const std::string> extra_args({"--force-merge"});
1569   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args),
1570             ProfileAssistant::kSuccess);
1571 
1572   ProfileCompilationInfo result;
1573   ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1574   ASSERT_TRUE(result.Load(reference_profile_fd));
1575   ASSERT_TRUE(info2.Equals(result));
1576 
1577   // Without force-merge we should fail.
1578   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args),
1579             ProfileAssistant::kErrorBadProfiles);
1580 }
1581 }  // namespace art
1582