LCOV - code coverage report
Current view: top level - src/inspector - v8-profiler-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 187 209 89.5 %
Date: 2017-04-26 Functions: 28 31 90.3 %

          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/inspector/protocol/Protocol.h"
      11             : #include "src/inspector/string-util.h"
      12             : #include "src/inspector/v8-debugger.h"
      13             : #include "src/inspector/v8-inspector-impl.h"
      14             : #include "src/inspector/v8-inspector-session-impl.h"
      15             : #include "src/inspector/v8-stack-trace-impl.h"
      16             : 
      17             : #include "include/v8-profiler.h"
      18             : 
      19             : namespace v8_inspector {
      20             : 
      21             : namespace ProfilerAgentState {
      22             : static const char samplingInterval[] = "samplingInterval";
      23             : static const char userInitiatedProfiling[] = "userInitiatedProfiling";
      24             : static const char profilerEnabled[] = "profilerEnabled";
      25             : static const char preciseCoverageStarted[] = "preciseCoverageStarted";
      26             : static const char preciseCoverageCallCount[] = "preciseCoverageCallCount";
      27             : }
      28             : 
      29             : namespace {
      30             : 
      31             : std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>>
      32         111 : buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node) {
      33         111 :   unsigned lineCount = node->GetHitLineCount();
      34         111 :   if (!lineCount) return nullptr;
      35             :   auto array = protocol::Array<protocol::Profiler::PositionTickInfo>::create();
      36          24 :   std::vector<v8::CpuProfileNode::LineTick> entries(lineCount);
      37          24 :   if (node->GetLineTicks(&entries[0], lineCount)) {
      38          24 :     for (unsigned i = 0; i < lineCount; i++) {
      39             :       std::unique_ptr<protocol::Profiler::PositionTickInfo> line =
      40             :           protocol::Profiler::PositionTickInfo::create()
      41          48 :               .setLine(entries[i].line)
      42          48 :               .setTicks(entries[i].hit_count)
      43             :               .build();
      44          24 :       array->addItem(std::move(line));
      45             :     }
      46             :   }
      47             :   return array;
      48             : }
      49             : 
      50         111 : std::unique_ptr<protocol::Profiler::ProfileNode> buildInspectorObjectFor(
      51             :     v8::Isolate* isolate, const v8::CpuProfileNode* node) {
      52         111 :   v8::HandleScope handleScope(isolate);
      53             :   auto callFrame =
      54             :       protocol::Runtime::CallFrame::create()
      55         333 :           .setFunctionName(toProtocolString(node->GetFunctionName()))
      56         222 :           .setScriptId(String16::fromInteger(node->GetScriptId()))
      57         222 :           .setUrl(toProtocolString(node->GetScriptResourceName()))
      58         111 :           .setLineNumber(node->GetLineNumber() - 1)
      59         111 :           .setColumnNumber(node->GetColumnNumber() - 1)
      60             :           .build();
      61             :   auto result = protocol::Profiler::ProfileNode::create()
      62         111 :                     .setCallFrame(std::move(callFrame))
      63         111 :                     .setHitCount(node->GetHitCount())
      64         111 :                     .setId(node->GetNodeId())
      65             :                     .build();
      66             : 
      67         111 :   const int childrenCount = node->GetChildrenCount();
      68         111 :   if (childrenCount) {
      69             :     auto children = protocol::Array<int>::create();
      70         132 :     for (int i = 0; i < childrenCount; i++)
      71         154 :       children->addItem(node->GetChild(i)->GetNodeId());
      72             :     result->setChildren(std::move(children));
      73             :   }
      74             : 
      75         111 :   const char* deoptReason = node->GetBailoutReason();
      76         111 :   if (deoptReason && deoptReason[0] && strcmp(deoptReason, "no reason"))
      77           0 :     result->setDeoptReason(deoptReason);
      78             : 
      79         111 :   auto positionTicks = buildInspectorObjectForPositionTicks(node);
      80         111 :   if (positionTicks) result->setPositionTicks(std::move(positionTicks));
      81             : 
      82         111 :   return result;
      83             : }
      84             : 
      85          34 : std::unique_ptr<protocol::Array<int>> buildInspectorObjectForSamples(
      86             :     v8::CpuProfile* v8profile) {
      87             :   auto array = protocol::Array<int>::create();
      88          34 :   int count = v8profile->GetSamplesCount();
      89         136 :   for (int i = 0; i < count; i++)
      90         204 :     array->addItem(v8profile->GetSample(i)->GetNodeId());
      91          34 :   return array;
      92             : }
      93             : 
      94          34 : std::unique_ptr<protocol::Array<int>> buildInspectorObjectForTimestamps(
      95             :     v8::CpuProfile* v8profile) {
      96             :   auto array = protocol::Array<int>::create();
      97          34 :   int count = v8profile->GetSamplesCount();
      98          34 :   uint64_t lastTime = v8profile->GetStartTime();
      99         136 :   for (int i = 0; i < count; i++) {
     100         102 :     uint64_t ts = v8profile->GetSampleTimestamp(i);
     101         204 :     array->addItem(static_cast<int>(ts - lastTime));
     102             :     lastTime = ts;
     103             :   }
     104          34 :   return array;
     105             : }
     106             : 
     107         111 : void flattenNodesTree(v8::Isolate* isolate, const v8::CpuProfileNode* node,
     108             :                       protocol::Array<protocol::Profiler::ProfileNode>* list) {
     109         222 :   list->addItem(buildInspectorObjectFor(isolate, node));
     110         111 :   const int childrenCount = node->GetChildrenCount();
     111         188 :   for (int i = 0; i < childrenCount; i++)
     112          77 :     flattenNodesTree(isolate, node->GetChild(i), list);
     113         111 : }
     114             : 
     115          34 : std::unique_ptr<protocol::Profiler::Profile> createCPUProfile(
     116             :     v8::Isolate* isolate, v8::CpuProfile* v8profile) {
     117             :   auto nodes = protocol::Array<protocol::Profiler::ProfileNode>::create();
     118          34 :   flattenNodesTree(isolate, v8profile->GetTopDownRoot(), nodes.get());
     119             :   return protocol::Profiler::Profile::create()
     120          34 :       .setNodes(std::move(nodes))
     121          34 :       .setStartTime(static_cast<double>(v8profile->GetStartTime()))
     122          34 :       .setEndTime(static_cast<double>(v8profile->GetEndTime()))
     123          68 :       .setSamples(buildInspectorObjectForSamples(v8profile))
     124          68 :       .setTimeDeltas(buildInspectorObjectForTimestamps(v8profile))
     125          34 :       .build();
     126             : }
     127             : 
     128          50 : std::unique_ptr<protocol::Debugger::Location> currentDebugLocation(
     129             :     V8InspectorImpl* inspector) {
     130             :   std::unique_ptr<V8StackTraceImpl> callStack =
     131          50 :       inspector->debugger()->captureStackTrace(false /* fullStack */);
     132             :   auto location = protocol::Debugger::Location::create()
     133         150 :                       .setScriptId(toString16(callStack->topScriptId()))
     134          50 :                       .setLineNumber(callStack->topLineNumber())
     135             :                       .build();
     136          50 :   location->setColumnNumber(callStack->topColumnNumber());
     137          50 :   return location;
     138             : }
     139             : 
     140             : volatile int s_lastProfileId = 0;
     141             : 
     142             : }  // namespace
     143             : 
     144           6 : class V8ProfilerAgentImpl::ProfileDescriptor {
     145             :  public:
     146          28 :   ProfileDescriptor(const String16& id, const String16& title)
     147          28 :       : m_id(id), m_title(title) {}
     148             :   String16 m_id;
     149             :   String16 m_title;
     150             : };
     151             : 
     152        4573 : V8ProfilerAgentImpl::V8ProfilerAgentImpl(
     153             :     V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
     154             :     protocol::DictionaryValue* state)
     155             :     : m_session(session),
     156        4573 :       m_isolate(m_session->inspector()->isolate()),
     157             :       m_state(state),
     158       18292 :       m_frontend(frontendChannel) {}
     159             : 
     160       13719 : V8ProfilerAgentImpl::~V8ProfilerAgentImpl() {
     161        4573 :   if (m_profiler) m_profiler->Dispose();
     162        9146 : }
     163             : 
     164          28 : void V8ProfilerAgentImpl::consoleProfile(const String16& title) {
     165          28 :   if (!m_enabled) return;
     166          28 :   String16 id = nextProfileId();
     167          56 :   m_startedProfiles.push_back(ProfileDescriptor(id, title));
     168          28 :   startProfiling(id);
     169             :   m_frontend.consoleProfileStarted(
     170          84 :       id, currentDebugLocation(m_session->inspector()), title);
     171             : }
     172             : 
     173          28 : void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) {
     174          34 :   if (!m_enabled) return;
     175             :   String16 id;
     176             :   String16 resolvedTitle;
     177             :   // Take last started profile if no title was passed.
     178          28 :   if (title.isEmpty()) {
     179          48 :     if (m_startedProfiles.empty()) return;
     180             :     id = m_startedProfiles.back().m_id;
     181             :     resolvedTitle = m_startedProfiles.back().m_title;
     182           2 :     m_startedProfiles.pop_back();
     183             :   } else {
     184          20 :     for (size_t i = 0; i < m_startedProfiles.size(); i++) {
     185          20 :       if (m_startedProfiles[i].m_title == title) {
     186             :         resolvedTitle = title;
     187             :         id = m_startedProfiles[i].m_id;
     188          20 :         m_startedProfiles.erase(m_startedProfiles.begin() + i);
     189          20 :         break;
     190             :       }
     191             :     }
     192          20 :     if (id.isEmpty()) return;
     193             :   }
     194             :   std::unique_ptr<protocol::Profiler::Profile> profile =
     195          22 :       stopProfiling(id, true);
     196          22 :   if (!profile) return;
     197             :   std::unique_ptr<protocol::Debugger::Location> location =
     198          22 :       currentDebugLocation(m_session->inspector());
     199             :   m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile),
     200         110 :                                     resolvedTitle);
     201             : }
     202             : 
     203          80 : Response V8ProfilerAgentImpl::enable() {
     204          80 :   if (m_enabled) return Response::OK();
     205          80 :   m_enabled = true;
     206         160 :   m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
     207          80 :   return Response::OK();
     208             : }
     209             : 
     210        4639 : Response V8ProfilerAgentImpl::disable() {
     211        4639 :   if (!m_enabled) return Response::OK();
     212         252 :   for (size_t i = m_startedProfiles.size(); i > 0; --i)
     213          18 :     stopProfiling(m_startedProfiles[i - 1].m_id, false);
     214             :   m_startedProfiles.clear();
     215         160 :   stop(nullptr);
     216         160 :   stopPreciseCoverage();
     217             :   DCHECK(!m_profiler);
     218          80 :   m_enabled = false;
     219         160 :   m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
     220          80 :   return Response::OK();
     221             : }
     222             : 
     223           0 : Response V8ProfilerAgentImpl::setSamplingInterval(int interval) {
     224           0 :   if (m_profiler) {
     225           0 :     return Response::Error("Cannot change sampling interval when profiling.");
     226             :   }
     227           0 :   m_state->setInteger(ProfilerAgentState::samplingInterval, interval);
     228           0 :   return Response::OK();
     229             : }
     230             : 
     231          36 : void V8ProfilerAgentImpl::restore() {
     232             :   DCHECK(!m_enabled);
     233          72 :   if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false))
     234          36 :     return;
     235           0 :   m_enabled = true;
     236             :   DCHECK(!m_profiler);
     237           0 :   if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling,
     238           0 :                                false)) {
     239           0 :     start();
     240             :   }
     241           0 :   if (m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
     242           0 :                                false)) {
     243             :     bool callCount = m_state->booleanProperty(
     244           0 :         ProfilerAgentState::preciseCoverageCallCount, false);
     245           0 :     startPreciseCoverage(Maybe<bool>(callCount));
     246             :   }
     247             : }
     248             : 
     249          24 : Response V8ProfilerAgentImpl::start() {
     250          24 :   if (m_recordingCPUProfile) return Response::OK();
     251          30 :   if (!m_enabled) return Response::Error("Profiler is not enabled");
     252          18 :   m_recordingCPUProfile = true;
     253          36 :   m_frontendInitiatedProfileId = nextProfileId();
     254          18 :   startProfiling(m_frontendInitiatedProfileId);
     255          36 :   m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
     256          18 :   return Response::OK();
     257             : }
     258             : 
     259         104 : Response V8ProfilerAgentImpl::stop(
     260             :     std::unique_ptr<protocol::Profiler::Profile>* profile) {
     261         104 :   if (!m_recordingCPUProfile) {
     262         172 :     return Response::Error("No recording profiles found");
     263             :   }
     264          18 :   m_recordingCPUProfile = false;
     265             :   std::unique_ptr<protocol::Profiler::Profile> cpuProfile =
     266          18 :       stopProfiling(m_frontendInitiatedProfileId, !!profile);
     267          18 :   if (profile) {
     268             :     *profile = std::move(cpuProfile);
     269          12 :     if (!profile->get()) return Response::Error("Profile is not found");
     270             :   }
     271             :   m_frontendInitiatedProfileId = String16();
     272          36 :   m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
     273          18 :   return Response::OK();
     274             : }
     275             : 
     276          48 : Response V8ProfilerAgentImpl::startPreciseCoverage(Maybe<bool> callCount) {
     277          48 :   if (!m_enabled) return Response::Error("Profiler is not enabled");
     278             :   bool callCountValue = callCount.fromMaybe(false);
     279          96 :   m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, true);
     280             :   m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount,
     281          96 :                       callCountValue);
     282             :   v8::debug::Coverage::SelectMode(
     283             :       m_isolate, callCountValue ? v8::debug::Coverage::kPreciseCount
     284          48 :                                 : v8::debug::Coverage::kPreciseBinary);
     285          48 :   return Response::OK();
     286             : }
     287             : 
     288         128 : Response V8ProfilerAgentImpl::stopPreciseCoverage() {
     289         128 :   if (!m_enabled) return Response::Error("Profiler is not enabled");
     290         256 :   m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false);
     291         256 :   m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount, false);
     292         128 :   v8::debug::Coverage::SelectMode(m_isolate, v8::debug::Coverage::kBestEffort);
     293         128 :   return Response::OK();
     294             : }
     295             : 
     296             : namespace {
     297          96 : Response coverageToProtocol(
     298             :     v8::Isolate* isolate, const v8::debug::Coverage& coverage,
     299             :     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
     300             :         out_result) {
     301             :   std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> result =
     302             :       protocol::Array<protocol::Profiler::ScriptCoverage>::create();
     303         120 :   for (size_t i = 0; i < coverage.ScriptCount(); i++) {
     304         120 :     v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
     305         120 :     v8::Local<v8::debug::Script> script = script_data.GetScript();
     306             :     std::unique_ptr<protocol::Array<protocol::Profiler::FunctionCoverage>>
     307             :         functions =
     308             :             protocol::Array<protocol::Profiler::FunctionCoverage>::create();
     309         288 :     for (size_t j = 0; j < script_data.FunctionCount(); j++) {
     310             :       v8::debug::Coverage::FunctionData function_data =
     311         288 :           script_data.GetFunctionData(j);
     312             :       std::unique_ptr<protocol::Array<protocol::Profiler::CoverageRange>>
     313             :           ranges = protocol::Array<protocol::Profiler::CoverageRange>::create();
     314             :       // At this point we only have per-function coverage data, so there is
     315             :       // only one range per function.
     316             :       ranges->addItem(protocol::Profiler::CoverageRange::create()
     317         576 :                           .setStartOffset(function_data.StartOffset())
     318         288 :                           .setEndOffset(function_data.EndOffset())
     319         288 :                           .setCount(function_data.Count())
     320         288 :                           .build());
     321             :       functions->addItem(
     322             :           protocol::Profiler::FunctionCoverage::create()
     323             :               .setFunctionName(toProtocolString(
     324        1152 :                   function_data.Name().FromMaybe(v8::Local<v8::String>())))
     325             :               .setRanges(std::move(ranges))
     326         288 :               .build());
     327             :     }
     328             :     String16 url;
     329             :     v8::Local<v8::String> name;
     330         240 :     if (script->Name().ToLocal(&name) || script->SourceURL().ToLocal(&name)) {
     331         240 :       url = toProtocolString(name);
     332             :     }
     333             :     result->addItem(protocol::Profiler::ScriptCoverage::create()
     334         360 :                         .setScriptId(String16::fromInteger(script->Id()))
     335             :                         .setUrl(url)
     336             :                         .setFunctions(std::move(functions))
     337         120 :                         .build());
     338             :   }
     339             :   *out_result = std::move(result);
     340          96 :   return Response::OK();
     341             : }
     342             : }  // anonymous namespace
     343             : 
     344          66 : Response V8ProfilerAgentImpl::takePreciseCoverage(
     345             :     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
     346             :         out_result) {
     347          66 :   if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
     348         132 :                                 false)) {
     349          12 :     return Response::Error("Precise coverage has not been started.");
     350             :   }
     351          60 :   v8::HandleScope handle_scope(m_isolate);
     352         120 :   v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(m_isolate);
     353         120 :   return coverageToProtocol(m_isolate, coverage, out_result);
     354             : }
     355             : 
     356          36 : Response V8ProfilerAgentImpl::getBestEffortCoverage(
     357             :     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
     358             :         out_result) {
     359          36 :   v8::HandleScope handle_scope(m_isolate);
     360             :   v8::debug::Coverage coverage =
     361          72 :       v8::debug::Coverage::CollectBestEffort(m_isolate);
     362          72 :   return coverageToProtocol(m_isolate, coverage, out_result);
     363             : }
     364             : 
     365          46 : String16 V8ProfilerAgentImpl::nextProfileId() {
     366             :   return String16::fromInteger(
     367          46 :       v8::base::NoBarrier_AtomicIncrement(&s_lastProfileId, 1));
     368             : }
     369             : 
     370          46 : void V8ProfilerAgentImpl::startProfiling(const String16& title) {
     371          46 :   v8::HandleScope handleScope(m_isolate);
     372          46 :   if (!m_startedProfilesCount) {
     373             :     DCHECK(!m_profiler);
     374          32 :     m_profiler = v8::CpuProfiler::New(m_isolate);
     375          32 :     m_profiler->SetIdle(m_idle);
     376             :     int interval =
     377          64 :         m_state->integerProperty(ProfilerAgentState::samplingInterval, 0);
     378          32 :     if (interval) m_profiler->SetSamplingInterval(interval);
     379             :   }
     380          46 :   ++m_startedProfilesCount;
     381          46 :   m_profiler->StartProfiling(toV8String(m_isolate, title), true);
     382          46 : }
     383             : 
     384          46 : std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling(
     385             :     const String16& title, bool serialize) {
     386          46 :   v8::HandleScope handleScope(m_isolate);
     387             :   v8::CpuProfile* profile =
     388          46 :       m_profiler->StopProfiling(toV8String(m_isolate, title));
     389          46 :   std::unique_ptr<protocol::Profiler::Profile> result;
     390          46 :   if (profile) {
     391          80 :     if (serialize) result = createCPUProfile(m_isolate, profile);
     392          46 :     profile->Delete();
     393             :   }
     394          46 :   --m_startedProfilesCount;
     395          46 :   if (!m_startedProfilesCount) {
     396          32 :     m_profiler->Dispose();
     397          32 :     m_profiler = nullptr;
     398             :   }
     399          46 :   return result;
     400             : }
     401             : 
     402           0 : bool V8ProfilerAgentImpl::idleStarted() {
     403           0 :   m_idle = true;
     404           0 :   if (m_profiler) m_profiler->SetIdle(m_idle);
     405           0 :   return m_profiler;
     406             : }
     407             : 
     408           0 : bool V8ProfilerAgentImpl::idleFinished() {
     409           0 :   m_idle = false;
     410           0 :   if (m_profiler) m_profiler->SetIdle(m_idle);
     411           0 :   return m_profiler;
     412             : }
     413             : 
     414             : }  // namespace v8_inspector

Generated by: LCOV version 1.10