Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
[Blink] Add in-depth allocation tracker
Browse files Browse the repository at this point in the history
BUG=XWALK-5109

This patch includes in-depth allocation tracker and extention of
protocol.json by stackEntryLine that is used for total time
annotations in CPU profiling

Details of HeapProfiler: Three new commands were added by analogy with
Chrome DevTools allocation tracker. Start/Stop and Event which is sent by timer.
Command stopTrackingHeapXDK accepts three parameters: stack depth for
unwinding, Sample After Value - period of timer and a flag to collect retention
information or not. Event sends to the host currently collected data about
symbols/callstack/objects. Command stopTrackingHeapXDK returns the final
info witch is similar to Event passed format with one more parameter:
duration of the collection.

Basing on this info consumer can build allocation call tree for any period
of time, annotate source by self and total allocation mertics and annotate
allocation call tree by the objects, which retain other objects in the
memory.

P.S.: This is a refactoring of the XDK patches for blink-crosswalk. Some blink
functionality was moved from one place to another and we had to rework the
patch.

The original patches are: 3c5a049, 89c615a, 0626260 in blink-crosswalk.
  • Loading branch information
Sergey Mishenkov authored and Mrunal Kapade committed Nov 20, 2015
1 parent ccf6775 commit b6447eb
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,20 @@ class InspectorHeapProfilerAgent::HeapStatsUpdateTask final : public NoBaseWillB
Timer<HeapStatsUpdateTask> m_timer;
};


class InspectorHeapProfilerAgent::HeapXDKUpdateTask final : public NoBaseWillBeGarbageCollectedFinalized<InspectorHeapProfilerAgent::HeapXDKUpdateTask>{
public:
HeapXDKUpdateTask(InspectorHeapProfilerAgent*);
void startTimer(float sav);
void resetTimer() { m_timer.stop(); }
void onTimer(Timer<HeapXDKUpdateTask>*);

private:
InspectorHeapProfilerAgent* m_heapProfilerAgent;
Timer<HeapXDKUpdateTask> m_timer;
};


PassOwnPtrWillBeRawPtr<InspectorHeapProfilerAgent> InspectorHeapProfilerAgent::create(v8::Isolate* isolate, InjectedScriptManager* injectedScriptManager)
{
return adoptPtrWillBeNoop(new InspectorHeapProfilerAgent(isolate, injectedScriptManager));
Expand Down Expand Up @@ -386,5 +400,118 @@ DEFINE_TRACE(InspectorHeapProfilerAgent)
InspectorBaseAgent::trace(visitor);
}

static PassRefPtr<TypeBuilder::HeapProfiler::HeapEventXDK> createHeapProfileXDK(const HeapProfileXDK& heapProfileXDK)
{
RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK> profile = TypeBuilder::HeapProfiler::HeapEventXDK::create()
.setDuration(heapProfileXDK.getDuration())
.setSymbols(heapProfileXDK.getSymbols())
.setFrames(heapProfileXDK.getFrames())
.setTypes(heapProfileXDK.getTypes())
.setChunks(heapProfileXDK.getChunks())
.setRetentions(heapProfileXDK.getRetentions());
return profile.release();
}

InspectorHeapProfilerAgent::HeapXDKUpdateTask::HeapXDKUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
: m_heapProfilerAgent(heapProfilerAgent)
, m_timer(this, &HeapXDKUpdateTask::onTimer)
{
}

void InspectorHeapProfilerAgent::HeapXDKUpdateTask::onTimer(Timer<HeapXDKUpdateTask>*)
{
// The timer is stopped on m_heapProfilerAgent destruction,
// so this method will never be called after m_heapProfilerAgent has been destroyed.
m_heapProfilerAgent->requestHeapXDKUpdate();
}

void InspectorHeapProfilerAgent::HeapXDKUpdateTask::startTimer(float sav)
{
ASSERT(!m_timer.isActive());
m_timer.startRepeating(sav, FROM_HERE);
}

void InspectorHeapProfilerAgent::startTrackingHeapXDK(ErrorString*,
const int* stack_depth,
const int* sav,
const bool* retentions)
{
m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);

// inline of startTrackingHeapObjectsInternal(allocationTrackingEnabled);
if (m_heapXDKUpdateTask)
return;
int stackDepth = 8;
if (stack_depth) {
stackDepth = *stack_depth;
}
float sav_timer = 1;
if (sav) {
sav_timer = (float)*sav / 1000.;
}
bool needRetentions = retentions && *retentions;
InspectorProfilerAgent::startTrackingHeapObjectsXDK(stackDepth, needRetentions);
m_heapXDKUpdateTask = adoptPtr(new HeapXDKUpdateTask(this));
m_heapXDKUpdateTask->startTimer(sav_timer);
}

