blob: e6917956ae30934d98d8b21ffb9a108d779dee62 [file] [log] [blame]
Calin Juravle877fd962016-01-05 14:29:29 +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>
Calin Juravle1e2de642018-01-18 01:08:23 -080018#include <stdio.h>
Calin Juravle877fd962016-01-05 14:29:29 +000019
Calin Juravle877fd962016-01-05 14:29:29 +000020#include "art_method-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include "base/unix_file/fd_file.h"
Calin Juravle877fd962016-01-05 14:29:29 +000022#include "class_linker-inl.h"
23#include "common_runtime_test.h"
David Sehr9e734c72018-01-04 17:56:19 -080024#include "dex/dex_file.h"
Calin Juravle2dba0ab2018-01-22 19:22:24 -080025#include "dex/dex_file_loader.h"
Calin Juravle877fd962016-01-05 14:29:29 +000026#include "handle_scope-inl.h"
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070027#include "jit/profile_compilation_info.h"
Mathieu Chartierdbddc222017-05-24 12:04:13 -070028#include "linear_alloc.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070029#include "method_reference.h"
30#include "mirror/class-inl.h"
31#include "mirror/class_loader.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070032#include "scoped_thread_state_change-inl.h"
Mathieu Chartierdbddc222017-05-24 12:04:13 -070033#include "type_reference.h"
Calin Juravle1e2de642018-01-18 01:08:23 -080034#include "ziparchive/zip_writer.h"
Calin Juravle877fd962016-01-05 14:29:29 +000035
36namespace art {
37
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070038using Hotness = ProfileCompilationInfo::MethodHotness;
39
Mathieu Chartierea650f32017-05-24 12:04:13 -070040static constexpr size_t kMaxMethodIds = 65535;
41
Calin Juravle877fd962016-01-05 14:29:29 +000042class ProfileCompilationInfoTest : public CommonRuntimeTest {
Calin Juravlecc3171a2017-05-19 16:47:53 -070043 public:
Calin Juravlee6f87cc2017-05-24 17:41:05 -070044 void PostRuntimeCreate() OVERRIDE {
Vladimir Marko69d310e2017-10-09 14:12:23 +010045 allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
Calin Juravlecc3171a2017-05-19 16:47:53 -070046 }
47
Calin Juravle877fd962016-01-05 14:29:29 +000048 protected:
49 std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
50 const std::string& clazz) {
51 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
52 Thread* self = Thread::Current();
53 ScopedObjectAccess soa(self);
54 StackHandleScope<1> hs(self);
Mathieu Chartierc4f39252016-10-05 18:32:08 -070055 Handle<mirror::ClassLoader> h_loader(
56 hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader()));
Calin Juravle877fd962016-01-05 14:29:29 +000057 mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
58
59 const auto pointer_size = class_linker->GetImagePointerSize();
60 std::vector<ArtMethod*> methods;
61 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
62 methods.push_back(&m);
63 }
64 return methods;
65 }
66
Calin Juravle85f7bf32016-03-18 16:23:40 +000067 bool AddMethod(const std::string& dex_location,
Calin Juravleb8697b12016-03-21 14:37:55 +000068 uint32_t checksum,
69 uint16_t method_index,
70 ProfileCompilationInfo* info) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070071 return info->AddMethodIndex(Hotness::kFlagHot,
72 dex_location,
73 checksum,
74 method_index,
75 kMaxMethodIds);
Calin Juravle877fd962016-01-05 14:29:29 +000076 }
77
Calin Juravle940eb0c2017-01-30 19:30:44 -080078 bool AddMethod(const std::string& dex_location,
79 uint32_t checksum,
80 uint16_t method_index,
81 const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
82 ProfileCompilationInfo* info) {
Calin Juravleee9cb412018-02-13 20:32:35 -080083 return info->AddMethod(
84 dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup);
Calin Juravle940eb0c2017-01-30 19:30:44 -080085 }
86
Calin Juravleb8697b12016-03-21 14:37:55 +000087 bool AddClass(const std::string& dex_location,
88 uint32_t checksum,
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070089 dex::TypeIndex type_index,
Calin Juravleb8697b12016-03-21 14:37:55 +000090 ProfileCompilationInfo* info) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070091 DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds);
92 classes.AddClass(type_index);
93 return info->AddClasses({classes});
Calin Juravleb8697b12016-03-21 14:37:55 +000094 }
95
Calin Juravle877fd962016-01-05 14:29:29 +000096 uint32_t GetFd(const ScratchFile& file) {
97 return static_cast<uint32_t>(file.GetFd());
98 }
Calin Juravleb8697b12016-03-21 14:37:55 +000099
Calin Juravlefe297a92016-03-24 20:33:22 +0000100 bool SaveProfilingInfo(
101 const std::string& filename,
102 const std::vector<ArtMethod*>& methods,
Calin Juravleee9cb412018-02-13 20:32:35 -0800103 const std::set<DexCacheResolvedClasses>& resolved_classes,
104 Hotness::Flag flags) {
Calin Juravlefe297a92016-03-24 20:33:22 +0000105 ProfileCompilationInfo info;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800106 std::vector<ProfileMethodInfo> profile_methods;
Calin Juravlee2d066d2016-04-19 16:33:46 +0100107 ScopedObjectAccess soa(Thread::Current());
108 for (ArtMethod* method : methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700109 profile_methods.emplace_back(
110 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
Calin Juravlee2d066d2016-04-19 16:33:46 +0100111 }
Calin Juravleee9cb412018-02-13 20:32:35 -0800112 if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800113 return false;
114 }
115 if (info.GetNumberOfMethods() != profile_methods.size()) {
Calin Juravlefe297a92016-03-24 20:33:22 +0000116 return false;
117 }
Calin Juravledcab1902017-05-12 19:18:47 -0700118 ProfileCompilationInfo file_profile;
119 if (!file_profile.Load(filename, false)) {
120 return false;
121 }
122 if (!info.MergeWith(file_profile)) {
123 return false;
124 }
125
126 return info.Save(filename, nullptr);
Calin Juravlefe297a92016-03-24 20:33:22 +0000127 }
128
Calin Juravle940eb0c2017-01-30 19:30:44 -0800129 // Saves the given art methods to a profile backed by 'filename' and adds
130 // some fake inline caches to it. The added inline caches are returned in
131 // the out map `profile_methods_map`.
132 bool SaveProfilingInfoWithFakeInlineCaches(
133 const std::string& filename,
134 const std::vector<ArtMethod*>& methods,
Calin Juravleee9cb412018-02-13 20:32:35 -0800135 Hotness::Flag flags,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800136 /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) {
137 ProfileCompilationInfo info;
138 std::vector<ProfileMethodInfo> profile_methods;
139 ScopedObjectAccess soa(Thread::Current());
140 for (ArtMethod* method : methods) {
141 std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
142 // Monomorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800143 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700144 std::vector<TypeReference> classes;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800145 classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
Calin Juravle589e71e2017-03-03 16:05:05 -0800146 caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800147 }
148 // Polymorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800149 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700150 std::vector<TypeReference> classes;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800151 for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
152 classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
153 }
Calin Juravle589e71e2017-03-03 16:05:05 -0800154 caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800155 }
156 // Megamorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800157 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700158 std::vector<TypeReference> classes;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800159 for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
160 classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
161 }
Calin Juravle589e71e2017-03-03 16:05:05 -0800162 caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
163 }
164 // Missing types
165 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700166 std::vector<TypeReference> classes;
Calin Juravle589e71e2017-03-03 16:05:05 -0800167 caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800168 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700169 ProfileMethodInfo pmi(MethodReference(method->GetDexFile(),
170 method->GetDexMethodIndex()),
Mathieu Chartierea650f32017-05-24 12:04:13 -0700171 caches);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800172 profile_methods.push_back(pmi);
173 profile_methods_map->Put(method, pmi);
174 }
175
Calin Juravleee9cb412018-02-13 20:32:35 -0800176 if (!info.AddMethods(profile_methods, flags)
177 || info.GetNumberOfMethods() != profile_methods.size()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800178 return false;
179 }
Calin Juravledcab1902017-05-12 19:18:47 -0700180 return info.Save(filename, nullptr);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800181 }
182
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700183 // Creates an inline cache which will be destructed at the end of the test.
184 ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
185 used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100186 std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700187 return used_inline_caches.back().get();
188 }
189
Calin Juravle940eb0c2017-01-30 19:30:44 -0800190 ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo(
191 const ProfileMethodInfo& pmi) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700192 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
193 ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800194 SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index
195 for (const auto& inline_cache : pmi.inline_caches) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800196 ProfileCompilationInfo::DexPcData& dex_pc_data =
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700197 ic_map->FindOrAdd(
Vladimir Marko69d310e2017-10-09 14:12:23 +0100198 inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
Calin Juravle589e71e2017-03-03 16:05:05 -0800199 if (inline_cache.is_missing_types) {
200 dex_pc_data.SetIsMissingTypes();
201 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800202 for (const auto& class_ref : inline_cache.classes) {
203 uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file),
204 static_cast<uint8_t>(dex_map.size()))->second;
Mathieu Chartierfc8b4222017-09-17 13:44:24 -0700205 dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800206 if (dex_profile_index >= offline_pmi.dex_references.size()) {
207 // This is a new dex.
208 const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
209 class_ref.dex_file->GetLocation());
210 offline_pmi.dex_references.emplace_back(dex_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700211 class_ref.dex_file->GetLocationChecksum(),
212 class_ref.dex_file->NumMethodIds());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800213 }
214 }
215 }
216 return offline_pmi;
217 }
218
219 // Creates an offline profile used for testing inline caches.
220 ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700221 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
Mathieu Chartierea650f32017-05-24 12:04:13 -0700222
Calin Juravle940eb0c2017-01-30 19:30:44 -0800223 // Monomorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800224 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100225 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800226 dex_pc_data.AddClass(0, dex::TypeIndex(0));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700227 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800228 }
229 // Polymorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800230 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100231 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800232 dex_pc_data.AddClass(0, dex::TypeIndex(0));
233 dex_pc_data.AddClass(1, dex::TypeIndex(1));
234 dex_pc_data.AddClass(2, dex::TypeIndex(2));
235
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700236 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800237 }
238 // Megamorphic
Calin Juravle589e71e2017-03-03 16:05:05 -0800239 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100240 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle589e71e2017-03-03 16:05:05 -0800241 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700242 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravle589e71e2017-03-03 16:05:05 -0800243 }
244 // Missing types
245 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100246 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle589e71e2017-03-03 16:05:05 -0800247 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700248 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800249 }
250
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700251 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
252
Mathieu Chartierea650f32017-05-24 12:04:13 -0700253 pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
254 pmi.dex_references.emplace_back("dex_location2", /* checksum */2, kMaxMethodIds);
255 pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700256
Calin Juravle940eb0c2017-01-30 19:30:44 -0800257 return pmi;
258 }
259
260 void MakeMegamorphic(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700261 ProfileCompilationInfo::InlineCacheMap* ic_map =
262 const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
263 for (auto it : *ic_map) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800264 for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) {
265 it.second.AddClass(0, dex::TypeIndex(k));
266 }
267 }
268 }
269
Calin Juravle589e71e2017-03-03 16:05:05 -0800270 void SetIsMissingTypes(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700271 ProfileCompilationInfo::InlineCacheMap* ic_map =
272 const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
273 for (auto it : *ic_map) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800274 it.second.SetIsMissingTypes();
275 }
276 }
277
Calin Juravle1e2de642018-01-18 01:08:23 -0800278 void TestProfileLoadFromZip(const char* zip_entry,
279 size_t zip_flags,
280 bool should_succeed,
281 bool should_succeed_with_empty_profile = false) {
282 // Create a valid profile.
283 ScratchFile profile;
284 ProfileCompilationInfo saved_info;
285 for (uint16_t i = 0; i < 10; i++) {
286 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
287 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
288 }
289 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
290 ASSERT_EQ(0, profile.GetFile()->Flush());
291
292 // Prepare the profile content for zipping.
293 ASSERT_TRUE(profile.GetFile()->ResetOffset());
Calin Juravle7cca51d2018-01-23 13:00:27 -0800294 std::vector<uint8_t> data(profile.GetFile()->GetLength());
295 ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
Calin Juravle1e2de642018-01-18 01:08:23 -0800296
297 // Zip the profile content.
298 ScratchFile zip;
299 FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
300 ZipWriter writer(file);
301 writer.StartEntry(zip_entry, zip_flags);
Calin Juravle7cca51d2018-01-23 13:00:27 -0800302 writer.WriteBytes(data.data(), data.size());
Calin Juravle1e2de642018-01-18 01:08:23 -0800303 writer.FinishEntry();
304 writer.Finish();
305 fflush(file);
306 fclose(file);
307
308 // Verify loading from the zip archive.
309 ProfileCompilationInfo loaded_info;
310 ASSERT_TRUE(zip.GetFile()->ResetOffset());
311 ASSERT_EQ(should_succeed, loaded_info.Load(zip.GetFile()->GetPath(), false));
312 if (should_succeed) {
313 if (should_succeed_with_empty_profile) {
314 ASSERT_TRUE(loaded_info.IsEmpty());
315 } else {
316 ASSERT_TRUE(loaded_info.Equals(saved_info));
317 }
318 }
319 }
320
Calin Juravled9f4d642018-01-24 20:33:00 -0800321 bool IsEmpty(const ProfileCompilationInfo& info) {
322 return info.IsEmpty();
323 }
324
Calin Juravle589e71e2017-03-03 16:05:05 -0800325 // Cannot sizeof the actual arrays so hard code the values here.
Calin Juravleb8697b12016-03-21 14:37:55 +0000326 // They should not change anyway.
327 static constexpr int kProfileMagicSize = 4;
328 static constexpr int kProfileVersionSize = 4;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700329
Vladimir Marko69d310e2017-10-09 14:12:23 +0100330 std::unique_ptr<ArenaAllocator> allocator_;
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700331
332 // Cache of inline caches generated during tests.
333 // This makes it easier to pass data between different utilities and ensure that
334 // caches are destructed at the end of the test.
335 std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
Calin Juravle877fd962016-01-05 14:29:29 +0000336};
337
338TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
339 ScratchFile profile;
340
341 Thread* self = Thread::Current();
342 jobject class_loader;
343 {
344 ScopedObjectAccess soa(self);
345 class_loader = LoadDex("ProfileTestMultiDex");
346 }
347 ASSERT_NE(class_loader, nullptr);
348
349 // Save virtual methods from Main.
Mathieu Chartier8913fc12015-12-09 16:38:30 -0800350 std::set<DexCacheResolvedClasses> resolved_classes;
Calin Juravle877fd962016-01-05 14:29:29 +0000351 std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
Calin Juravleee9cb412018-02-13 20:32:35 -0800352 ASSERT_TRUE(SaveProfilingInfo(
353 profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
Calin Juravle877fd962016-01-05 14:29:29 +0000354
355 // Check that what we saved is in the profile.
356 ProfileCompilationInfo info1;
357 ASSERT_TRUE(info1.Load(GetFd(profile)));
358 ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
359 {
360 ScopedObjectAccess soa(self);
361 for (ArtMethod* m : main_methods) {
Calin Juravleee9cb412018-02-13 20:32:35 -0800362 Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
363 ASSERT_TRUE(h.IsHot());
364 ASSERT_TRUE(h.IsPostStartup());
Calin Juravle877fd962016-01-05 14:29:29 +0000365 }
366 }
367
368 // Save virtual methods from Second.
369 std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
Calin Juravleee9cb412018-02-13 20:32:35 -0800370 ASSERT_TRUE(SaveProfilingInfo(
371 profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup));
Calin Juravle877fd962016-01-05 14:29:29 +0000372
373 // Check that what we saved is in the profile (methods form Main and Second).
374 ProfileCompilationInfo info2;
375 ASSERT_TRUE(profile.GetFile()->ResetOffset());
376 ASSERT_TRUE(info2.Load(GetFd(profile)));
377 ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
378 {
379 ScopedObjectAccess soa(self);
380 for (ArtMethod* m : main_methods) {
Calin Juravleee9cb412018-02-13 20:32:35 -0800381 Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
382 ASSERT_TRUE(h.IsHot());
383 ASSERT_TRUE(h.IsPostStartup());
Calin Juravle877fd962016-01-05 14:29:29 +0000384 }
385 for (ArtMethod* m : second_methods) {
Calin Juravleee9cb412018-02-13 20:32:35 -0800386 Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
387 ASSERT_TRUE(h.IsHot());
388 ASSERT_TRUE(h.IsStartup());
Calin Juravle877fd962016-01-05 14:29:29 +0000389 }
390 }
391}
392
393TEST_F(ProfileCompilationInfoTest, SaveFd) {
394 ScratchFile profile;
395
396 ProfileCompilationInfo saved_info;
397 // Save a few methods.
398 for (uint16_t i = 0; i < 10; i++) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000399 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
400 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
Calin Juravle877fd962016-01-05 14:29:29 +0000401 }
402 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
403 ASSERT_EQ(0, profile.GetFile()->Flush());
404
405 // Check that we get back what we saved.
406 ProfileCompilationInfo loaded_info;
407 ASSERT_TRUE(profile.GetFile()->ResetOffset());
408 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
409 ASSERT_TRUE(loaded_info.Equals(saved_info));
410
411 // Save more methods.
412 for (uint16_t i = 0; i < 100; i++) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000413 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
414 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
415 ASSERT_TRUE(AddMethod("dex_location3", /* checksum */ 3, /* method_idx */ i, &saved_info));
Calin Juravle877fd962016-01-05 14:29:29 +0000416 }
417 ASSERT_TRUE(profile.GetFile()->ResetOffset());
418 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
419 ASSERT_EQ(0, profile.GetFile()->Flush());
420
421 // Check that we get back everything we saved.
422 ProfileCompilationInfo loaded_info2;
423 ASSERT_TRUE(profile.GetFile()->ResetOffset());
424 ASSERT_TRUE(loaded_info2.Load(GetFd(profile)));
425 ASSERT_TRUE(loaded_info2.Equals(saved_info));
426}
427
Calin Juravle85f7bf32016-03-18 16:23:40 +0000428TEST_F(ProfileCompilationInfoTest, AddMethodsAndClassesFail) {
Calin Juravle877fd962016-01-05 14:29:29 +0000429 ScratchFile profile;
430
431 ProfileCompilationInfo info;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000432 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info));
Calin Juravle877fd962016-01-05 14:29:29 +0000433 // Trying to add info for an existing file but with a different checksum.
Calin Juravle85f7bf32016-03-18 16:23:40 +0000434 ASSERT_FALSE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info));
Calin Juravle877fd962016-01-05 14:29:29 +0000435}
436
Calin Juravle85f7bf32016-03-18 16:23:40 +0000437TEST_F(ProfileCompilationInfoTest, MergeFail) {
Calin Juravle877fd962016-01-05 14:29:29 +0000438 ScratchFile profile;
439
440 ProfileCompilationInfo info1;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000441 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
Calin Juravle877fd962016-01-05 14:29:29 +0000442 // Use the same file, change the checksum.
443 ProfileCompilationInfo info2;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000444 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
Calin Juravle877fd962016-01-05 14:29:29 +0000445
Calin Juravle85f7bf32016-03-18 16:23:40 +0000446 ASSERT_FALSE(info1.MergeWith(info2));
Calin Juravle877fd962016-01-05 14:29:29 +0000447}
448
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700449
450TEST_F(ProfileCompilationInfoTest, MergeFdFail) {
451 ScratchFile profile;
452
453 ProfileCompilationInfo info1;
454 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
455 // Use the same file, change the checksum.
456 ProfileCompilationInfo info2;
457 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
458
459 ASSERT_TRUE(info1.Save(profile.GetFd()));
460 ASSERT_EQ(0, profile.GetFile()->Flush());
461 ASSERT_TRUE(profile.GetFile()->ResetOffset());
462
463 ASSERT_FALSE(info2.Load(profile.GetFd()));
464}
465
Calin Juravleb8697b12016-03-21 14:37:55 +0000466TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) {
467 ScratchFile profile;
468
469 ProfileCompilationInfo saved_info;
470 // Save the maximum number of methods
471 for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
472 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
473 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
474 }
475 // Save the maximum number of classes
476 for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700477 ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, dex::TypeIndex(i), &saved_info));
478 ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &saved_info));
Calin Juravleb8697b12016-03-21 14:37:55 +0000479 }
480
481 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
482 ASSERT_EQ(0, profile.GetFile()->Flush());
483
484 // Check that we get back what we saved.
485 ProfileCompilationInfo loaded_info;
486 ASSERT_TRUE(profile.GetFile()->ResetOffset());
487 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
488 ASSERT_TRUE(loaded_info.Equals(saved_info));
489}
490
491TEST_F(ProfileCompilationInfoTest, SaveEmpty) {
492 ScratchFile profile;
493
494 ProfileCompilationInfo saved_info;
495 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
496 ASSERT_EQ(0, profile.GetFile()->Flush());
497
498 // Check that we get back what we saved.
499 ProfileCompilationInfo loaded_info;
500 ASSERT_TRUE(profile.GetFile()->ResetOffset());
501 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
502 ASSERT_TRUE(loaded_info.Equals(saved_info));
503}
504
505TEST_F(ProfileCompilationInfoTest, LoadEmpty) {
506 ScratchFile profile;
507
Calin Juravle940eb0c2017-01-30 19:30:44 -0800508 ProfileCompilationInfo empty_info;
Calin Juravleb8697b12016-03-21 14:37:55 +0000509
510 ProfileCompilationInfo loaded_info;
511 ASSERT_TRUE(profile.GetFile()->ResetOffset());
512 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800513 ASSERT_TRUE(loaded_info.Equals(empty_info));
Calin Juravleb8697b12016-03-21 14:37:55 +0000514}
515
516TEST_F(ProfileCompilationInfoTest, BadMagic) {
517 ScratchFile profile;
518 uint8_t buffer[] = { 1, 2, 3, 4 };
519 ASSERT_TRUE(profile.GetFile()->WriteFully(buffer, sizeof(buffer)));
520 ProfileCompilationInfo loaded_info;
521 ASSERT_TRUE(profile.GetFile()->ResetOffset());
522 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
523}
524
525TEST_F(ProfileCompilationInfoTest, BadVersion) {
526 ScratchFile profile;
527
528 ASSERT_TRUE(profile.GetFile()->WriteFully(
529 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
530 uint8_t version[] = { 'v', 'e', 'r', 's', 'i', 'o', 'n' };
531 ASSERT_TRUE(profile.GetFile()->WriteFully(version, sizeof(version)));
532 ASSERT_EQ(0, profile.GetFile()->Flush());
533
534 ProfileCompilationInfo loaded_info;
535 ASSERT_TRUE(profile.GetFile()->ResetOffset());
536 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
537}
538
539TEST_F(ProfileCompilationInfoTest, Incomplete) {
540 ScratchFile profile;
541 ASSERT_TRUE(profile.GetFile()->WriteFully(
542 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
543 ASSERT_TRUE(profile.GetFile()->WriteFully(
544 ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
545 // Write that we have at least one line.
546 uint8_t line_number[] = { 0, 1 };
547 ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
548 ASSERT_EQ(0, profile.GetFile()->Flush());
549
550 ProfileCompilationInfo loaded_info;
551 ASSERT_TRUE(profile.GetFile()->ResetOffset());
552 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
553}
554
555TEST_F(ProfileCompilationInfoTest, TooLongDexLocation) {
556 ScratchFile profile;
557 ASSERT_TRUE(profile.GetFile()->WriteFully(
558 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
559 ASSERT_TRUE(profile.GetFile()->WriteFully(
560 ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
561 // Write that we have at least one line.
562 uint8_t line_number[] = { 0, 1 };
563 ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
564
565 // dex_location_size, methods_size, classes_size, checksum.
566 // Dex location size is too big and should be rejected.
567 uint8_t line[] = { 255, 255, 0, 1, 0, 1, 0, 0, 0, 0 };
568 ASSERT_TRUE(profile.GetFile()->WriteFully(line, sizeof(line)));
569 ASSERT_EQ(0, profile.GetFile()->Flush());
570
571 ProfileCompilationInfo loaded_info;
572 ASSERT_TRUE(profile.GetFile()->ResetOffset());
573 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
574}
575
576TEST_F(ProfileCompilationInfoTest, UnexpectedContent) {
577 ScratchFile profile;
578
579 ProfileCompilationInfo saved_info;
580 // Save the maximum number of methods
581 for (uint16_t i = 0; i < 10; i++) {
582 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
583 }
584 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
585
586 uint8_t random_data[] = { 1, 2, 3};
587 ASSERT_TRUE(profile.GetFile()->WriteFully(random_data, sizeof(random_data)));
588
589 ASSERT_EQ(0, profile.GetFile()->Flush());
590
591 // Check that we fail because of unexpected data at the end of the file.
592 ProfileCompilationInfo loaded_info;
593 ASSERT_TRUE(profile.GetFile()->ResetOffset());
594 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
595}
596
Calin Juravle940eb0c2017-01-30 19:30:44 -0800597TEST_F(ProfileCompilationInfoTest, SaveInlineCaches) {
598 ScratchFile profile;
599
600 ProfileCompilationInfo saved_info;
601 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
602
603 // Add methods with inline caches.
604 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
605 // Add a method which is part of the same dex file as one of the
606 // class from the inline caches.
607 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
608 // Add a method which is outside the set of dex files.
609 ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
610 }
611
612 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
613 ASSERT_EQ(0, profile.GetFile()->Flush());
614
615 // Check that we get back what we saved.
616 ProfileCompilationInfo loaded_info;
617 ASSERT_TRUE(profile.GetFile()->ResetOffset());
618 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
619
620 ASSERT_TRUE(loaded_info.Equals(saved_info));
621
Calin Juravlecc3171a2017-05-19 16:47:53 -0700622 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
623 loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
624 ASSERT_TRUE(loaded_pmi1 != nullptr);
625 ASSERT_TRUE(*loaded_pmi1 == pmi);
626 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
627 loaded_info.GetMethod("dex_location4", /* checksum */ 4, /* method_idx */ 3);
628 ASSERT_TRUE(loaded_pmi2 != nullptr);
629 ASSERT_TRUE(*loaded_pmi2 == pmi);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800630}
631
632TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) {
633 ScratchFile profile;
634
635 ProfileCompilationInfo saved_info;
636 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
637
638 // Add methods with inline caches.
639 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
640 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
641 }
642
643 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
644 ASSERT_EQ(0, profile.GetFile()->Flush());
645
646 // Make the inline caches megamorphic and add them to the profile again.
647 ProfileCompilationInfo saved_info_extra;
648 ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
649 MakeMegamorphic(&pmi_extra);
650 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
651 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
652 }
653
654 ASSERT_TRUE(profile.GetFile()->ResetOffset());
655 ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
656 ASSERT_EQ(0, profile.GetFile()->Flush());
657
658 // Merge the profiles so that we have the same view as the file.
659 ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
660
661 // Check that we get back what we saved.
662 ProfileCompilationInfo loaded_info;
663 ASSERT_TRUE(profile.GetFile()->ResetOffset());
664 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
665
666 ASSERT_TRUE(loaded_info.Equals(saved_info));
667
Calin Juravlecc3171a2017-05-19 16:47:53 -0700668 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
669 loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
670
671 ASSERT_TRUE(loaded_pmi1 != nullptr);
672 ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800673}
674
Calin Juravle589e71e2017-03-03 16:05:05 -0800675TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) {
676 ScratchFile profile;
677
678 ProfileCompilationInfo saved_info;
679 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
680
681 // Add methods with inline caches.
682 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
683 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
684 }
685
686 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
687 ASSERT_EQ(0, profile.GetFile()->Flush());
688
689 // Make some inline caches megamorphic and add them to the profile again.
690 ProfileCompilationInfo saved_info_extra;
691 ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
692 MakeMegamorphic(&pmi_extra);
693 for (uint16_t method_idx = 5; method_idx < 10; method_idx++) {
694 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
695 }
696
697 // Mark all inline caches with missing types and add them to the profile again.
698 // This will verify that all inline caches (megamorphic or not) should be marked as missing types.
699 ProfileCompilationInfo::OfflineProfileMethodInfo missing_types = GetOfflineProfileMethodInfo();
700 SetIsMissingTypes(&missing_types);
701 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
702 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
703 }
704
705 ASSERT_TRUE(profile.GetFile()->ResetOffset());
706 ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
707 ASSERT_EQ(0, profile.GetFile()->Flush());
708
709 // Merge the profiles so that we have the same view as the file.
710 ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
711
712 // Check that we get back what we saved.
713 ProfileCompilationInfo loaded_info;
714 ASSERT_TRUE(profile.GetFile()->ResetOffset());
715 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
716
717 ASSERT_TRUE(loaded_info.Equals(saved_info));
718
Calin Juravlecc3171a2017-05-19 16:47:53 -0700719 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
720 loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
721 ASSERT_TRUE(loaded_pmi1 != nullptr);
722 ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
Calin Juravle589e71e2017-03-03 16:05:05 -0800723}
724
Calin Juravle940eb0c2017-01-30 19:30:44 -0800725TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
726 ScratchFile profile;
727
728 Thread* self = Thread::Current();
729 jobject class_loader;
730 {
731 ScopedObjectAccess soa(self);
732 class_loader = LoadDex("ProfileTestMultiDex");
733 }
734 ASSERT_NE(class_loader, nullptr);
735
736 // Save virtual methods from Main.
737 std::set<DexCacheResolvedClasses> resolved_classes;
738 std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
739
740 SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
741 ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
Calin Juravleee9cb412018-02-13 20:32:35 -0800742 profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800743
744 // Check that what we saved is in the profile.
745 ProfileCompilationInfo info;
746 ASSERT_TRUE(info.Load(GetFd(profile)));
747 ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size());
748 {
749 ScopedObjectAccess soa(self);
750 for (ArtMethod* m : main_methods) {
Calin Juravleee9cb412018-02-13 20:32:35 -0800751 Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
752 ASSERT_TRUE(h.IsHot());
753 ASSERT_TRUE(h.IsStartup());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800754 const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700755 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
756 info.GetMethod(m->GetDexFile()->GetLocation(),
757 m->GetDexFile()->GetLocationChecksum(),
758 m->GetDexMethodIndex());
759 ASSERT_TRUE(offline_pmi != nullptr);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800760 ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi =
761 ConvertProfileMethodInfo(pmi);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700762 ASSERT_EQ(converted_pmi, *offline_pmi);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800763 }
764 }
765}
766
Calin Juravle589e71e2017-03-03 16:05:05 -0800767TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800768 ScratchFile profile;
769
770 ProfileCompilationInfo info;
771 ProfileCompilationInfo::OfflineProfileMethodInfo pmi1 = GetOfflineProfileMethodInfo();
772 ProfileCompilationInfo::OfflineProfileMethodInfo pmi2 = GetOfflineProfileMethodInfo();
773 // Modify the checksum to trigger a mismatch.
774 pmi2.dex_references[0].dex_checksum++;
775
776 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /*method_idx*/ 0, pmi1, &info));
777 ASSERT_FALSE(AddMethod("dex_location2", /* checksum */ 2, /*method_idx*/ 0, pmi2, &info));
778}
779
780// Verify that profiles behave correctly even if the methods are added in a different
781// order and with a different dex profile indices for the dex files.
782TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
783 ScratchFile profile;
784
785 ProfileCompilationInfo info;
786 ProfileCompilationInfo info_reindexed;
787
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700788 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
789 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700790 pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
791 pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800792 for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100793 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800794 dex_pc_data.AddClass(0, dex::TypeIndex(0));
795 dex_pc_data.AddClass(1, dex::TypeIndex(1));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700796 ic_map->Put(dex_pc, dex_pc_data);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800797 }
798
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700799 ProfileCompilationInfo::InlineCacheMap* ic_map_reindexed = CreateInlineCacheMap();
800 ProfileCompilationInfo::OfflineProfileMethodInfo pmi_reindexed(ic_map_reindexed);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700801 pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
802 pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800803 for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100804 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800805 dex_pc_data.AddClass(1, dex::TypeIndex(0));
806 dex_pc_data.AddClass(0, dex::TypeIndex(1));
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700807 ic_map_reindexed->Put(dex_pc, dex_pc_data);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800808 }
809
810 // Profile 1 and Profile 2 get the same methods but in different order.
811 // This will trigger a different dex numbers.
812 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
813 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &info));
814 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &info));
815 }
816
817 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
818 ASSERT_TRUE(AddMethod(
819 "dex_location2", /* checksum */ 2, method_idx, pmi_reindexed, &info_reindexed));
820 ASSERT_TRUE(AddMethod(
821 "dex_location1", /* checksum */ 1, method_idx, pmi_reindexed, &info_reindexed));
822 }
823
Calin Juravlecc3171a2017-05-19 16:47:53 -0700824 ProfileCompilationInfo info_backup;
825 info_backup.MergeWith(info);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800826 ASSERT_TRUE(info.MergeWith(info_reindexed));
827 // Merging should have no effect as we're adding the exact same stuff.
828 ASSERT_TRUE(info.Equals(info_backup));
829 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700830 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
831 info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
832 ASSERT_TRUE(loaded_pmi1 != nullptr);
833 ASSERT_TRUE(*loaded_pmi1 == pmi);
834 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
835 info.GetMethod("dex_location2", /* checksum */ 2, method_idx);
836 ASSERT_TRUE(loaded_pmi2 != nullptr);
837 ASSERT_TRUE(*loaded_pmi2 == pmi);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800838 }
839}
840
841TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimit) {
842 ProfileCompilationInfo info;
843 // Save a few methods.
844 for (uint16_t i = 0; i < std::numeric_limits<uint8_t>::max(); i++) {
845 std::string dex_location = std::to_string(i);
846 ASSERT_TRUE(AddMethod(dex_location, /* checksum */ 1, /* method_idx */ i, &info));
847 }
848 // We only support at most 255 dex files.
849 ASSERT_FALSE(AddMethod(
850 /*dex_location*/ "256", /* checksum */ 1, /* method_idx */ 0, &info));
851}
852
Calin Juravle0def68d2017-02-21 19:00:33 -0800853TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) {
854 // Create a megamorphic inline cache.
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700855 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
856 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700857 pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100858 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle589e71e2017-03-03 16:05:05 -0800859 dex_pc_data.SetIsMegamorphic();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700860 ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
Calin Juravle0def68d2017-02-21 19:00:33 -0800861
862 ProfileCompilationInfo info_megamorphic;
863 ASSERT_TRUE(AddMethod("dex_location1",
864 /*checksum*/ 1,
865 /*method_idx*/ 0,
866 pmi,
867 &info_megamorphic));
868
869 // Create a profile with no inline caches (for the same method).
870 ProfileCompilationInfo info_no_inline_cache;
871 ASSERT_TRUE(AddMethod("dex_location1",
872 /*checksum*/ 1,
873 /*method_idx*/ 0,
874 &info_no_inline_cache));
875
876 // Merge the megamorphic cache into the empty one.
877 ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
878 ScratchFile profile;
879 // Saving profile should work without crashing (b/35644850).
880 ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
881}
882
Calin Juravle589e71e2017-03-03 16:05:05 -0800883TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) {
884 // Create an inline cache with missing types
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700885 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
886 ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700887 pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
Vladimir Marko69d310e2017-10-09 14:12:23 +0100888 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
Calin Juravle589e71e2017-03-03 16:05:05 -0800889 dex_pc_data.SetIsMissingTypes();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700890 ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
Calin Juravle589e71e2017-03-03 16:05:05 -0800891
892 ProfileCompilationInfo info_megamorphic;
893 ASSERT_TRUE(AddMethod("dex_location1",
894 /*checksum*/ 1,
895 /*method_idx*/ 0,
896 pmi,
897 &info_megamorphic));
898
899 // Create a profile with no inline caches (for the same method).
900 ProfileCompilationInfo info_no_inline_cache;
901 ASSERT_TRUE(AddMethod("dex_location1",
902 /*checksum*/ 1,
903 /*method_idx*/ 0,
904 &info_no_inline_cache));
905
906 // Merge the missing type cache into the empty one.
907 // Everything should be saved without errors.
908 ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
909 ScratchFile profile;
910 ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
911}
912
Mathieu Chartierea650f32017-05-24 12:04:13 -0700913TEST_F(ProfileCompilationInfoTest, SampledMethodsTest) {
914 ProfileCompilationInfo test_info;
915 static constexpr size_t kNumMethods = 1000;
916 static constexpr size_t kChecksum1 = 1234;
917 static constexpr size_t kChecksum2 = 4321;
918 static const std::string kDex1 = "dex1";
919 static const std::string kDex2 = "dex2";
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700920 test_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 1, kNumMethods);
921 test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex1, kChecksum1, 5, kNumMethods);
922 test_info.AddMethodIndex(Hotness::kFlagStartup, kDex2, kChecksum2, 2, kNumMethods);
923 test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex2, kChecksum2, 4, kNumMethods);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700924 auto run_test = [](const ProfileCompilationInfo& info) {
Mathieu Chartiere46f3a82017-06-19 19:54:12 -0700925 EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 2).IsInProfile());
926 EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 4).IsInProfile());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700927 EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 1).IsStartup());
928 EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 3).IsStartup());
929 EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 5).IsPostStartup());
930 EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 6).IsStartup());
931 EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 2).IsStartup());
932 EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 4).IsPostStartup());
Mathieu Chartierea650f32017-05-24 12:04:13 -0700933 };
934 run_test(test_info);
935
936 // Save the profile.
937 ScratchFile profile;
938 ASSERT_TRUE(test_info.Save(GetFd(profile)));
939 ASSERT_EQ(0, profile.GetFile()->Flush());
940 ASSERT_TRUE(profile.GetFile()->ResetOffset());
941
942 // Load the profile and make sure we can read the data and it matches what we expect.
943 ProfileCompilationInfo loaded_info;
944 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
945 run_test(loaded_info);
946
947 // Test that the bitmap gets merged properly.
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700948 EXPECT_FALSE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
Mathieu Chartierea650f32017-05-24 12:04:13 -0700949 {
950 ProfileCompilationInfo merge_info;
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700951 merge_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 11, kNumMethods);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700952 test_info.MergeWith(merge_info);
953 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700954 EXPECT_TRUE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700955
956 // Test bulk adding.
957 {
958 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
959 ProfileCompilationInfo info;
960 std::vector<uint16_t> hot_methods = {1, 3, 5};
961 std::vector<uint16_t> startup_methods = {1, 2};
962 std::vector<uint16_t> post_methods = {0, 2, 6};
963 ASSERT_GE(dex->NumMethodIds(), 7u);
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700964 info.AddMethodsForDex(static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700965 dex.get(),
966 hot_methods.begin(),
967 hot_methods.end());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700968 info.AddMethodsForDex(Hotness::kFlagStartup,
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700969 dex.get(),
970 startup_methods.begin(),
971 startup_methods.end());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700972 info.AddMethodsForDex(Hotness::kFlagPostStartup,
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700973 dex.get(),
974 post_methods.begin(),
975 post_methods.end());
976 for (uint16_t id : hot_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700977 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
978 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700979 }
980 for (uint16_t id : startup_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700981 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700982 }
983 for (uint16_t id : post_methods) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700984 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700985 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700986 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsPostStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700987 // Check that methods that shouldn't have been touched are OK.
Mathieu Chartiere46f3a82017-06-19 19:54:12 -0700988 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 0)).IsInProfile());
989 EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsInProfile());
990 EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 7)).IsInProfile());
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700991 EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 1)).IsPostStartup());
992 EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsStartup());
993 EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsStartup());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -0700994 }
Mathieu Chartierea650f32017-05-24 12:04:13 -0700995}
996
Calin Juravle1e2de642018-01-18 01:08:23 -0800997TEST_F(ProfileCompilationInfoTest, LoadFromZipCompress) {
998 TestProfileLoadFromZip("primary.prof",
999 ZipWriter::kCompress | ZipWriter::kAlign32,
1000 /*should_succeed*/true);
1001}
1002
1003TEST_F(ProfileCompilationInfoTest, LoadFromZipUnCompress) {
1004 TestProfileLoadFromZip("primary.prof",
1005 ZipWriter::kAlign32,
1006 /*should_succeed*/true);
1007}
1008
1009TEST_F(ProfileCompilationInfoTest, LoadFromZipUnAligned) {
1010 TestProfileLoadFromZip("primary.prof",
1011 0,
1012 /*should_succeed*/true);
1013}
1014
1015TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadZipEntry) {
1016 TestProfileLoadFromZip("invalid.profile.entry",
1017 0,
1018 /*should_succeed*/true,
1019 /*should_succeed_with_empty_profile*/true);
1020}
1021
1022TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadProfile) {
1023 // Create a bad profile.
1024 ScratchFile profile;
1025 ASSERT_TRUE(profile.GetFile()->WriteFully(
1026 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
1027 ASSERT_TRUE(profile.GetFile()->WriteFully(
1028 ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
1029 // Write that we have at least one line.
1030 uint8_t line_number[] = { 0, 1 };
1031 ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
1032 ASSERT_EQ(0, profile.GetFile()->Flush());
1033
1034 // Prepare the profile content for zipping.
1035 ASSERT_TRUE(profile.GetFile()->ResetOffset());
Calin Juravle7cca51d2018-01-23 13:00:27 -08001036 std::vector<uint8_t> data(profile.GetFile()->GetLength());
1037 ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
Calin Juravle1e2de642018-01-18 01:08:23 -08001038
1039 // Zip the profile content.
1040 ScratchFile zip;
1041 FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
1042 ZipWriter writer(file);
Calin Juravle7cca51d2018-01-23 13:00:27 -08001043 writer.StartEntry("primary.prof", ZipWriter::kAlign32);
1044 writer.WriteBytes(data.data(), data.size());
Calin Juravle1e2de642018-01-18 01:08:23 -08001045 writer.FinishEntry();
1046 writer.Finish();
1047 fflush(file);
1048 fclose(file);
1049
1050 // Check that we failed to load.
1051 ProfileCompilationInfo loaded_info;
1052 ASSERT_TRUE(zip.GetFile()->ResetOffset());
1053 ASSERT_FALSE(loaded_info.Load(GetFd(zip)));
1054}
1055
Calin Juravle2dba0ab2018-01-22 19:22:24 -08001056TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOk) {
1057 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
1058
1059 ProfileCompilationInfo info;
1060 for (const std::unique_ptr<const DexFile>& dex : dex_files) {
1061 // Create the profile with a different location so that we can update it to the
1062 // real dex location later.
1063 std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
1064 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
1065 std::string old_name = base_location + "-old" + multidex_suffix;
1066 info.AddMethodIndex(Hotness::kFlagHot,
1067 old_name,
1068 dex->GetLocationChecksum(),
1069 /* method_idx */ 0,
1070 dex->NumMethodIds());
1071 }
1072
1073 // Update the profile keys based on the original dex files
1074 ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
1075
1076 // Verify that we find the methods when searched with the original dex files.
1077 for (const std::unique_ptr<const DexFile>& dex : dex_files) {
1078 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
1079 info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
1080 ASSERT_TRUE(loaded_pmi != nullptr);
1081 }
1082}
1083
1084TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOkButNoUpdate) {
1085 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
1086
1087 ProfileCompilationInfo info;
1088 info.AddMethodIndex(Hotness::kFlagHot,
1089 "my.app",
1090 /* checksum */ 123,
1091 /* method_idx */ 0,
1092 /* num_method_ids */ 10);
1093
1094 // Update the profile keys based on the original dex files
1095 ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
1096
1097 // Verify that we did not perform any update and that we cannot find anything with the new
1098 // location.
1099 for (const std::unique_ptr<const DexFile>& dex : dex_files) {
1100 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
1101 info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
1102 ASSERT_TRUE(loaded_pmi == nullptr);
1103 }
1104
1105 // Verify that we can find the original entry.
1106 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
1107 info.GetMethod("my.app", /* checksum */ 123, /* method_idx */ 0);
1108 ASSERT_TRUE(loaded_pmi != nullptr);
1109}
1110
1111TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyFail) {
1112 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
1113
1114
1115 ProfileCompilationInfo info;
1116 // Add all dex
1117 for (const std::unique_ptr<const DexFile>& dex : dex_files) {
1118 // Create the profile with a different location so that we can update it to the
1119 // real dex location later.
1120 std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
1121 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
1122 std::string old_name = base_location + "-old" + multidex_suffix;
1123 info.AddMethodIndex(Hotness::kFlagHot,
1124 old_name,
1125 dex->GetLocationChecksum(),
1126 /* method_idx */ 0,
1127 dex->NumMethodIds());
1128 }
1129
1130 // Add a method index using the location we want to rename to.
1131 // This will cause the rename to fail because an existing entry would already have that name.
1132 info.AddMethodIndex(Hotness::kFlagHot,
1133 dex_files[0]->GetLocation(),
1134 /* checksum */ 123,
1135 /* method_idx */ 0,
1136 dex_files[0]->NumMethodIds());
1137
1138 ASSERT_FALSE(info.UpdateProfileKeys(dex_files));
1139}
1140
Calin Juravled9f4d642018-01-24 20:33:00 -08001141TEST_F(ProfileCompilationInfoTest, FilteredLoading) {
1142 ScratchFile profile;
1143
1144 ProfileCompilationInfo saved_info;
1145 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
1146
1147 // Add methods with inline caches.
1148 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1149 // Add a method which is part of the same dex file as one of the class from the inline caches.
1150 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
1151 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
1152 // Add a method which is outside the set of dex files.
1153 ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
1154 }
1155
1156 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1157 ASSERT_EQ(0, profile.GetFile()->Flush());
1158
1159 // Check that we get back what we saved.
1160 ProfileCompilationInfo loaded_info;
1161 ASSERT_TRUE(profile.GetFile()->ResetOffset());
1162
1163 // Filter out dex locations. Keep only dex_location1 and dex_location2.
1164 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1165 [](const std::string& dex_location, uint32_t checksum) -> bool {
1166 return (dex_location == "dex_location1" && checksum == 1)
1167 || (dex_location == "dex_location3" && checksum == 3);
1168 };
1169 ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1170
1171 // Verify that we filtered out locations during load.
1172
1173 // Dex location 2 and 4 should have been filtered out
1174 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1175 ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location2", /* checksum */ 2, method_idx));
1176 ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx));
1177 }
1178
1179 // Dex location 1 should have all all the inline caches referencing dex location 2 set to
1180 // missing types.
1181 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1182 // The methods for dex location 1 should be in the profile data.
1183 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
1184 loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ method_idx);
1185 ASSERT_TRUE(loaded_pmi1 != nullptr);
1186
1187 // Verify the inline cache.
1188 // Everything should be as constructed by GetOfflineProfileMethodInfo with the exception
1189 // of the inline caches referring types from dex_location2.
1190 // These should be set to IsMissingType.
1191 ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
1192
1193 // Monomorphic types should remain the same as dex_location1 was kept.
1194 for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
1195 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1196 dex_pc_data.AddClass(0, dex::TypeIndex(0));
1197 ic_map->Put(dex_pc, dex_pc_data);
1198 }
1199 // Polymorphic inline cache should have been transformed to IsMissingType due to
1200 // the removal of dex_location2.
1201 for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
1202 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1203 dex_pc_data.SetIsMissingTypes();
1204 ic_map->Put(dex_pc, dex_pc_data);
1205 }
1206
1207 // Megamorphic are not affected by removal of dex files.
1208 for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
1209 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1210 dex_pc_data.SetIsMegamorphic();
1211 ic_map->Put(dex_pc, dex_pc_data);
1212 }
1213 // Missing types are not affected be removal of dex files.
1214 for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
1215 ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1216 dex_pc_data.SetIsMissingTypes();
1217 ic_map->Put(dex_pc, dex_pc_data);
1218 }
1219
1220 ProfileCompilationInfo::OfflineProfileMethodInfo expected_pmi(ic_map);
1221
1222 // The dex references should not have dex_location2 in the list.
1223 expected_pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
1224 expected_pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
1225
1226 // Now check that we get back what we expect.
1227 ASSERT_TRUE(*loaded_pmi1 == expected_pmi);
1228 }
1229}
1230
1231TEST_F(ProfileCompilationInfoTest, FilteredLoadingRemoveAll) {
1232 ScratchFile profile;
1233
1234 ProfileCompilationInfo saved_info;
1235 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
1236
1237 // Add methods with inline caches.
1238 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1239 // Add a method which is part of the same dex file as one of the class from the inline caches.
1240 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
1241 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
1242 // Add a method which is outside the set of dex files.
1243 ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
1244 }
1245
1246 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1247 ASSERT_EQ(0, profile.GetFile()->Flush());
1248
1249 // Check that we get back what we saved.
1250 ProfileCompilationInfo loaded_info;
1251 ASSERT_TRUE(profile.GetFile()->ResetOffset());
1252
1253 // Remove all elements.
1254 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1255 [](const std::string&, uint32_t) -> bool { return false; };
1256 ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1257
1258 // Verify that we filtered out everything.
1259 ASSERT_TRUE(IsEmpty(loaded_info));
1260}
1261
1262TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) {
1263 ScratchFile profile;
1264
1265 ProfileCompilationInfo saved_info;
1266 ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
1267
1268 // Add methods with inline caches.
1269 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1270 // Add a method which is part of the same dex file as one of the
1271 // class from the inline caches.
1272 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
1273 // Add a method which is outside the set of dex files.
1274 ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
1275 }
1276
1277 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1278 ASSERT_EQ(0, profile.GetFile()->Flush());
1279
1280 // Check that we get back what we saved.
1281 ProfileCompilationInfo loaded_info;
1282 ASSERT_TRUE(profile.GetFile()->ResetOffset());
1283
1284 // Keep all elements.
1285 ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1286 [](const std::string&, uint32_t) -> bool { return true; };
1287 ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1288
1289
1290 ASSERT_TRUE(loaded_info.Equals(saved_info));
1291
1292 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1293 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
1294 loaded_info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
1295 ASSERT_TRUE(loaded_pmi1 != nullptr);
1296 ASSERT_TRUE(*loaded_pmi1 == pmi);
1297 }
1298 for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1299 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
1300 loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx);
1301 ASSERT_TRUE(loaded_pmi2 != nullptr);
1302 ASSERT_TRUE(*loaded_pmi2 == pmi);
1303 }
1304}
1305
Calin Juravle877fd962016-01-05 14:29:29 +00001306} // namespace art