| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 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 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 17 | #include <regex> | 
 | 18 | #include <sstream> | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 19 | #include <string> | 
 | 20 | #include <vector> | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 21 |  | 
| Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 22 | #include <sys/wait.h> | 
 | 23 | #include <unistd.h> | 
 | 24 |  | 
 | 25 | #include "android-base/stringprintf.h" | 
 | 26 |  | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 27 | #include "common_runtime_test.h" | 
 | 28 |  | 
 | 29 | #include "base/logging.h" | 
 | 30 | #include "base/macros.h" | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 31 | #include "dex_file-inl.h" | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 32 | #include "dex2oat_environment_test.h" | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 33 | #include "dex2oat_return_codes.h" | 
| Calin Juravle | 33083d6 | 2017-01-18 15:29:12 -0800 | [diff] [blame] | 34 | #include "jit/profile_compilation_info.h" | 
| Andreas Gampe | 67f0282 | 2016-06-24 21:05:23 -0700 | [diff] [blame] | 35 | #include "oat.h" | 
 | 36 | #include "oat_file.h" | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 37 | #include "utils.h" | 
 | 38 |  | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 39 | namespace art { | 
 | 40 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 41 | using android::base::StringPrintf; | 
 | 42 |  | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 43 | class Dex2oatTest : public Dex2oatEnvironmentTest { | 
 | 44 |  public: | 
 | 45 |   virtual void TearDown() OVERRIDE { | 
 | 46 |     Dex2oatEnvironmentTest::TearDown(); | 
 | 47 |  | 
 | 48 |     output_ = ""; | 
 | 49 |     error_msg_ = ""; | 
 | 50 |     success_ = false; | 
 | 51 |   } | 
 | 52 |  | 
 | 53 |  protected: | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 54 |   int GenerateOdexForTestWithStatus(const std::string& dex_location, | 
 | 55 |                                     const std::string& odex_location, | 
 | 56 |                                     CompilerFilter::Filter filter, | 
 | 57 |                                     std::string* error_msg, | 
 | 58 |                                     const std::vector<std::string>& extra_args = {}, | 
 | 59 |                                     bool use_fd = false) { | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 60 |     std::unique_ptr<File> oat_file; | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 61 |     std::vector<std::string> args; | 
 | 62 |     args.push_back("--dex-file=" + dex_location); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 63 |     if (use_fd) { | 
 | 64 |       oat_file.reset(OS::CreateEmptyFile(odex_location.c_str())); | 
 | 65 |       CHECK(oat_file != nullptr) << odex_location; | 
 | 66 |       args.push_back("--oat-fd=" + std::to_string(oat_file->Fd())); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 67 |       args.push_back("--oat-location=" + odex_location); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 68 |     } else { | 
 | 69 |       args.push_back("--oat-file=" + odex_location); | 
 | 70 |     } | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 71 |     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); | 
 | 72 |     args.push_back("--runtime-arg"); | 
 | 73 |     args.push_back("-Xnorelocate"); | 
 | 74 |  | 
 | 75 |     args.insert(args.end(), extra_args.begin(), extra_args.end()); | 
 | 76 |  | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 77 |     int status = Dex2Oat(args, error_msg); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 78 |     if (oat_file != nullptr) { | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 79 |       CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file"; | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 80 |     } | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 81 |     return status; | 
 | 82 |   } | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 83 |  | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 84 |   void GenerateOdexForTest(const std::string& dex_location, | 
 | 85 |                            const std::string& odex_location, | 
 | 86 |                            CompilerFilter::Filter filter, | 
 | 87 |                            const std::vector<std::string>& extra_args = {}, | 
 | 88 |                            bool expect_success = true, | 
 | 89 |                            bool use_fd = false) { | 
 | 90 |     std::string error_msg; | 
 | 91 |     int status = GenerateOdexForTestWithStatus(dex_location, | 
 | 92 |                                                odex_location, | 
 | 93 |                                                filter, | 
 | 94 |                                                &error_msg, | 
 | 95 |                                                extra_args, | 
 | 96 |                                                use_fd); | 
 | 97 |     bool success = (status == 0); | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 98 |     if (expect_success) { | 
| Andreas Gampe | 2e8a256 | 2017-01-18 20:39:02 -0800 | [diff] [blame] | 99 |       ASSERT_TRUE(success) << error_msg << std::endl << output_; | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 100 |  | 
 | 101 |       // Verify the odex file was generated as expected. | 
 | 102 |       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), | 
 | 103 |                                                        odex_location.c_str(), | 
 | 104 |                                                        nullptr, | 
 | 105 |                                                        nullptr, | 
 | 106 |                                                        false, | 
 | 107 |                                                        /*low_4gb*/false, | 
 | 108 |                                                        dex_location.c_str(), | 
 | 109 |                                                        &error_msg)); | 
 | 110 |       ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; | 
 | 111 |  | 
 | 112 |       CheckFilter(filter, odex_file->GetCompilerFilter()); | 
 | 113 |     } else { | 
 | 114 |       ASSERT_FALSE(success) << output_; | 
 | 115 |  | 
 | 116 |       error_msg_ = error_msg; | 
 | 117 |  | 
 | 118 |       // Verify there's no loadable odex file. | 
 | 119 |       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), | 
 | 120 |                                                        odex_location.c_str(), | 
 | 121 |                                                        nullptr, | 
 | 122 |                                                        nullptr, | 
 | 123 |                                                        false, | 
 | 124 |                                                        /*low_4gb*/false, | 
 | 125 |                                                        dex_location.c_str(), | 
 | 126 |                                                        &error_msg)); | 
 | 127 |       ASSERT_TRUE(odex_file.get() == nullptr); | 
 | 128 |     } | 
 | 129 |   } | 
 | 130 |  | 
 | 131 |   // Check the input compiler filter against the generated oat file's filter. Mayb be overridden | 
 | 132 |   // in subclasses when equality is not expected. | 
 | 133 |   virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) { | 
 | 134 |     EXPECT_EQ(expected, actual); | 
 | 135 |   } | 
 | 136 |  | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 137 |   int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 138 |     Runtime* runtime = Runtime::Current(); | 
 | 139 |  | 
 | 140 |     const std::vector<gc::space::ImageSpace*>& image_spaces = | 
 | 141 |         runtime->GetHeap()->GetBootImageSpaces(); | 
 | 142 |     if (image_spaces.empty()) { | 
 | 143 |       *error_msg = "No image location found for Dex2Oat."; | 
 | 144 |       return false; | 
 | 145 |     } | 
 | 146 |     std::string image_location = image_spaces[0]->GetImageLocation(); | 
 | 147 |  | 
 | 148 |     std::vector<std::string> argv; | 
 | 149 |     argv.push_back(runtime->GetCompilerExecutable()); | 
 | 150 |     argv.push_back("--runtime-arg"); | 
 | 151 |     argv.push_back("-classpath"); | 
 | 152 |     argv.push_back("--runtime-arg"); | 
 | 153 |     std::string class_path = runtime->GetClassPathString(); | 
 | 154 |     if (class_path == "") { | 
 | 155 |       class_path = OatFile::kSpecialSharedLibrary; | 
 | 156 |     } | 
 | 157 |     argv.push_back(class_path); | 