class InspectorHeapProfilerAgent::HeapXDKStream final : public InspectorProfilerAgent::OutputStream{
public:
HeapXDKStream(InspectorHeapProfilerAgent* heapProfilerAgent)
: m_heapProfilerAgent(heapProfilerAgent)
{
}

virtual void write(const uint32_t* chunk, const int size){}
virtual void write(const char* symbols, int symbolsSize,
const char* frames, int framesSize,
const char* types, int typesSize,
const char* chunks, int chunksSize,
const char* retentions, int retentionsSize) override
{
m_heapProfilerAgent->pushHeapXDKUpdate(symbols, symbolsSize, frames, framesSize,
types, typesSize, chunks, chunksSize,
retentions, retentionsSize);
}
private:
InspectorHeapProfilerAgent* m_heapProfilerAgent;
};

void InspectorHeapProfilerAgent::requestHeapXDKUpdate()
{
if (!frontend())
return;
HeapXDKStream stream(this);
InspectorProfilerAgent::requestHeapXDKUpdate(&stream);
}

void InspectorHeapProfilerAgent::stopTrackingHeapXDK(ErrorString* error, RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK>& profile)
{
if (!m_heapXDKUpdateTask) {
*error = "Heap object tracking is not started.";
return;
}

RefPtr<HeapProfileXDK> heapProfileXDK = InspectorProfilerAgent::stopTrackingHeapObjectsXDK();
profile = createHeapProfileXDK(*heapProfileXDK);

m_heapXDKUpdateTask->resetTimer();
m_heapXDKUpdateTask.clear();
m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false);

}
void InspectorHeapProfilerAgent::pushHeapXDKUpdate(const char* symbols, int symbolsSize,
const char* frames, int framesSize,
const char* types, int typesSize,
const char* chunks, int chunksSize,
const char* retentions, int retentionsSize)
{
if (!frontend())
return;
frontend()->heapXDKUpdate(String(symbols, symbolsSize), String(frames, framesSize),
String(types, typesSize), String(chunks, chunksSize),
String(retentions, retentionsSize));
}

} // namespace blink

Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/WTFString.h"
#include "core/inspector/InspectorProfilerAgent.h"

namespace v8 {
class Isolate;
Expand Down Expand Up @@ -75,19 +76,33 @@ class CORE_EXPORT InspectorHeapProfilerAgent final : public InspectorBaseAgent<I
void addInspectedHeapObject(ErrorString*, const String& inspectedHeapObjectId) override;
void getHeapObjectId(ErrorString*, const String& objectId, String* heapSnapshotObjectId) override;

void startTrackingHeapXDK(ErrorString*, const int* stack_depth, const int* sav, const bool* retentions) override;
void stopTrackingHeapXDK(ErrorString*, RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK>&) override;

private:
class HeapStatsUpdateTask;

class HeapXDKStream;
class HeapXDKUpdateTask;

InspectorHeapProfilerAgent(v8::Isolate*, InjectedScriptManager*);

void requestHeapStatsUpdate();

void startTrackingHeapObjectsInternal(bool trackAllocations);
void stopTrackingHeapObjectsInternal();

void requestHeapXDKUpdate();
void pushHeapXDKUpdate(const char* symbols, int symbolsSize,
const char* frames, int framesSize,
const char* types, int typesSize,
const char* chunks, int chunksSize,
const char* retentions, int retentionsSize);

v8::Isolate* m_isolate;
RawPtrWillBeMember<InjectedScriptManager> m_injectedScriptManager;
OwnPtrWillBeMember<HeapStatsUpdateTask> m_heapStatsUpdateTask;
OwnPtrWillBeMember<HeapXDKUpdateTask> m_heapXDKUpdateTask;
};

} // namespace blink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectFor(const
.setColumnNumber(node->GetColumnNumber())
.setHitCount(node->GetHitCount())
.setCallUID(node->GetCallUid())
.setStackEntryLine(node->GetSrcLine())
.setChildren(children.release())
.setPositionTicks(positionTicks.release())
.setDeoptReason(node->GetBailoutReason())
Expand Down Expand Up @@ -371,4 +372,91 @@ DEFINE_TRACE(InspectorProfilerAgent)
InspectorBaseAgent::trace(visitor);
}

String HeapProfileXDK::getSymbols() const
{
v8::HandleScope handleScope(m_isolate);
return toCoreString(v8AtomicString(m_isolate, m_event->getSymbols()));
}

String HeapProfileXDK::getFrames() const
{
v8::HandleScope handleScope(m_isolate);
return toCoreString(v8AtomicString(m_isolate, m_event->getFrames()));
}

String HeapProfileXDK::getTypes() const
{
v8::HandleScope handleScope(m_isolate);
return toCoreString(v8AtomicString(m_isolate, m_event->getTypes()));
}

String HeapProfileXDK::getChunks() const
{
v8::HandleScope handleScope(m_isolate);
return toCoreString(v8AtomicString(m_isolate, m_event->getChunks()));
}

