| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright 2015 The Chromium 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 "platform/v8_inspector/V8ProfilerAgentImpl.h" |  | 
|    6  |  | 
|    7 #include "platform/v8_inspector/Atomics.h" |  | 
|    8 #include "platform/v8_inspector/StringUtil.h" |  | 
|    9 #include "platform/v8_inspector/V8Debugger.h" |  | 
|   10 #include "platform/v8_inspector/V8InspectorImpl.h" |  | 
|   11 #include "platform/v8_inspector/V8InspectorSessionImpl.h" |  | 
|   12 #include "platform/v8_inspector/V8StackTraceImpl.h" |  | 
|   13 #include "platform/v8_inspector/protocol/Protocol.h" |  | 
|   14 #include <v8-profiler.h> |  | 
|   15  |  | 
|   16 #include <vector> |  | 
|   17  |  | 
|   18 #define ENSURE_V8_VERSION(major, minor) \ |  | 
|   19     (V8_MAJOR_VERSION * 1000 + V8_MINOR_VERSION >= (major) * 1000 + (minor)) |  | 
|   20  |  | 
|   21 namespace v8_inspector { |  | 
|   22  |  | 
|   23 namespace ProfilerAgentState { |  | 
|   24 static const char samplingInterval[] = "samplingInterval"; |  | 
|   25 static const char userInitiatedProfiling[] = "userInitiatedProfiling"; |  | 
|   26 static const char profilerEnabled[] = "profilerEnabled"; |  | 
|   27 } |  | 
|   28  |  | 
|   29 namespace { |  | 
|   30  |  | 
|   31 std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>> buildInsp
     ectorObjectForPositionTicks(const v8::CpuProfileNode* node) |  | 
|   32 { |  | 
|   33     unsigned lineCount = node->GetHitLineCount(); |  | 
|   34     if (!lineCount) |  | 
|   35         return nullptr; |  | 
|   36     auto array = protocol::Array<protocol::Profiler::PositionTickInfo>::create()
     ; |  | 
|   37     std::vector<v8::CpuProfileNode::LineTick> entries(lineCount); |  | 
|   38     if (node->GetLineTicks(&entries[0], lineCount)) { |  | 
|   39         for (unsigned i = 0; i < lineCount; i++) { |  | 
|   40             std::unique_ptr<protocol::Profiler::PositionTickInfo> line = protoco
     l::Profiler::PositionTickInfo::create() |  | 
|   41                 .setLine(entries[i].line) |  | 
|   42                 .setTicks(entries[i].hit_count).build(); |  | 
|   43             array->addItem(std::move(line)); |  | 
|   44         } |  | 
|   45     } |  | 
|   46     return array; |  | 
|   47 } |  | 
|   48  |  | 
|   49 std::unique_ptr<protocol::Profiler::ProfileNode> buildInspectorObjectFor(v8::Iso
     late* isolate, const v8::CpuProfileNode* node) |  | 
|   50 { |  | 
|   51     v8::HandleScope handleScope(isolate); |  | 
|   52     auto callFrame = protocol::Runtime::CallFrame::create() |  | 
|   53         .setFunctionName(toProtocolString(node->GetFunctionName())) |  | 
|   54         .setScriptId(String16::fromInteger(node->GetScriptId())) |  | 
|   55         .setUrl(toProtocolString(node->GetScriptResourceName())) |  | 
|   56         .setLineNumber(node->GetLineNumber() - 1) |  | 
|   57         .setColumnNumber(node->GetColumnNumber() - 1) |  | 
|   58         .build(); |  | 
|   59     auto result = protocol::Profiler::ProfileNode::create() |  | 
|   60         .setCallFrame(std::move(callFrame)) |  | 
|   61         .setHitCount(node->GetHitCount()) |  | 
|   62         .setId(node->GetNodeId()).build(); |  | 
|   63  |  | 
|   64     const int childrenCount = node->GetChildrenCount(); |  | 
|   65     if (childrenCount) { |  | 
|   66         auto children = protocol::Array<int>::create(); |  | 
|   67         for (int i = 0; i < childrenCount; i++) |  | 
|   68             children->addItem(node->GetChild(i)->GetNodeId()); |  | 
|   69         result->setChildren(std::move(children)); |  | 
|   70     } |  | 
|   71  |  | 
|   72     const char* deoptReason = node->GetBailoutReason(); |  | 
|   73     if (deoptReason && deoptReason[0] && strcmp(deoptReason, "no reason")) |  | 
|   74         result->setDeoptReason(deoptReason); |  | 
|   75  |  | 
|   76     auto positionTicks = buildInspectorObjectForPositionTicks(node); |  | 
|   77     if (positionTicks) |  | 
|   78         result->setPositionTicks(std::move(positionTicks)); |  | 
|   79  |  | 
|   80     return result; |  | 
|   81 } |  | 
|   82  |  | 
|   83 std::unique_ptr<protocol::Array<int>> buildInspectorObjectForSamples(v8::CpuProf
     ile* v8profile) |  | 
|   84 { |  | 
|   85     auto array = protocol::Array<int>::create(); |  | 
|   86     int count = v8profile->GetSamplesCount(); |  | 
|   87     for (int i = 0; i < count; i++) |  | 
|   88         array->addItem(v8profile->GetSample(i)->GetNodeId()); |  | 
|   89     return array; |  | 
|   90 } |  | 
|   91  |  | 
|   92 std::unique_ptr<protocol::Array<int>> buildInspectorObjectForTimestamps(v8::CpuP
     rofile* v8profile) |  | 
|   93 { |  | 
|   94     auto array = protocol::Array<int>::create(); |  | 
|   95     int count = v8profile->GetSamplesCount(); |  | 
|   96     uint64_t lastTime = v8profile->GetStartTime(); |  | 
|   97     for (int i = 0; i < count; i++) { |  | 
|   98         uint64_t ts = v8profile->GetSampleTimestamp(i); |  | 
|   99         array->addItem(static_cast<int>(ts - lastTime)); |  | 
|  100         lastTime = ts; |  | 
|  101     } |  | 
|  102     return array; |  | 
|  103 } |  | 
|  104  |  | 
|  105 void flattenNodesTree(v8::Isolate* isolate, const v8::CpuProfileNode* node, prot
     ocol::Array<protocol::Profiler::ProfileNode>* list) |  | 
|  106 { |  | 
|  107     list->addItem(buildInspectorObjectFor(isolate, node)); |  | 
|  108     const int childrenCount = node->GetChildrenCount(); |  | 
|  109     for (int i = 0; i < childrenCount; i++) |  | 
|  110         flattenNodesTree(isolate, node->GetChild(i), list); |  | 
|  111 } |  | 
|  112  |  | 
|  113 std::unique_ptr<protocol::Profiler::Profile> createCPUProfile(v8::Isolate* isola
     te, v8::CpuProfile* v8profile) |  | 
|  114 { |  | 
|  115     auto nodes = protocol::Array<protocol::Profiler::ProfileNode>::create(); |  | 
|  116     flattenNodesTree(isolate, v8profile->GetTopDownRoot(), nodes.get()); |  | 
|  117     return protocol::Profiler::Profile::create() |  | 
|  118         .setNodes(std::move(nodes)) |  | 
|  119         .setStartTime(static_cast<double>(v8profile->GetStartTime())) |  | 
|  120         .setEndTime(static_cast<double>(v8profile->GetEndTime())) |  | 
|  121         .setSamples(buildInspectorObjectForSamples(v8profile)) |  | 
|  122         .setTimeDeltas(buildInspectorObjectForTimestamps(v8profile)).build(); |  | 
|  123 } |  | 
|  124  |  | 
|  125 std::unique_ptr<protocol::Debugger::Location> currentDebugLocation(V8InspectorIm
     pl* inspector) |  | 
|  126 { |  | 
|  127     std::unique_ptr<V8StackTraceImpl> callStack = inspector->debugger()->capture
     StackTrace(false /* fullStack */); |  | 
|  128     auto location = protocol::Debugger::Location::create() |  | 
|  129         .setScriptId(toString16(callStack->topScriptId())) |  | 
|  130         .setLineNumber(callStack->topLineNumber()).build(); |  | 
|  131     location->setColumnNumber(callStack->topColumnNumber()); |  | 
|  132     return location; |  | 
|  133 } |  | 
|  134  |  | 
|  135 volatile int s_lastProfileId = 0; |  | 
|  136  |  | 
|  137 } // namespace |  | 
|  138  |  | 
|  139 class V8ProfilerAgentImpl::ProfileDescriptor { |  | 
|  140 public: |  | 
|  141     ProfileDescriptor(const String16& id, const String16& title) |  | 
|  142         : m_id(id) |  | 
|  143         , m_title(title) { } |  | 
|  144     String16 m_id; |  | 
|  145     String16 m_title; |  | 
|  146 }; |  | 
|  147  |  | 
|  148 V8ProfilerAgentImpl::V8ProfilerAgentImpl(V8InspectorSessionImpl* session, protoc
     ol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) |  | 
|  149     : m_session(session) |  | 
|  150     , m_isolate(m_session->inspector()->isolate()) |  | 
|  151     , m_profiler(nullptr) |  | 
|  152     , m_state(state) |  | 
|  153     , m_frontend(frontendChannel) |  | 
|  154     , m_enabled(false) |  | 
|  155     , m_recordingCPUProfile(false) |  | 
|  156 { |  | 
|  157 } |  | 
|  158  |  | 
|  159 V8ProfilerAgentImpl::~V8ProfilerAgentImpl() |  | 
|  160 { |  | 
|  161 #if ENSURE_V8_VERSION(5, 4) |  | 
|  162     if (m_profiler) |  | 
|  163         m_profiler->Dispose(); |  | 
|  164 #endif |  | 
|  165 } |  | 
|  166  |  | 
|  167 void V8ProfilerAgentImpl::consoleProfile(const String16& title) |  | 
|  168 { |  | 
|  169     if (!m_enabled) |  | 
|  170         return; |  | 
|  171     String16 id = nextProfileId(); |  | 
|  172     m_startedProfiles.push_back(ProfileDescriptor(id, title)); |  | 
|  173     startProfiling(id); |  | 
|  174     m_frontend.consoleProfileStarted(id, currentDebugLocation(m_session->inspect
     or()), title); |  | 
|  175 } |  | 
|  176  |  | 
|  177 void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) |  | 
|  178 { |  | 
|  179     if (!m_enabled) |  | 
|  180         return; |  | 
|  181     String16 id; |  | 
|  182     String16 resolvedTitle; |  | 
|  183     // Take last started profile if no title was passed. |  | 
|  184     if (title.isEmpty()) { |  | 
|  185         if (m_startedProfiles.empty()) |  | 
|  186             return; |  | 
|  187         id = m_startedProfiles.back().m_id; |  | 
|  188         resolvedTitle = m_startedProfiles.back().m_title; |  | 
|  189         m_startedProfiles.pop_back(); |  | 
|  190     } else { |  | 
|  191         for (size_t i = 0; i < m_startedProfiles.size(); i++) { |  | 
|  192             if (m_startedProfiles[i].m_title == title) { |  | 
|  193                 resolvedTitle = title; |  | 
|  194                 id = m_startedProfiles[i].m_id; |  | 
|  195                 m_startedProfiles.erase(m_startedProfiles.begin() + i); |  | 
|  196                 break; |  | 
|  197             } |  | 
|  198         } |  | 
|  199         if (id.isEmpty()) |  | 
|  200             return; |  | 
|  201     } |  | 
|  202     std::unique_ptr<protocol::Profiler::Profile> profile = stopProfiling(id, tru
     e); |  | 
|  203     if (!profile) |  | 
|  204         return; |  | 
|  205     std::unique_ptr<protocol::Debugger::Location> location = currentDebugLocatio
     n(m_session->inspector()); |  | 
|  206     m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile
     ), resolvedTitle); |  | 