| Nicolas Geoffray | 433b79a | 2017-01-30 20:54:45 +0000 | [diff] [blame] | 158 |     if (runtime->IsJavaDebuggable()) { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 159 |       argv.push_back("--debuggable"); | 
 | 160 |     } | 
 | 161 |     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); | 
 | 162 |  | 
 | 163 |     if (!runtime->IsVerificationEnabled()) { | 
 | 164 |       argv.push_back("--compiler-filter=verify-none"); | 
 | 165 |     } | 
 | 166 |  | 
 | 167 |     if (runtime->MustRelocateIfPossible()) { | 
 | 168 |       argv.push_back("--runtime-arg"); | 
 | 169 |       argv.push_back("-Xrelocate"); | 
 | 170 |     } else { | 
 | 171 |       argv.push_back("--runtime-arg"); | 
 | 172 |       argv.push_back("-Xnorelocate"); | 
 | 173 |     } | 
 | 174 |  | 
 | 175 |     if (!kIsTargetBuild) { | 
 | 176 |       argv.push_back("--host"); | 
 | 177 |     } | 
 | 178 |  | 
 | 179 |     argv.push_back("--boot-image=" + image_location); | 
 | 180 |  | 
 | 181 |     std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); | 
 | 182 |     argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); | 
 | 183 |  | 
 | 184 |     argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end()); | 
 | 185 |  | 
 | 186 |     // We must set --android-root. | 
 | 187 |     const char* android_root = getenv("ANDROID_ROOT"); | 
 | 188 |     CHECK(android_root != nullptr); | 
 | 189 |     argv.push_back("--android-root=" + std::string(android_root)); | 
 | 190 |  | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 191 |     int link[2]; | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 192 |  | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 193 |     if (pipe(link) == -1) { | 
 | 194 |       return false; | 
 | 195 |     } | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 196 |  | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 197 |     pid_t pid = fork(); | 
 | 198 |     if (pid == -1) { | 
 | 199 |       return false; | 
 | 200 |     } | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 201 |  | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 202 |     if (pid == 0) { | 
 | 203 |       // We need dex2oat to actually log things. | 
 | 204 |       setenv("ANDROID_LOG_TAGS", "*:d", 1); | 
 | 205 |       dup2(link[1], STDERR_FILENO); | 
 | 206 |       close(link[0]); | 
 | 207 |       close(link[1]); | 
 | 208 |       std::vector<const char*> c_args; | 
 | 209 |       for (const std::string& str : argv) { | 
 | 210 |         c_args.push_back(str.c_str()); | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 211 |       } | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 212 |       c_args.push_back(nullptr); | 
 | 213 |       execv(c_args[0], const_cast<char* const*>(c_args.data())); | 
 | 214 |       exit(1); | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 215 |       UNREACHABLE(); | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 216 |     } else { | 
 | 217 |       close(link[1]); | 
 | 218 |       char buffer[128]; | 
 | 219 |       memset(buffer, 0, 128); | 
 | 220 |       ssize_t bytes_read = 0; | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 221 |  | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 222 |       while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) { | 
 | 223 |         output_ += std::string(buffer, bytes_read); | 
 | 224 |       } | 
 | 225 |       close(link[0]); | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 226 |       int status = -1; | 
