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