Esempio n. 1
0
PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorUpdateCountersEvent::data()
{
    RefPtr<JSONObject> data = JSONObject::create();
    if (isMainThread()) {
        data->setNumber("documents", InspectorCounters::counterValue(InspectorCounters::DocumentCounter));
        data->setNumber("nodes", InspectorCounters::counterValue(InspectorCounters::NodeCounter));
        data->setNumber("jsEventListeners", InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter));
    }
    data->setNumber("jsHeapSizeUsed", static_cast<double>(usedHeapSize()));
    return TracedValue::fromJSONValue(data);
}
void V8GCController::gcPrologue(v8::Isolate* isolate, v8::GCType type, v8::GCCallbackFlags flags)
{
    if (isMainThread())
        ScriptForbiddenScope::enter();

    // TODO(haraken): A GC callback is not allowed to re-enter V8. This means
    // that it's unsafe to run Oilpan's GC in the GC callback because it may
    // run finalizers that call into V8. To avoid the risk, we should post
    // a task to schedule the Oilpan's GC.
    // (In practice, there is no finalizer that calls into V8 and thus is safe.)

    v8::HandleScope scope(isolate);
    switch (type) {
    case v8::kGCTypeScavenge:
        if (ThreadState::current())
            ThreadState::current()->willStartV8GC(BlinkGC::V8MinorGC);

        TRACE_EVENT_BEGIN1("devtools.timeline,v8", "MinorGC", "usedHeapSizeBefore", usedHeapSize(isolate));
        visitWeakHandlesForMinorGC(isolate);
        break;
    case v8::kGCTypeMarkSweepCompact:
        if (ThreadState::current())
            ThreadState::current()->willStartV8GC(BlinkGC::V8MajorGC);

        TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC", "usedHeapSizeBefore", usedHeapSize(isolate), "type", "atomic pause");
        gcPrologueForMajorGC(isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
        break;
    case v8::kGCTypeIncrementalMarking:
        if (ThreadState::current())
            ThreadState::current()->willStartV8GC(BlinkGC::V8MajorGC);

        TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC", "usedHeapSizeBefore", usedHeapSize(isolate), "type", "incremental marking");
        gcPrologueForMajorGC(isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
        break;
    case v8::kGCTypeProcessWeakCallbacks:
        TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC", "usedHeapSizeBefore", usedHeapSize(isolate), "type", "weak processing");
        break;
    default:
        ASSERT_NOT_REACHED();
    }
}
Esempio n. 3
0
void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type)
{
    // An empty stack could merely mean that the timeline agent was turned on in the middle of
    // an event.  Don't treat as an error.
    if (!m_recordStack.isEmpty()) {
        TimelineRecordEntry entry = m_recordStack.last();
        m_recordStack.removeLast();
        ASSERT(entry.type == type);
        entry.record->setObject("data", entry.data);
        entry.record->setArray("children", entry.children);
        entry.record->setNumber("endTime", timestamp());
        size_t usedHeapSizeDelta = usedHeapSize() - entry.usedHeapSizeAtStart;
        if (usedHeapSizeDelta)
            entry.record->setNumber("usedHeapSizeDelta", usedHeapSizeDelta);
        addRecordToTimeline(entry.record, type);
    }
}
Esempio n. 4
0
void InspectorTimelineAgent::setDOMCounters(TypeBuilder::Timeline::TimelineEvent* record)
{
    record->setUsedHeapSize(usedHeapSize());

    if (m_includeDOMCounters) {
        int documentCount = 0;
        int nodeCount = 0;
        if (m_inspectorType == PageInspector) {
            documentCount = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
            nodeCount = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
        }
        int listenerCount = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter);
        RefPtr<TypeBuilder::Timeline::DOMCounters> counters = TypeBuilder::Timeline::DOMCounters::create()
                .setDocuments(documentCount)
                .setNodes(nodeCount)
                .setJsEventListeners(listenerCount);
        record->setCounters(counters.release());
    }
}
void V8GCController::gcEpilogue(v8::Isolate* isolate, v8::GCType type, v8::GCCallbackFlags flags)
{
    switch (type) {
    case v8::kGCTypeScavenge:
        TRACE_EVENT_END1("devtools.timeline,v8", "MinorGC", "usedHeapSizeAfter", usedHeapSize(isolate));
        // TODO(haraken): Remove this. See the comment in gcPrologue.
        if (ThreadState::current())
            ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MinorGC);
        break;
    case v8::kGCTypeMarkSweepCompact:
        TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate));
        if (ThreadState::current())
            ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MajorGC);
        break;
    case v8::kGCTypeIncrementalMarking:
        TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate));
        break;
    case v8::kGCTypeProcessWeakCallbacks:
        TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate));
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    if (isMainThread())
        ScriptForbiddenScope::exit();

    // v8::kGCCallbackFlagForced forces a Blink heap garbage collection
    // when a garbage collection was forced from V8. This is either used
    // for tests that force GCs from JavaScript to verify that objects die
    // when expected.
    if (flags & v8::kGCCallbackFlagForced) {
        // This single GC is not enough for two reasons:
        //   (1) The GC is not precise because the GC scans on-stack pointers conservatively.
        //   (2) One GC is not enough to break a chain of persistent handles. It's possible that
        //       some heap allocated objects own objects that contain persistent handles
        //       pointing to other heap allocated objects. To break the chain, we need multiple GCs.
        //
        // Regarding (1), we force a precise GC at the end of the current event loop. So if you want
        // to collect all garbage, you need to wait until the next event loop.
        // Regarding (2), it would be OK in practice to trigger only one GC per gcEpilogue, because
        // GCController.collectAll() forces multiple V8's GC.
        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::ForcedGC);

        // Forces a precise GC at the end of the current event loop.
        if (ThreadState::current()) {
            RELEASE_ASSERT(!ThreadState::current()->isInGC());
            ThreadState::current()->setGCState(ThreadState::FullGCScheduled);
        }
    }

    // v8::kGCCallbackFlagCollectAllAvailableGarbage is used when V8 handles
    // low memory notifications.
    if (flags & v8::kGCCallbackFlagCollectAllAvailableGarbage) {
        // This single GC is not enough. See the above comment.
        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::ForcedGC);

        // Do not force a precise GC at the end of the current event loop.
        // According to UMA stats, the collection rate of the precise GC
        // scheduled at the end of the low memory handling is extremely low,
        // because the above conservative GC is sufficient for collecting
        // most objects. So we intentionally don't schedule a precise GC here.
    }

    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data());
}
Esempio n. 6
0
void V8GCController::gcEpilogue(v8::GCType type, v8::GCCallbackFlags flags)
{
    // FIXME: It would be nice if the GC callbacks passed the Isolate directly....
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    if (type == v8::kGCTypeScavenge)
        minorGCEpilogue(isolate);
    else if (type == v8::kGCTypeMarkSweepCompact)
        majorGCEpilogue(isolate);

    // Forces a Blink heap garbage collection when a garbage collection
    // was forced from V8. This is used for tests that force GCs from
    // JavaScript to verify that objects die when expected.
    if (flags & v8::kGCCallbackFlagForced) {
        // This single GC is not enough for two reasons:
        //   (1) The GC is not precise because the GC scans on-stack pointers conservatively.
        //   (2) One GC is not enough to break a chain of persistent handles. It's possible that
        //       some heap allocated objects own objects that contain persistent handles
        //       pointing to other heap allocated objects. To break the chain, we need multiple GCs.
        //
        // Regarding (1), we force a precise GC at the end of the current event loop. So if you want
        // to collect all garbage, you need to wait until the next event loop.
        // Regarding (2), it would be OK in practice to trigger only one GC per gcEpilogue, because
        // GCController.collectAll() forces 7 V8's GC.
        Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::ForcedGC);

        // Forces a precise GC at the end of the current event loop.
        Heap::setForcePreciseGCForTesting();
    }

    TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GCEvent", "usedHeapSizeAfter", usedHeapSize(isolate));
    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
}
Esempio n. 7
0
void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags)
{
    // FIXME: It would be nice if the GC callbacks passed the Isolate directly....
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GCEvent", "usedHeapSizeBefore", usedHeapSize(isolate));
    if (type == v8::kGCTypeScavenge)
        minorGCPrologue(isolate);
    else if (type == v8::kGCTypeMarkSweepCompact)
        majorGCPrologue(isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
}
Esempio n. 8
0
void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame)
{
    commitFrameRecord();
    RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
    setFrameIdentifier(record.get(), frame);
    m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type, usedHeapSize()));
}