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: 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 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 64 // Runs test with given arguments. 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 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. 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 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 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 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 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