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 "art_method-inl.h"
20 #include "base/unix_file/fd_file.h"
21 #include "common_runtime_test.h"
22 #include "exec_utils.h"
23 #include "jit/profile_compilation_info.h"
24 #include "linear_alloc.h"
25 #include "mirror/class-inl.h"
26 #include "obj_ptr-inl.h"
27 #include "profile_assistant.h"
28 #include "scoped_thread_state_change-inl.h"
29 #include "utils.h"
30 
31 namespace art {
32 
33 class ProfileAssistantTest : public CommonRuntimeTest {
34  public:
PostRuntimeCreate()35   void PostRuntimeCreate() OVERRIDE {
36     arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
37   }
38 
39  protected:
SetupProfile(const std::string & id,uint32_t checksum,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)40   void SetupProfile(const std::string& id,
41                     uint32_t checksum,
42                     uint16_t number_of_methods,
43                     uint16_t number_of_classes,
44                     const ScratchFile& profile,
45                     ProfileCompilationInfo* info,
46                     uint16_t start_method_index = 0,
47                     bool reverse_dex_write_order = false) {
48     std::string dex_location1 = "location1" + id;
49     uint32_t dex_location_checksum1 = checksum;
50     std::string dex_location2 = "location2" + id;
51     uint32_t dex_location_checksum2 = 10 * checksum;
52     for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
53       // reverse_dex_write_order controls the order in which the dex files will be added to
54       // the profile and thus written to disk.
55       ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
56           GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
57                                       dex_location2, dex_location_checksum2);
58       if (reverse_dex_write_order) {
59         ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, pmi));
60         ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, pmi));
61       } else {
62         ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, pmi));
63         ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, pmi));
64       }
65     }
66     for (uint16_t i = 0; i < number_of_classes; i++) {
67       ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
68     }
69 
70     ASSERT_TRUE(info->Save(GetFd(profile)));
71     ASSERT_EQ(0, profile.GetFile()->Flush());
72     ASSERT_TRUE(profile.GetFile()->ResetOffset());
73   }
74 
75   // Creates an inline cache which will be destructed at the end of the test.
CreateInlineCacheMap()76   ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
77     used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
78         std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
79     return used_inline_caches.back().get();
80   }
81 
GetOfflineProfileMethodInfo(const std::string & dex_location1,uint32_t dex_checksum1,const std::string & dex_location2,uint32_t dex_checksum2)82   ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
83         const std::string& dex_location1, uint32_t dex_checksum1,
84         const std::string& dex_location2, uint32_t dex_checksum2) {
85     ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
86     ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
87     pmi.dex_references.emplace_back(dex_location1, dex_checksum1);
88     pmi.dex_references.emplace_back(dex_location2, dex_checksum2);
89 
90     // Monomorphic
91     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
92       ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
93       dex_pc_data.AddClass(0, dex::TypeIndex(0));
94       ic_map->Put(dex_pc, dex_pc_data);
95     }
96     // Polymorphic
97     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
98       ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
99       dex_pc_data.AddClass(0, dex::TypeIndex(0));
100       dex_pc_data.AddClass(1, dex::TypeIndex(1));
101 
102       ic_map->Put(dex_pc, dex_pc_data);
103     }
104     // Megamorphic
105     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
106       ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
107       dex_pc_data.SetIsMegamorphic();
108       ic_map->Put(dex_pc, dex_pc_data);
109     }
110     // Missing types
111     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
112       ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
113       dex_pc_data.SetIsMissingTypes();
114       ic_map->Put(dex_pc, dex_pc_data);
115     }
116 
117     return pmi;
118   }
119 
GetFd(const ScratchFile & file) const120   int GetFd(const ScratchFile& file) const {
121     return static_cast<int>(file.GetFd());
122   }
123 
CheckProfileInfo(ScratchFile & file,const ProfileCompilationInfo & info)124   void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
125     ProfileCompilationInfo file_info;
126     ASSERT_TRUE(file.GetFile()->ResetOffset());
127     ASSERT_TRUE(file_info.Load(GetFd(file)));
128     ASSERT_TRUE(file_info.Equals(info));
129   }
130 
GetProfmanCmd()131   std::string GetProfmanCmd() {
132     std::string file_path = GetTestAndroidRoot();
133     file_path += "/bin/profman";
134     if (kIsDebugBuild) {
135       file_path += "d";
136     }
137     EXPECT_TRUE(OS::FileExists(file_path.c_str()))
138         << file_path << " should be a valid file path";
139     return file_path;
140   }
141   // Runs test with given arguments.
ProcessProfiles(const std::vector<int> & profiles_fd,int reference_profile_fd)142   int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
143     std::string profman_cmd = GetProfmanCmd();
144     std::vector<std::string> argv_str;
145     argv_str.push_back(profman_cmd);
146     for (size_t k = 0; k < profiles_fd.size(); k++) {
147       argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
148     }
149     argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
150 
151     std::string error;
152     return ExecAndReturnCode(argv_str, &error);
153   }
154 
GenerateTestProfile(const std::string & filename)155   bool GenerateTestProfile(const std::string& filename) {
156     std::string profman_cmd = GetProfmanCmd();
157     std::vector<std::string> argv_str;
158     argv_str.push_back(profman_cmd);
159     argv_str.push_back("--generate-test-profile=" + filename);
160     std::string error;
161     return ExecAndReturnCode(argv_str, &error);
162   }
163 
GenerateTestProfileWithInputDex(const std::string & filename)164   bool GenerateTestProfileWithInputDex(const std::string& filename) {
165     std::string profman_cmd = GetProfmanCmd();
166     std::vector<std::string> argv_str;
167     argv_str.push_back(profman_cmd);
168     argv_str.push_back("--generate-test-profile=" + filename);
169     argv_str.push_back("--generate-test-profile-seed=0");
170     argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
171     argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
172     std::string error;
173     return ExecAndReturnCode(argv_str, &error);
174   }
175 
CreateProfile(std::string profile_file_contents,const std::string & filename,const std::string & dex_location)176   bool CreateProfile(std::string profile_file_contents,
177                      const std::string& filename,
178                      const std::string& dex_location) {
179     ScratchFile class_names_file;
180     File* file = class_names_file.GetFile();
181     EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
182     EXPECT_EQ(0, file->Flush());
183     EXPECT_TRUE(file->ResetOffset());
184     std::string profman_cmd = GetProfmanCmd();
185     std::vector<std::string> argv_str;
186     argv_str.push_back(profman_cmd);
187     argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
188     argv_str.push_back("--reference-profile-file=" + filename);
189     argv_str.push_back("--apk=" + dex_location);
190     argv_str.push_back("--dex-location=" + dex_location);
191     std::string error;
192     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
193     return true;
194   }
195 
DumpClassesAndMethods(const std::string & filename,std::string * file_contents)196   bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
197     ScratchFile class_names_file;
198     std::string profman_cmd = GetProfmanCmd();
199     std::vector<std::string> argv_str;
200     argv_str.push_back(profman_cmd);
201     argv_str.push_back("--dump-classes-and-methods");
202     argv_str.push_back("--profile-file=" + filename);
203     argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
204     argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
205     argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(class_names_file)));
206     std::string error;
207     EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
208     File* file = class_names_file.GetFile();
209     EXPECT_EQ(0, file->Flush());
210     EXPECT_TRUE(file->ResetOffset());
211     int64_t length = file->GetLength();
212     std::unique_ptr<char[]> buf(new char[length]);
213     EXPECT_EQ(file->Read(buf.get(), length, 0), length);
214     *file_contents = std::string(buf.get(), length);
215     return true;
216   }
217 
CreateAndDump(const std::string & input_file_contents,std::string * output_file_contents)218   bool CreateAndDump(const std::string& input_file_contents,
219                      std::string* output_file_contents) {
220     ScratchFile profile_file;
221     EXPECT_TRUE(CreateProfile(input_file_contents,
222                               profile_file.GetFilename(),
223                               GetLibCoreDexFileNames()[0]));
224     profile_file.GetFile()->ResetOffset();
225     EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
226     return true;
227   }
228 
GetClass(jobject class_loader,const std::string & clazz)229   mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
230     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
231     Thread* self = Thread::Current();
232     ScopedObjectAccess soa(self);
233     StackHandleScope<1> hs(self);
234     Handle<mirror::ClassLoader> h_loader(
235         hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
236     return class_linker->FindClass(self, clazz.c_str(), h_loader);
237   }
238 
GetVirtualMethod(jobject class_loader,const std::string & clazz,const std::string & name)239   ArtMethod* GetVirtualMethod(jobject class_loader,
240                               const std::string& clazz,
241                               const std::string& name) {
242     mirror::Class* klass = GetClass(class_loader, clazz);
243     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
244     const auto pointer_size = class_linker->GetImagePointerSize();
245     ArtMethod* method = nullptr;
246     Thread* self = Thread::Current();
247     ScopedObjectAccess soa(self);
248     for (auto& m : klass->GetVirtualMethods(pointer_size)) {
249       if (name == m.GetName()) {
250         EXPECT_TRUE(method == nullptr);
251         method = &m;
252       }
253     }
254     return method;
255   }
256 
257   // Verify that given method has the expected inline caches and nothing else.
AssertInlineCaches(ArtMethod * method,const std::set<mirror::Class * > & expected_clases,const ProfileCompilationInfo & info,bool is_megamorphic,bool is_missing_types)258   void AssertInlineCaches(ArtMethod* method,
259                           const std::set<mirror::Class*>& expected_clases,
260                           const ProfileCompilationInfo& info,
261                           bool is_megamorphic,
262                           bool is_missing_types)
263       REQUIRES_SHARED(Locks::mutator_lock_) {
264     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
265         info.GetMethod(method->GetDexFile()->GetLocation(),
266                        method->GetDexFile()->GetLocationChecksum(),
267                        method->GetDexMethodIndex());
268     ASSERT_TRUE(pmi != nullptr);
269     ASSERT_EQ(pmi->inline_caches->size(), 1u);
270     const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
271 
272     ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
273     ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
274     ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
275     size_t found = 0;
276     for (mirror::Class* it : expected_clases) {
277       for (const auto& class_ref : dex_pc_data.classes) {
278         ProfileCompilationInfo::DexReference dex_ref =
279             pmi->dex_references[class_ref.dex_profile_index];
280         if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
281             class_ref.type_index == it->GetDexTypeIndex()) {
282           found++;
283         }
284       }
285     }
286 
287     ASSERT_EQ(expected_clases.size(), found);
288   }
289 
290   std::unique_ptr<ArenaAllocator> arena_;
291 
292   // Cache of inline caches generated during tests.
293   // This makes it easier to pass data between different utilities and ensure that
294   // caches are destructed at the end of the test.
295   std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
296 };
297 
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferences)298 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
299   ScratchFile profile1;
300   ScratchFile profile2;
301   ScratchFile reference_profile;
302 
303   std::vector<int> profile_fds({
304       GetFd(profile1),
305       GetFd(profile2)});
306   int reference_profile_fd = GetFd(reference_profile);
307 
308   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
309   ProfileCompilationInfo info1;
310   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
311   ProfileCompilationInfo info2;
312   SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
313 
314   // We should advise compilation.
315   ASSERT_EQ(ProfileAssistant::kCompile,
316             ProcessProfiles(profile_fds, reference_profile_fd));
317   // The resulting compilation info must be equal to the merge of the inputs.
318   ProfileCompilationInfo result;
319   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
320   ASSERT_TRUE(result.Load(reference_profile_fd));
321 
322   ProfileCompilationInfo expected;
323   ASSERT_TRUE(expected.MergeWith(info1));
324   ASSERT_TRUE(expected.MergeWith(info2));
325   ASSERT_TRUE(expected.Equals(result));
326 
327   // The information from profiles must remain the same.
328   CheckProfileInfo(profile1, info1);
329   CheckProfileInfo(profile2, info2);
330 }
331 
332 // TODO(calin): Add more tests for classes.
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferencesBecauseOfClasses)333 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
334   ScratchFile profile1;
335   ScratchFile reference_profile;
336 
337   std::vector<int> profile_fds({
338       GetFd(profile1)});
339   int reference_profile_fd = GetFd(reference_profile);
340 
341   const uint16_t kNumberOfClassesToEnableCompilation = 100;
342   ProfileCompilationInfo info1;
343   SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
344 
345   // We should advise compilation.
346   ASSERT_EQ(ProfileAssistant::kCompile,
347             ProcessProfiles(profile_fds, reference_profile_fd));
348   // The resulting compilation info must be equal to the merge of the inputs.
349   ProfileCompilationInfo result;
350   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
351   ASSERT_TRUE(result.Load(reference_profile_fd));
352 
353   ProfileCompilationInfo expected;
354   ASSERT_TRUE(expected.MergeWith(info1));
355   ASSERT_TRUE(expected.Equals(result));
356 
357   // The information from profiles must remain the same.
358   CheckProfileInfo(profile1, info1);
359 }
360 
TEST_F(ProfileAssistantTest,AdviseCompilationNonEmptyReferences)361 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
362   ScratchFile profile1;
363   ScratchFile profile2;
364   ScratchFile reference_profile;
365 
366   std::vector<int> profile_fds({
367       GetFd(profile1),
368       GetFd(profile2)});
369   int reference_profile_fd = GetFd(reference_profile);
370 
371   // The new profile info will contain the methods with indices 0-100.
372   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
373   ProfileCompilationInfo info1;
374   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
375   ProfileCompilationInfo info2;
376   SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
377 
378 
379   // The reference profile info will contain the methods with indices 50-150.
380   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
381   ProfileCompilationInfo reference_info;
382   SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
383       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
384 
385   // We should advise compilation.
386   ASSERT_EQ(ProfileAssistant::kCompile,
387             ProcessProfiles(profile_fds, reference_profile_fd));
388 
389   // The resulting compilation info must be equal to the merge of the inputs
390   ProfileCompilationInfo result;
391   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
392   ASSERT_TRUE(result.Load(reference_profile_fd));
393 
394   ProfileCompilationInfo expected;
395   ASSERT_TRUE(expected.MergeWith(info1));
396   ASSERT_TRUE(expected.MergeWith(info2));
397   ASSERT_TRUE(expected.MergeWith(reference_info));
398   ASSERT_TRUE(expected.Equals(result));
399 
400   // The information from profiles must remain the same.
401   CheckProfileInfo(profile1, info1);
402   CheckProfileInfo(profile2, info2);
403 }
404 
TEST_F(ProfileAssistantTest,DoNotAdviseCompilation)405 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
406   ScratchFile profile1;
407   ScratchFile profile2;
408   ScratchFile reference_profile;
409 
410   std::vector<int> profile_fds({
411       GetFd(profile1),
412       GetFd(profile2)});
413   int reference_profile_fd = GetFd(reference_profile);
414 
415   const uint16_t kNumberOfMethodsToSkipCompilation = 1;
416   ProfileCompilationInfo info1;
417   SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
418   ProfileCompilationInfo info2;
419   SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
420 
421   // We should not advise compilation.
422   ASSERT_EQ(ProfileAssistant::kSkipCompilation,
423             ProcessProfiles(profile_fds, reference_profile_fd));
424 
425   // The information from profiles must remain the same.
426   ProfileCompilationInfo file_info1;
427   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
428   ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
429   ASSERT_TRUE(file_info1.Equals(info1));
430 
431   ProfileCompilationInfo file_info2;
432   ASSERT_TRUE(profile2.GetFile()->ResetOffset());
433   ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
434   ASSERT_TRUE(file_info2.Equals(info2));
435 
436   // Reference profile files must remain empty.
437   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
438 
439   // The information from profiles must remain the same.
440   CheckProfileInfo(profile1, info1);
441   CheckProfileInfo(profile2, info2);
442 }
443 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfProfiles)444 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
445   ScratchFile profile1;
446   ScratchFile profile2;
447   ScratchFile reference_profile;
448 
449   std::vector<int> profile_fds({
450       GetFd(profile1),
451       GetFd(profile2)});
452   int reference_profile_fd = GetFd(reference_profile);
453 
454   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
455   // Assign different hashes for the same dex file. This will make merging of information to fail.
456   ProfileCompilationInfo info1;
457   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
458   ProfileCompilationInfo info2;
459   SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
460 
461   // We should fail processing.
462   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
463             ProcessProfiles(profile_fds, reference_profile_fd));
464 
465   // The information from profiles must remain the same.
466   CheckProfileInfo(profile1, info1);
467   CheckProfileInfo(profile2, info2);
468 
469   // Reference profile files must still remain empty.
470   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
471 }
472 
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfReferenceProfiles)473 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
474   ScratchFile profile1;
475   ScratchFile reference_profile;
476 
477   std::vector<int> profile_fds({
478       GetFd(profile1)});
479   int reference_profile_fd = GetFd(reference_profile);
480 
481   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
482   // Assign different hashes for the same dex file. This will make merging of information to fail.
483   ProfileCompilationInfo info1;
484   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
485   ProfileCompilationInfo reference_info;
486   SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
487 
488   // We should not advise compilation.
489   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
490   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
491   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
492             ProcessProfiles(profile_fds, reference_profile_fd));
493 
494   // The information from profiles must remain the same.
495   CheckProfileInfo(profile1, info1);
496 }
497 
TEST_F(ProfileAssistantTest,TestProfileGeneration)498 TEST_F(ProfileAssistantTest, TestProfileGeneration) {
499   ScratchFile profile;
500   // Generate a test profile.
501   GenerateTestProfile(profile.GetFilename());
502 
503   // Verify that the generated profile is valid and can be loaded.
504   ASSERT_TRUE(profile.GetFile()->ResetOffset());
505   ProfileCompilationInfo info;
506   ASSERT_TRUE(info.Load(GetFd(profile)));
507 }
508 
TEST_F(ProfileAssistantTest,TestProfileGenerationWithIndexDex)509 TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
510   ScratchFile profile;
511   // Generate a test profile passing in a dex file as reference.
512   GenerateTestProfileWithInputDex(profile.GetFilename());
513 
514   // Verify that the generated profile is valid and can be loaded.
515   ASSERT_TRUE(profile.GetFile()->ResetOffset());
516   ProfileCompilationInfo info;
517   ASSERT_TRUE(info.Load(GetFd(profile)));
518 }
519 
TEST_F(ProfileAssistantTest,TestProfileCreationAllMatch)520 TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
521   // Class names put here need to be in sorted order.
522   std::vector<std::string> class_names = {
523     "Ljava/lang/Comparable;",
524     "Ljava/lang/Math;",
525     "Ljava/lang/Object;",
526     "Ljava/lang/Object;-><init>()V"
527   };
528   std::string file_contents;
529   for (std::string& class_name : class_names) {
530     file_contents += class_name + std::string("\n");
531   }
532   std::string output_file_contents;
533   ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
534   ASSERT_EQ(output_file_contents, file_contents);
535 }
536 
TEST_F(ProfileAssistantTest,TestProfileCreationGenerateMethods)537 TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
538   // Class names put here need to be in sorted order.
539   std::vector<std::string> class_names = {
540     "Ljava/lang/Math;->*",
541   };
542   std::string input_file_contents;
543   std::string expected_contents;
544   for (std::string& class_name : class_names) {
545     input_file_contents += class_name + std::string("\n");
546     expected_contents += DescriptorToDot(class_name.c_str()) +
547         std::string("\n");
548   }
549   std::string output_file_contents;
550   ScratchFile profile_file;
551   EXPECT_TRUE(CreateProfile(input_file_contents,
552                             profile_file.GetFilename(),
553                             GetLibCoreDexFileNames()[0]));
554   ProfileCompilationInfo info;
555   profile_file.GetFile()->ResetOffset();
556   ASSERT_TRUE(info.Load(GetFd(profile_file)));
557   // Verify that the profile has matching methods.
558   ScopedObjectAccess soa(Thread::Current());
559   ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
560   ASSERT_TRUE(klass != nullptr);
561   size_t method_count = 0;
562   for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
563     if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
564       ++method_count;
565       std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
566           info.GetMethod(method.GetDexFile()->GetLocation(),
567                          method.GetDexFile()->GetLocationChecksum(),
568                          method.GetDexMethodIndex());
569       ASSERT_TRUE(pmi != nullptr);
570     }
571   }
572   EXPECT_GT(method_count, 0u);
573 }
574 
TEST_F(ProfileAssistantTest,TestProfileCreationOneNotMatched)575 TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
576   // Class names put here need to be in sorted order.
577   std::vector<std::string> class_names = {
578     "Ldoesnt/match/this/one;",
579     "Ljava/lang/Comparable;",
580     "Ljava/lang/Object;"
581   };
582   std::string input_file_contents;
583   for (std::string& class_name : class_names) {
584     input_file_contents += class_name + std::string("\n");
585   }
586   std::string output_file_contents;
587   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
588   std::string expected_contents =
589       class_names[1] + std::string("\n") +
590       class_names[2] + std::string("\n");
591   ASSERT_EQ(output_file_contents, expected_contents);
592 }
593 
TEST_F(ProfileAssistantTest,TestProfileCreationNoneMatched)594 TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
595   // Class names put here need to be in sorted order.
596   std::vector<std::string> class_names = {
597     "Ldoesnt/match/this/one;",
598     "Ldoesnt/match/this/one/either;",
599     "Lnor/this/one;"
600   };
601   std::string input_file_contents;
602   for (std::string& class_name : class_names) {
603     input_file_contents += class_name + std::string("\n");
604   }
605   std::string output_file_contents;
606   ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
607   std::string expected_contents("");
608   ASSERT_EQ(output_file_contents, expected_contents);
609 }
610 
TEST_F(ProfileAssistantTest,TestProfileCreateInlineCache)611 TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
612   // Create the profile content.
613   std::vector<std::string> methods = {
614     "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
615     "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
616     "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
617     "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
618     "LTestInline;->noInlineCache(LSuper;)I"
619   };
620   std::string input_file_contents;
621   for (std::string& m : methods) {
622     input_file_contents += m + std::string("\n");
623   }
624 
625   // Create the profile and save it to disk.
626   ScratchFile profile_file;
627   ASSERT_TRUE(CreateProfile(input_file_contents,
628                             profile_file.GetFilename(),
629                             GetTestDexFileName("ProfileTestMultiDex")));
630 
631   // Load the profile from disk.
632   ProfileCompilationInfo info;
633   profile_file.GetFile()->ResetOffset();
634   ASSERT_TRUE(info.Load(GetFd(profile_file)));
635 
636   // Load the dex files and verify that the profile contains the expected methods info.
637   ScopedObjectAccess soa(Thread::Current());
638   jobject class_loader = LoadDex("ProfileTestMultiDex");
639   ASSERT_NE(class_loader, nullptr);
640 
641   mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
642   mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
643   mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
644 
645   ASSERT_TRUE(sub_a != nullptr);
646   ASSERT_TRUE(sub_b != nullptr);
647   ASSERT_TRUE(sub_c != nullptr);
648 
649   {
650     // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
651     ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
652                                                      "LTestInline;",
653                                                      "inlineMonomorphic");
654     ASSERT_TRUE(inline_monomorphic != nullptr);
655     std::set<mirror::Class*> expected_monomorphic;
656     expected_monomorphic.insert(sub_a);
657     AssertInlineCaches(inline_monomorphic,
658                        expected_monomorphic,
659                        info,
660                        /*megamorphic*/false,
661                        /*missing_types*/false);
662   }
663 
664   {
665     // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
666     ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
667                                                     "LTestInline;",
668                                                     "inlinePolymorphic");
669     ASSERT_TRUE(inline_polymorhic != nullptr);
670     std::set<mirror::Class*> expected_polymorphic;
671     expected_polymorphic.insert(sub_a);
672     expected_polymorphic.insert(sub_b);
673     expected_polymorphic.insert(sub_c);
674     AssertInlineCaches(inline_polymorhic,
675                        expected_polymorphic,
676                        info,
677                        /*megamorphic*/false,
678                        /*missing_types*/false);
679   }
680 
681   {
682     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
683     ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
684                                                      "LTestInline;",
685                                                      "inlineMegamorphic");
686     ASSERT_TRUE(inline_megamorphic != nullptr);
687     std::set<mirror::Class*> expected_megamorphic;
688     AssertInlineCaches(inline_megamorphic,
689                        expected_megamorphic,
690                        info,
691                        /*megamorphic*/true,
692                        /*missing_types*/false);
693   }
694 
695   {
696     // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
697     ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
698                                                        "LTestInline;",
699                                                        "inlineMissingTypes");
700     ASSERT_TRUE(inline_missing_types != nullptr);
701     std::set<mirror::Class*> expected_missing_Types;
702     AssertInlineCaches(inline_missing_types,
703                        expected_missing_Types,
704                        info,
705                        /*megamorphic*/false,
706                        /*missing_types*/true);
707   }
708 
709   {
710     // Verify that method noInlineCache has no inline caches in the profile.
711     ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
712     ASSERT_TRUE(no_inline_cache != nullptr);
713     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
714         info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
715                        no_inline_cache->GetDexFile()->GetLocationChecksum(),
716                        no_inline_cache->GetDexMethodIndex());
717     ASSERT_TRUE(pmi_no_inline_cache != nullptr);
718     ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
719   }
720 }
721 
TEST_F(ProfileAssistantTest,MergeProfilesWithDifferentDexOrder)722 TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
723   ScratchFile profile1;
724   ScratchFile reference_profile;
725 
726   std::vector<int> profile_fds({GetFd(profile1)});
727   int reference_profile_fd = GetFd(reference_profile);
728 
729   // The new profile info will contain the methods with indices 0-100.
730   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
731   ProfileCompilationInfo info1;
732   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
733       /*start_method_index*/0, /*reverse_dex_write_order*/false);
734 
735   // The reference profile info will contain the methods with indices 50-150.
736   // When setting up the profile reverse the order in which the dex files
737   // are added to the profile. This will verify that profman merges profiles
738   // with a different dex order correctly.
739   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
740   ProfileCompilationInfo reference_info;
741   SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
742       &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
743 
744   // We should advise compilation.
745   ASSERT_EQ(ProfileAssistant::kCompile,
746             ProcessProfiles(profile_fds, reference_profile_fd));
747 
748   // The resulting compilation info must be equal to the merge of the inputs.
749   ProfileCompilationInfo result;
750   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
751   ASSERT_TRUE(result.Load(reference_profile_fd));
752 
753   ProfileCompilationInfo expected;
754   ASSERT_TRUE(expected.MergeWith(reference_info));
755   ASSERT_TRUE(expected.MergeWith(info1));
756   ASSERT_TRUE(expected.Equals(result));
757 
758   // The information from profile must remain the same.
759   CheckProfileInfo(profile1, info1);
760 }
761 
TEST_F(ProfileAssistantTest,TestProfileCreateWithInvalidData)762 TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
763   // Create the profile content.
764   std::vector<std::string> profile_methods = {
765     "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
766     "LTestInline;->invalid_method",
767     "invalid_class"
768   };
769   std::string input_file_contents;
770   for (std::string& m : profile_methods) {
771     input_file_contents += m + std::string("\n");
772   }
773 
774   // Create the profile and save it to disk.
775   ScratchFile profile_file;
776   std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
777   ASSERT_TRUE(CreateProfile(input_file_contents,
778                             profile_file.GetFilename(),
779                             dex_filename));
780 
781   // Load the profile from disk.
782   ProfileCompilationInfo info;
783   profile_file.GetFile()->ResetOffset();
784   ASSERT_TRUE(info.Load(GetFd(profile_file)));
785 
786   // Load the dex files and verify that the profile contains the expected methods info.
787   ScopedObjectAccess soa(Thread::Current());
788   jobject class_loader = LoadDex("ProfileTestMultiDex");
789   ASSERT_NE(class_loader, nullptr);
790 
791   ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
792                                                    "LTestInline;",
793                                                    "inlineMonomorphic");
794   const DexFile* dex_file = inline_monomorphic->GetDexFile();
795 
796   // Verify that the inline cache contains the invalid type.
797   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
798       info.GetMethod(dex_file->GetLocation(),
799                      dex_file->GetLocationChecksum(),
800                      inline_monomorphic->GetDexMethodIndex());
801   ASSERT_TRUE(pmi != nullptr);
802   ASSERT_EQ(pmi->inline_caches->size(), 1u);
803   const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
804   dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
805   ASSERT_EQ(1u, dex_pc_data.classes.size());
806   ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
807 
808   // Verify that the start-up classes contain the invalid class.
809   std::set<dex::TypeIndex> classes;
810   std::set<uint16_t> methods;
811   ASSERT_TRUE(info.GetClassesAndMethods(*dex_file, &classes, &methods));
812   ASSERT_EQ(1u, classes.size());
813   ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
814 
815   // Verify that the invalid method is in the profile.
816   ASSERT_EQ(2u, methods.size());
817   uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
818   ASSERT_TRUE(methods.find(invalid_method_index) != methods.end());
819 }
820 
821 }  // namespace art
822