| Nicolas Geoffray | 56fe0f0 | 2016-06-30 15:07:46 +0100 | [diff] [blame] | 227 |       if (waitpid(pid, &status, 0) != -1) { | 
 | 228 |         success_ = (status == 0); | 
 | 229 |       } | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 230 |       return status; | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 231 |     } | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 232 |   } | 
 | 233 |  | 
 | 234 |   std::string output_ = ""; | 
 | 235 |   std::string error_msg_ = ""; | 
 | 236 |   bool success_ = false; | 
 | 237 | }; | 
 | 238 |  | 
 | 239 | class Dex2oatSwapTest : public Dex2oatTest { | 
 | 240 |  protected: | 
 | 241 |   void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) { | 
 | 242 |     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; | 
 | 243 |     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; | 
 | 244 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 245 |     Copy(GetTestDexFileName(), dex_location); | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 246 |  | 
 | 247 |     std::vector<std::string> copy(extra_args); | 
 | 248 |  | 
 | 249 |     std::unique_ptr<ScratchFile> sf; | 
 | 250 |     if (use_fd) { | 
 | 251 |       sf.reset(new ScratchFile()); | 
| Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 252 |       copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd())); | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 253 |     } else { | 
 | 254 |       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap"; | 
 | 255 |       copy.push_back("--swap-file=" + swap_location); | 
 | 256 |     } | 
 | 257 |     GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy); | 
 | 258 |  | 
 | 259 |     CheckValidity(); | 
 | 260 |     ASSERT_TRUE(success_); | 
 | 261 |     CheckResult(expect_use); | 
 | 262 |   } | 
 | 263 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 264 |   virtual std::string GetTestDexFileName() { | 
| Vladimir Marko | 1535770 | 2017-02-09 10:37:31 +0000 | [diff] [blame] | 265 |     return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps"); | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 266 |   } | 
 | 267 |  | 
 | 268 |   virtual void CheckResult(bool expect_use) { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 269 |     if (kIsTargetBuild) { | 
 | 270 |       CheckTargetResult(expect_use); | 
 | 271 |     } else { | 
 | 272 |       CheckHostResult(expect_use); | 
 | 273 |     } | 
 | 274 |   } | 
 | 275 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 276 |   virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 277 |     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do | 
 | 278 |     //       something for variants with file descriptor where we can control the lifetime of | 
 | 279 |     //       the swap file and thus take a look at it. | 
 | 280 |   } | 
 | 281 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 282 |   virtual void CheckHostResult(bool expect_use) { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 283 |     if (!kIsTargetBuild) { | 
 | 284 |       if (expect_use) { | 
 | 285 |         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos) | 
 | 286 |             << output_; | 
 | 287 |       } else { | 
 | 288 |         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos) | 
 | 289 |             << output_; | 
 | 290 |       } | 
 | 291 |     } | 
 | 292 |   } | 
 | 293 |  | 
 | 294 |   // Check whether the dex2oat run was really successful. | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 295 |   virtual void CheckValidity() { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 296 |     if (kIsTargetBuild) { | 
 | 297 |       CheckTargetValidity(); | 
 | 298 |     } else { | 
 | 299 |       CheckHostValidity(); | 
 | 300 |     } | 
 | 301 |   } | 
 | 302 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 303 |   virtual void CheckTargetValidity() { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 304 |     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do | 
 | 305 |     //       something for variants with file descriptor where we can control the lifetime of | 
 | 306 |     //       the swap file and thus take a look at it. | 
 | 307 |   } | 
 | 308 |  | 
 | 309 |   // On the host, we can get the dex2oat output. Here, look for "dex2oat took." | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 310 |   virtual void CheckHostValidity() { | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 311 |     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; | 
 | 312 |   } | 
 | 313 | }; | 
 | 314 |  | 
 | 315 | TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) { | 
 | 316 |   RunTest(false /* use_fd */, false /* expect_use */); | 
 | 317 |   RunTest(true /* use_fd */, false /* expect_use */); | 
 | 318 | } | 
 | 319 |  | 
 | 320 | TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) { | 
 | 321 |   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); | 
 | 322 |   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); | 
 | 323 | } | 
 | 324 |  | 
 | 325 | TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) { | 
 | 326 |   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); | 
 | 327 |   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); | 
 | 328 | } | 
 | 329 |  | 
 | 330 | TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) { | 
 | 331 |   RunTest(false /* use_fd */, | 
 | 332 |           true /* expect_use */, | 
 | 333 |           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); | 
 | 334 |   RunTest(true /* use_fd */, | 
 | 335 |           true /* expect_use */, | 
 | 336 |           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); | 
 | 337 | } | 
 | 338 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 339 | class Dex2oatSwapUseTest : public Dex2oatSwapTest { | 
 | 340 |  protected: | 
 | 341 |   void CheckHostResult(bool expect_use) OVERRIDE { | 
 | 342 |     if (!kIsTargetBuild) { | 
 | 343 |       if (expect_use) { | 
 | 344 |         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos) | 
 | 345 |             << output_; | 
 | 346 |       } else { | 
 | 347 |         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos) | 
 | 348 |             << output_; | 
 | 349 |       } | 
 | 350 |     } | 
 | 351 |   } | 
 | 352 |  | 
 | 353 |   std::string GetTestDexFileName() OVERRIDE { | 
 | 354 |     // Use Statics as it has a handful of functions. | 
 | 355 |     return CommonRuntimeTest::GetTestDexFileName("Statics"); | 
 | 356 |   } | 
 | 357 |  | 
 | 358 |   void GrabResult1() { | 
 | 359 |     if (!kIsTargetBuild) { | 
 | 360 |       native_alloc_1_ = ParseNativeAlloc(); | 
 | 361 |       swap_1_ = ParseSwap(false /* expected */); | 
 | 362 |     } else { | 
 | 363 |       native_alloc_1_ = std::numeric_limits<size_t>::max(); | 
 | 364 |       swap_1_ = 0; | 
 | 365 |     } | 
 | 366 |   } | 
 | 367 |  | 
 | 368 |   void GrabResult2() { | 
 | 369 |     if (!kIsTargetBuild) { | 
 | 370 |       native_alloc_2_ = ParseNativeAlloc(); | 
 | 371 |       swap_2_ = ParseSwap(true /* expected */); | 
 | 372 |     } else { | 
 | 373 |       native_alloc_2_ = 0; | 
 | 374 |       swap_2_ = std::numeric_limits<size_t>::max(); | 
 | 375 |     } | 
 | 376 |   } | 
 | 377 |  | 
 | 378 |  private: | 
 | 379 |   size_t ParseNativeAlloc() { | 
 | 380 |     std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)"); | 
 | 381 |     std::smatch native_alloc_match; | 
 | 382 |     bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex); | 
 | 383 |     if (!found) { | 
 | 384 |       EXPECT_TRUE(found); | 
 | 385 |       return 0; | 
 | 386 |     } | 
 | 387 |     if (native_alloc_match.size() != 2U) { | 
 | 388 |       EXPECT_EQ(native_alloc_match.size(), 2U); | 
 | 389 |       return 0; | 
 | 390 |     } | 
 | 391 |  | 
 | 392 |     std::istringstream stream(native_alloc_match[1].str()); | 
 | 393 |     size_t value; | 
 | 394 |     stream >> value; | 
 | 395 |  | 
 | 396 |     return value; | 
 | 397 |   } | 
 | 398 |  | 
 | 399 |   size_t ParseSwap(bool expected) { | 
 | 400 |     std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)"); | 
 | 401 |     std::smatch swap_match; | 
 | 402 |     bool found = std::regex_search(output_, swap_match, swap_regex); | 
 | 403 |     if (found != expected) { | 
 | 404 |       EXPECT_EQ(expected, found); | 
 | 405 |       return 0; | 
 | 406 |     } | 
 | 407 |  | 
 | 408 |     if (!found) { | 
 | 409 |       return 0; | 
 | 410 |     } | 
 | 411 |  | 
 | 412 |     if (swap_match.size() != 2U) { | 
 | 413 |       EXPECT_EQ(swap_match.size(), 2U); | 
 | 414 |       return 0; | 
 | 415 |     } | 
 | 416 |  | 
 | 417 |     std::istringstream stream(swap_match[1].str()); | 
 | 418 |     size_t value; | 
 | 419 |     stream >> value; | 
 | 420 |  | 
 | 421 |     return value; | 
 | 422 |   } | 
 | 423 |  | 
 | 424 |  protected: | 
 | 425 |   size_t native_alloc_1_; | 
 | 426 |   size_t native_alloc_2_; | 
 | 427 |  | 
 | 428 |   size_t swap_1_; | 
 | 429 |   size_t swap_2_; | 
 | 430 | }; | 
 | 431 |  | 
 | 432 | TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) { | 
| Vladimir Marko | 57070da | 2017-02-14 16:16:30 +0000 | [diff] [blame] | 433 |   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not | 
| Roland Levillain | 19772bf | 2017-02-16 11:28:10 +0000 | [diff] [blame] | 434 |   // hold true on some x86 systems; disable this test while we | 
 | 435 |   // investigate (b/29259363). | 
 | 436 |   TEST_DISABLED_FOR_X86(); | 
| Vladimir Marko | 57070da | 2017-02-14 16:16:30 +0000 | [diff] [blame] | 437 |  | 
| Andreas Gampe | 7adeda8 | 2016-07-25 08:27:35 -0700 | [diff] [blame] | 438 |   RunTest(false /* use_fd */, | 
 | 439 |           false /* expect_use */); | 
 | 440 |   GrabResult1(); | 
 | 441 |   std::string output_1 = output_; | 
 | 442 |  | 
 | 443 |   output_ = ""; | 
 | 444 |  | 
 | 445 |   RunTest(false /* use_fd */, | 
 | 446 |           true /* expect_use */, | 
 | 447 |           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); | 
 | 448 |   GrabResult2(); | 
 | 449 |   std::string output_2 = output_; | 
 | 450 |  | 
 | 451 |   if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) { | 
 | 452 |     EXPECT_LT(native_alloc_2_, native_alloc_1_); | 
 | 453 |     EXPECT_LT(swap_1_, swap_2_); | 
 | 454 |  | 
 | 455 |     LOG(ERROR) << output_1; | 
 | 456 |     LOG(ERROR) << output_2; | 
 | 457 |   } | 
 | 458 | } | 
 | 459 |  | 
