blob: cd0aa6fd7d60f6f1af3b11ed84eb214e885965e2 [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"
21#include "profile_assistant.h"
22#include "jit/offline_profiling_info.h"
23#include "utils.h"
24
25namespace art {
26
27class ProfileAssistantTest : public CommonRuntimeTest {
28 protected:
29 void SetupProfile(const std::string& id,
30 uint32_t checksum,
31 uint16_t number_of_methods,
Calin Juravlec824b512016-03-29 20:33:33 +010032 uint16_t number_of_classes,
Calin Juravle2e2db782016-02-23 12:00:03 +000033 const ScratchFile& profile,
34 ProfileCompilationInfo* info,
35 uint16_t start_method_index = 0) {
36 std::string dex_location1 = "location1" + id;
37 uint32_t dex_location_checksum1 = checksum;
38 std::string dex_location2 = "location2" + id;
39 uint32_t dex_location_checksum2 = 10 * checksum;
40 for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
Mathieu Chartierc5dd3192015-12-09 16:38:30 -080041 ASSERT_TRUE(info->AddMethodIndex(dex_location1, dex_location_checksum1, i));
42 ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
Calin Juravle2e2db782016-02-23 12:00:03 +000043 }
Calin Juravlec824b512016-03-29 20:33:33 +010044 for (uint16_t i = 0; i < number_of_classes; i++) {
45 ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
46 }
47
Calin Juravle2e2db782016-02-23 12:00:03 +000048 ASSERT_TRUE(info->Save(GetFd(profile)));
49 ASSERT_EQ(0, profile.GetFile()->Flush());
50 ASSERT_TRUE(profile.GetFile()->ResetOffset());
51 }
52
53 int GetFd(const ScratchFile& file) const {
54 return static_cast<int>(file.GetFd());
55 }
56
57 void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
58 ProfileCompilationInfo file_info;
59 ASSERT_TRUE(file.GetFile()->ResetOffset());
60 ASSERT_TRUE(file_info.Load(GetFd(file)));
61 ASSERT_TRUE(file_info.Equals(info));
62 }
63
Calin Juravle7bcdb532016-06-07 16:14:47 +010064 std::string GetProfmanCmd() {
Calin Juravle2e2db782016-02-23 12:00:03 +000065 std::string file_path = GetTestAndroidRoot();
Calin Juravlede4fb632016-02-23 16:53:30 +000066 file_path += "/bin/profman";
Calin Juravle2e2db782016-02-23 12:00:03 +000067 if (kIsDebugBuild) {
68 file_path += "d";
69 }
Calin Juravle7bcdb532016-06-07 16:14:47 +010070 EXPECT_TRUE(OS::FileExists(file_path.c_str()))
71 << file_path << " should be a valid file path";
72 return file_path;
73 }
74 // Runs test with given arguments.
75 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
76 std::string profman_cmd = GetProfmanCmd();
Calin Juravle2e2db782016-02-23 12:00:03 +000077 std::vector<std::string> argv_str;
Calin Juravle7bcdb532016-06-07 16:14:47 +010078 argv_str.push_back(profman_cmd);
Calin Juravle2e2db782016-02-23 12:00:03 +000079 for (size_t k = 0; k < profiles_fd.size(); k++) {
80 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
81 }
82 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
83
84 std::string error;
85 return ExecAndReturnCode(argv_str, &error);
86 }
Calin Juravle7bcdb532016-06-07 16:14:47 +010087
88 bool GenerateTestProfile(const std::string& filename) {
89 std::string profman_cmd = GetProfmanCmd();
90 std::vector<std::string> argv_str;
91 argv_str.push_back(profman_cmd);
92 argv_str.push_back("--generate-test-profile=" + filename);
93 std::string error;
94 return ExecAndReturnCode(argv_str, &error);
95 }
Calin Juravle2e2db782016-02-23 12:00:03 +000096};
97
98TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
99 ScratchFile profile1;
100 ScratchFile profile2;
101 ScratchFile reference_profile;
102
103 std::vector<int> profile_fds({
104 GetFd(profile1),
105 GetFd(profile2)});
106 int reference_profile_fd = GetFd(reference_profile);
107
108 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
109 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100110 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000111 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100112 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000113
114 // We should advise compilation.
115 ASSERT_EQ(ProfileAssistant::kCompile,
116 ProcessProfiles(profile_fds, reference_profile_fd));
117 // The resulting compilation info must be equal to the merge of the inputs.
118 ProfileCompilationInfo result;
119 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
120 ASSERT_TRUE(result.Load(reference_profile_fd));
121
122 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000123 ASSERT_TRUE(expected.MergeWith(info1));
124 ASSERT_TRUE(expected.MergeWith(info2));
Calin Juravle2e2db782016-02-23 12:00:03 +0000125 ASSERT_TRUE(expected.Equals(result));
126
127 // The information from profiles must remain the same.
128 CheckProfileInfo(profile1, info1);
129 CheckProfileInfo(profile2, info2);
130}
131
Calin Juravlec824b512016-03-29 20:33:33 +0100132// TODO(calin): Add more tests for classes.
133TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
134 ScratchFile profile1;
135 ScratchFile reference_profile;
136
137 std::vector<int> profile_fds({
138 GetFd(profile1)});
139 int reference_profile_fd = GetFd(reference_profile);
140
141 const uint16_t kNumberOfClassesToEnableCompilation = 100;
142 ProfileCompilationInfo info1;
143 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
144
145 // We should advise compilation.
146 ASSERT_EQ(ProfileAssistant::kCompile,
147 ProcessProfiles(profile_fds, reference_profile_fd));
148 // The resulting compilation info must be equal to the merge of the inputs.
149 ProfileCompilationInfo result;
150 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
151 ASSERT_TRUE(result.Load(reference_profile_fd));
152
153 ProfileCompilationInfo expected;
154 ASSERT_TRUE(expected.MergeWith(info1));
155 ASSERT_TRUE(expected.Equals(result));
156
157 // The information from profiles must remain the same.
158 CheckProfileInfo(profile1, info1);
159}
160
Calin Juravle2e2db782016-02-23 12:00:03 +0000161TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
162 ScratchFile profile1;
163 ScratchFile profile2;
164 ScratchFile reference_profile;
165
166 std::vector<int> profile_fds({
167 GetFd(profile1),
168 GetFd(profile2)});
169 int reference_profile_fd = GetFd(reference_profile);
170
171 // The new profile info will contain the methods with indices 0-100.
172 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
173 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100174 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000175 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100176 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000177
178
179 // The reference profile info will contain the methods with indices 50-150.
180 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
181 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100182 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
Calin Juravle2e2db782016-02-23 12:00:03 +0000183 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
184
185 // We should advise compilation.
186 ASSERT_EQ(ProfileAssistant::kCompile,
187 ProcessProfiles(profile_fds, reference_profile_fd));
188
189 // The resulting compilation info must be equal to the merge of the inputs
190 ProfileCompilationInfo result;
191 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
192 ASSERT_TRUE(result.Load(reference_profile_fd));
193
194 ProfileCompilationInfo expected;
Calin Juravle67265462016-03-18 16:23:40 +0000195 ASSERT_TRUE(expected.MergeWith(info1));
196 ASSERT_TRUE(expected.MergeWith(info2));
197 ASSERT_TRUE(expected.MergeWith(reference_info));
Calin Juravle2e2db782016-02-23 12:00:03 +0000198 ASSERT_TRUE(expected.Equals(result));
199
200 // The information from profiles must remain the same.
201 CheckProfileInfo(profile1, info1);
202 CheckProfileInfo(profile2, info2);
203}
204
205TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
206 ScratchFile profile1;
207 ScratchFile profile2;
208 ScratchFile reference_profile;
209
210 std::vector<int> profile_fds({
211 GetFd(profile1),
212 GetFd(profile2)});
213 int reference_profile_fd = GetFd(reference_profile);
214
215 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
216 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100217 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000218 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100219 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000220
221 // We should not advise compilation.
222 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
223 ProcessProfiles(profile_fds, reference_profile_fd));
224
225 // The information from profiles must remain the same.
226 ProfileCompilationInfo file_info1;
227 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
228 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
229 ASSERT_TRUE(file_info1.Equals(info1));
230
231 ProfileCompilationInfo file_info2;
232 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
233 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
234 ASSERT_TRUE(file_info2.Equals(info2));
235
236 // Reference profile files must remain empty.
237 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
238
239 // The information from profiles must remain the same.
240 CheckProfileInfo(profile1, info1);
241 CheckProfileInfo(profile2, info2);
242}
243
244TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
245 ScratchFile profile1;
246 ScratchFile profile2;
247 ScratchFile reference_profile;
248
249 std::vector<int> profile_fds({
250 GetFd(profile1),
251 GetFd(profile2)});
252 int reference_profile_fd = GetFd(reference_profile);
253
254 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
255 // Assign different hashes for the same dex file. This will make merging of information to fail.
256 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100257 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000258 ProfileCompilationInfo info2;
Calin Juravlec824b512016-03-29 20:33:33 +0100259 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
Calin Juravle2e2db782016-02-23 12:00:03 +0000260
261 // We should fail processing.
262 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
263 ProcessProfiles(profile_fds, reference_profile_fd));
264
265 // The information from profiles must remain the same.
266 CheckProfileInfo(profile1, info1);
267 CheckProfileInfo(profile2, info2);
268
269 // Reference profile files must still remain empty.
270 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
271}
272
273TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
274 ScratchFile profile1;
275 ScratchFile reference_profile;
276
277 std::vector<int> profile_fds({
278 GetFd(profile1)});
279 int reference_profile_fd = GetFd(reference_profile);
280
281 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
282 // Assign different hashes for the same dex file. This will make merging of information to fail.
283 ProfileCompilationInfo info1;
Calin Juravlec824b512016-03-29 20:33:33 +0100284 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
Calin Juravle2e2db782016-02-23 12:00:03 +0000285 ProfileCompilationInfo reference_info;
Calin Juravlec824b512016-03-29 20:33:33 +0100286 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
Calin Juravle2e2db782016-02-23 12:00:03 +0000287
288 // We should not advise compilation.
289 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
290 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
291 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
292 ProcessProfiles(profile_fds, reference_profile_fd));
293
294 // The information from profiles must remain the same.
295 CheckProfileInfo(profile1, info1);
296}
297
Calin Juravle7bcdb532016-06-07 16:14:47 +0100298TEST_F(ProfileAssistantTest, TestProfileGeneration) {
299 ScratchFile profile;
300 // Generate a test profile.
301 GenerateTestProfile(profile.GetFilename());
302
303 // Verify that the generated profile is valid and can be loaded.
304 ASSERT_TRUE(profile.GetFile()->ResetOffset());
305 ProfileCompilationInfo info;
306 ASSERT_TRUE(info.Load(GetFd(profile)));
307}
308
Calin Juravle2e2db782016-02-23 12:00:03 +0000309} // namespace art