blob: c75f3e9688f54a64d9bda916a481333518484e16 [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 {
Vladimir Marko69d310e2017-10-09 14:12:23 +010038 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
Calin Juravlecc3171a2017-05-19 16:47:53 -070039 }
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(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100111 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700112 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++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100125 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.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++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100131 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.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++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100139 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.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++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100145 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.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 }
Mathieu Chartierf70fe3d2017-06-21 15:24:02 -0700174
Calin Juravle7bcdb532016-06-07 16:14:47 +0100175 // Runs test with given arguments.
176 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
177 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000178 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100179 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000180 for (size_t k = 0; k < profiles_fd.size(); k++) {
181 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
182 }
183 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
184
185 std::string error;
186 return ExecAndReturnCode(argv_str, &error);
187 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100188
189 bool GenerateTestProfile(const std::string& filename) {
190 std::string profman_cmd = GetProfmanCmd();
191 std::vector<std::string> argv_str;
192 argv_str.push_back(profman_cmd);
193 argv_str.push_back("--generate-test-profile=" + filename);
194 std::string error;
195 return ExecAndReturnCode(argv_str, &error);
196 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800197
Jeff Haof0a31f82017-03-27 15:50:37 -0700198 bool GenerateTestProfileWithInputDex(const std::string& filename) {
199 std::string profman_cmd = GetProfmanCmd();
200 std::vector<std::string> argv_str;
201 argv_str.push_back(profman_cmd);
202 argv_str.push_back("--generate-test-profile=" + filename);
203 argv_str.push_back("--generate-test-profile-seed=0");
204 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
205 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
206 std::string error;
207 return ExecAndReturnCode(argv_str, &error);
208 }
209
Andreas Gampe641a4732017-08-24 13:21:35 -0700210 bool CreateProfile(const std::string& profile_file_contents,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800211 const std::string& filename,
David Brazdilf13ac7c2018-01-30 10:09:08 +0000212 const std::string& dex_location,
213 bool skip_verification) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800214 ScratchFile class_names_file;
215 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800216 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800217 EXPECT_EQ(0, file->Flush());
218 EXPECT_TRUE(file->ResetOffset());
219 std::string profman_cmd = GetProfmanCmd();
220 std::vector<std::string> argv_str;
221 argv_str.push_back(profman_cmd);
222 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
223 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800224 argv_str.push_back("--apk=" + dex_location);
225 argv_str.push_back("--dex-location=" + dex_location);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000226 if (skip_verification) {
227 argv_str.push_back("--skip-apk-verification");
228 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800229 std::string error;
230 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
231 return true;
232 }
233
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700234 bool RunProfman(const std::string& filename,
235 std::vector<std::string>& extra_args,
236 std::string* output) {
237 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800238 std::string profman_cmd = GetProfmanCmd();
239 std::vector<std::string> argv_str;
240 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700241 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800242 argv_str.push_back("--profile-file=" + filename);
243 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800244 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000245 argv_str.push_back("--skip-apk-verification");
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700246 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800247 std::string error;
248 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700249 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800250 EXPECT_EQ(0, file->Flush());
251 EXPECT_TRUE(file->ResetOffset());
252 int64_t length = file->GetLength();
253 std::unique_ptr<char[]> buf(new char[length]);
254 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700255 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800256 return true;
257 }
258
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700259 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
260 std::vector<std::string> extra_args;
261 extra_args.push_back("--dump-classes-and-methods");
262 return RunProfman(filename, extra_args, file_contents);
263 }
264
265 bool DumpOnly(const std::string& filename, std::string* file_contents) {
266 std::vector<std::string> extra_args;
267 extra_args.push_back("--dump-only");
268 return RunProfman(filename, extra_args, file_contents);
269 }
270
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700271 bool CreateAndDump(const std::string& input_file_contents,
272 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800273 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800274 EXPECT_TRUE(CreateProfile(input_file_contents,
275 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000276 GetLibCoreDexFileNames()[0],
277 /* skip_verification */ true));
David Sehr7c80f2d2017-02-07 16:47:58 -0800278 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700279 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800280 return true;
281 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800282
283 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
284 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
285 Thread* self = Thread::Current();
286 ScopedObjectAccess soa(self);
287 StackHandleScope<1> hs(self);
288 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700289 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800290 return class_linker->FindClass(self, clazz.c_str(), h_loader);
291 }
292
293 ArtMethod* GetVirtualMethod(jobject class_loader,
294 const std::string& clazz,
295 const std::string& name) {
296 mirror::Class* klass = GetClass(class_loader, clazz);
297 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
298 const auto pointer_size = class_linker->GetImagePointerSize();
299 ArtMethod* method = nullptr;
300 Thread* self = Thread::Current();
301 ScopedObjectAccess soa(self);
302 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
303 if (name == m.GetName()) {
304 EXPECT_TRUE(method == nullptr);
305 method = &m;
306 }
307 }
308 return method;
309 }
310
311 // Verify that given method has the expected inline caches and nothing else.
312 void AssertInlineCaches(ArtMethod* method,
313 const std::set<mirror::Class*>& expected_clases,
314 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800315 bool is_megamorphic,
316 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800317 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700318 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
319 info.GetMethod(method->GetDexFile()->GetLocation(),
320 method->GetDexFile()->GetLocationChecksum(),
321 method->GetDexMethodIndex());
322 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700323 ASSERT_EQ(pmi->inline_caches->size(), 1u);
324 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800325
Calin Juravle589e71e2017-03-03 16:05:05 -0800326 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
327 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800328 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
329 size_t found = 0;
330 for (mirror::Class* it : expected_clases) {
331 for (const auto& class_ref : dex_pc_data.classes) {
332 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700333 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800334 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
335 class_ref.type_index == it->GetDexTypeIndex()) {
336 found++;
337 }
338 }
339 }
340
341 ASSERT_EQ(expected_clases.size(), found);
342 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700343
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700344 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
345 uint16_t methods_in_ref_profile) {
346 ScratchFile profile;
347 ScratchFile reference_profile;
348 std::vector<int> profile_fds({ GetFd(profile)});
349 int reference_profile_fd = GetFd(reference_profile);
350 std::vector<uint32_t> hot_methods_cur;
351 std::vector<uint32_t> hot_methods_ref;
352 std::vector<uint32_t> empty_vector;
353 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
354 hot_methods_cur.push_back(i);
355 }
356 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
357 hot_methods_ref.push_back(i);
358 }
359 ProfileCompilationInfo info1;
360 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
361 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
362 profile, &info1);
363 ProfileCompilationInfo info2;
364 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
365 reference_profile, &info2);
366 return ProcessProfiles(profile_fds, reference_profile_fd);
367 }
368
369 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
370 uint16_t classes_in_ref_profile) {
371 ScratchFile profile;
372 ScratchFile reference_profile;
373
374 std::vector<int> profile_fds({ GetFd(profile)});
375 int reference_profile_fd = GetFd(reference_profile);
376
377 ProfileCompilationInfo info1;
378 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
379 ProfileCompilationInfo info2;
380 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
381 return ProcessProfiles(profile_fds, reference_profile_fd);
382 }
383
Vladimir Marko69d310e2017-10-09 14:12:23 +0100384 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700385
386 // Cache of inline caches generated during tests.
387 // This makes it easier to pass data between different utilities and ensure that
388 // caches are destructed at the end of the test.
389 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000390};
391
392TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
393 ScratchFile profile1;
394 ScratchFile profile2;
395 ScratchFile reference_profile;
396
397 std::vector<int> profile_fds({
398 GetFd(profile1),
399 GetFd(profile2)});
400 int reference_profile_fd = GetFd(reference_profile);
401
402 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
403 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100404 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000405 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100406 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000407
408 // We should advise compilation.
409 ASSERT_EQ(ProfileAssistant::kCompile,
410 ProcessProfiles(profile_fds, reference_profile_fd));
411 // The resulting compilation info must be equal to the merge of the inputs.
412 ProfileCompilationInfo result;
413 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
414 ASSERT_TRUE(result.Load(reference_profile_fd));
415
416 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000417 ASSERT_TRUE(expected.MergeWith(info1));
418 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000419 ASSERT_TRUE(expected.Equals(result));
420
421 // The information from profiles must remain the same.
422 CheckProfileInfo(profile1, info1);
423 CheckProfileInfo(profile2, info2);
424}
425
Calin Juravlec824b512016-03-29 20:33:33 +0100426// TODO(calin): Add more tests for classes.
427TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
428 ScratchFile profile1;
429 ScratchFile reference_profile;
430
431 std::vector<int> profile_fds({
432 GetFd(profile1)});
433 int reference_profile_fd = GetFd(reference_profile);
434
435 const uint16_t kNumberOfClassesToEnableCompilation = 100;
436 ProfileCompilationInfo info1;
437 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
438
439 // We should advise compilation.
440 ASSERT_EQ(ProfileAssistant::kCompile,
441 ProcessProfiles(profile_fds, reference_profile_fd));
442 // The resulting compilation info must be equal to the merge of the inputs.
443 ProfileCompilationInfo result;
444 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
445 ASSERT_TRUE(result.Load(reference_profile_fd));
446
447 ProfileCompilationInfo expected;
448 ASSERT_TRUE(expected.MergeWith(info1));
449 ASSERT_TRUE(expected.Equals(result));
450
451 // The information from profiles must remain the same.
452 CheckProfileInfo(profile1, info1);
453}
454
Calin Juravle2e2db782016-02-23 12:00:03 +0000455TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
456 ScratchFile profile1;
457 ScratchFile profile2;
458 ScratchFile reference_profile;
459
460 std::vector<int> profile_fds({
461 GetFd(profile1),
462 GetFd(profile2)});
463 int reference_profile_fd = GetFd(reference_profile);
464
465 // The new profile info will contain the methods with indices 0-100.
466 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
467 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100468 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000469 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100470 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000471
472
473 // The reference profile info will contain the methods with indices 50-150.
474 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
475 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100476 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000477 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
478
479 // We should advise compilation.
480 ASSERT_EQ(ProfileAssistant::kCompile,
481 ProcessProfiles(profile_fds, reference_profile_fd));
482
483 // The resulting compilation info must be equal to the merge of the inputs
484 ProfileCompilationInfo result;
485 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
486 ASSERT_TRUE(result.Load(reference_profile_fd));
487
488 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000489 ASSERT_TRUE(expected.MergeWith(info1));
490 ASSERT_TRUE(expected.MergeWith(info2));
491 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000492 ASSERT_TRUE(expected.Equals(result));
493
494 // The information from profiles must remain the same.
495 CheckProfileInfo(profile1, info1);
496 CheckProfileInfo(profile2, info2);
497}
498
499TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
500 ScratchFile profile1;
501 ScratchFile profile2;
502 ScratchFile reference_profile;
503
504 std::vector<int> profile_fds({
505 GetFd(profile1),
506 GetFd(profile2)});
507 int reference_profile_fd = GetFd(reference_profile);
508
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700509 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000510 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100511 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000512 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100513 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000514
515 // We should not advise compilation.
516 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
517 ProcessProfiles(profile_fds, reference_profile_fd));
518
519 // The information from profiles must remain the same.
520 ProfileCompilationInfo file_info1;
521 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
522 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
523 ASSERT_TRUE(file_info1.Equals(info1));
524
525 ProfileCompilationInfo file_info2;
526 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
527 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
528 ASSERT_TRUE(file_info2.Equals(info2));
529
530 // Reference profile files must remain empty.
531 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
532
533 // The information from profiles must remain the same.
534 CheckProfileInfo(profile1, info1);
535 CheckProfileInfo(profile2, info2);
536}
537
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700538TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
539 const uint16_t kNumberOfMethodsInRefProfile = 6000;
540 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
541 // We should not advise compilation.
542 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
543 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
544 kNumberOfMethodsInRefProfile));
545}
546
547TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
548 const uint16_t kNumberOfMethodsInRefProfile = 6000;
549 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
550 // We should advise compilation.
551 ASSERT_EQ(ProfileAssistant::kCompile,
552 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
553 kNumberOfMethodsInRefProfile));
554}
555
556TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
557 const uint16_t kNumberOfClassesInRefProfile = 6000;
558 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
559 // We should not advise compilation.
560 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
561 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
562 kNumberOfClassesInRefProfile));
563}
564
565TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
566 const uint16_t kNumberOfClassesInRefProfile = 6000;
567 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
568 // We should advise compilation.
569 ASSERT_EQ(ProfileAssistant::kCompile,
570 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
571 kNumberOfClassesInRefProfile));
572}
573
Calin Juravle2e2db782016-02-23 12:00:03 +0000574TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
575 ScratchFile profile1;
576 ScratchFile profile2;
577 ScratchFile reference_profile;
578
579 std::vector<int> profile_fds({
580 GetFd(profile1),
581 GetFd(profile2)});
582 int reference_profile_fd = GetFd(reference_profile);
583
584 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
585 // Assign different hashes for the same dex file. This will make merging of information to fail.
586 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100587 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000588 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100589 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000590
591 // We should fail processing.
592 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
593 ProcessProfiles(profile_fds, reference_profile_fd));
594
595 // The information from profiles must remain the same.
596 CheckProfileInfo(profile1, info1);
597 CheckProfileInfo(profile2, info2);
598
599 // Reference profile files must still remain empty.
600 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
601}
602
603TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
604 ScratchFile profile1;
605 ScratchFile reference_profile;
606
607 std::vector<int> profile_fds({
608 GetFd(profile1)});
609 int reference_profile_fd = GetFd(reference_profile);
610
611 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
612 // Assign different hashes for the same dex file. This will make merging of information to fail.
613 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100614 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000615 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100616 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000617
618 // We should not advise compilation.
619 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
620 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
621 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
622 ProcessProfiles(profile_fds, reference_profile_fd));
623
624 // The information from profiles must remain the same.
625 CheckProfileInfo(profile1, info1);
626}
627
Calin Juravle7bcdb532016-06-07 16:14:47 +0100628TEST_F(ProfileAssistantTest, TestProfileGeneration) {
629 ScratchFile profile;
630 // Generate a test profile.
631 GenerateTestProfile(profile.GetFilename());
632
633 // Verify that the generated profile is valid and can be loaded.
634 ASSERT_TRUE(profile.GetFile()->ResetOffset());
635 ProfileCompilationInfo info;
636 ASSERT_TRUE(info.Load(GetFd(profile)));
637}
638
Jeff Haof0a31f82017-03-27 15:50:37 -0700639TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
640 ScratchFile profile;
641 // Generate a test profile passing in a dex file as reference.
642 GenerateTestProfileWithInputDex(profile.GetFilename());
643
644 // Verify that the generated profile is valid and can be loaded.
645 ASSERT_TRUE(profile.GetFile()->ResetOffset());
646 ProfileCompilationInfo info;
647 ASSERT_TRUE(info.Load(GetFd(profile)));
648}
649
David Sehr7c80f2d2017-02-07 16:47:58 -0800650TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
651 // Class names put here need to be in sorted order.
652 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700653 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800654 "Ljava/lang/Comparable;",
655 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700656 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700657 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800658 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700659 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800660 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700661 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800662 }
663 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700664 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
665 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800666}
667
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700668TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
669 // Class names put here need to be in sorted order.
670 std::vector<std::string> class_names = {
671 "Ljava/lang/Math;->*",
672 };
673 std::string input_file_contents;
674 std::string expected_contents;
675 for (std::string& class_name : class_names) {
676 input_file_contents += class_name + std::string("\n");
677 expected_contents += DescriptorToDot(class_name.c_str()) +
678 std::string("\n");
679 }
680 std::string output_file_contents;
681 ScratchFile profile_file;
682 EXPECT_TRUE(CreateProfile(input_file_contents,
683 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000684 GetLibCoreDexFileNames()[0],
685 /* skip_verification */ true));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700686 ProfileCompilationInfo info;
687 profile_file.GetFile()->ResetOffset();
688 ASSERT_TRUE(info.Load(GetFd(profile_file)));
689 // Verify that the profile has matching methods.
690 ScopedObjectAccess soa(Thread::Current());
691 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
692 ASSERT_TRUE(klass != nullptr);
693 size_t method_count = 0;
694 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
695 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
696 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700697 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
698 info.GetMethod(method.GetDexFile()->GetLocation(),
699 method.GetDexFile()->GetLocationChecksum(),
700 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700701 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700702 }
703 }
704 EXPECT_GT(method_count, 0u);
705}
706
Mathieu Chartier2f794552017-06-19 10:58:08 -0700707TEST_F(ProfileAssistantTest, TestBootImageProfile) {
708 const std::string core_dex = GetLibCoreDexFileNames()[0];
709
710 std::vector<ScratchFile> profiles;
711
712 // In image with enough clean occurrences.
713 const std::string kCleanClass = "Ljava/lang/CharSequence;";
714 // In image with enough dirty occurrences.
715 const std::string kDirtyClass = "Ljava/lang/Object;";
716 // Not in image becauseof not enough occurrences.
717 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
718 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
719 // Method that is hot.
720 // Also adds the class through inference since it is in each dex.
721 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
722 // Method that doesn't add the class since its only in one profile. Should still show up in the
723 // boot profile.
724 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700725 // Method that gets marked as hot since it's in multiple profiles.
726 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700727
728 // Thresholds for this test.
729 static const size_t kDirtyThreshold = 3;
730 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700731 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700732
733 // Create a bunch of boot profiles.
734 std::string dex1 =
735 kCleanClass + "\n" +
736 kDirtyClass + "\n" +
737 kUncommonCleanClass + "\n" +
738 "H" + kHotMethod + "\n" +
739 kUncommonDirtyClass;
740 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000741 EXPECT_TRUE(CreateProfile(
742 dex1, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700743
744 // Create a bunch of boot profiles.
745 std::string dex2 =
746 kCleanClass + "\n" +
747 kDirtyClass + "\n" +
748 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700749 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700750 kUncommonDirtyClass;
751 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000752 EXPECT_TRUE(CreateProfile(
753 dex2, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700754
755 // Create a bunch of boot profiles.
756 std::string dex3 =
757 "S" + kHotMethod + "\n" +
758 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700759 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700760 kDirtyClass + "\n";
761 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000762 EXPECT_TRUE(CreateProfile(
763 dex3, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700764
765 // Generate the boot profile.
766 ScratchFile out_profile;
767 std::vector<std::string> args;
768 args.push_back(GetProfmanCmd());
769 args.push_back("--generate-boot-image-profile");
770 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
771 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700772 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700773 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
774 args.push_back("--apk=" + core_dex);
775 args.push_back("--dex-location=" + core_dex);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000776 args.push_back("--skip-apk-verification");
Mathieu Chartier2f794552017-06-19 10:58:08 -0700777 for (const ScratchFile& profile : profiles) {
778 args.push_back("--profile-file=" + profile.GetFilename());
779 }
780 std::string error;
781 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
782 ASSERT_EQ(0, out_profile.GetFile()->Flush());
783 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
784
785 // Verify the boot profile contents.
786 std::string output_file_contents;
787 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
788 // Common classes, should be in the classes of the profile.
789 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
790 << output_file_contents;
791 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
792 << output_file_contents;
793 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
794 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
795 << output_file_contents;
796 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
797 << output_file_contents;
798 // Inferred class from a method common to all three profiles.
799 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
800 << output_file_contents;
801 // Aggregated methods hotness information.
802 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
803 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700804 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700805 << output_file_contents;
806 // Not inferred class, method is only in one profile.
807 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
808 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700809 // Test the sampled methods that became hot.
810 // Other method is in only one profile, it should not become hot.
811 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
812 << output_file_contents;
813 // Multi method is in at least two profiles, it should become hot.
814 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
815 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700816}
817
David Sehr7c80f2d2017-02-07 16:47:58 -0800818TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
819 // Class names put here need to be in sorted order.
820 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800821 "Ldoesnt/match/this/one;",
822 "Ljava/lang/Comparable;",
823 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800824 };
825 std::string input_file_contents;
826 for (std::string& class_name : class_names) {
827 input_file_contents += class_name + std::string("\n");
828 }
829 std::string output_file_contents;
830 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
831 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700832 class_names[1] + std::string("\n") +
833 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800834 ASSERT_EQ(output_file_contents, expected_contents);
835}
836
837TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
838 // Class names put here need to be in sorted order.
839 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800840 "Ldoesnt/match/this/one;",
841 "Ldoesnt/match/this/one/either;",
842 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800843 };
844 std::string input_file_contents;
845 for (std::string& class_name : class_names) {
846 input_file_contents += class_name + std::string("\n");
847 }
848 std::string output_file_contents;
849 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
850 std::string expected_contents("");
851 ASSERT_EQ(output_file_contents, expected_contents);
852}
853
Calin Juravlee0ac1152017-02-13 19:03:47 -0800854TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
855 // Create the profile content.
856 std::vector<std::string> methods = {
857 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
858 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
859 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800860 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800861 "LTestInline;->noInlineCache(LSuper;)I"
862 };
863 std::string input_file_contents;
864 for (std::string& m : methods) {
865 input_file_contents += m + std::string("\n");
866 }
867
868 // Create the profile and save it to disk.
869 ScratchFile profile_file;
870 ASSERT_TRUE(CreateProfile(input_file_contents,
871 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000872 GetTestDexFileName("ProfileTestMultiDex"),
873 /* skip_verification */ false));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800874
875 // Load the profile from disk.
876 ProfileCompilationInfo info;
877 profile_file.GetFile()->ResetOffset();
878 ASSERT_TRUE(info.Load(GetFd(profile_file)));
879
880 // Load the dex files and verify that the profile contains the expected methods info.
881 ScopedObjectAccess soa(Thread::Current());
882 jobject class_loader = LoadDex("ProfileTestMultiDex");
883 ASSERT_NE(class_loader, nullptr);
884
885 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
886 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
887 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
888
889 ASSERT_TRUE(sub_a != nullptr);
890 ASSERT_TRUE(sub_b != nullptr);
891 ASSERT_TRUE(sub_c != nullptr);
892
893 {
894 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
895 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
896 "LTestInline;",
897 "inlineMonomorphic");
898 ASSERT_TRUE(inline_monomorphic != nullptr);
899 std::set<mirror::Class*> expected_monomorphic;
900 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800901 AssertInlineCaches(inline_monomorphic,
902 expected_monomorphic,
903 info,
904 /*megamorphic*/false,
905 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800906 }
907
908 {
909 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
910 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
911 "LTestInline;",
912 "inlinePolymorphic");
913 ASSERT_TRUE(inline_polymorhic != nullptr);
914 std::set<mirror::Class*> expected_polymorphic;
915 expected_polymorphic.insert(sub_a);
916 expected_polymorphic.insert(sub_b);
917 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800918 AssertInlineCaches(inline_polymorhic,
919 expected_polymorphic,
920 info,
921 /*megamorphic*/false,
922 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800923 }
924
925 {
926 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
927 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
928 "LTestInline;",
929 "inlineMegamorphic");
930 ASSERT_TRUE(inline_megamorphic != nullptr);
931 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800932 AssertInlineCaches(inline_megamorphic,
933 expected_megamorphic,
934 info,
935 /*megamorphic*/true,
936 /*missing_types*/false);
937 }
938
939 {
940 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
941 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
942 "LTestInline;",
943 "inlineMissingTypes");
944 ASSERT_TRUE(inline_missing_types != nullptr);
945 std::set<mirror::Class*> expected_missing_Types;
946 AssertInlineCaches(inline_missing_types,
947 expected_missing_Types,
948 info,
949 /*megamorphic*/false,
950 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800951 }
952
953 {
954 // Verify that method noInlineCache has no inline caches in the profile.
955 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
956 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700957 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
958 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
959 no_inline_cache->GetDexFile()->GetLocationChecksum(),
960 no_inline_cache->GetDexMethodIndex());
961 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700962 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800963 }
964}
965
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700966TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
967 ScratchFile profile1;
968 ScratchFile reference_profile;
969
970 std::vector<int> profile_fds({GetFd(profile1)});
971 int reference_profile_fd = GetFd(reference_profile);
972
973 // The new profile info will contain the methods with indices 0-100.
974 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
975 ProfileCompilationInfo info1;
976 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
977 /*start_method_index*/0, /*reverse_dex_write_order*/false);
978
979 // The reference profile info will contain the methods with indices 50-150.
980 // When setting up the profile reverse the order in which the dex files
981 // are added to the profile. This will verify that profman merges profiles
982 // with a different dex order correctly.
983 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
984 ProfileCompilationInfo reference_info;
985 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
986 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
987
988 // We should advise compilation.
989 ASSERT_EQ(ProfileAssistant::kCompile,
990 ProcessProfiles(profile_fds, reference_profile_fd));
991
992 // The resulting compilation info must be equal to the merge of the inputs.
993 ProfileCompilationInfo result;
994 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
995 ASSERT_TRUE(result.Load(reference_profile_fd));
996
997 ProfileCompilationInfo expected;
998 ASSERT_TRUE(expected.MergeWith(reference_info));
999 ASSERT_TRUE(expected.MergeWith(info1));
1000 ASSERT_TRUE(expected.Equals(result));
1001
1002 // The information from profile must remain the same.
1003 CheckProfileInfo(profile1, info1);
1004}
1005
Calin Juravle08556882017-05-26 16:40:45 -07001006TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1007 // Create the profile content.
1008 std::vector<std::string> profile_methods = {
1009 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1010 "LTestInline;->invalid_method",
1011 "invalid_class"
1012 };
1013 std::string input_file_contents;
1014 for (std::string& m : profile_methods) {
1015 input_file_contents += m + std::string("\n");
1016 }
1017
1018 // Create the profile and save it to disk.
1019 ScratchFile profile_file;
1020 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1021 ASSERT_TRUE(CreateProfile(input_file_contents,
1022 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +00001023 dex_filename,
1024 /* skip_verification */ false));
Calin Juravle08556882017-05-26 16:40:45 -07001025
1026 // Load the profile from disk.
1027 ProfileCompilationInfo info;
1028 profile_file.GetFile()->ResetOffset();
1029 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1030
1031 // Load the dex files and verify that the profile contains the expected methods info.
1032 ScopedObjectAccess soa(Thread::Current());
1033 jobject class_loader = LoadDex("ProfileTestMultiDex");
1034 ASSERT_NE(class_loader, nullptr);
1035
1036 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1037 "LTestInline;",
1038 "inlineMonomorphic");
1039 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1040
1041 // Verify that the inline cache contains the invalid type.
1042 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1043 info.GetMethod(dex_file->GetLocation(),
1044 dex_file->GetLocationChecksum(),
1045 inline_monomorphic->GetDexMethodIndex());
1046 ASSERT_TRUE(pmi != nullptr);
1047 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1048 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1049 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1050 ASSERT_EQ(1u, dex_pc_data.classes.size());
1051 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1052
1053 // Verify that the start-up classes contain the invalid class.
1054 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001055 std::set<uint16_t> hot_methods;
1056 std::set<uint16_t> startup_methods;
1057 std::set<uint16_t> post_start_methods;
1058 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1059 &classes,
1060 &hot_methods,
1061 &startup_methods,
1062 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001063 ASSERT_EQ(1u, classes.size());
1064 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1065
1066 // Verify that the invalid method is in the profile.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001067 ASSERT_EQ(2u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001068 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001069 ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001070}
1071
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001072TEST_F(ProfileAssistantTest, DumpOnly) {
1073 ScratchFile profile;
1074
1075 const uint32_t kNumberOfMethods = 64;
1076 std::vector<uint32_t> hot_methods;
1077 std::vector<uint32_t> startup_methods;
1078 std::vector<uint32_t> post_startup_methods;
1079 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1080 if (i % 2 == 0) {
1081 hot_methods.push_back(i);
1082 }
1083 if (i % 3 == 1) {
1084 startup_methods.push_back(i);
1085 }
1086 if (i % 4 == 2) {
1087 post_startup_methods.push_back(i);
1088 }
1089 }
1090 EXPECT_GT(hot_methods.size(), 0u);
1091 EXPECT_GT(startup_methods.size(), 0u);
1092 EXPECT_GT(post_startup_methods.size(), 0u);
1093 ProfileCompilationInfo info1;
1094 SetupBasicProfile("p1",
1095 1,
1096 kNumberOfMethods,
1097 hot_methods,
1098 startup_methods,
1099 post_startup_methods,
1100 profile,
1101 &info1);
1102 std::string output;
1103 DumpOnly(profile.GetFilename(), &output);
1104 const size_t hot_offset = output.find("hot methods:");
1105 const size_t startup_offset = output.find("startup methods:");
1106 const size_t post_startup_offset = output.find("post startup methods:");
1107 const size_t classes_offset = output.find("classes:");
1108 ASSERT_NE(hot_offset, std::string::npos);
1109 ASSERT_NE(startup_offset, std::string::npos);
1110 ASSERT_NE(post_startup_offset, std::string::npos);
1111 ASSERT_LT(hot_offset, startup_offset);
1112 ASSERT_LT(startup_offset, post_startup_offset);
1113 // Check the actual contents of the dump by looking at the offsets of the methods.
1114 for (uint32_t m : hot_methods) {
1115 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1116 ASSERT_NE(pos, std::string::npos);
1117 EXPECT_LT(pos, startup_offset);
1118 }
1119 for (uint32_t m : startup_methods) {
1120 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1121 ASSERT_NE(pos, std::string::npos);
1122 EXPECT_LT(pos, post_startup_offset);
1123 }
1124 for (uint32_t m : post_startup_methods) {
1125 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1126 ASSERT_NE(pos, std::string::npos);
1127 EXPECT_LT(pos, classes_offset);
1128 }
1129}
1130
Calin Juravle2e2db782016-02-23 12:00:03 +00001131} // namespace art