1 /*
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
25 namespace art {
26
27 class ProfileAssistantTest : public CommonRuntimeTest {
28 protected:
SetupProfile(const std::string & id,uint32_t checksum,uint16_t number_of_methods,uint16_t number_of_classes,const ScratchFile & profile,ProfileCompilationInfo * info,uint16_t start_method_index=0)29 void SetupProfile(const std::string& id,
30 uint32_t checksum,
31 uint16_t number_of_methods,
32 uint16_t number_of_classes,
33 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++) {
41 ASSERT_TRUE(info->AddMethodIndex(dex_location1, dex_location_checksum1, i));
42 ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
43 }
44 for (uint16_t i = 0; i < number_of_classes; i++) {
45 ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
46 }
47
48 ASSERT_TRUE(info->Save(GetFd(profile)));
49 ASSERT_EQ(0, profile.GetFile()->Flush());
50 ASSERT_TRUE(profile.GetFile()->ResetOffset());
51 }
52
GetFd(const ScratchFile & file) const53 int GetFd(const ScratchFile& file) const {
54 return static_cast<int>(file.GetFd());
55 }
56
CheckProfileInfo(ScratchFile & file,const ProfileCompilationInfo & info)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
64 // Runs test with given arguments.
ProcessProfiles(const std::vector<int> & profiles_fd,int reference_profile_fd)65 int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
66 std::string file_path = GetTestAndroidRoot();
67 file_path += "/bin/profman";
68 if (kIsDebugBuild) {
69 file_path += "d";
70 }
71
72 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
73 std::vector<std::string> argv_str;
74 argv_str.push_back(file_path);
75 for (size_t k = 0; k < profiles_fd.size(); k++) {
76 argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
77 }
78 argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
79
80 std::string error;
81 return ExecAndReturnCode(argv_str, &error);
82 }
83 };
84
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferences)85 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
86 ScratchFile profile1;
87 ScratchFile profile2;
88 ScratchFile reference_profile;
89
90 std::vector<int> profile_fds({
91 GetFd(profile1),
92 GetFd(profile2)});
93 int reference_profile_fd = GetFd(reference_profile);
94
95 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
96 ProfileCompilationInfo info1;
97 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
98 ProfileCompilationInfo info2;
99 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
100
101 // We should advise compilation.
102 ASSERT_EQ(ProfileAssistant::kCompile,
103 ProcessProfiles(profile_fds, reference_profile_fd));
104 // The resulting compilation info must be equal to the merge of the inputs.
105 ProfileCompilationInfo result;
106 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
107 ASSERT_TRUE(result.Load(reference_profile_fd));
108
109 ProfileCompilationInfo expected;
110 ASSERT_TRUE(expected.MergeWith(info1));
111 ASSERT_TRUE(expected.MergeWith(info2));
112 ASSERT_TRUE(expected.Equals(result));
113
114 // The information from profiles must remain the same.
115 CheckProfileInfo(profile1, info1);
116 CheckProfileInfo(profile2, info2);
117 }
118
119 // TODO(calin): Add more tests for classes.
TEST_F(ProfileAssistantTest,AdviseCompilationEmptyReferencesBecauseOfClasses)120 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
121 ScratchFile profile1;
122 ScratchFile reference_profile;
123
124 std::vector<int> profile_fds({
125 GetFd(profile1)});
126 int reference_profile_fd = GetFd(reference_profile);
127
128 const uint16_t kNumberOfClassesToEnableCompilation = 100;
129 ProfileCompilationInfo info1;
130 SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
131
132 // We should advise compilation.
133 ASSERT_EQ(ProfileAssistant::kCompile,
134 ProcessProfiles(profile_fds, reference_profile_fd));
135 // The resulting compilation info must be equal to the merge of the inputs.
136 ProfileCompilationInfo result;
137 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
138 ASSERT_TRUE(result.Load(reference_profile_fd));
139
140 ProfileCompilationInfo expected;
141 ASSERT_TRUE(expected.MergeWith(info1));
142 ASSERT_TRUE(expected.Equals(result));
143
144 // The information from profiles must remain the same.
145 CheckProfileInfo(profile1, info1);
146 }
147
TEST_F(ProfileAssistantTest,AdviseCompilationNonEmptyReferences)148 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
149 ScratchFile profile1;
150 ScratchFile profile2;
151 ScratchFile reference_profile;
152
153 std::vector<int> profile_fds({
154 GetFd(profile1),
155 GetFd(profile2)});
156 int reference_profile_fd = GetFd(reference_profile);
157
158 // The new profile info will contain the methods with indices 0-100.
159 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
160 ProfileCompilationInfo info1;
161 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
162 ProfileCompilationInfo info2;
163 SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
164
165
166 // The reference profile info will contain the methods with indices 50-150.
167 const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
168 ProfileCompilationInfo reference_info;
169 SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
170 &reference_info, kNumberOfMethodsToEnableCompilation / 2);
171
172 // We should advise compilation.
173 ASSERT_EQ(ProfileAssistant::kCompile,
174 ProcessProfiles(profile_fds, reference_profile_fd));
175
176 // The resulting compilation info must be equal to the merge of the inputs
177 ProfileCompilationInfo result;
178 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
179 ASSERT_TRUE(result.Load(reference_profile_fd));
180
181 ProfileCompilationInfo expected;
182 ASSERT_TRUE(expected.MergeWith(info1));
183 ASSERT_TRUE(expected.MergeWith(info2));
184 ASSERT_TRUE(expected.MergeWith(reference_info));
185 ASSERT_TRUE(expected.Equals(result));
186
187 // The information from profiles must remain the same.
188 CheckProfileInfo(profile1, info1);
189 CheckProfileInfo(profile2, info2);
190 }
191
TEST_F(ProfileAssistantTest,DoNotAdviseCompilation)192 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
193 ScratchFile profile1;
194 ScratchFile profile2;
195 ScratchFile reference_profile;
196
197 std::vector<int> profile_fds({
198 GetFd(profile1),
199 GetFd(profile2)});
200 int reference_profile_fd = GetFd(reference_profile);
201
202 const uint16_t kNumberOfMethodsToSkipCompilation = 1;
203 ProfileCompilationInfo info1;
204 SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
205 ProfileCompilationInfo info2;
206 SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
207
208 // We should not advise compilation.
209 ASSERT_EQ(ProfileAssistant::kSkipCompilation,
210 ProcessProfiles(profile_fds, reference_profile_fd));
211
212 // The information from profiles must remain the same.
213 ProfileCompilationInfo file_info1;
214 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
215 ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
216 ASSERT_TRUE(file_info1.Equals(info1));
217
218 ProfileCompilationInfo file_info2;
219 ASSERT_TRUE(profile2.GetFile()->ResetOffset());
220 ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
221 ASSERT_TRUE(file_info2.Equals(info2));
222
223 // Reference profile files must remain empty.
224 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
225
226 // The information from profiles must remain the same.
227 CheckProfileInfo(profile1, info1);
228 CheckProfileInfo(profile2, info2);
229 }
230
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfProfiles)231 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
232 ScratchFile profile1;
233 ScratchFile profile2;
234 ScratchFile reference_profile;
235
236 std::vector<int> profile_fds({
237 GetFd(profile1),
238 GetFd(profile2)});
239 int reference_profile_fd = GetFd(reference_profile);
240
241 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
242 // Assign different hashes for the same dex file. This will make merging of information to fail.
243 ProfileCompilationInfo info1;
244 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
245 ProfileCompilationInfo info2;
246 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
247
248 // We should fail processing.
249 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
250 ProcessProfiles(profile_fds, reference_profile_fd));
251
252 // The information from profiles must remain the same.
253 CheckProfileInfo(profile1, info1);
254 CheckProfileInfo(profile2, info2);
255
256 // Reference profile files must still remain empty.
257 ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
258 }
259
TEST_F(ProfileAssistantTest,FailProcessingBecauseOfReferenceProfiles)260 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
261 ScratchFile profile1;
262 ScratchFile reference_profile;
263
264 std::vector<int> profile_fds({
265 GetFd(profile1)});
266 int reference_profile_fd = GetFd(reference_profile);
267
268 const uint16_t kNumberOfMethodsToEnableCompilation = 100;
269 // Assign different hashes for the same dex file. This will make merging of information to fail.
270 ProfileCompilationInfo info1;
271 SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
272 ProfileCompilationInfo reference_info;
273 SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
274
275 // We should not advise compilation.
276 ASSERT_TRUE(profile1.GetFile()->ResetOffset());
277 ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
278 ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
279 ProcessProfiles(profile_fds, reference_profile_fd));
280
281 // The information from profiles must remain the same.
282 CheckProfileInfo(profile1, info1);
283 }
284
285 } // namespace art
286