blob: e87852baf0338736549cdfc72d0b0d6448e209d1 [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
Mathieu Chartierea650f32017-05-24 12:04:13 -070033static constexpr size_t kMaxMethodIds = 65535;
34
Calin Juravle2e2db782016-02-23 12:00:03 +000035class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070036 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070037 void PostRuntimeCreate() OVERRIDE {
Calin Juravlecc3171a2017-05-19 16:47:53 -070038 arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
39 }
40
Calin Juravle2e2db782016-02-23 12:00:03 +000041 protected:
42 void SetupProfile(const std::string& id,
43 uint32_t checksum,
44 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010045 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000046 const ScratchFile& profile,
47 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070048 uint16_t start_method_index = 0,
49 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000050 std::string dex_location1 = "location1" + id;
51 uint32_t dex_location_checksum1 = checksum;
52 std::string dex_location2 = "location2" + id;
53 uint32_t dex_location_checksum2 = 10 * checksum;
54 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070055 // reverse_dex_write_order controls the order in which the dex files will be added to
56 // the profile and thus written to disk.
57 ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
58 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
59 dex_location2, dex_location_checksum2);
60 if (reverse_dex_write_order) {
Mathieu Chartierea650f32017-05-24 12:04:13 -070061 ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
62 ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070063 } else {
Mathieu Chartierea650f32017-05-24 12:04:13 -070064 ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
65 ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070066 }
Calin Juravle2e2db782016-02-23 12:00:03 +000067 }
Calin Juravlec824b512016-03-29 20:33:33 +010068 for (uint16_t i = 0; i < number_of_classes; i++) {
Mathieu Chartierea650f32017-05-24 12:04:13 -070069 ASSERT_TRUE(info->AddClassIndex(dex_location1,
70 dex_location_checksum1,
71 dex::TypeIndex(i),
72 kMaxMethodIds));
Calin Juravlec824b512016-03-29 20:33:33 +010073 }
74
Calin Juravle2e2db782016-02-23 12:00:03 +000075 ASSERT_TRUE(info->Save(GetFd(profile)));
76 ASSERT_EQ(0, profile.GetFile()->Flush());
77 ASSERT_TRUE(profile.GetFile()->ResetOffset());
78 }
79
Calin Juravlee6f87cc2017-05-24 17:41:05 -070080 // Creates an inline cache which will be destructed at the end of the test.
81 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
82 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
83 std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
84 return used_inline_caches.back().get();
85 }
86
Calin Juravlecea9e9d2017-03-23 19:04:59 -070087 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
88 const std::string& dex_location1, uint32_t dex_checksum1,
89 const std::string& dex_location2, uint32_t dex_checksum2) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -070090 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
91 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -070092 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, kMaxMethodIds);
93 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, kMaxMethodIds);
Calin Juravlecea9e9d2017-03-23 19:04:59 -070094
95 // Monomorphic
96 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070097 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -070098 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -070099 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700100 }
101 // Polymorphic
102 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700103 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700104 dex_pc_data.AddClass(0, dex::TypeIndex(0));
105 dex_pc_data.AddClass(1, dex::TypeIndex(1));
106
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700107 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700108 }
109 // Megamorphic
110 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700111 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700112 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700113 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700114 }
115 // Missing types
116 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700117 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700118 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700119 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700120 }
121
122 return pmi;
123 }
124
Calin Juravle2e2db782016-02-23 12:00:03 +0000125 int GetFd(const ScratchFile& file) const {
126 return static_cast<int>(file.GetFd());
127 }
128
129 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
130 ProfileCompilationInfo file_info;
131 ASSERT_TRUE(file.GetFile()->ResetOffset());
132 ASSERT_TRUE(file_info.Load(GetFd(file)));
133 ASSERT_TRUE(file_info.Equals(info));
134 }
135
Calin Juravle7bcdb532016-06-07 16:14:47 +0100136 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000137 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000138 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000139 if (kIsDebugBuild) {
140 file_path += "d";
141 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100142 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
143 << file_path << " should be a valid file path";
144 return file_path;
145 }
146 // Runs test with given arguments.
147 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
148 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000149 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100150 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000151 for (size_t k = 0; k < profiles_fd.size(); k++) {
152 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
153 }
154 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
155
156 std::string error;
157 return ExecAndReturnCode(argv_str, &error);
158 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100159
160 bool GenerateTestProfile(const std::string& filename) {
161 std::string profman_cmd = GetProfmanCmd();
162 std::vector<std::string> argv_str;
163 argv_str.push_back(profman_cmd);
164 argv_str.push_back("--generate-test-profile=" + filename);
165 std::string error;
166 return ExecAndReturnCode(argv_str, &error);
167 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800168
Jeff Haof0a31f82017-03-27 15:50:37 -0700169 bool GenerateTestProfileWithInputDex(const std::string& filename) {
170 std::string profman_cmd = GetProfmanCmd();
171 std::vector<std::string> argv_str;
172 argv_str.push_back(profman_cmd);
173 argv_str.push_back("--generate-test-profile=" + filename);
174 argv_str.push_back("--generate-test-profile-seed=0");
175 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
176 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
177 std::string error;
178 return ExecAndReturnCode(argv_str, &error);
179 }
180
Calin Juravlee0ac1152017-02-13 19:03:47 -0800181 bool CreateProfile(std::string profile_file_contents,
182 const std::string& filename,
183 const std::string& dex_location) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800184 ScratchFile class_names_file;
185 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800186 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800187 EXPECT_EQ(0, file->Flush());
188 EXPECT_TRUE(file->ResetOffset());
189 std::string profman_cmd = GetProfmanCmd();
190 std::vector<std::string> argv_str;
191 argv_str.push_back(profman_cmd);
192 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
193 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800194 argv_str.push_back("--apk=" + dex_location);
195 argv_str.push_back("--dex-location=" + dex_location);
David Sehr7c80f2d2017-02-07 16:47:58 -0800196 std::string error;
197 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
198 return true;
199 }
200
Mathieu Chartier34067262017-04-06 13:55:46 -0700201 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800202 ScratchFile class_names_file;
203 std::string profman_cmd = GetProfmanCmd();
204 std::vector<std::string> argv_str;
205 argv_str.push_back(profman_cmd);
Mathieu Chartier34067262017-04-06 13:55:46 -0700206 argv_str.push_back("--dump-classes-and-methods");
David Sehr7c80f2d2017-02-07 16:47:58 -0800207 argv_str.push_back("--profile-file=" + filename);
208 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800209 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
David Sehr7c80f2d2017-02-07 16:47:58 -0800210 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(class_names_file)));
211 std::string error;
212 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
213 File* file = class_names_file.GetFile();
214 EXPECT_EQ(0, file->Flush());
215 EXPECT_TRUE(file->ResetOffset());
216 int64_t length = file->GetLength();
217 std::unique_ptr<char[]> buf(new char[length]);
218 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
219 *file_contents = std::string(buf.get(), length);
220 return true;
221 }
222
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700223 bool CreateAndDump(const std::string& input_file_contents,
224 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800225 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800226 EXPECT_TRUE(CreateProfile(input_file_contents,
227 profile_file.GetFilename(),
228 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800229 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700230 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800231 return true;
232 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800233
234 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
235 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
236 Thread* self = Thread::Current();
237 ScopedObjectAccess soa(self);
238 StackHandleScope<1> hs(self);
239 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700240 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800241 return class_linker->FindClass(self, clazz.c_str(), h_loader);
242 }
243
244 ArtMethod* GetVirtualMethod(jobject class_loader,
245 const std::string& clazz,
246 const std::string& name) {
247 mirror::Class* klass = GetClass(class_loader, clazz);
248 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
249 const auto pointer_size = class_linker->GetImagePointerSize();
250 ArtMethod* method = nullptr;
251 Thread* self = Thread::Current();
252 ScopedObjectAccess soa(self);
253 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
254 if (name == m.GetName()) {
255 EXPECT_TRUE(method == nullptr);
256 method = &m;
257 }
258 }
259 return method;
260 }
261
262 // Verify that given method has the expected inline caches and nothing else.
263 void AssertInlineCaches(ArtMethod* method,
264 const std::set<mirror::Class*>& expected_clases,
265 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800266 bool is_megamorphic,
267 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800268 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700269 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
270 info.GetMethod(method->GetDexFile()->GetLocation(),
271 method->GetDexFile()->GetLocationChecksum(),
272 method->GetDexMethodIndex());
273 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700274 ASSERT_EQ(pmi->inline_caches->size(), 1u);
275 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800276
Calin Juravle589e71e2017-03-03 16:05:05 -0800277 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
278 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800279 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
280 size_t found = 0;
281 for (mirror::Class* it : expected_clases) {
282 for (const auto& class_ref : dex_pc_data.classes) {
283 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700284 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800285 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
286 class_ref.type_index == it->GetDexTypeIndex()) {
287 found++;
288 }
289 }
290 }
291
292 ASSERT_EQ(expected_clases.size(), found);
293 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700294
295 std::unique_ptr<ArenaAllocator> arena_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700296
297 // Cache of inline caches generated during tests.
298 // This makes it easier to pass data between different utilities and ensure that
299 // caches are destructed at the end of the test.
300 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000301};
302
303TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
304 ScratchFile profile1;
305 ScratchFile profile2;
306 ScratchFile reference_profile;
307
308 std::vector<int> profile_fds({
309 GetFd(profile1),
310 GetFd(profile2)});
311 int reference_profile_fd = GetFd(reference_profile);
312
313 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
314 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100315 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000316 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100317 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000318
319 // We should advise compilation.
320 ASSERT_EQ(ProfileAssistant::kCompile,
321 ProcessProfiles(profile_fds, reference_profile_fd));
322 // The resulting compilation info must be equal to the merge of the inputs.
323 ProfileCompilationInfo result;
324 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
325 ASSERT_TRUE(result.Load(reference_profile_fd));
326
327 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000328 ASSERT_TRUE(expected.MergeWith(info1));
329 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000330 ASSERT_TRUE(expected.Equals(result));
331
332 // The information from profiles must remain the same.
333 CheckProfileInfo(profile1, info1);
334 CheckProfileInfo(profile2, info2);
335}
336
Calin Juravlec824b512016-03-29 20:33:33 +0100337// TODO(calin): Add more tests for classes.
338TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
339 ScratchFile profile1;
340 ScratchFile reference_profile;
341
342 std::vector<int> profile_fds({
343 GetFd(profile1)});
344 int reference_profile_fd = GetFd(reference_profile);
345
346 const uint16_t kNumberOfClassesToEnableCompilation = 100;
347 ProfileCompilationInfo info1;
348 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
349
350 // We should advise compilation.
351 ASSERT_EQ(ProfileAssistant::kCompile,
352 ProcessProfiles(profile_fds, reference_profile_fd));
353 // The resulting compilation info must be equal to the merge of the inputs.
354 ProfileCompilationInfo result;
355 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
356 ASSERT_TRUE(result.Load(reference_profile_fd));
357
358 ProfileCompilationInfo expected;
359 ASSERT_TRUE(expected.MergeWith(info1));
360 ASSERT_TRUE(expected.Equals(result));
361
362 // The information from profiles must remain the same.
363 CheckProfileInfo(profile1, info1);
364}
365
Calin Juravle2e2db782016-02-23 12:00:03 +0000366TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
367 ScratchFile profile1;
368 ScratchFile profile2;
369 ScratchFile reference_profile;
370
371 std::vector<int> profile_fds({
372 GetFd(profile1),
373 GetFd(profile2)});
374 int reference_profile_fd = GetFd(reference_profile);
375
376 // The new profile info will contain the methods with indices 0-100.
377 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
378 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100379 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000380 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100381 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000382
383
384 // The reference profile info will contain the methods with indices 50-150.
385 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
386 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100387 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000388 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
389
390 // We should advise compilation.
391 ASSERT_EQ(ProfileAssistant::kCompile,
392 ProcessProfiles(profile_fds, reference_profile_fd));
393
394 // The resulting compilation info must be equal to the merge of the inputs
395 ProfileCompilationInfo result;
396 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
397 ASSERT_TRUE(result.Load(reference_profile_fd));
398
399 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000400 ASSERT_TRUE(expected.MergeWith(info1));
401 ASSERT_TRUE(expected.MergeWith(info2));
402 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000403 ASSERT_TRUE(expected.Equals(result));
404
405 // The information from profiles must remain the same.
406 CheckProfileInfo(profile1, info1);
407 CheckProfileInfo(profile2, info2);
408}
409
410TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
411 ScratchFile profile1;
412 ScratchFile profile2;
413 ScratchFile reference_profile;
414
415 std::vector<int> profile_fds({
416 GetFd(profile1),
417 GetFd(profile2)});
418 int reference_profile_fd = GetFd(reference_profile);
419
420 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
421 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100422 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000423 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100424 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000425
426 // We should not advise compilation.
427 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
428 ProcessProfiles(profile_fds, reference_profile_fd));
429
430 // The information from profiles must remain the same.
431 ProfileCompilationInfo file_info1;
432 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
433 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
434 ASSERT_TRUE(file_info1.Equals(info1));
435
436 ProfileCompilationInfo file_info2;
437 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
438 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
439 ASSERT_TRUE(file_info2.Equals(info2));
440
441 // Reference profile files must remain empty.
442 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
443
444 // The information from profiles must remain the same.
445 CheckProfileInfo(profile1, info1);
446 CheckProfileInfo(profile2, info2);
447}
448
449TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
450 ScratchFile profile1;
451 ScratchFile profile2;
452 ScratchFile reference_profile;
453
454 std::vector<int> profile_fds({
455 GetFd(profile1),
456 GetFd(profile2)});
457 int reference_profile_fd = GetFd(reference_profile);
458
459 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
460 // Assign different hashes for the same dex file. This will make merging of information to fail.
461 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100462 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000463 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100464 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000465
466 // We should fail processing.
467 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
468 ProcessProfiles(profile_fds, reference_profile_fd));
469
470 // The information from profiles must remain the same.
471 CheckProfileInfo(profile1, info1);
472 CheckProfileInfo(profile2, info2);
473
474 // Reference profile files must still remain empty.
475 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
476}
477
478TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
479 ScratchFile profile1;
480 ScratchFile reference_profile;
481
482 std::vector<int> profile_fds({
483 GetFd(profile1)});
484 int reference_profile_fd = GetFd(reference_profile);
485
486 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
487 // Assign different hashes for the same dex file. This will make merging of information to fail.
488 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100489 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000490 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100491 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000492
493 // We should not advise compilation.
494 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
495 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
496 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
497 ProcessProfiles(profile_fds, reference_profile_fd));
498
499 // The information from profiles must remain the same.
500 CheckProfileInfo(profile1, info1);
501}
502
Calin Juravle7bcdb532016-06-07 16:14:47 +0100503TEST_F(ProfileAssistantTest, TestProfileGeneration) {
504 ScratchFile profile;
505 // Generate a test profile.
506 GenerateTestProfile(profile.GetFilename());
507
508 // Verify that the generated profile is valid and can be loaded.
509 ASSERT_TRUE(profile.GetFile()->ResetOffset());
510 ProfileCompilationInfo info;
511 ASSERT_TRUE(info.Load(GetFd(profile)));
512}
513
Jeff Haof0a31f82017-03-27 15:50:37 -0700514TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
515 ScratchFile profile;
516 // Generate a test profile passing in a dex file as reference.
517 GenerateTestProfileWithInputDex(profile.GetFilename());
518
519 // Verify that the generated profile is valid and can be loaded.
520 ASSERT_TRUE(profile.GetFile()->ResetOffset());
521 ProfileCompilationInfo info;
522 ASSERT_TRUE(info.Load(GetFd(profile)));
523}
524
David Sehr7c80f2d2017-02-07 16:47:58 -0800525TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
526 // Class names put here need to be in sorted order.
527 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700528 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800529 "Ljava/lang/Comparable;",
530 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700531 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700532 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800533 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700534 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800535 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700536 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800537 }
538 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700539 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
540 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800541}
542
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700543TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
544 // Class names put here need to be in sorted order.
545 std::vector<std::string> class_names = {
546 "Ljava/lang/Math;->*",
547 };
548 std::string input_file_contents;
549 std::string expected_contents;
550 for (std::string& class_name : class_names) {
551 input_file_contents += class_name + std::string("\n");
552 expected_contents += DescriptorToDot(class_name.c_str()) +
553 std::string("\n");
554 }
555 std::string output_file_contents;
556 ScratchFile profile_file;
557 EXPECT_TRUE(CreateProfile(input_file_contents,
558 profile_file.GetFilename(),
559 GetLibCoreDexFileNames()[0]));
560 ProfileCompilationInfo info;
561 profile_file.GetFile()->ResetOffset();
562 ASSERT_TRUE(info.Load(GetFd(profile_file)));
563 // Verify that the profile has matching methods.
564 ScopedObjectAccess soa(Thread::Current());
565 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
566 ASSERT_TRUE(klass != nullptr);
567 size_t method_count = 0;
568 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
569 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
570 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700571 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
572 info.GetMethod(method.GetDexFile()->GetLocation(),
573 method.GetDexFile()->GetLocationChecksum(),
574 method.GetDexMethodIndex());
575 ASSERT_TRUE(pmi != nullptr);
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700576 }
577 }
578 EXPECT_GT(method_count, 0u);
579}
580
David Sehr7c80f2d2017-02-07 16:47:58 -0800581TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
582 // Class names put here need to be in sorted order.
583 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800584 "Ldoesnt/match/this/one;",
585 "Ljava/lang/Comparable;",
586 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800587 };
588 std::string input_file_contents;
589 for (std::string& class_name : class_names) {
590 input_file_contents += class_name + std::string("\n");
591 }
592 std::string output_file_contents;
593 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
594 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700595 class_names[1] + std::string("\n") +
596 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800597 ASSERT_EQ(output_file_contents, expected_contents);
598}
599
600TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
601 // Class names put here need to be in sorted order.
602 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800603 "Ldoesnt/match/this/one;",
604 "Ldoesnt/match/this/one/either;",
605 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800606 };
607 std::string input_file_contents;
608 for (std::string& class_name : class_names) {
609 input_file_contents += class_name + std::string("\n");
610 }
611 std::string output_file_contents;
612 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
613 std::string expected_contents("");
614 ASSERT_EQ(output_file_contents, expected_contents);
615}
616
Calin Juravlee0ac1152017-02-13 19:03:47 -0800617TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
618 // Create the profile content.
619 std::vector<std::string> methods = {
620 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
621 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
622 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800623 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800624 "LTestInline;->noInlineCache(LSuper;)I"
625 };
626 std::string input_file_contents;
627 for (std::string& m : methods) {
628 input_file_contents += m + std::string("\n");
629 }
630
631 // Create the profile and save it to disk.
632 ScratchFile profile_file;
633 ASSERT_TRUE(CreateProfile(input_file_contents,
634 profile_file.GetFilename(),
635 GetTestDexFileName("ProfileTestMultiDex")));
636
637 // Load the profile from disk.
638 ProfileCompilationInfo info;
639 profile_file.GetFile()->ResetOffset();
640 ASSERT_TRUE(info.Load(GetFd(profile_file)));
641
642 // Load the dex files and verify that the profile contains the expected methods info.
643 ScopedObjectAccess soa(Thread::Current());
644 jobject class_loader = LoadDex("ProfileTestMultiDex");
645 ASSERT_NE(class_loader, nullptr);
646
647 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
648 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
649 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
650
651 ASSERT_TRUE(sub_a != nullptr);
652 ASSERT_TRUE(sub_b != nullptr);
653 ASSERT_TRUE(sub_c != nullptr);
654
655 {
656 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
657 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
658 "LTestInline;",
659 "inlineMonomorphic");
660 ASSERT_TRUE(inline_monomorphic != nullptr);
661 std::set<mirror::Class*> expected_monomorphic;
662 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800663 AssertInlineCaches(inline_monomorphic,
664 expected_monomorphic,
665 info,
666 /*megamorphic*/false,
667 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800668 }
669
670 {
671 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
672 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
673 "LTestInline;",
674 "inlinePolymorphic");
675 ASSERT_TRUE(inline_polymorhic != nullptr);
676 std::set<mirror::Class*> expected_polymorphic;
677 expected_polymorphic.insert(sub_a);
678 expected_polymorphic.insert(sub_b);
679 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800680 AssertInlineCaches(inline_polymorhic,
681 expected_polymorphic,
682 info,
683 /*megamorphic*/false,
684 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800685 }
686
687 {
688 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
689 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
690 "LTestInline;",
691 "inlineMegamorphic");
692 ASSERT_TRUE(inline_megamorphic != nullptr);
693 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800694 AssertInlineCaches(inline_megamorphic,
695 expected_megamorphic,
696 info,
697 /*megamorphic*/true,
698 /*missing_types*/false);
699 }
700
701 {
702 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
703 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
704 "LTestInline;",
705 "inlineMissingTypes");
706 ASSERT_TRUE(inline_missing_types != nullptr);
707 std::set<mirror::Class*> expected_missing_Types;
708 AssertInlineCaches(inline_missing_types,
709 expected_missing_Types,
710 info,
711 /*megamorphic*/false,
712 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800713 }
714
715 {
716 // Verify that method noInlineCache has no inline caches in the profile.
717 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
718 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700719 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
720 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
721 no_inline_cache->GetDexFile()->GetLocationChecksum(),
722 no_inline_cache->GetDexMethodIndex());
723 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700724 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800725 }
726}
727
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700728TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
729 ScratchFile profile1;
730 ScratchFile reference_profile;
731
732 std::vector<int> profile_fds({GetFd(profile1)});
733 int reference_profile_fd = GetFd(reference_profile);
734
735 // The new profile info will contain the methods with indices 0-100.
736 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
737 ProfileCompilationInfo info1;
738 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
739 /*start_method_index*/0, /*reverse_dex_write_order*/false);
740
741 // The reference profile info will contain the methods with indices 50-150.
742 // When setting up the profile reverse the order in which the dex files
743 // are added to the profile. This will verify that profman merges profiles
744 // with a different dex order correctly.
745 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
746 ProfileCompilationInfo reference_info;
747 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
748 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
749
750 // We should advise compilation.
751 ASSERT_EQ(ProfileAssistant::kCompile,
752 ProcessProfiles(profile_fds, reference_profile_fd));
753
754 // The resulting compilation info must be equal to the merge of the inputs.
755 ProfileCompilationInfo result;
756 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
757 ASSERT_TRUE(result.Load(reference_profile_fd));
758
759 ProfileCompilationInfo expected;
760 ASSERT_TRUE(expected.MergeWith(reference_info));
761 ASSERT_TRUE(expected.MergeWith(info1));
762 ASSERT_TRUE(expected.Equals(result));
763
764 // The information from profile must remain the same.
765 CheckProfileInfo(profile1, info1);
766}
767
Calin Juravle08556882017-05-26 16:40:45 -0700768TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
769 // Create the profile content.
770 std::vector<std::string> profile_methods = {
771 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
772 "LTestInline;->invalid_method",
773 "invalid_class"
774 };
775 std::string input_file_contents;
776 for (std::string& m : profile_methods) {
777 input_file_contents += m + std::string("\n");
778 }
779
780 // Create the profile and save it to disk.
781 ScratchFile profile_file;
782 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
783 ASSERT_TRUE(CreateProfile(input_file_contents,
784 profile_file.GetFilename(),
785 dex_filename));
786
787 // Load the profile from disk.
788 ProfileCompilationInfo info;
789 profile_file.GetFile()->ResetOffset();
790 ASSERT_TRUE(info.Load(GetFd(profile_file)));
791
792 // Load the dex files and verify that the profile contains the expected methods info.
793 ScopedObjectAccess soa(Thread::Current());
794 jobject class_loader = LoadDex("ProfileTestMultiDex");
795 ASSERT_NE(class_loader, nullptr);
796
797 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
798 "LTestInline;",
799 "inlineMonomorphic");
800 const DexFile* dex_file = inline_monomorphic->GetDexFile();
801
802 // Verify that the inline cache contains the invalid type.
803 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
804 info.GetMethod(dex_file->GetLocation(),
805 dex_file->GetLocationChecksum(),
806 inline_monomorphic->GetDexMethodIndex());
807 ASSERT_TRUE(pmi != nullptr);
808 ASSERT_EQ(pmi->inline_caches->size(), 1u);
809 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
810 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
811 ASSERT_EQ(1u, dex_pc_data.classes.size());
812 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
813
814 // Verify that the start-up classes contain the invalid class.
815 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -0700816 std::set<uint16_t> hot_methods;
817 std::set<uint16_t> startup_methods;
818 std::set<uint16_t> post_start_methods;
819 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
820 &classes,
821 &hot_methods,
822 &startup_methods,
823 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -0700824 ASSERT_EQ(1u, classes.size());
825 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
826
827 // Verify that the invalid method is in the profile.
Mathieu Chartierea650f32017-05-24 12:04:13 -0700828 ASSERT_EQ(2u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -0700829 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Mathieu Chartierea650f32017-05-24 12:04:13 -0700830 ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -0700831}
832
Calin Juravle2e2db782016-02-23 12:00:03 +0000833} // namespace art