Commit 2b64eec0 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com
Browse files

GC activity timer should be tied to allocation, not collection

https://bugs.webkit.org/show_bug.cgi?id=83919

Reviewed by Geoffrey Garen.

* API/JSContextRef.cpp: Used the new didAbandonObjectGraph callback to indicate that now that we've
released a global object, we're abandoning a potentially large number of objects that JSC might want
to collect.
* heap/CopiedSpace.cpp:
(JSC::CopiedSpace::tryAllocateSlowCase): Added the call to timer's willAllocate function to indicate
that we've hit a slow path and are allocating now, so schedule the timer.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::collectAllGarbage): Removed the call to discardAllCompiledCode because it was causing us to
throw away too much code during our benchmarks (especially vp8, which is very large and thus has large
amounts of compiled code).
(JSC::Heap::collect): Added the new call to didCollect at the conclusion of a collection so that we
can cancel the timer if we no longer need to run a collection. Also added a check at the beginning of a
collection to see if we should throw away our compiled code. Currently this is set to happen about once
every minute.
* heap/Heap.h: Added field to keep track of the last time we threw away our compiled code.
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCase): Added call to willAllocate on the allocation slow path, just like
in CopiedSpace.
* runtime/GCActivityCallback.cpp: Added default stubs for non-CF platforms.
(JSC::DefaultGCActivityCallback::willAllocate):
(JSC):
(JSC::DefaultGCActivityCallback::didCollect):
(JSC::DefaultGCActivityCallback::didAbandonObjectGraph):
* runtime/GCActivityCallback.h: Added new functions to make JSC's GC timer less arcane. This includes replacing
the operator () with willAllocate() and adding an explicit didCollect() to cancel the timer after a collection
occurs rather than relying on the way the timer is invoked to cancel itself. Also added a callback for
when somebody else (e.g. WebCore or the JSC API) to notify JSC that they have just abandoned an entire graph of
objects and that JSC might want to clean them up.
(JSC::GCActivityCallback::~GCActivityCallback):
(JSC::GCActivityCallback::willAllocate):
(JSC::GCActivityCallback::didCollect):
(JSC::GCActivityCallback::didAbandonObjectGraph):
(JSC::GCActivityCallback::synchronize):
(DefaultGCActivityCallback):
* runtime/GCActivityCallbackCF.cpp: Re-wired all the run loop stuff to implement the aforementioned functions.
We added a flag to check whether the timer was active because the call to CFRunLoopTimerSetNextFireDate actually
turned out to be quite expensive (although Instruments couldn't tell us this).
(DefaultGCActivityCallbackPlatformData):
(JSC):
(JSC::DefaultGCActivityCallbackPlatformData::timerDidFire):
(JSC::DefaultGCActivityCallback::commonConstructor):
(JSC::scheduleTimer):
(JSC::cancelTimer):
(JSC::DefaultGCActivityCallback::willAllocate):
(JSC::DefaultGCActivityCallback::didCollect):
(JSC::DefaultGCActivityCallback::didAbandonObjectGraph):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@114511 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c0fc313a
......@@ -149,7 +149,7 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx)
globalData.heap.destroy();
} else if (releasingGlobalObject) {
globalData.heap.activityCallback()->synchronize();
(*globalData.heap.activityCallback())();
globalData.heap.activityCallback()->didAbandonObjectGraph();
}
globalData.deref();
......
2012-04-18 Mark Hahnenberg <mhahnenberg@apple.com>
GC activity timer should be tied to allocation, not collection
https://bugs.webkit.org/show_bug.cgi?id=83919
Reviewed by Geoffrey Garen.
* API/JSContextRef.cpp: Used the new didAbandonObjectGraph callback to indicate that now that we've
released a global object, we're abandoning a potentially large number of objects that JSC might want
to collect.
* heap/CopiedSpace.cpp:
(JSC::CopiedSpace::tryAllocateSlowCase): Added the call to timer's willAllocate function to indicate
that we've hit a slow path and are allocating now, so schedule the timer.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::collectAllGarbage): Removed the call to discardAllCompiledCode because it was causing us to
throw away too much code during our benchmarks (especially vp8, which is very large and thus has large
amounts of compiled code).
(JSC::Heap::collect): Added the new call to didCollect at the conclusion of a collection so that we
can cancel the timer if we no longer need to run a collection. Also added a check at the beginning of a
collection to see if we should throw away our compiled code. Currently this is set to happen about once
every minute.
* heap/Heap.h: Added field to keep track of the last time we threw away our compiled code.
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCase): Added call to willAllocate on the allocation slow path, just like
in CopiedSpace.
* runtime/GCActivityCallback.cpp: Added default stubs for non-CF platforms.
(JSC::DefaultGCActivityCallback::willAllocate):
(JSC):
(JSC::DefaultGCActivityCallback::didCollect):
(JSC::DefaultGCActivityCallback::didAbandonObjectGraph):
* runtime/GCActivityCallback.h: Added new functions to make JSC's GC timer less arcane. This includes replacing
the operator () with willAllocate() and adding an explicit didCollect() to cancel the timer after a collection
occurs rather than relying on the way the timer is invoked to cancel itself. Also added a callback for
when somebody else (e.g. WebCore or the JSC API) to notify JSC that they have just abandoned an entire graph of
objects and that JSC might want to clean them up.
(JSC::GCActivityCallback::~GCActivityCallback):
(JSC::GCActivityCallback::willAllocate):
(JSC::GCActivityCallback::didCollect):
(JSC::GCActivityCallback::didAbandonObjectGraph):
(JSC::GCActivityCallback::synchronize):
(DefaultGCActivityCallback):
* runtime/GCActivityCallbackCF.cpp: Re-wired all the run loop stuff to implement the aforementioned functions.
We added a flag to check whether the timer was active because the call to CFRunLoopTimerSetNextFireDate actually
turned out to be quite expensive (although Instruments couldn't tell us this).
(DefaultGCActivityCallbackPlatformData):
(JSC):
(JSC::DefaultGCActivityCallbackPlatformData::timerDidFire):
(JSC::DefaultGCActivityCallback::commonConstructor):
(JSC::scheduleTimer):
(JSC::cancelTimer):
(JSC::DefaultGCActivityCallback::willAllocate):
(JSC::DefaultGCActivityCallback::didCollect):
(JSC::DefaultGCActivityCallback::didAbandonObjectGraph):
2012-04-17 Filip Pizlo <fpizlo@apple.com>
 
DFG should not attempt to get rare case counts for op_mod on ARM
......@@ -27,6 +27,7 @@
#include "CopiedSpace.h"
#include "CopiedSpaceInlineMethods.h"
#include "GCActivityCallback.h"
namespace JSC {
......@@ -51,6 +52,8 @@ void CopiedSpace::init()
CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr)
{
m_heap->activityCallback()->willAllocate();
if (isOversize(bytes))
return tryAllocateOversize(bytes, outPtr);
......
......@@ -328,8 +328,8 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize)
, m_isSafeToCollect(false)
, m_globalData(globalData)
, m_lastGCLength(0)
, m_lastCodeDiscardTime(WTF::currentTime())
{
(*m_activityCallback)();
m_numberOfFreeBlocks = 0;
m_blockFreeingThread = createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree");
......@@ -783,11 +783,12 @@ void Heap::collectAllGarbage()
{
if (!m_isSafeToCollect)
return;
discardAllCompiledCode();
collect(DoSweep);
}
static double minute = 60.0;
void Heap::collect(SweepToggle sweepToggle)
{
SamplingRegion samplingRegion("Garbage Collection");
......@@ -796,7 +797,13 @@ void Heap::collect(SweepToggle sweepToggle)
ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
ASSERT(m_isSafeToCollect);
JAVASCRIPTCORE_GC_BEGIN();
double lastGCStartTime = WTF::currentTime();
if (lastGCStartTime - m_lastCodeDiscardTime > minute) {
discardAllCompiledCode();
m_lastCodeDiscardTime = WTF::currentTime();
}
#if ENABLE(GGC)
bool fullGC = sweepToggle == DoSweep;
if (!fullGC)
......@@ -855,7 +862,7 @@ void Heap::collect(SweepToggle sweepToggle)
m_lastGCLength = lastGCEndTime - lastGCStartTime;
JAVASCRIPTCORE_GC_END();
(*m_activityCallback)();
m_activityCallback->didCollect();
}
void Heap::canonicalizeCellLivenessData()
......
......@@ -247,6 +247,7 @@ namespace JSC {
JSGlobalData* m_globalData;
double m_lastGCLength;
double m_lastCodeDiscardTime;
DoublyLinkedList<FunctionExecutable> m_functions;
};
......
#include "config.h"
#include "MarkedAllocator.h"
#include "GCActivityCallback.h"
#include "Heap.h"
namespace JSC {
......@@ -41,6 +42,8 @@ void* MarkedAllocator::allocateSlowCase()
ASSERT(m_heap->m_operationInProgress == NoOperation);
#endif
m_heap->activityCallback()->willAllocate();
void* result = tryAllocate();
if (LIKELY(result != 0))
......
......@@ -42,7 +42,15 @@ DefaultGCActivityCallback::~DefaultGCActivityCallback()
{
}
void DefaultGCActivityCallback::operator()()
void DefaultGCActivityCallback::willAllocate()
{
}
void DefaultGCActivityCallback::didCollect()
{
}
void DefaultGCActivityCallback::didAbandonObjectGraph()
{
}
......
......@@ -42,9 +42,11 @@ class Heap;
class GCActivityCallback {
public:
virtual ~GCActivityCallback() {}
virtual void operator()() {}
virtual void synchronize() {}
virtual ~GCActivityCallback() { }
virtual void willAllocate() { }
virtual void didCollect() { }
virtual void didAbandonObjectGraph() { }
virtual void synchronize() { }
protected:
GCActivityCallback() {}
......@@ -57,10 +59,12 @@ public:
static PassOwnPtr<DefaultGCActivityCallback> create(Heap*);
DefaultGCActivityCallback(Heap*);
~DefaultGCActivityCallback();
virtual ~DefaultGCActivityCallback();
void operator()();
void synchronize();
virtual void willAllocate();
virtual void didCollect();
virtual void didAbandonObjectGraph();
virtual void synchronize();
#if USE(CF)
protected:
......
......@@ -45,21 +45,24 @@
namespace JSC {
struct DefaultGCActivityCallbackPlatformData {
static void trigger(CFRunLoopTimerRef, void *info);
static void timerDidFire(CFRunLoopTimerRef, void *info);
RetainPtr<CFRunLoopTimerRef> timer;
RetainPtr<CFRunLoopRef> runLoop;
CFRunLoopTimerContext context;
bool timerIsActive;
};
const double gcCPUBudget = 0.025;
const double gcTimerIntervalMultiplier = 1.0 / gcCPUBudget;
const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10;
const CFTimeInterval hour = 60 * 60;
void DefaultGCActivityCallbackPlatformData::trigger(CFRunLoopTimerRef timer, void *info)
void DefaultGCActivityCallbackPlatformData::timerDidFire(CFRunLoopTimerRef, void *info)
{
Heap* heap = static_cast<Heap*>(info);
APIEntryShim shim(heap->globalData());
heap->collectAllGarbage();
CFRunLoopTimerSetNextFireDate(timer, CFAbsoluteTimeGetCurrent() + decade);
}
DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
......@@ -88,16 +91,43 @@ void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLo
memset(&d->context, 0, sizeof(CFRunLoopTimerContext));
d->context.info = heap;
d->runLoop = runLoop;
d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::trigger, &d->context));
d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::timerDidFire, &d->context));
d->timerIsActive = false;
CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
}
void DefaultGCActivityCallback::operator()()
static void scheduleTimer(DefaultGCActivityCallbackPlatformData* d)
{
CFTimeInterval triggerInterval = static_cast<Heap*>(d->context.info)->lastGCLength() * 100.0;
if (d->timerIsActive)
return;
d->timerIsActive = true;
CFTimeInterval triggerInterval = static_cast<Heap*>(d->context.info)->lastGCLength() * gcTimerIntervalMultiplier;
CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + triggerInterval);
}
static void cancelTimer(DefaultGCActivityCallbackPlatformData* d)
{
if (!d->timerIsActive)
return;
d->timerIsActive = false;
CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + decade);
}
void DefaultGCActivityCallback::willAllocate()
{
scheduleTimer(d.get());
}
void DefaultGCActivityCallback::didCollect()
{
cancelTimer(d.get());
}
void DefaultGCActivityCallback::didAbandonObjectGraph()
{
scheduleTimer(d.get());
}
void DefaultGCActivityCallback::synchronize()
{
if (CFRunLoopGetCurrent() == d->runLoop.get())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment