blob: 1c328987cbed0827d82e8a14eb1717621088a4ef [file] [log] [blame]
Calin Juravle2e2db782016-02-23 12:00:03 +00001/*
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
Calin Juravlee0ac1152017-02-13 19:03:47 -080019#include "art_method-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000020#include "base/unix_file/fd_file.h"
21#include "common_runtime_test.h"
David Sehr97c381e2017-02-01 15:09:58 -080022#include "exec_utils.h"
Calin Juravle33083d62017-01-18 15:29:12 -080023#include "jit/profile_compilation_info.h"
Calin Juravlecc3171a2017-05-19 16:47:53 -070024#include "linear_alloc.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080025#include "mirror/class-inl.h"
Mathieu Chartierd808e8b2017-03-21 13:37:41 -070026#include "obj_ptr-inl.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080027#include "profile_assistant.h"
28#include "scoped_thread_state_change-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000029#include "utils.h"
30
31namespace art {
32
33class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070034 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070035 void PostRuntimeCreate() OVERRIDE {
Calin Juravlecc3171a2017-05-19 16:47:53 -070036 arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
37 }
38
Calin Juravle2e2db782016-02-23 12:00:03 +000039 protected:
40 void SetupProfile(const std::string& id,
41 uint32_t checksum,
42 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010043 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000044 const ScratchFile& profile,
45 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070046 uint16_t start_method_index = 0,
47 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000048 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++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070053 // 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 }
Calin Juravle2e2db782016-02-23 12:00:03 +000065 }
Calin Juravlec824b512016-03-29 20:33:33 +010066 for (uint16_t i = 0; i < number_of_classes; i++) {
Andreas Gampea5b09a62016-11-17 15:21:22 -080067 ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
Calin Juravlec824b512016-03-29 20:33:33 +010068 }
69
Calin Juravle2e2db782016-02-23 12:00:03 +000070 ASSERT_TRUE(info->Save(GetFd(profile)));
71 ASSERT_EQ(0, profile.GetFile()->Flush());
72 ASSERT_TRUE(profile.GetFile()->ResetOffset());
73 }
74
Calin Juravlee6f87cc2017-05-24 17:41:05 -070075 // Creates an inline cache which will be destructed at the end of the test.
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
Calin Juravlecea9e9d2017-03-23 19:04:59 -070082 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
83 const std::string& dex_location1, uint32_t dex_checksum1,
84 const std::string& dex_location2, uint32_t dex_checksum2) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -070085 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
86 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Calin Juravlecea9e9d2017-03-23 19:04:59 -070087 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++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070092 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -070093 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -070094 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -070095 }
96 // Polymorphic
97 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070098 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -070099 dex_pc_data.AddClass(0, dex::TypeIndex(0));
100 dex_pc_data.AddClass(1, dex::TypeIndex(1));
101
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700102 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700103 }
104 // Megamorphic
105 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700106 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700107 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700108 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700109 }
110 // Missing types
111 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700112 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700113 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700114 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700115 }
116
117 return pmi;
118 }
119
Calin Juravle2e2db782016-02-23 12:00:03 +0000120 int GetFd(const ScratchFile& file) const {
121 return static_cast<int>(file.GetFd());
122 }
123
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
Calin Juravle7bcdb532016-06-07 16:14:47 +0100131 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000132 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000133 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000134 if (kIsDebugBuild) {
135 file_path += "d";
136 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100137 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.
142 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
143 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000144 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100145 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000146 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 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100154
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 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800163
Jeff Haof0a31f82017-03-27 15:50:37 -0700164 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
Calin Juravlee0ac1152017-02-13 19:03:47 -0800176 bool CreateProfile(std::string profile_file_contents,
177 const std::string& filename,
178 const std::string& dex_location) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800179 ScratchFile class_names_file;
180 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800181 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800182 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);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800189 argv_str.push_back("--apk=" + dex_location);
190 argv_str.push_back("--dex-location=" + dex_location);
David Sehr7c80f2d2017-02-07 16:47:58 -0800191 std::string error;
192 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
193 return true;
194 }
195
Mathieu Chartier34067262017-04-06 13:55:46 -0700196 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800197 ScratchFile class_names_file;
198 std::string profman_cmd = GetProfmanCmd();
199 std::vector<std::string> argv_str;
200 argv_str.push_back(profman_cmd);
Mathieu Chartier34067262017-04-06 13:55:46 -0700201 argv_str.push_back("--dump-classes-and-methods");
David Sehr7c80f2d2017-02-07 16:47:58 -0800202 argv_str.push_back("--profile-file=" + filename);
203 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800204 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
David Sehr7c80f2d2017-02-07 16:47:58 -0800205 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
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700218 bool CreateAndDump(const std::string& input_file_contents,
219 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800220 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800221 EXPECT_TRUE(CreateProfile(input_file_contents,
222 profile_file.GetFilename(),
223 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800224 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700225 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800226 return true;
227 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800228
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(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700235 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800236 return class_linker->FindClass(self, clazz.c_str(), h_loader);
237 }
238
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.
258 void AssertInlineCaches(ArtMethod* method,
259 const std::set<mirror::Class*>& expected_clases,
260 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800261 bool is_megamorphic,
262 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800263 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700264 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
265 info.GetMethod(method->GetDexFile()->GetLocation(),
266 method->GetDexFile()->GetLocationChecksum(),
267 method->GetDexMethodIndex());
268 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700269 ASSERT_EQ(pmi->inline_caches->size(), 1u);
270 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800271
Calin Juravle589e71e2017-03-03 16:05:05 -0800272 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
273 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800274 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 =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700279 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800280 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 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700289
290 std::unique_ptr<ArenaAllocator> arena_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700291
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;
Calin Juravle2e2db782016-02-23 12:00:03 +0000296};
297
298TEST_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;
Calin Juravlec824b512016-03-29 20:33:33 +0100310 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000311 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100312 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000313
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;
Calin Juravle67265462016-03-18 16:23:40 +0000323 ASSERT_TRUE(expected.MergeWith(info1));
324 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000325 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
Calin Juravlec824b512016-03-29 20:33:33 +0100332// TODO(calin): Add more tests for classes.
333TEST_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
Calin Juravle2e2db782016-02-23 12:00:03 +0000361TEST_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;
Calin Juravlec824b512016-03-29 20:33:33 +0100374 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000375 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100376 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000377
378
379 // The reference profile info will contain the methods with indices 50-150.
380 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
381 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100382 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000383 &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;
Calin Juravle67265462016-03-18 16:23:40 +0000395 ASSERT_TRUE(expected.MergeWith(info1));
396 ASSERT_TRUE(expected.MergeWith(info2));
397 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000398 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
405TEST_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;
Calin Juravlec824b512016-03-29 20:33:33 +0100417 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000418 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100419 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000420
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
444TEST_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;
Calin Juravlec824b512016-03-29 20:33:33 +0100457 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000458 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100459 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000460
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
473TEST_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;
Calin Juravlec824b512016-03-29 20:33:33 +0100484 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000485 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100486 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000487
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
Calin Juravle7bcdb532016-06-07 16:14:47 +0100498TEST_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
Jeff Haof0a31f82017-03-27 15:50:37 -0700509TEST_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
David Sehr7c80f2d2017-02-07 16:47:58 -0800520TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
521 // Class names put here need to be in sorted order.
522 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800523 "Ljava/lang/Comparable;",
524 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700525 "Ljava/lang/Object;",
526 "Ljava/lang/Object;-><init>()V"
David Sehr7c80f2d2017-02-07 16:47:58 -0800527 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700528 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800529 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700530 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800531 }
532 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700533 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
534 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800535}
536
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700537TEST_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;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700565 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
566 info.GetMethod(method.GetDexFile()->GetLocation(),
567 method.GetDexFile()->GetLocationChecksum(),
568 method.GetDexMethodIndex());
569 ASSERT_TRUE(pmi != nullptr);
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700570 }
571 }
572 EXPECT_GT(method_count, 0u);
573}
574
David Sehr7c80f2d2017-02-07 16:47:58 -0800575TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
576 // Class names put here need to be in sorted order.
577 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800578 "Ldoesnt/match/this/one;",
579 "Ljava/lang/Comparable;",
580 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800581 };
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 =
Mathieu Chartier34067262017-04-06 13:55:46 -0700589 class_names[1] + std::string("\n") +
590 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800591 ASSERT_EQ(output_file_contents, expected_contents);
592}
593
594TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
595 // Class names put here need to be in sorted order.
596 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800597 "Ldoesnt/match/this/one;",
598 "Ldoesnt/match/this/one/either;",
599 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800600 };
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
Calin Juravlee0ac1152017-02-13 19:03:47 -0800611TEST_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;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800617 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800618 "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);
Calin Juravle589e71e2017-03-03 16:05:05 -0800657 AssertInlineCaches(inline_monomorphic,
658 expected_monomorphic,
659 info,
660 /*megamorphic*/false,
661 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800662 }
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);
Calin Juravle589e71e2017-03-03 16:05:05 -0800674 AssertInlineCaches(inline_polymorhic,
675 expected_polymorphic,
676 info,
677 /*megamorphic*/false,
678 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800679 }
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;
Calin Juravle589e71e2017-03-03 16:05:05 -0800688 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);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800707 }
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);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700713 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);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700718 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800719 }
720}
721
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700722TEST_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
Calin Juravle08556882017-05-26 16:40:45 -0700762TEST_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
Calin Juravle2e2db782016-02-23 12:00:03 +0000821} // namespace art