| Andreas Gampe | 67f0282 | 2016-06-24 21:05:23 -0700 | [diff] [blame] | 460 | class Dex2oatVeryLargeTest : public Dex2oatTest { | 
 | 461 |  protected: | 
 | 462 |   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED, | 
 | 463 |                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE { | 
 | 464 |     // Ignore, we'll do our own checks. | 
 | 465 |   } | 
 | 466 |  | 
 | 467 |   void RunTest(CompilerFilter::Filter filter, | 
 | 468 |                bool expect_large, | 
 | 469 |                const std::vector<std::string>& extra_args = {}) { | 
 | 470 |     std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; | 
 | 471 |     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; | 
 | 472 |  | 
 | 473 |     Copy(GetDexSrc1(), dex_location); | 
 | 474 |  | 
| Andreas Gampe | ca620d7 | 2016-11-08 08:09:33 -0800 | [diff] [blame] | 475 |     GenerateOdexForTest(dex_location, odex_location, filter, extra_args); | 
| Andreas Gampe | 67f0282 | 2016-06-24 21:05:23 -0700 | [diff] [blame] | 476 |  | 
 | 477 |     CheckValidity(); | 
 | 478 |     ASSERT_TRUE(success_); | 
 | 479 |     CheckResult(dex_location, odex_location, filter, expect_large); | 
 | 480 |   } | 
 | 481 |  | 
 | 482 |   void CheckResult(const std::string& dex_location, | 
 | 483 |                    const std::string& odex_location, | 
 | 484 |                    CompilerFilter::Filter filter, | 
 | 485 |                    bool expect_large) { | 
 | 486 |     // Host/target independent checks. | 
 | 487 |     std::string error_msg; | 
 | 488 |     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), | 
 | 489 |                                                      odex_location.c_str(), | 
 | 490 |                                                      nullptr, | 
 | 491 |                                                      nullptr, | 
 | 492 |                                                      false, | 
 | 493 |                                                      /*low_4gb*/false, | 
 | 494 |                                                      dex_location.c_str(), | 
 | 495 |                                                      &error_msg)); | 
 | 496 |     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; | 
 | 497 |     if (expect_large) { | 
 | 498 |       // Note: we cannot check the following: | 
 | 499 |       //   EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, | 
 | 500 |       //                                          odex_file->GetCompilerFilter())); | 
 | 501 |       // The reason is that the filter override currently happens when the dex files are | 
 | 502 |       // loaded in dex2oat, which is after the oat file has been started. Thus, the header | 
 | 503 |       // store cannot be changed, and the original filter is set in stone. | 
 | 504 |  | 
 | 505 |       for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { | 
 | 506 |         std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); | 
 | 507 |         ASSERT_TRUE(dex_file != nullptr); | 
 | 508 |         uint32_t class_def_count = dex_file->NumClassDefs(); | 
 | 509 |         ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max()); | 
 | 510 |         for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { | 
 | 511 |           OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); | 
 | 512 |           EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled); | 
 | 513 |         } | 
 | 514 |       } | 
 | 515 |  | 
 | 516 |       // If the input filter was "below," it should have been used. | 
 | 517 |       if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) { | 
 | 518 |         EXPECT_EQ(odex_file->GetCompilerFilter(), filter); | 
 | 519 |       } | 
 | 520 |     } else { | 
 | 521 |       EXPECT_EQ(odex_file->GetCompilerFilter(), filter); | 
 | 522 |     } | 
 | 523 |  | 
 | 524 |     // Host/target dependent checks. | 
 | 525 |     if (kIsTargetBuild) { | 
 | 526 |       CheckTargetResult(expect_large); | 
 | 527 |     } else { | 
 | 528 |       CheckHostResult(expect_large); | 
 | 529 |     } | 
 | 530 |   } | 
 | 531 |  | 
 | 532 |   void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) { | 
 | 533 |     // TODO: Ignore for now. May do something for fd things. | 
 | 534 |   } | 
 | 535 |  | 
 | 536 |   void CheckHostResult(bool expect_large) { | 
 | 537 |     if (!kIsTargetBuild) { | 
 | 538 |       if (expect_large) { | 
 | 539 |         EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."), | 
 | 540 |                   std::string::npos) | 
 | 541 |             << output_; | 
 | 542 |       } else { | 
 | 543 |         EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."), | 
 | 544 |                   std::string::npos) | 
 | 545 |             << output_; | 
 | 546 |       } | 
 | 547 |     } | 
 | 548 |   } | 
 | 549 |  | 
 | 550 |   // Check whether the dex2oat run was really successful. | 
 | 551 |   void CheckValidity() { | 
 | 552 |     if (kIsTargetBuild) { | 
 | 553 |       CheckTargetValidity(); | 
 | 554 |     } else { | 
 | 555 |       CheckHostValidity(); | 
 | 556 |     } | 
 | 557 |   } | 
 | 558 |  | 
 | 559 |   void CheckTargetValidity() { | 
 | 560 |     // TODO: Ignore for now. | 
 | 561 |   } | 
 | 562 |  | 
 | 563 |   // On the host, we can get the dex2oat output. Here, look for "dex2oat took." | 
 | 564 |   void CheckHostValidity() { | 
 | 565 |     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; | 
 | 566 |   } | 
 | 567 | }; | 
 | 568 |  | 
 | 569 | TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) { | 
 | 570 |   RunTest(CompilerFilter::kVerifyNone, false); | 
 | 571 |   RunTest(CompilerFilter::kVerifyAtRuntime, false); | 
 | 572 |   RunTest(CompilerFilter::kInterpretOnly, false); | 
 | 573 |   RunTest(CompilerFilter::kSpeed, false); | 
 | 574 |  | 
 | 575 |   RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" }); | 
 | 576 |   RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" }); | 
 | 577 |   RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" }); | 
 | 578 |   RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" }); | 
 | 579 | } | 
 | 580 |  | 
 | 581 | TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) { | 
 | 582 |   RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" }); | 
 | 583 |   RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" }); | 
 | 584 |   RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" }); | 
 | 585 |   RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" }); | 
 | 586 | } | 
 | 587 |  | 
