Bug 1629064 - pt 4. Add a pref for the maximum number of concurrent GCs r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D105957
This commit is contained in:
Paul Bone 2021-05-12 06:46:09 +00:00
Родитель ca5b034b04
Коммит 883b7bec01
3 изменённых файлов: 88 добавлений и 27 удалений

Просмотреть файл

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/StaticPrefs_page_load.h" #include "mozilla/StaticPrefs_page_load.h"
#include "mozilla/StaticPrefs_javascript.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "mozilla/ipc/IdleSchedulerParent.h" #include "mozilla/ipc/IdleSchedulerParent.h"
#include "nsSystemInfo.h" #include "nsSystemInfo.h"
@ -19,52 +20,93 @@ base::SharedMemory* IdleSchedulerParent::sActiveChildCounter = nullptr;
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT> std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
IdleSchedulerParent::sInUseChildCounters; IdleSchedulerParent::sInUseChildCounters;
LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests; LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests;
Atomic<int32_t> IdleSchedulerParent::sMaxConcurrentIdleTasksInChildProcesses( int32_t IdleSchedulerParent::sMaxConcurrentIdleTasksInChildProcesses = 1;
-1);
uint32_t IdleSchedulerParent::sMaxConcurrentGCs = 1; uint32_t IdleSchedulerParent::sMaxConcurrentGCs = 1;
uint32_t IdleSchedulerParent::sActiveGCs = 0; uint32_t IdleSchedulerParent::sActiveGCs = 0;
uint32_t IdleSchedulerParent::sChildProcessesRunningPrioritizedOperation = 0; uint32_t IdleSchedulerParent::sChildProcessesRunningPrioritizedOperation = 0;
uint32_t IdleSchedulerParent::sChildProcessesAlive = 0; uint32_t IdleSchedulerParent::sChildProcessesAlive = 0;
nsITimer* IdleSchedulerParent::sStarvationPreventer = nullptr; nsITimer* IdleSchedulerParent::sStarvationPreventer = nullptr;
uint32_t IdleSchedulerParent::sNumCPUs = 0;
uint32_t IdleSchedulerParent::sPrefConcurrentGCsMax = 0;
uint32_t IdleSchedulerParent::sPrefConcurrentGCsCPUDivisor = 0;
IdleSchedulerParent::IdleSchedulerParent() { IdleSchedulerParent::IdleSchedulerParent() {
sChildProcessesAlive++; sChildProcessesAlive++;
if (sMaxConcurrentIdleTasksInChildProcesses == -1) { uint32_t max_gcs_pref =
StaticPrefs::javascript_options_concurrent_multiprocess_gcs_max();
uint32_t cpu_divisor_pref =
StaticPrefs::javascript_options_concurrent_multiprocess_gcs_cpu_divisor();
if (!max_gcs_pref) {
max_gcs_pref = UINT32_MAX;
}
if (!cpu_divisor_pref) {
cpu_divisor_pref = 4;
}
if (!sNumCPUs) {
// While waiting for the real logical core count behave as if there was
// just one core.
sNumCPUs = 1;
// nsISystemInfo can be initialized only on the main thread. // nsISystemInfo can be initialized only on the main thread.
// While waiting for the real logical core count behave as if there was just
// one core.
sMaxConcurrentIdleTasksInChildProcesses = 1;
nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
nsCOMPtr<nsIRunnable> runnable = nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction("cpucount getter", [thread]() { NS_NewRunnableFunction("cpucount getter", [thread]() {
// Always pretend that there is at least one core for child processes.
// If there are multiple logical cores, reserve one for the parent
// process and for the non-main threads.
ProcessInfo processInfo = {}; ProcessInfo processInfo = {};
if (NS_SUCCEEDED(CollectProcessInfo(processInfo)) && if (NS_SUCCEEDED(CollectProcessInfo(processInfo))) {
processInfo.cpuCount > 1) { uint32_t num_cpus = processInfo.cpuCount;
// On one and two processor (or hardware thread) systems this will // We have a new cpu count, Update the number of idle tasks.
// allow one concurrent idle task. nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
sMaxConcurrentIdleTasksInChildProcesses = "IdleSchedulerParent::CalculateNumIdleTasks", [num_cpus]() {
std::max(processInfo.cpuCount - 1, 1); // We're setting this within this lambda because it's run on
sMaxConcurrentGCs = std::max(processInfo.cpuCount / 4, 1); // the correct thread and avoids a race.
// We have a new cpu count, reschedule idle scheduler. sNumCPUs = num_cpus;
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction("IdleSchedulerParent::Schedule", []() { // This reads the sPrefConcurrentGCsMax and
if (sActiveChildCounter && sActiveChildCounter->memory()) { // sPrefConcurrentGCsCPUDivisor values set below, it will run
static_cast<Atomic<int32_t>*>(sActiveChildCounter->memory()) // after the code that sets those.
[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] = CalculateNumIdleTasks();
static_cast<int32_t>(
sMaxConcurrentIdleTasksInChildProcesses);
}
IdleSchedulerParent::Schedule(nullptr);
}); });
thread->Dispatch(runnable, NS_DISPATCH_NORMAL); thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
} }
}); });
NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCK); NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
} }
if (sPrefConcurrentGCsMax != max_gcs_pref ||
sPrefConcurrentGCsCPUDivisor != cpu_divisor_pref) {
// We execute this if these preferences have changed. We also want to make
// sure it executes for the first IdleSchedulerParent, which it does because
// sPrefConcurrentGCsMax and sPrefConcurrentGCsCPUDivisor are initially
// zero.
sPrefConcurrentGCsMax = max_gcs_pref;
sPrefConcurrentGCsCPUDivisor = cpu_divisor_pref;
CalculateNumIdleTasks();
}
}
void IdleSchedulerParent::CalculateNumIdleTasks() {
MOZ_ASSERT(sNumCPUs);
MOZ_ASSERT(sPrefConcurrentGCsMax);
MOZ_ASSERT(sPrefConcurrentGCsCPUDivisor);
// On one and two processor (or hardware thread) systems this will
// allow one concurrent idle task.
sMaxConcurrentIdleTasksInChildProcesses = int32_t(std::max(sNumCPUs, 1u));
sMaxConcurrentGCs =
std::min(std::max(sNumCPUs / sPrefConcurrentGCsCPUDivisor, 1u),
sPrefConcurrentGCsMax);
if (sActiveChildCounter && sActiveChildCounter->memory()) {
static_cast<Atomic<int32_t>*>(
sActiveChildCounter->memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
}
IdleSchedulerParent::Schedule(nullptr);
} }
IdleSchedulerParent::~IdleSchedulerParent() { IdleSchedulerParent::~IdleSchedulerParent() {

Просмотреть файл

@ -47,6 +47,8 @@ class IdleSchedulerParent final
IdleSchedulerParent(); IdleSchedulerParent();
~IdleSchedulerParent(); ~IdleSchedulerParent();
static void CalculateNumIdleTasks();
static int32_t ActiveCount(); static int32_t ActiveCount();
static void Schedule(IdleSchedulerParent* aRequester); static void Schedule(IdleSchedulerParent* aRequester);
static bool HasSpareCycles(int32_t aActiveCount); static bool HasSpareCycles(int32_t aActiveCount);
@ -104,7 +106,7 @@ class IdleSchedulerParent final
// mRequestingGC and mDoingGC fields for the GC state. // mRequestingGC and mDoingGC fields for the GC state.
static LinkedList<IdleSchedulerParent> sIdleAndGCRequests; static LinkedList<IdleSchedulerParent> sIdleAndGCRequests;
static Atomic<int32_t> sMaxConcurrentIdleTasksInChildProcesses; static int32_t sMaxConcurrentIdleTasksInChildProcesses;
static uint32_t sMaxConcurrentGCs; static uint32_t sMaxConcurrentGCs;
static uint32_t sActiveGCs; static uint32_t sActiveGCs;
@ -116,6 +118,10 @@ class IdleSchedulerParent final
static uint32_t sChildProcessesAlive; static uint32_t sChildProcessesAlive;
static nsITimer* sStarvationPreventer; static nsITimer* sStarvationPreventer;
static uint32_t sNumCPUs;
static uint32_t sPrefConcurrentGCsMax;
static uint32_t sPrefConcurrentGCsCPUDivisor;
}; };
} // namespace ipc } // namespace ipc

Просмотреть файл

@ -5756,6 +5756,19 @@
value: @IS_NOT_ANDROID@ value: @IS_NOT_ANDROID@
mirror: always mirror: always
# We allow at most MIN(max, MAX(NUM_CPUS / cpu_divisor, 1)) concurrent GCs
# between processes
- name: javascript.options.concurrent_multiprocess_gcs.cpu_divisor
type: RelaxedAtomicUint32
value: 4
mirror: always
# See 'cpu_divisor' above, 0 means UINT_32_MAX.
- name: javascript.options.concurrent_multiprocess_gcs.max
type: RelaxedAtomicUint32
value: 0
mirror: always
- name: javascript.options.mem.log - name: javascript.options.mem.log
type: bool type: bool
value: false value: false