blob: 764458aececdb589be21e362f1c27e98f66df49c [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>
18
19#include "base/unix_file/fd_file.h"
20#include "art_method-inl.h"
21#include "class_linker-inl.h"
22#include "common_runtime_test.h"
23#include "dex_file.h"
Calin Juravlee2d066d2016-04-19 16:33:46 +010024#include "method_reference.h"
Calin Juravle877fd962016-01-05 14:29:29 +000025#include "mirror/class-inl.h"
26#include "mirror/class_loader.h"
27#include "handle_scope-inl.h"
28#include "jit/offline_profiling_info.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070029#include "scoped_thread_state_change-inl.h"
Calin Juravle877fd962016-01-05 14:29:29 +000030
31namespace art {
32
33class ProfileCompilationInfoTest : public CommonRuntimeTest {
34 protected:
35 std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
36 const std::string& clazz) {
37 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
38 Thread* self = Thread::Current();
39 ScopedObjectAccess soa(self);
40 StackHandleScope<1> hs(self);
41 Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
42 reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader))));
43 mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
44
45 const auto pointer_size = class_linker->GetImagePointerSize();
46 std::vector<ArtMethod*> methods;
47 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
48 methods.push_back(&m);
49 }
50 return methods;
51 }
52
Calin Juravle85f7bf32016-03-18 16:23:40 +000053 bool AddMethod(const std::string& dex_location,
Calin Juravleb8697b12016-03-21 14:37:55 +000054 uint32_t checksum,
55 uint16_t method_index,
56 ProfileCompilationInfo* info) {
Mathieu Chartier8913fc12015-12-09 16:38:30 -080057 return info->AddMethodIndex(dex_location, checksum, method_index);
Calin Juravle877fd962016-01-05 14:29:29 +000058 }
59
Calin Juravleb8697b12016-03-21 14:37:55 +000060 bool AddClass(const std::string& dex_location,
61 uint32_t checksum,
62 uint16_t class_index,
63 ProfileCompilationInfo* info) {
64 return info->AddMethodIndex(dex_location, checksum, class_index);
65 }
66
Calin Juravle877fd962016-01-05 14:29:29 +000067 uint32_t GetFd(const ScratchFile& file) {
68 return static_cast<uint32_t>(file.GetFd());
69 }
Calin Juravleb8697b12016-03-21 14:37:55 +000070
Calin Juravlefe297a92016-03-24 20:33:22 +000071 bool SaveProfilingInfo(
72 const std::string& filename,
73 const std::vector<ArtMethod*>& methods,
74 const std::set<DexCacheResolvedClasses>& resolved_classes) {
75 ProfileCompilationInfo info;
Calin Juravlee2d066d2016-04-19 16:33:46 +010076 std::vector<MethodReference> method_refs;
77 ScopedObjectAccess soa(Thread::Current());
78 for (ArtMethod* method : methods) {
79 method_refs.emplace_back(method->GetDexFile(), method->GetDexMethodIndex());
80 }
81 if (!info.AddMethodsAndClasses(method_refs, resolved_classes)) {
Calin Juravlefe297a92016-03-24 20:33:22 +000082 return false;
83 }
84 return info.MergeAndSave(filename, nullptr, false);
85 }
86
Calin Juravleb8697b12016-03-21 14:37:55 +000087 // Cannot sizeof the actual arrays so hardcode the values here.
88 // They should not change anyway.
89 static constexpr int kProfileMagicSize = 4;
90 static constexpr int kProfileVersionSize = 4;
Calin Juravle877fd962016-01-05 14:29:29 +000091};
92
93TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
94 ScratchFile profile;
95
96 Thread* self = Thread::Current();
97 jobject class_loader;
98 {
99 ScopedObjectAccess soa(self);
100 class_loader = LoadDex("ProfileTestMultiDex");
101 }
102 ASSERT_NE(class_loader, nullptr);
103
104 // Save virtual methods from Main.
Mathieu Chartier8913fc12015-12-09 16:38:30 -0800105 std::set<DexCacheResolvedClasses> resolved_classes;
Calin Juravle877fd962016-01-05 14:29:29 +0000106 std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
Calin Juravlefe297a92016-03-24 20:33:22 +0000107 ASSERT_TRUE(SaveProfilingInfo(profile.GetFilename(), main_methods, resolved_classes));
Calin Juravle877fd962016-01-05 14:29:29 +0000108
109 // Check that what we saved is in the profile.
110 ProfileCompilationInfo info1;
111 ASSERT_TRUE(info1.Load(GetFd(profile)));
112 ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
113 {
114 ScopedObjectAccess soa(self);
115 for (ArtMethod* m : main_methods) {
116 ASSERT_TRUE(info1.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
117 }
118 }
119
120 // Save virtual methods from Second.
121 std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
Calin Juravlefe297a92016-03-24 20:33:22 +0000122 ASSERT_TRUE(SaveProfilingInfo(profile.GetFilename(), second_methods, resolved_classes));
Calin Juravle877fd962016-01-05 14:29:29 +0000123
124 // Check that what we saved is in the profile (methods form Main and Second).
125 ProfileCompilationInfo info2;
126 ASSERT_TRUE(profile.GetFile()->ResetOffset());
127 ASSERT_TRUE(info2.Load(GetFd(profile)));
128 ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
129 {
130 ScopedObjectAccess soa(self);
131 for (ArtMethod* m : main_methods) {
132 ASSERT_TRUE(info2.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
133 }
134 for (ArtMethod* m : second_methods) {
135 ASSERT_TRUE(info2.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
136 }
137 }
138}
139
140TEST_F(ProfileCompilationInfoTest, SaveFd) {
141 ScratchFile profile;
142
143 ProfileCompilationInfo saved_info;
144 // Save a few methods.
145 for (uint16_t i = 0; i < 10; i++) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000146 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
147 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
Calin Juravle877fd962016-01-05 14:29:29 +0000148 }
149 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
150 ASSERT_EQ(0, profile.GetFile()->Flush());
151
152 // Check that we get back what we saved.
153 ProfileCompilationInfo loaded_info;
154 ASSERT_TRUE(profile.GetFile()->ResetOffset());
155 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
156 ASSERT_TRUE(loaded_info.Equals(saved_info));
157
158 // Save more methods.
159 for (uint16_t i = 0; i < 100; i++) {
Calin Juravle85f7bf32016-03-18 16:23:40 +0000160 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
161 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
162 ASSERT_TRUE(AddMethod("dex_location3", /* checksum */ 3, /* method_idx */ i, &saved_info));
Calin Juravle877fd962016-01-05 14:29:29 +0000163 }
164 ASSERT_TRUE(profile.GetFile()->ResetOffset());
165 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
166 ASSERT_EQ(0, profile.GetFile()->Flush());
167
168 // Check that we get back everything we saved.
169 ProfileCompilationInfo loaded_info2;
170 ASSERT_TRUE(profile.GetFile()->ResetOffset());
171 ASSERT_TRUE(loaded_info2.Load(GetFd(profile)));
172 ASSERT_TRUE(loaded_info2.Equals(saved_info));
173}
174
Calin Juravle85f7bf32016-03-18 16:23:40 +0000175TEST_F(ProfileCompilationInfoTest, AddMethodsAndClassesFail) {
Calin Juravle877fd962016-01-05 14:29:29 +0000176 ScratchFile profile;
177
178 ProfileCompilationInfo info;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000179 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info));
Calin Juravle877fd962016-01-05 14:29:29 +0000180 // Trying to add info for an existing file but with a different checksum.
Calin Juravle85f7bf32016-03-18 16:23:40 +0000181 ASSERT_FALSE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info));
Calin Juravle877fd962016-01-05 14:29:29 +0000182}
183
Calin Juravle85f7bf32016-03-18 16:23:40 +0000184TEST_F(ProfileCompilationInfoTest, MergeFail) {
Calin Juravle877fd962016-01-05 14:29:29 +0000185 ScratchFile profile;
186
187 ProfileCompilationInfo info1;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000188 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
Calin Juravle877fd962016-01-05 14:29:29 +0000189 // Use the same file, change the checksum.
190 ProfileCompilationInfo info2;
Calin Juravle85f7bf32016-03-18 16:23:40 +0000191 ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
Calin Juravle877fd962016-01-05 14:29:29 +0000192
Calin Juravle85f7bf32016-03-18 16:23:40 +0000193 ASSERT_FALSE(info1.MergeWith(info2));
Calin Juravle877fd962016-01-05 14:29:29 +0000194}
195
Calin Juravleb8697b12016-03-21 14:37:55 +0000196TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) {
197 ScratchFile profile;
198
199 ProfileCompilationInfo saved_info;
200 // Save the maximum number of methods
201 for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
202 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
203 ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
204 }
205 // Save the maximum number of classes
206 for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
207 ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, /* class_idx */ i, &saved_info));
208 ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, /* class_idx */ i, &saved_info));
209 }
210
211 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
212 ASSERT_EQ(0, profile.GetFile()->Flush());
213
214 // Check that we get back what we saved.
215 ProfileCompilationInfo loaded_info;
216 ASSERT_TRUE(profile.GetFile()->ResetOffset());
217 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
218 ASSERT_TRUE(loaded_info.Equals(saved_info));
219}
220
221TEST_F(ProfileCompilationInfoTest, SaveEmpty) {
222 ScratchFile profile;
223
224 ProfileCompilationInfo saved_info;
225 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
226 ASSERT_EQ(0, profile.GetFile()->Flush());
227
228 // Check that we get back what we saved.
229 ProfileCompilationInfo loaded_info;
230 ASSERT_TRUE(profile.GetFile()->ResetOffset());
231 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
232 ASSERT_TRUE(loaded_info.Equals(saved_info));
233}
234
235TEST_F(ProfileCompilationInfoTest, LoadEmpty) {
236 ScratchFile profile;
237
238 ProfileCompilationInfo empyt_info;
239
240 ProfileCompilationInfo loaded_info;
241 ASSERT_TRUE(profile.GetFile()->ResetOffset());
242 ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
243 ASSERT_TRUE(loaded_info.Equals(empyt_info));
244}
245
246TEST_F(ProfileCompilationInfoTest, BadMagic) {
247 ScratchFile profile;
248 uint8_t buffer[] = { 1, 2, 3, 4 };
249 ASSERT_TRUE(profile.GetFile()->WriteFully(buffer, sizeof(buffer)));
250 ProfileCompilationInfo loaded_info;
251 ASSERT_TRUE(profile.GetFile()->ResetOffset());
252 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
253}
254
255TEST_F(ProfileCompilationInfoTest, BadVersion) {
256 ScratchFile profile;
257
258 ASSERT_TRUE(profile.GetFile()->WriteFully(
259 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
260 uint8_t version[] = { 'v', 'e', 'r', 's', 'i', 'o', 'n' };
261 ASSERT_TRUE(profile.GetFile()->WriteFully(version, sizeof(version)));
262 ASSERT_EQ(0, profile.GetFile()->Flush());
263
264 ProfileCompilationInfo loaded_info;
265 ASSERT_TRUE(profile.GetFile()->ResetOffset());
266 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
267}
268
269TEST_F(ProfileCompilationInfoTest, Incomplete) {
270 ScratchFile profile;
271 ASSERT_TRUE(profile.GetFile()->WriteFully(
272 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
273 ASSERT_TRUE(profile.GetFile()->WriteFully(
274 ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
275 // Write that we have at least one line.
276 uint8_t line_number[] = { 0, 1 };
277 ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
278 ASSERT_EQ(0, profile.GetFile()->Flush());
279
280 ProfileCompilationInfo loaded_info;
281 ASSERT_TRUE(profile.GetFile()->ResetOffset());
282 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
283}
284
285TEST_F(ProfileCompilationInfoTest, TooLongDexLocation) {
286 ScratchFile profile;
287 ASSERT_TRUE(profile.GetFile()->WriteFully(
288 ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
289 ASSERT_TRUE(profile.GetFile()->WriteFully(
290 ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
291 // Write that we have at least one line.
292 uint8_t line_number[] = { 0, 1 };
293 ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
294
295 // dex_location_size, methods_size, classes_size, checksum.
296 // Dex location size is too big and should be rejected.
297 uint8_t line[] = { 255, 255, 0, 1, 0, 1, 0, 0, 0, 0 };
298 ASSERT_TRUE(profile.GetFile()->WriteFully(line, sizeof(line)));
299 ASSERT_EQ(0, profile.GetFile()->Flush());
300
301 ProfileCompilationInfo loaded_info;
302 ASSERT_TRUE(profile.GetFile()->ResetOffset());
303 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
304}
305
306TEST_F(ProfileCompilationInfoTest, UnexpectedContent) {
307 ScratchFile profile;
308
309 ProfileCompilationInfo saved_info;
310 // Save the maximum number of methods
311 for (uint16_t i = 0; i < 10; i++) {
312 ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
313 }
314 ASSERT_TRUE(saved_info.Save(GetFd(profile)));
315
316 uint8_t random_data[] = { 1, 2, 3};
317 ASSERT_TRUE(profile.GetFile()->WriteFully(random_data, sizeof(random_data)));
318
319 ASSERT_EQ(0, profile.GetFile()->Flush());
320
321 // Check that we fail because of unexpected data at the end of the file.
322 ProfileCompilationInfo loaded_info;
323 ASSERT_TRUE(profile.GetFile()->ResetOffset());
324 ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
325}
326
Calin Juravle877fd962016-01-05 14:29:29 +0000327} // namespace art