| Mathieu Chartier | 97ab5e3 | 2017-02-22 13:35:44 -0800 | [diff] [blame] | 588 | // Regressin test for b/35665292. | 
 | 589 | TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) { | 
 | 590 |   // Test that dex2oat doesn't crash with speed-profile but no input profile. | 
 | 591 |   RunTest(CompilerFilter::kSpeedProfile, false); | 
 | 592 | } | 
 | 593 |  | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 594 | class Dex2oatLayoutTest : public Dex2oatTest { | 
 | 595 |  protected: | 
 | 596 |   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED, | 
 | 597 |                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE { | 
 | 598 |     // Ignore, we'll do our own checks. | 
 | 599 |   } | 
 | 600 |  | 
| Jeff Hao | 41fba6a | 2016-11-28 11:53:33 -0800 | [diff] [blame] | 601 |   // Emits a profile with a single dex file with the given location and a single class index of 1. | 
 | 602 |   void GenerateProfile(const std::string& test_profile, | 
 | 603 |                        const std::string& dex_location, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 604 |                        size_t num_classes, | 
| Jeff Hao | 41fba6a | 2016-11-28 11:53:33 -0800 | [diff] [blame] | 605 |                        uint32_t checksum) { | 
 | 606 |     int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); | 
 | 607 |     CHECK_GE(profile_test_fd, 0); | 
 | 608 |  | 
 | 609 |     ProfileCompilationInfo info; | 
 | 610 |     std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 611 |     for (size_t i = 0; i < num_classes; ++i) { | 
 | 612 |       info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i)); | 
 | 613 |     } | 
