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