blob: c6661855bea0707419ea2804d298fd03056ce012 [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 Sehr8f4b0562018-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 Juravle33083d62017-01-18 15:29:12 -080026#include "jit/profile_compilation_info.h"
Calin Juravlecc3171a2017-05-19 16:47:53 -070027#include "linear_alloc.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080028#include "mirror/class-inl.h"
Mathieu Chartierd808e8b2017-03-21 13:37:41 -070029#include "obj_ptr-inl.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,
Calin Juravle40636e82018-04-26 16:00:11 -0700246 const std::string& dex_location) {
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 Sehr7c80f2d2017-02-07 16:47:58 -0800259 std::string error;
260 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
261 return true;
262 }
263
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700264 bool RunProfman(const std::string& filename,
265 std::vector<std::string>& extra_args,
266 std::string* output) {
267 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800268 std::string profman_cmd = GetProfmanCmd();
269 std::vector<std::string> argv_str;
270 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700271 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800272 argv_str.push_back("--profile-file=" + filename);
273 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800274 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700275 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800276 std::string error;
277 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700278 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800279 EXPECT_EQ(0, file->Flush());
280 EXPECT_TRUE(file->ResetOffset());
281 int64_t length = file->GetLength();
282 std::unique_ptr<char[]> buf(new char[length]);
283 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700284 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800285 return true;
286 }
287
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700288 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
289 std::vector<std::string> extra_args;
290 extra_args.push_back("--dump-classes-and-methods");
291 return RunProfman(filename, extra_args, file_contents);
292 }
293
294 bool DumpOnly(const std::string& filename, std::string* file_contents) {
295 std::vector<std::string> extra_args;
296 extra_args.push_back("--dump-only");
297 return RunProfman(filename, extra_args, file_contents);
298 }
299
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700300 bool CreateAndDump(const std::string& input_file_contents,
301 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800302 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800303 EXPECT_TRUE(CreateProfile(input_file_contents,
304 profile_file.GetFilename(),
Calin Juravle40636e82018-04-26 16:00:11 -0700305 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800306 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700307 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800308 return true;
309 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800310
311 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
312 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
313 Thread* self = Thread::Current();
314 ScopedObjectAccess soa(self);
315 StackHandleScope<1> hs(self);
316 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700317 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800318 return class_linker->FindClass(self, clazz.c_str(), h_loader);
319 }
320
321 ArtMethod* GetVirtualMethod(jobject class_loader,
322 const std::string& clazz,
323 const std::string& name) {
324 mirror::Class* klass = GetClass(class_loader, clazz);
325 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
326 const auto pointer_size = class_linker->GetImagePointerSize();
327 ArtMethod* method = nullptr;
328 Thread* self = Thread::Current();
329 ScopedObjectAccess soa(self);
330 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
331 if (name == m.GetName()) {
332 EXPECT_TRUE(method == nullptr);
333 method = &m;
334 }
335 }
336 return method;
337 }
338
339 // Verify that given method has the expected inline caches and nothing else.
340 void AssertInlineCaches(ArtMethod* method,
341 const std::set<mirror::Class*>& expected_clases,
342 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800343 bool is_megamorphic,
344 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800345 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700346 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
347 info.GetMethod(method->GetDexFile()->GetLocation(),
348 method->GetDexFile()->GetLocationChecksum(),
349 method->GetDexMethodIndex());
350 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700351 ASSERT_EQ(pmi->inline_caches->size(), 1u);
352 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800353
Calin Juravle589e71e2017-03-03 16:05:05 -0800354 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
355 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800356 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
357 size_t found = 0;
358 for (mirror::Class* it : expected_clases) {
359 for (const auto& class_ref : dex_pc_data.classes) {
360 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700361 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800362 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
363 class_ref.type_index == it->GetDexTypeIndex()) {
364 found++;
365 }
366 }
367 }
368
369 ASSERT_EQ(expected_clases.size(), found);
370 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700371
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700372 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
373 uint16_t methods_in_ref_profile) {
374 ScratchFile profile;
375 ScratchFile reference_profile;
376 std::vector<int> profile_fds({ GetFd(profile)});
377 int reference_profile_fd = GetFd(reference_profile);
378 std::vector<uint32_t> hot_methods_cur;
379 std::vector<uint32_t> hot_methods_ref;
380 std::vector<uint32_t> empty_vector;
381 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
382 hot_methods_cur.push_back(i);
383 }
384 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
385 hot_methods_ref.push_back(i);
386 }
387 ProfileCompilationInfo info1;
388 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
389 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
390 profile, &info1);
391 ProfileCompilationInfo info2;
392 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
393 reference_profile, &info2);
394 return ProcessProfiles(profile_fds, reference_profile_fd);
395 }
396
397 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
398 uint16_t classes_in_ref_profile) {
399 ScratchFile profile;
400 ScratchFile reference_profile;
401
402 std::vector<int> profile_fds({ GetFd(profile)});
403 int reference_profile_fd = GetFd(reference_profile);
404
405 ProfileCompilationInfo info1;
406 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
407 ProfileCompilationInfo info2;
408 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
409 return ProcessProfiles(profile_fds, reference_profile_fd);
410 }
411
Vladimir Marko69d310e2017-10-09 14:12:23 +0100412 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700413
414 // Cache of inline caches generated during tests.
415 // This makes it easier to pass data between different utilities and ensure that
416 // caches are destructed at the end of the test.
417 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000418};
419
420TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
421 ScratchFile profile1;
422 ScratchFile profile2;
423 ScratchFile reference_profile;
424
425 std::vector<int> profile_fds({
426 GetFd(profile1),
427 GetFd(profile2)});
428 int reference_profile_fd = GetFd(reference_profile);
429
430 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
431 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100432 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000433 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100434 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000435
436 // We should advise compilation.
437 ASSERT_EQ(ProfileAssistant::kCompile,
438 ProcessProfiles(profile_fds, reference_profile_fd));
439 // The resulting compilation info must be equal to the merge of the inputs.
440 ProfileCompilationInfo result;
441 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
442 ASSERT_TRUE(result.Load(reference_profile_fd));
443
444 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000445 ASSERT_TRUE(expected.MergeWith(info1));
446 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000447 ASSERT_TRUE(expected.Equals(result));
448
449 // The information from profiles must remain the same.
450 CheckProfileInfo(profile1, info1);
451 CheckProfileInfo(profile2, info2);
452}
453
Calin Juravlec824b512016-03-29 20:33:33 +0100454// TODO(calin): Add more tests for classes.
455TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
456 ScratchFile profile1;
457 ScratchFile reference_profile;
458
459 std::vector<int> profile_fds({
460 GetFd(profile1)});
461 int reference_profile_fd = GetFd(reference_profile);
462
463 const uint16_t kNumberOfClassesToEnableCompilation = 100;
464 ProfileCompilationInfo info1;
465 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
466
467 // We should advise compilation.
468 ASSERT_EQ(ProfileAssistant::kCompile,
469 ProcessProfiles(profile_fds, reference_profile_fd));
470 // The resulting compilation info must be equal to the merge of the inputs.
471 ProfileCompilationInfo result;
472 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
473 ASSERT_TRUE(result.Load(reference_profile_fd));
474
475 ProfileCompilationInfo expected;
476 ASSERT_TRUE(expected.MergeWith(info1));
477 ASSERT_TRUE(expected.Equals(result));
478
479 // The information from profiles must remain the same.
480 CheckProfileInfo(profile1, info1);
481}
482
Calin Juravle2e2db782016-02-23 12:00:03 +0000483TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
484 ScratchFile profile1;
485 ScratchFile profile2;
486 ScratchFile reference_profile;
487
488 std::vector<int> profile_fds({
489 GetFd(profile1),
490 GetFd(profile2)});
491 int reference_profile_fd = GetFd(reference_profile);
492
493 // The new profile info will contain the methods with indices 0-100.
494 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
495 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100496 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000497 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100498 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000499
500
501 // The reference profile info will contain the methods with indices 50-150.
502 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
503 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100504 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000505 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
506
507 // We should advise compilation.
508 ASSERT_EQ(ProfileAssistant::kCompile,
509 ProcessProfiles(profile_fds, reference_profile_fd));
510
511 // The resulting compilation info must be equal to the merge of the inputs
512 ProfileCompilationInfo result;
513 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
514 ASSERT_TRUE(result.Load(reference_profile_fd));
515
516 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000517 ASSERT_TRUE(expected.MergeWith(info1));
518 ASSERT_TRUE(expected.MergeWith(info2));
519 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000520 ASSERT_TRUE(expected.Equals(result));
521
522 // The information from profiles must remain the same.
523 CheckProfileInfo(profile1, info1);
524 CheckProfileInfo(profile2, info2);
525}
526
527TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
528 ScratchFile profile1;
529 ScratchFile profile2;
530 ScratchFile reference_profile;
531
532 std::vector<int> profile_fds({
533 GetFd(profile1),
534 GetFd(profile2)});
535 int reference_profile_fd = GetFd(reference_profile);
536
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700537 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000538 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100539 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000540 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100541 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000542
543 // We should not advise compilation.
544 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
545 ProcessProfiles(profile_fds, reference_profile_fd));
546
547 // The information from profiles must remain the same.
548 ProfileCompilationInfo file_info1;
549 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
550 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
551 ASSERT_TRUE(file_info1.Equals(info1));
552
553 ProfileCompilationInfo file_info2;
554 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
555 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
556 ASSERT_TRUE(file_info2.Equals(info2));
557
558 // Reference profile files must remain empty.
559 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
560
561 // The information from profiles must remain the same.
562 CheckProfileInfo(profile1, info1);
563 CheckProfileInfo(profile2, info2);
564}
565
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700566TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
567 const uint16_t kNumberOfMethodsInRefProfile = 6000;
568 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
569 // We should not advise compilation.
570 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
571 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
572 kNumberOfMethodsInRefProfile));
573}
574
575TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
576 const uint16_t kNumberOfMethodsInRefProfile = 6000;
577 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
578 // We should advise compilation.
579 ASSERT_EQ(ProfileAssistant::kCompile,
580 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
581 kNumberOfMethodsInRefProfile));
582}
583
584TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
585 const uint16_t kNumberOfClassesInRefProfile = 6000;
586 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
587 // We should not advise compilation.
588 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
589 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
590 kNumberOfClassesInRefProfile));
591}
592
593TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
594 const uint16_t kNumberOfClassesInRefProfile = 6000;
595 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
596 // We should advise compilation.
597 ASSERT_EQ(ProfileAssistant::kCompile,
598 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
599 kNumberOfClassesInRefProfile));
600}
601
Calin Juravle2e2db782016-02-23 12:00:03 +0000602TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
603 ScratchFile profile1;
604 ScratchFile profile2;
605 ScratchFile reference_profile;
606
607 std::vector<int> profile_fds({
608 GetFd(profile1),
609 GetFd(profile2)});
610 int reference_profile_fd = GetFd(reference_profile);
611
612 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
613 // Assign different hashes for the same dex file. This will make merging of information to fail.
614 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100615 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000616 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100617 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000618
619 // We should fail processing.
620 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
621 ProcessProfiles(profile_fds, reference_profile_fd));
622
623 // The information from profiles must remain the same.
624 CheckProfileInfo(profile1, info1);
625 CheckProfileInfo(profile2, info2);
626
627 // Reference profile files must still remain empty.
628 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
629}
630
631TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
632 ScratchFile profile1;
633 ScratchFile reference_profile;
634
635 std::vector<int> profile_fds({
636 GetFd(profile1)});
637 int reference_profile_fd = GetFd(reference_profile);
638
639 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
640 // Assign different hashes for the same dex file. This will make merging of information to fail.
641 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100642 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000643 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100644 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000645
646 // We should not advise compilation.
647 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
648 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
649 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
650 ProcessProfiles(profile_fds, reference_profile_fd));
651
652 // The information from profiles must remain the same.
653 CheckProfileInfo(profile1, info1);
654}
655
Calin Juravle7bcdb532016-06-07 16:14:47 +0100656TEST_F(ProfileAssistantTest, TestProfileGeneration) {
657 ScratchFile profile;
658 // Generate a test profile.
659 GenerateTestProfile(profile.GetFilename());
660
661 // Verify that the generated profile is valid and can be loaded.
662 ASSERT_TRUE(profile.GetFile()->ResetOffset());
663 ProfileCompilationInfo info;
664 ASSERT_TRUE(info.Load(GetFd(profile)));
665}
666
Jeff Haof0a31f82017-03-27 15:50:37 -0700667TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
668 ScratchFile profile;
669 // Generate a test profile passing in a dex file as reference.
670 GenerateTestProfileWithInputDex(profile.GetFilename());
671
672 // Verify that the generated profile is valid and can be loaded.
673 ASSERT_TRUE(profile.GetFile()->ResetOffset());
674 ProfileCompilationInfo info;
675 ASSERT_TRUE(info.Load(GetFd(profile)));
676}
677
David Sehr7c80f2d2017-02-07 16:47:58 -0800678TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
679 // Class names put here need to be in sorted order.
680 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700681 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800682 "Ljava/lang/Comparable;",
683 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700684 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700685 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800686 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700687 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800688 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700689 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800690 }
691 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700692 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
693 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800694}
695
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700696TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
697 // Class names put here need to be in sorted order.
698 std::vector<std::string> class_names = {
699 "Ljava/lang/Math;->*",
700 };
701 std::string input_file_contents;
702 std::string expected_contents;
703 for (std::string& class_name : class_names) {
704 input_file_contents += class_name + std::string("\n");
705 expected_contents += DescriptorToDot(class_name.c_str()) +
706 std::string("\n");
707 }
708 std::string output_file_contents;
709 ScratchFile profile_file;
710 EXPECT_TRUE(CreateProfile(input_file_contents,
711 profile_file.GetFilename(),
Calin Juravle40636e82018-04-26 16:00:11 -0700712 GetLibCoreDexFileNames()[0]));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700713 ProfileCompilationInfo info;
714 profile_file.GetFile()->ResetOffset();
715 ASSERT_TRUE(info.Load(GetFd(profile_file)));
716 // Verify that the profile has matching methods.
717 ScopedObjectAccess soa(Thread::Current());
718 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
719 ASSERT_TRUE(klass != nullptr);
720 size_t method_count = 0;
721 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
722 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
723 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700724 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
725 info.GetMethod(method.GetDexFile()->GetLocation(),
726 method.GetDexFile()->GetLocationChecksum(),
727 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700728 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700729 }
730 }
731 EXPECT_GT(method_count, 0u);
732}
733
Mathieu Chartier2f794552017-06-19 10:58:08 -0700734TEST_F(ProfileAssistantTest, TestBootImageProfile) {
735 const std::string core_dex = GetLibCoreDexFileNames()[0];
736
737 std::vector<ScratchFile> profiles;
738
739 // In image with enough clean occurrences.
740 const std::string kCleanClass = "Ljava/lang/CharSequence;";
741 // In image with enough dirty occurrences.
742 const std::string kDirtyClass = "Ljava/lang/Object;";
743 // Not in image becauseof not enough occurrences.
744 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
745 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
746 // Method that is hot.
747 // Also adds the class through inference since it is in each dex.
748 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
749 // Method that doesn't add the class since its only in one profile. Should still show up in the
750 // boot profile.
751 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700752 // Method that gets marked as hot since it's in multiple profiles.
753 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700754
755 // Thresholds for this test.
756 static const size_t kDirtyThreshold = 3;
757 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700758 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700759
760 // Create a bunch of boot profiles.
761 std::string dex1 =
762 kCleanClass + "\n" +
763 kDirtyClass + "\n" +
764 kUncommonCleanClass + "\n" +
765 "H" + kHotMethod + "\n" +
766 kUncommonDirtyClass;
767 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000768 EXPECT_TRUE(CreateProfile(
Calin Juravle40636e82018-04-26 16:00:11 -0700769 dex1, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700770
771 // Create a bunch of boot profiles.
772 std::string dex2 =
773 kCleanClass + "\n" +
774 kDirtyClass + "\n" +
775 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700776 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700777 kUncommonDirtyClass;
778 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000779 EXPECT_TRUE(CreateProfile(
Calin Juravle40636e82018-04-26 16:00:11 -0700780 dex2, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700781
782 // Create a bunch of boot profiles.
783 std::string dex3 =
784 "S" + kHotMethod + "\n" +
785 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700786 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700787 kDirtyClass + "\n";
788 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000789 EXPECT_TRUE(CreateProfile(
Calin Juravle40636e82018-04-26 16:00:11 -0700790 dex3, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700791
792 // Generate the boot profile.
793 ScratchFile out_profile;
794 std::vector<std::string> args;
795 args.push_back(GetProfmanCmd());
796 args.push_back("--generate-boot-image-profile");
797 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
798 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700799 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700800 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
801 args.push_back("--apk=" + core_dex);
802 args.push_back("--dex-location=" + core_dex);
803 for (const ScratchFile& profile : profiles) {
804 args.push_back("--profile-file=" + profile.GetFilename());
805 }
806 std::string error;
807 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
808 ASSERT_EQ(0, out_profile.GetFile()->Flush());
809 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
810
811 // Verify the boot profile contents.
812 std::string output_file_contents;
813 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
814 // Common classes, should be in the classes of the profile.
815 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
816 << output_file_contents;
817 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
818 << output_file_contents;
819 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
820 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
821 << output_file_contents;
822 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
823 << output_file_contents;
824 // Inferred class from a method common to all three profiles.
825 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
826 << output_file_contents;
827 // Aggregated methods hotness information.
828 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
829 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700830 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700831 << output_file_contents;
832 // Not inferred class, method is only in one profile.
833 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
834 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700835 // Test the sampled methods that became hot.
836 // Other method is in only one profile, it should not become hot.
837 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
838 << output_file_contents;
839 // Multi method is in at least two profiles, it should become hot.
840 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
841 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700842}
843
David Sehr7c80f2d2017-02-07 16:47:58 -0800844TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
845 // Class names put here need to be in sorted order.
846 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800847 "Ldoesnt/match/this/one;",
848 "Ljava/lang/Comparable;",
849 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800850 };
851 std::string input_file_contents;
852 for (std::string& class_name : class_names) {
853 input_file_contents += class_name + std::string("\n");
854 }
855 std::string output_file_contents;
856 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
857 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700858 class_names[1] + std::string("\n") +
859 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800860 ASSERT_EQ(output_file_contents, expected_contents);
861}
862
863TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
864 // Class names put here need to be in sorted order.
865 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800866 "Ldoesnt/match/this/one;",
867 "Ldoesnt/match/this/one/either;",
868 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800869 };
870 std::string input_file_contents;
871 for (std::string& class_name : class_names) {
872 input_file_contents += class_name + std::string("\n");
873 }
874 std::string output_file_contents;
875 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
876 std::string expected_contents("");
877 ASSERT_EQ(output_file_contents, expected_contents);
878}
879
Calin Juravlee0ac1152017-02-13 19:03:47 -0800880TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
881 // Create the profile content.
882 std::vector<std::string> methods = {
883 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
884 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
885 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800886 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800887 "LTestInline;->noInlineCache(LSuper;)I"
888 };
889 std::string input_file_contents;
890 for (std::string& m : methods) {
891 input_file_contents += m + std::string("\n");
892 }
893
894 // Create the profile and save it to disk.
895 ScratchFile profile_file;
896 ASSERT_TRUE(CreateProfile(input_file_contents,
897 profile_file.GetFilename(),
Calin Juravle40636e82018-04-26 16:00:11 -0700898 GetTestDexFileName("ProfileTestMultiDex")));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800899
900 // Load the profile from disk.
901 ProfileCompilationInfo info;
902 profile_file.GetFile()->ResetOffset();
903 ASSERT_TRUE(info.Load(GetFd(profile_file)));
904
905 // Load the dex files and verify that the profile contains the expected methods info.
906 ScopedObjectAccess soa(Thread::Current());
907 jobject class_loader = LoadDex("ProfileTestMultiDex");
908 ASSERT_NE(class_loader, nullptr);
909
910 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
911 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
912 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
913
914 ASSERT_TRUE(sub_a != nullptr);
915 ASSERT_TRUE(sub_b != nullptr);
916 ASSERT_TRUE(sub_c != nullptr);
917
918 {
919 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
920 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
921 "LTestInline;",
922 "inlineMonomorphic");
923 ASSERT_TRUE(inline_monomorphic != nullptr);
924 std::set<mirror::Class*> expected_monomorphic;
925 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800926 AssertInlineCaches(inline_monomorphic,
927 expected_monomorphic,
928 info,
929 /*megamorphic*/false,
930 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800931 }
932
933 {
934 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
935 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
936 "LTestInline;",
937 "inlinePolymorphic");
938 ASSERT_TRUE(inline_polymorhic != nullptr);
939 std::set<mirror::Class*> expected_polymorphic;
940 expected_polymorphic.insert(sub_a);
941 expected_polymorphic.insert(sub_b);
942 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800943 AssertInlineCaches(inline_polymorhic,
944 expected_polymorphic,
945 info,
946 /*megamorphic*/false,
947 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800948 }
949
950 {
951 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
952 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
953 "LTestInline;",
954 "inlineMegamorphic");
955 ASSERT_TRUE(inline_megamorphic != nullptr);
956 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800957 AssertInlineCaches(inline_megamorphic,
958 expected_megamorphic,
959 info,
960 /*megamorphic*/true,
961 /*missing_types*/false);
962 }
963
964 {
965 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
966 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
967 "LTestInline;",
968 "inlineMissingTypes");
969 ASSERT_TRUE(inline_missing_types != nullptr);
970 std::set<mirror::Class*> expected_missing_Types;
971 AssertInlineCaches(inline_missing_types,
972 expected_missing_Types,
973 info,
974 /*megamorphic*/false,
975 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800976 }
977
978 {
979 // Verify that method noInlineCache has no inline caches in the profile.
980 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
981 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700982 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
983 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
984 no_inline_cache->GetDexFile()->GetLocationChecksum(),
985 no_inline_cache->GetDexMethodIndex());
986 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700987 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800988 }
989}
990
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700991TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
992 ScratchFile profile1;
993 ScratchFile reference_profile;
994
995 std::vector<int> profile_fds({GetFd(profile1)});
996 int reference_profile_fd = GetFd(reference_profile);
997
998 // The new profile info will contain the methods with indices 0-100.
999 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1000 ProfileCompilationInfo info1;
1001 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1002 /*start_method_index*/0, /*reverse_dex_write_order*/false);
1003
1004 // The reference profile info will contain the methods with indices 50-150.
1005 // When setting up the profile reverse the order in which the dex files
1006 // are added to the profile. This will verify that profman merges profiles
1007 // with a different dex order correctly.
1008 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1009 ProfileCompilationInfo reference_info;
1010 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1011 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
1012
1013 // We should advise compilation.
1014 ASSERT_EQ(ProfileAssistant::kCompile,
1015 ProcessProfiles(profile_fds, reference_profile_fd));
1016
1017 // The resulting compilation info must be equal to the merge of the inputs.
1018 ProfileCompilationInfo result;
1019 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1020 ASSERT_TRUE(result.Load(reference_profile_fd));
1021
1022 ProfileCompilationInfo expected;
1023 ASSERT_TRUE(expected.MergeWith(reference_info));
1024 ASSERT_TRUE(expected.MergeWith(info1));
1025 ASSERT_TRUE(expected.Equals(result));
1026
1027 // The information from profile must remain the same.
1028 CheckProfileInfo(profile1, info1);
1029}
1030
Calin Juravle08556882017-05-26 16:40:45 -07001031TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1032 // Create the profile content.
1033 std::vector<std::string> profile_methods = {
1034 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1035 "LTestInline;->invalid_method",
1036 "invalid_class"
1037 };
1038 std::string input_file_contents;
1039 for (std::string& m : profile_methods) {
1040 input_file_contents += m + std::string("\n");
1041 }
1042
1043 // Create the profile and save it to disk.
1044 ScratchFile profile_file;
1045 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1046 ASSERT_TRUE(CreateProfile(input_file_contents,
1047 profile_file.GetFilename(),
Calin Juravle40636e82018-04-26 16:00:11 -07001048 dex_filename));
Calin Juravle08556882017-05-26 16:40:45 -07001049
1050 // Load the profile from disk.
1051 ProfileCompilationInfo info;
1052 profile_file.GetFile()->ResetOffset();
1053 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1054
1055 // Load the dex files and verify that the profile contains the expected methods info.
1056 ScopedObjectAccess soa(Thread::Current());
1057 jobject class_loader = LoadDex("ProfileTestMultiDex");
1058 ASSERT_NE(class_loader, nullptr);
1059
1060 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1061 "LTestInline;",
1062 "inlineMonomorphic");
1063 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1064
1065 // Verify that the inline cache contains the invalid type.
1066 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1067 info.GetMethod(dex_file->GetLocation(),
1068 dex_file->GetLocationChecksum(),
1069 inline_monomorphic->GetDexMethodIndex());
1070 ASSERT_TRUE(pmi != nullptr);
1071 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1072 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1073 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1074 ASSERT_EQ(1u, dex_pc_data.classes.size());
1075 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1076
1077 // Verify that the start-up classes contain the invalid class.
1078 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001079 std::set<uint16_t> hot_methods;
1080 std::set<uint16_t> startup_methods;
1081 std::set<uint16_t> post_start_methods;
1082 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1083 &classes,
1084 &hot_methods,
1085 &startup_methods,
1086 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001087 ASSERT_EQ(1u, classes.size());
1088 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1089
Calin Juravleee9cb412018-02-13 20:32:35 -08001090 // Verify that the invalid method did not get in the profile.
1091 ASSERT_EQ(1u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001092 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Calin Juravleee9cb412018-02-13 20:32:35 -08001093 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001094}
1095
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001096TEST_F(ProfileAssistantTest, DumpOnly) {
1097 ScratchFile profile;
1098
1099 const uint32_t kNumberOfMethods = 64;
1100 std::vector<uint32_t> hot_methods;
1101 std::vector<uint32_t> startup_methods;
1102 std::vector<uint32_t> post_startup_methods;
1103 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1104 if (i % 2 == 0) {
1105 hot_methods.push_back(i);
1106 }
1107 if (i % 3 == 1) {
1108 startup_methods.push_back(i);
1109 }
1110 if (i % 4 == 2) {
1111 post_startup_methods.push_back(i);
1112 }
1113 }
1114 EXPECT_GT(hot_methods.size(), 0u);
1115 EXPECT_GT(startup_methods.size(), 0u);
1116 EXPECT_GT(post_startup_methods.size(), 0u);
1117 ProfileCompilationInfo info1;
1118 SetupBasicProfile("p1",
1119 1,
1120 kNumberOfMethods,
1121 hot_methods,
1122 startup_methods,
1123 post_startup_methods,
1124 profile,
1125 &info1);
1126 std::string output;
1127 DumpOnly(profile.GetFilename(), &output);
1128 const size_t hot_offset = output.find("hot methods:");
1129 const size_t startup_offset = output.find("startup methods:");
1130 const size_t post_startup_offset = output.find("post startup methods:");
1131 const size_t classes_offset = output.find("classes:");
1132 ASSERT_NE(hot_offset, std::string::npos);
1133 ASSERT_NE(startup_offset, std::string::npos);
1134 ASSERT_NE(post_startup_offset, std::string::npos);
1135 ASSERT_LT(hot_offset, startup_offset);
1136 ASSERT_LT(startup_offset, post_startup_offset);
1137 // Check the actual contents of the dump by looking at the offsets of the methods.
1138 for (uint32_t m : hot_methods) {
1139 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1140 ASSERT_NE(pos, std::string::npos);
1141 EXPECT_LT(pos, startup_offset);
1142 }
1143 for (uint32_t m : startup_methods) {
1144 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1145 ASSERT_NE(pos, std::string::npos);
1146 EXPECT_LT(pos, post_startup_offset);
1147 }
1148 for (uint32_t m : post_startup_methods) {
1149 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1150 ASSERT_NE(pos, std::string::npos);
1151 EXPECT_LT(pos, classes_offset);
1152 }
1153}
1154
Calin Juravlee10c1e22018-01-26 20:10:15 -08001155TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1156 ScratchFile profile1;
1157 ScratchFile profile2;
1158 ScratchFile reference_profile;
1159
1160 std::vector<int> profile_fds({
1161 GetFd(profile1),
1162 GetFd(profile2)});
1163 int reference_profile_fd = GetFd(reference_profile);
1164
1165 // Use a real dex file to generate profile test data.
1166 // The file will be used during merging to filter unwanted data.
1167 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1168 const DexFile& d1 = *dex_files[0];
1169 const DexFile& d2 = *dex_files[1];
1170 // The new profile info will contain the methods with indices 0-100.
1171 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1172 ProfileCompilationInfo info1;
1173 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1174 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1175 ProfileCompilationInfo info2;
1176 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2,
1177 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1178
1179
1180 // The reference profile info will contain the methods with indices 50-150.
1181 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1182 ProfileCompilationInfo reference_info;
1183 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1184 kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1185 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1186
1187 // Run profman and pass the dex file with --apk-fd.
1188 android::base::unique_fd apk_fd(
1189 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1190 ASSERT_GE(apk_fd.get(), 0);
1191
1192 std::string profman_cmd = GetProfmanCmd();
1193 std::vector<std::string> argv_str;
1194 argv_str.push_back(profman_cmd);
1195 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1196 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1197 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1198 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1199 std::string error;
1200
1201 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1202
1203 // Verify that we can load the result.
1204
1205 ProfileCompilationInfo result;
1206 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1207 ASSERT_TRUE(result.Load(reference_profile_fd));
1208
1209
1210 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1211 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1212 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1213
1214 // Verify that the result filtered out data not belonging to the dex file.
1215 // This is equivalent to checking that the result is equal to the merging of
1216 // all profiles while filtering out data not belonging to the dex file.
1217
1218 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1219 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1220 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation())
1221 && checksum == d1.GetLocationChecksum())
1222 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation())
1223 && checksum == d2.GetLocationChecksum());
1224 };
1225
1226 ProfileCompilationInfo info1_filter;
1227 ProfileCompilationInfo info2_filter;
1228 ProfileCompilationInfo expected;
1229
1230 info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn);
1231 info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn);
1232 expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn);
1233
1234 ASSERT_TRUE(expected.MergeWith(info1_filter));
1235 ASSERT_TRUE(expected.MergeWith(info2_filter));
1236
1237 ASSERT_TRUE(expected.Equals(result));
1238}
1239
Calin Juravle02c08792018-02-15 19:40:48 -08001240TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1241 ScratchFile profile1;
1242 ScratchFile reference_profile;
1243
1244 // Use a real dex file to generate profile test data. During the copy-and-update the
1245 // matching is done based on checksum so we have to match with the real thing.
1246 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1247 const DexFile& d1 = *dex_files[0];
1248 const DexFile& d2 = *dex_files[1];
1249
1250 ProfileCompilationInfo info1;
1251 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1252 SetupProfile("fake-location1",
1253 d1.GetLocationChecksum(),
1254 "fake-location2",
1255 d2.GetLocationChecksum(),
1256 num_methods_to_add,
1257 /*num_classes*/ 0,
1258 profile1,
1259 &info1,
1260 /*start_method_index*/ 0,
1261 /*reverse_dex_write_order*/ false,
1262 /*number_of_methods1*/ d1.NumMethodIds(),
1263 /*number_of_methods2*/ d2.NumMethodIds());
1264
1265 // Run profman and pass the dex file with --apk-fd.
1266 android::base::unique_fd apk_fd(
1267 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1268 ASSERT_GE(apk_fd.get(), 0);
1269
1270 std::string profman_cmd = GetProfmanCmd();
1271 std::vector<std::string> argv_str;
1272 argv_str.push_back(profman_cmd);
1273 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1274 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1275 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1276 argv_str.push_back("--copy-and-update-profile-key");
1277 std::string error;
1278
1279 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1280
1281 // Verify that we can load the result.
1282 ProfileCompilationInfo result;
1283 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1284 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1285
1286 // Verify that the renaming was done.
1287 for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1288 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1289 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i;
1290 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i;
1291
1292 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr);
1293 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr);
1294 }
1295}
1296
Calin Juravle2e2db782016-02-23 12:00:03 +00001297} // namespace art