int HeapProfileXDK::getDuration() const
{
return (int)m_event->getDuration();
}

String HeapProfileXDK::getRetentions() const
{
v8::HandleScope handleScope(m_isolate);
return toCoreString(v8AtomicString(m_isolate, m_event->getRetentions()));
}

namespace {

class HeapXDKStream : public v8::OutputStream {
public:
HeapXDKStream(InspectorProfilerAgent::OutputStream* stream) : m_stream(stream) { }
virtual void EndOfStream() override { }

virtual WriteResult WriteAsciiChunk(char* data, int size) override
{
ASSERT(false);
return kAbort;
}

virtual WriteResult WriteHeapXDKChunk(const char* symbols, size_t symbolsSize,
const char* frames, size_t framesSize,
const char* types, size_t typesSize,
const char* chunks, size_t chunksSize,
const char* retentions,
size_t retentionSize) override
{
m_stream->write(symbols, symbolsSize, frames, framesSize,
types, typesSize, chunks, chunksSize,
retentions, retentionSize);
return kContinue;
}

private:
InspectorProfilerAgent::OutputStream* m_stream;
};

}

void InspectorProfilerAgent::requestHeapXDKUpdate(InspectorProfilerAgent::OutputStream* stream)
{
HeapXDKStream heapXDKStream(stream);
v8::Isolate::GetCurrent()->GetHeapProfiler()->GetHeapXDKStats(
&heapXDKStream);
}

void InspectorProfilerAgent::startTrackingHeapObjectsXDK(int stackDepth, bool retentions)
{
v8::Isolate::GetCurrent()->GetHeapProfiler()->StartTrackingHeapObjectsXDK(
stackDepth, retentions);
}

PassRefPtr<HeapProfileXDK> InspectorProfilerAgent::stopTrackingHeapObjectsXDK()
{
return HeapProfileXDK::create(
v8::Isolate::GetCurrent()
->GetHeapProfiler()->StopTrackingHeapObjectsXDK(), v8::Isolate::GetCurrent());
}

} // namespace blink
41 changes: 41 additions & 0 deletions third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "wtf/Noncopyable.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/WTFString.h"
#include <v8-profiler.h>

namespace v8 {
class CpuProfile;
Expand All @@ -52,6 +53,31 @@ class InspectorOverlay;

typedef String ErrorString;

class HeapProfileXDK final : public RefCountedWillBeGarbageCollectedFinalized<HeapProfileXDK> {
public:
static PassRefPtrWillBeRawPtr<HeapProfileXDK> create(v8::HeapEventXDK* event, v8::Isolate* isolate)
{
return adoptRefWillBeNoop(new HeapProfileXDK(event, isolate));
}

String getSymbols() const;
String getFrames() const;
String getTypes() const;
String getChunks() const;
String getRetentions() const;
int getDuration() const;

private:
HeapProfileXDK(v8::HeapEventXDK* event, v8::Isolate* isolate)
: m_event(event),
m_isolate(isolate)
{
}

v8::HeapEventXDK* m_event;
v8::Isolate* m_isolate;
};

class CORE_EXPORT InspectorProfilerAgent final : public InspectorBaseAgent<InspectorProfilerAgent, InspectorFrontend::Profiler>, public InspectorBackendDispatcher::ProfilerCommandHandler {
WTF_MAKE_NONCOPYABLE(InspectorProfilerAgent);
WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(InspectorProfilerAgent);
Expand All @@ -60,6 +86,17 @@ class CORE_EXPORT InspectorProfilerAgent final : public InspectorBaseAgent<Inspe
~InspectorProfilerAgent() override;
DECLARE_VIRTUAL_TRACE();

class OutputStream {
public:
virtual ~OutputStream() { }
virtual void write(const uint32_t* chunk, const int size) = 0;
virtual void write(const char* symbols, int symbolsSize,
const char* frames, int framesSize,
const char* types, int typesSize,
const char* chunks, int chunksSize,
const char* retentions, int retentionsSize) { };
};

void consoleProfile(ExecutionContext*, const String& title);
void consoleProfileEnd(const String& title);

Expand All @@ -76,6 +113,10 @@ class CORE_EXPORT InspectorProfilerAgent final : public InspectorBaseAgent<Inspe
void willEnterNestedRunLoop();
void didLeaveNestedRunLoop();

static void startTrackingHeapObjectsXDK(int stackDepth, bool retentions);
static PassRefPtr<HeapProfileXDK> stopTrackingHeapObjectsXDK();
static void requestHeapXDKUpdate(OutputStream*);

private:
InspectorProfilerAgent(v8::Isolate*, InjectedScriptManager*, InspectorOverlay*);
bool enabled();
Expand Down
Loading

0 comments on commit b6447eb

Please sign in to comment.