Merge "Save profile information in a separate thread." am: 58b2329de7
am: da6e49016d
* commit 'da6e49016dc37704f45b13217a8c6f8e726ab8e1':
Save profile information in a separate thread.
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 6264578..de4314c 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -108,6 +108,7 @@
jit/jit_instrumentation.cc \
jit/offline_profiling_info.cc \
jit/profiling_info.cc \
+ jit/profile_saver.cc \
lambda/art_lambda_method.cc \
lambda/box_table.cc \
lambda/closure.cc \
diff --git a/runtime/atomic.h b/runtime/atomic.h
index 87de506..0faa3c6 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -199,6 +199,11 @@
return this->load(std::memory_order_relaxed);
}
+ // Load from memory with acquire ordering.
+ T LoadAcquire() const {
+ return this->load(std::memory_order_acquire);
+ }
+
// Word tearing allowed, but may race.
// TODO: Optimize?
// There has been some discussion of eventually disallowing word
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index b2fc74d..ab70f4c 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -26,6 +26,7 @@
#include "jit_instrumentation.h"
#include "oat_file_manager.h"
#include "offline_profiling_info.h"
+#include "profile_saver.h"
#include "runtime.h"
#include "runtime_options.h"
#include "utils.h"
@@ -66,7 +67,7 @@
Jit::Jit()
: jit_library_handle_(nullptr), jit_compiler_handle_(nullptr), jit_load_(nullptr),
jit_compile_method_(nullptr), dump_info_on_shutdown_(false),
- cumulative_timings_("JIT timings") {
+ cumulative_timings_("JIT timings"), save_profiling_info_(false) {
}
Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
@@ -80,14 +81,12 @@
if (jit->GetCodeCache() == nullptr) {
return nullptr;
}
- jit->offline_profile_info_.reset(nullptr);
- if (options->GetSaveProfilingInfo()) {
- jit->offline_profile_info_.reset(new OfflineProfilingInfo());
- }
+ jit->save_profiling_info_ = options->GetSaveProfilingInfo();
LOG(INFO) << "JIT created with initial_capacity="
<< PrettySize(options->GetCodeCacheInitialCapacity())
<< ", max_capacity=" << PrettySize(options->GetCodeCacheMaxCapacity())
- << ", compile_threshold=" << options->GetCompileThreshold();
+ << ", compile_threshold=" << options->GetCompileThreshold()
+ << ", save_profiling_info=" << options->GetSaveProfilingInfo();
return jit.release();
}
@@ -173,25 +172,21 @@
}
}
-void Jit::SaveProfilingInfo(const std::string& filename) {
- if (offline_profile_info_ == nullptr) {
- return;
+void Jit::StartProfileSaver(const std::string& filename,
+ const std::vector<std::string>& code_paths) {
+ if (save_profiling_info_) {
+ ProfileSaver::Start(filename, code_cache_.get(), code_paths);
}
- uint64_t last_update_ns = code_cache_->GetLastUpdateTimeNs();
- if (offline_profile_info_->NeedsSaving(last_update_ns)) {
- VLOG(profiler) << "Initiate save profiling information to: " << filename;
- std::set<ArtMethod*> methods;
- {
- ScopedObjectAccess soa(Thread::Current());
- code_cache_->GetCompiledArtMethods(offline_profile_info_->GetTrackedDexLocations(), methods);
- }
- offline_profile_info_->SaveProfilingInfo(filename, last_update_ns, methods);
- } else {
- VLOG(profiler) << "No need to save profiling information to: " << filename;
+}
+
+void Jit::StopProfileSaver() {
+ if (save_profiling_info_ && ProfileSaver::IsStarted()) {
+ ProfileSaver::Stop();
}
}
Jit::~Jit() {
+ DCHECK(!save_profiling_info_ || !ProfileSaver::IsStarted());
if (dump_info_on_shutdown_) {
DumpInfo(LOG(INFO));
}
@@ -210,12 +205,5 @@
new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
}
-void Jit::SetDexLocationsForProfiling(const std::vector<std::string>& dex_base_locations) {
- if (offline_profile_info_ == nullptr) {
- return;
- }
- offline_profile_info_->SetTrackedDexLocations(dex_base_locations);
-}
-
} // namespace jit
} // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 7a2db31..0edce2f 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -72,8 +72,8 @@
return instrumentation_cache_.get();
}
- void SetDexLocationsForProfiling(const std::vector<std::string>& dex_locations);
- void SaveProfilingInfo(const std::string& filename);
+ void StartProfileSaver(const std::string& filename, const std::vector<std::string>& code_paths);
+ void StopProfileSaver();
void DumpForSigQuit(std::ostream& os) {
DumpInfo(os);
@@ -98,7 +98,8 @@
std::unique_ptr<jit::JitCodeCache> code_cache_;
CompilerCallbacks* compiler_callbacks_; // Owned by the jit compiler.
- std::unique_ptr<OfflineProfilingInfo> offline_profile_info_;
+ bool save_profiling_info_;
+
DISALLOW_COPY_AND_ASSIGN(Jit);
};
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 033a8f0..08eac0e 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -317,7 +317,7 @@
// code.
GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(code_ptr));
}
- last_update_time_ns_ = NanoTime();
+ last_update_time_ns_.StoreRelease(NanoTime());
VLOG(jit)
<< "JIT added "
<< PrettyMethod(method) << "@" << method
@@ -689,18 +689,17 @@
}
void JitCodeCache::GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
- std::set<ArtMethod*>& methods) {
+ std::vector<ArtMethod*>& methods) {
MutexLock mu(Thread::Current(), lock_);
for (auto it : method_code_map_) {
if (ContainsElement(dex_base_locations, it.second->GetDexFile()->GetBaseLocation())) {
- methods.insert(it.second);
+ methods.push_back(it.second);
}
}
}
-uint64_t JitCodeCache::GetLastUpdateTimeNs() {
- MutexLock mu(Thread::Current(), lock_);
- return last_update_time_ns_;
+uint64_t JitCodeCache::GetLastUpdateTimeNs() const {
+ return last_update_time_ns_.LoadAcquire();
}
bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self) {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 0ceb17a..1c842e4 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -148,11 +148,11 @@
// Adds to `methods` all the compiled ArtMethods which are part of any of the given dex locations.
void GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
- std::set<ArtMethod*>& methods)
+ std::vector<ArtMethod*>& methods)
REQUIRES(!lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
- uint64_t GetLastUpdateTimeNs() REQUIRES(!lock_);
+ uint64_t GetLastUpdateTimeNs() const;
size_t GetCurrentCapacity() REQUIRES(!lock_) {
MutexLock lock(Thread::Current(), lock_);
@@ -249,7 +249,8 @@
bool has_done_one_collection_ GUARDED_BY(lock_);
// Last time the the code_cache was updated.
- uint64_t last_update_time_ns_ GUARDED_BY(lock_);
+ // It is atomic to avoid locking when reading it.
+ Atomic<uint64_t> last_update_time_ns_;
DISALLOW_IMPLICIT_CONSTRUCTORS(JitCodeCache);
};
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index 511b53d..5dc0e45 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -17,7 +17,7 @@
#include "offline_profiling_info.h"
#include <fstream>
-#include <set>
+#include <vector>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/uio.h>
@@ -30,34 +30,8 @@
namespace art {
-// An arbitrary value to throttle save requests. Set to 500ms for now.
-static constexpr const uint64_t kMilisecondsToNano = 1000000;
-static constexpr const uint64_t kMinimumTimeBetweenSavesNs = 500 * kMilisecondsToNano;
-
-void OfflineProfilingInfo::SetTrackedDexLocations(
- const std::vector<std::string>& dex_base_locations) {
- tracked_dex_base_locations_.clear();
- tracked_dex_base_locations_.insert(dex_base_locations.begin(), dex_base_locations.end());
- VLOG(profiler) << "Tracking dex locations: " << Join(dex_base_locations, ':');
-}
-
-const std::set<const std::string>& OfflineProfilingInfo::GetTrackedDexLocations() const {
- return tracked_dex_base_locations_;
-}
-
-bool OfflineProfilingInfo::NeedsSaving(uint64_t last_update_time_ns) const {
- return !tracked_dex_base_locations_.empty() &&
- (last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs);
-}
-
void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename,
- uint64_t last_update_time_ns,
- const std::set<ArtMethod*>& methods) {
- if (!NeedsSaving(last_update_time_ns)) {
- VLOG(profiler) << "No need to saved profile info to " << filename;
- return;
- }
-
+ const std::vector<ArtMethod*>& methods) {
if (methods.empty()) {
VLOG(profiler) << "No info to save to " << filename;
return;
@@ -67,7 +41,6 @@
{
ScopedObjectAccess soa(Thread::Current());
for (auto it = methods.begin(); it != methods.end(); it++) {
- DCHECK(ContainsElement(tracked_dex_base_locations_, (*it)->GetDexFile()->GetBaseLocation()));
AddMethodInfo(*it, &info);
}
}
@@ -75,9 +48,8 @@
// This doesn't need locking because we are trying to lock the file for exclusive
// access and fail immediately if we can't.
if (Serialize(filename, info)) {
- last_update_time_ns_.StoreRelaxed(last_update_time_ns);
- VLOG(profiler) << "Successfully saved profile info to "
- << filename << " with time stamp: " << last_update_time_ns;
+ VLOG(profiler) << "Successfully saved profile info to " << filename
+ << " Size: " << GetFileSizeBytes(filename);
}
}
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index 8c5ffbe..32d4c5b 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_JIT_OFFLINE_PROFILING_INFO_H_
#include <set>
+#include <vector>
#include "atomic.h"
#include "dex_file.h"
@@ -36,12 +37,7 @@
*/
class OfflineProfilingInfo {
public:
- bool NeedsSaving(uint64_t last_update_time_ns) const;
- void SaveProfilingInfo(const std::string& filename,
- uint64_t last_update_time_ns,
- const std::set<ArtMethod*>& methods);
- void SetTrackedDexLocations(const std::vector<std::string>& dex_locations);
- const std::set<const std::string>& GetTrackedDexLocations() const;
+ void SaveProfilingInfo(const std::string& filename, const std::vector<ArtMethod*>& methods);
private:
// Map identifying the location of the profiled methods.
@@ -51,12 +47,6 @@
void AddMethodInfo(ArtMethod* method, DexFileToMethodsMap* info)
SHARED_REQUIRES(Locks::mutator_lock_);
bool Serialize(const std::string& filename, const DexFileToMethodsMap& info) const;
-
- // TODO(calin): Verify if Atomic is really needed (are we sure to be called from a
- // single thread?)
- Atomic<uint64_t> last_update_time_ns_;
-
- std::set<const std::string> tracked_dex_base_locations_;
};
/**
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
new file mode 100644
index 0000000..0278138
--- /dev/null
+++ b/runtime/jit/profile_saver.cc
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "profile_saver.h"
+
+#include "art_method-inl.h"
+#include "scoped_thread_state_change.h"
+#include "oat_file_manager.h"
+
+namespace art {
+
+// An arbitrary value to throttle save requests. Set to 500ms for now.
+static constexpr const uint64_t kMilisecondsToNano = 1000000;
+static constexpr const uint64_t kMinimumTimeBetweenCodeCacheUpdatesNs = 500 * kMilisecondsToNano;
+
+// TODO: read the constants from ProfileOptions,
+// Add a random delay each time we go to sleep so that we don't hammer the CPU
+// with all profile savers running at the same time.
+static constexpr const uint64_t kRandomDelayMaxMs = 10 * 1000; // 10 seconds
+static constexpr const uint64_t kMaxBackoffMs = 4 * 60 * 1000; // 4 minutes
+static constexpr const uint64_t kSavePeriodMs = 4 * 1000; // 4 seconds
+static constexpr const double kBackoffCoef = 1.5;
+
+static constexpr const uint32_t kMinimumNrOrMethodsToSave = 10;
+
+ProfileSaver* ProfileSaver::instance_ = nullptr;
+pthread_t ProfileSaver::profiler_pthread_ = 0U;
+
+ProfileSaver::ProfileSaver(const std::string& output_filename,
+ jit::JitCodeCache* jit_code_cache,
+ const std::vector<std::string>& code_paths)
+ : output_filename_(output_filename),
+ jit_code_cache_(jit_code_cache),
+ tracked_dex_base_locations_(code_paths.begin(), code_paths.end()),
+ code_cache_last_update_time_ns_(0),
+ shutting_down_(false),
+ wait_lock_("ProfileSaver wait lock"),
+ period_condition_("ProfileSaver period condition", wait_lock_) {
+}
+
+void ProfileSaver::Run() {
+ srand(MicroTime() * getpid());
+ Thread* self = Thread::Current();
+
+ uint64_t save_period_ms = kSavePeriodMs;
+ VLOG(profiler) << "Save profiling information every " << save_period_ms << " ms";
+ while (true) {
+ if (ShuttingDown(self)) {
+ break;
+ }
+
+ uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs;
+ uint64_t sleep_time_ms = save_period_ms + random_sleep_delay_ms;
+ {
+ MutexLock mu(self, wait_lock_);
+ period_condition_.TimedWait(self, sleep_time_ms, 0);
+ }
+
+ if (ShuttingDown(self)) {
+ break;
+ }
+
+ if (!ProcessProfilingInfo() && save_period_ms < kMaxBackoffMs) {
+ // If we don't need to save now it is less likely that we will need to do
+ // so in the future. Increase the time between saves according to the
+ // kBackoffCoef, but make it no larger than kMaxBackoffMs.
+ save_period_ms = static_cast<uint64_t>(kBackoffCoef * save_period_ms);
+ } else {
+ // Reset the period to the initial value as it's highly likely to JIT again.
+ save_period_ms = kSavePeriodMs;
+ }
+ }
+}
+
+bool ProfileSaver::ProcessProfilingInfo() {
+ VLOG(profiler) << "Initiating save profiling information to: " << output_filename_;
+
+ uint64_t last_update_time_ns = jit_code_cache_->GetLastUpdateTimeNs();
+ if (last_update_time_ns - code_cache_last_update_time_ns_
+ > kMinimumTimeBetweenCodeCacheUpdatesNs) {
+ VLOG(profiler) << "Not enough time has passed since the last code cache update.";
+ return false;
+ }
+
+ uint64_t start = NanoTime();
+ code_cache_last_update_time_ns_ = last_update_time_ns;
+ std::vector<ArtMethod*> methods;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ jit_code_cache_->GetCompiledArtMethods(tracked_dex_base_locations_, methods);
+ }
+ if (methods.size() < kMinimumNrOrMethodsToSave) {
+ VLOG(profiler) << "Not enough information to save. Nr of methods: " << methods.size();
+ return false;
+ }
+ offline_profiling_info_.SaveProfilingInfo(output_filename_, methods);
+
+ VLOG(profiler) << "Saved profile time: " << PrettyDuration(NanoTime() - start);
+
+ return true;
+}
+
+void* ProfileSaver::RunProfileSaverThread(void* arg) {
+ Runtime* runtime = Runtime::Current();
+ ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
+
+ CHECK(runtime->AttachCurrentThread("Profile Saver",
+ /*as_daemon*/true,
+ runtime->GetSystemThreadGroup(),
+ /*create_peer*/true));
+ profile_saver->Run();
+
+ runtime->DetachCurrentThread();
+ VLOG(profiler) << "Profile saver shutdown";
+ return nullptr;
+}
+
+void ProfileSaver::Start(const std::string& output_filename,
+ jit::JitCodeCache* jit_code_cache,
+ const std::vector<std::string>& code_paths) {
+ DCHECK(Runtime::Current()->UseJit());
+ DCHECK(!output_filename.empty());
+ DCHECK(jit_code_cache != nullptr);
+
+ MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
+ // Don't start two profile saver threads.
+ if (instance_ != nullptr) {
+ DCHECK(false) << "Tried to start two profile savers";
+ return;
+ }
+
+ VLOG(profiler) << "Starting profile saver using output file: " << output_filename
+ << ". Tracking: " << Join(code_paths, ':');
+
+ instance_ = new ProfileSaver(output_filename, jit_code_cache, code_paths);
+
+ // Create a new thread which does the saving.
+ CHECK_PTHREAD_CALL(
+ pthread_create,
+ (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
+ "Profile saver thread");
+}
+
+void ProfileSaver::Stop() {
+ ProfileSaver* profile_saver = nullptr;
+ pthread_t profiler_pthread = 0U;
+
+ {
+ MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
+ VLOG(profiler) << "Stopping profile saver thread for file: " << instance_->output_filename_;
+ profile_saver = instance_;
+ profiler_pthread = profiler_pthread_;
+ if (instance_ == nullptr) {
+ DCHECK(false) << "Tried to stop a profile saver which was not started";
+ return;
+ }
+ if (instance_->shutting_down_) {
+ DCHECK(false) << "Tried to stop the profile saver twice";
+ return;
+ }
+ instance_->shutting_down_ = true;
+ }
+
+ {
+ // Wake up the saver thread if it is sleeping to allow for a clean exit.
+ MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
+ profile_saver->period_condition_.Signal(Thread::Current());
+ }
+
+ // Wait for the saver thread to stop.
+ CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
+
+ {
+ MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
+ instance_ = nullptr;
+ profiler_pthread_ = 0U;
+ }
+ delete profile_saver;
+}
+
+bool ProfileSaver::ShuttingDown(Thread* self) {
+ MutexLock mu(self, *Locks::profiler_lock_);
+ return shutting_down_;
+}
+
+bool ProfileSaver::IsStarted() {
+ MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
+ return instance_ != nullptr;
+}
+
+} // namespace art
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
new file mode 100644
index 0000000..88efd41
--- /dev/null
+++ b/runtime/jit/profile_saver.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_JIT_PROFILE_SAVER_H_
+#define ART_RUNTIME_JIT_PROFILE_SAVER_H_
+
+#include "base/mutex.h"
+#include "jit_code_cache.h"
+#include "offline_profiling_info.h"
+
+namespace art {
+
+class ProfileSaver {
+ public:
+ // Starts the profile saver thread.
+ static void Start(const std::string& output_filename,
+ jit::JitCodeCache* jit_code_cache,
+ const std::vector<std::string>& code_paths)
+ REQUIRES(!Locks::profiler_lock_, !wait_lock_);
+
+ // Stops the profile saver thread.
+ // NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock.
+ static void Stop()
+ REQUIRES(!Locks::profiler_lock_, !wait_lock_)
+ NO_THREAD_SAFETY_ANALYSIS;
+
+ // Returns true if the profile saver is started.
+ static bool IsStarted() REQUIRES(!Locks::profiler_lock_);
+
+ private:
+ ProfileSaver(const std::string& output_filename,
+ jit::JitCodeCache* jit_code_cache,
+ const std::vector<std::string>& code_paths);
+
+ // NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock.
+ static void* RunProfileSaverThread(void* arg)
+ REQUIRES(!Locks::profiler_lock_, !wait_lock_)
+ NO_THREAD_SAFETY_ANALYSIS;
+
+ // 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();
+ // Returns true if the saver is shutting down (ProfileSaver::Stop() has been called).
+ bool ShuttingDown(Thread* self) REQUIRES(!Locks::profiler_lock_);
+
+ // The only instance of the saver.
+ static ProfileSaver* instance_ GUARDED_BY(Locks::profiler_lock_);
+ // Profile saver thread.
+ static pthread_t profiler_pthread_ GUARDED_BY(Locks::profiler_lock_);
+
+ const std::string output_filename_;
+ jit::JitCodeCache* jit_code_cache_;
+ const std::set<const std::string> tracked_dex_base_locations_;
+ OfflineProfilingInfo offline_profiling_info_;
+ uint64_t code_cache_last_update_time_ns_;
+ bool shutting_down_ GUARDED_BY(Locks::profiler_lock_);
+
+ // Save period condition support.
+ Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ ConditionVariable period_condition_ GUARDED_BY(wait_lock_);
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSaver);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_JIT_PROFILE_SAVER_H_
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 424cc11..4b24f82 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -224,7 +224,6 @@
static void VMRuntime_updateProcessState(JNIEnv*, jobject, jint process_state) {
Runtime* runtime = Runtime::Current();
runtime->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
- runtime->UpdateProfilerState(process_state);
}
static void VMRuntime_trimHeap(JNIEnv* env, jobject) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index be64bff..98aa8d8 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -190,7 +190,6 @@
abort_(nullptr),
stats_enabled_(false),
is_running_on_memory_tool_(RUNNING_ON_MEMORY_TOOL),
- profiler_started_(false),
instrumentation_(),
main_thread_group_(nullptr),
system_thread_group_(nullptr),
@@ -258,11 +257,6 @@
self = nullptr;
}
- // Shut down background profiler before the runtime exits.
- if (profiler_started_) {
- BackgroundMethodSamplingProfiler::Shutdown();
- }
-
// Make sure to let the GC complete if it is running.
heap_->WaitForGcToComplete(gc::kGcCauseBackground, self);
heap_->DeleteThreadPool();
@@ -271,6 +265,8 @@
// 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();
}
// Make sure our internal threads are dead before we start tearing down things they're using.
@@ -617,8 +613,7 @@
if (fd >= 0) {
close(fd);
} else if (errno != EEXIST) {
- LOG(INFO) << "Failed to access the profile file. Profiler disabled.";
- return true;
+ LOG(WARNING) << "Failed to access the profile file. Profiler disabled.";
}
}
@@ -1694,11 +1689,13 @@
void Runtime::RegisterAppInfo(const std::vector<std::string>& code_paths,
const std::string& profile_output_filename) {
+ VLOG(profiler) << "Register app with " << profile_output_filename_
+ << " " << Join(code_paths, ':');
DCHECK(!profile_output_filename.empty());
- if (jit_.get() != nullptr) {
- jit_->SetDexLocationsForProfiling(code_paths);
- }
profile_output_filename_ = profile_output_filename;
+ if (jit_.get() != nullptr && !profile_output_filename.empty() && !code_paths.empty()) {
+ jit_->StartProfileSaver(profile_output_filename, code_paths);
+ }
}
// Transaction support.
@@ -1844,18 +1841,6 @@
argv->push_back(feature_string);
}
-void Runtime::MaybeSaveJitProfilingInfo() {
- if (jit_.get() != nullptr && !profile_output_filename_.empty()) {
- jit_->SaveProfilingInfo(profile_output_filename_);
- }
-}
-
-void Runtime::UpdateProfilerState(int state) {
- if (state == kProfileBackground) {
- MaybeSaveJitProfilingInfo();
- }
-}
-
void Runtime::CreateJit() {
CHECK(!IsAotCompiler());
if (GetInstrumentation()->IsForcedInterpretOnly()) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 5df1ca9..20acffb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -470,7 +470,6 @@
void RegisterAppInfo(const std::vector<std::string>& code_paths,
const std::string& profile_output_filename);
- void UpdateProfilerState(int state);
// Transaction support.
bool IsActiveTransaction() const {
@@ -735,7 +734,6 @@
std::string profile_output_filename_;
ProfilerOptions profiler_options_;
- bool profiler_started_;
std::unique_ptr<TraceConfig> trace_config_;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index eddc3a4..ff6b4c0 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1860,4 +1860,10 @@
*parsed_value = value;
}
+int64_t GetFileSizeBytes(const std::string& filename) {
+ struct stat stat_buf;
+ int rc = stat(filename.c_str(), &stat_buf);
+ return rc == 0 ? stat_buf.st_size : -1;
+}
+
} // namespace art
diff --git a/runtime/utils.h b/runtime/utils.h
index 5b9e963..a07e74c 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -367,6 +367,9 @@
return dist(rng);
}
+// Return the file size in bytes or -1 if the file does not exists.
+int64_t GetFileSizeBytes(const std::string& filename);
+
} // namespace art
#endif // ART_RUNTIME_UTILS_H_