зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
ca5b034b04
Коммит
883b7bec01
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/StaticPrefs_page_load.h"
|
||||
#include "mozilla/StaticPrefs_javascript.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/ipc/IdleSchedulerParent.h"
|
||||
#include "nsSystemInfo.h"
|
||||
|
@ -19,52 +20,93 @@ base::SharedMemory* IdleSchedulerParent::sActiveChildCounter = nullptr;
|
|||
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
|
||||
IdleSchedulerParent::sInUseChildCounters;
|
||||
LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests;
|
||||
Atomic<int32_t> IdleSchedulerParent::sMaxConcurrentIdleTasksInChildProcesses(
|
||||
-1);
|
||||
int32_t IdleSchedulerParent::sMaxConcurrentIdleTasksInChildProcesses = 1;
|
||||
uint32_t IdleSchedulerParent::sMaxConcurrentGCs = 1;
|
||||
uint32_t IdleSchedulerParent::sActiveGCs = 0;
|
||||
uint32_t IdleSchedulerParent::sChildProcessesRunningPrioritizedOperation = 0;
|
||||
uint32_t IdleSchedulerParent::sChildProcessesAlive = 0;
|
||||
nsITimer* IdleSchedulerParent::sStarvationPreventer = nullptr;
|
||||
|
||||
uint32_t IdleSchedulerParent::sNumCPUs = 0;
|
||||
uint32_t IdleSchedulerParent::sPrefConcurrentGCsMax = 0;
|
||||
uint32_t IdleSchedulerParent::sPrefConcurrentGCsCPUDivisor = 0;
|
||||
|
||||
IdleSchedulerParent::IdleSchedulerParent() {
|
||||
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.
|
||||
// While waiting for the real logical core count behave as if there was just
|
||||
// one core.
|
||||
sMaxConcurrentIdleTasksInChildProcesses = 1;
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
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 = {};
|
||||
if (NS_SUCCEEDED(CollectProcessInfo(processInfo)) &&
|
||||
processInfo.cpuCount > 1) {
|
||||
// On one and two processor (or hardware thread) systems this will
|
||||
// allow one concurrent idle task.
|
||||
sMaxConcurrentIdleTasksInChildProcesses =
|
||||
std::max(processInfo.cpuCount - 1, 1);
|
||||
sMaxConcurrentGCs = std::max(processInfo.cpuCount / 4, 1);
|
||||
// We have a new cpu count, reschedule idle scheduler.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableFunction("IdleSchedulerParent::Schedule", []() {
|
||||
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);
|
||||
if (NS_SUCCEEDED(CollectProcessInfo(processInfo))) {
|
||||
uint32_t num_cpus = processInfo.cpuCount;
|
||||
// We have a new cpu count, Update the number of idle tasks.
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
|
||||
"IdleSchedulerParent::CalculateNumIdleTasks", [num_cpus]() {
|
||||
// We're setting this within this lambda because it's run on
|
||||
// the correct thread and avoids a race.
|
||||
sNumCPUs = num_cpus;
|
||||
|
||||
// This reads the sPrefConcurrentGCsMax and
|
||||
// sPrefConcurrentGCsCPUDivisor values set below, it will run
|
||||
// after the code that sets those.
|
||||
CalculateNumIdleTasks();
|
||||
});
|
||||
|
||||
thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
});
|
||||
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() {
|
||||
|
|
|
@ -47,6 +47,8 @@ class IdleSchedulerParent final
|
|||
IdleSchedulerParent();
|
||||
~IdleSchedulerParent();
|
||||
|
||||
static void CalculateNumIdleTasks();
|
||||
|
||||
static int32_t ActiveCount();
|
||||
static void Schedule(IdleSchedulerParent* aRequester);
|
||||
static bool HasSpareCycles(int32_t aActiveCount);
|
||||
|
@ -104,7 +106,7 @@ class IdleSchedulerParent final
|
|||
// mRequestingGC and mDoingGC fields for the GC state.
|
||||
static LinkedList<IdleSchedulerParent> sIdleAndGCRequests;
|
||||
|
||||
static Atomic<int32_t> sMaxConcurrentIdleTasksInChildProcesses;
|
||||
static int32_t sMaxConcurrentIdleTasksInChildProcesses;
|
||||
static uint32_t sMaxConcurrentGCs;
|
||||
static uint32_t sActiveGCs;
|
||||
|
||||
|
@ -116,6 +118,10 @@ class IdleSchedulerParent final
|
|||
static uint32_t sChildProcessesAlive;
|
||||
|
||||
static nsITimer* sStarvationPreventer;
|
||||
|
||||
static uint32_t sNumCPUs;
|
||||
static uint32_t sPrefConcurrentGCsMax;
|
||||
static uint32_t sPrefConcurrentGCsCPUDivisor;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -5756,6 +5756,19 @@
|
|||
value: @IS_NOT_ANDROID@
|
||||
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
|
||||
type: bool
|
||||
value: false
|
||||
|
|
Загрузка…
Ссылка в новой задаче