blob: 7b57c46df3e01a8a71dc65a227337fb8103c0536 [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:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010043 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++) {
Calin Juravle3ee9cfd2018-12-11 13:38:35 -0800105 ASSERT_TRUE(info->AddClassIndex(ProfileCompilationInfo::GetProfileDexFileKey(dex_location1),
Mathieu Chartierea650f32017-05-24 12:04:13 -0700106 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,
Stephen Hines48ba1972018-09-24 13:35:54 -0700119 const std::vector<uint32_t>& hot_methods,
120 const std::vector<uint32_t>& startup_methods,
121 const std::vector<uint32_t>& post_startup_methods,
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700122 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() {
Roland Levillainfb6a5c02019-03-29 20:20:16 +0000201 std::string file_path = GetAndroidRuntimeBinDir() + "/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000202 if (kIsDebugBuild) {
203 file_path += "d";
204 }
Roland Levillainfb6a5c02019-03-29 20:20:16 +0000205 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
Calin Juravle7bcdb532016-06-07 16:14:47 +0100206 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 Juravle1bfe4bd2018-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 Juravle1bfe4bd2018-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
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100311 ObjPtr<mirror::Class> GetClass(ScopedObjectAccess& soa,
312 jobject class_loader,
313 const std::string& clazz) REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800314 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100315 StackHandleScope<1> hs(soa.Self());
316 Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
317 ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader))));
318 return class_linker->FindClass(soa.Self(), clazz.c_str(), h_loader);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800319 }
320
321 ArtMethod* GetVirtualMethod(jobject class_loader,
322 const std::string& clazz,
323 const std::string& name) {
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100324 ScopedObjectAccess soa(Thread::Current());
325 ObjPtr<mirror::Class> klass = GetClass(soa, class_loader, clazz);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800326 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
327 const auto pointer_size = class_linker->GetImagePointerSize();
328 ArtMethod* method = nullptr;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800329 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
330 if (name == m.GetName()) {
331 EXPECT_TRUE(method == nullptr);
332 method = &m;
333 }
334 }
335 return method;
336 }
337
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100338 static TypeReference MakeTypeReference(ObjPtr<mirror::Class> klass)
339 REQUIRES_SHARED(Locks::mutator_lock_) {
340 return TypeReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
341 }
342
Calin Juravlee0ac1152017-02-13 19:03:47 -0800343 // Verify that given method has the expected inline caches and nothing else.
344 void AssertInlineCaches(ArtMethod* method,
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100345 const TypeReferenceSet& expected_clases,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800346 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800347 bool is_megamorphic,
348 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800349 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700350 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
351 info.GetMethod(method->GetDexFile()->GetLocation(),
352 method->GetDexFile()->GetLocationChecksum(),
353 method->GetDexMethodIndex());
354 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700355 ASSERT_EQ(pmi->inline_caches->size(), 1u);
356 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800357
Calin Juravle589e71e2017-03-03 16:05:05 -0800358 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
359 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800360 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
361 size_t found = 0;
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100362 for (const TypeReference& type_ref : expected_clases) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800363 for (const auto& class_ref : dex_pc_data.classes) {
364 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700365 pmi->dex_references[class_ref.dex_profile_index];
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100366 if (dex_ref.MatchesDex(type_ref.dex_file) && class_ref.type_index == type_ref.TypeIndex()) {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800367 found++;
368 }
369 }
370 }
371
372 ASSERT_EQ(expected_clases.size(), found);
373 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700374
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700375 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
376 uint16_t methods_in_ref_profile) {
377 ScratchFile profile;
378 ScratchFile reference_profile;
379 std::vector<int> profile_fds({ GetFd(profile)});
380 int reference_profile_fd = GetFd(reference_profile);
381 std::vector<uint32_t> hot_methods_cur;
382 std::vector<uint32_t> hot_methods_ref;
383 std::vector<uint32_t> empty_vector;
384 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
385 hot_methods_cur.push_back(i);
386 }
387 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
388 hot_methods_ref.push_back(i);
389 }
390 ProfileCompilationInfo info1;
391 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
392 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
393 profile, &info1);
394 ProfileCompilationInfo info2;
395 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
396 reference_profile, &info2);
397 return ProcessProfiles(profile_fds, reference_profile_fd);
398 }
399
400 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
401 uint16_t classes_in_ref_profile) {
402 ScratchFile profile;
403 ScratchFile reference_profile;
404
405 std::vector<int> profile_fds({ GetFd(profile)});
406 int reference_profile_fd = GetFd(reference_profile);
407
408 ProfileCompilationInfo info1;
409 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
410 ProfileCompilationInfo info2;
411 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
412 return ProcessProfiles(profile_fds, reference_profile_fd);
413 }
414
Vladimir Marko69d310e2017-10-09 14:12:23 +0100415 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700416
417 // Cache of inline caches generated during tests.
418 // This makes it easier to pass data between different utilities and ensure that
419 // caches are destructed at the end of the test.
420 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000421};
422
423TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
424 ScratchFile profile1;
425 ScratchFile profile2;
426 ScratchFile reference_profile;
427
428 std::vector<int> profile_fds({
429 GetFd(profile1),
430 GetFd(profile2)});
431 int reference_profile_fd = GetFd(reference_profile);
432
433 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
434 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100435 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000436 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100437 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000438
439 // We should advise compilation.
440 ASSERT_EQ(ProfileAssistant::kCompile,
441 ProcessProfiles(profile_fds, reference_profile_fd));
442 // The resulting compilation info must be equal to the merge of the inputs.
443 ProfileCompilationInfo result;
444 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
445 ASSERT_TRUE(result.Load(reference_profile_fd));
446
447 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000448 ASSERT_TRUE(expected.MergeWith(info1));
449 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000450 ASSERT_TRUE(expected.Equals(result));
451
452 // The information from profiles must remain the same.
453 CheckProfileInfo(profile1, info1);
454 CheckProfileInfo(profile2, info2);
455}
456
Calin Juravlec824b512016-03-29 20:33:33 +0100457// TODO(calin): Add more tests for classes.
458TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
459 ScratchFile profile1;
460 ScratchFile reference_profile;
461
462 std::vector<int> profile_fds({
463 GetFd(profile1)});
464 int reference_profile_fd = GetFd(reference_profile);
465
466 const uint16_t kNumberOfClassesToEnableCompilation = 100;
467 ProfileCompilationInfo info1;
468 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
469
470 // We should advise compilation.
471 ASSERT_EQ(ProfileAssistant::kCompile,
472 ProcessProfiles(profile_fds, reference_profile_fd));
473 // The resulting compilation info must be equal to the merge of the inputs.
474 ProfileCompilationInfo result;
475 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
476 ASSERT_TRUE(result.Load(reference_profile_fd));
477
478 ProfileCompilationInfo expected;
479 ASSERT_TRUE(expected.MergeWith(info1));
480 ASSERT_TRUE(expected.Equals(result));
481
482 // The information from profiles must remain the same.
483 CheckProfileInfo(profile1, info1);
484}
485
Calin Juravle2e2db782016-02-23 12:00:03 +0000486TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
487 ScratchFile profile1;
488 ScratchFile profile2;
489 ScratchFile reference_profile;
490
491 std::vector<int> profile_fds({
492 GetFd(profile1),
493 GetFd(profile2)});
494 int reference_profile_fd = GetFd(reference_profile);
495
496 // The new profile info will contain the methods with indices 0-100.
497 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
498 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100499 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000500 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100501 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000502
503
504 // The reference profile info will contain the methods with indices 50-150.
505 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
506 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100507 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000508 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
509
510 // We should advise compilation.
511 ASSERT_EQ(ProfileAssistant::kCompile,
512 ProcessProfiles(profile_fds, reference_profile_fd));
513
514 // The resulting compilation info must be equal to the merge of the inputs
515 ProfileCompilationInfo result;
516 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
517 ASSERT_TRUE(result.Load(reference_profile_fd));
518
519 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000520 ASSERT_TRUE(expected.MergeWith(info1));
521 ASSERT_TRUE(expected.MergeWith(info2));
522 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000523 ASSERT_TRUE(expected.Equals(result));
524
525 // The information from profiles must remain the same.
526 CheckProfileInfo(profile1, info1);
527 CheckProfileInfo(profile2, info2);
528}
529
530TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
531 ScratchFile profile1;
532 ScratchFile profile2;
533 ScratchFile reference_profile;
534
535 std::vector<int> profile_fds({
536 GetFd(profile1),
537 GetFd(profile2)});
538 int reference_profile_fd = GetFd(reference_profile);
539
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700540 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000541 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100542 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000543 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100544 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000545
546 // We should not advise compilation.
547 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
548 ProcessProfiles(profile_fds, reference_profile_fd));
549
550 // The information from profiles must remain the same.
551 ProfileCompilationInfo file_info1;
552 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
553 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
554 ASSERT_TRUE(file_info1.Equals(info1));
555
556 ProfileCompilationInfo file_info2;
557 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
558 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
559 ASSERT_TRUE(file_info2.Equals(info2));
560
561 // Reference profile files must remain empty.
562 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
563
564 // The information from profiles must remain the same.
565 CheckProfileInfo(profile1, info1);
566 CheckProfileInfo(profile2, info2);
567}
568
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700569TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
570 const uint16_t kNumberOfMethodsInRefProfile = 6000;
571 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
572 // We should not advise compilation.
573 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
574 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
575 kNumberOfMethodsInRefProfile));
576}
577
578TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
579 const uint16_t kNumberOfMethodsInRefProfile = 6000;
580 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
581 // We should advise compilation.
582 ASSERT_EQ(ProfileAssistant::kCompile,
583 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
584 kNumberOfMethodsInRefProfile));
585}
586
587TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
588 const uint16_t kNumberOfClassesInRefProfile = 6000;
589 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
590 // We should not advise compilation.
591 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
592 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
593 kNumberOfClassesInRefProfile));
594}
595
596TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
597 const uint16_t kNumberOfClassesInRefProfile = 6000;
598 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
599 // We should advise compilation.
600 ASSERT_EQ(ProfileAssistant::kCompile,
601 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
602 kNumberOfClassesInRefProfile));
603}
604
Calin Juravle2e2db782016-02-23 12:00:03 +0000605TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
606 ScratchFile profile1;
607 ScratchFile profile2;
608 ScratchFile reference_profile;
609
610 std::vector<int> profile_fds({
611 GetFd(profile1),
612 GetFd(profile2)});
613 int reference_profile_fd = GetFd(reference_profile);
614
615 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
616 // Assign different hashes for the same dex file. This will make merging of information to fail.
617 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100618 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000619 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100620 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000621
622 // We should fail processing.
623 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
624 ProcessProfiles(profile_fds, reference_profile_fd));
625
626 // The information from profiles must remain the same.
627 CheckProfileInfo(profile1, info1);
628 CheckProfileInfo(profile2, info2);
629
630 // Reference profile files must still remain empty.
631 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
632}
633
634TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
635 ScratchFile profile1;
636 ScratchFile reference_profile;
637
638 std::vector<int> profile_fds({
639 GetFd(profile1)});
640 int reference_profile_fd = GetFd(reference_profile);
641
642 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
643 // Assign different hashes for the same dex file. This will make merging of information to fail.
644 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100645 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000646 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100647 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000648
649 // We should not advise compilation.
650 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
651 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
652 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
653 ProcessProfiles(profile_fds, reference_profile_fd));
654
655 // The information from profiles must remain the same.
656 CheckProfileInfo(profile1, info1);
657}
658
Calin Juravle7bcdb532016-06-07 16:14:47 +0100659TEST_F(ProfileAssistantTest, TestProfileGeneration) {
660 ScratchFile profile;
661 // Generate a test profile.
662 GenerateTestProfile(profile.GetFilename());
663
664 // Verify that the generated profile is valid and can be loaded.
665 ASSERT_TRUE(profile.GetFile()->ResetOffset());
666 ProfileCompilationInfo info;
667 ASSERT_TRUE(info.Load(GetFd(profile)));
668}
669
Jeff Haof0a31f82017-03-27 15:50:37 -0700670TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
671 ScratchFile profile;
672 // Generate a test profile passing in a dex file as reference.
673 GenerateTestProfileWithInputDex(profile.GetFilename());
674
675 // Verify that the generated profile is valid and can be loaded.
676 ASSERT_TRUE(profile.GetFile()->ResetOffset());
677 ProfileCompilationInfo info;
678 ASSERT_TRUE(info.Load(GetFd(profile)));
679}
680
David Sehr7c80f2d2017-02-07 16:47:58 -0800681TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
682 // Class names put here need to be in sorted order.
683 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700684 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800685 "Ljava/lang/Comparable;",
686 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700687 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700688 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800689 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700690 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800691 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700692 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800693 }
694 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700695 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
696 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800697}
698
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700699TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
700 // Class names put here need to be in sorted order.
701 std::vector<std::string> class_names = {
702 "Ljava/lang/Math;->*",
703 };
704 std::string input_file_contents;
705 std::string expected_contents;
706 for (std::string& class_name : class_names) {
707 input_file_contents += class_name + std::string("\n");
708 expected_contents += DescriptorToDot(class_name.c_str()) +
709 std::string("\n");
710 }
711 std::string output_file_contents;
712 ScratchFile profile_file;
713 EXPECT_TRUE(CreateProfile(input_file_contents,
714 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700715 GetLibCoreDexFileNames()[0]));
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700716 ProfileCompilationInfo info;
717 profile_file.GetFile()->ResetOffset();
718 ASSERT_TRUE(info.Load(GetFd(profile_file)));
719 // Verify that the profile has matching methods.
720 ScopedObjectAccess soa(Thread::Current());
Andreas Gampe9b031f72018-10-04 11:03:34 -0700721 ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader= */ nullptr, "Ljava/lang/Math;");
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700722 ASSERT_TRUE(klass != nullptr);
723 size_t method_count = 0;
724 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
725 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
726 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700727 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
728 info.GetMethod(method.GetDexFile()->GetLocation(),
729 method.GetDexFile()->GetLocationChecksum(),
730 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700731 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700732 }
733 }
734 EXPECT_GT(method_count, 0u);
735}
736
Mathieu Chartier2f794552017-06-19 10:58:08 -0700737TEST_F(ProfileAssistantTest, TestBootImageProfile) {
738 const std::string core_dex = GetLibCoreDexFileNames()[0];
739
740 std::vector<ScratchFile> profiles;
741
742 // In image with enough clean occurrences.
743 const std::string kCleanClass = "Ljava/lang/CharSequence;";
744 // In image with enough dirty occurrences.
745 const std::string kDirtyClass = "Ljava/lang/Object;";
746 // Not in image becauseof not enough occurrences.
747 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
748 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
749 // Method that is hot.
750 // Also adds the class through inference since it is in each dex.
751 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
752 // Method that doesn't add the class since its only in one profile. Should still show up in the
753 // boot profile.
754 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700755 // Method that gets marked as hot since it's in multiple profiles.
756 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700757
758 // Thresholds for this test.
759 static const size_t kDirtyThreshold = 3;
760 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700761 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700762
763 // Create a bunch of boot profiles.
764 std::string dex1 =
765 kCleanClass + "\n" +
766 kDirtyClass + "\n" +
767 kUncommonCleanClass + "\n" +
768 "H" + kHotMethod + "\n" +
769 kUncommonDirtyClass;
770 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000771 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700772 dex1, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700773
774 // Create a bunch of boot profiles.
775 std::string dex2 =
776 kCleanClass + "\n" +
777 kDirtyClass + "\n" +
778 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700779 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700780 kUncommonDirtyClass;
781 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000782 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700783 dex2, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700784
785 // Create a bunch of boot profiles.
786 std::string dex3 =
787 "S" + kHotMethod + "\n" +
788 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700789 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700790 kDirtyClass + "\n";
791 profiles.emplace_back(ScratchFile());
David Brazdilf13ac7c2018-01-30 10:09:08 +0000792 EXPECT_TRUE(CreateProfile(
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700793 dex3, profiles.back().GetFilename(), core_dex));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700794
795 // Generate the boot profile.
796 ScratchFile out_profile;
797 std::vector<std::string> args;
798 args.push_back(GetProfmanCmd());
799 args.push_back("--generate-boot-image-profile");
800 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
801 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700802 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700803 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
804 args.push_back("--apk=" + core_dex);
805 args.push_back("--dex-location=" + core_dex);
806 for (const ScratchFile& profile : profiles) {
807 args.push_back("--profile-file=" + profile.GetFilename());
808 }
809 std::string error;
810 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
811 ASSERT_EQ(0, out_profile.GetFile()->Flush());
812 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
813
814 // Verify the boot profile contents.
815 std::string output_file_contents;
816 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
817 // Common classes, should be in the classes of the profile.
818 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
819 << output_file_contents;
820 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
821 << output_file_contents;
822 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
823 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
824 << output_file_contents;
825 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
826 << output_file_contents;
827 // Inferred class from a method common to all three profiles.
828 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
829 << output_file_contents;
830 // Aggregated methods hotness information.
831 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
832 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700833 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700834 << output_file_contents;
835 // Not inferred class, method is only in one profile.
836 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
837 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700838 // Test the sampled methods that became hot.
839 // Other method is in only one profile, it should not become hot.
840 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
841 << output_file_contents;
842 // Multi method is in at least two profiles, it should become hot.
843 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
844 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700845}
846
David Sehr7c80f2d2017-02-07 16:47:58 -0800847TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
848 // Class names put here need to be in sorted order.
849 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800850 "Ldoesnt/match/this/one;",
851 "Ljava/lang/Comparable;",
852 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800853 };
854 std::string input_file_contents;
855 for (std::string& class_name : class_names) {
856 input_file_contents += class_name + std::string("\n");
857 }
858 std::string output_file_contents;
859 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
860 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700861 class_names[1] + std::string("\n") +
862 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800863 ASSERT_EQ(output_file_contents, expected_contents);
864}
865
866TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
867 // Class names put here need to be in sorted order.
868 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800869 "Ldoesnt/match/this/one;",
870 "Ldoesnt/match/this/one/either;",
871 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800872 };
873 std::string input_file_contents;
874 for (std::string& class_name : class_names) {
875 input_file_contents += class_name + std::string("\n");
876 }
877 std::string output_file_contents;
878 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
879 std::string expected_contents("");
880 ASSERT_EQ(output_file_contents, expected_contents);
881}
882
Calin Juravlee0ac1152017-02-13 19:03:47 -0800883TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
884 // Create the profile content.
885 std::vector<std::string> methods = {
886 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
887 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
888 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800889 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800890 "LTestInline;->noInlineCache(LSuper;)I"
891 };
892 std::string input_file_contents;
893 for (std::string& m : methods) {
894 input_file_contents += m + std::string("\n");
895 }
896
897 // Create the profile and save it to disk.
898 ScratchFile profile_file;
899 ASSERT_TRUE(CreateProfile(input_file_contents,
900 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -0700901 GetTestDexFileName("ProfileTestMultiDex")));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800902
903 // Load the profile from disk.
904 ProfileCompilationInfo info;
905 profile_file.GetFile()->ResetOffset();
906 ASSERT_TRUE(info.Load(GetFd(profile_file)));
907
908 // Load the dex files and verify that the profile contains the expected methods info.
909 ScopedObjectAccess soa(Thread::Current());
910 jobject class_loader = LoadDex("ProfileTestMultiDex");
911 ASSERT_NE(class_loader, nullptr);
912
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100913 StackHandleScope<3> hs(soa.Self());
914 Handle<mirror::Class> sub_a = hs.NewHandle(GetClass(soa, class_loader, "LSubA;"));
915 Handle<mirror::Class> sub_b = hs.NewHandle(GetClass(soa, class_loader, "LSubB;"));
916 Handle<mirror::Class> sub_c = hs.NewHandle(GetClass(soa, class_loader, "LSubC;"));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800917
918 ASSERT_TRUE(sub_a != nullptr);
919 ASSERT_TRUE(sub_b != nullptr);
920 ASSERT_TRUE(sub_c != nullptr);
921
922 {
923 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
924 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
925 "LTestInline;",
926 "inlineMonomorphic");
927 ASSERT_TRUE(inline_monomorphic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100928 TypeReferenceSet expected_monomorphic;
929 expected_monomorphic.insert(MakeTypeReference(sub_a.Get()));
Calin Juravle589e71e2017-03-03 16:05:05 -0800930 AssertInlineCaches(inline_monomorphic,
931 expected_monomorphic,
932 info,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700933 /*is_megamorphic=*/false,
934 /*is_missing_types=*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800935 }
936
937 {
938 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
939 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
940 "LTestInline;",
941 "inlinePolymorphic");
942 ASSERT_TRUE(inline_polymorhic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100943 TypeReferenceSet expected_polymorphic;
944 expected_polymorphic.insert(MakeTypeReference(sub_a.Get()));
945 expected_polymorphic.insert(MakeTypeReference(sub_b.Get()));
946 expected_polymorphic.insert(MakeTypeReference(sub_c.Get()));
Calin Juravle589e71e2017-03-03 16:05:05 -0800947 AssertInlineCaches(inline_polymorhic,
948 expected_polymorphic,
949 info,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700950 /*is_megamorphic=*/false,
951 /*is_missing_types=*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800952 }
953
954 {
955 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
956 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
957 "LTestInline;",
958 "inlineMegamorphic");
959 ASSERT_TRUE(inline_megamorphic != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100960 TypeReferenceSet expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800961 AssertInlineCaches(inline_megamorphic,
962 expected_megamorphic,
963 info,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700964 /*is_megamorphic=*/true,
965 /*is_missing_types=*/false);
Calin Juravle589e71e2017-03-03 16:05:05 -0800966 }
967
968 {
969 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
970 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
971 "LTestInline;",
972 "inlineMissingTypes");
973 ASSERT_TRUE(inline_missing_types != nullptr);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +0100974 TypeReferenceSet expected_missing_Types;
Calin Juravle589e71e2017-03-03 16:05:05 -0800975 AssertInlineCaches(inline_missing_types,
976 expected_missing_Types,
977 info,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700978 /*is_megamorphic=*/false,
979 /*is_missing_types=*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800980 }
981
982 {
983 // Verify that method noInlineCache has no inline caches in the profile.
984 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
985 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700986 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
987 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
988 no_inline_cache->GetDexFile()->GetLocationChecksum(),
989 no_inline_cache->GetDexMethodIndex());
990 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700991 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800992 }
993}
994
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700995TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
996 ScratchFile profile1;
997 ScratchFile reference_profile;
998
999 std::vector<int> profile_fds({GetFd(profile1)});
1000 int reference_profile_fd = GetFd(reference_profile);
1001
1002 // The new profile info will contain the methods with indices 0-100.
1003 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1004 ProfileCompilationInfo info1;
1005 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
Andreas Gampe9b031f72018-10-04 11:03:34 -07001006 /*start_method_index=*/0, /*reverse_dex_write_order=*/false);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001007
1008 // The reference profile info will contain the methods with indices 50-150.
1009 // When setting up the profile reverse the order in which the dex files
1010 // are added to the profile. This will verify that profman merges profiles
1011 // with a different dex order correctly.
1012 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1013 ProfileCompilationInfo reference_info;
1014 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Andreas Gampe9b031f72018-10-04 11:03:34 -07001015 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order=*/true);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001016
1017 // We should advise compilation.
1018 ASSERT_EQ(ProfileAssistant::kCompile,
1019 ProcessProfiles(profile_fds, reference_profile_fd));
1020
1021 // The resulting compilation info must be equal to the merge of the inputs.
1022 ProfileCompilationInfo result;
1023 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1024 ASSERT_TRUE(result.Load(reference_profile_fd));
1025
1026 ProfileCompilationInfo expected;
1027 ASSERT_TRUE(expected.MergeWith(reference_info));
1028 ASSERT_TRUE(expected.MergeWith(info1));
1029 ASSERT_TRUE(expected.Equals(result));
1030
1031 // The information from profile must remain the same.
1032 CheckProfileInfo(profile1, info1);
1033}
1034
Calin Juravle08556882017-05-26 16:40:45 -07001035TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
1036 // Create the profile content.
1037 std::vector<std::string> profile_methods = {
1038 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
1039 "LTestInline;->invalid_method",
1040 "invalid_class"
1041 };
1042 std::string input_file_contents;
1043 for (std::string& m : profile_methods) {
1044 input_file_contents += m + std::string("\n");
1045 }
1046
1047 // Create the profile and save it to disk.
1048 ScratchFile profile_file;
1049 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1050 ASSERT_TRUE(CreateProfile(input_file_contents,
1051 profile_file.GetFilename(),
Calin Juravle1bfe4bd2018-04-26 16:00:11 -07001052 dex_filename));
Calin Juravle08556882017-05-26 16:40:45 -07001053
1054 // Load the profile from disk.
1055 ProfileCompilationInfo info;
1056 profile_file.GetFile()->ResetOffset();
1057 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1058
1059 // Load the dex files and verify that the profile contains the expected methods info.
1060 ScopedObjectAccess soa(Thread::Current());
1061 jobject class_loader = LoadDex("ProfileTestMultiDex");
1062 ASSERT_NE(class_loader, nullptr);
1063
1064 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1065 "LTestInline;",
1066 "inlineMonomorphic");
1067 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1068
1069 // Verify that the inline cache contains the invalid type.
1070 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1071 info.GetMethod(dex_file->GetLocation(),
1072 dex_file->GetLocationChecksum(),
1073 inline_monomorphic->GetDexMethodIndex());
1074 ASSERT_TRUE(pmi != nullptr);
1075 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1076 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1077 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1078 ASSERT_EQ(1u, dex_pc_data.classes.size());
1079 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1080
1081 // Verify that the start-up classes contain the invalid class.
1082 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001083 std::set<uint16_t> hot_methods;
1084 std::set<uint16_t> startup_methods;
1085 std::set<uint16_t> post_start_methods;
1086 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1087 &classes,
1088 &hot_methods,
1089 &startup_methods,
1090 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001091 ASSERT_EQ(1u, classes.size());
1092 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1093
Calin Juravleee9cb412018-02-13 20:32:35 -08001094 // Verify that the invalid method did not get in the profile.
1095 ASSERT_EQ(1u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001096 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Calin Juravleee9cb412018-02-13 20:32:35 -08001097 ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001098}
1099
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001100TEST_F(ProfileAssistantTest, DumpOnly) {
1101 ScratchFile profile;
1102
1103 const uint32_t kNumberOfMethods = 64;
1104 std::vector<uint32_t> hot_methods;
1105 std::vector<uint32_t> startup_methods;
1106 std::vector<uint32_t> post_startup_methods;
1107 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1108 if (i % 2 == 0) {
1109 hot_methods.push_back(i);
1110 }
1111 if (i % 3 == 1) {
1112 startup_methods.push_back(i);
1113 }
1114 if (i % 4 == 2) {
1115 post_startup_methods.push_back(i);
1116 }
1117 }
1118 EXPECT_GT(hot_methods.size(), 0u);
1119 EXPECT_GT(startup_methods.size(), 0u);
1120 EXPECT_GT(post_startup_methods.size(), 0u);
1121 ProfileCompilationInfo info1;
1122 SetupBasicProfile("p1",
1123 1,
1124 kNumberOfMethods,
1125 hot_methods,
1126 startup_methods,
1127 post_startup_methods,
1128 profile,
1129 &info1);
1130 std::string output;
1131 DumpOnly(profile.GetFilename(), &output);
1132 const size_t hot_offset = output.find("hot methods:");
1133 const size_t startup_offset = output.find("startup methods:");
1134 const size_t post_startup_offset = output.find("post startup methods:");
1135 const size_t classes_offset = output.find("classes:");
1136 ASSERT_NE(hot_offset, std::string::npos);
1137 ASSERT_NE(startup_offset, std::string::npos);
1138 ASSERT_NE(post_startup_offset, std::string::npos);
1139 ASSERT_LT(hot_offset, startup_offset);
1140 ASSERT_LT(startup_offset, post_startup_offset);
1141 // Check the actual contents of the dump by looking at the offsets of the methods.
1142 for (uint32_t m : hot_methods) {
1143 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001144 ASSERT_NE(pos, std::string::npos) << output;
1145 EXPECT_LT(pos, startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001146 }
1147 for (uint32_t m : startup_methods) {
1148 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001149 ASSERT_NE(pos, std::string::npos) << output;
1150 EXPECT_LT(pos, post_startup_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001151 }
1152 for (uint32_t m : post_startup_methods) {
1153 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001154 ASSERT_NE(pos, std::string::npos) << output;
1155 EXPECT_LT(pos, classes_offset) << output;
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001156 }
1157}
1158
Calin Juravlee10c1e22018-01-26 20:10:15 -08001159TEST_F(ProfileAssistantTest, MergeProfilesWithFilter) {
1160 ScratchFile profile1;
1161 ScratchFile profile2;
1162 ScratchFile reference_profile;
1163
1164 std::vector<int> profile_fds({
1165 GetFd(profile1),
1166 GetFd(profile2)});
1167 int reference_profile_fd = GetFd(reference_profile);
1168
1169 // Use a real dex file to generate profile test data.
1170 // The file will be used during merging to filter unwanted data.
1171 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1172 const DexFile& d1 = *dex_files[0];
1173 const DexFile& d2 = *dex_files[1];
1174 // The new profile info will contain the methods with indices 0-100.
1175 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1176 ProfileCompilationInfo info1;
1177 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1178 kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
1179 ProfileCompilationInfo info2;
1180 SetupProfile(d2.GetLocation(), d2.GetLocationChecksum(), "p2", 2,
1181 kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
1182
1183
1184 // The reference profile info will contain the methods with indices 50-150.
1185 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
1186 ProfileCompilationInfo reference_info;
1187 SetupProfile(d1.GetLocation(), d1.GetLocationChecksum(), "p1", 1,
1188 kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
1189 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
1190
1191 // Run profman and pass the dex file with --apk-fd.
1192 android::base::unique_fd apk_fd(
Andreas Gampedfcd82c2018-10-16 20:22:37 -07001193 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); // NOLINT
Calin Juravlee10c1e22018-01-26 20:10:15 -08001194 ASSERT_GE(apk_fd.get(), 0);
1195
1196 std::string profman_cmd = GetProfmanCmd();
1197 std::vector<std::string> argv_str;
1198 argv_str.push_back(profman_cmd);
1199 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1200 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1201 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1202 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1203 std::string error;
1204
1205 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1206
1207 // Verify that we can load the result.
1208
1209 ProfileCompilationInfo result;
1210 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1211 ASSERT_TRUE(result.Load(reference_profile_fd));
1212
1213
1214 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
1215 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
1216 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1217
1218 // Verify that the result filtered out data not belonging to the dex file.
1219 // This is equivalent to checking that the result is equal to the merging of
1220 // all profiles while filtering out data not belonging to the dex file.
1221
1222 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1223 [&d1, &d2](const std::string& dex_location, uint32_t checksum) -> bool {
1224 return (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d1.GetLocation())
1225 && checksum == d1.GetLocationChecksum())
1226 || (dex_location == ProfileCompilationInfo::GetProfileDexFileKey(d2.GetLocation())
1227 && checksum == d2.GetLocationChecksum());
1228 };
1229
1230 ProfileCompilationInfo info1_filter;
1231 ProfileCompilationInfo info2_filter;
1232 ProfileCompilationInfo expected;
1233
Andreas Gampe9b031f72018-10-04 11:03:34 -07001234 info2_filter.Load(profile1.GetFd(), /*merge_classes=*/ true, filter_fn);
1235 info2_filter.Load(profile2.GetFd(), /*merge_classes=*/ true, filter_fn);
1236 expected.Load(reference_profile.GetFd(), /*merge_classes=*/ true, filter_fn);
Calin Juravlee10c1e22018-01-26 20:10:15 -08001237
1238 ASSERT_TRUE(expected.MergeWith(info1_filter));
1239 ASSERT_TRUE(expected.MergeWith(info2_filter));
1240
1241 ASSERT_TRUE(expected.Equals(result));
1242}
1243
Calin Juravle02c08792018-02-15 19:40:48 -08001244TEST_F(ProfileAssistantTest, CopyAndUpdateProfileKey) {
1245 ScratchFile profile1;
1246 ScratchFile reference_profile;
1247
1248 // Use a real dex file to generate profile test data. During the copy-and-update the
1249 // matching is done based on checksum so we have to match with the real thing.
1250 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1251 const DexFile& d1 = *dex_files[0];
1252 const DexFile& d2 = *dex_files[1];
1253
1254 ProfileCompilationInfo info1;
1255 uint16_t num_methods_to_add = std::min(d1.NumMethodIds(), d2.NumMethodIds());
1256 SetupProfile("fake-location1",
1257 d1.GetLocationChecksum(),
1258 "fake-location2",
1259 d2.GetLocationChecksum(),
1260 num_methods_to_add,
Andreas Gampe9b031f72018-10-04 11:03:34 -07001261 /*number_of_classes=*/ 0,
Calin Juravle02c08792018-02-15 19:40:48 -08001262 profile1,
1263 &info1,
Andreas Gampe9b031f72018-10-04 11:03:34 -07001264 /*start_method_index=*/ 0,
1265 /*reverse_dex_write_order=*/ false,
1266 /*number_of_methods1=*/ d1.NumMethodIds(),
1267 /*number_of_methods2=*/ d2.NumMethodIds());
Calin Juravle02c08792018-02-15 19:40:48 -08001268
1269 // Run profman and pass the dex file with --apk-fd.
1270 android::base::unique_fd apk_fd(
Andreas Gampedfcd82c2018-10-16 20:22:37 -07001271 open(GetTestDexFileName("ProfileTestMultiDex").c_str(), O_RDONLY)); // NOLINT
Calin Juravle02c08792018-02-15 19:40:48 -08001272 ASSERT_GE(apk_fd.get(), 0);
1273
1274 std::string profman_cmd = GetProfmanCmd();
1275 std::vector<std::string> argv_str;
1276 argv_str.push_back(profman_cmd);
1277 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1278 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1279 argv_str.push_back("--apk-fd=" + std::to_string(apk_fd.get()));
1280 argv_str.push_back("--copy-and-update-profile-key");
1281 std::string error;
1282
1283 ASSERT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1284
1285 // Verify that we can load the result.
1286 ProfileCompilationInfo result;
1287 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1288 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1289
1290 // Verify that the renaming was done.
1291 for (uint16_t i = 0; i < num_methods_to_add; i ++) {
1292 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi;
1293 ASSERT_TRUE(result.GetMethod(d1.GetLocation(), d1.GetLocationChecksum(), i) != nullptr) << i;
1294 ASSERT_TRUE(result.GetMethod(d2.GetLocation(), d2.GetLocationChecksum(), i) != nullptr) << i;
1295
1296 ASSERT_TRUE(result.GetMethod("fake-location1", d1.GetLocationChecksum(), i) == nullptr);
1297 ASSERT_TRUE(result.GetMethod("fake-location2", d2.GetLocationChecksum(), i) == nullptr);
1298 }
1299}
1300
Calin Juravle3ee9cfd2018-12-11 13:38:35 -08001301TEST_F(ProfileAssistantTest, MergeProfilesWithCounters) {
1302 ScratchFile profile1;
1303 ScratchFile profile2;
1304 ScratchFile reference_profile;
1305
1306 // The new profile info will contain methods with indices 0-100.
1307 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
1308 const uint16_t kNumberOfClasses = 50;
1309
1310 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
1311 const DexFile& d1 = *dex_files[0];
1312 const DexFile& d2 = *dex_files[1];
1313 ProfileCompilationInfo info1;
1314 SetupProfile(
1315 d1.GetLocation(), d1.GetLocationChecksum(),
1316 d2.GetLocation(), d2.GetLocationChecksum(),
1317 kNumberOfMethodsToEnableCompilation, kNumberOfClasses, profile1, &info1);
1318 ProfileCompilationInfo info2;
1319 SetupProfile(
1320 d1.GetLocation(), d1.GetLocationChecksum(),
1321 d2.GetLocation(), d2.GetLocationChecksum(),
1322 kNumberOfMethodsToEnableCompilation, kNumberOfClasses, profile2, &info2);
1323
1324 std::string profman_cmd = GetProfmanCmd();
1325 std::vector<std::string> argv_str;
1326 argv_str.push_back(profman_cmd);
1327 argv_str.push_back("--profile-file-fd=" + std::to_string(profile1.GetFd()));
1328 argv_str.push_back("--profile-file-fd=" + std::to_string(profile2.GetFd()));
1329 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile.GetFd()));
1330 argv_str.push_back("--store-aggregation-counters");
1331 std::string error;
1332
1333 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0) << error;
1334
1335 // Verify that we can load the result and that the counters are in place.
1336
1337 ProfileCompilationInfo result;
1338 result.PrepareForAggregationCounters();
1339 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
1340 ASSERT_TRUE(result.Load(reference_profile.GetFd()));
1341
1342 ASSERT_TRUE(result.StoresAggregationCounters());
1343 ASSERT_EQ(2, result.GetAggregationCounter());
1344
1345 for (uint16_t i = 0; i < kNumberOfMethodsToEnableCompilation; i++) {
1346 ASSERT_EQ(1, result.GetMethodAggregationCounter(MethodReference(&d1, i)));
1347 ASSERT_EQ(1, result.GetMethodAggregationCounter(MethodReference(&d2, i)));
1348 }
1349 for (uint16_t i = 0; i < kNumberOfClasses; i++) {
1350 ASSERT_EQ(1, result.GetClassAggregationCounter(TypeReference(&d1, dex::TypeIndex(i))));
1351 }
1352}
1353
Calin Juravle2e2db782016-02-23 12:00:03 +00001354} // namespace art