| Jeff Hao | 41fba6a | 2016-11-28 11:53:33 -0800 | [diff] [blame] | 614 |     bool result = info.Save(profile_test_fd); | 
 | 615 |     close(profile_test_fd); | 
 | 616 |     ASSERT_TRUE(result); | 
 | 617 |   } | 
 | 618 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 619 |   void CompileProfileOdex(const std::string& dex_location, | 
 | 620 |                           const std::string& odex_location, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 621 |                           const std::string& app_image_file_name, | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 622 |                           bool use_fd, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 623 |                           size_t num_profile_classes, | 
| Nicolas Geoffray | 97fa992 | 2017-03-09 13:13:25 +0000 | [diff] [blame] | 624 |                           const std::vector<std::string>& extra_args = {}, | 
 | 625 |                           bool expect_success = true) { | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 626 |     const std::string profile_location = GetScratchDir() + "/primary.prof"; | 
| Jeff Hao | 41fba6a | 2016-11-28 11:53:33 -0800 | [diff] [blame] | 627 |     const char* location = dex_location.c_str(); | 
 | 628 |     std::string error_msg; | 
 | 629 |     std::vector<std::unique_ptr<const DexFile>> dex_files; | 
 | 630 |     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files)); | 
 | 631 |     EXPECT_EQ(dex_files.size(), 1U); | 
 | 632 |     std::unique_ptr<const DexFile>& dex_file = dex_files[0]; | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 633 |     GenerateProfile(profile_location, | 
 | 634 |                     dex_location, | 
 | 635 |                     num_profile_classes, | 
 | 636 |                     dex_file->GetLocationChecksum()); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 637 |     std::vector<std::string> copy(extra_args); | 
 | 638 |     copy.push_back("--profile-file=" + profile_location); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 639 |     std::unique_ptr<File> app_image_file; | 
 | 640 |     if (!app_image_file_name.empty()) { | 
 | 641 |       if (use_fd) { | 
 | 642 |         app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str())); | 
 | 643 |         copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd())); | 
 | 644 |       } else { | 
 | 645 |         copy.push_back("--app-image-file=" + app_image_file_name); | 
 | 646 |       } | 
 | 647 |     } | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 648 |     GenerateOdexForTest(dex_location, | 
 | 649 |                         odex_location, | 
 | 650 |                         CompilerFilter::kSpeedProfile, | 
 | 651 |                         copy, | 
| Nicolas Geoffray | 97fa992 | 2017-03-09 13:13:25 +0000 | [diff] [blame] | 652 |                         expect_success, | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 653 |                         use_fd); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 654 |     if (app_image_file != nullptr) { | 
 | 655 |       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file"; | 
 | 656 |     } | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 657 |   } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 658 |  | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 659 |   uint64_t GetImageSize(const std::string& image_file_name) { | 
 | 660 |     EXPECT_FALSE(image_file_name.empty()); | 
 | 661 |     std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str())); | 
 | 662 |     CHECK(file != nullptr); | 
 | 663 |     ImageHeader image_header; | 
 | 664 |     const bool success = file->ReadFully(&image_header, sizeof(image_header)); | 
 | 665 |     CHECK(success); | 
 | 666 |     CHECK(image_header.IsValid()); | 
 | 667 |     ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_); | 
 | 668 |     return image_header.GetImageSize(); | 
 | 669 |   } | 
 | 670 |  | 
 | 671 |   void RunTest(bool app_image) { | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 672 |     std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; | 
 | 673 |     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 674 |     std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): ""; | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 675 |     Copy(GetDexSrc2(), dex_location); | 
 | 676 |  | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 677 |     uint64_t image_file_empty_profile = 0; | 
 | 678 |     if (app_image) { | 
 | 679 |       CompileProfileOdex(dex_location, | 
 | 680 |                          odex_location, | 
 | 681 |                          app_image_file, | 
 | 682 |                          /* use_fd */ false, | 
 | 683 |                          /* num_profile_classes */ 0); | 
 | 684 |       CheckValidity(); | 
 | 685 |       ASSERT_TRUE(success_); | 
 | 686 |       // Don't check the result since CheckResult relies on the class being in the profile. | 
 | 687 |       image_file_empty_profile = GetImageSize(app_image_file); | 
 | 688 |       EXPECT_GT(image_file_empty_profile, 0u); | 
 | 689 |     } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 690 |  | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 691 |     // Small profile. | 
 | 692 |     CompileProfileOdex(dex_location, | 
 | 693 |                        odex_location, | 
 | 694 |                        app_image_file, | 
 | 695 |                        /* use_fd */ false, | 
 | 696 |                        /* num_profile_classes */ 1); | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 697 |     CheckValidity(); | 
 | 698 |     ASSERT_TRUE(success_); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 699 |     CheckResult(dex_location, odex_location, app_image_file); | 
 | 700 |  | 
 | 701 |     if (app_image) { | 
 | 702 |       // Test that the profile made a difference by adding more classes. | 
 | 703 |       const uint64_t image_file_small_profile = GetImageSize(app_image_file); | 
 | 704 |       CHECK_LT(image_file_empty_profile, image_file_small_profile); | 
 | 705 |     } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 706 |   } | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 707 |  | 
 | 708 |   void RunTestVDex() { | 
 | 709 |     std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; | 
 | 710 |     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; | 
 | 711 |     std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex"; | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 712 |     std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art"; | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 713 |     Copy(GetDexSrc2(), dex_location); | 
 | 714 |  | 
 | 715 |     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); | 
 | 716 |     CHECK(vdex_file1 != nullptr) << vdex_location; | 
 | 717 |     ScratchFile vdex_file2; | 
 | 718 |     { | 
 | 719 |       std::string input_vdex = "--input-vdex-fd=-1"; | 
 | 720 |       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); | 
 | 721 |       CompileProfileOdex(dex_location, | 
 | 722 |                          odex_location, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 723 |                          app_image_file_name, | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 724 |                          /* use_fd */ true, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 725 |                          /* num_profile_classes */ 1, | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 726 |                          { input_vdex, output_vdex }); | 
 | 727 |       EXPECT_GT(vdex_file1->GetLength(), 0u); | 
 | 728 |     } | 
 | 729 |     { | 
| Nicolas Geoffray | 97fa992 | 2017-03-09 13:13:25 +0000 | [diff] [blame] | 730 |       // Test that vdex and dexlayout fail gracefully. | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 731 |       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); | 
 | 732 |       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd()); | 
 | 733 |       CompileProfileOdex(dex_location, | 
 | 734 |                          odex_location, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 735 |                          app_image_file_name, | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 736 |                          /* use_fd */ true, | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 737 |                          /* num_profile_classes */ 1, | 
| Nicolas Geoffray | 97fa992 | 2017-03-09 13:13:25 +0000 | [diff] [blame] | 738 |                          { input_vdex, output_vdex }, | 
 | 739 |                          /* expect_success */ false); | 
 | 740 |       EXPECT_EQ(vdex_file2.GetFile()->GetLength(), 0u); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 741 |     } | 
 | 742 |     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; | 
 | 743 |     CheckValidity(); | 
