blob: a6c3cf067baae10e4abbacb951ddbc5c389cf970 [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 }
Calin Juravle2e2db782016-02-23 12:00:03 +000097};
98
99TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
100 ScratchFile profile1;
101 ScratchFile profile2;
102 ScratchFile reference_profile;
103
104 std::vector<int> profile_fds({
105 GetFd(profile1),
106 GetFd(profile2)});
107 int reference_profile_fd = GetFd(reference_profile);
108
109 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
110 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100111 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000112 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100113 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000114
115 // We should advise compilation.
116 ASSERT_EQ(ProfileAssistant::kCompile,
117 ProcessProfiles(profile_fds, reference_profile_fd));
118 // The resulting compilation info must be equal to the merge of the inputs.
119 ProfileCompilationInfo result;
120 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
121 ASSERT_TRUE(result.Load(reference_profile_fd));
122
123 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000124 ASSERT_TRUE(expected.MergeWith(info1));
125 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000126 ASSERT_TRUE(expected.Equals(result));
127
128 // The information from profiles must remain the same.
129 CheckProfileInfo(profile1, info1);
130 CheckProfileInfo(profile2, info2);
131}
132
Calin Juravlec824b512016-03-29 20:33:33 +0100133// TODO(calin): Add more tests for classes.
134TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
135 ScratchFile profile1;
136 ScratchFile reference_profile;
137
138 std::vector<int> profile_fds({
139 GetFd(profile1)});
140 int reference_profile_fd = GetFd(reference_profile);
141
142 const uint16_t kNumberOfClassesToEnableCompilation = 100;
143 ProfileCompilationInfo info1;
144 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
145
146 // We should advise compilation.
147 ASSERT_EQ(ProfileAssistant::kCompile,
148 ProcessProfiles(profile_fds, reference_profile_fd));
149 // The resulting compilation info must be equal to the merge of the inputs.
150 ProfileCompilationInfo result;
151 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
152 ASSERT_TRUE(result.Load(reference_profile_fd));
153
154 ProfileCompilationInfo expected;
155 ASSERT_TRUE(expected.MergeWith(info1));
156 ASSERT_TRUE(expected.Equals(result));
157
158 // The information from profiles must remain the same.
159 CheckProfileInfo(profile1, info1);
160}
161
Calin Juravle2e2db782016-02-23 12:00:03 +0000162TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
163 ScratchFile profile1;
164 ScratchFile profile2;
165 ScratchFile reference_profile;
166
167 std::vector<int> profile_fds({
168 GetFd(profile1),
169 GetFd(profile2)});
170 int reference_profile_fd = GetFd(reference_profile);
171
172 // The new profile info will contain the methods with indices 0-100.
173 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
174 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100175 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000176 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100177 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000178
179
180 // The reference profile info will contain the methods with indices 50-150.
181 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
182 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100183 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000184 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
185
186 // We should advise compilation.
187 ASSERT_EQ(ProfileAssistant::kCompile,
188 ProcessProfiles(profile_fds, reference_profile_fd));
189
190 // The resulting compilation info must be equal to the merge of the inputs
191 ProfileCompilationInfo result;
192 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
193 ASSERT_TRUE(result.Load(reference_profile_fd));
194
195 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000196 ASSERT_TRUE(expected.MergeWith(info1));
197 ASSERT_TRUE(expected.MergeWith(info2));
198 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000199 ASSERT_TRUE(expected.Equals(result));
200
201 // The information from profiles must remain the same.
202 CheckProfileInfo(profile1, info1);
203 CheckProfileInfo(profile2, info2);
204}
205
206TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
207 ScratchFile profile1;
208 ScratchFile profile2;
209 ScratchFile reference_profile;
210
211 std::vector<int> profile_fds({
212 GetFd(profile1),
213 GetFd(profile2)});
214 int reference_profile_fd = GetFd(reference_profile);
215
216 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
217 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100218 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000219 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100220 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000221
222 // We should not advise compilation.
223 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
224 ProcessProfiles(profile_fds, reference_profile_fd));
225
226 // The information from profiles must remain the same.
227 ProfileCompilationInfo file_info1;
228 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
229 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
230 ASSERT_TRUE(file_info1.Equals(info1));
231
232 ProfileCompilationInfo file_info2;
233 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
234 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
235 ASSERT_TRUE(file_info2.Equals(info2));
236
237 // Reference profile files must remain empty.
238 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
239
240 // The information from profiles must remain the same.
241 CheckProfileInfo(profile1, info1);
242 CheckProfileInfo(profile2, info2);
243}
244
245TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
246 ScratchFile profile1;
247 ScratchFile profile2;
248 ScratchFile reference_profile;
249
250 std::vector<int> profile_fds({
251 GetFd(profile1),
252 GetFd(profile2)});
253 int reference_profile_fd = GetFd(reference_profile);
254
255 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
256 // Assign different hashes for the same dex file. This will make merging of information to fail.
257 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100258 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000259 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100260 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000261
262 // We should fail processing.
263 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
264 ProcessProfiles(profile_fds, reference_profile_fd));
265
266 // The information from profiles must remain the same.
267 CheckProfileInfo(profile1, info1);
268 CheckProfileInfo(profile2, info2);
269
270 // Reference profile files must still remain empty.
271 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
272}
273
274TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
275 ScratchFile profile1;
276 ScratchFile reference_profile;
277
278 std::vector<int> profile_fds({
279 GetFd(profile1)});
280 int reference_profile_fd = GetFd(reference_profile);
281
282 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
283 // Assign different hashes for the same dex file. This will make merging of information to fail.
284 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100285 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000286 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100287 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000288
289 // We should not advise compilation.
290 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
291 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
292 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
293 ProcessProfiles(profile_fds, reference_profile_fd));
294
295 // The information from profiles must remain the same.
296 CheckProfileInfo(profile1, info1);
297}
298
Calin Juravle7bcdb532016-06-07 16:14:47 +0100299TEST_F(ProfileAssistantTest, TestProfileGeneration) {
300 ScratchFile profile;
301 // Generate a test profile.
302 GenerateTestProfile(profile.GetFilename());
303
304 // Verify that the generated profile is valid and can be loaded.
305 ASSERT_TRUE(profile.GetFile()->ResetOffset());
306 ProfileCompilationInfo info;
307 ASSERT_TRUE(info.Load(GetFd(profile)));
308}
309
Calin Juravle2e2db782016-02-23 12:00:03 +0000310} // namespace art