diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp index b8df378b1ea4..bddde4b18979 100644 --- a/layout/style/GeckoBindings.cpp +++ b/layout/style/GeckoBindings.cpp @@ -47,6 +47,7 @@ #include "mozilla/EffectCompositor.h" #include "mozilla/EffectSet.h" #include "mozilla/FontPropertyTypes.h" +#include "mozilla/Hal.h" #include "mozilla/Keyframe.h" #include "mozilla/Mutex.h" #include "mozilla/Preferences.h" @@ -1661,6 +1662,26 @@ bool Gecko_IsMainThread() { return NS_IsMainThread(); } bool Gecko_IsDOMWorkerThread() { return !!GetCurrentThreadWorkerPrivate(); } +int32_t Gecko_GetNumStyleThreads() { + if (const auto& cpuInfo = hal::GetHeterogeneousCpuInfo()) { + size_t numBigCpus = cpuInfo->mBigCpus.Count(); + // If CPUs are homogeneous we do not need to override stylo's + // default number of threads. + if (numBigCpus != cpuInfo->mTotalNumCpus) { + // From testing on a variety of devices it appears using only + // the number of big cores gives best performance when there are + // 2 or more big cores. If there are fewer than 2 big cores then + // additionally using the medium cores performs better. + if (numBigCpus >= 2) { + return static_cast(numBigCpus); + } + return static_cast(numBigCpus + cpuInfo->mMediumCpus.Count()); + } + } + + return -1; +} + const nsAttrValue* Gecko_GetSVGAnimatedClass(const Element* aElement) { MOZ_ASSERT(aElement->IsSVGElement()); return static_cast(aElement)->GetAnimatedClassName(); diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h index 1d5d60bb4e7c..ea90f6b0422f 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h @@ -609,6 +609,10 @@ bool Gecko_IsMainThread(); // Returns true if we're currently on a DOM worker thread. bool Gecko_IsDOMWorkerThread(); +// Returns the preferred number of style threads to use, or -1 for no +// preference. +int32_t Gecko_GetNumStyleThreads(); + // Media feature helpers. // // Defined in nsMediaFeatures.cpp. diff --git a/servo/components/style/global_style_data.rs b/servo/components/style/global_style_data.rs index 0b6e4e1546e1..ca52af4d8228 100644 --- a/servo/components/style/global_style_data.rs +++ b/servo/components/style/global_style_data.rs @@ -166,12 +166,21 @@ lazy_static! { let num_threads = if threads_pref >= 0 { threads_pref as usize } else { - use num_cpus; - // The default heuristic is num_virtual_cores * .75. This gives us three threads on a - // hyper-threaded dual core, and six threads on a hyper-threaded quad core. - let threads = cmp::max(num_cpus::get() * 3 / 4, 1); - // There's no point in creating a thread pool if there's one thread. - if threads == 1 { 0 } else { threads } + // Gecko may wish to override the default number of threads, for example on + // systems with heterogeneous CPUs. + #[cfg(feature = "gecko")] + let num_threads = unsafe { bindings::Gecko_GetNumStyleThreads() }; + #[cfg(not(feature = "gecko"))] + let num_threads = -1; + + if num_threads >= 0 { + num_threads as usize + } else { + use num_cpus; + // The default heuristic is num_virtual_cores * .75. This gives us three threads on a + // hyper-threaded dual core, and six threads on a hyper-threaded quad core. + cmp::max(num_cpus::get() * 3 / 4, 1) + } }; let num_threads = cmp::min(num_threads, STYLO_MAX_THREADS);