Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: src/inspector/V8HeapProfilerAgentImpl.cpp

Issue 2292573002: [inspector] Initial import of v8_inspector. (Closed)
Patch Set: format the code, disable cpplint Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/inspector/V8HeapProfilerAgentImpl.h ('k') | src/inspector/V8InjectedScriptHost.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/inspector/V8HeapProfilerAgentImpl.h"
6
7 #include "src/inspector/InjectedScript.h"
8 #include "src/inspector/StringUtil.h"
9 #include "src/inspector/V8Debugger.h"
10 #include "src/inspector/V8InspectorImpl.h"
11 #include "src/inspector/V8InspectorSessionImpl.h"
12 #include "src/inspector/protocol/Protocol.h"
13 #include "src/inspector/public/V8InspectorClient.h"
14
15 #include <v8-profiler.h>
16 #include <v8-version.h>
17
18 namespace v8_inspector {
19
20 namespace {
21
22 namespace HeapProfilerAgentState {
23 static const char heapProfilerEnabled[] = "heapProfilerEnabled";
24 static const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled";
25 static const char allocationTrackingEnabled[] = "allocationTrackingEnabled";
26 #if V8_MAJOR_VERSION >= 5
27 static const char samplingHeapProfilerEnabled[] = "samplingHeapProfilerEnabled";
28 static const char samplingHeapProfilerInterval[] =
29 "samplingHeapProfilerInterval";
30 #endif
31 }
32
33 class HeapSnapshotProgress final : public v8::ActivityControl {
34 public:
35 HeapSnapshotProgress(protocol::HeapProfiler::Frontend* frontend)
36 : m_frontend(frontend) {}
37 ControlOption ReportProgressValue(int done, int total) override {
38 m_frontend->reportHeapSnapshotProgress(done, total,
39 protocol::Maybe<bool>());
40 if (done >= total) {
41 m_frontend->reportHeapSnapshotProgress(total, total, true);
42 }
43 m_frontend->flush();
44 return kContinue;
45 }
46
47 private:
48 protocol::HeapProfiler::Frontend* m_frontend;
49 };
50
51 class GlobalObjectNameResolver final
52 : public v8::HeapProfiler::ObjectNameResolver {
53 public:
54 explicit GlobalObjectNameResolver(V8InspectorSessionImpl* session)
55 : m_offset(0), m_strings(10000), m_session(session) {}
56
57 const char* GetName(v8::Local<v8::Object> object) override {
58 InspectedContext* context = m_session->inspector()->getContext(
59 m_session->contextGroupId(),
60 V8Debugger::contextId(object->CreationContext()));
61 if (!context) return "";
62 String16 name = context->origin();
63 size_t length = name.length();
64 if (m_offset + length + 1 >= m_strings.size()) return "";
65 for (size_t i = 0; i < length; ++i) {
66 UChar ch = name[i];
67 m_strings[m_offset + i] = ch > 0xff ? '?' : static_cast<char>(ch);
68 }
69 m_strings[m_offset + length] = '\0';
70 char* result = &*m_strings.begin() + m_offset;
71 m_offset += length + 1;
72 return result;
73 }
74
75 private:
76 size_t m_offset;
77 std::vector<char> m_strings;
78 V8InspectorSessionImpl* m_session;
79 };
80
81 class HeapSnapshotOutputStream final : public v8::OutputStream {
82 public:
83 HeapSnapshotOutputStream(protocol::HeapProfiler::Frontend* frontend)
84 : m_frontend(frontend) {}
85 void EndOfStream() override {}
86 int GetChunkSize() override { return 102400; }
87 WriteResult WriteAsciiChunk(char* data, int size) override {
88 m_frontend->addHeapSnapshotChunk(String16(data, size));
89 m_frontend->flush();
90 return kContinue;
91 }
92
93 private:
94 protocol::HeapProfiler::Frontend* m_frontend;
95 };
96
97 v8::Local<v8::Object> objectByHeapObjectId(v8::Isolate* isolate, int id) {
98 v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
99 v8::Local<v8::Value> value = profiler->FindObjectById(id);
100 if (value.IsEmpty() || !value->IsObject()) return v8::Local<v8::Object>();
101 return value.As<v8::Object>();
102 }
103
104 class InspectableHeapObject final : public V8InspectorSession::Inspectable {
105 public:
106 explicit InspectableHeapObject(int heapObjectId)
107 : m_heapObjectId(heapObjectId) {}
108 v8::Local<v8::Value> get(v8::Local<v8::Context> context) override {
109 return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId);
110 }
111
112 private:
113 int m_heapObjectId;
114 };
115
116 class HeapStatsStream final : public v8::OutputStream {
117 public:
118 HeapStatsStream(protocol::HeapProfiler::Frontend* frontend)
119 : m_frontend(frontend) {}
120
121 void EndOfStream() override {}
122
123 WriteResult WriteAsciiChunk(char* data, int size) override {
124 DCHECK(false);
125 return kAbort;
126 }
127
128 WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* updateData,
129 int count) override {
130 DCHECK_GT(count, 0);
131 std::unique_ptr<protocol::Array<int>> statsDiff =
132 protocol::Array<int>::create();
133 for (int i = 0; i < count; ++i) {
134 statsDiff->addItem(updateData[i].index);
135 statsDiff->addItem(updateData[i].count);
136 statsDiff->addItem(updateData[i].size);
137 }
138 m_frontend->heapStatsUpdate(std::move(statsDiff));
139 return kContinue;
140 }
141
142 private:
143 protocol::HeapProfiler::Frontend* m_frontend;
144 };
145
146 } // namespace
147
148 V8HeapProfilerAgentImpl::V8HeapProfilerAgentImpl(
149 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
150 protocol::DictionaryValue* state)
151 : m_session(session),
152 m_isolate(session->inspector()->isolate()),
153 m_frontend(frontendChannel),
154 m_state(state),
155 m_hasTimer(false) {}
156
157 V8HeapProfilerAgentImpl::~V8HeapProfilerAgentImpl() {}
158
159 void V8HeapProfilerAgentImpl::restore() {
160 if (m_state->booleanProperty(HeapProfilerAgentState::heapProfilerEnabled,
161 false))
162 m_frontend.resetProfiles();
163 if (m_state->booleanProperty(
164 HeapProfilerAgentState::heapObjectsTrackingEnabled, false))
165 startTrackingHeapObjectsInternal(m_state->booleanProperty(
166 HeapProfilerAgentState::allocationTrackingEnabled, false));
167 #if V8_MAJOR_VERSION >= 5
168 if (m_state->booleanProperty(
169 HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) {
170 ErrorString error;
171 double samplingInterval = m_state->doubleProperty(
172 HeapProfilerAgentState::samplingHeapProfilerInterval, -1);
173 DCHECK_GE(samplingInterval, 0);
174 startSampling(&error, Maybe<double>(samplingInterval));
175 }
176 #endif
177 }
178
179 void V8HeapProfilerAgentImpl::collectGarbage(ErrorString*) {
180 m_isolate->LowMemoryNotification();
181 }
182
183 void V8HeapProfilerAgentImpl::startTrackingHeapObjects(
184 ErrorString*, const protocol::Maybe<bool>& trackAllocations) {
185 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
186 bool allocationTrackingEnabled = trackAllocations.fromMaybe(false);
187 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
188 allocationTrackingEnabled);
189 startTrackingHeapObjectsInternal(allocationTrackingEnabled);
190 }
191
192 void V8HeapProfilerAgentImpl::stopTrackingHeapObjects(
193 ErrorString* error, const protocol::Maybe<bool>& reportProgress) {
194 requestHeapStatsUpdate();
195 takeHeapSnapshot(error, reportProgress);
196 stopTrackingHeapObjectsInternal();
197 }
198
199 void V8HeapProfilerAgentImpl::enable(ErrorString*) {
200 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
201 }
202
203 void V8HeapProfilerAgentImpl::disable(ErrorString* error) {
204 stopTrackingHeapObjectsInternal();
205 #if V8_MAJOR_VERSION >= 5
206 if (m_state->booleanProperty(
207 HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) {
208 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
209 if (profiler) profiler->StopSamplingHeapProfiler();
210 }
211 #endif
212 m_isolate->GetHeapProfiler()->ClearObjectIds();
213 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
214 }
215
216 void V8HeapProfilerAgentImpl::takeHeapSnapshot(
217 ErrorString* errorString, const protocol::Maybe<bool>& reportProgress) {
218 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
219 if (!profiler) {
220 *errorString = "Cannot access v8 heap profiler";
221 return;
222 }
223 std::unique_ptr<HeapSnapshotProgress> progress;
224 if (reportProgress.fromMaybe(false))
225 progress = wrapUnique(new HeapSnapshotProgress(&m_frontend));
226
227 GlobalObjectNameResolver resolver(m_session);
228 const v8::HeapSnapshot* snapshot =
229 profiler->TakeHeapSnapshot(progress.get(), &resolver);
230 if (!snapshot) {
231 *errorString = "Failed to take heap snapshot";
232 return;
233 }
234 HeapSnapshotOutputStream stream(&m_frontend);
235 snapshot->Serialize(&stream);
236 const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
237 }
238
239 void V8HeapProfilerAgentImpl::getObjectByHeapObjectId(
240 ErrorString* error, const String16& heapSnapshotObjectId,
241 const protocol::Maybe<String16>& objectGroup,
242 std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
243 bool ok;
244 int id = heapSnapshotObjectId.toInteger(&ok);
245 if (!ok) {
246 *error = "Invalid heap snapshot object id";
247 return;
248 }
249
250 v8::HandleScope handles(m_isolate);
251 v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
252 if (heapObject.IsEmpty()) {
253 *error = "Object is not available";
254 return;
255 }
256
257 if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) {
258 *error = "Object is not available";
259 return;
260 }
261
262 *result = m_session->wrapObject(heapObject->CreationContext(), heapObject,
263 objectGroup.fromMaybe(""), false);
264 if (!result) *error = "Object is not available";
265 }
266
267 void V8HeapProfilerAgentImpl::addInspectedHeapObject(
268 ErrorString* errorString, const String16& inspectedHeapObjectId) {
269 bool ok;
270 int id = inspectedHeapObjectId.toInteger(&ok);
271 if (!ok) {
272 *errorString = "Invalid heap snapshot object id";
273 return;
274 }
275
276 v8::HandleScope handles(m_isolate);
277 v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
278 if (heapObject.IsEmpty()) {
279 *errorString = "Object is not available";
280 return;
281 }
282
283 if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) {
284 *errorString = "Object is not available";
285 return;
286 }
287
288 m_session->addInspectedObject(wrapUnique(new InspectableHeapObject(id)));
289 }
290
291 void V8HeapProfilerAgentImpl::getHeapObjectId(ErrorString* errorString,
292 const String16& objectId,
293 String16* heapSnapshotObjectId) {
294 v8::HandleScope handles(m_isolate);
295 v8::Local<v8::Value> value;
296 v8::Local<v8::Context> context;
297 if (!m_session->unwrapObject(errorString, objectId, &value, &context,
298 nullptr) ||
299 value->IsUndefined())
300 return;
301
302 v8::SnapshotObjectId id = m_isolate->GetHeapProfiler()->GetObjectId(value);
303 *heapSnapshotObjectId = String16::fromInteger(id);
304 }
305
306 void V8HeapProfilerAgentImpl::requestHeapStatsUpdate() {
307 HeapStatsStream stream(&m_frontend);
308 v8::SnapshotObjectId lastSeenObjectId =
309 m_isolate->GetHeapProfiler()->GetHeapStats(&stream);
310 m_frontend.lastSeenObjectId(
311 lastSeenObjectId, m_session->inspector()->client()->currentTimeMS());
312 }
313
314 // static
315 void V8HeapProfilerAgentImpl::onTimer(void* data) {
316 reinterpret_cast<V8HeapProfilerAgentImpl*>(data)->requestHeapStatsUpdate();
317 }
318
319 void V8HeapProfilerAgentImpl::startTrackingHeapObjectsInternal(
320 bool trackAllocations) {
321 m_isolate->GetHeapProfiler()->StartTrackingHeapObjects(trackAllocations);
322 if (!m_hasTimer) {
323 m_hasTimer = true;
324 m_session->inspector()->client()->startRepeatingTimer(
325 0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast<void*>(this));
326 }
327 }
328
329 void V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() {
330 if (m_hasTimer) {
331 m_session->inspector()->client()->cancelTimer(
332 reinterpret_cast<void*>(this));
333 m_hasTimer = false;
334 }
335 m_isolate->GetHeapProfiler()->StopTrackingHeapObjects();
336 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
337 false);
338 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, false);
339 }
340
341 void V8HeapProfilerAgentImpl::startSampling(
342 ErrorString* errorString, const Maybe<double>& samplingInterval) {
343 #if V8_MAJOR_VERSION >= 5
344 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
345 if (!profiler) {
346 *errorString = "Cannot access v8 heap profiler";
347 return;
348 }
349 const unsigned defaultSamplingInterval = 1 << 15;
350 double samplingIntervalValue =
351 samplingInterval.fromMaybe(defaultSamplingInterval);
352 m_state->setDouble(HeapProfilerAgentState::samplingHeapProfilerInterval,
353 samplingIntervalValue);
354 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
355 true);
356 #if V8_MAJOR_VERSION * 1000 + V8_MINOR_VERSION >= 5002
357 profiler->StartSamplingHeapProfiler(
358 static_cast<uint64_t>(samplingIntervalValue), 128,
359 v8::HeapProfiler::kSamplingForceGC);
360 #else
361 profiler->StartSamplingHeapProfiler(
362 static_cast<uint64_t>(samplingIntervalValue), 128);
363 #endif
364 #endif
365 }
366
367 #if V8_MAJOR_VERSION >= 5
368 namespace {
369 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode>
370 buildSampingHeapProfileNode(const v8::AllocationProfile::Node* node) {
371 auto children = protocol::Array<
372 protocol::HeapProfiler::SamplingHeapProfileNode>::create();
373 for (const auto* child : node->children)
374 children->addItem(buildSampingHeapProfileNode(child));
375 size_t selfSize = 0;
376 for (const auto& allocation : node->allocations)
377 selfSize += allocation.size * allocation.count;
378 std::unique_ptr<protocol::Runtime::CallFrame> callFrame =
379 protocol::Runtime::CallFrame::create()
380 .setFunctionName(toProtocolString(node->name))
381 .setScriptId(String16::fromInteger(node->script_id))
382 .setUrl(toProtocolString(node->script_name))
383 .setLineNumber(node->line_number - 1)
384 .setColumnNumber(node->column_number - 1)
385 .build();
386 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode> result =
387 protocol::HeapProfiler::SamplingHeapProfileNode::create()
388 .setCallFrame(std::move(callFrame))
389 .setSelfSize(selfSize)
390 .setChildren(std::move(children))
391 .build();
392 return result;
393 }
394 } // namespace
395 #endif
396
397 void V8HeapProfilerAgentImpl::stopSampling(
398 ErrorString* errorString,
399 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
400 #if V8_MAJOR_VERSION >= 5
401 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
402 if (!profiler) {
403 *errorString = "Cannot access v8 heap profiler";
404 return;
405 }
406 v8::HandleScope scope(
407 m_isolate); // Allocation profile contains Local handles.
408 std::unique_ptr<v8::AllocationProfile> v8Profile(
409 profiler->GetAllocationProfile());
410 profiler->StopSamplingHeapProfiler();
411 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
412 false);
413 if (!v8Profile) {
414 *errorString = "Cannot access v8 sampled heap profile.";
415 return;
416 }
417 v8::AllocationProfile::Node* root = v8Profile->GetRootNode();
418 *profile = protocol::HeapProfiler::SamplingHeapProfile::create()
419 .setHead(buildSampingHeapProfileNode(root))
420 .build();
421 #endif
422 }
423
424 } // namespace v8_inspector
OLDNEW
« no previous file with comments | « src/inspector/V8HeapProfilerAgentImpl.h ('k') | src/inspector/V8InjectedScriptHost.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698