mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
Revert "import from UXP: Issue #3092 - Initial idle GC implementation (18ddd00a)"
This reverts commit 5a6d30bb90.
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
#include "jsgc.h"
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "gc/IdleGC.h"
|
||||
#include "gc/Nursery.h"
|
||||
#include "gc/Statistics.h"
|
||||
#include "gc/StoreBuffer.h"
|
||||
@@ -651,13 +650,6 @@ class GCRuntime
|
||||
void onOutOfMallocMemory();
|
||||
void onOutOfMallocMemory(const AutoLockGC& lock);
|
||||
|
||||
/* Idle-time GC notifications. */
|
||||
void notifyJSExecutionStart();
|
||||
void notifyJSExecutionEnd();
|
||||
IdleGCManager& idleGCMgr() {
|
||||
return idleGC;
|
||||
}
|
||||
|
||||
size_t maxMallocBytesAllocated() { return maxMallocBytes; }
|
||||
|
||||
uint64_t nextCellUniqueId() {
|
||||
@@ -1027,9 +1019,6 @@ class GCRuntime
|
||||
GCSchedulingTunables tunables;
|
||||
GCSchedulingState schedulingState;
|
||||
|
||||
/* Idle-time garbage collection manager. */
|
||||
IdleGCManager idleGC;
|
||||
|
||||
MemProfiler mMemProfiler;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* IDLE-TIME GARBAGE COLLECTION SYSTEM
|
||||
*
|
||||
* Overview
|
||||
* --------
|
||||
* This system implements idle-time-only garbage collection, deferring GC work
|
||||
* to periods when the JavaScript engine is not actively processing code.
|
||||
* This improves perceived responsiveness by avoiding GC pauses during critical
|
||||
* execution windows.
|
||||
*
|
||||
* Architecture
|
||||
* -----------
|
||||
*
|
||||
* The system consists of several key components:
|
||||
*
|
||||
* 1. IdleGCManager (gc/IdleGC.h, gc/IdleGC.cpp)
|
||||
* - Tracks when the JS engine is executing vs. idle
|
||||
* - Maintains timestamp of last execution activity
|
||||
* - Checks if sufficient idle time has passed
|
||||
* - Configurable idle threshold (default: 100ms)
|
||||
* - Can determine which GC reasons should bypass idle checks
|
||||
*
|
||||
* 2. GCRuntime Integration (gc/GCRuntime.h)
|
||||
* - Contains an IdleGCManager instance
|
||||
* - Provides public methods: notifyJSExecutionStart/End()
|
||||
* - Modified checkIfGCAllowedInCurrentState() to check idle status
|
||||
*
|
||||
* 3. Activity Tracking (vm/Runtime.cpp)
|
||||
* - triggerActivityCallback() now notifies IdleGCManager
|
||||
* - Called when JS enters/exits request (execution boundary)
|
||||
* - Updated in jsapi.cpp's StartRequest/StopRequest functions
|
||||
*
|
||||
* 4. Public API (jsapi.h, jsapi.cpp)
|
||||
* - JS_SetIdleGCEnabled() / JS_IsIdleGCEnabled()
|
||||
* - JS_SetIdleGCThreshold() / JS_GetIdleGCThreshold()
|
||||
* - JS_GetIdleTimeSinceLastExecution()
|
||||
* - Allows embedders to configure idle GC behavior
|
||||
*
|
||||
* Behavior
|
||||
* --------
|
||||
*
|
||||
* Normal GC Trigger (Idle GC Enabled):
|
||||
*
|
||||
* 1. JS code executes → notifyJSExecutionStart() called
|
||||
* 2. JS code finishes → notifyJSExecutionEnd() called, timestamp recorded
|
||||
* 3. GC needed → checkIfGCAllowedInCurrentState() checks idle status
|
||||
* 4a. If idle >= threshold → GC proceeds normally
|
||||
* 4b. If still executing/idle < threshold → GC is deferred
|
||||
* 5. Once idle threshold is met, next GC request proceeds
|
||||
*
|
||||
* Critical GC Triggers (Always Proceed):
|
||||
*
|
||||
* The following GC reasons bypass idle checking:
|
||||
* - OUT_OF_MEMORY: Memory pressure conditions
|
||||
* - ALLOC_TRIGGER: Allocation threshold exceeded
|
||||
* - MALLOC_PRESSURE: Malloc pressure from OS
|
||||
* - EAGER_ALLOC_TRIGGER: Eager allocation trigger
|
||||
* - API: Explicit JS API calls
|
||||
* - DETERMINISTIC: Deterministic tests
|
||||
* - EVICT_NURSERY: Nursery eviction
|
||||
* - SHUTDOWN_CC, DESTROY_RUNTIME, LAST_DITCH: Shutdown GCs
|
||||
* - DESTROY_ZONE, COMPARTMENT_REVOKED: Zone/compartment destruction
|
||||
*
|
||||
* Configuration
|
||||
* -------------
|
||||
*
|
||||
* Idle GC Enabled (default: true):
|
||||
* - Enables idle-time-only GC mode
|
||||
* - Can be toggled dynamically via JS_SetIdleGCEnabled()
|
||||
*
|
||||
* Idle Threshold (default: 100ms):
|
||||
* - Minimum idle time before GC is permitted
|
||||
* - Configurable via JS_SetIdleGCThreshold(ms)
|
||||
* - Typical values: 50-200ms depending on application
|
||||
*
|
||||
* Integration Examples
|
||||
* --------------------
|
||||
*
|
||||
* Browser Integration:
|
||||
*
|
||||
* // When browser loads configuration
|
||||
* JS_SetIdleGCEnabled(cx, true);
|
||||
* JS_SetIdleGCThreshold(cx, 100); // 100ms idle threshold
|
||||
*
|
||||
* // Monitor idle GC effectiveness (optional)
|
||||
* uint64_t idleTime = JS_GetIdleTimeSinceLastExecution(cx);
|
||||
* if (idleTime > JS_GetIdleGCThreshold(cx)) {
|
||||
* // System is idle, GC would be allowed if triggered
|
||||
* }
|
||||
*
|
||||
* Disabling for Specific Scenarios:
|
||||
*
|
||||
* // During initialization when nothing is "idle" yet
|
||||
* JS_SetIdleGCEnabled(cx, false);
|
||||
* // ... do initial setup ...
|
||||
* JS_SetIdleGCEnabled(cx, true); // Re-enable for normal operation
|
||||
*
|
||||
* Performance Considerations
|
||||
* --------------------------
|
||||
*
|
||||
* Benefits:
|
||||
* - Reduced jank during active JS execution
|
||||
* - GC pauses moved to idle periods where users won't notice
|
||||
* - Especially effective for interactive applications
|
||||
* - Improves Time-to-Interactive and First Input Delay metrics
|
||||
*
|
||||
* Tradeoffs:
|
||||
* - May accumulate more garbage before collection
|
||||
* - Requires predictable idle periods (not suitable for all workloads)
|
||||
* - Critical memory pressure GCs still proceed immediately
|
||||
*
|
||||
* Tuning:
|
||||
* - Lower threshold (50ms) = more frequent GC, less memory overhead
|
||||
* - Higher threshold (200ms) = less GC overhead, more memory usage
|
||||
* - Optimal value depends on application's execution pattern
|
||||
*
|
||||
* Testing
|
||||
* -------
|
||||
*
|
||||
* Unit Tests:
|
||||
* // Test idle detection
|
||||
* JS_SetIdleGCThreshold(cx, 100);
|
||||
* // Simulate JS execution
|
||||
* cx->runtime()->gc.notifyJSExecutionStart();
|
||||
* // ... wait 50ms ...
|
||||
* MOZ_ASSERT(!cx->runtime()->gc.idleGCMgr().isIdleEnough());
|
||||
* cx->runtime()->gc.notifyJSExecutionEnd();
|
||||
* // ... wait 150ms ...
|
||||
* MOZ_ASSERT(cx->runtime()->gc.idleGCMgr().isIdleEnough());
|
||||
*
|
||||
* Integration Tests:
|
||||
* - Verify GC is deferred during active execution
|
||||
* - Verify GC proceeds after idle period
|
||||
* - Verify critical GC reasons bypass idle check
|
||||
* - Measure latency improvements
|
||||
*
|
||||
* Implementation Notes
|
||||
* --------------------
|
||||
*
|
||||
* Thread Safety:
|
||||
* - IdleGCManager uses mozilla::Atomic for thread-safe state
|
||||
* - TimeStamp operations are atomic
|
||||
* - No additional locking needed beyond existing GC locks
|
||||
*
|
||||
* Compatibility:
|
||||
* - Works with both incremental and non-incremental GC
|
||||
* - Compatible with generational GC
|
||||
* - Works with zone GC and full GC
|
||||
* - Respects existing GC suppression mechanisms
|
||||
*
|
||||
* Future Enhancements
|
||||
* -------------------
|
||||
*
|
||||
* Potential improvements:
|
||||
* - Adaptive idle threshold based on historical GC times
|
||||
* - Per-zone idle configuration
|
||||
* - Integration with browser rendering idle callback API
|
||||
* - Metrics/telemetry for idle GC effectiveness
|
||||
* - Machine learning-based prediction of idle periods
|
||||
* - Cooperative GC scheduling with other subsystems
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gc/IdleGC.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
IdleGCManager::IdleGCManager()
|
||||
: lastExecutionTime_(mozilla::TimeStamp::Now()),
|
||||
idleGCEnabled_(true),
|
||||
idleThresholdMs_(100), // 100ms default idle threshold
|
||||
isExecuting_(false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
IdleGCManager::notifyJSExecutionStart()
|
||||
{
|
||||
isExecuting_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
IdleGCManager::notifyJSExecutionEnd()
|
||||
{
|
||||
isExecuting_ = false;
|
||||
lastExecutionTime_ = mozilla::TimeStamp::Now();
|
||||
}
|
||||
|
||||
bool
|
||||
IdleGCManager::isIdleEnough() const
|
||||
{
|
||||
if (!idleGCEnabled_) {
|
||||
return true; // If disabled, always consider idle
|
||||
}
|
||||
|
||||
if (isExecuting_) {
|
||||
return false; // Still executing, not idle
|
||||
}
|
||||
|
||||
uint64_t idleTime = idleTimeSinceLastExecution();
|
||||
return idleTime >= idleThresholdMs_;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
IdleGCManager::idleTimeSinceLastExecution() const
|
||||
{
|
||||
mozilla::TimeStamp now = mozilla::TimeStamp::Now();
|
||||
mozilla::TimeDuration idle = now - lastExecutionTime_;
|
||||
return idle.ToMilliseconds();
|
||||
}
|
||||
|
||||
bool
|
||||
IdleGCManager::shouldBypassIdleCheck(JS::gcreason::Reason reason)
|
||||
{
|
||||
// These reasons indicate urgent GC needs that should bypass idle checking
|
||||
switch (reason) {
|
||||
// Allocation and memory pressure conditions.
|
||||
case JS::gcreason::ALLOC_TRIGGER:
|
||||
case JS::gcreason::EAGER_ALLOC_TRIGGER:
|
||||
case JS::gcreason::TOO_MUCH_MALLOC:
|
||||
case JS::gcreason::MEM_PRESSURE:
|
||||
case JS::gcreason::LAST_DITCH:
|
||||
|
||||
// Nursery/store-buffer pressure.
|
||||
case JS::gcreason::OUT_OF_NURSERY:
|
||||
case JS::gcreason::EVICT_NURSERY:
|
||||
case JS::gcreason::FULL_STORE_BUFFER:
|
||||
case JS::gcreason::SHARED_MEMORY_LIMIT:
|
||||
|
||||
// Explicit API calls
|
||||
case JS::gcreason::API:
|
||||
case JS::gcreason::ABORT_GC:
|
||||
|
||||
// Shutdown and finalization
|
||||
case JS::gcreason::SHUTDOWN_CC:
|
||||
case JS::gcreason::DESTROY_RUNTIME:
|
||||
case JS::gcreason::NSJSCONTEXT_DESTROY:
|
||||
case JS::gcreason::XPCONNECT_SHUTDOWN:
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IdleGCManager::reset()
|
||||
{
|
||||
lastExecutionTime_ = mozilla::TimeStamp::Now();
|
||||
isExecuting_ = false;
|
||||
}
|
||||
|
||||
} // namespace gc
|
||||
} // namespace js
|
||||
@@ -1,118 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef gc_IdleGC_h
|
||||
#define gc_IdleGC_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "js/GCAPI.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* Idle-Time Garbage Collection System
|
||||
* ====================================
|
||||
*
|
||||
* This system defers garbage collection to occur only during periods when
|
||||
* the browser is not actively processing JavaScript. This helps maintain
|
||||
* responsiveness by avoiding GC pauses during critical execution windows.
|
||||
*
|
||||
* When JavaScript execution is active, GC triggers are deferred. Once the
|
||||
* JS engine has been idle for a configurable threshold period, pending GC
|
||||
* work is performed immediately or incrementally as appropriate.
|
||||
*
|
||||
* Key characteristics:
|
||||
* - Tracks JavaScript activity via hooks in the execution engine
|
||||
* - Configurable idle time threshold (default: 100ms)
|
||||
* - Can be disabled per-zone or globally
|
||||
* - Works with both incremental and non-incremental GC modes
|
||||
* - Respects critical GC reasons that override idle checking
|
||||
*/
|
||||
|
||||
class IdleGCManager
|
||||
{
|
||||
public:
|
||||
// Initialize the idle GC manager
|
||||
IdleGCManager();
|
||||
|
||||
/*
|
||||
* Called when JavaScript execution begins. Marks the engine as active.
|
||||
*/
|
||||
void notifyJSExecutionStart();
|
||||
|
||||
/*
|
||||
* Called when JavaScript execution ends. Records the end time for
|
||||
* idle detection purposes.
|
||||
*/
|
||||
void notifyJSExecutionEnd();
|
||||
|
||||
/*
|
||||
* Check if the system has been idle for long enough to permit GC.
|
||||
* Returns true if sufficient idle time has passed since last JS execution.
|
||||
*/
|
||||
bool isIdleEnough() const;
|
||||
|
||||
/*
|
||||
* Get the amount of idle time since the last JS execution.
|
||||
* Returns time in milliseconds.
|
||||
*/
|
||||
uint64_t idleTimeSinceLastExecution() const;
|
||||
|
||||
/*
|
||||
* Set the idle threshold - minimum idle time before GC is permitted.
|
||||
* Time is in milliseconds. Default is 100ms.
|
||||
*/
|
||||
void setIdleThresholdMs(uint64_t thresholdMs) {
|
||||
idleThresholdMs_ = thresholdMs;
|
||||
}
|
||||
|
||||
uint64_t idleThresholdMs() const {
|
||||
return idleThresholdMs_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable idle-time-only GC mode.
|
||||
*/
|
||||
void setIdleGCEnabled(bool enabled) {
|
||||
idleGCEnabled_ = enabled;
|
||||
}
|
||||
|
||||
bool isIdleGCEnabled() const {
|
||||
return idleGCEnabled_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a GC reason should bypass idle checking.
|
||||
* Critical reasons (OOM-like pressure, nursery pressure, explicit requests)
|
||||
* always proceed.
|
||||
*/
|
||||
static bool shouldBypassIdleCheck(JS::gcreason::Reason reason);
|
||||
|
||||
/*
|
||||
* Reset idle tracking state (used during GC or at shutdown).
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
// Timestamp of the last JavaScript execution activity
|
||||
mozilla::TimeStamp lastExecutionTime_;
|
||||
|
||||
// Whether idle-time-only GC mode is enabled
|
||||
mozilla::Atomic<bool, mozilla::ReleaseAcquire> idleGCEnabled_;
|
||||
|
||||
// Minimum idle time (in milliseconds) before GC is permitted
|
||||
mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> idleThresholdMs_;
|
||||
|
||||
// Whether the JS engine is currently executing
|
||||
mozilla::Atomic<bool, mozilla::ReleaseAcquire> isExecuting_;
|
||||
};
|
||||
|
||||
} // namespace gc
|
||||
} // namespace js
|
||||
|
||||
#endif // gc_IdleGC_h
|
||||
@@ -1495,36 +1495,6 @@ JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem)
|
||||
JS_SetGCParameter(cx, config[i].key, config[i].value);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetIdleGCEnabled(JSContext* cx, bool enabled)
|
||||
{
|
||||
cx->gc.idleGCMgr().setIdleGCEnabled(enabled);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_IsIdleGCEnabled(JSContext* cx)
|
||||
{
|
||||
return cx->gc.idleGCMgr().isIdleGCEnabled();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetIdleGCThreshold(JSContext* cx, uint64_t milliseconds)
|
||||
{
|
||||
cx->gc.idleGCMgr().setIdleThresholdMs(milliseconds);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint64_t)
|
||||
JS_GetIdleGCThreshold(JSContext* cx)
|
||||
{
|
||||
return cx->gc.idleGCMgr().idleThresholdMs();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint64_t)
|
||||
JS_GetIdleTimeSinceLastExecution(JSContext* cx)
|
||||
{
|
||||
return cx->gc.idleGCMgr().idleTimeSinceLastExecution();
|
||||
}
|
||||
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length,
|
||||
|
||||
@@ -1758,40 +1758,6 @@ JS_GetGCParameter(JSContext* cx, JSGCParamKey key);
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem);
|
||||
|
||||
/*
|
||||
* Idle-time garbage collection control.
|
||||
* These functions allow control over when GC occurs - specifically, whether
|
||||
* GC should only run when the browser/application is not doing active JS work.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enable or disable idle-time-only GC mode.
|
||||
* When enabled, GC is deferred until the JS engine has been idle for the
|
||||
* configured threshold period (default: 100ms).
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetIdleGCEnabled(JSContext* cx, bool enabled);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsIdleGCEnabled(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Set the minimum idle time (in milliseconds) before GC is permitted.
|
||||
* Use this to configure how long the JS engine must be inactive before
|
||||
* pending GC work can proceed.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetIdleGCThreshold(JSContext* cx, uint64_t milliseconds);
|
||||
|
||||
extern JS_PUBLIC_API(uint64_t)
|
||||
JS_GetIdleGCThreshold(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Get the current idle time since the last JS execution.
|
||||
*/
|
||||
extern JS_PUBLIC_API(uint64_t)
|
||||
JS_GetIdleTimeSinceLastExecution(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Create a new JSString whose chars member refers to external memory, i.e.,
|
||||
* memory requiring application-specific finalization.
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
#include "gc/FindSCCs.h"
|
||||
#include "gc/GCInternals.h"
|
||||
#include "gc/GCTrace.h"
|
||||
#include "gc/IdleGC.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Memory.h"
|
||||
#include "gc/Policy.h"
|
||||
@@ -6013,10 +6012,6 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
|
||||
if (rt->isBeingDestroyed() && !IsShutdownGC(reason))
|
||||
return false;
|
||||
|
||||
// Check if the system is idle enough for GC, unless this is a critical GC
|
||||
if (!IdleGCManager::shouldBypassIdleCheck(reason) && !idleGC.isIdleEnough())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6180,18 +6175,6 @@ GCRuntime::notifyDidPaint()
|
||||
interFrameGC = false;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::notifyJSExecutionStart()
|
||||
{
|
||||
idleGC.notifyJSExecutionStart();
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::notifyJSExecutionEnd()
|
||||
{
|
||||
idleGC.notifyJSExecutionEnd();
|
||||
}
|
||||
|
||||
static bool
|
||||
ZonesSelected(JSRuntime* rt)
|
||||
{
|
||||
|
||||
@@ -216,7 +216,6 @@ main_deunified_sources = [
|
||||
'gc/Allocator.cpp',
|
||||
'gc/Barrier.cpp',
|
||||
'gc/GCTrace.cpp',
|
||||
'gc/IdleGC.cpp',
|
||||
'gc/Iteration.cpp',
|
||||
'gc/Marking.cpp',
|
||||
'gc/Memory.cpp',
|
||||
|
||||
@@ -747,12 +747,6 @@ JSRuntime::traceSharedIntlData(JSTracer* trc)
|
||||
void
|
||||
JSRuntime::triggerActivityCallback(bool active)
|
||||
{
|
||||
if (active) {
|
||||
gc.notifyJSExecutionStart();
|
||||
} else {
|
||||
gc.notifyJSExecutionEnd();
|
||||
}
|
||||
|
||||
if (!activityCallback)
|
||||
return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user