OSDN Git Service

Ensure the profile is written to disk at shutdown
authorCalin Juravle <calin@google.com>
Wed, 15 Mar 2017 01:45:55 +0000 (18:45 -0700)
committerCalin Juravle <calin@google.com>
Thu, 16 Mar 2017 00:19:45 +0000 (17:19 -0700)
Force profile saving during shutdown. It will make benchmark automation
much easier.

Test: test-art-host
Bug: 26719109
Change-Id: I529aa1a7b1192c53960fdb4ddc13b10b99e846cc

runtime/jit/profile_saver.cc
runtime/jit/profile_saver.h
runtime/runtime.cc

index 2724b00..e2bd1cb 100644 (file)
@@ -121,15 +121,16 @@ void ProfileSaver::Run() {
       break;
     }
 
-    uint16_t new_methods = 0;
+    uint16_t number_of_new_methods = 0;
     uint64_t start_work = NanoTime();
-    bool profile_saved_to_disk = ProcessProfilingInfo(&new_methods);
+    bool profile_saved_to_disk = ProcessProfilingInfo(/*force_save*/false, &number_of_new_methods);
     // Update the notification counter based on result. Note that there might be contention on this
     // but we don't care about to be 100% precise.
     if (!profile_saved_to_disk) {
       // If we didn't save to disk it may be because we didn't have enough new methods.
-      // Set the jit activity notifications to new_methods so we can wake up earlier if needed.
-      jit_activity_notifications_ = new_methods;
+      // Set the jit activity notifications to number_of_new_methods so we can wake up earlier
+      // if needed.
+      jit_activity_notifications_ = number_of_new_methods;
     }
     total_ns_of_work_ += NanoTime() - start_work;
   }
@@ -256,7 +257,7 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
       total_number_of_profile_entries_cached);
 }
 
-bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
+bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number_of_new_methods) {
   ScopedTrace trace(__PRETTY_FUNCTION__);
   SafeMap<std::string, std::set<std::string>> tracked_locations;
   {
@@ -267,10 +268,16 @@ bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
 
   bool profile_file_saved = false;
   uint64_t total_number_of_profile_entries_cached = 0;
-  *new_methods = 0;
+  if (number_of_new_methods != nullptr) {
+    *number_of_new_methods = 0;
+  }
 
   for (const auto& it : tracked_locations) {
-    if (ShuttingDown(Thread::Current())) {
+    if (!force_save && ShuttingDown(Thread::Current())) {
+      // The ProfileSaver is in shutdown mode, meaning a stop request was made and
+      // we need to exit cleanly (by waiting for the saver thread to finish). Unless
+      // we have a request for a forced save, do not do any processing so that we
+      // speed up the exit.
       return true;
     }
     const std::string& filename = it.first;
@@ -292,7 +299,8 @@ bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
         cached_profile->GetNumberOfResolvedClasses() -
         static_cast<int64_t>(cached_info->last_save_number_of_classes);
 
-    if (delta_number_of_methods < options_.GetMinMethodsToSave() &&
+    if (!force_save &&
+        delta_number_of_methods < options_.GetMinMethodsToSave() &&
         delta_number_of_classes < options_.GetMinClassesToSave()) {
       VLOG(profiler) << "Not enough information to save to: " << filename
           << " Number of methods: " << delta_number_of_methods
@@ -300,7 +308,10 @@ bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
       total_number_of_skipped_writes_++;
       continue;
     }
-    *new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods), *new_methods);
+    if (number_of_new_methods != nullptr) {
+      *number_of_new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods),
+                                        *number_of_new_methods);
+    }
     uint64_t bytes_written;
     // Force the save. In case the profile data is corrupted or the the profile
     // has the wrong version this will "fix" the file to the correct format.
@@ -454,6 +465,9 @@ void ProfileSaver::Stop(bool dump_info) {
   // Wait for the saver thread to stop.
   CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
 
+  // Force save everything before destroying the instance.
+  instance_->ProcessProfilingInfo(/*force_save*/true, /*number_of_new_methods*/nullptr);
+
   {
     MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
     instance_ = nullptr;
@@ -516,8 +530,7 @@ void ProfileSaver::ForceProcessProfiles() {
   // but we only use this in testing when we now this won't happen.
   // Refactor the way we handle the instance so that we don't end up in this situation.
   if (saver != nullptr) {
-    uint16_t new_methods;
-    saver->ProcessProfilingInfo(&new_methods);
+    saver->ProcessProfilingInfo(/*force_save*/true, /*number_of_new_methods*/nullptr);
   }
 }
 
index 8e0682d..4dd8e60 100644 (file)
@@ -79,9 +79,14 @@ class ProfileSaver {
 
   // The run loop for the saver.
   void Run() REQUIRES(!Locks::profiler_lock_, !wait_lock_);
+
   // Processes the existing profiling info from the jit code cache and returns
   // true if it needed to be saved to disk.
-  bool ProcessProfilingInfo(uint16_t* new_methods)
+  // If number_of_new_methods is not null, after the call it will contain the number of new methods
+  // written to disk.
+  // If force_save is true, the saver will ignore any constraints which limit IO (e.g. will write
+  // the profile to disk even if it's just one new method).
+  bool ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number_of_new_methods)
     REQUIRES(!Locks::profiler_lock_)
     REQUIRES(!Locks::mutator_lock_);
 
index 9fd2c88..2a4ae74 100644 (file)
@@ -286,6 +286,13 @@ Runtime::~Runtime() {
     LOG(WARNING) << "Current thread not detached in Runtime shutdown";
   }
 
+  if (jit_ != nullptr) {
+    // Stop the profile saver thread before marking the runtime as shutting down.
+    // The saver will try to dump the profiles before being sopped and that
+    // requires holding the mutator lock.
+    jit_->StopProfileSaver();
+  }
+
   {
     ScopedTrace trace2("Wait for shutdown cond");
     MutexLock mu(self, *Locks::runtime_shutdown_lock_);
@@ -327,8 +334,6 @@ Runtime::~Runtime() {
     // Delete thread pool before the thread list since we don't want to wait forever on the
     // JIT compiler threads.
     jit_->DeleteThreadPool();
-    // Similarly, stop the profile saver thread before deleting the thread list.
-    jit_->StopProfileSaver();
   }
 
   // TODO Maybe do some locking.