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

Commit

Permalink
[XDK] Add in-depth allocation tracker
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Mishenkov Sergey authored and Raphael Kubo da Costa committed May 16, 2016
1 parent 34b9287 commit e1bd830
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ class InspectorHeapProfilerAgent::HeapStatsUpdateTask final {
Timer<HeapStatsUpdateTask> m_timer;
};

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

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

InspectorHeapProfilerAgent::HeapStatsUpdateTask::HeapStatsUpdateTask(V8HeapProfilerAgent* heapProfilerAgent)
: m_heapProfilerAgent(heapProfilerAgent)
, m_timer(this, &HeapStatsUpdateTask::onTimer)
Expand Down Expand Up @@ -231,4 +243,46 @@ void InspectorHeapProfilerAgent::stopSampling(ErrorString* errorString, OwnPtr<p
m_v8HeapProfilerAgent->stopSampling(errorString, profile);
}

InspectorHeapProfilerAgent::HeapXDKUpdateTask::HeapXDKUpdateTask(V8HeapProfilerAgent* 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, BLINK_FROM_HERE);
}

void InspectorHeapProfilerAgent::startTrackingHeapXDK(ErrorString* error, const protocol::Maybe<int>& depth, const protocol::Maybe<int>& sav, const protocol::Maybe<bool>& retentions)
{
if (m_heapXDKUpdateTask)
return;

m_v8HeapProfilerAgent->startTrackingHeapXDK(error, depth, sav, retentions);
float savTimer = (float) sav.fromMaybe(1000) / 1000.;
m_heapXDKUpdateTask = adoptPtr(new HeapXDKUpdateTask(m_v8HeapProfilerAgent.get()));
m_heapXDKUpdateTask->startTimer(savTimer);
}

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

m_v8HeapProfilerAgent->stopTrackingHeapXDK(error, profile);
m_heapXDKUpdateTask->resetTimer();
m_heapXDKUpdateTask.clear();
}

} // namespace blink
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "wtf/Noncopyable.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include <v8-profiler.h>

namespace v8 {
class Isolate;
Expand Down Expand Up @@ -73,9 +74,13 @@ class CORE_EXPORT InspectorHeapProfilerAgent final : public InspectorBaseAgent<I
void getHeapObjectId(ErrorString*, const String& objectId, String* heapSnapshotObjectId) override;
void startSampling(ErrorString*) override;
void stopSampling(ErrorString*, OwnPtr<protocol::HeapProfiler::SamplingHeapProfile>*) override;
void startTrackingHeapXDK(ErrorString*, const Maybe<int>& stack_depth, const Maybe<int>& sav, const Maybe<bool>& retentions) override;
void stopTrackingHeapXDK(ErrorString*, OwnPtr<protocol::HeapProfiler::HeapEventXDK>*) override;

private:
class HeapStatsUpdateTask;
class HeapXDKStream;
class HeapXDKUpdateTask;

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

Expand All @@ -85,6 +90,7 @@ class CORE_EXPORT InspectorHeapProfilerAgent final : public InspectorBaseAgent<I

OwnPtr<V8HeapProfilerAgent> m_v8HeapProfilerAgent;
OwnPtr<HeapStatsUpdateTask> m_heapStatsUpdateTask;
OwnPtr<HeapXDKUpdateTask> m_heapXDKUpdateTask;
v8::Isolate* m_isolate;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ WebInspector.HeapProfilerModel.Events = {
LastSeenObjectId: "LastSeenObjectId",
AddHeapSnapshotChunk: "AddHeapSnapshotChunk",
ReportHeapSnapshotProgress: "ReportHeapSnapshotProgress",
ResetProfiles: "ResetProfiles"
ResetProfiles: "ResetProfiles",
HeapXDKUpdate: "HeapXDKUpdate"
}

WebInspector.HeapProfilerModel.prototype = {
Expand Down Expand Up @@ -70,6 +71,14 @@ WebInspector.HeapProfilerModel.prototype = {
this.dispatchEventToListeners(WebInspector.HeapProfilerModel.Events.ResetProfiles);
},

/**
* @param {string} message
*/
heapXDKUpdate: function (message)
{
this.dispatchEventToListeners(WebInspector.HeapProfilerModel.Events.HeapXDKUpdate, message);
},

__proto__: WebInspector.SDKModel.prototype
}

Expand Down Expand Up @@ -129,5 +138,14 @@ WebInspector.HeapProfilerDispatcher.prototype = {
resetProfiles: function()
{
this._heapProfilerModel.resetProfiles();
},

/**
* @override
* @param {string} message
*/
heapXDKUpdate: function(message)
{
this._heapProfilerModel.heapXDKUpdate(message);
}
}
38 changes: 38 additions & 0 deletions third_party/WebKit/Source/devtools/protocol.json
Original file line number Diff line number Diff line change
Expand Up @@ -4016,6 +4016,7 @@
{ "name": "columnNumber", "type": "integer", "description": "1-based column number of the function start position." },
{ "name": "hitCount", "type": "integer", "description": "Number of samples where this node was on top of the call stack." },
{ "name": "callUID", "type": "number", "description": "Call UID." },
{ "name": "stackEntryLine", "type": "integer", "description": "Hit line for entry in stack." },
{ "name": "children", "type": "array", "items": { "$ref": "CPUProfileNode" }, "description": "Child nodes." },
{ "name": "deoptReason", "type": "string", "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."},
{ "name": "id", "type": "integer", "description": "Unique id of the node." },
Expand Down Expand Up @@ -4120,6 +4121,19 @@
"properties": [
{ "name": "head", "$ref": "SamplingHeapProfileNode" }
]
},
{
"id": "HeapEventXDK",
"type": "object",
"description": "",
"properties": [
{ "name": "duration", "type": "integer" },
{ "name": "symbols", "type": "string" },
{ "name": "frames", "type": "string" },
{ "name": "types", "type": "string" },
{ "name": "chunks", "type": "string" },
{ "name": "retentions", "type": "string" }
]
}
],
"commands": [
Expand All @@ -4142,6 +4156,20 @@
]

},
{
"name": "startTrackingHeapXDK",
"parameters": [
{ "name": "stack_depth", "type": "integer", "optional": true },
{ "name": "sav", "type": "integer", "optional": true },
{ "name": "retentions", "type": "boolean", "optional": true }
]
},
{
"name": "stopTrackingHeapXDK",
"returns": [
{ "name": "profileXDK", "$ref": "HeapEventXDK", "description": "Recorded profile." }
]
},
{
"name": "takeHeapSnapshot",
"parameters": [
Expand Down Expand Up @@ -4219,6 +4247,16 @@
"parameters": [
{ "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."}
]
},
{
"name": "heapXDKUpdate",
"parameters": [
{ "name": "symbols", "type": "string" },
{ "name": "frames", "type": "string" },
{ "name": "types", "type": "string" },
{ "name": "chunks", "type": "string" },
{ "name": "retentions", "type": "string" }
]
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,113 @@ void V8HeapProfilerAgentImpl::stopSampling(ErrorString* errorString, OwnPtr<prot
.setHead(buildSampingHeapProfileNode(root)).build();
}

class HeapXDKStream : public v8::OutputStream {
public:
HeapXDKStream(protocol::Frontend::HeapProfiler* frontend)
: m_frontend(frontend)
{
}
void EndOfStream() override { }

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

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_frontend->heapXDKUpdate(String(symbols, symbolsSize), String(frames, framesSize), String(types, typesSize), String(chunks, chunksSize), String(retentions, retentionSize));
return kContinue;
}

private:
protocol::Frontend::HeapProfiler* m_frontend;
};

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

void V8HeapProfilerAgentImpl::startTrackingHeapXDK(ErrorString* error, const protocol::Maybe<int>& depth, const protocol::Maybe<int>& sav, const protocol::Maybe<bool>& retentions)
{
v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
if (!profiler) {
*error = "Cannot access v8 heap profiler";
return;
}

m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
int stackDepth = depth.fromMaybe(8);
bool needRetentions = retentions.fromMaybe(false);
profiler->StartTrackingHeapObjectsXDK(stackDepth, needRetentions);
}

void V8HeapProfilerAgentImpl::stopTrackingHeapXDK(ErrorString* error, OwnPtr<protocol::HeapProfiler::HeapEventXDK>* profile)
{
v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
if (!profiler) {
*error = "Cannot access v8 heap profiler";
return;
}

OwnPtr<HeapProfileXDK> heapProfileXDK = HeapProfileXDK::create(
profiler->StopTrackingHeapObjectsXDK(), m_isolate);
*profile = createHeapProfileXDK(*heapProfileXDK);
m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false);
}

