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