|  207 } |  | 
|  208  |  | 
|  209 void V8ProfilerAgentImpl::enable(ErrorString*) |  | 
|  210 { |  | 
|  211     if (m_enabled) |  | 
|  212         return; |  | 
|  213     m_enabled = true; |  | 
|  214 #if ENSURE_V8_VERSION(5, 4) |  | 
|  215     DCHECK(!m_profiler); |  | 
|  216     m_profiler = v8::CpuProfiler::New(m_isolate); |  | 
|  217 #endif |  | 
|  218     m_state->setBoolean(ProfilerAgentState::profilerEnabled, true); |  | 
|  219 } |  | 
|  220  |  | 
|  221 void V8ProfilerAgentImpl::disable(ErrorString* errorString) |  | 
|  222 { |  | 
|  223     if (!m_enabled) |  | 
|  224         return; |  | 
|  225     for (size_t i = m_startedProfiles.size(); i > 0; --i) |  | 
|  226         stopProfiling(m_startedProfiles[i - 1].m_id, false); |  | 
|  227     m_startedProfiles.clear(); |  | 
|  228     stop(nullptr, nullptr); |  | 
|  229 #if ENSURE_V8_VERSION(5, 4) |  | 
|  230     m_profiler->Dispose(); |  | 
|  231     m_profiler = nullptr; |  | 
|  232 #endif |  | 
|  233     m_enabled = false; |  | 
|  234     m_state->setBoolean(ProfilerAgentState::profilerEnabled, false); |  | 
|  235 } |  | 
|  236  |  | 
|  237 void V8ProfilerAgentImpl::setSamplingInterval(ErrorString* error, int interval) |  | 
|  238 { |  | 
|  239     if (m_recordingCPUProfile) { |  | 
|  240         *error = "Cannot change sampling interval when profiling."; |  | 
|  241         return; |  | 
|  242     } |  | 
|  243     m_state->setInteger(ProfilerAgentState::samplingInterval, interval); |  | 
|  244     profiler()->SetSamplingInterval(interval); |  | 
|  245 } |  | 
|  246  |  | 
|  247 void V8ProfilerAgentImpl::restore() |  | 
|  248 { |  | 
|  249     DCHECK(!m_enabled); |  | 
|  250     if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false)) |  | 
|  251         return; |  | 
|  252     m_enabled = true; |  | 
|  253 #if ENSURE_V8_VERSION(5, 4) |  | 
|  254     DCHECK(!m_profiler); |  | 
|  255     m_profiler = v8::CpuProfiler::New(m_isolate); |  | 
|  256 #endif |  | 
|  257     int interval = 0; |  | 
|  258     m_state->getInteger(ProfilerAgentState::samplingInterval, &interval); |  | 
|  259     if (interval) |  | 
|  260         profiler()->SetSamplingInterval(interval); |  | 
|  261     if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling, fal
     se)) { |  | 
|  262         ErrorString error; |  | 
|  263         start(&error); |  | 
|  264     } |  | 
|  265 } |  | 
|  266  |  | 
|  267 void V8ProfilerAgentImpl::start(ErrorString* error) |  | 
|  268 { |  | 
|  269     if (m_recordingCPUProfile) |  | 
|  270         return; |  | 
|  271     if (!m_enabled) { |  | 
|  272         *error = "Profiler is not enabled"; |  | 
|  273         return; |  | 
|  274     } |  | 
|  275     m_recordingCPUProfile = true; |  | 
|  276     m_frontendInitiatedProfileId = nextProfileId(); |  | 
|  277     startProfiling(m_frontendInitiatedProfileId); |  | 
|  278     m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true); |  | 
|  279 } |  | 
|  280  |  | 
|  281 void V8ProfilerAgentImpl::stop(ErrorString* errorString, std::unique_ptr<protoco
     l::Profiler::Profile>* profile) |  | 
