From 9902a0945d22cd5757b16ebe85fe07059723aa09 Mon Sep 17 00:00:00 2001 From: stk Date: Mon, 16 May 2022 10:01:09 +0200 Subject: [PATCH] Add ThreadPriority::Low, and use QoS class Utility on Mac On Apple Silicon Macs, using a Darwin thread priority of PRIO_DARWIN_BG seems to map directly to the QoS class Background. With this priority, the thread is confined to efficiency cores only, which makes background indexing take forever. Introduce a new ThreadPriority "Low" that sits in the middle between Background and Default, and maps to QoS class "Utility" on Mac. Make this new priority the default for indexing. This makes the thread run on all cores, but still lowers priority enough to keep the machine responsive, and not interfere with user-initiated actions. I didn't change the implementations for Windows and Linux; on these systems, both ThreadPriority::Background and ThreadPriority::Low map to the same thread priority. This could be changed as a followup (e.g. by using SCHED_BATCH for Low on Linux). See also https://github.com/clangd/clangd/issues/1119. Reviewed By: sammccall, dgoldman Differential Revision: https://reviews.llvm.org/D124715 --- clang-tools-extra/clangd/index/Background.h | 2 +- clang/tools/libclang/CIndex.cpp | 4 ++- llvm/include/llvm/Support/Threading.h | 19 +++++++---- llvm/lib/Support/Unix/Threading.inc | 37 +++++++++++---------- llvm/lib/Support/Windows/Threading.inc | 4 ++- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h index 040ca2d002bc..97f9095ed2c2 100644 --- a/clang-tools-extra/clangd/index/Background.h +++ b/clang-tools-extra/clangd/index/Background.h @@ -72,7 +72,7 @@ public: explicit Task(std::function Run) : Run(std::move(Run)) {} std::function Run; - llvm::ThreadPriority ThreadPri = llvm::ThreadPriority::Background; + llvm::ThreadPriority ThreadPri = llvm::ThreadPriority::Low; unsigned QueuePri = 0; // Higher-priority tasks will run first. std::string Tag; // Allows priority to be boosted later. uint64_t Key = 0; // If the key matches a previous task, drop this one. diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 6df673fec4ad..235ca3e9c060 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9025,7 +9025,9 @@ void clang::setThreadBackgroundPriority() { return; #if LLVM_ENABLE_THREADS - llvm::set_thread_priority(llvm::ThreadPriority::Background); + // The function name setThreadBackgroundPriority is for historical reasons; + // Low is more appropriate. + llvm::set_thread_priority(llvm::ThreadPriority::Low); #endif } diff --git a/llvm/include/llvm/Support/Threading.h b/llvm/include/llvm/Support/Threading.h index b158a57a1a21..1e7e5f7b8f50 100644 --- a/llvm/include/llvm/Support/Threading.h +++ b/llvm/include/llvm/Support/Threading.h @@ -233,15 +233,20 @@ bool llvm_is_multithreaded(); unsigned get_cpus(); enum class ThreadPriority { + /// Lower the current thread's priority as much as possible. Can be used + /// for long-running tasks that are not time critical; more energy- + /// efficient than Low. Background = 0, - Default = 1, + + /// Lower the current thread's priority such that it does not affect + /// foreground tasks significantly. This is a good default for long- + /// running, latency-insensitive tasks to make sure cpu is not hogged + /// by this task. + Low = 1, + + /// Restore the current thread's priority to default scheduling priority. + Default = 2, }; - /// If priority is Background tries to lower current threads priority such - /// that it does not affect foreground tasks significantly. Can be used for - /// long-running, latency-insensitive tasks to make sure cpu is not hogged by - /// this task. - /// If the priority is default tries to restore current threads priority to - /// default scheduling priority. enum class SetThreadPriorityResult { FAILURE, SUCCESS }; SetThreadPriorityResult set_thread_priority(ThreadPriority Priority); } diff --git a/llvm/lib/Support/Unix/Threading.inc b/llvm/lib/Support/Unix/Threading.inc index 5de1cf071ba9..99f64b4f553d 100644 --- a/llvm/lib/Support/Unix/Threading.inc +++ b/llvm/lib/Support/Unix/Threading.inc @@ -18,6 +18,7 @@ #if defined(__APPLE__) #include #include +#include #endif #include @@ -258,27 +259,29 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { // SCHED_OTHER the standard round-robin time-sharing policy; return !pthread_setschedparam( pthread_self(), - Priority == ThreadPriority::Background ? SCHED_IDLE : SCHED_OTHER, + // FIXME: consider SCHED_BATCH for Low + Priority == ThreadPriority::Default ? SCHED_OTHER : SCHED_IDLE, &priority) ? SetThreadPriorityResult::SUCCESS : SetThreadPriorityResult::FAILURE; #elif defined(__APPLE__) - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html - // When setting a thread into background state the scheduling priority is set - // to lowest value, disk and network IO are throttled. Network IO will be - // throttled for any sockets the thread opens after going into background - // state. Any previously opened sockets are not affected. - - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getiopolicy_np.3.html - // I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O - // request occurs within a small time window (usually a fraction of a second) - // of another NORMAL I/O request, the thread that issues the THROTTLE I/O is - // forced to sleep for a certain interval. This slows down the thread that - // issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk - // I/O bandwidth. - return !setpriority(PRIO_DARWIN_THREAD, 0, - Priority == ThreadPriority::Background ? PRIO_DARWIN_BG - : 0) + // https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon + // + // Background - Applies to work that isn’t visible to the user and may take significant + // time to complete. Examples include indexing, backing up, or synchronizing data. This + // class emphasizes energy efficiency. + // + // Utility - Applies to work that takes anywhere from a few seconds to a few minutes to + // complete. Examples include downloading a document or importing data. This class + // offers a balance between responsiveness, performance, and energy efficiency. + const auto qosClass = [&](){ + switch (Priority) { + case ThreadPriority::Background: return QOS_CLASS_BACKGROUND; + case ThreadPriority::Low: return QOS_CLASS_UTILITY; + case ThreadPriority::Default: return QOS_CLASS_DEFAULT; + } + }(); + return !pthread_set_qos_class_self_np(qosClass, 0) ? SetThreadPriorityResult::SUCCESS : SetThreadPriorityResult::FAILURE; #endif diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc index 7b48ca8fb1fb..26f690e0f5a3 100644 --- a/llvm/lib/Support/Windows/Threading.inc +++ b/llvm/lib/Support/Windows/Threading.inc @@ -120,8 +120,10 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { // End background processing mode. The system restores the resource scheduling // priorities of the thread as they were before the thread entered background // processing mode. + // + // FIXME: consider THREAD_PRIORITY_BELOW_NORMAL for Low return SetThreadPriority(GetCurrentThread(), - Priority == ThreadPriority::Background + Priority != ThreadPriority::Default ? THREAD_MODE_BACKGROUND_BEGIN : THREAD_MODE_BACKGROUND_END) ? SetThreadPriorityResult::SUCCESS