OSDN Git Service

am c1bfaa22: Remove dex2oat watchdog warning
[android-x86/art.git] / dex2oat / dex2oat.cc
index 833a678..7d48e45 100644 (file)
@@ -264,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();
   }
 
 
@@ -353,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,
@@ -387,6 +387,7 @@ class Dex2Oat {
                                                               instruction_set_features_,
                                                               image,
                                                               image_classes.release(),
+                                                              compiled_classes.release(),
                                                               thread_count_,
                                                               dump_stats,
                                                               dump_passes,
@@ -426,19 +427,25 @@ 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.
-    oat_file->Flush();
+    if (oat_file->Flush() != 0) {
+      PLOG(ERROR) << "Failed flushing oat file " << oat_file->GetPath();
+      oat_file->Erase();
+      return nullptr;
+    }
 
     if (!driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) {
       t2.NewTiming("Patching ELF");
       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;
       }
     }
@@ -464,15 +471,23 @@ class Dex2Oat {
       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;
-    }
+
     // 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;
       }
     }
@@ -593,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 { \
@@ -656,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)));
@@ -704,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
@@ -723,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
@@ -840,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;
@@ -939,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;
@@ -1120,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");
   }
@@ -1238,9 +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();
-    oat_file->SetLength(0);
+    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;
@@ -1248,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;
   }
 
@@ -1261,6 +1274,7 @@ static int dex2oat(int argc, char** argv) {
     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));
@@ -1292,6 +1306,7 @@ static int dex2oat(int argc, char** argv) {
                        thread_count)) {
     LOG(ERROR) << "Failed to create dex2oat";
     timings.EndTiming();
+    oat_file->Erase();
     return EXIT_FAILURE;
   }
   std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
@@ -1321,11 +1336,34 @@ static int dex2oat(int argc, char** argv) {
       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()) {
@@ -1340,12 +1378,14 @@ static int dex2oat(int argc, char** argv) {
         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();
@@ -1354,6 +1394,7 @@ static int dex2oat(int argc, char** argv) {
       if (failure_count > 0) {
         LOG(ERROR) << "Failed to open some dex files: " << failure_count;
         timings.EndTiming();
+        oat_file->Erase();
         return EXIT_FAILURE;
       }
     }
@@ -1369,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;
       }
     }
@@ -1427,6 +1471,7 @@ static int dex2oat(int argc, char** argv) {
                                                                         bitcode_filename,
                                                                         image,
                                                                         image_classes,
+                                                                        compiled_classes,
                                                                         dump_stats,
                                                                         dump_passes,
                                                                         timings,
@@ -1439,8 +1484,16 @@ static int dex2oat(int argc, char** argv) {
     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.
   //
@@ -1520,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]);
@@ -1537,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();
 
@@ -1563,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);
   }