blob: 1dd1a4afc04c0a8b212377c0f8a21fecda51af83 [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 Juravlee10c1e22018-01-26 20:10:15 -080019#include "android-base/strings.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080020#include "art_method-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000021#include "base/unix_file/fd_file.h"
22#include "common_runtime_test.h"
David Sehr97c381e2017-02-01 15:09:58 -080023#include "exec_utils.h"
Calin Juravle33083d62017-01-18 15:29:12 -080024#include "jit/profile_compilation_info.h"
Calin Juravlecc3171a2017-05-19 16:47:53 -070025#include "linear_alloc.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080026#include "mirror/class-inl.h"
Mathieu Chartierd808e8b2017-03-21 13:37:41 -070027#include "obj_ptr-inl.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080028#include "profile_assistant.h"
29#include "scoped_thread_state_change-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000030#include "utils.h"
31
32namespace art {
33
Calin Juravleee9cb412018-02-13 20:32:35 -080034using Hotness = ProfileCompilationInfo::MethodHotness;
35
Mathieu Chartierea650f32017-05-24 12:04:13 -070036static constexpr size_t kMaxMethodIds = 65535;
37
Calin Juravle2e2db782016-02-23 12:00:03 +000038class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070039 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070040 void PostRuntimeCreate() OVERRIDE {
Vladimir Marko69d310e2017-10-09 14:12:23 +010041 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
Calin Juravlecc3171a2017-05-19 16:47:53 -070042 }
43
Calin Juravle2e2db782016-02-23 12:00:03 +000044 protected:
45 void SetupProfile(const std::string& id,
46 uint32_t checksum,
47 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010048 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000049 const ScratchFile& profile,
50 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070051 uint16_t start_method_index = 0,
52 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000053 std::string dex_location1 = "location1" + id;
54 uint32_t dex_location_checksum1 = checksum;
55 std::string dex_location2 = "location2" + id;
56 uint32_t dex_location_checksum2 = 10 * checksum;
Calin Juravlee10c1e22018-01-26 20:10:15 -080057 SetupProfile(dex_location1,
58 dex_location_checksum1,
59 dex_location2,
60 dex_location_checksum2,
61 number_of_methods,
62 number_of_classes,
63 profile,
64 info,
65 start_method_index,
66 reverse_dex_write_order);
67 }
68
69 void SetupProfile(const std::string& dex_location1,
70 uint32_t dex_location_checksum1,
71 const std::string& dex_location2,
72 uint32_t dex_location_checksum2,
73 uint16_t number_of_methods,
74 uint16_t number_of_classes,
75 const ScratchFile& profile,
76 ProfileCompilationInfo* info,
77 uint16_t start_method_index = 0,
Calin Juravle02c08792018-02-15 19:40:48 -080078 bool reverse_dex_write_order = false,
79 uint32_t number_of_methods1 = kMaxMethodIds,
80 uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravle2e2db782016-02-23 12:00:03 +000081 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070082 // reverse_dex_write_order controls the order in which the dex files will be added to
83 // the profile and thus written to disk.
84 ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
85 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -080086 dex_location2, dex_location_checksum2,
87 number_of_methods1, number_of_methods2);
Calin Juravleee9cb412018-02-13 20:32:35 -080088 Hotness::Flag flags = Hotness::kFlagPostStartup;
Calin Juravlecea9e9d2017-03-23 19:04:59 -070089 if (reverse_dex_write_order) {
Calin Juravleee9cb412018-02-13 20:32:35 -080090 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080091 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -080092 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080093 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070094 } else {
Calin Juravleee9cb412018-02-13 20:32:35 -080095 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080096 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -080097 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080098 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070099 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000100 }
Calin Juravlec824b512016-03-29 20:33:33 +0100101 for (uint16_t i = 0; i < number_of_classes; i++) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700102 ASSERT_TRUE(info->AddClassIndex(dex_location1,
103 dex_location_checksum1,
104 dex::TypeIndex(i),
Calin Juravle02c08792018-02-15 19:40:48 -0800105 number_of_methods1));
Calin Juravlec824b512016-03-29 20:33:33 +0100106 }
107
Calin Juravle2e2db782016-02-23 12:00:03 +0000108 ASSERT_TRUE(info->Save(GetFd(profile)));
109 ASSERT_EQ(0, profile.GetFile()->Flush());
110 ASSERT_TRUE(profile.GetFile()->ResetOffset());
111 }
112
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700113 void SetupBasicProfile(const std::string& id,
114 uint32_t checksum,
115 uint16_t number_of_methods,
116 const std::vector<uint32_t> hot_methods,
117 const std::vector<uint32_t> startup_methods,
118 const std::vector<uint32_t> post_startup_methods,
119 const ScratchFile& profile,
120 ProfileCompilationInfo* info) {
121 std::string dex_location = "location1" + id;
122 for (uint32_t idx : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700123 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700124 }
125 for (uint32_t idx : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700126 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700127 }
128 for (uint32_t idx : post_startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700129 info->AddMethodIndex(Hotness::kFlagPostStartup,
130 dex_location,
131 checksum,
132 idx,
133 number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700134 }
135 ASSERT_TRUE(info->Save(GetFd(profile)));
136 ASSERT_EQ(0, profile.GetFile()->Flush());
137 ASSERT_TRUE(profile.GetFile()->ResetOffset());
138 }
139
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700140 // Creates an inline cache which will be destructed at the end of the test.
141 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
142 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100143 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700144 return used_inline_caches.back().get();
145 }
146
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700147 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
148 const std::string& dex_location1, uint32_t dex_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -0800149 const std::string& dex_location2, uint32_t dex_checksum2,
150 uint32_t number_of_methods1 = kMaxMethodIds, uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700151 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
152 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Calin Juravle02c08792018-02-15 19:40:48 -0800153 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, number_of_methods1);
154 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, number_of_methods2);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700155
156 // Monomorphic
157 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100158 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700159 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700160 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700161 }
162 // Polymorphic
163 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100164 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700165 dex_pc_data.AddClass(0, dex::TypeIndex(0));
166 dex_pc_data.AddClass(1, dex::TypeIndex(1));
167
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700168 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700169 }
170 // Megamorphic
171 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100172 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700173 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700174 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700175 }
176 // Missing types
177 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100178 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700179 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700180 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700181 }
182
183 return pmi;
184 }
185
Calin Juravle2e2db782016-02-23 12:00:03 +0000186 int GetFd(const ScratchFile& file) const {
187 return static_cast<int>(file.GetFd());
188 }
189
190 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
191 ProfileCompilationInfo file_info;
192 ASSERT_TRUE(file.GetFile()->ResetOffset());
193 ASSERT_TRUE(file_info.Load(GetFd(file)));
194 ASSERT_TRUE(file_info.Equals(info));
195 }
196
Calin Juravle7bcdb532016-06-07 16:14:47 +0100197 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000198 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000199 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000200 if (kIsDebugBuild) {
201 file_path += "d";
202 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100203 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
204 << file_path << " should be a valid file path";
205 return file_path;
206 }
Mathieu Chartierf70fe3d2017-06-21 15:24:02 -0700207
Calin Juravle7bcdb532016-06-07 16:14:47 +0100208 // Runs test with given arguments.
209 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
210 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000211 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100212 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000213 for (size_t k = 0; k < profiles_fd.size(); k++) {
214 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
215 }
216 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
217
218 std::string error;
219 return ExecAndReturnCode(argv_str, &error);
220 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100221
222 bool GenerateTestProfile(const std::string& filename) {
223 std::string profman_cmd = GetProfmanCmd();
224 std::vector<std::string> argv_str;
225 argv_str.push_back(profman_cmd);
226 argv_str.push_back("--generate-test-profile=" + filename);
227 std::string error;
228 return ExecAndReturnCode(argv_str, &error);
229 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800230
Jeff Haof0a31f82017-03-27 15:50:37 -0700231 bool GenerateTestProfileWithInputDex(const std::string& filename) {
232 std::string profman_cmd = GetProfmanCmd();
233 std::vector<std::string> argv_str;
234 argv_str.push_back(profman_cmd);
235 argv_str.push_back("--generate-test-profile=" + filename);
236 argv_str.push_back("--generate-test-profile-seed=0");
237 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
238 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
239 std::string error;
240 return ExecAndReturnCode(argv_str, &error);
241 }
242
Andreas Gampe641a4732017-08-24 13:21:35 -0700243 bool CreateProfile(const std::string& profile_file_contents,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800244 const std::string& filename,
David Brazdilf13ac7c2018-01-30 10:09:08 +0000245 const std::string& dex_location,
246 bool skip_verification) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800247 ScratchFile class_names_file;
248 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800249 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800250 EXPECT_EQ(0, file->Flush());
251 EXPECT_TRUE(file->ResetOffset());
252 std::string profman_cmd = GetProfmanCmd();
253 std::vector<std::string> argv_str;
254 argv_str.push_back(profman_cmd);
255 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
256 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800257 argv_str.push_back("--apk=" + dex_location);
258 argv_str.push_back("--dex-location=" + dex_location);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000259 if (skip_verification) {
260 argv_str.push_back("--skip-apk-verification");
261 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800262 std::string error;
263 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
264 return true;
265 }
266
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700267 bool RunProfman(const std::string& filename,
268 std::vector<std::string>& extra_args,
269 std::string* output) {
270 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800271 std::string profman_cmd = GetProfmanCmd();
272 std::vector<std::string> argv_str;
273 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700274 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800275 argv_str.push_back("--profile-file=" + filename);
276 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800277 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000278 argv_str.push_back("--skip-apk-verification");
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700279 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800280 std::string error;
281 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700282 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800283 EXPECT_EQ(0, file->Flush());
284 EXPECT_TRUE(file->ResetOffset());
285 int64_t length = file->GetLength();
286 std::unique_ptr<char[]> buf(new char[length]);
287 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700288 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800289 return true;
290 }
291
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700292 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
293 std::vector<std::string> extra_args;
294 extra_args.push_back("--dump-classes-and-methods");
295 return RunProfman(filename, extra_args, file_contents);
296 }
297
298 bool DumpOnly(const std::string& filename, std::string* file_contents) {
299 std::vector<std::string> extra_args;
300 extra_args.push_back("--dump-only");
301 return RunProfman(filename, extra_args, file_contents);
302 }
303
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700304 bool CreateAndDump(const std::string& input_file_contents,
305 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800306 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800307 EXPECT_TRUE(CreateProfile(input_file_contents,
308 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000309 GetLibCoreDexFileNames()[0],
310 /* skip_verification */ true));
David Sehr7c80f2d2017-02-07 16:47:58 -0800311 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700312 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800313 return true;
314 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800315
316 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
317 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
318 Thread* self = Thread::Current();
319 ScopedObjectAccess soa(self);
320 StackHandleScope<1> hs(self);
321 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700322 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800323 return class_linker->FindClass(self, clazz.c_str(), h_loader);
324 }
325
326 ArtMethod* GetVirtualMethod(jobject class_loader,
327 const std::string& clazz,
328 const std::string& name) {
329 mirror::Class* klass = GetClass(class_loader, clazz);
330 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
331 const auto pointer_size = class_linker->GetImagePointerSize();
332 ArtMethod* method = nullptr;
333 Thread* self = Thread::Current();
334 ScopedObjectAccess soa(self);
335 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
336 if (name == m.GetName()) {
337 EXPECT_TRUE(method == nullptr);
338 method = &m;
339 }
340 }
341 return method;
342 }
343
344 // Verify that given method has the expected inline caches and nothing else.
345 void AssertInlineCaches(ArtMethod* method,
346 const std::set<mirror::Class*>& expected_clases,
347 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800348 bool is_megamorphic,
349 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800350 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700351 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
352 info.GetMethod(method->GetDexFile()->GetLocation(),
353 method->GetDexFile()->GetLocationChecksum(),
354 method->GetDexMethodIndex());
355 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700356 ASSERT_EQ(pmi->inline_caches->size(), 1u);
357 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800358
Calin Juravle589e71e2017-03-03 16:05:05 -0800359 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
360 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800361 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
362 size_t found = 0;
363 for (mirror::Class* it : expected_clases) {
364 for (const auto& class_ref : dex_pc_data.classes) {
365 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700366 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800367 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
368 class_ref.type_index == it->GetDexTypeIndex()) {
369 found++;
370 }
371 }
372 }
373
374 ASSERT_EQ(expected_clases.size(), found);
375 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700376
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700377 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
378 uint16_t methods_in_ref_profile) {
379 ScratchFile profile;
380 ScratchFile reference_profile;
381 std::vector<int> profile_fds({ GetFd(profile)});
382 int reference_profile_fd = GetFd(reference_profile);
383 std::vector<uint32_t> hot_methods_cur;
384 std::vector<uint32_t> hot_methods_ref;
385 std::vector<uint32_t> empty_vector;
386 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
387 hot_methods_cur.push_back(i);
388 }
389 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
390 hot_methods_ref.push_back(i);
391 }
392 ProfileCompilationInfo info1;
393 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
394 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
395 profile, &info1);
396 ProfileCompilationInfo info2;
397 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
398 reference_profile, &info2);
399 return ProcessProfiles(profile_fds, reference_profile_fd);
400 }
401
402 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
403 uint16_t classes_in_ref_profile) {
404 ScratchFile profile;
405 ScratchFile reference_profile;
406
407 std::vector<int> profile_fds({ GetFd(profile)});
408 int reference_profile_fd = GetFd(reference_profile);
409
410 ProfileCompilationInfo info1;
411 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
412 ProfileCompilationInfo info2;
413 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
414 return ProcessProfiles(profile_fds, reference_profile_fd);
415 }
416
Vladimir Marko69d310e2017-10-09 14:12:23 +0100417 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700418
419 // Cache of inline caches generated during tests.
420 // This makes it easier to pass data between different utilities and ensure that
421 // caches are destructed at the end of the test.
422 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000423};
424
425TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
426 ScratchFile profile1;
427 ScratchFile profile2;
428 ScratchFile reference_profile;
429
430 std::vector<int> profile_fds({
431 GetFd(profile1),
432 GetFd(profile2)});
433 int reference_profile_fd = GetFd(reference_profile);
434
435 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
436 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100437 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000438 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100439 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000440
441 // We should advise compilation.
442 ASSERT_EQ(ProfileAssistant::kCompile,
443 ProcessProfiles(profile_fds, reference_profile_fd));
444 // The resulting compilation info must be equal to the merge of the inputs.
445 ProfileCompilationInfo result;
446 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
447 ASSERT_TRUE(result.Load(reference_profile_fd));
448
449 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000450 ASSERT_TRUE(expected.MergeWith(info1));
451 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000452 ASSERT_TRUE(expected.Equals(result));
453
454 // The information from profiles must remain the same.
455 CheckProfileInfo(profile1, info1);
456 CheckProfileInfo(profile2, info2);
457}
458
Calin Juravlec824b512016-03-29 20:33:33 +0100459// TODO(calin): Add more tests for classes.
460TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
461 ScratchFile profile1;
462 ScratchFile reference_profile;
463
464 std::vector<int> profile_fds({
465 GetFd(profile1)});
466 int reference_profile_fd = GetFd(reference_profile);
467
468 const uint16_t kNumberOfClassesToEnableCompilation = 100;
469 ProfileCompilationInfo info1;
470 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
471
472 // We should advise compilation.
473 ASSERT_EQ(ProfileAssistant::kCompile,
474 ProcessProfiles(profile_fds, reference_profile_fd));
475 // The resulting compilation info must be equal to the merge of the inputs.
476 ProfileCompilationInfo result;
477 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
478 ASSERT_TRUE(result.Load(reference_profile_fd));
479
480 ProfileCompilationInfo expected;
481 ASSERT_TRUE(expected.MergeWith(info1));
482 ASSERT_TRUE(expected.Equals(result));
483
484 // The information from profiles must remain the same.
485 CheckProfileInfo(profile1, info1);
486}
487
Calin Juravle2e2db782016-02-23 12:00:03 +0000488TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
489 ScratchFile profile1;
490 ScratchFile profile2;
491 ScratchFile reference_profile;
492
493 std::vector<int> profile_fds({
494 GetFd(profile1),
495 GetFd(profile2)});
496 int reference_profile_fd = GetFd(reference_profile);
497
498 // The new profile info will contain the methods with indices 0-100.
499 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
500 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100501 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000502 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100503 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000504
505
506 // The reference profile info will contain the methods with indices 50-150.
507 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
508 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100509 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000510 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
511
512 // We should advise compilation.
513 ASSERT_EQ(ProfileAssistant::kCompile,
514 ProcessProfiles(profile_fds, reference_profile_fd));
515
516 // The resulting compilation info must be equal to the merge of the inputs
517 ProfileCompilationInfo result;
518 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
519 ASSERT_TRUE(result.Load(reference_profile_fd));
520
521 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000522 ASSERT_TRUE(expected.MergeWith(info1));
523 ASSERT_TRUE(expected.MergeWith(info2));
524 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000525 ASSERT_TRUE(expected.Equals(result));
526
527 // The information from profiles must remain the same.
528 CheckProfileInfo(profile1, info1);
529 CheckProfileInfo(profile2, info2);
530}
531
532TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
533 ScratchFile profile1;
534 ScratchFile profile2;
535 ScratchFile reference_profile;
536
537 std::vector<int> profile_fds({
538 GetFd(profile1),
539 GetFd(profile2)});
540 int reference_profile_fd = GetFd(reference_profile);
541
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700542 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000543 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100544 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000545 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100546 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000547
548 // We should not advise compilation.
549 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
550 ProcessProfiles(profile_fds, reference_profile_fd));
551
552 // The information from profiles must remain the same.
553 ProfileCompilationInfo file_info1;
554 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
555 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
556 ASSERT_TRUE(file_info1.Equals(info1));
557
558 ProfileCompilationInfo file_info2;
559 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
560 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
561 ASSERT_TRUE(file_info2.Equals(info2));
562
563 // Reference profile files must remain empty.
564 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
565
566 // The information from profiles must remain the same.
567 CheckProfileInfo(profile1, info1);
568 CheckProfileInfo(profile2, info2);
569}
570
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700571TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
572 const uint16_t kNumberOfMethodsInRefProfile = 6000;
573 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
574 // We should not advise compilation.
575 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
576 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
577 kNumberOfMethodsInRefProfile));
578}
579
580TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
581 const uint16_t kNumberOfMethodsInRefProfile = 6000;
582 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
583 // We should advise compilation.
584 ASSERT_EQ(ProfileAssistant::kCompile,
585 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
586 kNumberOfMethodsInRefProfile));
587}
588
589TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
590 const uint16_t kNumberOfClassesInRefProfile = 6000;
591 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
592 // We should not advise compilation.
593 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
594 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
595 kNumberOfClassesInRefProfile));
596}
597
598TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
599 const uint16_t kNumberOfClassesInRefProfile = 6000;
600 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
601 // We should advise compilation.
602 ASSERT_EQ(ProfileAssistant::kCompile,
603 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
604 kNumberOfClassesInRefProfile));
605}
606
Calin Juravle2e2db782016-02-23 12:00:03 +0000607TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
608 ScratchFile profile1;
609 ScratchFile profile2;
610 ScratchFile reference_profile;
611
612 std::vector<int> profile_fds({
613 GetFd(profile1),
614 GetFd(profile2)});
615 int reference_profile_fd = GetFd(reference_profile);
616
617 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
618 // Assign different hashes for the same dex file. This will make merging of information to fail.
619 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100620 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000621 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100622 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000623
624 // We should fail processing.
625 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
626 ProcessProfiles(profile_fds, reference_profile_fd));
627
628 // The information from profiles must remain the same.
629 CheckProfileInfo(profile1, info1);
630 CheckProfileInfo(profile2, info2);
631
632 // Reference profile files must still remain empty.
633 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
634}
635
636TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
637 ScratchFile profile1;
638 ScratchFile reference_profile;
639
640 std::vector<int> profile_fds({
641 GetFd(profile1)});
642 int reference_profile_fd = GetFd(reference_profile);
643
644 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
645 // Assign different hashes for the same dex file. This will make merging of information to fail.
646 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100647 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000648 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100649 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000650
651 // We should not advise compilation.
652 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
653 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
654 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
655 ProcessProfiles(profile_fds, reference_profile_fd));
656
657 // The information from profiles must remain the same.
658 CheckProfileInfo(profile1, info1);
659}
660
Calin Juravle7bcdb532016-06-07 16:14:47 +0100661TEST_F(ProfileAssistantTest, TestProfileGeneration) {
662 ScratchFile profile;
663 // Generate a test profile.
664 GenerateTestProfile(profile.GetFilename());
665
666 // Verify that the generated profile is valid and can be loaded.
667 ASSERT_TRUE(profile.GetFile()->ResetOffset());
668 ProfileCompilationInfo info;
669 ASSERT_TRUE(info.Load(GetFd(profile)));
670}
671
Jeff Haof0a31f82017-03-27 15:50:37 -0700672TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
673 ScratchFile profile;
674 // Generate a test profile passing in a dex file as reference.
675 GenerateTestProfileWithInputDex(profile.GetFilename());
676
677 // Verify that the generated profile is valid and can be loaded.
678 ASSERT_TRUE(profile.GetFile()->ResetOffset());
679 ProfileCompilationInfo info;
680 ASSERT_TRUE(info.Load(GetFd(profile)));
681}
682
David Sehr7c80f2d2017-02-07 16:47:58 -0800683TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
684 // Class names put here need to be in sorted order.
685 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700686 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800687 "Ljava/lang/Comparable;",
688 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700689 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700690 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800691 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700692 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800693 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700694 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800695 }
696 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700697 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
698 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800699}
700
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700701TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
702 // Class names put here need to be in sorted order.
703 std::vector<std::string> class_names = {
704 "Ljava/lang/Math;->*",
705 };
706 std::string input_file_contents;
707 std::string expected_contents;
708 for (std::string& class_name : class_names) {
709 input_file_contents += class_name + std::string("\n");
710 expected_contents += DescriptorToDot(class_name.c_str()) +
711 std::string("\n");
712 }
713 std::string output_file_contents;
714 ScratchFile profile_file;
715 EXPECT_TRUE(CreateProfile(input_file_contents,
716 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000717 GetLibCoreDexFileNames()[0],
718 /* skip_verification */ true));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700719 ProfileCompilationInfo info;
720 profile_file.GetFile()->ResetOffset();
721 ASSERT_TRUE(info.Load(GetFd(profile_file)));
722 // Verify that the profile has matching methods.
723 ScopedObjectAccess soa(Thread::Current());
724 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
725 ASSERT_TRUE(klass != nullptr);
726 size_t method_count = 0;
727 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
728 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
729 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700730 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
731 info.GetMethod(method.GetDexFile()->GetLocation(),
732 method.GetDexFile()->GetLocationChecksum(),
733 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700734 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700735 }
736 }
737 EXPECT_GT(method_count, 0u);
738}
739
Mathieu Chartier2f794552017-06-19 10:58:08 -0700740TEST_F(ProfileAssistantTest, TestBootImageProfile) {
741 const std::string core_dex = GetLibCoreDexFileNames()[0];
742
743 std::vector<ScratchFile> profiles;
744
745 // In image with enough clean occurrences.
746 const std::string kCleanClass = "Ljava/lang/CharSequence;";
747 // In image with enough dirty occurrences.
748 const std::string kDirtyClass = "Ljava/lang/Object;";
749 // Not in image becauseof not enough occurrences.
750 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
751 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
752 // Method that is hot.
753 // Also adds the class through inference since it is in each dex.
754 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
755 // Method that doesn't add the class since its only in one profile. Should still show up in the
756 // boot profile.
757 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700758 // Method that gets marked as hot since it's in multiple profiles.
759 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700760
761 // Thresholds for this test.
762 static const size_t kDirtyThreshold = 3;
763 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700764 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700765
766 // Create a bunch of boot profiles.
767 std::string dex1 =
768 kCleanClass + "\n" +
769 kDirtyClass + "\n" +
770 kUncommonCleanClass + "\n" +
771 "H" + kHotMethod + "\n" +
772 kUncommonDirtyClass;
773 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000774 EXPECT_TRUE(CreateProfile(
775 dex1, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700776
777 // Create a bunch of boot profiles.
778 std::string dex2 =
779 kCleanClass + "\n" +
780 kDirtyClass + "\n" +
781 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700782 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700783 kUncommonDirtyClass;
784 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000785 EXPECT_TRUE(CreateProfile(
786 dex2, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700787
788 // Create a bunch of boot profiles.
789 std::string dex3 =
790 "S" + kHotMethod + "\n" +
791 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700792 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700793 kDirtyClass + "\n";
794 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000795 EXPECT_TRUE(CreateProfile(
796 dex3, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700797
798 // Generate the boot profile.
799 ScratchFile out_profile;
800 std::vector<std::string> args;
801 args.push_back(GetProfmanCmd());
802 args.push_back("--generate-boot-image-profile");
803 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
804 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700805 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700806 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
807 args.push_back("--apk=" + core_dex);
808 args.push_back("--dex-location=" + core_dex);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000809 args.push_back("--skip-apk-verification");
Mathieu Chartier2f794552017-06-19 10:58:08 -0700810 for (const ScratchFile& profile : profiles) {
811 args.push_back("--profile-file=" + profile.GetFilename());
812 }
813 std::string error;
814 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
815 ASSERT_EQ(0, out_profile.GetFile()->Flush());
816 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
817
818 // Verify the boot profile contents.
819 std::string output_file_contents;
820 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
821 // Common classes, should be in the classes of the profile.
822 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
823 << output_file_contents;
824 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
825 << output_file_contents;
826 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
827 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
828 << output_file_contents;
829 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
830 << output_file_contents;
831 // Inferred class from a method common to all three profiles.
832 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
833 << output_file_contents;
834 // Aggregated methods hotness information.
835 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
836 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700837 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700838 << output_file_contents;
839 // Not inferred class, method is only in one profile.
840 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
841 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700842 // Test the sampled methods that became hot.
843 // Other method is in only one profile, it should not become hot.
844 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
845 << output_file_contents;
846 // Multi method is in at least two profiles, it should become hot.
847 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
848 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700849}
850
David Sehr7c80f2d2017-02-07 16:47:58 -0800851TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
852 // Class names put here need to be in sorted order.
853 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800854 "Ldoesnt/match/this/one;",
855 "Ljava/lang/Comparable;",
856 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800857 };
858 std::string input_file_contents;
859 for (std::string& class_name : class_names) {
860 input_file_contents += class_name + std::string("\n");
861 }
862 std::string output_file_contents;
863 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
864 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700865 class_names[1] + std::string("\n") +
866 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800867 ASSERT_EQ(output_file_contents, expected_contents);
868}
869
870TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
871 // Class names put here need to be in sorted order.
872 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800873 "Ldoesnt/match/this/one;",
874 "Ldoesnt/match/this/one/either;",
875 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800876 };
877 std::string input_file_contents;
878 for (std::string& class_name : class_names) {
879 input_file_contents += class_name + std::string("\n");
880 }
881 std::string output_file_contents;
882 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
883 std::string expected_contents("");
884 ASSERT_EQ(output_file_contents, expected_contents);
885}
886
Calin Juravlee0ac1152017-02-13 19:03:47 -0800887TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
888 // Create the profile content.
889 std::vector<std::string> methods = {
890 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
891 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
892 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800893 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800894 "LTestInline;->noInlineCache(LSuper;)I"
895 };
896 std::string input_file_contents;
897 for (std::string& m : methods) {
898 input_file_contents += m + std::string("\n");
899 }
900
901 // Create the profile and save it to disk.
902 ScratchFile profile_file;
903 ASSERT_TRUE(CreateProfile(input_file_contents,
904 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000905 GetTestDexFileName("ProfileTestMultiDex"),
906 /* skip_verification */ false));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800907
908 // Load the profile from disk.
909 ProfileCompilationInfo info;
910 profile_file.GetFile()->ResetOffset();
911 ASSERT_TRUE(info.Load(GetFd(profile_file)));
912
913 // Load the dex files and verify that the profile contains the expected methods info.
914 ScopedObjectAccess soa(Thread::Current());
915 jobject class_loader = LoadDex("ProfileTestMultiDex");
916 ASSERT_NE(class_loader, nullptr);
917
918 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
919 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
920 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
921
922 ASSERT_TRUE(sub_a != nullptr);
923 ASSERT_TRUE(sub_b != nullptr);
924 ASSERT_TRUE(sub_c != nullptr);
925
926 {
927 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
928 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
929 "LTestInline;",
930 "inlineMonomorphic");
931 ASSERT_TRUE(inline_monomorphic != nullptr);
932 std::set<mirror::Class*> expected_monomorphic;
933 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800934 AssertInlineCaches(inline_monomorphic,
935 expected_monomorphic,
936 info,
937 /*megamorphic*/false,
938 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800939 }
940
941 {
942 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
943 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
944 "LTestInline;",
945 "inlinePolymorphic");
946 ASSERT_TRUE(inline_polymorhic != nullptr);
947 std::set<mirror::Class*> expected_polymorphic;
948 expected_polymorphic.insert(sub_a);
949 expected_polymorphic.insert(sub_b);
950 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800951 AssertInlineCaches(inline_polymorhic,
952 expected_polymorphic,
953 info,
954 /*megamorphic*/false,
955 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800956 }
957
958 {
959 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
960 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
961 "LTestInline;",
962 "inlineMegamorphic");
963 ASSERT_TRUE(inline_megamorphic != nullptr);
964 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800965 AssertInlineCaches(inline_megamorphic,
966 expected_megamorphic,
967 info,
968 /*megamorphic*/true,
969 /*missing_types*/false);
970 }
971
972 {
973 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
974 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
975 "LTestInline;",
976 "inlineMissingTypes");
977 ASSERT_TRUE(inline_missing_types != nullptr);
978 std::set<mirror::Class*> expected_missing_Types;
979 AssertInlineCaches(inline_missing_types,
980 expected_missing_Types,
981 info,
982 /*megamorphic*/false,
983 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800984 }
985
986 {
987 // Verify that method noInlineCache has no inline caches in the profile.
988 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
989 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700990 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
991 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
992 no_inline_cache->GetDexFile()->GetLocationChecksum(),
993 no_inline_cache->GetDexMethodIndex());
994 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700995 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800996 }
997}
998
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700999TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
1000 ScratchFile profile1;
1001 ScratchFile reference_profile;
1002
1003 std::vector<int> profile_fds({GetFd(profile1)});
1004 int reference_profile_fd = GetFd(reference_profile);
1005
1006 // The new profile info will contain the methods with indices 0-100.
1007 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1008 ProfileCompilationInfo info1;
1009 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1010 /*start_method_index*/0, /*reverse_dex_write_order*/false);
1011
1012 // The reference profile info will contain the methods with indices 50-150.
1013 // When setting up the profile reverse the order in which the dex files
1014 // are added to the profile. This will verify that profman merges profiles
1015 // with a different dex order correctly.
1016 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1017 ProfileCompilationInfo reference_info;
1018 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1019 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
1020
1021 // We should advise compilation.
1022 ASSERT_EQ(ProfileAssistant::kCompile,
1023 ProcessProfiles(profile_fds, reference_profile_fd));
1024
1025 // The resulting compilation info must be equal to the merge of the inputs.
1026 ProfileCompilationInfo result;
1027 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1028 ASSERT_TRUE(result.Load(reference_profile_fd));
1029
1030 ProfileCompilationInfo expected;
1031 ASSERT_TRUE(expected.MergeWith(reference_info));
1032 ASSERT_TRUE(expected.MergeWith(info1));
1033 ASSERT_TRUE(expected.Equals(result));
1034
1035 // The information from profile must remain the same.
1036 CheckProfileInfo(profile1, info1);
1037}
1038
Calin Juravle08556882017-05-26 16:40:45 -07001039TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1040 // Create the profile content.
1041 std::vector<std::string> profile_methods = {
1042 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1043 "LTestInline;->invalid_method",
1044 "invalid_class"
1045 };
1046 std::string input_file_contents;
1047 for (std::string& m : profile_methods) {
1048 input_file_contents += m + std::string("\n");
1049 }
1050
1051 // Create the profile and save it to disk.
1052 ScratchFile profile_file;
1053 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1054 ASSERT_TRUE(CreateProfile(input_file_contents,
1055 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +00001056 dex_filename,
1057 /* skip_verification */ false));
Calin Juravle08556882017-05-26 16:40:45 -07001058
1059 // Load the profile from disk.
1060 ProfileCompilationInfo info;
1061 profile_file.GetFile()->ResetOffset();
1062 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1063
1064 // Load the dex files and verify that the profile contains the expected methods info.
1065 ScopedObjectAccess soa(Thread::Current());
1066 jobject class_loader = LoadDex("ProfileTestMultiDex");
1067 ASSERT_NE(class_loader, nullptr);
1068
1069 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1070 "LTestInline;",
1071 "inlineMonomorphic");
1072 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1073
1074 // Verify that the inline cache contains the invalid type.
1075 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1076 info.GetMethod(dex_file->GetLocation(),
1077 dex_file->GetLocationChecksum(),
1078 inline_monomorphic->GetDexMethodIndex());
1079 ASSERT_TRUE(pmi != nullptr);
1080 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1081 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1082 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1083 ASSERT_EQ(1u, dex_pc_data.classes.size());
1084 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1085
1086 // Verify that the start-up classes contain the invalid class.
1087 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001088 std::set<uint16_t> hot_methods;
1089 std::set<uint16_t> startup_methods;
1090 std::set<uint16_t> post_start_methods;
1091 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1092 &classes,
1093 &hot_methods,
1094 &startup_methods,
1095 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001096 ASSERT_EQ(1u, classes.size());
1097 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1098
Calin Juravleee9cb412018-02-13 20:32:35 -08001099 // Verify that the invalid method did not get in the profile.
1100 ASSERT_EQ(1u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001101 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Calin Juravleee9cb412018-02-13 20:32:35 -08001102 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001103}
1104
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001105TEST_F(ProfileAssistantTest, DumpOnly) {
1106 ScratchFile profile;
1107
1108 const uint32_t kNumberOfMethods = 64;
1109 std::vector<uint32_t> hot_methods;
1110 std::vector<uint32_t> startup_methods;
1111 std::vector<uint32_t> post_startup_methods;
1112 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1113 if (i % 2 == 0) {
1114 hot_methods.push_back(i);
1115 }
1116 if (i % 3 == 1) {
1117 startup_methods.push_back(i);
1118 }
1119 if (i % 4 == 2) {
1120 post_startup_methods.push_back(i);
1121 }
1122 }
1123 EXPECT_GT(hot_methods.size(), 0u);
1124 EXPECT_GT(startup_methods.size(), 0u);
1125 EXPECT_GT(post_startup_methods.size(), 0u);
1126 ProfileCompilationInfo info1;
1127 SetupBasicProfile("p1",
1128 1,
1129 kNumberOfMethods,
1130 hot_methods,
1131 startup_methods,
1132 post_startup_methods,
1133 profile,
1134 &info1);
1135 std::string output;
1136 DumpOnly(profile.GetFilename(), &output);
1137 const size_t hot_offset = output.find("hot methods:");
1138 const size_t startup_offset = output.find("startup methods:");
1139 const size_t post_startup_offset = output.find("post startup methods:");
1140 const size_t classes_offset = output.find("classes:");
1141 ASSERT_NE(hot_offset, std::string::npos);
1142 ASSERT_NE(startup_offset, std::string::npos);
1143 ASSERT_NE(post_startup_offset, std::string::npos);
1144 ASSERT_LT(hot_offset, startup_offset);
1145 ASSERT_LT(startup_offset, post_startup_offset);
1146 // Check the actual contents of the dump by looking at the offsets of the methods.
1147 for (uint32_t m : hot_methods) {
1148 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1149 ASSERT_NE(pos, std::string::npos);
1150 EXPECT_LT(pos, startup_offset);
1151 }
1152 for (uint32_t m : startup_methods) {
1153 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1154 ASSERT_NE(pos, std::string::npos);
1155 EXPECT_LT(pos, post_startup_offset);
1156 }
1157 for (uint32_t m : post_startup_methods) {
1158 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1159 ASSERT_NE(pos, std::string::npos);
1160 EXPECT_LT(pos, classes_offset);
1161 }
1162}
1163
Calin Juravlee10c1e22018-01-26 20:10:15 -08001164TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1165 ScratchFile profile1;
1166 ScratchFile profile2;
1167 ScratchFile reference_profile;
1168
1169 std::vector<int> profile_fds({
1170 GetFd(profile1),
1171 GetFd(profile2)});
1172 int reference_profile_fd = GetFd(reference_profile);
1173
1174 // Use a real dex file to generate profile test data.
1175 // The file will be used during merging to filter unwanted data.
1176 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1177 const DexFile& d1 = *dex_files[0];
1178 const DexFile& d2 = *dex_files[1];
1179 // The new profile info will contain the methods with indices 0-100.
1180 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1181 ProfileCompilationInfo info1;
1182 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1183 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1184 ProfileCompilationInfo info2;
1185 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2,
1186 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1187
1188
1189 // The reference profile info will contain the methods with indices 50-150.
1190 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1191 ProfileCompilationInfo reference_info;
1192 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1193 kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1194 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1195
1196 // Run profman and pass the dex file with --apk-fd.
1197 android::base::unique_fd apk_fd(
1198 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1199 ASSERT_GE(apk_fd.get(), 0);
1200
1201 std::string profman_cmd = GetProfmanCmd();
1202 std::vector<std::string> argv_str;
1203 argv_str.push_back(profman_cmd);
1204 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1205 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1206 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1207 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1208 std::string error;
1209
1210 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1211
1212 // Verify that we can load the result.
1213
1214 ProfileCompilationInfo result;
1215 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1216 ASSERT_TRUE(result.Load(reference_profile_fd));
1217
1218
1219 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1220 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1221 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1222
1223 // Verify that the result filtered out data not belonging to the dex file.
1224 // This is equivalent to checking that the result is equal to the merging of
1225 // all profiles while filtering out data not belonging to the dex file.
1226
1227 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1228 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1229 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation())
1230 && checksum == d1.GetLocationChecksum())
1231 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation())
1232 && checksum == d2.GetLocationChecksum());
1233 };
1234
1235 ProfileCompilationInfo info1_filter;
1236 ProfileCompilationInfo info2_filter;
1237 ProfileCompilationInfo expected;
1238
1239 info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn);
1240 info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn);
1241 expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn);
1242
1243 ASSERT_TRUE(expected.MergeWith(info1_filter));
1244 ASSERT_TRUE(expected.MergeWith(info2_filter));
1245
1246 ASSERT_TRUE(expected.Equals(result));
1247}
1248
Calin Juravle02c08792018-02-15 19:40:48 -08001249TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1250 ScratchFile profile1;
1251 ScratchFile reference_profile;
1252
1253 // Use a real dex file to generate profile test data. During the copy-and-update the
1254 // matching is done based on checksum so we have to match with the real thing.
1255 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1256 const DexFile& d1 = *dex_files[0];
1257 const DexFile& d2 = *dex_files[1];
1258
1259 ProfileCompilationInfo info1;
1260 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1261 SetupProfile("fake-location1",
1262 d1.GetLocationChecksum(),
1263 "fake-location2",
1264 d2.GetLocationChecksum(),
1265 num_methods_to_add,
1266 /*num_classes*/ 0,
1267 profile1,
1268 &info1,
1269 /*start_method_index*/ 0,
1270 /*reverse_dex_write_order*/ false,
1271 /*number_of_methods1*/ d1.NumMethodIds(),
1272 /*number_of_methods2*/ d2.NumMethodIds());
1273
1274 // Run profman and pass the dex file with --apk-fd.
1275 android::base::unique_fd apk_fd(
1276 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1277 ASSERT_GE(apk_fd.get(), 0);
1278
1279 std::string profman_cmd = GetProfmanCmd();
1280 std::vector<std::string> argv_str;
1281 argv_str.push_back(profman_cmd);
1282 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1283 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1284 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1285 argv_str.push_back("--copy-and-update-profile-key");
1286 std::string error;
1287
1288 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1289
1290 // Verify that we can load the result.
1291 ProfileCompilationInfo result;
1292 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1293 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1294
1295 // Verify that the renaming was done.
1296 for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1297 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1298 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i;
1299 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i;
1300
1301 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr);
1302 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr);
1303 }
1304}
1305
Calin Juravle2e2db782016-02-23 12:00:03 +00001306} // namespace art