|  282 { |  | 
|  283     if (!m_recordingCPUProfile) { |  | 
|  284         if (errorString) |  | 
|  285             *errorString = "No recording profiles found"; |  | 
|  286         return; |  | 
|  287     } |  | 
|  288     m_recordingCPUProfile = false; |  | 
|  289     std::unique_ptr<protocol::Profiler::Profile> cpuProfile = stopProfiling(m_fr
     ontendInitiatedProfileId, !!profile); |  | 
|  290     if (profile) { |  | 
|  291         *profile = std::move(cpuProfile); |  | 
|  292         if (!profile->get() && errorString) |  | 
|  293             *errorString = "Profile is not found"; |  | 
|  294     } |  | 
|  295     m_frontendInitiatedProfileId = String16(); |  | 
|  296     m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false); |  | 
|  297 } |  | 
|  298  |  | 
|  299 String16 V8ProfilerAgentImpl::nextProfileId() |  | 
|  300 { |  | 
|  301     return String16::fromInteger(atomicIncrement(&s_lastProfileId)); |  | 
|  302 } |  | 
|  303  |  | 
|  304 void V8ProfilerAgentImpl::startProfiling(const String16& title) |  | 
|  305 { |  | 
|  306     v8::HandleScope handleScope(m_isolate); |  | 
|  307     profiler()->StartProfiling(toV8String(m_isolate, title), true); |  | 
|  308 } |  | 
|  309  |  | 
|  310 std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling(
     const String16& title, bool serialize) |  | 
