Restore profile saver priority in GC critical section
Restore profile saver thread priority during the GC critical section.
This helps prevent priority inversions blocking the GC for long
periods of time.
Average time spent in GC critical section during phone booting
(20 samples): 137.4963182ms -> 62.22603846ms
Bug: 62941975
Test: phone boot and make
Change-Id: Ie8180974e92a7bf5ebb847eeee741c7fd5bdf59f
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index b41bc78..10dddae 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -43,6 +43,33 @@
ProfileSaver* ProfileSaver::instance_ = nullptr;
pthread_t ProfileSaver::profiler_pthread_ = 0U;
+// At what priority to schedule the saver threads. 9 is the lowest foreground priority on device.
+static constexpr int kProfileSaverPthreadPriority = 9;
+
+static void SetProfileSaverThreadPriority(pthread_t thread, int priority) {
+#if defined(ART_TARGET_ANDROID)
+ int result = setpriority(PRIO_PROCESS, pthread_gettid_np(thread), priority);
+ if (result != 0) {
+ LOG(ERROR) << "Failed to setpriority to :" << priority;
+ }
+#else
+ UNUSED(thread);
+ UNUSED(priority);
+#endif
+}
+
+static int GetDefaultThreadPriority() {
+#if defined(ART_TARGET_ANDROID)
+ pthread_attr_t attr;
+ sched_param param;
+ pthread_attr_init(&attr);
+ pthread_attr_getschedparam(&attr, ¶m);
+ return param.sched_priority;
+#else
+ return 0;
+#endif
+}
+
ProfileSaver::ProfileSaver(const ProfileSaverOptions& options,
const std::string& output_filename,
jit::JitCodeCache* jit_code_cache,
@@ -241,6 +268,20 @@
const bool profile_boot_class_path_;
};
+class ScopedDefaultPriority {
+ public:
+ explicit ScopedDefaultPriority(pthread_t thread) : thread_(thread) {
+ SetProfileSaverThreadPriority(thread_, GetDefaultThreadPriority());
+ }
+
+ ~ScopedDefaultPriority() {
+ SetProfileSaverThreadPriority(thread_, kProfileSaverPthreadPriority);
+ }
+
+ private:
+ const pthread_t thread_;
+};
+
void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
ScopedTrace trace(__PRETTY_FUNCTION__);
const uint64_t start_time = NanoTime();
@@ -257,7 +298,15 @@
TypeReferenceCollection resolved_classes(allocator.Adapter(), allocator.Adapter());
const bool is_low_ram = Runtime::Current()->GetHeap()->IsLowMemoryMode();
const size_t hot_threshold = options_.GetHotStartupMethodSamples(is_low_ram);
+ pthread_t profiler_pthread;
{
+ MutexLock mu(self, *Locks::profiler_lock_);
+ profiler_pthread = profiler_pthread_;
+ }
+ {
+ // Restore profile saver thread priority during the GC critical section. This helps prevent
+ // priority inversions blocking the GC for long periods of time.
+ ScopedDefaultPriority sdp(profiler_pthread);
ScopedObjectAccess soa(self);
gc::ScopedGCCriticalSection sgcs(self,
gc::kGcCauseProfileSaver,
@@ -543,15 +592,7 @@
(&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
"Profile saver thread");
-#if defined(ART_TARGET_ANDROID)
- // At what priority to schedule the saver threads. 9 is the lowest foreground priority on device.
- static constexpr int kProfileSaverPthreadPriority = 9;
- int result = setpriority(
- PRIO_PROCESS, pthread_gettid_np(profiler_pthread_), kProfileSaverPthreadPriority);
- if (result != 0) {
- PLOG(ERROR) << "Failed to setpriority to :" << kProfileSaverPthreadPriority;
- }
-#endif
+ SetProfileSaverThreadPriority(profiler_pthread_, kProfileSaverPthreadPriority);
}
void ProfileSaver::Stop(bool dump_info) {