OSDN Git Service

am c1bfaa22: Remove dex2oat watchdog warning
[android-x86/art.git] / dex2oat / dex2oat.cc
index bd39e67..7d48e45 100644 (file)
@@ -155,6 +155,9 @@ static void Usage(const char* fmt, ...) {
   UsageError("      Example: --instruction-set-features=div");
   UsageError("      Default: default");
   UsageError("");
+  UsageError("  --compile-pic: Force indirect use of code, methods, and classes");
+  UsageError("      Default: disabled");
+  UsageError("");
   UsageError("  --compiler-backend=(Quick|Optimizing|Portable): select compiler backend");
   UsageError("      set.");
   UsageError("      Example: --compiler-backend=Portable");
@@ -261,12 +264,11 @@ class Dex2Oat {
 
   ~Dex2Oat() {
     delete runtime_;
-    LogCompletionTime();
   }
 
-  void LogCompletionTime() {
+  void LogCompletionTime(const CompilerDriver* compiler) {
     LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
-              << " (threads: " << thread_count_ << ")";
+              << " (threads: " << thread_count_ << ") " << compiler->GetMemoryUsageString();
   }
 
 
@@ -350,6 +352,7 @@ class Dex2Oat {
                                       const std::string& bitcode_filename,
                                       bool image,
                                       std::unique_ptr<std::set<std::string>>& image_classes,
+                                      std::unique_ptr<std::set<std::string>>& compiled_classes,
                                       bool dump_stats,
                                       bool dump_passes,
                                       TimingLogger& timings,
@@ -384,6 +387,7 @@ class Dex2Oat {
                                                               instruction_set_features_,
                                                               image,
                                                               image_classes.release(),
+                                                              compiled_classes.release(),
                                                               thread_count_,
                                                               dump_stats,
                                                               dump_passes,
@@ -423,6 +427,16 @@ class Dex2Oat {
     t2.NewTiming("Writing ELF");
     if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
       LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
+      oat_file->Erase();
+      return nullptr;
+    }
+
+    // Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view
+    // of the file already made it there and won't be re-ordered with writes from PatchOat or
+    // image patching.
+    if (oat_file->Flush() != 0) {
+      PLOG(ERROR) << "Failed flushing oat file " << oat_file->GetPath();
+      oat_file->Erase();
       return nullptr;
     }
 
@@ -431,6 +445,7 @@ class Dex2Oat {
       std::string error_msg;
       if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) {
         LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() << ": " << error_msg;
+        oat_file->Erase();
         return nullptr;
       }
     }
@@ -448,22 +463,35 @@ class Dex2Oat {
     {
       // ImageWriter is scoped so it can free memory before doing FixupElf
       ImageWriter image_writer(compiler);
-      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
+      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location,
+                              compiler_options_->GetCompilePic())) {
         LOG(ERROR) << "Failed to create image file " << image_filename;
         return false;
       }
       oat_data_begin = image_writer.GetOatDataBegin();
     }
 
-    std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
-    if (oat_file.get() == nullptr) {
-      PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
-      return false;
-    }
-    if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
-      LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
-      return false;
+
+    // Do not fix up the ELF file if we are --compile-pic
+    if (!compiler_options_->GetCompilePic()) {
+      std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
+      if (oat_file.get() == nullptr) {
+        PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
+        return false;
+      }
+
+      if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
+        LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
+        oat_file->Erase();
+        return false;
+      }
+
+      if (oat_file->FlushCloseOrErase() != 0) {
+        PLOG(ERROR) << "Failed to flush and close patched oat file " << oat_filename;
+        return false;
+      }
     }
+
     return true;
   }
 
@@ -580,7 +608,7 @@ static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
 // during development when fatal aborts lead to a cascade of failures
 // that result in a deadlock.
 class WatchDog {
-// WatchDog defines its own CHECK_PTHREAD_CALL to avoid using Log which uses locks
+// WatchDog defines its own CHECK_PTHREAD_CALL to avoid using LOG which uses locks
 #undef CHECK_PTHREAD_CALL
 #define CHECK_WATCH_DOG_PTHREAD_CALL(call, args, what) \
   do { \
@@ -643,41 +671,23 @@ class WatchDog {
             message.c_str());
   }
 
-  static void Warn(const std::string& message) {
-    Message('W', message);
-  }
-
   static void Fatal(const std::string& message) {
     Message('F', message);
     exit(1);
   }
 
   void Wait() {
-    bool warning = true;
-    CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
     // TODO: tune the multiplier for GC verification, the following is just to make the timeout
     //       large.
     int64_t multiplier = kVerifyObjectSupport > kVerifyObjectModeFast ? 100 : 1;
-    timespec warning_ts;
-    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogWarningSeconds * 1000, 0, &warning_ts);
     timespec timeout_ts;
     InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
     const char* reason = "dex2oat watch dog thread waiting";
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
     while (!shutting_down_) {
-      int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_,
-                                                         warning ? &warning_ts
-                                                                 : &timeout_ts));
+      int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_, &timeout_ts));
       if (rc == ETIMEDOUT) {
-        std::string message(StringPrintf("dex2oat did not finish after %d seconds",
-                                         warning ? kWatchDogWarningSeconds
-                                                 : kWatchDogTimeoutSeconds));
-        if (warning) {
-          Warn(message.c_str());
-          warning = false;
-        } else {
-          Fatal(message.c_str());
-        }
+        Fatal(StringPrintf("dex2oat did not finish after %d seconds", kWatchDogTimeoutSeconds));
       } else if (rc != 0) {
         std::string message(StringPrintf("pthread_cond_timedwait failed: %s",
                                          strerror(errno)));
@@ -691,13 +701,9 @@ class WatchDog {
   // Debug builds are slower so they have larger timeouts.
   static const unsigned int kSlowdownFactor = kIsDebugBuild ? 5U : 1U;
 #if ART_USE_PORTABLE_COMPILER
-  // 2 minutes scaled by kSlowdownFactor.
-  static const unsigned int kWatchDogWarningSeconds = kSlowdownFactor * 2 * 60;
   // 30 minutes scaled by kSlowdownFactor.
   static const unsigned int kWatchDogTimeoutSeconds = kSlowdownFactor * 30 * 60;
 #else
-  // 1 minutes scaled by kSlowdownFactor.
-  static const unsigned int kWatchDogWarningSeconds = kSlowdownFactor * 1 * 60;
   // 6 minutes scaled by kSlowdownFactor.
   static const unsigned int kWatchDogTimeoutSeconds = kSlowdownFactor * 6 * 60;
 #endif
@@ -710,7 +716,6 @@ class WatchDog {
   pthread_attr_t attr_;
   pthread_t pthread_;
 };
-const unsigned int WatchDog::kWatchDogWarningSeconds;
 const unsigned int WatchDog::kWatchDogTimeoutSeconds;
 
 // Given a set of instruction features from the build, parse it.  The
@@ -777,7 +782,7 @@ void ParseDouble(const std::string& option, char after_char,
   *parsed_value = value;
 }
 
-static int dex2oat(int argc, char** argv) {
+static void b13564922() {
 #if defined(__linux__) && defined(__arm__)
   int major, minor;
   struct utsname uts;
@@ -795,6 +800,10 @@ static int dex2oat(int argc, char** argv) {
     }
   }
 #endif
+}
+
+static int dex2oat(int argc, char** argv) {
+  b13564922();
 
   original_argc = argc;
   original_argv = argv;
@@ -823,6 +832,8 @@ static int dex2oat(int argc, char** argv) {
   std::string bitcode_filename;
   const char* image_classes_zip_filename = nullptr;
   const char* image_classes_filename = nullptr;
+  const char* compiled_classes_zip_filename = nullptr;
+  const char* compiled_classes_filename = nullptr;
   std::string image_filename;
   std::string boot_image_filename;
   uintptr_t image_base = 0;
@@ -833,6 +844,7 @@ static int dex2oat(int argc, char** argv) {
       ? Compiler::kPortable
       : Compiler::kQuick;
   const char* compiler_filter_string = nullptr;
+  bool compile_pic = false;
   int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
   int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
   int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
@@ -921,6 +933,10 @@ static int dex2oat(int argc, char** argv) {
       image_classes_filename = option.substr(strlen("--image-classes=")).data();
     } else if (option.starts_with("--image-classes-zip=")) {
       image_classes_zip_filename = option.substr(strlen("--image-classes-zip=")).data();
+    } else if (option.starts_with("--compiled-classes=")) {
+      compiled_classes_filename = option.substr(strlen("--compiled-classes=")).data();
+    } else if (option.starts_with("--compiled-classes-zip=")) {
+      compiled_classes_zip_filename = option.substr(strlen("--compiled-classes-zip=")).data();
     } else if (option.starts_with("--base=")) {
       const char* image_base_str = option.substr(strlen("--base=")).data();
       char* end;
@@ -959,6 +975,8 @@ static int dex2oat(int argc, char** argv) {
       }
     } else if (option.starts_with("--compiler-filter=")) {
       compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
+    } else if (option == "--compile-pic") {
+      compile_pic = true;
     } else if (option.starts_with("--huge-method-max=")) {
       const char* threshold = option.substr(strlen("--huge-method-max=")).data();
       if (!ParseInt(threshold, &huge_method_threshold)) {
@@ -1019,6 +1037,7 @@ static int dex2oat(int argc, char** argv) {
       include_debug_symbols = true;
     } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") {
       include_debug_symbols = false;
+      generate_gdb_information = false;  // Depends on debug symbols, see above.
     } else if (option.starts_with("--profile-file=")) {
       profile_file = option.substr(strlen("--profile-file=")).data();
       VLOG(compiler) << "dex2oat: profile file is " << profile_file;
@@ -1099,6 +1118,18 @@ static int dex2oat(int argc, char** argv) {
     Usage("--image-classes-zip should be used with --image-classes");
   }
 
+  if (compiled_classes_filename != nullptr && !image) {
+    Usage("--compiled-classes should only be used with --image");
+  }
+
+  if (compiled_classes_filename != nullptr && !boot_image_option.empty()) {
+    Usage("--compiled-classes should not be used with --boot-image");
+  }
+
+  if (compiled_classes_zip_filename != nullptr && compiled_classes_filename == nullptr) {
+    Usage("--compiled-classes-zip should be used with --compiled-classes");
+  }
+
   if (dex_filenames.empty() && zip_fd == -1) {
     Usage("Input must be supplied with either --dex-file or --zip-fd");
   }
@@ -1197,7 +1228,8 @@ static int dex2oat(int argc, char** argv) {
                                                                         include_debug_symbols,
                                                                         implicit_null_checks,
                                                                         implicit_so_checks,
-                                                                        implicit_suspend_checks
+                                                                        implicit_suspend_checks,
+                                                                        compile_pic
 #ifdef ART_SEA_IR_MODE
                                                                         , compiler_options.sea_ir_ =
                                                                               true;
@@ -1216,8 +1248,11 @@ static int dex2oat(int argc, char** argv) {
       oat_location = oat_filename;
     }
   } else {
-    oat_file.reset(new File(oat_fd, oat_location));
+    oat_file.reset(new File(oat_fd, oat_location, true));
     oat_file->DisableAutoClose();
+    if (oat_file->SetLength(0)) {  // Only warn for truncation error.
+      PLOG(WARNING) << "Truncating oat file " << oat_location << " failed.";
+    }
   }
   if (oat_file.get() == nullptr) {
     PLOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -1225,6 +1260,7 @@ static int dex2oat(int argc, char** argv) {
   }
   if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
     PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location;
+    oat_file->Erase();
     return EXIT_FAILURE;
   }
 
@@ -1233,10 +1269,12 @@ static int dex2oat(int argc, char** argv) {
 
   RuntimeOptions runtime_options;
   std::vector<const DexFile*> boot_class_path;
+  art::MemMap::Init();  // For ZipEntry::ExtractToMemMap.
   if (boot_image_option.empty()) {
     size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
     if (failure_count > 0) {
       LOG(ERROR) << "Failed to open some dex files: " << failure_count;
+      oat_file->Erase();
       return EXIT_FAILURE;
     }
     runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
@@ -1267,6 +1305,8 @@ static int dex2oat(int argc, char** argv) {
                        &method_inliner_map,
                        thread_count)) {
     LOG(ERROR) << "Failed to create dex2oat";
+    timings.EndTiming();
+    oat_file->Erase();
     return EXIT_FAILURE;
   }
   std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
@@ -1295,11 +1335,35 @@ static int dex2oat(int argc, char** argv) {
     if (image_classes.get() == nullptr) {
       LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
           "': " << error_msg;
+      timings.EndTiming();
+      oat_file->Erase();
       return EXIT_FAILURE;
     }
   } else if (image) {
     image_classes.reset(new std::set<std::string>);
   }
+  // If --compiled-classes was specified, calculate the full list of classes to compile in the
+  // image.
+  std::unique_ptr<std::set<std::string>> compiled_classes(nullptr);
+  if (compiled_classes_filename != nullptr) {
+    std::string error_msg;
+    if (compiled_classes_zip_filename != nullptr) {
+      compiled_classes.reset(dex2oat->ReadImageClassesFromZip(compiled_classes_zip_filename,
+                                                              compiled_classes_filename,
+                                                              &error_msg));
+    } else {
+      compiled_classes.reset(dex2oat->ReadImageClassesFromFile(compiled_classes_filename));
+    }
+    if (compiled_classes.get() == nullptr) {
+      LOG(ERROR) << "Failed to create list of compiled classes from '" << compiled_classes_filename
+                 << "': " << error_msg;
+      timings.EndTiming();
+      oat_file->Erase();
+      return EXIT_FAILURE;
+    }
+  } else if (image) {
+    compiled_classes.reset(nullptr);  // By default compile everything.
+  }
 
   std::vector<const DexFile*> dex_files;
   if (boot_image_option.empty()) {
@@ -1313,11 +1377,15 @@ static int dex2oat(int argc, char** argv) {
       if (zip_archive.get() == nullptr) {
         LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
             << error_msg;
+        timings.EndTiming();
+        oat_file->Erase();
         return EXIT_FAILURE;
       }
       if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) {
         LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
             << "': " << error_msg;
+        timings.EndTiming();
+        oat_file->Erase();
         return EXIT_FAILURE;
       }
       ATRACE_END();
@@ -1325,6 +1393,8 @@ static int dex2oat(int argc, char** argv) {
       size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
       if (failure_count > 0) {
         LOG(ERROR) << "Failed to open some dex files: " << failure_count;
+        timings.EndTiming();
+        oat_file->Erase();
         return EXIT_FAILURE;
       }
     }
@@ -1340,7 +1410,10 @@ static int dex2oat(int argc, char** argv) {
                         << ". Try: adb shell chmod 777 /data/local/tmp";
             continue;
         }
-        tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
+        // This is just dumping files for debugging. Ignore errors, and leave remnants.
+        UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()));
+        UNUSED(tmp_file->Flush());
+        UNUSED(tmp_file->Close());
         LOG(INFO) << "Wrote input to " << tmp_file_name;
       }
     }
@@ -1374,17 +1447,20 @@ static int dex2oat(int argc, char** argv) {
       new SafeMap<std::string, std::string>());
 
   // Insert some compiler things.
-  std::ostringstream oss;
-  for (int i = 0; i < argc; ++i) {
-    if (i > 0) {
-      oss << ' ';
+  {
+    std::ostringstream oss;
+    for (int i = 0; i < argc; ++i) {
+      if (i > 0) {
+        oss << ' ';
+      }
+      oss << argv[i];
     }
-    oss << argv[i];
+    key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
+    oss.str("");  // Reset.
+    oss << kRuntimeISA;
+    key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());
+    key_value_store->Put(OatHeader::kPicKey, compile_pic ? "true" : "false");
   }
-  key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
-  oss.str("");  // Reset.
-  oss << kRuntimeISA;
-  key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());
 
   std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
                                                                         android_root,
@@ -1395,6 +1471,7 @@ static int dex2oat(int argc, char** argv) {
                                                                         bitcode_filename,
                                                                         image,
                                                                         image_classes,
+                                                                        compiled_classes,
                                                                         dump_stats,
                                                                         dump_passes,
                                                                         timings,
@@ -1403,11 +1480,20 @@ static int dex2oat(int argc, char** argv) {
                                                                         key_value_store.get()));
   if (compiler.get() == nullptr) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
+    timings.EndTiming();
     return EXIT_FAILURE;
   }
 
-  VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location;
+  if (!kUsePortableCompiler) {
+    if (oat_file->FlushCloseOrErase() != 0) {
+      PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location;
+      timings.EndTiming();
+      return EXIT_FAILURE;
+    }
+    oat_file.reset();
+  }
 
+  VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location;
   // Notes on the interleaving of creating the image and oat file to
   // ensure the references between the two are correct.
   //
@@ -1466,6 +1552,7 @@ static int dex2oat(int argc, char** argv) {
                                                            oat_location,
                                                            *compiler.get());
     if (!image_creation_success) {
+      timings.EndTiming();
       return EXIT_FAILURE;
     }
     VLOG(compiler) << "Image written successfully: " << image_filename;
@@ -1486,8 +1573,14 @@ static int dex2oat(int argc, char** argv) {
   // We need to strip after image creation because FixupElf needs to use .strtab.
   if (oat_unstripped != oat_stripped) {
     TimingLogger::ScopedTiming t("dex2oat OatFile copy", &timings);
-    oat_file.reset();
-     std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
+    if (kUsePortableCompiler) {
+      if (oat_file->FlushCloseOrErase() != 0) {
+        PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location;
+        return EXIT_FAILURE;
+      }
+      oat_file.reset();
+    }
+    std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
     std::unique_ptr<File> out(OS::CreateEmptyFile(oat_stripped.c_str()));
     size_t buffer_size = 8192;
     std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_size]);
@@ -1503,22 +1596,34 @@ static int dex2oat(int argc, char** argv) {
     VLOG(compiler) << "Oat file copied successfully (stripped): " << oat_stripped;
   }
 
-#if ART_USE_PORTABLE_COMPILER  // We currently only generate symbols on Portable
-  if (!compiler_options.GetIncludeDebugSymbols()) {
-    timings.NewSplit("dex2oat ElfStripper");
-    // Strip unneeded sections for target
-    off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
-    CHECK_EQ(0, seek_actual);
-    std::string error_msg;
-    CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg;
+  if (kUsePortableCompiler) {
+    if (!compiler_options->GetIncludeDebugSymbols()) {
+      timings.NewTiming("dex2oat ElfStripper");
+      // Strip unneeded sections for target
+      off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
+      CHECK_EQ(0, seek_actual);
+      std::string error_msg;
+      CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg;
 
 
-    // We wrote the oat file successfully, and want to keep it.
-    VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location;
-  } else {
-    VLOG(compiler) << "Oat file written successfully without stripping: " << oat_location;
+      // We wrote the oat file successfully, and want to keep it.
+      VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location;
+    } else {
+      VLOG(compiler) << "Oat file written successfully without stripping: " << oat_location;
+    }
+    if (oat_file->FlushCloseOrErase() != 0) {
+      LOG(ERROR) << "Failed to flush and close oat file: " << oat_location;
+      return EXIT_FAILURE;
+    }
+    oat_file.reset(nullptr);
+  }
+
+  if (oat_file.get() != nullptr) {
+    if (oat_file->FlushCloseOrErase() != 0) {
+      PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location << "/" << oat_filename;
+      return EXIT_FAILURE;
+    }
   }
-#endif  // ART_USE_PORTABLE_COMPILER
 
   timings.EndTiming();
 
@@ -1529,10 +1634,10 @@ static int dex2oat(int argc, char** argv) {
     LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
   }
 
+  dex2oat->LogCompletionTime(compiler.get());
   // Everything was successfully written, do an explicit exit here to avoid running Runtime
   // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
   if (!kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
-    dex2oat->LogCompletionTime();
     exit(EXIT_SUCCESS);
   }