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); |
+ 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; |
} |