|  311 { |  | 
|  312     v8::HandleScope handleScope(m_isolate); |  | 
|  313     v8::CpuProfile* profile = profiler()->StopProfiling(toV8String(m_isolate, ti
     tle)); |  | 
|  314     if (!profile) |  | 
|  315         return nullptr; |  | 
|  316     std::unique_ptr<protocol::Profiler::Profile> result; |  | 
|  317     if (serialize) |  | 
|  318         result = createCPUProfile(m_isolate, profile); |  | 
|  319     profile->Delete(); |  | 
|  320     return result; |  | 
|  321 } |  | 
|  322  |  | 
|  323 bool V8ProfilerAgentImpl::isRecording() const |  | 
|  324 { |  | 
|  325     return m_recordingCPUProfile || !m_startedProfiles.empty(); |  | 
|  326 } |  | 
|  327  |  | 
|  328 v8::CpuProfiler* V8ProfilerAgentImpl::profiler() |  | 
|  329 { |  | 
|  330 #if ENSURE_V8_VERSION(5, 4) |  | 
|  331     return m_profiler; |  | 
|  332 #else |  | 
|  333     return m_isolate->GetCpuProfiler(); |  | 
|  334 #endif |  | 
|  335 } |  | 
|  336  |  | 
|  337 } // namespace v8_inspector |  | 
| OLD | NEW |