void V8HeapProfilerAgentImpl::requestHeapXDKUpdate()
{
if (!m_frontend)
return;
HeapXDKStream heapXDKStream(m_frontend);
m_isolate->GetHeapProfiler()->GetHeapXDKStats(
&heapXDKStream);
}

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

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

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

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

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

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

} // namespace blink
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "platform/v8_inspector/public/V8HeapProfilerAgent.h"
#include "wtf/Forward.h"
#include "wtf/Noncopyable.h"
#include <v8-profiler.h>

namespace blink {

Expand All @@ -17,6 +18,31 @@ typedef String ErrorString;

using protocol::Maybe;

class HeapProfileXDK final {
public:
static PassOwnPtr<HeapProfileXDK> create(v8::HeapEventXDK* event, v8::Isolate* isolate)
{
return adoptPtr(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 V8HeapProfilerAgentImpl : public V8HeapProfilerAgent {
WTF_MAKE_NONCOPYABLE(V8HeapProfilerAgentImpl);
public:
Expand All @@ -42,10 +68,14 @@ class V8HeapProfilerAgentImpl : public V8HeapProfilerAgent {
void addInspectedHeapObject(ErrorString*, const String& inspectedHeapObjectId) override;
void getHeapObjectId(ErrorString*, const String& objectId, String* heapSnapshotObjectId) override;

void startTrackingHeapXDK(ErrorString*, const Maybe<int>& depth, const Maybe<int>& sav, const Maybe<bool>& retentions) override;
void stopTrackingHeapXDK(ErrorString*, OwnPtr<protocol::HeapProfiler::HeapEventXDK>*) override;

void startSampling(ErrorString*) override;
void stopSampling(ErrorString*, OwnPtr<protocol::HeapProfiler::SamplingHeapProfile>*) override;

void requestHeapStatsUpdate() override;
void requestHeapXDKUpdate() override;

private:
void startTrackingHeapObjectsInternal(bool trackAllocations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ PassOwnPtr<protocol::Profiler::CPUProfileNode> buildInspectorObjectFor(v8::Isola
.setColumnNumber(node->GetColumnNumber())
.setHitCount(node->GetHitCount())
.setCallUID(node->GetCallUid())
.setStackEntryLine(node->GetSrcLine())
.setChildren(children.release())
.setPositionTicks(positionTicks.release())
.setDeoptReason(node->GetBailoutReason())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class PLATFORM_EXPORT V8HeapProfilerAgent : public protocol::Dispatcher::HeapPro
virtual ~V8HeapProfilerAgent() { }

virtual void requestHeapStatsUpdate() = 0;
virtual void requestHeapXDKUpdate() = 0;
};

} // namespace blink
Expand Down

0 comments on commit e1bd830

Please sign in to comment.