blob: 9e2ab39a488284548a75b1b00dd874ff92fe860a [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
Mathieu Chartier28b5c582017-06-06 14:12:50 -070080 void SetupBasicProfile(const std::string& id,
81 uint32_t checksum,
82 uint16_t number_of_methods,
83 const std::vector<uint32_t> hot_methods,
84 const std::vector<uint32_t> startup_methods,
85 const std::vector<uint32_t> post_startup_methods,
86 const ScratchFile& profile,
87 ProfileCompilationInfo* info) {
88 std::string dex_location = "location1" + id;
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070089 using Hotness = ProfileCompilationInfo::MethodHotness;
Mathieu Chartier28b5c582017-06-06 14:12:50 -070090 for (uint32_t idx : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070091 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -070092 }
93 for (uint32_t idx : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070094 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -070095 }
96 for (uint32_t idx : post_startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070097 info->AddMethodIndex(Hotness::kFlagPostStartup,
98 dex_location,
99 checksum,
100 idx,
101 number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700102 }
103 ASSERT_TRUE(info->Save(GetFd(profile)));
104 ASSERT_EQ(0, profile.GetFile()->Flush());
105 ASSERT_TRUE(profile.GetFile()->ResetOffset());
106 }
107
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700108 // Creates an inline cache which will be destructed at the end of the test.
109 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
110 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
111 std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
112 return used_inline_caches.back().get();
113 }
114
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700115 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
116 const std::string& dex_location1, uint32_t dex_checksum1,
117 const std::string& dex_location2, uint32_t dex_checksum2) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700118 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
119 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700120 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, kMaxMethodIds);
121 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, kMaxMethodIds);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700122
123 // Monomorphic
124 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700125 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700126 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700127 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700128 }
129 // Polymorphic
130 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700131 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700132 dex_pc_data.AddClass(0, dex::TypeIndex(0));
133 dex_pc_data.AddClass(1, dex::TypeIndex(1));
134
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700135 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700136 }
137 // Megamorphic
138 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700139 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700140 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700141 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700142 }
143 // Missing types
144 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700145 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700146 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700147 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700148 }
149
150 return pmi;
151 }
152
Calin Juravle2e2db782016-02-23 12:00:03 +0000153 int GetFd(const ScratchFile& file) const {
154 return static_cast<int>(file.GetFd());
155 }
156
157 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
158 ProfileCompilationInfo file_info;
159 ASSERT_TRUE(file.GetFile()->ResetOffset());
160 ASSERT_TRUE(file_info.Load(GetFd(file)));
161 ASSERT_TRUE(file_info.Equals(info));
162 }
163
Calin Juravle7bcdb532016-06-07 16:14:47 +0100164 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000165 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000166 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000167 if (kIsDebugBuild) {
168 file_path += "d";
169 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100170 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
171 << file_path << " should be a valid file path";
172 return file_path;
173 }
174 // Runs test with given arguments.
175 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
176 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000177 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100178 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000179 for (size_t k = 0; k < profiles_fd.size(); k++) {
180 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
181 }
182 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
183
184 std::string error;
185 return ExecAndReturnCode(argv_str, &error);
186 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100187
188 bool GenerateTestProfile(const std::string& filename) {
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("--generate-test-profile=" + filename);
193 std::string error;
194 return ExecAndReturnCode(argv_str, &error);
195 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800196
Jeff Haof0a31f82017-03-27 15:50:37 -0700197 bool GenerateTestProfileWithInputDex(const std::string& filename) {
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("--generate-test-profile=" + filename);
202 argv_str.push_back("--generate-test-profile-seed=0");
203 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
204 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
205 std::string error;
206 return ExecAndReturnCode(argv_str, &error);
207 }
208
Calin Juravlee0ac1152017-02-13 19:03:47 -0800209 bool CreateProfile(std::string profile_file_contents,
210 const std::string& filename,
211 const std::string& dex_location) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800212 ScratchFile class_names_file;
213 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800214 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800215 EXPECT_EQ(0, file->Flush());
216 EXPECT_TRUE(file->ResetOffset());
217 std::string profman_cmd = GetProfmanCmd();
218 std::vector<std::string> argv_str;
219 argv_str.push_back(profman_cmd);
220 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
221 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800222 argv_str.push_back("--apk=" + dex_location);
223 argv_str.push_back("--dex-location=" + dex_location);
David Sehr7c80f2d2017-02-07 16:47:58 -0800224 std::string error;
225 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
226 return true;
227 }
228
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700229 bool RunProfman(const std::string& filename,
230 std::vector<std::string>& extra_args,
231 std::string* output) {
232 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800233 std::string profman_cmd = GetProfmanCmd();
234 std::vector<std::string> argv_str;
235 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700236 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800237 argv_str.push_back("--profile-file=" + filename);
238 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800239 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700240 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800241 std::string error;
242 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700243 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800244 EXPECT_EQ(0, file->Flush());
245 EXPECT_TRUE(file->ResetOffset());
246 int64_t length = file->GetLength();
247 std::unique_ptr<char[]> buf(new char[length]);
248 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700249 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800250 return true;
251 }
252
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700253 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
254 std::vector<std::string> extra_args;
255 extra_args.push_back("--dump-classes-and-methods");
256 return RunProfman(filename, extra_args, file_contents);
257 }
258
259 bool DumpOnly(const std::string& filename, std::string* file_contents) {
260 std::vector<std::string> extra_args;
261 extra_args.push_back("--dump-only");
262 return RunProfman(filename, extra_args, file_contents);
263 }
264
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700265 bool CreateAndDump(const std::string& input_file_contents,
266 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800267 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800268 EXPECT_TRUE(CreateProfile(input_file_contents,
269 profile_file.GetFilename(),
270 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800271 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700272 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800273 return true;
274 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800275
276 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
277 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
278 Thread* self = Thread::Current();
279 ScopedObjectAccess soa(self);
280 StackHandleScope<1> hs(self);
281 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700282 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800283 return class_linker->FindClass(self, clazz.c_str(), h_loader);
284 }
285
286 ArtMethod* GetVirtualMethod(jobject class_loader,
287 const std::string& clazz,
288 const std::string& name) {
289 mirror::Class* klass = GetClass(class_loader, clazz);
290 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
291 const auto pointer_size = class_linker->GetImagePointerSize();
292 ArtMethod* method = nullptr;
293 Thread* self = Thread::Current();
294 ScopedObjectAccess soa(self);
295 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
296 if (name == m.GetName()) {
297 EXPECT_TRUE(method == nullptr);
298 method = &m;
299 }
300 }
301 return method;
302 }
303
304 // Verify that given method has the expected inline caches and nothing else.
305 void AssertInlineCaches(ArtMethod* method,
306 const std::set<mirror::Class*>& expected_clases,
307 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800308 bool is_megamorphic,
309 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800310 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700311 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
312 info.GetMethod(method->GetDexFile()->GetLocation(),
313 method->GetDexFile()->GetLocationChecksum(),
314 method->GetDexMethodIndex());
315 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700316 ASSERT_EQ(pmi->inline_caches->size(), 1u);
317 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800318
Calin Juravle589e71e2017-03-03 16:05:05 -0800319 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
320 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800321 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
322 size_t found = 0;
323 for (mirror::Class* it : expected_clases) {
324 for (const auto& class_ref : dex_pc_data.classes) {
325 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700326 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800327 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
328 class_ref.type_index == it->GetDexTypeIndex()) {
329 found++;
330 }
331 }
332 }
333
334 ASSERT_EQ(expected_clases.size(), found);
335 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700336
337 std::unique_ptr<ArenaAllocator> arena_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700338
339 // Cache of inline caches generated during tests.
340 // This makes it easier to pass data between different utilities and ensure that
341 // caches are destructed at the end of the test.
342 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000343};
344
345TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
346 ScratchFile profile1;
347 ScratchFile profile2;
348 ScratchFile reference_profile;
349
350 std::vector<int> profile_fds({
351 GetFd(profile1),
352 GetFd(profile2)});
353 int reference_profile_fd = GetFd(reference_profile);
354
355 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
356 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100357 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000358 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100359 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000360
361 // We should advise compilation.
362 ASSERT_EQ(ProfileAssistant::kCompile,
363 ProcessProfiles(profile_fds, reference_profile_fd));
364 // The resulting compilation info must be equal to the merge of the inputs.
365 ProfileCompilationInfo result;
366 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
367 ASSERT_TRUE(result.Load(reference_profile_fd));
368
369 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000370 ASSERT_TRUE(expected.MergeWith(info1));
371 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000372 ASSERT_TRUE(expected.Equals(result));
373
374 // The information from profiles must remain the same.
375 CheckProfileInfo(profile1, info1);
376 CheckProfileInfo(profile2, info2);
377}
378
Calin Juravlec824b512016-03-29 20:33:33 +0100379// TODO(calin): Add more tests for classes.
380TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
381 ScratchFile profile1;
382 ScratchFile reference_profile;
383
384 std::vector<int> profile_fds({
385 GetFd(profile1)});
386 int reference_profile_fd = GetFd(reference_profile);
387
388 const uint16_t kNumberOfClassesToEnableCompilation = 100;
389 ProfileCompilationInfo info1;
390 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
391
392 // We should advise compilation.
393 ASSERT_EQ(ProfileAssistant::kCompile,
394 ProcessProfiles(profile_fds, reference_profile_fd));
395 // The resulting compilation info must be equal to the merge of the inputs.
396 ProfileCompilationInfo result;
397 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
398 ASSERT_TRUE(result.Load(reference_profile_fd));
399
400 ProfileCompilationInfo expected;
401 ASSERT_TRUE(expected.MergeWith(info1));
402 ASSERT_TRUE(expected.Equals(result));
403
404 // The information from profiles must remain the same.
405 CheckProfileInfo(profile1, info1);
406}
407
Calin Juravle2e2db782016-02-23 12:00:03 +0000408TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
409 ScratchFile profile1;
410 ScratchFile profile2;
411 ScratchFile reference_profile;
412
413 std::vector<int> profile_fds({
414 GetFd(profile1),
415 GetFd(profile2)});
416 int reference_profile_fd = GetFd(reference_profile);
417
418 // The new profile info will contain the methods with indices 0-100.
419 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
420 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100421 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000422 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100423 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000424
425
426 // The reference profile info will contain the methods with indices 50-150.
427 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
428 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100429 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000430 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
431
432 // We should advise compilation.
433 ASSERT_EQ(ProfileAssistant::kCompile,
434 ProcessProfiles(profile_fds, reference_profile_fd));
435
436 // The resulting compilation info must be equal to the merge of the inputs
437 ProfileCompilationInfo result;
438 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
439 ASSERT_TRUE(result.Load(reference_profile_fd));
440
441 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000442 ASSERT_TRUE(expected.MergeWith(info1));
443 ASSERT_TRUE(expected.MergeWith(info2));
444 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000445 ASSERT_TRUE(expected.Equals(result));
446
447 // The information from profiles must remain the same.
448 CheckProfileInfo(profile1, info1);
449 CheckProfileInfo(profile2, info2);
450}
451
452TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
453 ScratchFile profile1;
454 ScratchFile profile2;
455 ScratchFile reference_profile;
456
457 std::vector<int> profile_fds({
458 GetFd(profile1),
459 GetFd(profile2)});
460 int reference_profile_fd = GetFd(reference_profile);
461
462 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
463 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100464 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000465 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100466 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000467
468 // We should not advise compilation.
469 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
470 ProcessProfiles(profile_fds, reference_profile_fd));
471
472 // The information from profiles must remain the same.
473 ProfileCompilationInfo file_info1;
474 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
475 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
476 ASSERT_TRUE(file_info1.Equals(info1));
477
478 ProfileCompilationInfo file_info2;
479 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
480 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
481 ASSERT_TRUE(file_info2.Equals(info2));
482
483 // Reference profile files must remain empty.
484 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
485
486 // The information from profiles must remain the same.
487 CheckProfileInfo(profile1, info1);
488 CheckProfileInfo(profile2, info2);
489}
490
491TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
492 ScratchFile profile1;
493 ScratchFile profile2;
494 ScratchFile reference_profile;
495
496 std::vector<int> profile_fds({
497 GetFd(profile1),
498 GetFd(profile2)});
499 int reference_profile_fd = GetFd(reference_profile);
500
501 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
502 // Assign different hashes for the same dex file. This will make merging of information to fail.
503 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100504 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000505 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100506 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000507
508 // We should fail processing.
509 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
510 ProcessProfiles(profile_fds, reference_profile_fd));
511
512 // The information from profiles must remain the same.
513 CheckProfileInfo(profile1, info1);
514 CheckProfileInfo(profile2, info2);
515
516 // Reference profile files must still remain empty.
517 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
518}
519
520TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
521 ScratchFile profile1;
522 ScratchFile reference_profile;
523
524 std::vector<int> profile_fds({
525 GetFd(profile1)});
526 int reference_profile_fd = GetFd(reference_profile);
527
528 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
529 // Assign different hashes for the same dex file. This will make merging of information to fail.
530 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100531 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000532 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100533 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000534
535 // We should not advise compilation.
536 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
537 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
538 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
539 ProcessProfiles(profile_fds, reference_profile_fd));
540
541 // The information from profiles must remain the same.
542 CheckProfileInfo(profile1, info1);
543}
544
Calin Juravle7bcdb532016-06-07 16:14:47 +0100545TEST_F(ProfileAssistantTest, TestProfileGeneration) {
546 ScratchFile profile;
547 // Generate a test profile.
548 GenerateTestProfile(profile.GetFilename());
549
550 // Verify that the generated profile is valid and can be loaded.
551 ASSERT_TRUE(profile.GetFile()->ResetOffset());
552 ProfileCompilationInfo info;
553 ASSERT_TRUE(info.Load(GetFd(profile)));
554}
555
Jeff Haof0a31f82017-03-27 15:50:37 -0700556TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
557 ScratchFile profile;
558 // Generate a test profile passing in a dex file as reference.
559 GenerateTestProfileWithInputDex(profile.GetFilename());
560
561 // Verify that the generated profile is valid and can be loaded.
562 ASSERT_TRUE(profile.GetFile()->ResetOffset());
563 ProfileCompilationInfo info;
564 ASSERT_TRUE(info.Load(GetFd(profile)));
565}
566
David Sehr7c80f2d2017-02-07 16:47:58 -0800567TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
568 // Class names put here need to be in sorted order.
569 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700570 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800571 "Ljava/lang/Comparable;",
572 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700573 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700574 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800575 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700576 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800577 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700578 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800579 }
580 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700581 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
582 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800583}
584
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700585TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
586 // Class names put here need to be in sorted order.
587 std::vector<std::string> class_names = {
588 "Ljava/lang/Math;->*",
589 };
590 std::string input_file_contents;
591 std::string expected_contents;
592 for (std::string& class_name : class_names) {
593 input_file_contents += class_name + std::string("\n");
594 expected_contents += DescriptorToDot(class_name.c_str()) +
595 std::string("\n");
596 }
597 std::string output_file_contents;
598 ScratchFile profile_file;
599 EXPECT_TRUE(CreateProfile(input_file_contents,
600 profile_file.GetFilename(),
601 GetLibCoreDexFileNames()[0]));
602 ProfileCompilationInfo info;
603 profile_file.GetFile()->ResetOffset();
604 ASSERT_TRUE(info.Load(GetFd(profile_file)));
605 // Verify that the profile has matching methods.
606 ScopedObjectAccess soa(Thread::Current());
607 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
608 ASSERT_TRUE(klass != nullptr);
609 size_t method_count = 0;
610 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
611 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
612 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700613 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
614 info.GetMethod(method.GetDexFile()->GetLocation(),
615 method.GetDexFile()->GetLocationChecksum(),
616 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700617 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700618 }
619 }
620 EXPECT_GT(method_count, 0u);
621}
622
David Sehr7c80f2d2017-02-07 16:47:58 -0800623TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
624 // Class names put here need to be in sorted order.
625 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800626 "Ldoesnt/match/this/one;",
627 "Ljava/lang/Comparable;",
628 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800629 };
630 std::string input_file_contents;
631 for (std::string& class_name : class_names) {
632 input_file_contents += class_name + std::string("\n");
633 }
634 std::string output_file_contents;
635 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
636 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700637 class_names[1] + std::string("\n") +
638 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800639 ASSERT_EQ(output_file_contents, expected_contents);
640}
641
642TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
643 // Class names put here need to be in sorted order.
644 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800645 "Ldoesnt/match/this/one;",
646 "Ldoesnt/match/this/one/either;",
647 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800648 };
649 std::string input_file_contents;
650 for (std::string& class_name : class_names) {
651 input_file_contents += class_name + std::string("\n");
652 }
653 std::string output_file_contents;
654 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
655 std::string expected_contents("");
656 ASSERT_EQ(output_file_contents, expected_contents);
657}
658
Calin Juravlee0ac1152017-02-13 19:03:47 -0800659TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
660 // Create the profile content.
661 std::vector<std::string> methods = {
662 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
663 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
664 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800665 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800666 "LTestInline;->noInlineCache(LSuper;)I"
667 };
668 std::string input_file_contents;
669 for (std::string& m : methods) {
670 input_file_contents += m + std::string("\n");
671 }
672
673 // Create the profile and save it to disk.
674 ScratchFile profile_file;
675 ASSERT_TRUE(CreateProfile(input_file_contents,
676 profile_file.GetFilename(),
677 GetTestDexFileName("ProfileTestMultiDex")));
678
679 // Load the profile from disk.
680 ProfileCompilationInfo info;
681 profile_file.GetFile()->ResetOffset();
682 ASSERT_TRUE(info.Load(GetFd(profile_file)));
683
684 // Load the dex files and verify that the profile contains the expected methods info.
685 ScopedObjectAccess soa(Thread::Current());
686 jobject class_loader = LoadDex("ProfileTestMultiDex");
687 ASSERT_NE(class_loader, nullptr);
688
689 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
690 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
691 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
692
693 ASSERT_TRUE(sub_a != nullptr);
694 ASSERT_TRUE(sub_b != nullptr);
695 ASSERT_TRUE(sub_c != nullptr);
696
697 {
698 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
699 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
700 "LTestInline;",
701 "inlineMonomorphic");
702 ASSERT_TRUE(inline_monomorphic != nullptr);
703 std::set<mirror::Class*> expected_monomorphic;
704 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800705 AssertInlineCaches(inline_monomorphic,
706 expected_monomorphic,
707 info,
708 /*megamorphic*/false,
709 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800710 }
711
712 {
713 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
714 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
715 "LTestInline;",
716 "inlinePolymorphic");
717 ASSERT_TRUE(inline_polymorhic != nullptr);
718 std::set<mirror::Class*> expected_polymorphic;
719 expected_polymorphic.insert(sub_a);
720 expected_polymorphic.insert(sub_b);
721 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800722 AssertInlineCaches(inline_polymorhic,
723 expected_polymorphic,
724 info,
725 /*megamorphic*/false,
726 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800727 }
728
729 {
730 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
731 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
732 "LTestInline;",
733 "inlineMegamorphic");
734 ASSERT_TRUE(inline_megamorphic != nullptr);
735 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800736 AssertInlineCaches(inline_megamorphic,
737 expected_megamorphic,
738 info,
739 /*megamorphic*/true,
740 /*missing_types*/false);
741 }
742
743 {
744 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
745 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
746 "LTestInline;",
747 "inlineMissingTypes");
748 ASSERT_TRUE(inline_missing_types != nullptr);
749 std::set<mirror::Class*> expected_missing_Types;
750 AssertInlineCaches(inline_missing_types,
751 expected_missing_Types,
752 info,
753 /*megamorphic*/false,
754 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800755 }
756
757 {
758 // Verify that method noInlineCache has no inline caches in the profile.
759 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
760 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700761 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
762 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
763 no_inline_cache->GetDexFile()->GetLocationChecksum(),
764 no_inline_cache->GetDexMethodIndex());
765 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700766 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800767 }
768}
769
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700770TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
771 ScratchFile profile1;
772 ScratchFile reference_profile;
773
774 std::vector<int> profile_fds({GetFd(profile1)});
775 int reference_profile_fd = GetFd(reference_profile);
776
777 // The new profile info will contain the methods with indices 0-100.
778 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
779 ProfileCompilationInfo info1;
780 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
781 /*start_method_index*/0, /*reverse_dex_write_order*/false);
782
783 // The reference profile info will contain the methods with indices 50-150.
784 // When setting up the profile reverse the order in which the dex files
785 // are added to the profile. This will verify that profman merges profiles
786 // with a different dex order correctly.
787 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
788 ProfileCompilationInfo reference_info;
789 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
790 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
791
792 // We should advise compilation.
793 ASSERT_EQ(ProfileAssistant::kCompile,
794 ProcessProfiles(profile_fds, reference_profile_fd));
795
796 // The resulting compilation info must be equal to the merge of the inputs.
797 ProfileCompilationInfo result;
798 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
799 ASSERT_TRUE(result.Load(reference_profile_fd));
800
801 ProfileCompilationInfo expected;
802 ASSERT_TRUE(expected.MergeWith(reference_info));
803 ASSERT_TRUE(expected.MergeWith(info1));
804 ASSERT_TRUE(expected.Equals(result));
805
806 // The information from profile must remain the same.
807 CheckProfileInfo(profile1, info1);
808}
809
Calin Juravle08556882017-05-26 16:40:45 -0700810TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
811 // Create the profile content.
812 std::vector<std::string> profile_methods = {
813 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
814 "LTestInline;->invalid_method",
815 "invalid_class"
816 };
817 std::string input_file_contents;
818 for (std::string& m : profile_methods) {
819 input_file_contents += m + std::string("\n");
820 }
821
822 // Create the profile and save it to disk.
823 ScratchFile profile_file;
824 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
825 ASSERT_TRUE(CreateProfile(input_file_contents,
826 profile_file.GetFilename(),
827 dex_filename));
828
829 // Load the profile from disk.
830 ProfileCompilationInfo info;
831 profile_file.GetFile()->ResetOffset();
832 ASSERT_TRUE(info.Load(GetFd(profile_file)));
833
834 // Load the dex files and verify that the profile contains the expected methods info.
835 ScopedObjectAccess soa(Thread::Current());
836 jobject class_loader = LoadDex("ProfileTestMultiDex");
837 ASSERT_NE(class_loader, nullptr);
838
839 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
840 "LTestInline;",
841 "inlineMonomorphic");
842 const DexFile* dex_file = inline_monomorphic->GetDexFile();
843
844 // Verify that the inline cache contains the invalid type.
845 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
846 info.GetMethod(dex_file->GetLocation(),
847 dex_file->GetLocationChecksum(),
848 inline_monomorphic->GetDexMethodIndex());
849 ASSERT_TRUE(pmi != nullptr);
850 ASSERT_EQ(pmi->inline_caches->size(), 1u);
851 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
852 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
853 ASSERT_EQ(1u, dex_pc_data.classes.size());
854 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
855
856 // Verify that the start-up classes contain the invalid class.
857 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -0700858 std::set<uint16_t> hot_methods;
859 std::set<uint16_t> startup_methods;
860 std::set<uint16_t> post_start_methods;
861 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
862 &classes,
863 &hot_methods,
864 &startup_methods,
865 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -0700866 ASSERT_EQ(1u, classes.size());
867 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
868
869 // Verify that the invalid method is in the profile.
Mathieu Chartierea650f32017-05-24 12:04:13 -0700870 ASSERT_EQ(2u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -0700871 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Mathieu Chartierea650f32017-05-24 12:04:13 -0700872 ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -0700873}
874
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700875TEST_F(ProfileAssistantTest, DumpOnly) {
876 ScratchFile profile;
877
878 const uint32_t kNumberOfMethods = 64;
879 std::vector<uint32_t> hot_methods;
880 std::vector<uint32_t> startup_methods;
881 std::vector<uint32_t> post_startup_methods;
882 for (size_t i = 0; i < kNumberOfMethods; ++i) {
883 if (i % 2 == 0) {
884 hot_methods.push_back(i);
885 }
886 if (i % 3 == 1) {
887 startup_methods.push_back(i);
888 }
889 if (i % 4 == 2) {
890 post_startup_methods.push_back(i);
891 }
892 }
893 EXPECT_GT(hot_methods.size(), 0u);
894 EXPECT_GT(startup_methods.size(), 0u);
895 EXPECT_GT(post_startup_methods.size(), 0u);
896 ProfileCompilationInfo info1;
897 SetupBasicProfile("p1",
898 1,
899 kNumberOfMethods,
900 hot_methods,
901 startup_methods,
902 post_startup_methods,
903 profile,
904 &info1);
905 std::string output;
906 DumpOnly(profile.GetFilename(), &output);
907 const size_t hot_offset = output.find("hot methods:");
908 const size_t startup_offset = output.find("startup methods:");
909 const size_t post_startup_offset = output.find("post startup methods:");
910 const size_t classes_offset = output.find("classes:");
911 ASSERT_NE(hot_offset, std::string::npos);
912 ASSERT_NE(startup_offset, std::string::npos);
913 ASSERT_NE(post_startup_offset, std::string::npos);
914 ASSERT_LT(hot_offset, startup_offset);
915 ASSERT_LT(startup_offset, post_startup_offset);
916 // Check the actual contents of the dump by looking at the offsets of the methods.
917 for (uint32_t m : hot_methods) {
918 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
919 ASSERT_NE(pos, std::string::npos);
920 EXPECT_LT(pos, startup_offset);
921 }
922 for (uint32_t m : startup_methods) {
923 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
924 ASSERT_NE(pos, std::string::npos);
925 EXPECT_LT(pos, post_startup_offset);
926 }
927 for (uint32_t m : post_startup_methods) {
928 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
929 ASSERT_NE(pos, std::string::npos);
930 EXPECT_LT(pos, classes_offset);
931 }
932}
933
Calin Juravle2e2db782016-02-23 12:00:03 +0000934} // namespace art