| Nicolas Geoffray | 97fa992 | 2017-03-09 13:13:25 +0000 | [diff] [blame] | 744 |     ASSERT_FALSE(success_); | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 745 |   } | 
 | 746 |  | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 747 |   void CheckResult(const std::string& dex_location, | 
 | 748 |                    const std::string& odex_location, | 
 | 749 |                    const std::string& app_image_file_name) { | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 750 |     // Host/target independent checks. | 
 | 751 |     std::string error_msg; | 
 | 752 |     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), | 
 | 753 |                                                      odex_location.c_str(), | 
 | 754 |                                                      nullptr, | 
 | 755 |                                                      nullptr, | 
 | 756 |                                                      false, | 
 | 757 |                                                      /*low_4gb*/false, | 
 | 758 |                                                      dex_location.c_str(), | 
 | 759 |                                                      &error_msg)); | 
 | 760 |     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; | 
 | 761 |  | 
| Jeff Hao | 042e898 | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 762 |     const char* location = dex_location.c_str(); | 
 | 763 |     std::vector<std::unique_ptr<const DexFile>> dex_files; | 
 | 764 |     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files)); | 
 | 765 |     EXPECT_EQ(dex_files.size(), 1U); | 
 | 766 |     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0]; | 
 | 767 |  | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 768 |     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { | 
| Jeff Hao | 042e898 | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 769 |       std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg); | 
 | 770 |       ASSERT_TRUE(new_dex_file != nullptr); | 
 | 771 |       uint32_t class_def_count = new_dex_file->NumClassDefs(); | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 772 |       ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max()); | 
| Jeff Hao | 042e898 | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 773 |       ASSERT_GE(class_def_count, 2U); | 
 | 774 |  | 
 | 775 |       // The new layout swaps the classes at indexes 0 and 1. | 
 | 776 |       std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_); | 
 | 777 |       std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_); | 
 | 778 |       std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_); | 
 | 779 |       std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_); | 
 | 780 |       EXPECT_EQ(old_class0, new_class1); | 
 | 781 |       EXPECT_EQ(old_class1, new_class0); | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 782 |     } | 
 | 783 |  | 
