blob: 73724b2ad5be7dddd0e5daa60889001667e4a271 [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 Juravlee0ac1152017-02-13 19:03:47 -080019#include "art_method-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000020#include "base/unix_file/fd_file.h"
21#include "common_runtime_test.h"
David Sehr97c381e2017-02-01 15:09:58 -080022#include "exec_utils.h"
Calin Juravle33083d62017-01-18 15:29:12 -080023#include "jit/profile_compilation_info.h"
Calin Juravlecc3171a2017-05-19 16:47:53 -070024#include "linear_alloc.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080025#include "mirror/class-inl.h"
Mathieu Chartierd808e8b2017-03-21 13:37:41 -070026#include "obj_ptr-inl.h"
Calin Juravlee0ac1152017-02-13 19:03:47 -080027#include "profile_assistant.h"
28#include "scoped_thread_state_change-inl.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000029#include "utils.h"
30
31namespace art {
32
Mathieu Chartierea650f32017-05-24 12:04:13 -070033static constexpr size_t kMaxMethodIds = 65535;
34
Calin Juravle2e2db782016-02-23 12:00:03 +000035class ProfileAssistantTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070036 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070037 void PostRuntimeCreate() OVERRIDE {
Calin Juravlecc3171a2017-05-19 16:47:53 -070038 arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
39 }
40
Calin Juravle2e2db782016-02-23 12:00:03 +000041 protected:
42 void SetupProfile(const std::string& id,
43 uint32_t checksum,
44 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010045 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000046 const ScratchFile& profile,
47 ProfileCompilationInfo* info,
Calin Juravlecea9e9d2017-03-23 19:04:59 -070048 uint16_t start_method_index = 0,
49 bool reverse_dex_write_order = false) {
Calin Juravle2e2db782016-02-23 12:00:03 +000050 std::string dex_location1 = "location1" + id;
51 uint32_t dex_location_checksum1 = checksum;
52 std::string dex_location2 = "location2" + id;
53 uint32_t dex_location_checksum2 = 10 * checksum;
54 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070055 // reverse_dex_write_order controls the order in which the dex files will be added to
56 // the profile and thus written to disk.
57 ProfileCompilationInfo::OfflineProfileMethodInfo pmi =
58 GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
59 dex_location2, dex_location_checksum2);
60 if (reverse_dex_write_order) {
Mathieu Chartierea650f32017-05-24 12:04:13 -070061 ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
62 ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070063 } else {
Mathieu Chartierea650f32017-05-24 12:04:13 -070064 ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
65 ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
Calin Juravlecea9e9d2017-03-23 19:04:59 -070066 }
Calin Juravle2e2db782016-02-23 12:00:03 +000067 }
Calin Juravlec824b512016-03-29 20:33:33 +010068 for (uint16_t i = 0; i < number_of_classes; i++) {
Mathieu Chartierea650f32017-05-24 12:04:13 -070069 ASSERT_TRUE(info->AddClassIndex(dex_location1,
70 dex_location_checksum1,
71 dex::TypeIndex(i),
72 kMaxMethodIds));
Calin Juravlec824b512016-03-29 20:33:33 +010073 }
74
Calin Juravle2e2db782016-02-23 12:00:03 +000075 ASSERT_TRUE(info->Save(GetFd(profile)));
76 ASSERT_EQ(0, profile.GetFile()->Flush());
77 ASSERT_TRUE(profile.GetFile()->ResetOffset());
78 }
79
Mathieu Chartier28b5c582017-06-06 14:12:50 -070080 void SetupBasicProfile(const std::string& id,
81 uint32_t checksum,
82 uint16_t number_of_methods,
83 const std::vector<uint32_t> hot_methods,
84 const std::vector<uint32_t> startup_methods,
85 const std::vector<uint32_t> post_startup_methods,
86 const ScratchFile& profile,
87 ProfileCompilationInfo* info) {
88 std::string dex_location = "location1" + id;
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070089 using Hotness = ProfileCompilationInfo::MethodHotness;
Mathieu Chartier28b5c582017-06-06 14:12:50 -070090 for (uint32_t idx : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070091 info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -070092 }
93 for (uint32_t idx : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070094 info->AddMethodIndex(Hotness::kFlagStartup, dex_location, checksum, idx, number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -070095 }
96 for (uint32_t idx : post_startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070097 info->AddMethodIndex(Hotness::kFlagPostStartup,
98 dex_location,
99 checksum,
100 idx,
101 number_of_methods);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700102 }
103 ASSERT_TRUE(info->Save(GetFd(profile)));
104 ASSERT_EQ(0, profile.GetFile()->Flush());
105 ASSERT_TRUE(profile.GetFile()->ResetOffset());
106 }
107
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700108 // Creates an inline cache which will be destructed at the end of the test.
109 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
110 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
111 std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
112 return used_inline_caches.back().get();
113 }
114
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700115 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo(
116 const std::string& dex_location1, uint32_t dex_checksum1,
117 const std::string& dex_location2, uint32_t dex_checksum2) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700118 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
119 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700120 pmi.dex_references.emplace_back(dex_location1, dex_checksum1, kMaxMethodIds);
121 pmi.dex_references.emplace_back(dex_location2, dex_checksum2, kMaxMethodIds);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700122
123 // Monomorphic
124 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700125 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700126 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700127 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700128 }
129 // Polymorphic
130 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700131 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700132 dex_pc_data.AddClass(0, dex::TypeIndex(0));
133 dex_pc_data.AddClass(1, dex::TypeIndex(1));
134
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700135 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700136 }
137 // Megamorphic
138 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700139 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700140 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700141 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700142 }
143 // Missing types
144 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700145 ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700146 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700147 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700148 }
149
150 return pmi;
151 }
152
Calin Juravle2e2db782016-02-23 12:00:03 +0000153 int GetFd(const ScratchFile& file) const {
154 return static_cast<int>(file.GetFd());
155 }
156
157 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
158 ProfileCompilationInfo file_info;
159 ASSERT_TRUE(file.GetFile()->ResetOffset());
160 ASSERT_TRUE(file_info.Load(GetFd(file)));
161 ASSERT_TRUE(file_info.Equals(info));
162 }
163
Calin Juravle7bcdb532016-06-07 16:14:47 +0100164 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +0000165 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +0000166 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +0000167 if (kIsDebugBuild) {
168 file_path += "d";
169 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100170 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
171 << file_path << " should be a valid file path";
172 return file_path;
173 }
Mathieu Chartierf70fe3d2017-06-21 15:24:02 -0700174
Calin Juravle7bcdb532016-06-07 16:14:47 +0100175 // Runs test with given arguments.
176 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
177 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +0000178 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +0100179 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +0000180 for (size_t k = 0; k < profiles_fd.size(); k++) {
181 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
182 }
183 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
184
185 std::string error;
186 return ExecAndReturnCode(argv_str, &error);
187 }
Calin Juravle7bcdb532016-06-07 16:14:47 +0100188
189 bool GenerateTestProfile(const std::string& filename) {
190 std::string profman_cmd = GetProfmanCmd();
191 std::vector<std::string> argv_str;
192 argv_str.push_back(profman_cmd);
193 argv_str.push_back("--generate-test-profile=" + filename);
194 std::string error;
195 return ExecAndReturnCode(argv_str, &error);
196 }
David Sehr7c80f2d2017-02-07 16:47:58 -0800197
Jeff Haof0a31f82017-03-27 15:50:37 -0700198 bool GenerateTestProfileWithInputDex(const std::string& filename) {
199 std::string profman_cmd = GetProfmanCmd();
200 std::vector<std::string> argv_str;
201 argv_str.push_back(profman_cmd);
202 argv_str.push_back("--generate-test-profile=" + filename);
203 argv_str.push_back("--generate-test-profile-seed=0");
204 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
205 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
206 std::string error;
207 return ExecAndReturnCode(argv_str, &error);
208 }
209
Andreas Gampe641a4732017-08-24 13:21:35 -0700210 bool CreateProfile(const std::string& profile_file_contents,
Calin Juravlee0ac1152017-02-13 19:03:47 -0800211 const std::string& filename,
212 const std::string& dex_location) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800213 ScratchFile class_names_file;
214 File* file = class_names_file.GetFile();
Calin Juravlee0ac1152017-02-13 19:03:47 -0800215 EXPECT_TRUE(file->WriteFully(profile_file_contents.c_str(), profile_file_contents.length()));
David Sehr7c80f2d2017-02-07 16:47:58 -0800216 EXPECT_EQ(0, file->Flush());
217 EXPECT_TRUE(file->ResetOffset());
218 std::string profman_cmd = GetProfmanCmd();
219 std::vector<std::string> argv_str;
220 argv_str.push_back(profman_cmd);
221 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
222 argv_str.push_back("--reference-profile-file=" + filename);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800223 argv_str.push_back("--apk=" + dex_location);
224 argv_str.push_back("--dex-location=" + dex_location);
David Sehr7c80f2d2017-02-07 16:47:58 -0800225 std::string error;
226 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
227 return true;
228 }
229
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700230 bool RunProfman(const std::string& filename,
231 std::vector<std::string>& extra_args,
232 std::string* output) {
233 ScratchFile output_file;
David Sehr7c80f2d2017-02-07 16:47:58 -0800234 std::string profman_cmd = GetProfmanCmd();
235 std::vector<std::string> argv_str;
236 argv_str.push_back(profman_cmd);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700237 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
David Sehr7c80f2d2017-02-07 16:47:58 -0800238 argv_str.push_back("--profile-file=" + filename);
239 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800240 argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700241 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
David Sehr7c80f2d2017-02-07 16:47:58 -0800242 std::string error;
243 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700244 File* file = output_file.GetFile();
David Sehr7c80f2d2017-02-07 16:47:58 -0800245 EXPECT_EQ(0, file->Flush());
246 EXPECT_TRUE(file->ResetOffset());
247 int64_t length = file->GetLength();
248 std::unique_ptr<char[]> buf(new char[length]);
249 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700250 *output = std::string(buf.get(), length);
David Sehr7c80f2d2017-02-07 16:47:58 -0800251 return true;
252 }
253
Mathieu Chartier28b5c582017-06-06 14:12:50 -0700254 bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
255 std::vector<std::string> extra_args;
256 extra_args.push_back("--dump-classes-and-methods");
257 return RunProfman(filename, extra_args, file_contents);
258 }
259
260 bool DumpOnly(const std::string& filename, std::string* file_contents) {
261 std::vector<std::string> extra_args;
262 extra_args.push_back("--dump-only");
263 return RunProfman(filename, extra_args, file_contents);
264 }
265
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700266 bool CreateAndDump(const std::string& input_file_contents,
267 std::string* output_file_contents) {
David Sehr7c80f2d2017-02-07 16:47:58 -0800268 ScratchFile profile_file;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800269 EXPECT_TRUE(CreateProfile(input_file_contents,
270 profile_file.GetFilename(),
271 GetLibCoreDexFileNames()[0]));
David Sehr7c80f2d2017-02-07 16:47:58 -0800272 profile_file.GetFile()->ResetOffset();
Mathieu Chartier34067262017-04-06 13:55:46 -0700273 EXPECT_TRUE(DumpClassesAndMethods(profile_file.GetFilename(), output_file_contents));
David Sehr7c80f2d2017-02-07 16:47:58 -0800274 return true;
275 }
Calin Juravlee0ac1152017-02-13 19:03:47 -0800276
277 mirror::Class* GetClass(jobject class_loader, const std::string& clazz) {
278 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
279 Thread* self = Thread::Current();
280 ScopedObjectAccess soa(self);
281 StackHandleScope<1> hs(self);
282 Handle<mirror::ClassLoader> h_loader(
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700283 hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader))));
Calin Juravlee0ac1152017-02-13 19:03:47 -0800284 return class_linker->FindClass(self, clazz.c_str(), h_loader);
285 }
286
287 ArtMethod* GetVirtualMethod(jobject class_loader,
288 const std::string& clazz,
289 const std::string& name) {
290 mirror::Class* klass = GetClass(class_loader, clazz);
291 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
292 const auto pointer_size = class_linker->GetImagePointerSize();
293 ArtMethod* method = nullptr;
294 Thread* self = Thread::Current();
295 ScopedObjectAccess soa(self);
296 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
297 if (name == m.GetName()) {
298 EXPECT_TRUE(method == nullptr);
299 method = &m;
300 }
301 }
302 return method;
303 }
304
305 // Verify that given method has the expected inline caches and nothing else.
306 void AssertInlineCaches(ArtMethod* method,
307 const std::set<mirror::Class*>& expected_clases,
308 const ProfileCompilationInfo& info,
Calin Juravle589e71e2017-03-03 16:05:05 -0800309 bool is_megamorphic,
310 bool is_missing_types)
Calin Juravlee0ac1152017-02-13 19:03:47 -0800311 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700312 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
313 info.GetMethod(method->GetDexFile()->GetLocation(),
314 method->GetDexFile()->GetLocationChecksum(),
315 method->GetDexMethodIndex());
316 ASSERT_TRUE(pmi != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700317 ASSERT_EQ(pmi->inline_caches->size(), 1u);
318 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
Calin Juravlee0ac1152017-02-13 19:03:47 -0800319
Calin Juravle589e71e2017-03-03 16:05:05 -0800320 ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic);
321 ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800322 ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size());
323 size_t found = 0;
324 for (mirror::Class* it : expected_clases) {
325 for (const auto& class_ref : dex_pc_data.classes) {
326 ProfileCompilationInfo::DexReference dex_ref =
Calin Juravlecc3171a2017-05-19 16:47:53 -0700327 pmi->dex_references[class_ref.dex_profile_index];
Calin Juravlee0ac1152017-02-13 19:03:47 -0800328 if (dex_ref.MatchesDex(&(it->GetDexFile())) &&
329 class_ref.type_index == it->GetDexTypeIndex()) {
330 found++;
331 }
332 }
333 }
334
335 ASSERT_EQ(expected_clases.size(), found);
336 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700337
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700338 int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
339 uint16_t methods_in_ref_profile) {
340 ScratchFile profile;
341 ScratchFile reference_profile;
342 std::vector<int> profile_fds({ GetFd(profile)});
343 int reference_profile_fd = GetFd(reference_profile);
344 std::vector<uint32_t> hot_methods_cur;
345 std::vector<uint32_t> hot_methods_ref;
346 std::vector<uint32_t> empty_vector;
347 for (size_t i = 0; i < methods_in_cur_profile; ++i) {
348 hot_methods_cur.push_back(i);
349 }
350 for (size_t i = 0; i < methods_in_ref_profile; ++i) {
351 hot_methods_ref.push_back(i);
352 }
353 ProfileCompilationInfo info1;
354 uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
355 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
356 profile, &info1);
357 ProfileCompilationInfo info2;
358 SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
359 reference_profile, &info2);
360 return ProcessProfiles(profile_fds, reference_profile_fd);
361 }
362
363 int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
364 uint16_t classes_in_ref_profile) {
365 ScratchFile profile;
366 ScratchFile reference_profile;
367
368 std::vector<int> profile_fds({ GetFd(profile)});
369 int reference_profile_fd = GetFd(reference_profile);
370
371 ProfileCompilationInfo info1;
372 SetupProfile("p1", 1, 0, classes_in_cur_profile, profile, &info1);
373 ProfileCompilationInfo info2;
374 SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
375 return ProcessProfiles(profile_fds, reference_profile_fd);
376 }
377
Calin Juravlecc3171a2017-05-19 16:47:53 -0700378 std::unique_ptr<ArenaAllocator> arena_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700379
380 // Cache of inline caches generated during tests.
381 // This makes it easier to pass data between different utilities and ensure that
382 // caches are destructed at the end of the test.
383 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle2e2db782016-02-23 12:00:03 +0000384};
385
386TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
387 ScratchFile profile1;
388 ScratchFile profile2;
389 ScratchFile reference_profile;
390
391 std::vector<int> profile_fds({
392 GetFd(profile1),
393 GetFd(profile2)});
394 int reference_profile_fd = GetFd(reference_profile);
395
396 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
397 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100398 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000399 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100400 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000401
402 // We should advise compilation.
403 ASSERT_EQ(ProfileAssistant::kCompile,
404 ProcessProfiles(profile_fds, reference_profile_fd));
405 // The resulting compilation info must be equal to the merge of the inputs.
406 ProfileCompilationInfo result;
407 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
408 ASSERT_TRUE(result.Load(reference_profile_fd));
409
410 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000411 ASSERT_TRUE(expected.MergeWith(info1));
412 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000413 ASSERT_TRUE(expected.Equals(result));
414
415 // The information from profiles must remain the same.
416 CheckProfileInfo(profile1, info1);
417 CheckProfileInfo(profile2, info2);
418}
419
Calin Juravlec824b512016-03-29 20:33:33 +0100420// TODO(calin): Add more tests for classes.
421TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
422 ScratchFile profile1;
423 ScratchFile reference_profile;
424
425 std::vector<int> profile_fds({
426 GetFd(profile1)});
427 int reference_profile_fd = GetFd(reference_profile);
428
429 const uint16_t kNumberOfClassesToEnableCompilation = 100;
430 ProfileCompilationInfo info1;
431 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
432
433 // We should advise compilation.
434 ASSERT_EQ(ProfileAssistant::kCompile,
435 ProcessProfiles(profile_fds, reference_profile_fd));
436 // The resulting compilation info must be equal to the merge of the inputs.
437 ProfileCompilationInfo result;
438 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
439 ASSERT_TRUE(result.Load(reference_profile_fd));
440
441 ProfileCompilationInfo expected;
442 ASSERT_TRUE(expected.MergeWith(info1));
443 ASSERT_TRUE(expected.Equals(result));
444
445 // The information from profiles must remain the same.
446 CheckProfileInfo(profile1, info1);
447}
448
Calin Juravle2e2db782016-02-23 12:00:03 +0000449TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
450 ScratchFile profile1;
451 ScratchFile profile2;
452 ScratchFile reference_profile;
453
454 std::vector<int> profile_fds({
455 GetFd(profile1),
456 GetFd(profile2)});
457 int reference_profile_fd = GetFd(reference_profile);
458
459 // The new profile info will contain the methods with indices 0-100.
460 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
461 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100462 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000463 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100464 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000465
466
467 // The reference profile info will contain the methods with indices 50-150.
468 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
469 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100470 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000471 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
472
473 // We should advise compilation.
474 ASSERT_EQ(ProfileAssistant::kCompile,
475 ProcessProfiles(profile_fds, reference_profile_fd));
476
477 // The resulting compilation info must be equal to the merge of the inputs
478 ProfileCompilationInfo result;
479 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
480 ASSERT_TRUE(result.Load(reference_profile_fd));
481
482 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000483 ASSERT_TRUE(expected.MergeWith(info1));
484 ASSERT_TRUE(expected.MergeWith(info2));
485 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000486 ASSERT_TRUE(expected.Equals(result));
487
488 // The information from profiles must remain the same.
489 CheckProfileInfo(profile1, info1);
490 CheckProfileInfo(profile2, info2);
491}
492
493TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
494 ScratchFile profile1;
495 ScratchFile profile2;
496 ScratchFile reference_profile;
497
498 std::vector<int> profile_fds({
499 GetFd(profile1),
500 GetFd(profile2)});
501 int reference_profile_fd = GetFd(reference_profile);
502
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700503 const uint16_t kNumberOfMethodsToSkipCompilation = 24; // Threshold is 100.
Calin Juravle2e2db782016-02-23 12:00:03 +0000504 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100505 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000506 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100507 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000508
509 // We should not advise compilation.
510 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
511 ProcessProfiles(profile_fds, reference_profile_fd));
512
513 // The information from profiles must remain the same.
514 ProfileCompilationInfo file_info1;
515 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
516 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
517 ASSERT_TRUE(file_info1.Equals(info1));
518
519 ProfileCompilationInfo file_info2;
520 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
521 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
522 ASSERT_TRUE(file_info2.Equals(info2));
523
524 // Reference profile files must remain empty.
525 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
526
527 // The information from profiles must remain the same.
528 CheckProfileInfo(profile1, info1);
529 CheckProfileInfo(profile2, info2);
530}
531
Shubham Ajmera9ab6e1d2017-09-25 18:40:54 -0700532TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
533 const uint16_t kNumberOfMethodsInRefProfile = 6000;
534 const uint16_t kNumberOfMethodsInCurProfile = 6100; // Threshold is 2%.
535 // We should not advise compilation.
536 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
537 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
538 kNumberOfMethodsInRefProfile));
539}
540
541TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
542 const uint16_t kNumberOfMethodsInRefProfile = 6000;
543 const uint16_t kNumberOfMethodsInCurProfile = 6200; // Threshold is 2%.
544 // We should advise compilation.
545 ASSERT_EQ(ProfileAssistant::kCompile,
546 CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
547 kNumberOfMethodsInRefProfile));
548}
549
550TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
551 const uint16_t kNumberOfClassesInRefProfile = 6000;
552 const uint16_t kNumberOfClassesInCurProfile = 6110; // Threshold is 2%.
553 // We should not advise compilation.
554 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
555 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
556 kNumberOfClassesInRefProfile));
557}
558
559TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
560 const uint16_t kNumberOfClassesInRefProfile = 6000;
561 const uint16_t kNumberOfClassesInCurProfile = 6120; // Threshold is 2%.
562 // We should advise compilation.
563 ASSERT_EQ(ProfileAssistant::kCompile,
564 CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
565 kNumberOfClassesInRefProfile));
566}
567
Calin Juravle2e2db782016-02-23 12:00:03 +0000568TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
569 ScratchFile profile1;
570 ScratchFile profile2;
571 ScratchFile reference_profile;
572
573 std::vector<int> profile_fds({
574 GetFd(profile1),
575 GetFd(profile2)});
576 int reference_profile_fd = GetFd(reference_profile);
577
578 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
579 // Assign different hashes for the same dex file. This will make merging of information to fail.
580 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100581 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000582 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100583 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000584
585 // We should fail processing.
586 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
587 ProcessProfiles(profile_fds, reference_profile_fd));
588
589 // The information from profiles must remain the same.
590 CheckProfileInfo(profile1, info1);
591 CheckProfileInfo(profile2, info2);
592
593 // Reference profile files must still remain empty.
594 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
595}
596
597TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
598 ScratchFile profile1;
599 ScratchFile reference_profile;
600
601 std::vector<int> profile_fds({
602 GetFd(profile1)});
603 int reference_profile_fd = GetFd(reference_profile);
604
605 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
606 // Assign different hashes for the same dex file. This will make merging of information to fail.
607 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100608 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000609 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100610 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000611
612 // We should not advise compilation.
613 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
614 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
615 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
616 ProcessProfiles(profile_fds, reference_profile_fd));
617
618 // The information from profiles must remain the same.
619 CheckProfileInfo(profile1, info1);
620}
621
Calin Juravle7bcdb532016-06-07 16:14:47 +0100622TEST_F(ProfileAssistantTest, TestProfileGeneration) {
623 ScratchFile profile;
624 // Generate a test profile.
625 GenerateTestProfile(profile.GetFilename());
626
627 // Verify that the generated profile is valid and can be loaded.
628 ASSERT_TRUE(profile.GetFile()->ResetOffset());
629 ProfileCompilationInfo info;
630 ASSERT_TRUE(info.Load(GetFd(profile)));
631}
632
Jeff Haof0a31f82017-03-27 15:50:37 -0700633TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
634 ScratchFile profile;
635 // Generate a test profile passing in a dex file as reference.
636 GenerateTestProfileWithInputDex(profile.GetFilename());
637
638 // Verify that the generated profile is valid and can be loaded.
639 ASSERT_TRUE(profile.GetFile()->ResetOffset());
640 ProfileCompilationInfo info;
641 ASSERT_TRUE(info.Load(GetFd(profile)));
642}
643
David Sehr7c80f2d2017-02-07 16:47:58 -0800644TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
645 // Class names put here need to be in sorted order.
646 std::vector<std::string> class_names = {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700647 "HLjava/lang/Object;-><init>()V",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800648 "Ljava/lang/Comparable;",
649 "Ljava/lang/Math;",
Mathieu Chartier34067262017-04-06 13:55:46 -0700650 "Ljava/lang/Object;",
Mathieu Chartierea650f32017-05-24 12:04:13 -0700651 "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
David Sehr7c80f2d2017-02-07 16:47:58 -0800652 };
Mathieu Chartier34067262017-04-06 13:55:46 -0700653 std::string file_contents;
David Sehr7c80f2d2017-02-07 16:47:58 -0800654 for (std::string& class_name : class_names) {
Mathieu Chartier34067262017-04-06 13:55:46 -0700655 file_contents += class_name + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800656 }
657 std::string output_file_contents;
Mathieu Chartier34067262017-04-06 13:55:46 -0700658 ASSERT_TRUE(CreateAndDump(file_contents, &output_file_contents));
659 ASSERT_EQ(output_file_contents, file_contents);
David Sehr7c80f2d2017-02-07 16:47:58 -0800660}
661
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700662TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) {
663 // Class names put here need to be in sorted order.
664 std::vector<std::string> class_names = {
665 "Ljava/lang/Math;->*",
666 };
667 std::string input_file_contents;
668 std::string expected_contents;
669 for (std::string& class_name : class_names) {
670 input_file_contents += class_name + std::string("\n");
671 expected_contents += DescriptorToDot(class_name.c_str()) +
672 std::string("\n");
673 }
674 std::string output_file_contents;
675 ScratchFile profile_file;
676 EXPECT_TRUE(CreateProfile(input_file_contents,
677 profile_file.GetFilename(),
678 GetLibCoreDexFileNames()[0]));
679 ProfileCompilationInfo info;
680 profile_file.GetFile()->ResetOffset();
681 ASSERT_TRUE(info.Load(GetFd(profile_file)));
682 // Verify that the profile has matching methods.
683 ScopedObjectAccess soa(Thread::Current());
684 ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;");
685 ASSERT_TRUE(klass != nullptr);
686 size_t method_count = 0;
687 for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
688 if (!method.IsCopied() && method.GetCodeItem() != nullptr) {
689 ++method_count;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700690 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
691 info.GetMethod(method.GetDexFile()->GetLocation(),
692 method.GetDexFile()->GetLocationChecksum(),
693 method.GetDexMethodIndex());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700694 ASSERT_TRUE(pmi != nullptr) << method.PrettyMethod();
Mathieu Chartierd808e8b2017-03-21 13:37:41 -0700695 }
696 }
697 EXPECT_GT(method_count, 0u);
698}
699
Mathieu Chartier2f794552017-06-19 10:58:08 -0700700TEST_F(ProfileAssistantTest, TestBootImageProfile) {
701 const std::string core_dex = GetLibCoreDexFileNames()[0];
702
703 std::vector<ScratchFile> profiles;
704
705 // In image with enough clean occurrences.
706 const std::string kCleanClass = "Ljava/lang/CharSequence;";
707 // In image with enough dirty occurrences.
708 const std::string kDirtyClass = "Ljava/lang/Object;";
709 // Not in image becauseof not enough occurrences.
710 const std::string kUncommonCleanClass = "Ljava/lang/Process;";
711 const std::string kUncommonDirtyClass = "Ljava/lang/Package;";
712 // Method that is hot.
713 // Also adds the class through inference since it is in each dex.
714 const std::string kHotMethod = "Ljava/lang/Comparable;->compareTo(Ljava/lang/Object;)I";
715 // Method that doesn't add the class since its only in one profile. Should still show up in the
716 // boot profile.
717 const std::string kOtherMethod = "Ljava/util/HashMap;-><init>()V";
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700718 // Method that gets marked as hot since it's in multiple profiles.
719 const std::string kMultiMethod = "Ljava/util/ArrayList;->clear()V";
Mathieu Chartier2f794552017-06-19 10:58:08 -0700720
721 // Thresholds for this test.
722 static const size_t kDirtyThreshold = 3;
723 static const size_t kCleanThreshold = 2;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700724 static const size_t kMethodThreshold = 2;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700725
726 // Create a bunch of boot profiles.
727 std::string dex1 =
728 kCleanClass + "\n" +
729 kDirtyClass + "\n" +
730 kUncommonCleanClass + "\n" +
731 "H" + kHotMethod + "\n" +
732 kUncommonDirtyClass;
733 profiles.emplace_back(ScratchFile());
734 EXPECT_TRUE(CreateProfile(dex1, profiles.back().GetFilename(), core_dex));
735
736 // Create a bunch of boot profiles.
737 std::string dex2 =
738 kCleanClass + "\n" +
739 kDirtyClass + "\n" +
740 "P" + kHotMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700741 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700742 kUncommonDirtyClass;
743 profiles.emplace_back(ScratchFile());
744 EXPECT_TRUE(CreateProfile(dex2, profiles.back().GetFilename(), core_dex));
745
746 // Create a bunch of boot profiles.
747 std::string dex3 =
748 "S" + kHotMethod + "\n" +
749 "P" + kOtherMethod + "\n" +
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700750 "P" + kMultiMethod + "\n" +
Mathieu Chartier2f794552017-06-19 10:58:08 -0700751 kDirtyClass + "\n";
752 profiles.emplace_back(ScratchFile());
753 EXPECT_TRUE(CreateProfile(dex3, profiles.back().GetFilename(), core_dex));
754
755 // Generate the boot profile.
756 ScratchFile out_profile;
757 std::vector<std::string> args;
758 args.push_back(GetProfmanCmd());
759 args.push_back("--generate-boot-image-profile");
760 args.push_back("--boot-image-class-threshold=" + std::to_string(kDirtyThreshold));
761 args.push_back("--boot-image-clean-class-threshold=" + std::to_string(kCleanThreshold));
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700762 args.push_back("--boot-image-sampled-method-threshold=" + std::to_string(kMethodThreshold));
Mathieu Chartier2f794552017-06-19 10:58:08 -0700763 args.push_back("--reference-profile-file=" + out_profile.GetFilename());
764 args.push_back("--apk=" + core_dex);
765 args.push_back("--dex-location=" + core_dex);
766 for (const ScratchFile& profile : profiles) {
767 args.push_back("--profile-file=" + profile.GetFilename());
768 }
769 std::string error;
770 EXPECT_EQ(ExecAndReturnCode(args, &error), 0) << error;
771 ASSERT_EQ(0, out_profile.GetFile()->Flush());
772 ASSERT_TRUE(out_profile.GetFile()->ResetOffset());
773
774 // Verify the boot profile contents.
775 std::string output_file_contents;
776 EXPECT_TRUE(DumpClassesAndMethods(out_profile.GetFilename(), &output_file_contents));
777 // Common classes, should be in the classes of the profile.
778 EXPECT_NE(output_file_contents.find(kCleanClass + "\n"), std::string::npos)
779 << output_file_contents;
780 EXPECT_NE(output_file_contents.find(kDirtyClass + "\n"), std::string::npos)
781 << output_file_contents;
782 // Uncommon classes, should not fit preloaded class criteria and should not be in the profile.
783 EXPECT_EQ(output_file_contents.find(kUncommonCleanClass + "\n"), std::string::npos)
784 << output_file_contents;
785 EXPECT_EQ(output_file_contents.find(kUncommonDirtyClass + "\n"), std::string::npos)
786 << output_file_contents;
787 // Inferred class from a method common to all three profiles.
788 EXPECT_NE(output_file_contents.find("Ljava/lang/Comparable;\n"), std::string::npos)
789 << output_file_contents;
790 // Aggregated methods hotness information.
791 EXPECT_NE(output_file_contents.find("HSP" + kHotMethod), std::string::npos)
792 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700793 EXPECT_NE(output_file_contents.find("P" + kOtherMethod), std::string::npos)
Mathieu Chartier2f794552017-06-19 10:58:08 -0700794 << output_file_contents;
795 // Not inferred class, method is only in one profile.
796 EXPECT_EQ(output_file_contents.find("Ljava/util/HashMap;\n"), std::string::npos)
797 << output_file_contents;
Mathieu Chartier8eecddf2017-07-12 16:05:54 -0700798 // Test the sampled methods that became hot.
799 // Other method is in only one profile, it should not become hot.
800 EXPECT_EQ(output_file_contents.find("HP" + kOtherMethod), std::string::npos)
801 << output_file_contents;
802 // Multi method is in at least two profiles, it should become hot.
803 EXPECT_NE(output_file_contents.find("HP" + kMultiMethod), std::string::npos)
804 << output_file_contents;
Mathieu Chartier2f794552017-06-19 10:58:08 -0700805}
806
David Sehr7c80f2d2017-02-07 16:47:58 -0800807TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
808 // Class names put here need to be in sorted order.
809 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800810 "Ldoesnt/match/this/one;",
811 "Ljava/lang/Comparable;",
812 "Ljava/lang/Object;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800813 };
814 std::string input_file_contents;
815 for (std::string& class_name : class_names) {
816 input_file_contents += class_name + std::string("\n");
817 }
818 std::string output_file_contents;
819 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
820 std::string expected_contents =
Mathieu Chartier34067262017-04-06 13:55:46 -0700821 class_names[1] + std::string("\n") +
822 class_names[2] + std::string("\n");
David Sehr7c80f2d2017-02-07 16:47:58 -0800823 ASSERT_EQ(output_file_contents, expected_contents);
824}
825
826TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
827 // Class names put here need to be in sorted order.
828 std::vector<std::string> class_names = {
Calin Juravlee0ac1152017-02-13 19:03:47 -0800829 "Ldoesnt/match/this/one;",
830 "Ldoesnt/match/this/one/either;",
831 "Lnor/this/one;"
David Sehr7c80f2d2017-02-07 16:47:58 -0800832 };
833 std::string input_file_contents;
834 for (std::string& class_name : class_names) {
835 input_file_contents += class_name + std::string("\n");
836 }
837 std::string output_file_contents;
838 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
839 std::string expected_contents("");
840 ASSERT_EQ(output_file_contents, expected_contents);
841}
842
Calin Juravlee0ac1152017-02-13 19:03:47 -0800843TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) {
844 // Create the profile content.
845 std::vector<std::string> methods = {
846 "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;",
847 "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;",
848 "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;",
Calin Juravle589e71e2017-03-03 16:05:05 -0800849 "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types",
Calin Juravlee0ac1152017-02-13 19:03:47 -0800850 "LTestInline;->noInlineCache(LSuper;)I"
851 };
852 std::string input_file_contents;
853 for (std::string& m : methods) {
854 input_file_contents += m + std::string("\n");
855 }
856
857 // Create the profile and save it to disk.
858 ScratchFile profile_file;
859 ASSERT_TRUE(CreateProfile(input_file_contents,
860 profile_file.GetFilename(),
861 GetTestDexFileName("ProfileTestMultiDex")));
862
863 // Load the profile from disk.
864 ProfileCompilationInfo info;
865 profile_file.GetFile()->ResetOffset();
866 ASSERT_TRUE(info.Load(GetFd(profile_file)));
867
868 // Load the dex files and verify that the profile contains the expected methods info.
869 ScopedObjectAccess soa(Thread::Current());
870 jobject class_loader = LoadDex("ProfileTestMultiDex");
871 ASSERT_NE(class_loader, nullptr);
872
873 mirror::Class* sub_a = GetClass(class_loader, "LSubA;");
874 mirror::Class* sub_b = GetClass(class_loader, "LSubB;");
875 mirror::Class* sub_c = GetClass(class_loader, "LSubC;");
876
877 ASSERT_TRUE(sub_a != nullptr);
878 ASSERT_TRUE(sub_b != nullptr);
879 ASSERT_TRUE(sub_c != nullptr);
880
881 {
882 // Verify that method inlineMonomorphic has the expected inline caches and nothing else.
883 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
884 "LTestInline;",
885 "inlineMonomorphic");
886 ASSERT_TRUE(inline_monomorphic != nullptr);
887 std::set<mirror::Class*> expected_monomorphic;
888 expected_monomorphic.insert(sub_a);
Calin Juravle589e71e2017-03-03 16:05:05 -0800889 AssertInlineCaches(inline_monomorphic,
890 expected_monomorphic,
891 info,
892 /*megamorphic*/false,
893 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800894 }
895
896 {
897 // Verify that method inlinePolymorphic has the expected inline caches and nothing else.
898 ArtMethod* inline_polymorhic = GetVirtualMethod(class_loader,
899 "LTestInline;",
900 "inlinePolymorphic");
901 ASSERT_TRUE(inline_polymorhic != nullptr);
902 std::set<mirror::Class*> expected_polymorphic;
903 expected_polymorphic.insert(sub_a);
904 expected_polymorphic.insert(sub_b);
905 expected_polymorphic.insert(sub_c);
Calin Juravle589e71e2017-03-03 16:05:05 -0800906 AssertInlineCaches(inline_polymorhic,
907 expected_polymorphic,
908 info,
909 /*megamorphic*/false,
910 /*missing_types*/false);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800911 }
912
913 {
914 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
915 ArtMethod* inline_megamorphic = GetVirtualMethod(class_loader,
916 "LTestInline;",
917 "inlineMegamorphic");
918 ASSERT_TRUE(inline_megamorphic != nullptr);
919 std::set<mirror::Class*> expected_megamorphic;
Calin Juravle589e71e2017-03-03 16:05:05 -0800920 AssertInlineCaches(inline_megamorphic,
921 expected_megamorphic,
922 info,
923 /*megamorphic*/true,
924 /*missing_types*/false);
925 }
926
927 {
928 // Verify that method inlineMegamorphic has the expected inline caches and nothing else.
929 ArtMethod* inline_missing_types = GetVirtualMethod(class_loader,
930 "LTestInline;",
931 "inlineMissingTypes");
932 ASSERT_TRUE(inline_missing_types != nullptr);
933 std::set<mirror::Class*> expected_missing_Types;
934 AssertInlineCaches(inline_missing_types,
935 expected_missing_Types,
936 info,
937 /*megamorphic*/false,
938 /*missing_types*/true);
Calin Juravlee0ac1152017-02-13 19:03:47 -0800939 }
940
941 {
942 // Verify that method noInlineCache has no inline caches in the profile.
943 ArtMethod* no_inline_cache = GetVirtualMethod(class_loader, "LTestInline;", "noInlineCache");
944 ASSERT_TRUE(no_inline_cache != nullptr);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700945 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi_no_inline_cache =
946 info.GetMethod(no_inline_cache->GetDexFile()->GetLocation(),
947 no_inline_cache->GetDexFile()->GetLocationChecksum(),
948 no_inline_cache->GetDexMethodIndex());
949 ASSERT_TRUE(pmi_no_inline_cache != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700950 ASSERT_TRUE(pmi_no_inline_cache->inline_caches->empty());
Calin Juravlee0ac1152017-02-13 19:03:47 -0800951 }
952}
953
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700954TEST_F(ProfileAssistantTest, MergeProfilesWithDifferentDexOrder) {
955 ScratchFile profile1;
956 ScratchFile reference_profile;
957
958 std::vector<int> profile_fds({GetFd(profile1)});
959 int reference_profile_fd = GetFd(reference_profile);
960
961 // The new profile info will contain the methods with indices 0-100.
962 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
963 ProfileCompilationInfo info1;
964 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
965 /*start_method_index*/0, /*reverse_dex_write_order*/false);
966
967 // The reference profile info will contain the methods with indices 50-150.
968 // When setting up the profile reverse the order in which the dex files
969 // are added to the profile. This will verify that profman merges profiles
970 // with a different dex order correctly.
971 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
972 ProfileCompilationInfo reference_info;
973 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
974 &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
975
976 // We should advise compilation.
977 ASSERT_EQ(ProfileAssistant::kCompile,
978 ProcessProfiles(profile_fds, reference_profile_fd));
979
980 // The resulting compilation info must be equal to the merge of the inputs.
981 ProfileCompilationInfo result;
982 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
983 ASSERT_TRUE(result.Load(reference_profile_fd));
984
985 ProfileCompilationInfo expected;
986 ASSERT_TRUE(expected.MergeWith(reference_info));
987 ASSERT_TRUE(expected.MergeWith(info1));
988 ASSERT_TRUE(expected.Equals(result));
989
990 // The information from profile must remain the same.
991 CheckProfileInfo(profile1, info1);
992}
993
Calin Juravle08556882017-05-26 16:40:45 -0700994TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
995 // Create the profile content.
996 std::vector<std::string> profile_methods = {
997 "LTestInline;->inlineMonomorphic(LSuper;)I+invalid_class",
998 "LTestInline;->invalid_method",
999 "invalid_class"
1000 };
1001 std::string input_file_contents;
1002 for (std::string& m : profile_methods) {
1003 input_file_contents += m + std::string("\n");
1004 }
1005
1006 // Create the profile and save it to disk.
1007 ScratchFile profile_file;
1008 std::string dex_filename = GetTestDexFileName("ProfileTestMultiDex");
1009 ASSERT_TRUE(CreateProfile(input_file_contents,
1010 profile_file.GetFilename(),
1011 dex_filename));
1012
1013 // Load the profile from disk.
1014 ProfileCompilationInfo info;
1015 profile_file.GetFile()->ResetOffset();
1016 ASSERT_TRUE(info.Load(GetFd(profile_file)));
1017
1018 // Load the dex files and verify that the profile contains the expected methods info.
1019 ScopedObjectAccess soa(Thread::Current());
1020 jobject class_loader = LoadDex("ProfileTestMultiDex");
1021 ASSERT_NE(class_loader, nullptr);
1022
1023 ArtMethod* inline_monomorphic = GetVirtualMethod(class_loader,
1024 "LTestInline;",
1025 "inlineMonomorphic");
1026 const DexFile* dex_file = inline_monomorphic->GetDexFile();
1027
1028 // Verify that the inline cache contains the invalid type.
1029 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> pmi =
1030 info.GetMethod(dex_file->GetLocation(),
1031 dex_file->GetLocationChecksum(),
1032 inline_monomorphic->GetDexMethodIndex());
1033 ASSERT_TRUE(pmi != nullptr);
1034 ASSERT_EQ(pmi->inline_caches->size(), 1u);
1035 const ProfileCompilationInfo::DexPcData& dex_pc_data = pmi->inline_caches->begin()->second;
1036 dex::TypeIndex invalid_class_index(std::numeric_limits<uint16_t>::max() - 1);
1037 ASSERT_EQ(1u, dex_pc_data.classes.size());
1038 ASSERT_EQ(invalid_class_index, dex_pc_data.classes.begin()->type_index);
1039
1040 // Verify that the start-up classes contain the invalid class.
1041 std::set<dex::TypeIndex> classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001042 std::set<uint16_t> hot_methods;
1043 std::set<uint16_t> startup_methods;
1044 std::set<uint16_t> post_start_methods;
1045 ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
1046 &classes,
1047 &hot_methods,
1048 &startup_methods,
1049 &post_start_methods));
Calin Juravle08556882017-05-26 16:40:45 -07001050 ASSERT_EQ(1u, classes.size());
1051 ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
1052
1053 // Verify that the invalid method is in the profile.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001054 ASSERT_EQ(2u, hot_methods.size());
Calin Juravle08556882017-05-26 16:40:45 -07001055 uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001056 ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
Calin Juravle08556882017-05-26 16:40:45 -07001057}
1058
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001059TEST_F(ProfileAssistantTest, DumpOnly) {
1060 ScratchFile profile;
1061
1062 const uint32_t kNumberOfMethods = 64;
1063 std::vector<uint32_t> hot_methods;
1064 std::vector<uint32_t> startup_methods;
1065 std::vector<uint32_t> post_startup_methods;
1066 for (size_t i = 0; i < kNumberOfMethods; ++i) {
1067 if (i % 2 == 0) {
1068 hot_methods.push_back(i);
1069 }
1070 if (i % 3 == 1) {
1071 startup_methods.push_back(i);
1072 }
1073 if (i % 4 == 2) {
1074 post_startup_methods.push_back(i);
1075 }
1076 }
1077 EXPECT_GT(hot_methods.size(), 0u);
1078 EXPECT_GT(startup_methods.size(), 0u);
1079 EXPECT_GT(post_startup_methods.size(), 0u);
1080 ProfileCompilationInfo info1;
1081 SetupBasicProfile("p1",
1082 1,
1083 kNumberOfMethods,
1084 hot_methods,
1085 startup_methods,
1086 post_startup_methods,
1087 profile,
1088 &info1);
1089 std::string output;
1090 DumpOnly(profile.GetFilename(), &output);
1091 const size_t hot_offset = output.find("hot methods:");
1092 const size_t startup_offset = output.find("startup methods:");
1093 const size_t post_startup_offset = output.find("post startup methods:");
1094 const size_t classes_offset = output.find("classes:");
1095 ASSERT_NE(hot_offset, std::string::npos);
1096 ASSERT_NE(startup_offset, std::string::npos);
1097 ASSERT_NE(post_startup_offset, std::string::npos);
1098 ASSERT_LT(hot_offset, startup_offset);
1099 ASSERT_LT(startup_offset, post_startup_offset);
1100 // Check the actual contents of the dump by looking at the offsets of the methods.
1101 for (uint32_t m : hot_methods) {
1102 const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
1103 ASSERT_NE(pos, std::string::npos);
1104 EXPECT_LT(pos, startup_offset);
1105 }
1106 for (uint32_t m : startup_methods) {
1107 const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
1108 ASSERT_NE(pos, std::string::npos);
1109 EXPECT_LT(pos, post_startup_offset);
1110 }
1111 for (uint32_t m : post_startup_methods) {
1112 const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
1113 ASSERT_NE(pos, std::string::npos);
1114 EXPECT_LT(pos, classes_offset);
1115 }
1116}
1117
Calin Juravle2e2db782016-02-23 12:00:03 +00001118} // namespace art