Line data Source code
1 : // Copyright 2015 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/v8-profiler-agent-impl.h"
6 :
7 : #include <vector>
8 :
9 : #include "src/base/atomicops.h"
10 : #include "src/debug/debug-interface.h"
11 : #include "src/flags.h" // TODO(jgruber): Remove include and DEPS entry.
12 : #include "src/inspector/protocol/Protocol.h"
13 : #include "src/inspector/string-util.h"
14 : #include "src/inspector/v8-debugger.h"
15 : #include "src/inspector/v8-inspector-impl.h"
16 : #include "src/inspector/v8-inspector-session-impl.h"
17 : #include "src/inspector/v8-stack-trace-impl.h"
18 :
19 : #include "include/v8-profiler.h"
20 :
21 : namespace v8_inspector {
22 :
23 : namespace ProfilerAgentState {
24 : static const char samplingInterval[] = "samplingInterval";
25 : static const char userInitiatedProfiling[] = "userInitiatedProfiling";
26 : static const char profilerEnabled[] = "profilerEnabled";
27 : static const char preciseCoverageStarted[] = "preciseCoverageStarted";
28 : static const char preciseCoverageCallCount[] = "preciseCoverageCallCount";
29 : static const char preciseCoverageDetailed[] = "preciseCoverageDetailed";
30 : static const char typeProfileStarted[] = "typeProfileStarted";
31 : }
32 :
33 : namespace {
34 :
35 494 : String16 resourceNameToUrl(V8InspectorImpl* inspector,
36 : v8::Local<v8::String> v8Name) {
37 247 : String16 name = toProtocolString(inspector->isolate(), v8Name);
38 247 : if (!inspector) return name;
39 : std::unique_ptr<StringBuffer> url =
40 247 : inspector->client()->resourceNameToUrl(toStringView(name));
41 247 : return url ? toString16(url->string()) : name;
42 : }
43 :
44 : std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>>
45 107 : buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node) {
46 107 : unsigned lineCount = node->GetHitLineCount();
47 107 : if (!lineCount) return nullptr;
48 : auto array = protocol::Array<protocol::Profiler::PositionTickInfo>::create();
49 2 : std::vector<v8::CpuProfileNode::LineTick> entries(lineCount);
50 2 : if (node->GetLineTicks(&entries[0], lineCount)) {
51 2 : for (unsigned i = 0; i < lineCount; i++) {
52 : std::unique_ptr<protocol::Profiler::PositionTickInfo> line =
53 : protocol::Profiler::PositionTickInfo::create()
54 4 : .setLine(entries[i].line)
55 4 : .setTicks(entries[i].hit_count)
56 : .build();
57 2 : array->addItem(std::move(line));
58 : }
59 : }
60 : return array;
61 : }
62 :
63 107 : std::unique_ptr<protocol::Profiler::ProfileNode> buildInspectorObjectFor(
64 107 : V8InspectorImpl* inspector, const v8::CpuProfileNode* node) {
65 : v8::Isolate* isolate = inspector->isolate();
66 107 : v8::HandleScope handleScope(isolate);
67 : auto callFrame =
68 : protocol::Runtime::CallFrame::create()
69 321 : .setFunctionName(toProtocolString(isolate, node->GetFunctionName()))
70 214 : .setScriptId(String16::fromInteger(node->GetScriptId()))
71 214 : .setUrl(resourceNameToUrl(inspector, node->GetScriptResourceName()))
72 107 : .setLineNumber(node->GetLineNumber() - 1)
73 107 : .setColumnNumber(node->GetColumnNumber() - 1)
74 : .build();
75 : auto result = protocol::Profiler::ProfileNode::create()
76 107 : .setCallFrame(std::move(callFrame))
77 107 : .setHitCount(node->GetHitCount())
78 107 : .setId(node->GetNodeId())
79 : .build();
80 :
81 107 : const int childrenCount = node->GetChildrenCount();
82 107 : if (childrenCount) {
83 : auto children = protocol::Array<int>::create();
84 117 : for (int i = 0; i < childrenCount; i++)
85 124 : children->addItem(node->GetChild(i)->GetNodeId());
86 : result->setChildren(std::move(children));
87 : }
88 :
89 107 : const char* deoptReason = node->GetBailoutReason();
90 107 : if (deoptReason && deoptReason[0] && strcmp(deoptReason, "no reason"))
91 0 : result->setDeoptReason(deoptReason);
92 :
93 107 : auto positionTicks = buildInspectorObjectForPositionTicks(node);
94 107 : if (positionTicks) result->setPositionTicks(std::move(positionTicks));
95 :
96 107 : return result;
97 : }
98 :
99 45 : std::unique_ptr<protocol::Array<int>> buildInspectorObjectForSamples(
100 : v8::CpuProfile* v8profile) {
101 : auto array = protocol::Array<int>::create();
102 45 : int count = v8profile->GetSamplesCount();
103 89 : for (int i = 0; i < count; i++)
104 88 : array->addItem(v8profile->GetSample(i)->GetNodeId());
105 45 : return array;
106 : }
107 :
108 45 : std::unique_ptr<protocol::Array<int>> buildInspectorObjectForTimestamps(
109 : v8::CpuProfile* v8profile) {
110 : auto array = protocol::Array<int>::create();
111 45 : int count = v8profile->GetSamplesCount();
112 45 : uint64_t lastTime = v8profile->GetStartTime();
113 89 : for (int i = 0; i < count; i++) {
114 44 : uint64_t ts = v8profile->GetSampleTimestamp(i);
115 88 : array->addItem(static_cast<int>(ts - lastTime));
116 : lastTime = ts;
117 : }
118 45 : return array;
119 : }
120 :
121 107 : void flattenNodesTree(V8InspectorImpl* inspector,
122 : const v8::CpuProfileNode* node,
123 : protocol::Array<protocol::Profiler::ProfileNode>* list) {
124 214 : list->addItem(buildInspectorObjectFor(inspector, node));
125 107 : const int childrenCount = node->GetChildrenCount();
126 169 : for (int i = 0; i < childrenCount; i++)
127 62 : flattenNodesTree(inspector, node->GetChild(i), list);
128 107 : }
129 :
130 45 : std::unique_ptr<protocol::Profiler::Profile> createCPUProfile(
131 : V8InspectorImpl* inspector, v8::CpuProfile* v8profile) {
132 : auto nodes = protocol::Array<protocol::Profiler::ProfileNode>::create();
133 45 : flattenNodesTree(inspector, v8profile->GetTopDownRoot(), nodes.get());
134 : return protocol::Profiler::Profile::create()
135 45 : .setNodes(std::move(nodes))
136 45 : .setStartTime(static_cast<double>(v8profile->GetStartTime()))
137 45 : .setEndTime(static_cast<double>(v8profile->GetEndTime()))
138 90 : .setSamples(buildInspectorObjectForSamples(v8profile))
139 90 : .setTimeDeltas(buildInspectorObjectForTimestamps(v8profile))
140 45 : .build();
141 : }
142 :
143 75 : std::unique_ptr<protocol::Debugger::Location> currentDebugLocation(
144 : V8InspectorImpl* inspector) {
145 : std::unique_ptr<V8StackTraceImpl> callStack =
146 75 : inspector->debugger()->captureStackTrace(false /* fullStack */);
147 : auto location = protocol::Debugger::Location::create()
148 225 : .setScriptId(toString16(callStack->topScriptId()))
149 75 : .setLineNumber(callStack->topLineNumber())
150 : .build();
151 75 : location->setColumnNumber(callStack->topColumnNumber());
152 75 : return location;
153 : }
154 :
155 : volatile int s_lastProfileId = 0;
156 :
157 : } // namespace
158 :
159 55 : class V8ProfilerAgentImpl::ProfileDescriptor {
160 : public:
161 : ProfileDescriptor(const String16& id, const String16& title)
162 40 : : m_id(id), m_title(title) {}
163 : String16 m_id;
164 : String16 m_title;
165 : };
166 :
167 3834 : V8ProfilerAgentImpl::V8ProfilerAgentImpl(
168 : V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
169 : protocol::DictionaryValue* state)
170 : : m_session(session),
171 3834 : m_isolate(m_session->inspector()->isolate()),
172 : m_state(state),
173 15336 : m_frontend(frontendChannel) {}
174 :
175 11502 : V8ProfilerAgentImpl::~V8ProfilerAgentImpl() {
176 3834 : if (m_profiler) m_profiler->Dispose();
177 7668 : }
178 :
179 40 : void V8ProfilerAgentImpl::consoleProfile(const String16& title) {
180 40 : if (!m_enabled) return;
181 40 : String16 id = nextProfileId();
182 80 : m_startedProfiles.push_back(ProfileDescriptor(id, title));
183 40 : startProfiling(id);
184 : m_frontend.consoleProfileStarted(
185 80 : id, currentDebugLocation(m_session->inspector()), title);
186 : }
187 :
188 40 : void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) {
189 45 : if (!m_enabled) return;
190 40 : String16 id;
191 40 : String16 resolvedTitle;
192 : // Take last started profile if no title was passed.
193 40 : if (title.isEmpty()) {
194 65 : if (m_startedProfiles.empty()) return;
195 10 : id = m_startedProfiles.back().m_id;
196 10 : resolvedTitle = m_startedProfiles.back().m_title;
197 10 : m_startedProfiles.pop_back();
198 : } else {
199 25 : for (size_t i = 0; i < m_startedProfiles.size(); i++) {
200 25 : if (m_startedProfiles[i].m_title == title) {
201 25 : resolvedTitle = title;
202 25 : id = m_startedProfiles[i].m_id;
203 25 : m_startedProfiles.erase(m_startedProfiles.begin() + i);
204 25 : break;
205 : }
206 : }
207 25 : if (id.isEmpty()) return;
208 : }
209 : std::unique_ptr<protocol::Profiler::Profile> profile =
210 35 : stopProfiling(id, true);
211 35 : if (!profile) return;
212 : std::unique_ptr<protocol::Debugger::Location> location =
213 35 : currentDebugLocation(m_session->inspector());
214 : m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile),
215 175 : resolvedTitle);
216 : }
217 :
218 185 : Response V8ProfilerAgentImpl::enable() {
219 185 : if (m_enabled) return Response::OK();
220 185 : m_enabled = true;
221 370 : m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
222 185 : return Response::OK();
223 : }
224 :
225 3999 : Response V8ProfilerAgentImpl::disable() {
226 3999 : if (!m_enabled) return Response::OK();
227 565 : for (size_t i = m_startedProfiles.size(); i > 0; --i)
228 15 : stopProfiling(m_startedProfiles[i - 1].m_id, false);
229 : m_startedProfiles.clear();
230 370 : stop(nullptr);
231 370 : stopPreciseCoverage();
232 : DCHECK(!m_profiler);
233 185 : m_enabled = false;
234 370 : m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
235 185 : return Response::OK();
236 : }
237 :
238 0 : Response V8ProfilerAgentImpl::setSamplingInterval(int interval) {
239 0 : if (m_profiler) {
240 0 : return Response::Error("Cannot change sampling interval when profiling.");
241 : }
242 0 : m_state->setInteger(ProfilerAgentState::samplingInterval, interval);
243 0 : return Response::OK();
244 : }
245 :
246 55 : void V8ProfilerAgentImpl::restore() {
247 : DCHECK(!m_enabled);
248 110 : if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false))
249 55 : return;
250 0 : m_enabled = true;
251 : DCHECK(!m_profiler);
252 0 : if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling,
253 0 : false)) {
254 0 : start();
255 : }
256 0 : if (m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
257 0 : false)) {
258 : bool callCount = m_state->booleanProperty(
259 0 : ProfilerAgentState::preciseCoverageCallCount, false);
260 : bool detailed = m_state->booleanProperty(
261 0 : ProfilerAgentState::preciseCoverageDetailed, false);
262 0 : startPreciseCoverage(Maybe<bool>(callCount), Maybe<bool>(detailed));
263 : }
264 : }
265 :
266 20 : Response V8ProfilerAgentImpl::start() {
267 20 : if (m_recordingCPUProfile) return Response::OK();
268 25 : if (!m_enabled) return Response::Error("Profiler is not enabled");
269 15 : m_recordingCPUProfile = true;
270 30 : m_frontendInitiatedProfileId = nextProfileId();
271 15 : startProfiling(m_frontendInitiatedProfileId);
272 30 : m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
273 15 : return Response::OK();
274 : }
275 :
276 205 : Response V8ProfilerAgentImpl::stop(
277 : std::unique_ptr<protocol::Profiler::Profile>* profile) {
278 205 : if (!m_recordingCPUProfile) {
279 380 : return Response::Error("No recording profiles found");
280 : }
281 15 : m_recordingCPUProfile = false;
282 : std::unique_ptr<protocol::Profiler::Profile> cpuProfile =
283 15 : stopProfiling(m_frontendInitiatedProfileId, !!profile);
284 15 : if (profile) {
285 : *profile = std::move(cpuProfile);
286 10 : if (!profile->get()) return Response::Error("Profile is not found");
287 : }
288 30 : m_frontendInitiatedProfileId = String16();
289 30 : m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
290 15 : return Response::OK();
291 : }
292 :
293 85 : Response V8ProfilerAgentImpl::startPreciseCoverage(Maybe<bool> callCount,
294 : Maybe<bool> detailed) {
295 85 : if (!m_enabled) return Response::Error("Profiler is not enabled");
296 : bool callCountValue = callCount.fromMaybe(false);
297 : bool detailedValue = detailed.fromMaybe(false);
298 170 : m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, true);
299 : m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount,
300 170 : callCountValue);
301 : m_state->setBoolean(ProfilerAgentState::preciseCoverageDetailed,
302 170 : detailedValue);
303 : // BlockCount is a superset of PreciseCount. It includes block-granularity
304 : // coverage data if it exists (at the time of writing, that's the case for
305 : // each function recompiled after the BlockCount mode has been set); and
306 : // function-granularity coverage data otherwise.
307 : typedef v8::debug::Coverage C;
308 : C::Mode mode = callCountValue
309 : ? (detailedValue ? C::kBlockCount : C::kPreciseCount)
310 85 : : (detailedValue ? C::kBlockBinary : C::kPreciseBinary);
311 85 : C::SelectMode(m_isolate, mode);
312 85 : return Response::OK();
313 : }
314 :
315 270 : Response V8ProfilerAgentImpl::stopPreciseCoverage() {
316 270 : if (!m_enabled) return Response::Error("Profiler is not enabled");
317 540 : m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false);
318 540 : m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount, false);
319 540 : m_state->setBoolean(ProfilerAgentState::preciseCoverageDetailed, false);
320 270 : v8::debug::Coverage::SelectMode(m_isolate, v8::debug::Coverage::kBestEffort);
321 270 : return Response::OK();
322 : }
323 :
324 : namespace {
325 : std::unique_ptr<protocol::Profiler::CoverageRange> createCoverageRange(
326 : int start, int end, int count) {
327 : return protocol::Profiler::CoverageRange::create()
328 515 : .setStartOffset(start)
329 : .setEndOffset(end)
330 : .setCount(count)
331 : .build();
332 : }
333 :
334 170 : Response coverageToProtocol(
335 170 : V8InspectorImpl* inspector, const v8::debug::Coverage& coverage,
336 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
337 : out_result) {
338 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> result =
339 : protocol::Array<protocol::Profiler::ScriptCoverage>::create();
340 : v8::Isolate* isolate = inspector->isolate();
341 370 : for (size_t i = 0; i < coverage.ScriptCount(); i++) {
342 200 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
343 200 : v8::Local<v8::debug::Script> script = script_data.GetScript();
344 : std::unique_ptr<protocol::Array<protocol::Profiler::FunctionCoverage>>
345 : functions =
346 : protocol::Array<protocol::Profiler::FunctionCoverage>::create();
347 675 : for (size_t j = 0; j < script_data.FunctionCount(); j++) {
348 : v8::debug::Coverage::FunctionData function_data =
349 475 : script_data.GetFunctionData(j);
350 : std::unique_ptr<protocol::Array<protocol::Profiler::CoverageRange>>
351 : ranges = protocol::Array<protocol::Profiler::CoverageRange>::create();
352 :
353 : // Add function range.
354 : ranges->addItem(createCoverageRange(function_data.StartOffset(),
355 : function_data.EndOffset(),
356 950 : function_data.Count()));
357 :
358 : // Process inner blocks.
359 515 : for (size_t k = 0; k < function_data.BlockCount(); k++) {
360 : v8::debug::Coverage::BlockData block_data =
361 40 : function_data.GetBlockData(k);
362 : ranges->addItem(createCoverageRange(block_data.StartOffset(),
363 : block_data.EndOffset(),
364 80 : block_data.Count()));
365 : }
366 :
367 : functions->addItem(
368 : protocol::Profiler::FunctionCoverage::create()
369 : .setFunctionName(toProtocolString(
370 : isolate,
371 1900 : function_data.Name().FromMaybe(v8::Local<v8::String>())))
372 : .setRanges(std::move(ranges))
373 475 : .setIsBlockCoverage(function_data.HasBlockCoverage())
374 475 : .build());
375 : }
376 200 : String16 url;
377 : v8::Local<v8::String> name;
378 400 : if (script->SourceURL().ToLocal(&name) && name->Length()) {
379 0 : url = toProtocolString(isolate, name);
380 400 : } else if (script->Name().ToLocal(&name) && name->Length()) {
381 200 : url = resourceNameToUrl(inspector, name);
382 : }
383 : result->addItem(protocol::Profiler::ScriptCoverage::create()
384 600 : .setScriptId(String16::fromInteger(script->Id()))
385 : .setUrl(url)
386 : .setFunctions(std::move(functions))
387 200 : .build());
388 : }
389 : *out_result = std::move(result);
390 170 : return Response::OK();
391 : }
392 : } // anonymous namespace
393 :
394 120 : Response V8ProfilerAgentImpl::takePreciseCoverage(
395 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
396 : out_result) {
397 120 : if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
398 240 : false)) {
399 20 : return Response::Error("Precise coverage has not been started.");
400 : }
401 110 : v8::HandleScope handle_scope(m_isolate);
402 110 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(m_isolate);
403 220 : return coverageToProtocol(m_session->inspector(), coverage, out_result);
404 : }
405 :
406 60 : Response V8ProfilerAgentImpl::getBestEffortCoverage(
407 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
408 : out_result) {
409 60 : v8::HandleScope handle_scope(m_isolate);
410 : v8::debug::Coverage coverage =
411 60 : v8::debug::Coverage::CollectBestEffort(m_isolate);
412 120 : return coverageToProtocol(m_session->inspector(), coverage, out_result);
413 : }
414 :
415 : namespace {
416 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>
417 100 : typeProfileToProtocol(V8InspectorImpl* inspector,
418 : const v8::debug::TypeProfile& type_profile) {
419 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>
420 : result = protocol::Array<protocol::Profiler::ScriptTypeProfile>::create();
421 : v8::Isolate* isolate = inspector->isolate();
422 90 : for (size_t i = 0; i < type_profile.ScriptCount(); i++) {
423 : v8::debug::TypeProfile::ScriptData script_data =
424 40 : type_profile.GetScriptData(i);
425 40 : v8::Local<v8::debug::Script> script = script_data.GetScript();
426 : std::unique_ptr<protocol::Array<protocol::Profiler::TypeProfileEntry>>
427 : entries =
428 : protocol::Array<protocol::Profiler::TypeProfileEntry>::create();
429 :
430 305 : for (const auto& entry : script_data.Entries()) {
431 : std::unique_ptr<protocol::Array<protocol::Profiler::TypeObject>> types =
432 : protocol::Array<protocol::Profiler::TypeObject>::create();
433 800 : for (const auto& type : entry.Types()) {
434 : types->addItem(
435 : protocol::Profiler::TypeObject::create()
436 : .setName(toProtocolString(
437 735 : isolate, type.FromMaybe(v8::Local<v8::String>())))
438 245 : .build());
439 : }
440 : entries->addItem(protocol::Profiler::TypeProfileEntry::create()
441 370 : .setOffset(entry.SourcePosition())
442 : .setTypes(std::move(types))
443 185 : .build());
444 40 : }
445 40 : String16 url;
446 : v8::Local<v8::String> name;
447 80 : if (script->SourceURL().ToLocal(&name) && name->Length()) {
448 0 : url = toProtocolString(isolate, name);
449 80 : } else if (script->Name().ToLocal(&name) && name->Length()) {
450 80 : url = resourceNameToUrl(inspector, name);
451 : }
452 : result->addItem(protocol::Profiler::ScriptTypeProfile::create()
453 120 : .setScriptId(String16::fromInteger(script->Id()))
454 : .setUrl(url)
455 : .setEntries(std::move(entries))
456 40 : .build());
457 : }
458 50 : return result;
459 : }
460 : } // anonymous namespace
461 :
462 65 : Response V8ProfilerAgentImpl::startTypeProfile() {
463 130 : m_state->setBoolean(ProfilerAgentState::typeProfileStarted, true);
464 : v8::debug::TypeProfile::SelectMode(m_isolate,
465 65 : v8::debug::TypeProfile::kCollect);
466 65 : return Response::OK();
467 : }
468 :
469 60 : Response V8ProfilerAgentImpl::stopTypeProfile() {
470 120 : m_state->setBoolean(ProfilerAgentState::typeProfileStarted, false);
471 60 : v8::debug::TypeProfile::SelectMode(m_isolate, v8::debug::TypeProfile::kNone);
472 60 : return Response::OK();
473 : }
474 :
475 60 : Response V8ProfilerAgentImpl::takeTypeProfile(
476 : std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>*
477 : out_result) {
478 60 : if (!m_state->booleanProperty(ProfilerAgentState::typeProfileStarted,
479 120 : false)) {
480 20 : return Response::Error("Type profile has not been started.");
481 : }
482 50 : v8::HandleScope handle_scope(m_isolate);
483 : v8::debug::TypeProfile type_profile =
484 50 : v8::debug::TypeProfile::Collect(m_isolate);
485 100 : *out_result = typeProfileToProtocol(m_session->inspector(), type_profile);
486 100 : return Response::OK();
487 : }
488 :
489 55 : String16 V8ProfilerAgentImpl::nextProfileId() {
490 : return String16::fromInteger(
491 55 : v8::base::Relaxed_AtomicIncrement(&s_lastProfileId, 1));
492 : }
493 :
494 55 : void V8ProfilerAgentImpl::startProfiling(const String16& title) {
495 55 : v8::HandleScope handleScope(m_isolate);
496 55 : if (!m_startedProfilesCount) {
497 : DCHECK(!m_profiler);
498 35 : m_profiler = v8::CpuProfiler::New(m_isolate);
499 : int interval =
500 70 : m_state->integerProperty(ProfilerAgentState::samplingInterval, 0);
501 35 : if (interval) m_profiler->SetSamplingInterval(interval);
502 : }
503 55 : ++m_startedProfilesCount;
504 55 : m_profiler->StartProfiling(toV8String(m_isolate, title), true);
505 55 : }
506 :
507 55 : std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling(
508 : const String16& title, bool serialize) {
509 55 : v8::HandleScope handleScope(m_isolate);
510 : v8::CpuProfile* profile =
511 55 : m_profiler->StopProfiling(toV8String(m_isolate, title));
512 55 : std::unique_ptr<protocol::Profiler::Profile> result;
513 55 : if (profile) {
514 100 : if (serialize) result = createCPUProfile(m_session->inspector(), profile);
515 55 : profile->Delete();
516 : }
517 55 : --m_startedProfilesCount;
518 55 : if (!m_startedProfilesCount) {
519 35 : m_profiler->Dispose();
520 35 : m_profiler = nullptr;
521 : }
522 55 : return result;
523 : }
524 :
525 : } // namespace v8_inspector
|