blob: 17b7af17a2832962446dfa0d774f00ae4056aec2 [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"
David Sehrc431b9d2018-03-02 12:01:51 -080022#include "base/utils.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000023#include "common_runtime_test.h"
David Sehrb2ec9f52018-02-21 13:20:31 -080024#include "dex/descriptors_names.h"
David Sehr97c381e2017-02-01 15:09:58 -080025#include "exec_utils.h"
Calin Juravlecc3171a2017-05-19 16:47:53 -070026#include "linear_alloc.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080027#include "mirror/class-inl.h"
Mathieu Chartierd808e8b2017-03-21 13:37:41 -070028#include "obj_ptr-inl.h"
David Sehr82d046e2018-04-23 08:14:19 -070029#include "profile/profile_compilation_info.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080030#include "profile_assistant.h"
31#include "scoped_thread_state_change-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000032
33namespace art {
34
Calin Juravleee9cb412018-02-13 20:32:35 -080035using Hotness = ProfileCompilationInfo::MethodHotness;
36
Mathieu Chartierea650f32017-05-24 12:04:13 -070037static constexpr size_t kMaxMethodIds = 65535;
38
Calin Juravle2e2db782016-02-23 12:00:03 +000039class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070040 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070041 void PostRuntimeCreate() OVERRIDE {
Vladimir Marko69d310e2017-10-09 14:12:23 +010042 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
Calin Juravlecc3171a2017-05-19 16:47:53 -070043 }
44
Calin Juravle2e2db782016-02-23 12:00:03 +000045 protected:
46 void SetupProfile(const std::string& id,
47 uint32_t checksum,
48 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010049 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000050 const ScratchFile& profile,
51 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070052 uint16_t start_method_index = 0,
53 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000054 std::string dex_location1 = "location1" + id;
55 uint32_t dex_location_checksum1 = checksum;
56 std::string dex_location2 = "location2" + id;
57 uint32_t dex_location_checksum2 = 10 * checksum;
Calin Juravlee10c1e22018-01-26 20:10:15 -080058 SetupProfile(dex_location1,
59 dex_location_checksum1,
60 dex_location2,
61 dex_location_checksum2,
62 number_of_methods,
63 number_of_classes,
64 profile,
65 info,
66 start_method_index,
67 reverse_dex_write_order);
68 }
69
70 void SetupProfile(const std::string& dex_location1,
71 uint32_t dex_location_checksum1,
72 const std::string& dex_location2,
73 uint32_t dex_location_checksum2,
74 uint16_t number_of_methods,
75 uint16_t number_of_classes,
76 const ScratchFile& profile,
77 ProfileCompilationInfo* info,
78 uint16_t start_method_index = 0,
Calin Juravle02c08792018-02-15 19:40:48 -080079 bool reverse_dex_write_order = false,
80 uint32_t number_of_methods1 = kMaxMethodIds,
81 uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravle2e2db782016-02-23 12:00:03 +000082 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070083 // reverse_dex_write_order controls the order in which the dex files will be added to
84 // the profile and thus written to disk.
85 ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
86 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -080087 dex_location2, dex_location_checksum2,
88 number_of_methods1, number_of_methods2);
Calin Juravleee9cb412018-02-13 20:32:35 -080089 Hotness::Flag flags = Hotness::kFlagPostStartup;
Calin Juravlecea9e9d2017-03-23 19:04:59 -070090 if (reverse_dex_write_order) {
Calin Juravleee9cb412018-02-13 20:32:35 -080091 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080092 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -080093 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080094 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070095 } else {
Calin Juravleee9cb412018-02-13 20:32:35 -080096 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080097 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -080098 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080099 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700100 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000101 }
Calin Juravlec824b512016-03-29 20:33:33 +0100102 for (uint16_t i = 0; i < number_of_classes; i++) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700103 ASSERT_TRUE(info->AddClassIndex(dex_location1,
104 dex_location_checksum1,
105 dex::TypeIndex(i),
Calin Juravle02c08792018-02-15 19:40:48 -0800106 number_of_methods1));
Calin Juravlec824b512016-03-29 20:33:33 +0100107 }
108
Calin Juravle2e2db782016-02-23 12:00:03 +0000109 ASSERT_TRUE(info->Save(GetFd(profile)));
110 ASSERT_EQ(0, profile.GetFile()->Flush());
111 ASSERT_TRUE(profile.GetFile()->ResetOffset());
112 }
113
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700114 void SetupBasicProfile(const std::string& id,
115 uint32_t checksum,
116 uint16_t number_of_methods,
117 const std::vector<uint32_t> hot_methods,
118 const std::vector<uint32_t> startup_methods,
119 const std::vector<uint32_t> post_startup_methods,
120 const ScratchFile& profile,
121 ProfileCompilationInfo* info) {
122 std::string dex_location = "location1" + id;
123 for (uint32_t idx : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700124 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700125 }
126 for (uint32_t idx : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700127 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700128 }
129 for (uint32_t idx : post_startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700130 info->AddMethodIndex(Hotness::kFlagPostStartup,
131 dex_location,
132 checksum,
133 idx,
134 number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700135 }
136 ASSERT_TRUE(info->Save(GetFd(profile)));
137 ASSERT_EQ(0, profile.GetFile()->Flush());
138 ASSERT_TRUE(profile.GetFile()->ResetOffset());
139 }
140
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700141 // Creates an inline cache which will be destructed at the end of the test.
142 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
143 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100144 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700145 return used_inline_caches.back().get();
146 }
147
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700148 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
149 const std::string& dex_location1, uint32_t dex_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -0800150 const std::string& dex_location2, uint32_t dex_checksum2,
151 uint32_t number_of_methods1 = kMaxMethodIds, uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700152 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
153 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Calin Juravle02c08792018-02-15 19:40:48 -0800154 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, number_of_methods1);
155 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, number_of_methods2);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700156
157 // Monomorphic
158 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100159 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700160 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700161 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700162 }
163 // Polymorphic
164 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100165 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700166 dex_pc_data.AddClass(0, dex::TypeIndex(0));
167 dex_pc_data.AddClass(1, dex::TypeIndex(1));
168
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700169 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700170 }
171 // Megamorphic
172 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100173 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700174 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700175 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700176 }
177 // Missing types
178 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100179 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700180 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700181 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700182 }
183
184 return pmi;
185 }
186
Calin Juravle2e2db782016-02-23 12:00:03 +0000187 int GetFd(const ScratchFile& file) const {
188 return static_cast<int>(file.GetFd());
189 }
190
191 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
192 ProfileCompilationInfo file_info;
193 ASSERT_TRUE(file.GetFile()->ResetOffset());
194 ASSERT_TRUE(file_info.Load(GetFd(file)));
195 ASSERT_TRUE(file_info.Equals(info));
196 }
197
Calin Juravle7bcdb532016-06-07 16:14:47 +0100198 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000199 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000200 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000201 if (kIsDebugBuild) {
202 file_path += "d";
203 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100204 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
205 << file_path << " should be a valid file path";
206 return file_path;
207 }
Mathieu Chartierf70fe3d2017-06-21 15:24:02 -0700208
Calin Juravle7bcdb532016-06-07 16:14:47 +0100209 // Runs test with given arguments.
210 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
211 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000212 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100213 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000214 for (size_t k = 0; k < profiles_fd.size(); k++) {
215 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
216 }
217 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
218
219 std::string error;
220 return ExecAndReturnCode(argv_str, &error);
221 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100222
223 bool GenerateTestProfile(const std::string& filename) {
224 std::string profman_cmd = GetProfmanCmd();
225 std::vector<std::string> argv_str;
226 argv_str.push_back(profman_cmd);
227 argv_str.push_back("--generate-test-profile=" + filename);
228 std::string error;
229 return ExecAndReturnCode(argv_str, &error);
230 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800231
Jeff Haof0a31f82017-03-27 15:50:37 -0700232 bool GenerateTestProfileWithInputDex(const std::string& filename) {
233 std::string profman_cmd = GetProfmanCmd();
234 std::vector<std::string> argv_str;
235 argv_str.push_back(profman_cmd);
236 argv_str.push_back("--generate-test-profile=" + filename);
237 argv_str.push_back("--generate-test-profile-seed=0");
238 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
239 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
240 std::string error;
241 return ExecAndReturnCode(argv_str, &error);
242 }
243
Andreas Gampe641a4732017-08-24 13:21:35 -0700244 bool CreateProfile(const std::string& profile_file_contents,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800245 const std::string& filename,
David Brazdilf13ac7c2018-01-30 10:09:08 +0000246 const std::string& dex_location,
247 bool skip_verification) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800248 ScratchFile class_names_file;
249 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800250 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800251 EXPECT_EQ(0, file->Flush());
252 EXPECT_TRUE(file->ResetOffset());
253 std::string profman_cmd = GetProfmanCmd();
254 std::vector<std::string> argv_str;
255 argv_str.push_back(profman_cmd);
256 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
257 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800258 argv_str.push_back("--apk=" + dex_location);
259 argv_str.push_back("--dex-location=" + dex_location);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000260 if (skip_verification) {
261 argv_str.push_back("--skip-apk-verification");
262 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800263 std::string error;
264 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
265 return true;
266 }
267
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700268 bool RunProfman(const std::string& filename,
269 std::vector<std::string>& extra_args,
270 std::string* output) {
271 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800272 std::string profman_cmd = GetProfmanCmd();
273 std::vector<std::string> argv_str;
274 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700275 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800276 argv_str.push_back("--profile-file=" + filename);
277 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800278 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000279 argv_str.push_back("--skip-apk-verification");
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700280 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800281 std::string error;
282 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700283 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800284 EXPECT_EQ(0, file->Flush());
285 EXPECT_TRUE(file->ResetOffset());
286 int64_t length = file->GetLength();
287 std::unique_ptr<char[]> buf(new char[length]);
288 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700289 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800290 return true;
291 }
292
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700293 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
294 std::vector<std::string> extra_args;
295 extra_args.push_back("--dump-classes-and-methods");
296 return RunProfman(filename, extra_args, file_contents);
297 }
298
299 bool DumpOnly(const std::string& filename, std::string* file_contents) {
300 std::vector<std::string> extra_args;
301 extra_args.push_back("--dump-only");
302 return RunProfman(filename, extra_args, file_contents);
303 }
304
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700305 bool CreateAndDump(const std::string& input_file_contents,
306 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800307 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800308 EXPECT_TRUE(CreateProfile(input_file_contents,
309 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000310 GetLibCoreDexFileNames()[0],
311 /* skip_verification */ true));
David Sehr7c80f2d2017-02-07 16:47:58 -0800312 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700313 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800314 return true;
315 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800316
317 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
318 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
319 Thread* self = Thread::Current();
320 ScopedObjectAccess soa(self);
321 StackHandleScope<1> hs(self);
322 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700323 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800324 return class_linker->FindClass(self, clazz.c_str(), h_loader);
325 }
326
327 ArtMethod* GetVirtualMethod(jobject class_loader,
328 const std::string& clazz,
329 const std::string& name) {
330 mirror::Class* klass = GetClass(class_loader, clazz);
331 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
332 const auto pointer_size = class_linker->GetImagePointerSize();
333 ArtMethod* method = nullptr;
334 Thread* self = Thread::Current();
335 ScopedObjectAccess soa(self);
336 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
337 if (name == m.GetName()) {
338 EXPECT_TRUE(method == nullptr);
339 method = &m;
340 }
341 }
342 return method;
343 }
344
345 // Verify that given method has the expected inline caches and nothing else.
346 void AssertInlineCaches(ArtMethod* method,
347 const std::set<mirror::Class*>& expected_clases,
348 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800349 bool is_megamorphic,
350 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800351 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700352 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
353 info.GetMethod(method->GetDexFile()->GetLocation(),
354 method->GetDexFile()->GetLocationChecksum(),
355 method->GetDexMethodIndex());
356 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700357 ASSERT_EQ(pmi->inline_caches->size(), 1u);
358 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800359
Calin Juravle589e71e2017-03-03 16:05:05 -0800360 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
361 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800362 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
363 size_t found = 0;
364 for (mirror::Class* it : expected_clases) {
365 for (const auto& class_ref : dex_pc_data.classes) {
366 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700367 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800368 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
369 class_ref.type_index == it->GetDexTypeIndex()) {
370 found++;
371 }
372 }
373 }
374
375 ASSERT_EQ(expected_clases.size(), found);
376 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700377
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700378 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
379 uint16_t methods_in_ref_profile) {
380 ScratchFile profile;
381 ScratchFile reference_profile;
382 std::vector<int> profile_fds({ GetFd(profile)});
383 int reference_profile_fd = GetFd(reference_profile);
384 std::vector<uint32_t> hot_methods_cur;
385 std::vector<uint32_t> hot_methods_ref;
386 std::vector<uint32_t> empty_vector;
387 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
388 hot_methods_cur.push_back(i);
389 }
390 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
391 hot_methods_ref.push_back(i);
392 }
393 ProfileCompilationInfo info1;
394 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
395 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
396 profile, &info1);
397 ProfileCompilationInfo info2;
398 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
399 reference_profile, &info2);
400 return ProcessProfiles(profile_fds, reference_profile_fd);
401 }
402
403 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
404 uint16_t classes_in_ref_profile) {
405 ScratchFile profile;
406 ScratchFile reference_profile;
407
408 std::vector<int> profile_fds({ GetFd(profile)});
409 int reference_profile_fd = GetFd(reference_profile);
410
411 ProfileCompilationInfo info1;
412 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
413 ProfileCompilationInfo info2;
414 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
415 return ProcessProfiles(profile_fds, reference_profile_fd);
416 }
417
Vladimir Marko69d310e2017-10-09 14:12:23 +0100418 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700419
420 // Cache of inline caches generated during tests.
421 // This makes it easier to pass data between different utilities and ensure that
422 // caches are destructed at the end of the test.
423 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000424};
425
426TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
427 ScratchFile profile1;
428 ScratchFile profile2;
429 ScratchFile reference_profile;
430
431 std::vector<int> profile_fds({
432 GetFd(profile1),
433 GetFd(profile2)});
434 int reference_profile_fd = GetFd(reference_profile);
435
436 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
437 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100438 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000439 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100440 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000441
442 // We should advise compilation.
443 ASSERT_EQ(ProfileAssistant::kCompile,
444 ProcessProfiles(profile_fds, reference_profile_fd));
445 // The resulting compilation info must be equal to the merge of the inputs.
446 ProfileCompilationInfo result;
447 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
448 ASSERT_TRUE(result.Load(reference_profile_fd));
449
450 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000451 ASSERT_TRUE(expected.MergeWith(info1));
452 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000453 ASSERT_TRUE(expected.Equals(result));
454
455 // The information from profiles must remain the same.
456 CheckProfileInfo(profile1, info1);
457 CheckProfileInfo(profile2, info2);
458}
459
Calin Juravlec824b512016-03-29 20:33:33 +0100460// TODO(calin): Add more tests for classes.
461TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
462 ScratchFile profile1;
463 ScratchFile reference_profile;
464
465 std::vector<int> profile_fds({
466 GetFd(profile1)});
467 int reference_profile_fd = GetFd(reference_profile);
468
469 const uint16_t kNumberOfClassesToEnableCompilation = 100;
470 ProfileCompilationInfo info1;
471 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
472
473 // We should advise compilation.
474 ASSERT_EQ(ProfileAssistant::kCompile,
475 ProcessProfiles(profile_fds, reference_profile_fd));
476 // The resulting compilation info must be equal to the merge of the inputs.
477 ProfileCompilationInfo result;
478 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
479 ASSERT_TRUE(result.Load(reference_profile_fd));
480
481 ProfileCompilationInfo expected;
482 ASSERT_TRUE(expected.MergeWith(info1));
483 ASSERT_TRUE(expected.Equals(result));
484
485 // The information from profiles must remain the same.
486 CheckProfileInfo(profile1, info1);
487}
488
Calin Juravle2e2db782016-02-23 12:00:03 +0000489TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
490 ScratchFile profile1;
491 ScratchFile profile2;
492 ScratchFile reference_profile;
493
494 std::vector<int> profile_fds({
495 GetFd(profile1),
496 GetFd(profile2)});
497 int reference_profile_fd = GetFd(reference_profile);
498
499 // The new profile info will contain the methods with indices 0-100.
500 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
501 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100502 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000503 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100504 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000505
506
507 // The reference profile info will contain the methods with indices 50-150.
508 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
509 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100510 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000511 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
512
513 // We should advise compilation.
514 ASSERT_EQ(ProfileAssistant::kCompile,
515 ProcessProfiles(profile_fds, reference_profile_fd));
516
517 // The resulting compilation info must be equal to the merge of the inputs
518 ProfileCompilationInfo result;
519 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
520 ASSERT_TRUE(result.Load(reference_profile_fd));
521
522 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000523 ASSERT_TRUE(expected.MergeWith(info1));
524 ASSERT_TRUE(expected.MergeWith(info2));
525 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000526 ASSERT_TRUE(expected.Equals(result));
527
528 // The information from profiles must remain the same.
529 CheckProfileInfo(profile1, info1);
530 CheckProfileInfo(profile2, info2);
531}
532
533TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
534 ScratchFile profile1;
535 ScratchFile profile2;
536 ScratchFile reference_profile;
537
538 std::vector<int> profile_fds({
539 GetFd(profile1),
540 GetFd(profile2)});
541 int reference_profile_fd = GetFd(reference_profile);
542
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700543 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000544 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100545 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000546 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100547 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000548
549 // We should not advise compilation.
550 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
551 ProcessProfiles(profile_fds, reference_profile_fd));
552
553 // The information from profiles must remain the same.
554 ProfileCompilationInfo file_info1;
555 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
556 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
557 ASSERT_TRUE(file_info1.Equals(info1));
558
559 ProfileCompilationInfo file_info2;
560 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
561 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
562 ASSERT_TRUE(file_info2.Equals(info2));
563
564 // Reference profile files must remain empty.
565 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
566
567 // The information from profiles must remain the same.
568 CheckProfileInfo(profile1, info1);
569 CheckProfileInfo(profile2, info2);
570}
571
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700572TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
573 const uint16_t kNumberOfMethodsInRefProfile = 6000;
574 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
575 // We should not advise compilation.
576 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
577 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
578 kNumberOfMethodsInRefProfile));
579}
580
581TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
582 const uint16_t kNumberOfMethodsInRefProfile = 6000;
583 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
584 // We should advise compilation.
585 ASSERT_EQ(ProfileAssistant::kCompile,
586 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
587 kNumberOfMethodsInRefProfile));
588}
589
590TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
591 const uint16_t kNumberOfClassesInRefProfile = 6000;
592 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
593 // We should not advise compilation.
594 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
595 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
596 kNumberOfClassesInRefProfile));
597}
598
599TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
600 const uint16_t kNumberOfClassesInRefProfile = 6000;
601 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
602 // We should advise compilation.
603 ASSERT_EQ(ProfileAssistant::kCompile,
604 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
605 kNumberOfClassesInRefProfile));
606}
607
Calin Juravle2e2db782016-02-23 12:00:03 +0000608TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
609 ScratchFile profile1;
610 ScratchFile profile2;
611 ScratchFile reference_profile;
612
613 std::vector<int> profile_fds({
614 GetFd(profile1),
615 GetFd(profile2)});
616 int reference_profile_fd = GetFd(reference_profile);
617
618 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
619 // Assign different hashes for the same dex file. This will make merging of information to fail.
620 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100621 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000622 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100623 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000624
625 // We should fail processing.
626 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
627 ProcessProfiles(profile_fds, reference_profile_fd));
628
629 // The information from profiles must remain the same.
630 CheckProfileInfo(profile1, info1);
631 CheckProfileInfo(profile2, info2);
632
633 // Reference profile files must still remain empty.
634 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
635}
636
637TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
638 ScratchFile profile1;
639 ScratchFile reference_profile;
640
641 std::vector<int> profile_fds({
642 GetFd(profile1)});
643 int reference_profile_fd = GetFd(reference_profile);
644
645 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
646 // Assign different hashes for the same dex file. This will make merging of information to fail.
647 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100648 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000649 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100650 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000651
652 // We should not advise compilation.
653 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
654 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
655 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
656 ProcessProfiles(profile_fds, reference_profile_fd));
657
658 // The information from profiles must remain the same.
659 CheckProfileInfo(profile1, info1);
660}
661
Calin Juravle7bcdb532016-06-07 16:14:47 +0100662TEST_F(ProfileAssistantTest, TestProfileGeneration) {
663 ScratchFile profile;
664 // Generate a test profile.
665 GenerateTestProfile(profile.GetFilename());
666
667 // Verify that the generated profile is valid and can be loaded.
668 ASSERT_TRUE(profile.GetFile()->ResetOffset());
669 ProfileCompilationInfo info;
670 ASSERT_TRUE(info.Load(GetFd(profile)));
671}
672
Jeff Haof0a31f82017-03-27 15:50:37 -0700673TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
674 ScratchFile profile;
675 // Generate a test profile passing in a dex file as reference.
676 GenerateTestProfileWithInputDex(profile.GetFilename());
677
678 // Verify that the generated profile is valid and can be loaded.
679 ASSERT_TRUE(profile.GetFile()->ResetOffset());
680 ProfileCompilationInfo info;
681 ASSERT_TRUE(info.Load(GetFd(profile)));
682}
683
David Sehr7c80f2d2017-02-07 16:47:58 -0800684TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
685 // Class names put here need to be in sorted order.
686 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700687 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800688 "Ljava/lang/Comparable;",
689 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700690 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700691 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800692 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700693 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800694 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700695 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800696 }
697 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700698 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
699 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800700}
701
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700702TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
703 // Class names put here need to be in sorted order.
704 std::vector<std::string> class_names = {
705 "Ljava/lang/Math;->*",
706 };
707 std::string input_file_contents;
708 std::string expected_contents;
709 for (std::string& class_name : class_names) {
710 input_file_contents += class_name + std::string("\n");
711 expected_contents += DescriptorToDot(class_name.c_str()) +
712 std::string("\n");
713 }
714 std::string output_file_contents;
715 ScratchFile profile_file;
716 EXPECT_TRUE(CreateProfile(input_file_contents,
717 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000718 GetLibCoreDexFileNames()[0],
719 /* skip_verification */ true));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700720 ProfileCompilationInfo info;
721 profile_file.GetFile()->ResetOffset();
722 ASSERT_TRUE(info.Load(GetFd(profile_file)));
723 // Verify that the profile has matching methods.
724 ScopedObjectAccess soa(Thread::Current());
725 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
726 ASSERT_TRUE(klass != nullptr);
727 size_t method_count = 0;
728 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
729 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
730 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700731 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
732 info.GetMethod(method.GetDexFile()->GetLocation(),
733 method.GetDexFile()->GetLocationChecksum(),
734 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700735 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700736 }
737 }
738 EXPECT_GT(method_count, 0u);
739}
740
Mathieu Chartier2f794552017-06-19 10:58:08 -0700741TEST_F(ProfileAssistantTest, TestBootImageProfile) {
742 const std::string core_dex = GetLibCoreDexFileNames()[0];
743
744 std::vector<ScratchFile> profiles;
745
746 // In image with enough clean occurrences.
747 const std::string kCleanClass = "Ljava/lang/CharSequence;";
748 // In image with enough dirty occurrences.
749 const std::string kDirtyClass = "Ljava/lang/Object;";
750 // Not in image becauseof not enough occurrences.
751 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
752 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
753 // Method that is hot.
754 // Also adds the class through inference since it is in each dex.
755 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
756 // Method that doesn't add the class since its only in one profile. Should still show up in the
757 // boot profile.
758 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700759 // Method that gets marked as hot since it's in multiple profiles.
760 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700761
762 // Thresholds for this test.
763 static const size_t kDirtyThreshold = 3;
764 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700765 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700766
767 // Create a bunch of boot profiles.
768 std::string dex1 =
769 kCleanClass + "\n" +
770 kDirtyClass + "\n" +
771 kUncommonCleanClass + "\n" +
772 "H" + kHotMethod + "\n" +
773 kUncommonDirtyClass;
774 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000775 EXPECT_TRUE(CreateProfile(
776 dex1, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700777
778 // Create a bunch of boot profiles.
779 std::string dex2 =
780 kCleanClass + "\n" +
781 kDirtyClass + "\n" +
782 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700783 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700784 kUncommonDirtyClass;
785 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000786 EXPECT_TRUE(CreateProfile(
787 dex2, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700788
789 // Create a bunch of boot profiles.
790 std::string dex3 =
791 "S" + kHotMethod + "\n" +
792 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700793 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700794 kDirtyClass + "\n";
795 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000796 EXPECT_TRUE(CreateProfile(
797 dex3, profiles.back().GetFilename(), core_dex, /* skip_verification */ true));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700798
799 // Generate the boot profile.
800 ScratchFile out_profile;
801 std::vector<std::string> args;
802 args.push_back(GetProfmanCmd());
803 args.push_back("--generate-boot-image-profile");
804 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
805 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700806 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700807 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
808 args.push_back("--apk=" + core_dex);
809 args.push_back("--dex-location=" + core_dex);
David Brazdilf13ac7c2018-01-30 10:09:08 +0000810 args.push_back("--skip-apk-verification");
Mathieu Chartier2f794552017-06-19 10:58:08 -0700811 for (const ScratchFile& profile : profiles) {
812 args.push_back("--profile-file=" + profile.GetFilename());
813 }
814 std::string error;
815 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
816 ASSERT_EQ(0, out_profile.GetFile()->Flush());
817 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
818
819 // Verify the boot profile contents.
820 std::string output_file_contents;
821 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
822 // Common classes, should be in the classes of the profile.
823 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
824 << output_file_contents;
825 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
826 << output_file_contents;
827 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
828 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
829 << output_file_contents;
830 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
831 << output_file_contents;
832 // Inferred class from a method common to all three profiles.
833 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
834 << output_file_contents;
835 // Aggregated methods hotness information.
836 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
837 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700838 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700839 << output_file_contents;
840 // Not inferred class, method is only in one profile.
841 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
842 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700843 // Test the sampled methods that became hot.
844 // Other method is in only one profile, it should not become hot.
845 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
846 << output_file_contents;
847 // Multi method is in at least two profiles, it should become hot.
848 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
849 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700850}
851
David Sehr7c80f2d2017-02-07 16:47:58 -0800852TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
853 // Class names put here need to be in sorted order.
854 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800855 "Ldoesnt/match/this/one;",
856 "Ljava/lang/Comparable;",
857 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800858 };
859 std::string input_file_contents;
860 for (std::string& class_name : class_names) {
861 input_file_contents += class_name + std::string("\n");
862 }
863 std::string output_file_contents;
864 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
865 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700866 class_names[1] + std::string("\n") +
867 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800868 ASSERT_EQ(output_file_contents, expected_contents);
869}
870
871TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
872 // Class names put here need to be in sorted order.
873 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800874 "Ldoesnt/match/this/one;",
875 "Ldoesnt/match/this/one/either;",
876 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800877 };
878 std::string input_file_contents;
879 for (std::string& class_name : class_names) {
880 input_file_contents += class_name + std::string("\n");
881 }
882 std::string output_file_contents;
883 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
884 std::string expected_contents("");
885 ASSERT_EQ(output_file_contents, expected_contents);
886}
887
Calin Juravlee0ac1152017-02-13 19:03:47 -0800888TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
889 // Create the profile content.
890 std::vector<std::string> methods = {
891 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
892 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
893 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800894 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800895 "LTestInline;->noInlineCache(LSuper;)I"
896 };
897 std::string input_file_contents;
898 for (std::string& m : methods) {
899 input_file_contents += m + std::string("\n");
900 }
901
902 // Create the profile and save it to disk.
903 ScratchFile profile_file;
904 ASSERT_TRUE(CreateProfile(input_file_contents,
905 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +0000906 GetTestDexFileName("ProfileTestMultiDex"),
907 /* skip_verification */ false));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800908
909 // Load the profile from disk.
910 ProfileCompilationInfo info;
911 profile_file.GetFile()->ResetOffset();
912 ASSERT_TRUE(info.Load(GetFd(profile_file)));
913
914 // Load the dex files and verify that the profile contains the expected methods info.
915 ScopedObjectAccess soa(Thread::Current());
916 jobject class_loader = LoadDex("ProfileTestMultiDex");
917 ASSERT_NE(class_loader, nullptr);
918
919 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
920 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
921 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
922
923 ASSERT_TRUE(sub_a != nullptr);
924 ASSERT_TRUE(sub_b != nullptr);
925 ASSERT_TRUE(sub_c != nullptr);
926
927 {
928 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
929 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
930 "LTestInline;",
931 "inlineMonomorphic");
932 ASSERT_TRUE(inline_monomorphic != nullptr);
933 std::set<mirror::Class*> expected_monomorphic;
934 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800935 AssertInlineCaches(inline_monomorphic,
936 expected_monomorphic,
937 info,
938 /*megamorphic*/false,
939 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800940 }
941
942 {
943 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
944 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
945 "LTestInline;",
946 "inlinePolymorphic");
947 ASSERT_TRUE(inline_polymorhic != nullptr);
948 std::set<mirror::Class*> expected_polymorphic;
949 expected_polymorphic.insert(sub_a);
950 expected_polymorphic.insert(sub_b);
951 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800952 AssertInlineCaches(inline_polymorhic,
953 expected_polymorphic,
954 info,
955 /*megamorphic*/false,
956 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800957 }
958
959 {
960 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
961 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
962 "LTestInline;",
963 "inlineMegamorphic");
964 ASSERT_TRUE(inline_megamorphic != nullptr);
965 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800966 AssertInlineCaches(inline_megamorphic,
967 expected_megamorphic,
968 info,
969 /*megamorphic*/true,
970 /*missing_types*/false);
971 }
972
973 {
974 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
975 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
976 "LTestInline;",
977 "inlineMissingTypes");
978 ASSERT_TRUE(inline_missing_types != nullptr);
979 std::set<mirror::Class*> expected_missing_Types;
980 AssertInlineCaches(inline_missing_types,
981 expected_missing_Types,
982 info,
983 /*megamorphic*/false,
984 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800985 }
986
987 {
988 // Verify that method noInlineCache has no inline caches in the profile.
989 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
990 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700991 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
992 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
993 no_inline_cache->GetDexFile()->GetLocationChecksum(),
994 no_inline_cache->GetDexMethodIndex());
995 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700996 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800997 }
998}
999
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001000TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
1001 ScratchFile profile1;
1002 ScratchFile reference_profile;
1003
1004 std::vector<int> profile_fds({GetFd(profile1)});
1005 int reference_profile_fd = GetFd(reference_profile);
1006
1007 // The new profile info will contain the methods with indices 0-100.
1008 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1009 ProfileCompilationInfo info1;
1010 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1011 /*start_method_index*/0, /*reverse_dex_write_order*/false);
1012
1013 // The reference profile info will contain the methods with indices 50-150.
1014 // When setting up the profile reverse the order in which the dex files
1015 // are added to the profile. This will verify that profman merges profiles
1016 // with a different dex order correctly.
1017 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1018 ProfileCompilationInfo reference_info;
1019 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1020 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
1021
1022 // We should advise compilation.
1023 ASSERT_EQ(ProfileAssistant::kCompile,
1024 ProcessProfiles(profile_fds, reference_profile_fd));
1025
1026 // The resulting compilation info must be equal to the merge of the inputs.
1027 ProfileCompilationInfo result;
1028 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1029 ASSERT_TRUE(result.Load(reference_profile_fd));
1030
1031 ProfileCompilationInfo expected;
1032 ASSERT_TRUE(expected.MergeWith(reference_info));
1033 ASSERT_TRUE(expected.MergeWith(info1));
1034 ASSERT_TRUE(expected.Equals(result));
1035
1036 // The information from profile must remain the same.
1037 CheckProfileInfo(profile1, info1);
1038}
1039
Calin Juravle08556882017-05-26 16:40:45 -07001040TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1041 // Create the profile content.
1042 std::vector<std::string> profile_methods = {
1043 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1044 "LTestInline;->invalid_method",
1045 "invalid_class"
1046 };
1047 std::string input_file_contents;
1048 for (std::string& m : profile_methods) {
1049 input_file_contents += m + std::string("\n");
1050 }
1051
1052 // Create the profile and save it to disk.
1053 ScratchFile profile_file;
1054 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1055 ASSERT_TRUE(CreateProfile(input_file_contents,
1056 profile_file.GetFilename(),
David Brazdilf13ac7c2018-01-30 10:09:08 +00001057 dex_filename,
1058 /* skip_verification */ false));
Calin Juravle08556882017-05-26 16:40:45 -07001059
1060 // Load the profile from disk.
1061 ProfileCompilationInfo info;
1062 profile_file.GetFile()->ResetOffset();
1063 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1064
1065 // Load the dex files and verify that the profile contains the expected methods info.
1066 ScopedObjectAccess soa(Thread::Current());
1067 jobject class_loader = LoadDex("ProfileTestMultiDex");
1068 ASSERT_NE(class_loader, nullptr);
1069
1070 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1071 "LTestInline;",
1072 "inlineMonomorphic");
1073 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1074
1075 // Verify that the inline cache contains the invalid type.
1076 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1077 info.GetMethod(dex_file->GetLocation(),
1078 dex_file->GetLocationChecksum(),
1079 inline_monomorphic->GetDexMethodIndex());
1080 ASSERT_TRUE(pmi != nullptr);
1081 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1082 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1083 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1084 ASSERT_EQ(1u, dex_pc_data.classes.size());
1085 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1086
1087 // Verify that the start-up classes contain the invalid class.
1088 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001089 std::set<uint16_t> hot_methods;
1090 std::set<uint16_t> startup_methods;
1091 std::set<uint16_t> post_start_methods;
1092 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1093 &classes,
1094 &hot_methods,
1095 &startup_methods,
1096 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001097 ASSERT_EQ(1u, classes.size());
1098 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1099
Calin Juravleee9cb412018-02-13 20:32:35 -08001100 // Verify that the invalid method did not get in the profile.
1101 ASSERT_EQ(1u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001102 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Calin Juravleee9cb412018-02-13 20:32:35 -08001103 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001104}
1105
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001106TEST_F(ProfileAssistantTest, DumpOnly) {
1107 ScratchFile profile;
1108
1109 const uint32_t kNumberOfMethods = 64;
1110 std::vector<uint32_t> hot_methods;
1111 std::vector<uint32_t> startup_methods;
1112 std::vector<uint32_t> post_startup_methods;
1113 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1114 if (i % 2 == 0) {
1115 hot_methods.push_back(i);
1116 }
1117 if (i % 3 == 1) {
1118 startup_methods.push_back(i);
1119 }
1120 if (i % 4 == 2) {
1121 post_startup_methods.push_back(i);
1122 }
1123 }
1124 EXPECT_GT(hot_methods.size(), 0u);
1125 EXPECT_GT(startup_methods.size(), 0u);
1126 EXPECT_GT(post_startup_methods.size(), 0u);
1127 ProfileCompilationInfo info1;
1128 SetupBasicProfile("p1",
1129 1,
1130 kNumberOfMethods,
1131 hot_methods,
1132 startup_methods,
1133 post_startup_methods,
1134 profile,
1135 &info1);
1136 std::string output;
1137 DumpOnly(profile.GetFilename(), &output);
1138 const size_t hot_offset = output.find("hot methods:");
1139 const size_t startup_offset = output.find("startup methods:");
1140 const size_t post_startup_offset = output.find("post startup methods:");
1141 const size_t classes_offset = output.find("classes:");
1142 ASSERT_NE(hot_offset, std::string::npos);
1143 ASSERT_NE(startup_offset, std::string::npos);
1144 ASSERT_NE(post_startup_offset, std::string::npos);
1145 ASSERT_LT(hot_offset, startup_offset);
1146 ASSERT_LT(startup_offset, post_startup_offset);
1147 // Check the actual contents of the dump by looking at the offsets of the methods.
1148 for (uint32_t m : hot_methods) {
1149 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001150 ASSERT_NE(pos, std::string::npos) << output;
1151 EXPECT_LT(pos, startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001152 }
1153 for (uint32_t m : startup_methods) {
1154 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001155 ASSERT_NE(pos, std::string::npos) << output;
1156 EXPECT_LT(pos, post_startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001157 }
1158 for (uint32_t m : post_startup_methods) {
1159 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001160 ASSERT_NE(pos, std::string::npos) << output;
1161 EXPECT_LT(pos, classes_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001162 }
1163}
1164
Calin Juravlee10c1e22018-01-26 20:10:15 -08001165TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1166 ScratchFile profile1;
1167 ScratchFile profile2;
1168 ScratchFile reference_profile;
1169
1170 std::vector<int> profile_fds({
1171 GetFd(profile1),
1172 GetFd(profile2)});
1173 int reference_profile_fd = GetFd(reference_profile);
1174
1175 // Use a real dex file to generate profile test data.
1176 // The file will be used during merging to filter unwanted data.
1177 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1178 const DexFile& d1 = *dex_files[0];
1179 const DexFile& d2 = *dex_files[1];
1180 // The new profile info will contain the methods with indices 0-100.
1181 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1182 ProfileCompilationInfo info1;
1183 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1184 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1185 ProfileCompilationInfo info2;
1186 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2,
1187 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1188
1189
1190 // The reference profile info will contain the methods with indices 50-150.
1191 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1192 ProfileCompilationInfo reference_info;
1193 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1194 kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1195 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1196
1197 // Run profman and pass the dex file with --apk-fd.
1198 android::base::unique_fd apk_fd(
1199 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1200 ASSERT_GE(apk_fd.get(), 0);
1201
1202 std::string profman_cmd = GetProfmanCmd();
1203 std::vector<std::string> argv_str;
1204 argv_str.push_back(profman_cmd);
1205 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1206 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1207 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1208 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1209 std::string error;
1210
1211 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1212
1213 // Verify that we can load the result.
1214
1215 ProfileCompilationInfo result;
1216 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1217 ASSERT_TRUE(result.Load(reference_profile_fd));
1218
1219
1220 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1221 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1222 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1223
1224 // Verify that the result filtered out data not belonging to the dex file.
1225 // This is equivalent to checking that the result is equal to the merging of
1226 // all profiles while filtering out data not belonging to the dex file.
1227
1228 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1229 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1230 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation())
1231 && checksum == d1.GetLocationChecksum())
1232 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation())
1233 && checksum == d2.GetLocationChecksum());
1234 };
1235
1236 ProfileCompilationInfo info1_filter;
1237 ProfileCompilationInfo info2_filter;
1238 ProfileCompilationInfo expected;
1239
1240 info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn);
1241 info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn);
1242 expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn);
1243
1244 ASSERT_TRUE(expected.MergeWith(info1_filter));
1245 ASSERT_TRUE(expected.MergeWith(info2_filter));
1246
1247 ASSERT_TRUE(expected.Equals(result));
1248}
1249
Calin Juravle02c08792018-02-15 19:40:48 -08001250TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1251 ScratchFile profile1;
1252 ScratchFile reference_profile;
1253
1254 // Use a real dex file to generate profile test data. During the copy-and-update the
1255 // matching is done based on checksum so we have to match with the real thing.
1256 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1257 const DexFile& d1 = *dex_files[0];
1258 const DexFile& d2 = *dex_files[1];
1259
1260 ProfileCompilationInfo info1;
1261 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1262 SetupProfile("fake-location1",
1263 d1.GetLocationChecksum(),
1264 "fake-location2",
1265 d2.GetLocationChecksum(),
1266 num_methods_to_add,
1267 /*num_classes*/ 0,
1268 profile1,
1269 &info1,
1270 /*start_method_index*/ 0,
1271 /*reverse_dex_write_order*/ false,
1272 /*number_of_methods1*/ d1.NumMethodIds(),
1273 /*number_of_methods2*/ d2.NumMethodIds());
1274
1275 // Run profman and pass the dex file with --apk-fd.
1276 android::base::unique_fd apk_fd(
1277 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1278 ASSERT_GE(apk_fd.get(), 0);
1279
1280 std::string profman_cmd = GetProfmanCmd();
1281 std::vector<std::string> argv_str;
1282 argv_str.push_back(profman_cmd);
1283 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1284 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1285 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1286 argv_str.push_back("--copy-and-update-profile-key");
1287 std::string error;
1288
1289 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1290
1291 // Verify that we can load the result.
1292 ProfileCompilationInfo result;
1293 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1294 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1295
1296 // Verify that the renaming was done.
1297 for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1298 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1299 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i;
1300 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i;
1301
1302 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr);
1303 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr);
1304 }
1305}
1306
Calin Juravle2e2db782016-02-23 12:00:03 +00001307} // namespace art