Chromium Code Reviews| Index: src/inspector/v8-profiler-agent-impl.cc |
| diff --git a/src/inspector/v8-profiler-agent-impl.cc b/src/inspector/v8-profiler-agent-impl.cc |
| index 16c4777e84db7eda02e92c05dfee506fd7884785..c7d1cc26174bd07698943ed3290047a67695e3bd 100644 |
| --- a/src/inspector/v8-profiler-agent-impl.cc |
| +++ b/src/inspector/v8-profiler-agent-impl.cc |
| @@ -22,6 +22,7 @@ namespace ProfilerAgentState { |
| static const char samplingInterval[] = "samplingInterval"; |
| static const char userInitiatedProfiling[] = "userInitiatedProfiling"; |
| static const char profilerEnabled[] = "profilerEnabled"; |
| +static const char preciseCoverageStarted[] = "preciseCoverageStarted"; |
| } |
| namespace { |
| @@ -152,11 +153,8 @@ V8ProfilerAgentImpl::V8ProfilerAgentImpl( |
| protocol::DictionaryValue* state) |
| : m_session(session), |
| m_isolate(m_session->inspector()->isolate()), |
| - m_profiler(nullptr), |
| m_state(state), |
| - m_frontend(frontendChannel), |
| - m_enabled(false), |
| - m_recordingCPUProfile(false) {} |
| + m_frontend(frontendChannel) {} |
| V8ProfilerAgentImpl::~V8ProfilerAgentImpl() { |
| if (m_profiler) m_profiler->Dispose(); |
| @@ -204,8 +202,6 @@ void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) { |
| Response V8ProfilerAgentImpl::enable() { |
| if (m_enabled) return Response::OK(); |
| m_enabled = true; |
| - DCHECK(!m_profiler); |
| - m_profiler = v8::CpuProfiler::New(m_isolate); |
| m_state->setBoolean(ProfilerAgentState::profilerEnabled, true); |
| return Response::OK(); |
| } |
| @@ -216,18 +212,18 @@ Response V8ProfilerAgentImpl::disable() { |
| stopProfiling(m_startedProfiles[i - 1].m_id, false); |
| m_startedProfiles.clear(); |
| stop(nullptr); |
| - m_profiler->Dispose(); |
| - m_profiler = nullptr; |
| + stopPreciseCoverage(); |
| + DCHECK(!m_profiler); |
| m_enabled = false; |
| m_state->setBoolean(ProfilerAgentState::profilerEnabled, false); |
| return Response::OK(); |
| } |
| Response V8ProfilerAgentImpl::setSamplingInterval(int interval) { |
| - if (m_recordingCPUProfile) |
| + if (m_profiler) { |
| return Response::Error("Cannot change sampling interval when profiling."); |
| + } |
| m_state->setInteger(ProfilerAgentState::samplingInterval, interval); |
| - m_profiler->SetSamplingInterval(interval); |
| return Response::OK(); |
| } |
| @@ -237,14 +233,14 @@ void V8ProfilerAgentImpl::restore() { |
| return; |
| m_enabled = true; |
| DCHECK(!m_profiler); |
| - m_profiler = v8::CpuProfiler::New(m_isolate); |
| - int interval = 0; |
| - m_state->getInteger(ProfilerAgentState::samplingInterval, &interval); |
| - if (interval) m_profiler->SetSamplingInterval(interval); |
| if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling, |
| false)) { |
| start(); |
| } |
| + if (m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted, |
| + false)) { |
| + startPreciseCoverage(); |
| + } |
| } |
| Response V8ProfilerAgentImpl::start() { |
| @@ -259,8 +255,9 @@ Response V8ProfilerAgentImpl::start() { |
| Response V8ProfilerAgentImpl::stop( |
| std::unique_ptr<protocol::Profiler::Profile>* profile) { |
| - if (!m_recordingCPUProfile) |
| + if (!m_recordingCPUProfile) { |
| return Response::Error("No recording profiles found"); |
| + } |
| m_recordingCPUProfile = false; |
| std::unique_ptr<protocol::Profiler::Profile> cpuProfile = |
| stopProfiling(m_frontendInitiatedProfileId, !!profile); |
| @@ -273,6 +270,90 @@ Response V8ProfilerAgentImpl::stop( |
| return Response::OK(); |
| } |
| +Response V8ProfilerAgentImpl::startPreciseCoverage() { |
| + if (!m_enabled) return Response::Error("Profiler is not enabled"); |
| + m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, true); |
| + v8::debug::Coverage::TogglePrecise(m_isolate, true); |
| + return Response::OK(); |
| +} |
| + |
| +Response V8ProfilerAgentImpl::stopPreciseCoverage() { |
| + if (!m_enabled) return Response::Error("Profiler is not enabled"); |
| + m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false); |
| + v8::debug::Coverage::TogglePrecise(m_isolate, false); |
| + return Response::OK(); |
| +} |
| + |
| +namespace { |
| +Response takeCoverage( |
| + v8::Isolate* isolate, bool reset_count, |
| + std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| + out_result) { |
| + std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> result = |
| + protocol::Array<protocol::Profiler::ScriptCoverage>::create(); |
| + v8::HandleScope handle_scope(isolate); |
| + v8::debug::Coverage coverage = |
| + v8::debug::Coverage::Collect(isolate, reset_count); |
| + for (size_t i = 0; i < coverage.ScriptCount(); i++) { |
| + v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i); |
| + v8::Local<v8::debug::Script> script = script_data.GetScript(); |
| + std::unique_ptr<protocol::Array<protocol::Profiler::FunctionCoverage>> |
| + functions = |
| + protocol::Array<protocol::Profiler::FunctionCoverage>::create(); |
| + for (size_t j = 0; j < script_data.FunctionCount(); j++) { |
| + v8::debug::Coverage::FunctionData function_data = |
| + script_data.GetFunctionData(j); |
| + std::unique_ptr<protocol::Array<protocol::Profiler::CoverageRange>> |
| + ranges = protocol::Array<protocol::Profiler::CoverageRange>::create(); |
| + // At this point we only have per-function coverage data, so there is |
| + // only one range per function. |
| + ranges->addItem( |
| + protocol::Profiler::CoverageRange::create() |
| + .setStartLineNumber(function_data.Start().GetLineNumber()) |
| + .setStartColumnNumber(function_data.Start().GetColumnNumber()) |
| + .setEndLineNumber(function_data.End().GetLineNumber()) |
| + .setEndColumnNumber(function_data.End().GetColumnNumber()) |
| + .setCount(function_data.Count()) |
| + .build()); |
| + functions->addItem( |
| + protocol::Profiler::FunctionCoverage::create() |
| + .setFunctionName(toProtocolString( |
| + function_data.Name().FromMaybe(v8::Local<v8::String>()))) |
| + .setRanges(std::move(ranges)) |
| + .build()); |
| + } |
| + String16 url; |
| + v8::Local<v8::String> name; |
| + if (script->Name().ToLocal(&name) || script->SourceURL().ToLocal(&name)) { |
| + url = toProtocolString(name); |
| + } |
| + result->addItem(protocol::Profiler::ScriptCoverage::create() |
| + .setScriptId(String16::fromInteger(script->Id())) |
| + .setUrl(url) |
| + .setFunctions(std::move(functions)) |
| + .build()); |
| + } |
| + *out_result = std::move(result); |
| + return Response::OK(); |
| +} |
| +} // anonymous namespace |
| + |
| +Response V8ProfilerAgentImpl::takePreciseCoverage( |
| + std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| + out_result) { |
| + if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted, |
| + false)) { |
| + return Response::Error("Precise coverage has not been started."); |
| + } |
| + return takeCoverage(m_isolate, true, out_result); |
| +} |
| + |
| +Response V8ProfilerAgentImpl::getBestEffortCoverage( |
| + std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| + out_result) { |
| + return takeCoverage(m_isolate, false, out_result); |
| +} |
| + |
| String16 V8ProfilerAgentImpl::nextProfileId() { |
| return String16::fromInteger( |
| v8::base::NoBarrier_AtomicIncrement(&s_lastProfileId, 1)); |
| @@ -280,6 +361,15 @@ String16 V8ProfilerAgentImpl::nextProfileId() { |
| void V8ProfilerAgentImpl::startProfiling(const String16& title) { |
| v8::HandleScope handleScope(m_isolate); |
| + if (!m_startedProfilesCount) { |
| + DCHECK(!m_profiler); |
| + m_profiler = v8::CpuProfiler::New(m_isolate); |
| + m_profiler->SetIdle(m_idle); |
|
alph
2017/02/24 03:12:56
Do you really need that? I bet m_idle is always fa
kozy
2017/02/24 03:15:41
I'm not sure. I'll try to get rid of this flag in
|
| + int interval = |
| + m_state->integerProperty(ProfilerAgentState::samplingInterval, 0); |
| + if (interval) m_profiler->SetSamplingInterval(interval); |
| + } |
| + ++m_startedProfilesCount; |
| m_profiler->StartProfiling(toV8String(m_isolate, title), true); |
| } |
| @@ -288,24 +378,28 @@ std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling( |
| v8::HandleScope handleScope(m_isolate); |
| v8::CpuProfile* profile = |
| m_profiler->StopProfiling(toV8String(m_isolate, title)); |
| - if (!profile) return nullptr; |
| std::unique_ptr<protocol::Profiler::Profile> result; |
| - if (serialize) result = createCPUProfile(m_isolate, profile); |
| - profile->Delete(); |
| + if (profile) { |
| + if (serialize) result = createCPUProfile(m_isolate, profile); |
| + profile->Delete(); |
| + } |
| + --m_startedProfilesCount; |
| + if (!m_startedProfilesCount) { |
| + m_profiler->Dispose(); |
| + m_profiler = nullptr; |
| + } |
| return result; |
| } |
| -bool V8ProfilerAgentImpl::isRecording() const { |
| - return m_recordingCPUProfile || !m_startedProfiles.empty(); |
| -} |
| - |
| bool V8ProfilerAgentImpl::idleStarted() { |
| - if (m_profiler) m_profiler->SetIdle(true); |
| + m_idle = true; |
| + if (m_profiler) m_profiler->SetIdle(m_idle); |
| return m_profiler; |
| } |
| bool V8ProfilerAgentImpl::idleFinished() { |
| - if (m_profiler) m_profiler->SetIdle(false); |
| + m_idle = false; |
| + if (m_profiler) m_profiler->SetIdle(m_idle); |
| return m_profiler; |
| } |