blob: 370f59dc8a04da86579ceaf71f4cf73938631811 [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"
Vladimir Markoa8bba7d2018-05-30 15:18:48 +010025#include "dex/type_reference.h"
David Sehr97c381e2017-02-01 15:09:58 -080026#include "exec_utils.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"
David Sehr82d046e2018-04-23 08:14:19 -070030#include "profile/profile_compilation_info.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080031#include "profile_assistant.h"
32#include "scoped_thread_state_change-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000033
34namespace art {
35
Calin Juravleee9cb412018-02-13 20:32:35 -080036using Hotness = ProfileCompilationInfo::MethodHotness;
Vladimir Markoa8bba7d2018-05-30 15:18:48 +010037using TypeReferenceSet = std::set<TypeReference, TypeReferenceValueComparator>;
Calin Juravleee9cb412018-02-13 20:32:35 -080038
Mathieu Chartierea650f32017-05-24 12:04:13 -070039static constexpr size_t kMaxMethodIds = 65535;
40
Calin Juravle2e2db782016-02-23 12:00:03 +000041class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070042 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070043 void PostRuntimeCreate() OVERRIDE {
Vladimir Marko69d310e2017-10-09 14:12:23 +010044 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
Calin Juravlecc3171a2017-05-19 16:47:53 -070045 }
46
Calin Juravle2e2db782016-02-23 12:00:03 +000047 protected:
48 void SetupProfile(const std::string& id,
49 uint32_t checksum,
50 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010051 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000052 const ScratchFile& profile,
53 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070054 uint16_t start_method_index = 0,
55 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000056 std::string dex_location1 = "location1" + id;
57 uint32_t dex_location_checksum1 = checksum;
58 std::string dex_location2 = "location2" + id;
59 uint32_t dex_location_checksum2 = 10 * checksum;
Calin Juravlee10c1e22018-01-26 20:10:15 -080060 SetupProfile(dex_location1,
61 dex_location_checksum1,
62 dex_location2,
63 dex_location_checksum2,
64 number_of_methods,
65 number_of_classes,
66 profile,
67 info,
68 start_method_index,
69 reverse_dex_write_order);
70 }
71
72 void SetupProfile(const std::string& dex_location1,
73 uint32_t dex_location_checksum1,
74 const std::string& dex_location2,
75 uint32_t dex_location_checksum2,
76 uint16_t number_of_methods,
77 uint16_t number_of_classes,
78 const ScratchFile& profile,
79 ProfileCompilationInfo* info,
80 uint16_t start_method_index = 0,
Calin Juravle02c08792018-02-15 19:40:48 -080081 bool reverse_dex_write_order = false,
82 uint32_t number_of_methods1 = kMaxMethodIds,
83 uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravle2e2db782016-02-23 12:00:03 +000084 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070085 // reverse_dex_write_order controls the order in which the dex files will be added to
86 // the profile and thus written to disk.
87 ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
88 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -080089 dex_location2, dex_location_checksum2,
90 number_of_methods1, number_of_methods2);
Calin Juravleee9cb412018-02-13 20:32:35 -080091 Hotness::Flag flags = Hotness::kFlagPostStartup;
Calin Juravlecea9e9d2017-03-23 19:04:59 -070092 if (reverse_dex_write_order) {
Calin Juravleee9cb412018-02-13 20:32:35 -080093 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080094 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -080095 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080096 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070097 } else {
Calin Juravleee9cb412018-02-13 20:32:35 -080098 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -080099 dex_location1, dex_location_checksum1, i, number_of_methods1, pmi, flags));
Calin Juravleee9cb412018-02-13 20:32:35 -0800100 ASSERT_TRUE(info->AddMethod(
Calin Juravle02c08792018-02-15 19:40:48 -0800101 dex_location2, dex_location_checksum2, i, number_of_methods2, pmi, flags));
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700102 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000103 }
Calin Juravlec824b512016-03-29 20:33:33 +0100104 for (uint16_t i = 0; i < number_of_classes; i++) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700105 ASSERT_TRUE(info->AddClassIndex(dex_location1,
106 dex_location_checksum1,
107 dex::TypeIndex(i),
Calin Juravle02c08792018-02-15 19:40:48 -0800108 number_of_methods1));
Calin Juravlec824b512016-03-29 20:33:33 +0100109 }
110
Calin Juravle2e2db782016-02-23 12:00:03 +0000111 ASSERT_TRUE(info->Save(GetFd(profile)));
112 ASSERT_EQ(0, profile.GetFile()->Flush());
113 ASSERT_TRUE(profile.GetFile()->ResetOffset());
114 }
115
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700116 void SetupBasicProfile(const std::string& id,
117 uint32_t checksum,
118 uint16_t number_of_methods,
119 const std::vector<uint32_t> hot_methods,
120 const std::vector<uint32_t> startup_methods,
121 const std::vector<uint32_t> post_startup_methods,
122 const ScratchFile& profile,
123 ProfileCompilationInfo* info) {
124 std::string dex_location = "location1" + id;
125 for (uint32_t idx : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700126 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700127 }
128 for (uint32_t idx : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700129 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700130 }
131 for (uint32_t idx : post_startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700132 info->AddMethodIndex(Hotness::kFlagPostStartup,
133 dex_location,
134 checksum,
135 idx,
136 number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700137 }
138 ASSERT_TRUE(info->Save(GetFd(profile)));
139 ASSERT_EQ(0, profile.GetFile()->Flush());
140 ASSERT_TRUE(profile.GetFile()->ResetOffset());
141 }
142
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700143 // Creates an inline cache which will be destructed at the end of the test.
144 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
145 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100146 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700147 return used_inline_caches.back().get();
148 }
149
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700150 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
151 const std::string& dex_location1, uint32_t dex_checksum1,
Calin Juravle02c08792018-02-15 19:40:48 -0800152 const std::string& dex_location2, uint32_t dex_checksum2,
153 uint32_t number_of_methods1 = kMaxMethodIds, uint32_t number_of_methods2 = kMaxMethodIds) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700154 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
155 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Calin Juravle02c08792018-02-15 19:40:48 -0800156 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, number_of_methods1);
157 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, number_of_methods2);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700158
159 // Monomorphic
160 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100161 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700162 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700163 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700164 }
165 // Polymorphic
166 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100167 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700168 dex_pc_data.AddClass(0, dex::TypeIndex(0));
169 dex_pc_data.AddClass(1, dex::TypeIndex(1));
170
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700171 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700172 }
173 // Megamorphic
174 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100175 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700176 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700177 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700178 }
179 // Missing types
180 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100181 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700182 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700183 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700184 }
185
186 return pmi;
187 }
188
Calin Juravle2e2db782016-02-23 12:00:03 +0000189 int GetFd(const ScratchFile& file) const {
190 return static_cast<int>(file.GetFd());
191 }
192
193 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
194 ProfileCompilationInfo file_info;
195 ASSERT_TRUE(file.GetFile()->ResetOffset());
196 ASSERT_TRUE(file_info.Load(GetFd(file)));
197 ASSERT_TRUE(file_info.Equals(info));
198 }
199
Calin Juravle7bcdb532016-06-07 16:14:47 +0100200 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000201 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000202 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000203 if (kIsDebugBuild) {
204 file_path += "d";
205 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100206 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
207 << file_path << " should be a valid file path";
208 return file_path;
209 }
Mathieu Chartierf70fe3d2017-06-21 15:24:02 -0700210
Calin Juravle7bcdb532016-06-07 16:14:47 +0100211 // Runs test with given arguments.
212 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
213 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000214 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100215 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000216 for (size_t k = 0; k < profiles_fd.size(); k++) {
217 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
218 }
219 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
220
221 std::string error;
222 return ExecAndReturnCode(argv_str, &error);
223 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100224
225 bool GenerateTestProfile(const std::string& filename) {
226 std::string profman_cmd = GetProfmanCmd();
227 std::vector<std::string> argv_str;
228 argv_str.push_back(profman_cmd);
229 argv_str.push_back("--generate-test-profile=" + filename);
230 std::string error;
231 return ExecAndReturnCode(argv_str, &error);
232 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800233
Jeff Haof0a31f82017-03-27 15:50:37 -0700234 bool GenerateTestProfileWithInputDex(const std::string& filename) {
235 std::string profman_cmd = GetProfmanCmd();
236 std::vector<std::string> argv_str;
237 argv_str.push_back(profman_cmd);
238 argv_str.push_back("--generate-test-profile=" + filename);
239 argv_str.push_back("--generate-test-profile-seed=0");
240 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
241 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
242 std::string error;
243 return ExecAndReturnCode(argv_str, &error);
244 }
245
Andreas Gampe641a4732017-08-24 13:21:35 -0700246 bool CreateProfile(const std::string& profile_file_contents,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800247 const std::string& filename,
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700248 const std::string& dex_location) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800249 ScratchFile class_names_file;
250 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800251 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800252 EXPECT_EQ(0, file->Flush());
253 EXPECT_TRUE(file->ResetOffset());
254 std::string profman_cmd = GetProfmanCmd();
255 std::vector<std::string> argv_str;
256 argv_str.push_back(profman_cmd);
257 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
258 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800259 argv_str.push_back("--apk=" + dex_location);
260 argv_str.push_back("--dex-location=" + dex_location);
David Sehr7c80f2d2017-02-07 16:47:58 -0800261 std::string error;
262 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
263 return true;
264 }
265
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700266 bool RunProfman(const std::string& filename,
267 std::vector<std::string>& extra_args,
268 std::string* output) {
269 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800270 std::string profman_cmd = GetProfmanCmd();
271 std::vector<std::string> argv_str;
272 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700273 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800274 argv_str.push_back("--profile-file=" + filename);
275 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800276 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700277 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800278 std::string error;
279 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700280 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800281 EXPECT_EQ(0, file->Flush());
282 EXPECT_TRUE(file->ResetOffset());
283 int64_t length = file->GetLength();
284 std::unique_ptr<char[]> buf(new char[length]);
285 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700286 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800287 return true;
288 }
289
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700290 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
291 std::vector<std::string> extra_args;
292 extra_args.push_back("--dump-classes-and-methods");
293 return RunProfman(filename, extra_args, file_contents);
294 }
295
296 bool DumpOnly(const std::string& filename, std::string* file_contents) {
297 std::vector<std::string> extra_args;
298 extra_args.push_back("--dump-only");
299 return RunProfman(filename, extra_args, file_contents);
300 }
301
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700302 bool CreateAndDump(const std::string& input_file_contents,
303 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800304 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800305 EXPECT_TRUE(CreateProfile(input_file_contents,
306 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700307 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800308 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700309 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800310 return true;
311 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800312
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100313 ObjPtr<mirror::Class> GetClass(ScopedObjectAccess& soa,
314 jobject class_loader,
315 const std::string& clazz) REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800316 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100317 StackHandleScope<1> hs(soa.Self());
318 Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
319 ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader))));
320 return class_linker->FindClass(soa.Self(), clazz.c_str(), h_loader);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800321 }
322
323 ArtMethod* GetVirtualMethod(jobject class_loader,
324 const std::string& clazz,
325 const std::string& name) {
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100326 ScopedObjectAccess soa(Thread::Current());
327 ObjPtr<mirror::Class> klass = GetClass(soa, class_loader, clazz);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800328 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
329 const auto pointer_size = class_linker->GetImagePointerSize();
330 ArtMethod* method = nullptr;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800331 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
332 if (name == m.GetName()) {
333 EXPECT_TRUE(method == nullptr);
334 method = &m;
335 }
336 }
337 return method;
338 }
339
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100340 static TypeReference MakeTypeReference(ObjPtr<mirror::Class> klass)
341 REQUIRES_SHARED(Locks::mutator_lock_) {
342 return TypeReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
343 }
344
Calin Juravlee0ac1152017-02-13 19:03:47 -0800345 // Verify that given method has the expected inline caches and nothing else.
346 void AssertInlineCaches(ArtMethod* method,
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100347 const TypeReferenceSet& expected_clases,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800348 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;
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100364 for (const TypeReference& type_ref : expected_clases) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800365 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];
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100368 if (dex_ref.MatchesDex(type_ref.dex_file) && class_ref.type_index == type_ref.TypeIndex()) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800369 found++;
370 }
371 }
372 }
373
374 ASSERT_EQ(expected_clases.size(), found);
375 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700376
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700377 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
378 uint16_t methods_in_ref_profile) {
379 ScratchFile profile;
380 ScratchFile reference_profile;
381 std::vector<int> profile_fds({ GetFd(profile)});
382 int reference_profile_fd = GetFd(reference_profile);
383 std::vector<uint32_t> hot_methods_cur;
384 std::vector<uint32_t> hot_methods_ref;
385 std::vector<uint32_t> empty_vector;
386 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
387 hot_methods_cur.push_back(i);
388 }
389 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
390 hot_methods_ref.push_back(i);
391 }
392 ProfileCompilationInfo info1;
393 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
394 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
395 profile, &info1);
396 ProfileCompilationInfo info2;
397 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
398 reference_profile, &info2);
399 return ProcessProfiles(profile_fds, reference_profile_fd);
400 }
401
402 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
403 uint16_t classes_in_ref_profile) {
404 ScratchFile profile;
405 ScratchFile reference_profile;
406
407 std::vector<int> profile_fds({ GetFd(profile)});
408 int reference_profile_fd = GetFd(reference_profile);
409
410 ProfileCompilationInfo info1;
411 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
412 ProfileCompilationInfo info2;
413 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
414 return ProcessProfiles(profile_fds, reference_profile_fd);
415 }
416
Vladimir Marko69d310e2017-10-09 14:12:23 +0100417 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700418
419 // Cache of inline caches generated during tests.
420 // This makes it easier to pass data between different utilities and ensure that
421 // caches are destructed at the end of the test.
422 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000423};
424
425TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
426 ScratchFile profile1;
427 ScratchFile profile2;
428 ScratchFile reference_profile;
429
430 std::vector<int> profile_fds({
431 GetFd(profile1),
432 GetFd(profile2)});
433 int reference_profile_fd = GetFd(reference_profile);
434
435 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
436 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100437 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000438 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100439 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000440
441 // We should advise compilation.
442 ASSERT_EQ(ProfileAssistant::kCompile,
443 ProcessProfiles(profile_fds, reference_profile_fd));
444 // The resulting compilation info must be equal to the merge of the inputs.
445 ProfileCompilationInfo result;
446 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
447 ASSERT_TRUE(result.Load(reference_profile_fd));
448
449 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000450 ASSERT_TRUE(expected.MergeWith(info1));
451 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000452 ASSERT_TRUE(expected.Equals(result));
453
454 // The information from profiles must remain the same.
455 CheckProfileInfo(profile1, info1);
456 CheckProfileInfo(profile2, info2);
457}
458
Calin Juravlec824b512016-03-29 20:33:33 +0100459// TODO(calin): Add more tests for classes.
460TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
461 ScratchFile profile1;
462 ScratchFile reference_profile;
463
464 std::vector<int> profile_fds({
465 GetFd(profile1)});
466 int reference_profile_fd = GetFd(reference_profile);
467
468 const uint16_t kNumberOfClassesToEnableCompilation = 100;
469 ProfileCompilationInfo info1;
470 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
471
472 // We should advise compilation.
473 ASSERT_EQ(ProfileAssistant::kCompile,
474 ProcessProfiles(profile_fds, reference_profile_fd));
475 // The resulting compilation info must be equal to the merge of the inputs.
476 ProfileCompilationInfo result;
477 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
478 ASSERT_TRUE(result.Load(reference_profile_fd));
479
480 ProfileCompilationInfo expected;
481 ASSERT_TRUE(expected.MergeWith(info1));
482 ASSERT_TRUE(expected.Equals(result));
483
484 // The information from profiles must remain the same.
485 CheckProfileInfo(profile1, info1);
486}
487
Calin Juravle2e2db782016-02-23 12:00:03 +0000488TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
489 ScratchFile profile1;
490 ScratchFile profile2;
491 ScratchFile reference_profile;
492
493 std::vector<int> profile_fds({
494 GetFd(profile1),
495 GetFd(profile2)});
496 int reference_profile_fd = GetFd(reference_profile);
497
498 // The new profile info will contain the methods with indices 0-100.
499 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
500 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100501 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000502 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100503 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000504
505
506 // The reference profile info will contain the methods with indices 50-150.
507 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
508 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100509 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000510 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
511
512 // We should advise compilation.
513 ASSERT_EQ(ProfileAssistant::kCompile,
514 ProcessProfiles(profile_fds, reference_profile_fd));
515
516 // The resulting compilation info must be equal to the merge of the inputs
517 ProfileCompilationInfo result;
518 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
519 ASSERT_TRUE(result.Load(reference_profile_fd));
520
521 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000522 ASSERT_TRUE(expected.MergeWith(info1));
523 ASSERT_TRUE(expected.MergeWith(info2));
524 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000525 ASSERT_TRUE(expected.Equals(result));
526
527 // The information from profiles must remain the same.
528 CheckProfileInfo(profile1, info1);
529 CheckProfileInfo(profile2, info2);
530}
531
532TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
533 ScratchFile profile1;
534 ScratchFile profile2;
535 ScratchFile reference_profile;
536
537 std::vector<int> profile_fds({
538 GetFd(profile1),
539 GetFd(profile2)});
540 int reference_profile_fd = GetFd(reference_profile);
541
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700542 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000543 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100544 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000545 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100546 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000547
548 // We should not advise compilation.
549 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
550 ProcessProfiles(profile_fds, reference_profile_fd));
551
552 // The information from profiles must remain the same.
553 ProfileCompilationInfo file_info1;
554 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
555 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
556 ASSERT_TRUE(file_info1.Equals(info1));
557
558 ProfileCompilationInfo file_info2;
559 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
560 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
561 ASSERT_TRUE(file_info2.Equals(info2));
562
563 // Reference profile files must remain empty.
564 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
565
566 // The information from profiles must remain the same.
567 CheckProfileInfo(profile1, info1);
568 CheckProfileInfo(profile2, info2);
569}
570
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700571TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
572 const uint16_t kNumberOfMethodsInRefProfile = 6000;
573 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
574 // We should not advise compilation.
575 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
576 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
577 kNumberOfMethodsInRefProfile));
578}
579
580TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
581 const uint16_t kNumberOfMethodsInRefProfile = 6000;
582 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
583 // We should advise compilation.
584 ASSERT_EQ(ProfileAssistant::kCompile,
585 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
586 kNumberOfMethodsInRefProfile));
587}
588
589TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
590 const uint16_t kNumberOfClassesInRefProfile = 6000;
591 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
592 // We should not advise compilation.
593 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
594 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
595 kNumberOfClassesInRefProfile));
596}
597
598TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
599 const uint16_t kNumberOfClassesInRefProfile = 6000;
600 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
601 // We should advise compilation.
602 ASSERT_EQ(ProfileAssistant::kCompile,
603 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
604 kNumberOfClassesInRefProfile));
605}
606
Calin Juravle2e2db782016-02-23 12:00:03 +0000607TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
608 ScratchFile profile1;
609 ScratchFile profile2;
610 ScratchFile reference_profile;
611
612 std::vector<int> profile_fds({
613 GetFd(profile1),
614 GetFd(profile2)});
615 int reference_profile_fd = GetFd(reference_profile);
616
617 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
618 // Assign different hashes for the same dex file. This will make merging of information to fail.
619 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100620 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000621 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100622 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000623
624 // We should fail processing.
625 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
626 ProcessProfiles(profile_fds, reference_profile_fd));
627
628 // The information from profiles must remain the same.
629 CheckProfileInfo(profile1, info1);
630 CheckProfileInfo(profile2, info2);
631
632 // Reference profile files must still remain empty.
633 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
634}
635
636TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
637 ScratchFile profile1;
638 ScratchFile reference_profile;
639
640 std::vector<int> profile_fds({
641 GetFd(profile1)});
642 int reference_profile_fd = GetFd(reference_profile);
643
644 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
645 // Assign different hashes for the same dex file. This will make merging of information to fail.
646 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100647 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000648 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100649 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000650
651 // We should not advise compilation.
652 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
653 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
654 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
655 ProcessProfiles(profile_fds, reference_profile_fd));
656
657 // The information from profiles must remain the same.
658 CheckProfileInfo(profile1, info1);
659}
660
Calin Juravle7bcdb532016-06-07 16:14:47 +0100661TEST_F(ProfileAssistantTest, TestProfileGeneration) {
662 ScratchFile profile;
663 // Generate a test profile.
664 GenerateTestProfile(profile.GetFilename());
665
666 // Verify that the generated profile is valid and can be loaded.
667 ASSERT_TRUE(profile.GetFile()->ResetOffset());
668 ProfileCompilationInfo info;
669 ASSERT_TRUE(info.Load(GetFd(profile)));
670}
671
Jeff Haof0a31f82017-03-27 15:50:37 -0700672TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
673 ScratchFile profile;
674 // Generate a test profile passing in a dex file as reference.
675 GenerateTestProfileWithInputDex(profile.GetFilename());
676
677 // Verify that the generated profile is valid and can be loaded.
678 ASSERT_TRUE(profile.GetFile()->ResetOffset());
679 ProfileCompilationInfo info;
680 ASSERT_TRUE(info.Load(GetFd(profile)));
681}
682
David Sehr7c80f2d2017-02-07 16:47:58 -0800683TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
684 // Class names put here need to be in sorted order.
685 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700686 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800687 "Ljava/lang/Comparable;",
688 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700689 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700690 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800691 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700692 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800693 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700694 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800695 }
696 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700697 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
698 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800699}
700
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700701TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
702 // Class names put here need to be in sorted order.
703 std::vector<std::string> class_names = {
704 "Ljava/lang/Math;->*",
705 };
706 std::string input_file_contents;
707 std::string expected_contents;
708 for (std::string& class_name : class_names) {
709 input_file_contents += class_name + std::string("\n");
710 expected_contents += DescriptorToDot(class_name.c_str()) +
711 std::string("\n");
712 }
713 std::string output_file_contents;
714 ScratchFile profile_file;
715 EXPECT_TRUE(CreateProfile(input_file_contents,
716 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700717 GetLibCoreDexFileNames()[0]));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700718 ProfileCompilationInfo info;
719 profile_file.GetFile()->ResetOffset();
720 ASSERT_TRUE(info.Load(GetFd(profile_file)));
721 // Verify that the profile has matching methods.
722 ScopedObjectAccess soa(Thread::Current());
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100723 ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader */ nullptr, "Ljava/lang/Math;");
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700724 ASSERT_TRUE(klass != nullptr);
725 size_t method_count = 0;
726 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
727 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
728 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700729 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
730 info.GetMethod(method.GetDexFile()->GetLocation(),
731 method.GetDexFile()->GetLocationChecksum(),
732 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700733 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700734 }
735 }
736 EXPECT_GT(method_count, 0u);
737}
738
Mathieu Chartier2f794552017-06-19 10:58:08 -0700739TEST_F(ProfileAssistantTest, TestBootImageProfile) {
740 const std::string core_dex = GetLibCoreDexFileNames()[0];
741
742 std::vector<ScratchFile> profiles;
743
744 // In image with enough clean occurrences.
745 const std::string kCleanClass = "Ljava/lang/CharSequence;";
746 // In image with enough dirty occurrences.
747 const std::string kDirtyClass = "Ljava/lang/Object;";
748 // Not in image becauseof not enough occurrences.
749 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
750 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
751 // Method that is hot.
752 // Also adds the class through inference since it is in each dex.
753 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
754 // Method that doesn't add the class since its only in one profile. Should still show up in the
755 // boot profile.
756 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700757 // Method that gets marked as hot since it's in multiple profiles.
758 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700759
760 // Thresholds for this test.
761 static const size_t kDirtyThreshold = 3;
762 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700763 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700764
765 // Create a bunch of boot profiles.
766 std::string dex1 =
767 kCleanClass + "\n" +
768 kDirtyClass + "\n" +
769 kUncommonCleanClass + "\n" +
770 "H" + kHotMethod + "\n" +
771 kUncommonDirtyClass;
772 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000773 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700774 dex1, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700775
776 // Create a bunch of boot profiles.
777 std::string dex2 =
778 kCleanClass + "\n" +
779 kDirtyClass + "\n" +
780 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700781 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700782 kUncommonDirtyClass;
783 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000784 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700785 dex2, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700786
787 // Create a bunch of boot profiles.
788 std::string dex3 =
789 "S" + kHotMethod + "\n" +
790 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700791 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700792 kDirtyClass + "\n";
793 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000794 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700795 dex3, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700796
797 // Generate the boot profile.
798 ScratchFile out_profile;
799 std::vector<std::string> args;
800 args.push_back(GetProfmanCmd());
801 args.push_back("--generate-boot-image-profile");
802 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
803 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700804 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700805 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
806 args.push_back("--apk=" + core_dex);
807 args.push_back("--dex-location=" + core_dex);
808 for (const ScratchFile& profile : profiles) {
809 args.push_back("--profile-file=" + profile.GetFilename());
810 }
811 std::string error;
812 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
813 ASSERT_EQ(0, out_profile.GetFile()->Flush());
814 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
815
816 // Verify the boot profile contents.
817 std::string output_file_contents;
818 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
819 // Common classes, should be in the classes of the profile.
820 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
821 << output_file_contents;
822 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
823 << output_file_contents;
824 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
825 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
826 << output_file_contents;
827 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
828 << output_file_contents;
829 // Inferred class from a method common to all three profiles.
830 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
831 << output_file_contents;
832 // Aggregated methods hotness information.
833 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
834 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700835 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700836 << output_file_contents;
837 // Not inferred class, method is only in one profile.
838 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
839 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700840 // Test the sampled methods that became hot.
841 // Other method is in only one profile, it should not become hot.
842 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
843 << output_file_contents;
844 // Multi method is in at least two profiles, it should become hot.
845 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
846 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700847}
848
David Sehr7c80f2d2017-02-07 16:47:58 -0800849TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
850 // Class names put here need to be in sorted order.
851 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800852 "Ldoesnt/match/this/one;",
853 "Ljava/lang/Comparable;",
854 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800855 };
856 std::string input_file_contents;
857 for (std::string& class_name : class_names) {
858 input_file_contents += class_name + std::string("\n");
859 }
860 std::string output_file_contents;
861 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
862 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700863 class_names[1] + std::string("\n") +
864 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800865 ASSERT_EQ(output_file_contents, expected_contents);
866}
867
868TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
869 // Class names put here need to be in sorted order.
870 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800871 "Ldoesnt/match/this/one;",
872 "Ldoesnt/match/this/one/either;",
873 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800874 };
875 std::string input_file_contents;
876 for (std::string& class_name : class_names) {
877 input_file_contents += class_name + std::string("\n");
878 }
879 std::string output_file_contents;
880 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
881 std::string expected_contents("");
882 ASSERT_EQ(output_file_contents, expected_contents);
883}
884
Calin Juravlee0ac1152017-02-13 19:03:47 -0800885TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
886 // Create the profile content.
887 std::vector<std::string> methods = {
888 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
889 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
890 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800891 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800892 "LTestInline;->noInlineCache(LSuper;)I"
893 };
894 std::string input_file_contents;
895 for (std::string& m : methods) {
896 input_file_contents += m + std::string("\n");
897 }
898
899 // Create the profile and save it to disk.
900 ScratchFile profile_file;
901 ASSERT_TRUE(CreateProfile(input_file_contents,
902 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700903 GetTestDexFileName("ProfileTestMultiDex")));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800904
905 // Load the profile from disk.
906 ProfileCompilationInfo info;
907 profile_file.GetFile()->ResetOffset();
908 ASSERT_TRUE(info.Load(GetFd(profile_file)));
909
910 // Load the dex files and verify that the profile contains the expected methods info.
911 ScopedObjectAccess soa(Thread::Current());
912 jobject class_loader = LoadDex("ProfileTestMultiDex");
913 ASSERT_NE(class_loader, nullptr);
914
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100915 StackHandleScope<3> hs(soa.Self());
916 Handle<mirror::Class> sub_a = hs.NewHandle(GetClass(soa, class_loader, "LSubA;"));
917 Handle<mirror::Class> sub_b = hs.NewHandle(GetClass(soa, class_loader, "LSubB;"));
918 Handle<mirror::Class> sub_c = hs.NewHandle(GetClass(soa, class_loader, "LSubC;"));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800919
920 ASSERT_TRUE(sub_a != nullptr);
921 ASSERT_TRUE(sub_b != nullptr);
922 ASSERT_TRUE(sub_c != nullptr);
923
924 {
925 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
926 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
927 "LTestInline;",
928 "inlineMonomorphic");
929 ASSERT_TRUE(inline_monomorphic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100930 TypeReferenceSet expected_monomorphic;
931 expected_monomorphic.insert(MakeTypeReference(sub_a.Get()));
Calin Juravle589e71e2017-03-03 16:05:05 -0800932 AssertInlineCaches(inline_monomorphic,
933 expected_monomorphic,
934 info,
935 /*megamorphic*/false,
936 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800937 }
938
939 {
940 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
941 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
942 "LTestInline;",
943 "inlinePolymorphic");
944 ASSERT_TRUE(inline_polymorhic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100945 TypeReferenceSet expected_polymorphic;
946 expected_polymorphic.insert(MakeTypeReference(sub_a.Get()));
947 expected_polymorphic.insert(MakeTypeReference(sub_b.Get()));
948 expected_polymorphic.insert(MakeTypeReference(sub_c.Get()));
Calin Juravle589e71e2017-03-03 16:05:05 -0800949 AssertInlineCaches(inline_polymorhic,
950 expected_polymorphic,
951 info,
952 /*megamorphic*/false,
953 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800954 }
955
956 {
957 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
958 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
959 "LTestInline;",
960 "inlineMegamorphic");
961 ASSERT_TRUE(inline_megamorphic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100962 TypeReferenceSet expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800963 AssertInlineCaches(inline_megamorphic,
964 expected_megamorphic,
965 info,
966 /*megamorphic*/true,
967 /*missing_types*/false);
968 }
969
970 {
971 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
972 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
973 "LTestInline;",
974 "inlineMissingTypes");
975 ASSERT_TRUE(inline_missing_types != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100976 TypeReferenceSet expected_missing_Types;
Calin Juravle589e71e2017-03-03 16:05:05 -0800977 AssertInlineCaches(inline_missing_types,
978 expected_missing_Types,
979 info,
980 /*megamorphic*/false,
981 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800982 }
983
984 {
985 // Verify that method noInlineCache has no inline caches in the profile.
986 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
987 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700988 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
989 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
990 no_inline_cache->GetDexFile()->GetLocationChecksum(),
991 no_inline_cache->GetDexMethodIndex());
992 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700993 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800994 }
995}
996
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700997TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
998 ScratchFile profile1;
999 ScratchFile reference_profile;
1000
1001 std::vector<int> profile_fds({GetFd(profile1)});
1002 int reference_profile_fd = GetFd(reference_profile);
1003
1004 // The new profile info will contain the methods with indices 0-100.
1005 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1006 ProfileCompilationInfo info1;
1007 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
1008 /*start_method_index*/0, /*reverse_dex_write_order*/false);
1009
1010 // The reference profile info will contain the methods with indices 50-150.
1011 // When setting up the profile reverse the order in which the dex files
1012 // are added to the profile. This will verify that profman merges profiles
1013 // with a different dex order correctly.
1014 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1015 ProfileCompilationInfo reference_info;
1016 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1017 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
1018
1019 // We should advise compilation.
1020 ASSERT_EQ(ProfileAssistant::kCompile,
1021 ProcessProfiles(profile_fds, reference_profile_fd));
1022
1023 // The resulting compilation info must be equal to the merge of the inputs.
1024 ProfileCompilationInfo result;
1025 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1026 ASSERT_TRUE(result.Load(reference_profile_fd));
1027
1028 ProfileCompilationInfo expected;
1029 ASSERT_TRUE(expected.MergeWith(reference_info));
1030 ASSERT_TRUE(expected.MergeWith(info1));
1031 ASSERT_TRUE(expected.Equals(result));
1032
1033 // The information from profile must remain the same.
1034 CheckProfileInfo(profile1, info1);
1035}
1036
Calin Juravle08556882017-05-26 16:40:45 -07001037TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1038 // Create the profile content.
1039 std::vector<std::string> profile_methods = {
1040 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1041 "LTestInline;->invalid_method",
1042 "invalid_class"
1043 };
1044 std::string input_file_contents;
1045 for (std::string& m : profile_methods) {
1046 input_file_contents += m + std::string("\n");
1047 }
1048
1049 // Create the profile and save it to disk.
1050 ScratchFile profile_file;
1051 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1052 ASSERT_TRUE(CreateProfile(input_file_contents,
1053 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -07001054 dex_filename));
Calin Juravle08556882017-05-26 16:40:45 -07001055
1056 // Load the profile from disk.
1057 ProfileCompilationInfo info;
1058 profile_file.GetFile()->ResetOffset();
1059 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1060
1061 // Load the dex files and verify that the profile contains the expected methods info.
1062 ScopedObjectAccess soa(Thread::Current());
1063 jobject class_loader = LoadDex("ProfileTestMultiDex");
1064 ASSERT_NE(class_loader, nullptr);
1065
1066 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1067 "LTestInline;",
1068 "inlineMonomorphic");
1069 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1070
1071 // Verify that the inline cache contains the invalid type.
1072 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1073 info.GetMethod(dex_file->GetLocation(),
1074 dex_file->GetLocationChecksum(),
1075 inline_monomorphic->GetDexMethodIndex());
1076 ASSERT_TRUE(pmi != nullptr);
1077 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1078 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1079 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1080 ASSERT_EQ(1u, dex_pc_data.classes.size());
1081 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1082
1083 // Verify that the start-up classes contain the invalid class.
1084 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001085 std::set<uint16_t> hot_methods;
1086 std::set<uint16_t> startup_methods;
1087 std::set<uint16_t> post_start_methods;
1088 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1089 &classes,
1090 &hot_methods,
1091 &startup_methods,
1092 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001093 ASSERT_EQ(1u, classes.size());
1094 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1095
Calin Juravleee9cb412018-02-13 20:32:35 -08001096 // Verify that the invalid method did not get in the profile.
1097 ASSERT_EQ(1u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001098 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Calin Juravleee9cb412018-02-13 20:32:35 -08001099 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001100}
1101
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001102TEST_F(ProfileAssistantTest, DumpOnly) {
1103 ScratchFile profile;
1104
1105 const uint32_t kNumberOfMethods = 64;
1106 std::vector<uint32_t> hot_methods;
1107 std::vector<uint32_t> startup_methods;
1108 std::vector<uint32_t> post_startup_methods;
1109 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1110 if (i % 2 == 0) {
1111 hot_methods.push_back(i);
1112 }
1113 if (i % 3 == 1) {
1114 startup_methods.push_back(i);
1115 }
1116 if (i % 4 == 2) {
1117 post_startup_methods.push_back(i);
1118 }
1119 }
1120 EXPECT_GT(hot_methods.size(), 0u);
1121 EXPECT_GT(startup_methods.size(), 0u);
1122 EXPECT_GT(post_startup_methods.size(), 0u);
1123 ProfileCompilationInfo info1;
1124 SetupBasicProfile("p1",
1125 1,
1126 kNumberOfMethods,
1127 hot_methods,
1128 startup_methods,
1129 post_startup_methods,
1130 profile,
1131 &info1);
1132 std::string output;
1133 DumpOnly(profile.GetFilename(), &output);
1134 const size_t hot_offset = output.find("hot methods:");
1135 const size_t startup_offset = output.find("startup methods:");
1136 const size_t post_startup_offset = output.find("post startup methods:");
1137 const size_t classes_offset = output.find("classes:");
1138 ASSERT_NE(hot_offset, std::string::npos);
1139 ASSERT_NE(startup_offset, std::string::npos);
1140 ASSERT_NE(post_startup_offset, std::string::npos);
1141 ASSERT_LT(hot_offset, startup_offset);
1142 ASSERT_LT(startup_offset, post_startup_offset);
1143 // Check the actual contents of the dump by looking at the offsets of the methods.
1144 for (uint32_t m : hot_methods) {
1145 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001146 ASSERT_NE(pos, std::string::npos) << output;
1147 EXPECT_LT(pos, startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001148 }
1149 for (uint32_t m : startup_methods) {
1150 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001151 ASSERT_NE(pos, std::string::npos) << output;
1152 EXPECT_LT(pos, post_startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001153 }
1154 for (uint32_t m : post_startup_methods) {
1155 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001156 ASSERT_NE(pos, std::string::npos) << output;
1157 EXPECT_LT(pos, classes_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001158 }
1159}
1160
Calin Juravlee10c1e22018-01-26 20:10:15 -08001161TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1162 ScratchFile profile1;
1163 ScratchFile profile2;
1164 ScratchFile reference_profile;
1165
1166 std::vector<int> profile_fds({
1167 GetFd(profile1),
1168 GetFd(profile2)});
1169 int reference_profile_fd = GetFd(reference_profile);
1170
1171 // Use a real dex file to generate profile test data.
1172 // The file will be used during merging to filter unwanted data.
1173 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1174 const DexFile& d1 = *dex_files[0];
1175 const DexFile& d2 = *dex_files[1];
1176 // The new profile info will contain the methods with indices 0-100.
1177 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1178 ProfileCompilationInfo info1;
1179 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1180 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1181 ProfileCompilationInfo info2;
1182 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2,
1183 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1184
1185
1186 // The reference profile info will contain the methods with indices 50-150.
1187 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1188 ProfileCompilationInfo reference_info;
1189 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1190 kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1191 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1192
1193 // Run profman and pass the dex file with --apk-fd.
1194 android::base::unique_fd apk_fd(
1195 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1196 ASSERT_GE(apk_fd.get(), 0);
1197
1198 std::string profman_cmd = GetProfmanCmd();
1199 std::vector<std::string> argv_str;
1200 argv_str.push_back(profman_cmd);
1201 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1202 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1203 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1204 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1205 std::string error;
1206
1207 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1208
1209 // Verify that we can load the result.
1210
1211 ProfileCompilationInfo result;
1212 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1213 ASSERT_TRUE(result.Load(reference_profile_fd));
1214
1215
1216 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1217 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1218 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1219
1220 // Verify that the result filtered out data not belonging to the dex file.
1221 // This is equivalent to checking that the result is equal to the merging of
1222 // all profiles while filtering out data not belonging to the dex file.
1223
1224 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1225 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1226 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation())
1227 && checksum == d1.GetLocationChecksum())
1228 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation())
1229 && checksum == d2.GetLocationChecksum());
1230 };
1231
1232 ProfileCompilationInfo info1_filter;
1233 ProfileCompilationInfo info2_filter;
1234 ProfileCompilationInfo expected;
1235
1236 info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn);
1237 info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn);
1238 expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn);
1239
1240 ASSERT_TRUE(expected.MergeWith(info1_filter));
1241 ASSERT_TRUE(expected.MergeWith(info2_filter));
1242
1243 ASSERT_TRUE(expected.Equals(result));
1244}
1245
Calin Juravle02c08792018-02-15 19:40:48 -08001246TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1247 ScratchFile profile1;
1248 ScratchFile reference_profile;
1249
1250 // Use a real dex file to generate profile test data. During the copy-and-update the
1251 // matching is done based on checksum so we have to match with the real thing.
1252 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1253 const DexFile& d1 = *dex_files[0];
1254 const DexFile& d2 = *dex_files[1];
1255
1256 ProfileCompilationInfo info1;
1257 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1258 SetupProfile("fake-location1",
1259 d1.GetLocationChecksum(),
1260 "fake-location2",
1261 d2.GetLocationChecksum(),
1262 num_methods_to_add,
1263 /*num_classes*/ 0,
1264 profile1,
1265 &info1,
1266 /*start_method_index*/ 0,
1267 /*reverse_dex_write_order*/ false,
1268 /*number_of_methods1*/ d1.NumMethodIds(),
1269 /*number_of_methods2*/ d2.NumMethodIds());
1270
1271 // Run profman and pass the dex file with --apk-fd.
1272 android::base::unique_fd apk_fd(
1273 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY));
1274 ASSERT_GE(apk_fd.get(), 0);
1275
1276 std::string profman_cmd = GetProfmanCmd();
1277 std::vector<std::string> argv_str;
1278 argv_str.push_back(profman_cmd);
1279 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1280 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1281 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1282 argv_str.push_back("--copy-and-update-profile-key");
1283 std::string error;
1284
1285 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1286
1287 // Verify that we can load the result.
1288 ProfileCompilationInfo result;
1289 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1290 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1291
1292 // Verify that the renaming was done.
1293 for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1294 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1295 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i;
1296 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i;
1297
1298 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr);
1299 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr);
1300 }
1301}
1302
Calin Juravle2e2db782016-02-23 12:00:03 +00001303} // namespace art