#463: rework idle callbacks to use max timeout; try to fix stalls; pref off by default for FPR9

This commit is contained in:
Cameron Kaiser 2018-07-23 21:23:48 -07:00
parent 05241abca1
commit 12cdb0cd25
2 changed files with 43 additions and 7 deletions

View File

@ -264,8 +264,8 @@ class nsIScriptTimeoutHandler;
// which also uses Mach factor analysis to determine load, because most
// calls will have a max timeout and thus the function is likely to run at
// *some* point.
static const int32_t MACH_FACTOR_MIN = 700;
static const int32_t MACH_CHECK_INTERVAL = 2000;
static const int32_t MACH_FACTOR_MIN = 900;
static const int32_t MACH_CHECK_INTERVAL = 1000;
// This number is actually in the W3C standard, but we allow it to be
// adjusted.
static const int32_t CALLBACK_IDLE_INTERVAL = 50;
@ -275,7 +275,10 @@ static int32_t sIdleCallbackIdleInterval = CALLBACK_IDLE_INTERVAL;
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/bootstrap.h>
#include <sys/param.h>
#include <sys/sysctl.h>
static processor_set_name_port_t sMachDefaultPset;
static uint32_t sNumCPUs;
static struct processor_set_load_info sMachLoadInfo;
static host_name_port_t sMachHost;
@ -1245,10 +1248,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
CALLBACK_IDLE_INTERVAL);
sMachHost = mach_host_self();
kern_return_t ret = processor_set_default(sMachHost, &sMachDefaultPset);
sNumCPUs = 1;
if (ret != KERN_SUCCESS) {
fprintf(stderr, "TenFourFox: Unable to initialize Mach idle monitoring: %i\n", (uint32_t)ret);
sMachFactorMin = 0;
}
int mib[2] = { CTL_HW, HW_NCPU };
size_t len = sizeof(sNumCPUs);
if (sysctl(mib, 2, &sNumCPUs, &len, NULL, 0) == -1)
sNumCPUs = 1;
#if DEBUG
fprintf(stderr, "GlobalWindow: %i CPUs\n", sNumCPUs);
#endif
}
if (gDumpFile == nullptr) {
@ -11591,7 +11602,13 @@ SystemIsIdle()
(processor_set_info_t)&sMachLoadInfo, &count);
if (kr != KERN_SUCCESS) return true;
return (sMachLoadInfo.mach_factor > sMachFactorMin);
#if DEBUG
fprintf(stderr, "SystemIsIdle(%i/%i: %s)\n",
sMachLoadInfo.mach_factor,
sMachFactorMin * sNumCPUs,
(sMachLoadInfo.mach_factor > (sMachFactorMin * sNumCPUs)) ? "true" : "false");
#endif
return (sMachLoadInfo.mach_factor > (sMachFactorMin * sNumCPUs));
}
nsresult
@ -11640,6 +11657,9 @@ nsGlobalWindow::SetTimeoutOrIntervalOrIdleCallback(nsIScriptTimeoutHandler *aHan
timeout->mDeadline = interval;
timeout->mScriptHandler = nullptr;
// XXX: Current logic short circuits this and simply makes idle callbacks
// into fixed timeouts.
#if(0)
// If RequestIdleCallback says this is not an interval, then it must
// want it to run right away. Otherwise schedule the idle checks.
if (aIsInterval) {
@ -11647,6 +11667,9 @@ nsGlobalWindow::SetTimeoutOrIntervalOrIdleCallback(nsIScriptTimeoutHandler *aHan
} else
interval = 0;
timeout->mInterval = interval;
#else
// Leave interval as it is
#endif
} else {
timeout->mInterval = interval;
timeout->mCallback = nullptr;
@ -12145,7 +12168,12 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
timeout->mElapsed += timeout->mInterval;
if (!timeout->mInterval || timeout->mElapsed >= timeout->mDeadline || SystemIsIdle()) {
rescheduleOk = false;
timeout->mIsInterval = false; // don't reschedule
timeout_was_cleared = RunTimeoutHandler(timeout, scx);
if (timeout->mTimer) {
timeout->mTimer->Cancel();
timeout->mTimer = nullptr;
}
}
} else
timeout_was_cleared = RunTimeoutHandler(timeout, scx);
@ -14004,13 +14032,20 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx,
{
MOZ_RELEASE_ASSERT(IsInnerWindow());
AssertIsOnMainThread();
int32_t handle = -1, timeout = 3600000; /* default 60 minutes */
int32_t handle = -1, timeout = 5000; /* default 5 seconds */
nsresult rv;
if (aOptions.mTimeout.WasPassed())
timeout = aOptions.mTimeout.Value();
if (SystemIsIdle()) {
// XXX: Deferring initial run of the callback beyond the timeout period
// invariably causes problems. But if a timeout was specified, we can
// generally assume it's safe to hit that.
if (1) { // SystemIsIdle()) {
#if DEBUG
fprintf(stderr, "Idle callback initialized, timeout %d ms\n", timeout);
#endif
// The computer is already idle, so we will run the callback now.
rv = SetTimeoutOrIntervalOrIdleCallback(nullptr, timeout, false, &handle,
&aCallback);
@ -14019,6 +14054,7 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx,
rv = SetTimeoutOrIntervalOrIdleCallback(nullptr, timeout, true, &handle,
&aCallback);
}
if (NS_SUCCEEDED(rv))
return handle;
@ -14033,7 +14069,7 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle)
ErrorResult ignored;
// XXX: As written, this is just an alias for clearTimeout(), so
// web scripts could call either to clear any time of timeout
// web scripts could call either to clear any type of timeout
// or interval. Do we care?
if (aHandle > 0) {

View File

@ -1043,7 +1043,7 @@ pref("dom.disable_window_open_feature.status", true);
pref("dom.allow_scripts_to_close_windows", false);
// TenFourFox issue 463
pref("tenfourfox.dom.requestIdleCallback.enabled", true);
pref("tenfourfox.dom.requestIdleCallback.enabled", false);
pref("dom.require_user_interaction_for_beforeunload", true);