blob: d395c170bfcb5f81f4f259d6166ff5354bbeb889 [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
19#include "base/unix_file/fd_file.h"
20#include "common_runtime_test.h"
David Sehr97c381e2017-02-01 15:09:58 -080021#include "exec_utils.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000022#include "profile_assistant.h"
Calin Juravle33083d62017-01-18 15:29:12 -080023#include "jit/profile_compilation_info.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000024#include "utils.h"
25
26namespace art {
27
28class ProfileAssistantTest : public CommonRuntimeTest {
29 protected:
30 void SetupProfile(const std::string& id,
31 uint32_t checksum,
32 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010033 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000034 const ScratchFile& profile,
35 ProfileCompilationInfo* info,
36 uint16_t start_method_index = 0) {
37 std::string dex_location1 = "location1" + id;
38 uint32_t dex_location_checksum1 = checksum;
39 std::string dex_location2 = "location2" + id;
40 uint32_t dex_location_checksum2 = 10 * checksum;
41 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Mathieu Chartierc5dd3192015-12-09 16:38:30 -080042 ASSERT_TRUE(info->AddMethodIndex(dex_location1, dex_location_checksum1, i));
43 ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
Calin Juravle2e2db782016-02-23 12:00:03 +000044 }
Calin Juravlec824b512016-03-29 20:33:33 +010045 for (uint16_t i = 0; i < number_of_classes; i++) {
Andreas Gampea5b09a62016-11-17 15:21:22 -080046 ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
Calin Juravlec824b512016-03-29 20:33:33 +010047 }
48
Calin Juravle2e2db782016-02-23 12:00:03 +000049 ASSERT_TRUE(info->Save(GetFd(profile)));
50 ASSERT_EQ(0, profile.GetFile()->Flush());
51 ASSERT_TRUE(profile.GetFile()->ResetOffset());
52 }
53
54 int GetFd(const ScratchFile& file) const {
55 return static_cast<int>(file.GetFd());
56 }
57
58 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
59 ProfileCompilationInfo file_info;
60 ASSERT_TRUE(file.GetFile()->ResetOffset());
61 ASSERT_TRUE(file_info.Load(GetFd(file)));
62 ASSERT_TRUE(file_info.Equals(info));
63 }
64
Calin Juravle7bcdb532016-06-07 16:14:47 +010065 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +000066 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +000067 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +000068 if (kIsDebugBuild) {
69 file_path += "d";
70 }
Calin Juravle7bcdb532016-06-07 16:14:47 +010071 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
72 << file_path << " should be a valid file path";
73 return file_path;
74 }
75 // Runs test with given arguments.
76 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
77 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +000078 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +010079 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +000080 for (size_t k = 0; k < profiles_fd.size(); k++) {
81 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
82 }
83 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
84
85 std::string error;
86 return ExecAndReturnCode(argv_str, &error);
87 }
Calin Juravle7bcdb532016-06-07 16:14:47 +010088
89 bool GenerateTestProfile(const std::string& filename) {
90 std::string profman_cmd = GetProfmanCmd();
91 std::vector<std::string> argv_str;
92 argv_str.push_back(profman_cmd);
93 argv_str.push_back("--generate-test-profile=" + filename);
94 std::string error;
95 return ExecAndReturnCode(argv_str, &error);
96 }
David Sehr7c80f2d2017-02-07 16:47:58 -080097
98 bool CreateProfile(std::string class_file_contents, const std::string& filename) {
99 ScratchFile class_names_file;
100 File* file = class_names_file.GetFile();
101 EXPECT_TRUE(file->WriteFully(class_file_contents.c_str(), class_file_contents.length()));
102 EXPECT_EQ(0, file->Flush());
103 EXPECT_TRUE(file->ResetOffset());
104 std::string profman_cmd = GetProfmanCmd();
105 std::vector<std::string> argv_str;
106 argv_str.push_back(profman_cmd);
107 argv_str.push_back("--create-profile-from=" + class_names_file.GetFilename());
108 argv_str.push_back("--reference-profile-file=" + filename);
109 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
110 argv_str.push_back("--dex-location=classes.dex");
111 std::string error;
112 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
113 return true;
114 }
115
116 bool DumpClasses(const std::string& filename, std::string* file_contents) {
117 ScratchFile class_names_file;
118 std::string profman_cmd = GetProfmanCmd();
119 std::vector<std::string> argv_str;
120 argv_str.push_back(profman_cmd);
121 argv_str.push_back("--dump-classes");
122 argv_str.push_back("--profile-file=" + filename);
123 argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
124 argv_str.push_back("--dex-location=classes.dex");
125 argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(class_names_file)));
126 std::string error;
127 EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
128 File* file = class_names_file.GetFile();
129 EXPECT_EQ(0, file->Flush());
130 EXPECT_TRUE(file->ResetOffset());
131 int64_t length = file->GetLength();
132 std::unique_ptr<char[]> buf(new char[length]);
133 EXPECT_EQ(file->Read(buf.get(), length, 0), length);
134 *file_contents = std::string(buf.get(), length);
135 return true;
136 }
137
138 bool CreateAndDump(const std::string& input_file_contents, std::string* output_file_contents) {
139 ScratchFile profile_file;
140 EXPECT_TRUE(CreateProfile(input_file_contents, profile_file.GetFilename()));
141 profile_file.GetFile()->ResetOffset();
142 EXPECT_TRUE(DumpClasses(profile_file.GetFilename(), output_file_contents));
143 return true;
144 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000145};
146
147TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
148 ScratchFile profile1;
149 ScratchFile profile2;
150 ScratchFile reference_profile;
151
152 std::vector<int> profile_fds({
153 GetFd(profile1),
154 GetFd(profile2)});
155 int reference_profile_fd = GetFd(reference_profile);
156
157 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
158 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100159 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000160 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100161 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000162
163 // We should advise compilation.
164 ASSERT_EQ(ProfileAssistant::kCompile,
165 ProcessProfiles(profile_fds, reference_profile_fd));
166 // The resulting compilation info must be equal to the merge of the inputs.
167 ProfileCompilationInfo result;
168 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
169 ASSERT_TRUE(result.Load(reference_profile_fd));
170
171 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000172 ASSERT_TRUE(expected.MergeWith(info1));
173 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000174 ASSERT_TRUE(expected.Equals(result));
175
176 // The information from profiles must remain the same.
177 CheckProfileInfo(profile1, info1);
178 CheckProfileInfo(profile2, info2);
179}
180
Calin Juravlec824b512016-03-29 20:33:33 +0100181// TODO(calin): Add more tests for classes.
182TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
183 ScratchFile profile1;
184 ScratchFile reference_profile;
185
186 std::vector<int> profile_fds({
187 GetFd(profile1)});
188 int reference_profile_fd = GetFd(reference_profile);
189
190 const uint16_t kNumberOfClassesToEnableCompilation = 100;
191 ProfileCompilationInfo info1;
192 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
193
194 // We should advise compilation.
195 ASSERT_EQ(ProfileAssistant::kCompile,
196 ProcessProfiles(profile_fds, reference_profile_fd));
197 // The resulting compilation info must be equal to the merge of the inputs.
198 ProfileCompilationInfo result;
199 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
200 ASSERT_TRUE(result.Load(reference_profile_fd));
201
202 ProfileCompilationInfo expected;
203 ASSERT_TRUE(expected.MergeWith(info1));
204 ASSERT_TRUE(expected.Equals(result));
205
206 // The information from profiles must remain the same.
207 CheckProfileInfo(profile1, info1);
208}
209
Calin Juravle2e2db782016-02-23 12:00:03 +0000210TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
211 ScratchFile profile1;
212 ScratchFile profile2;
213 ScratchFile reference_profile;
214
215 std::vector<int> profile_fds({
216 GetFd(profile1),
217 GetFd(profile2)});
218 int reference_profile_fd = GetFd(reference_profile);
219
220 // The new profile info will contain the methods with indices 0-100.
221 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
222 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100223 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000224 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100225 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000226
227
228 // The reference profile info will contain the methods with indices 50-150.
229 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
230 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100231 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000232 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
233
234 // We should advise compilation.
235 ASSERT_EQ(ProfileAssistant::kCompile,
236 ProcessProfiles(profile_fds, reference_profile_fd));
237
238 // The resulting compilation info must be equal to the merge of the inputs
239 ProfileCompilationInfo result;
240 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
241 ASSERT_TRUE(result.Load(reference_profile_fd));
242
243 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000244 ASSERT_TRUE(expected.MergeWith(info1));
245 ASSERT_TRUE(expected.MergeWith(info2));
246 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000247 ASSERT_TRUE(expected.Equals(result));
248
249 // The information from profiles must remain the same.
250 CheckProfileInfo(profile1, info1);
251 CheckProfileInfo(profile2, info2);
252}
253
254TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
255 ScratchFile profile1;
256 ScratchFile profile2;
257 ScratchFile reference_profile;
258
259 std::vector<int> profile_fds({
260 GetFd(profile1),
261 GetFd(profile2)});
262 int reference_profile_fd = GetFd(reference_profile);
263
264 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
265 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100266 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000267 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100268 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000269
270 // We should not advise compilation.
271 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
272 ProcessProfiles(profile_fds, reference_profile_fd));
273
274 // The information from profiles must remain the same.
275 ProfileCompilationInfo file_info1;
276 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
277 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
278 ASSERT_TRUE(file_info1.Equals(info1));
279
280 ProfileCompilationInfo file_info2;
281 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
282 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
283 ASSERT_TRUE(file_info2.Equals(info2));
284
285 // Reference profile files must remain empty.
286 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
287
288 // The information from profiles must remain the same.
289 CheckProfileInfo(profile1, info1);
290 CheckProfileInfo(profile2, info2);
291}
292
293TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
294 ScratchFile profile1;
295 ScratchFile profile2;
296 ScratchFile reference_profile;
297
298 std::vector<int> profile_fds({
299 GetFd(profile1),
300 GetFd(profile2)});
301 int reference_profile_fd = GetFd(reference_profile);
302
303 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
304 // Assign different hashes for the same dex file. This will make merging of information to fail.
305 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100306 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000307 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100308 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000309
310 // We should fail processing.
311 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
312 ProcessProfiles(profile_fds, reference_profile_fd));
313
314 // The information from profiles must remain the same.
315 CheckProfileInfo(profile1, info1);
316 CheckProfileInfo(profile2, info2);
317
318 // Reference profile files must still remain empty.
319 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
320}
321
322TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
323 ScratchFile profile1;
324 ScratchFile reference_profile;
325
326 std::vector<int> profile_fds({
327 GetFd(profile1)});
328 int reference_profile_fd = GetFd(reference_profile);
329
330 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
331 // Assign different hashes for the same dex file. This will make merging of information to fail.
332 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100333 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000334 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100335 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000336
337 // We should not advise compilation.
338 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
339 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
340 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
341 ProcessProfiles(profile_fds, reference_profile_fd));
342
343 // The information from profiles must remain the same.
344 CheckProfileInfo(profile1, info1);
345}
346
Calin Juravle7bcdb532016-06-07 16:14:47 +0100347TEST_F(ProfileAssistantTest, TestProfileGeneration) {
348 ScratchFile profile;
349 // Generate a test profile.
350 GenerateTestProfile(profile.GetFilename());
351
352 // Verify that the generated profile is valid and can be loaded.
353 ASSERT_TRUE(profile.GetFile()->ResetOffset());
354 ProfileCompilationInfo info;
355 ASSERT_TRUE(info.Load(GetFd(profile)));
356}
357
David Sehr7c80f2d2017-02-07 16:47:58 -0800358TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
359 // Class names put here need to be in sorted order.
360 std::vector<std::string> class_names = {
361 "java.lang.Comparable",
362 "java.lang.Math",
363 "java.lang.Object"
364 };
365 std::string input_file_contents;
366 for (std::string& class_name : class_names) {
367 input_file_contents += class_name + std::string("\n");
368 }
369 std::string output_file_contents;
370 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
371 ASSERT_EQ(output_file_contents, input_file_contents);
372}
373
374TEST_F(ProfileAssistantTest, TestProfileCreationOneNotMatched) {
375 // Class names put here need to be in sorted order.
376 std::vector<std::string> class_names = {
377 "doesnt.match.this.one",
378 "java.lang.Comparable",
379 "java.lang.Object"
380 };
381 std::string input_file_contents;
382 for (std::string& class_name : class_names) {
383 input_file_contents += class_name + std::string("\n");
384 }
385 std::string output_file_contents;
386 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
387 std::string expected_contents =
388 class_names[1] + std::string("\n") + class_names[2] + std::string("\n");
389 ASSERT_EQ(output_file_contents, expected_contents);
390}
391
392TEST_F(ProfileAssistantTest, TestProfileCreationNoneMatched) {
393 // Class names put here need to be in sorted order.
394 std::vector<std::string> class_names = {
395 "doesnt.match.this.one",
396 "doesnt.match.this.one.either",
397 "nor.this.one"
398 };
399 std::string input_file_contents;
400 for (std::string& class_name : class_names) {
401 input_file_contents += class_name + std::string("\n");
402 }
403 std::string output_file_contents;
404 ASSERT_TRUE(CreateAndDump(input_file_contents, &output_file_contents));
405 std::string expected_contents("");
406 ASSERT_EQ(output_file_contents, expected_contents);
407}
408
Calin Juravle2e2db782016-02-23 12:00:03 +0000409} // namespace art