| Jeff Hao | c155b05 | 2017-01-17 17:43:29 -0800 | [diff] [blame] | 784 |     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile); | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 785 |  | 
 | 786 |     if (!app_image_file_name.empty()) { | 
 | 787 |       // Go peek at the image header to make sure it was large enough to contain the class. | 
 | 788 |       std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str())); | 
 | 789 |       ImageHeader image_header; | 
 | 790 |       bool success = file->ReadFully(&image_header, sizeof(image_header)); | 
 | 791 |       ASSERT_TRUE(success); | 
 | 792 |       ASSERT_TRUE(image_header.IsValid()); | 
 | 793 |       EXPECT_GT(image_header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u); | 
 | 794 |     } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 795 |   } | 
 | 796 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 797 |   // Check whether the dex2oat run was really successful. | 
 | 798 |   void CheckValidity() { | 
 | 799 |     if (kIsTargetBuild) { | 
 | 800 |       CheckTargetValidity(); | 
 | 801 |     } else { | 
 | 802 |       CheckHostValidity(); | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 803 |     } | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 804 |   } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 805 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 806 |   void CheckTargetValidity() { | 
 | 807 |     // TODO: Ignore for now. | 
 | 808 |   } | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 809 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 810 |   // On the host, we can get the dex2oat output. Here, look for "dex2oat took." | 
 | 811 |   void CheckHostValidity() { | 
 | 812 |     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; | 
 | 813 |   } | 
 | 814 | }; | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 815 |  | 
 | 816 | TEST_F(Dex2oatLayoutTest, TestLayout) { | 
| Mathieu Chartier | 046854b | 2017-03-01 17:16:22 -0800 | [diff] [blame] | 817 |   RunTest(/* app-image */ false); | 
 | 818 | } | 
 | 819 |  | 
 | 820 | TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) { | 
 | 821 |   RunTest(/* app-image */ true); | 
| Jeff Hao | 608f2ce | 2016-10-19 11:17:11 -0700 | [diff] [blame] | 822 | } | 
 | 823 |  | 
| Mathieu Chartier | 8bc343b | 2017-03-01 15:20:30 -0800 | [diff] [blame] | 824 | TEST_F(Dex2oatLayoutTest, TestVdexLayout) { | 
 | 825 |   RunTestVDex(); | 
 | 826 | } | 
 | 827 |  | 
| Andreas Gampe | 2e8a256 | 2017-01-18 20:39:02 -0800 | [diff] [blame] | 828 | class Dex2oatWatchdogTest : public Dex2oatTest { | 
 | 829 |  protected: | 
 | 830 |   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) { | 
 | 831 |     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; | 
 | 832 |     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; | 
 | 833 |  | 
 | 834 |     Copy(GetTestDexFileName(), dex_location); | 
 | 835 |  | 
 | 836 |     std::vector<std::string> copy(extra_args); | 
 | 837 |  | 
 | 838 |     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap"; | 
 | 839 |     copy.push_back("--swap-file=" + swap_location); | 
 | 840 |     GenerateOdexForTest(dex_location, | 
 | 841 |                         odex_location, | 
 | 842 |                         CompilerFilter::kSpeed, | 
 | 843 |                         copy, | 
 | 844 |                         expect_success); | 
 | 845 |   } | 
 | 846 |  | 
 | 847 |   std::string GetTestDexFileName() { | 
 | 848 |     return GetDexSrc1(); | 
 | 849 |   } | 
 | 850 | }; | 
 | 851 |  | 
 | 852 | TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) { | 
 | 853 |   // Check with default. | 
 | 854 |   RunTest(true); | 
 | 855 |  | 
 | 856 |   // Check with ten minutes. | 
 | 857 |   RunTest(true, { "--watchdog-timeout=600000" }); | 
 | 858 | } | 
 | 859 |  | 
 | 860 | TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) { | 
 | 861 |   // Check with ten milliseconds. | 
 | 862 |   RunTest(false, { "--watchdog-timeout=10" }); | 
 | 863 | } | 
 | 864 |  | 
| Andreas Gampe | f788297 | 2017-03-20 16:35:24 -0700 | [diff] [blame] | 865 | class Dex2oatReturnCodeTest : public Dex2oatTest { | 
 | 866 |  protected: | 
 | 867 |   int RunTest(const std::vector<std::string>& extra_args = {}) { | 
 | 868 |     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; | 
 | 869 |     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; | 
 | 870 |  | 
 | 871 |     Copy(GetTestDexFileName(), dex_location); | 
 | 872 |  | 
 | 873 |     std::string error_msg; | 
 | 874 |     return GenerateOdexForTestWithStatus(dex_location, | 
 | 875 |                                          odex_location, | 
 | 876 |                                          CompilerFilter::kSpeed, | 
 | 877 |                                          &error_msg, | 
 | 878 |                                          extra_args); | 
 | 879 |   } | 
 | 880 |  | 
 | 881 |   std::string GetTestDexFileName() { | 
 | 882 |     return GetDexSrc1(); | 
 | 883 |   } | 
 | 884 | }; | 
 | 885 |  | 
 | 886 | TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) { | 
 | 887 |   int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" }); | 
 | 888 |   EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_; | 
 | 889 | } | 
 | 890 |  | 
| Andreas Gampe | e1459ae | 2016-06-29 09:36:30 -0700 | [diff] [blame] | 891 | }  // namespace art |