OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/inspector/v8-profiler-agent-impl.h" | 5 #include "src/inspector/v8-profiler-agent-impl.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "src/base/atomicops.h" | 9 #include "src/base/atomicops.h" |
10 #include "src/inspector/protocol/Protocol.h" | 10 #include "src/inspector/protocol/Protocol.h" |
11 #include "src/inspector/string-util.h" | 11 #include "src/inspector/string-util.h" |
12 #include "src/inspector/v8-debugger.h" | 12 #include "src/inspector/v8-debugger.h" |
13 #include "src/inspector/v8-inspector-impl.h" | 13 #include "src/inspector/v8-inspector-impl.h" |
14 #include "src/inspector/v8-inspector-session-impl.h" | 14 #include "src/inspector/v8-inspector-session-impl.h" |
15 #include "src/inspector/v8-stack-trace-impl.h" | 15 #include "src/inspector/v8-stack-trace-impl.h" |
16 | 16 |
17 #include "include/v8-profiler.h" | 17 #include "include/v8-profiler.h" |
18 | 18 |
19 namespace v8_inspector { | 19 namespace v8_inspector { |
20 | 20 |
21 namespace ProfilerAgentState { | 21 namespace ProfilerAgentState { |
22 static const char samplingInterval[] = "samplingInterval"; | 22 static const char samplingInterval[] = "samplingInterval"; |
23 static const char userInitiatedProfiling[] = "userInitiatedProfiling"; | 23 static const char userInitiatedProfiling[] = "userInitiatedProfiling"; |
24 static const char profilerEnabled[] = "profilerEnabled"; | 24 static const char profilerEnabled[] = "profilerEnabled"; |
| 25 static const char preciseCoverageStarted[] = "preciseCoverageStarted"; |
25 } | 26 } |
26 | 27 |
27 namespace { | 28 namespace { |
28 | 29 |
29 std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>> | 30 std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>> |
30 buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node) { | 31 buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node) { |
31 unsigned lineCount = node->GetHitLineCount(); | 32 unsigned lineCount = node->GetHitLineCount(); |
32 if (!lineCount) return nullptr; | 33 if (!lineCount) return nullptr; |
33 auto array = protocol::Array<protocol::Profiler::PositionTickInfo>::create(); | 34 auto array = protocol::Array<protocol::Profiler::PositionTickInfo>::create(); |
34 std::vector<v8::CpuProfileNode::LineTick> entries(lineCount); | 35 std::vector<v8::CpuProfileNode::LineTick> entries(lineCount); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 : m_id(id), m_title(title) {} | 146 : m_id(id), m_title(title) {} |
146 String16 m_id; | 147 String16 m_id; |
147 String16 m_title; | 148 String16 m_title; |
148 }; | 149 }; |
149 | 150 |
150 V8ProfilerAgentImpl::V8ProfilerAgentImpl( | 151 V8ProfilerAgentImpl::V8ProfilerAgentImpl( |
151 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, | 152 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, |
152 protocol::DictionaryValue* state) | 153 protocol::DictionaryValue* state) |
153 : m_session(session), | 154 : m_session(session), |
154 m_isolate(m_session->inspector()->isolate()), | 155 m_isolate(m_session->inspector()->isolate()), |
155 m_profiler(nullptr), | |
156 m_state(state), | 156 m_state(state), |
157 m_frontend(frontendChannel), | 157 m_frontend(frontendChannel) {} |
158 m_enabled(false), | |
159 m_recordingCPUProfile(false) {} | |
160 | 158 |
161 V8ProfilerAgentImpl::~V8ProfilerAgentImpl() { | 159 V8ProfilerAgentImpl::~V8ProfilerAgentImpl() { |
162 if (m_profiler) m_profiler->Dispose(); | 160 if (m_profiler) m_profiler->Dispose(); |
163 } | 161 } |
164 | 162 |
165 void V8ProfilerAgentImpl::consoleProfile(const String16& title) { | 163 void V8ProfilerAgentImpl::consoleProfile(const String16& title) { |
166 if (!m_enabled) return; | 164 if (!m_enabled) return; |
167 String16 id = nextProfileId(); | 165 String16 id = nextProfileId(); |
168 m_startedProfiles.push_back(ProfileDescriptor(id, title)); | 166 m_startedProfiles.push_back(ProfileDescriptor(id, title)); |
169 startProfiling(id); | 167 startProfiling(id); |
(...skipping 27 matching lines...) Expand all Loading... |
197 if (!profile) return; | 195 if (!profile) return; |
198 std::unique_ptr<protocol::Debugger::Location> location = | 196 std::unique_ptr<protocol::Debugger::Location> location = |
199 currentDebugLocation(m_session->inspector()); | 197 currentDebugLocation(m_session->inspector()); |
200 m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile), | 198 m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile), |
201 resolvedTitle); | 199 resolvedTitle); |
202 } | 200 } |
203 | 201 |
204 Response V8ProfilerAgentImpl::enable() { | 202 Response V8ProfilerAgentImpl::enable() { |
205 if (m_enabled) return Response::OK(); | 203 if (m_enabled) return Response::OK(); |
206 m_enabled = true; | 204 m_enabled = true; |
207 DCHECK(!m_profiler); | |
208 m_profiler = v8::CpuProfiler::New(m_isolate); | |
209 m_state->setBoolean(ProfilerAgentState::profilerEnabled, true); | 205 m_state->setBoolean(ProfilerAgentState::profilerEnabled, true); |
210 return Response::OK(); | 206 return Response::OK(); |
211 } | 207 } |
212 | 208 |
213 Response V8ProfilerAgentImpl::disable() { | 209 Response V8ProfilerAgentImpl::disable() { |
214 if (!m_enabled) return Response::OK(); | 210 if (!m_enabled) return Response::OK(); |
215 for (size_t i = m_startedProfiles.size(); i > 0; --i) | 211 for (size_t i = m_startedProfiles.size(); i > 0; --i) |
216 stopProfiling(m_startedProfiles[i - 1].m_id, false); | 212 stopProfiling(m_startedProfiles[i - 1].m_id, false); |
217 m_startedProfiles.clear(); | 213 m_startedProfiles.clear(); |
218 stop(nullptr); | 214 stop(nullptr); |
219 m_profiler->Dispose(); | 215 stopPreciseCoverage(); |
220 m_profiler = nullptr; | 216 DCHECK(!m_profiler); |
221 m_enabled = false; | 217 m_enabled = false; |
222 m_state->setBoolean(ProfilerAgentState::profilerEnabled, false); | 218 m_state->setBoolean(ProfilerAgentState::profilerEnabled, false); |
223 return Response::OK(); | 219 return Response::OK(); |
224 } | 220 } |
225 | 221 |
226 Response V8ProfilerAgentImpl::setSamplingInterval(int interval) { | 222 Response V8ProfilerAgentImpl::setSamplingInterval(int interval) { |
227 if (m_recordingCPUProfile) | 223 if (m_profiler) { |
228 return Response::Error("Cannot change sampling interval when profiling."); | 224 return Response::Error("Cannot change sampling interval when profiling."); |
| 225 } |
229 m_state->setInteger(ProfilerAgentState::samplingInterval, interval); | 226 m_state->setInteger(ProfilerAgentState::samplingInterval, interval); |
230 m_profiler->SetSamplingInterval(interval); | |
231 return Response::OK(); | 227 return Response::OK(); |
232 } | 228 } |
233 | 229 |
234 void V8ProfilerAgentImpl::restore() { | 230 void V8ProfilerAgentImpl::restore() { |
235 DCHECK(!m_enabled); | 231 DCHECK(!m_enabled); |
236 if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false)) | 232 if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false)) |
237 return; | 233 return; |
238 m_enabled = true; | 234 m_enabled = true; |
239 DCHECK(!m_profiler); | 235 DCHECK(!m_profiler); |
240 m_profiler = v8::CpuProfiler::New(m_isolate); | |
241 int interval = 0; | |
242 m_state->getInteger(ProfilerAgentState::samplingInterval, &interval); | |
243 if (interval) m_profiler->SetSamplingInterval(interval); | |
244 if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling, | 236 if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling, |
245 false)) { | 237 false)) { |
246 start(); | 238 start(); |
247 } | 239 } |
| 240 if (m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted, |
| 241 false)) { |
| 242 startPreciseCoverage(); |
| 243 } |
248 } | 244 } |
249 | 245 |
250 Response V8ProfilerAgentImpl::start() { | 246 Response V8ProfilerAgentImpl::start() { |
251 if (m_recordingCPUProfile) return Response::OK(); | 247 if (m_recordingCPUProfile) return Response::OK(); |
252 if (!m_enabled) return Response::Error("Profiler is not enabled"); | 248 if (!m_enabled) return Response::Error("Profiler is not enabled"); |
253 m_recordingCPUProfile = true; | 249 m_recordingCPUProfile = true; |
254 m_frontendInitiatedProfileId = nextProfileId(); | 250 m_frontendInitiatedProfileId = nextProfileId(); |
255 startProfiling(m_frontendInitiatedProfileId); | 251 startProfiling(m_frontendInitiatedProfileId); |
256 m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true); | 252 m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true); |
257 return Response::OK(); | 253 return Response::OK(); |
258 } | 254 } |
259 | 255 |
260 Response V8ProfilerAgentImpl::stop( | 256 Response V8ProfilerAgentImpl::stop( |
261 std::unique_ptr<protocol::Profiler::Profile>* profile) { | 257 std::unique_ptr<protocol::Profiler::Profile>* profile) { |
262 if (!m_recordingCPUProfile) | 258 if (!m_recordingCPUProfile) { |
263 return Response::Error("No recording profiles found"); | 259 return Response::Error("No recording profiles found"); |
| 260 } |
264 m_recordingCPUProfile = false; | 261 m_recordingCPUProfile = false; |
265 std::unique_ptr<protocol::Profiler::Profile> cpuProfile = | 262 std::unique_ptr<protocol::Profiler::Profile> cpuProfile = |
266 stopProfiling(m_frontendInitiatedProfileId, !!profile); | 263 stopProfiling(m_frontendInitiatedProfileId, !!profile); |
267 if (profile) { | 264 if (profile) { |
268 *profile = std::move(cpuProfile); | 265 *profile = std::move(cpuProfile); |
269 if (!profile->get()) return Response::Error("Profile is not found"); | 266 if (!profile->get()) return Response::Error("Profile is not found"); |
270 } | 267 } |
271 m_frontendInitiatedProfileId = String16(); | 268 m_frontendInitiatedProfileId = String16(); |
272 m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false); | 269 m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false); |
273 return Response::OK(); | 270 return Response::OK(); |
274 } | 271 } |
275 | 272 |
| 273 Response V8ProfilerAgentImpl::startPreciseCoverage() { |
| 274 if (!m_enabled) return Response::Error("Profiler is not enabled"); |
| 275 m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, true); |
| 276 v8::debug::Coverage::TogglePrecise(m_isolate, true); |
| 277 return Response::OK(); |
| 278 } |
| 279 |
| 280 Response V8ProfilerAgentImpl::stopPreciseCoverage() { |
| 281 if (!m_enabled) return Response::Error("Profiler is not enabled"); |
| 282 m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false); |
| 283 v8::debug::Coverage::TogglePrecise(m_isolate, false); |
| 284 return Response::OK(); |
| 285 } |
| 286 |
| 287 namespace { |
| 288 Response takeCoverage( |
| 289 v8::Isolate* isolate, bool reset_count, |
| 290 std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| 291 out_result) { |
| 292 std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> result = |
| 293 protocol::Array<protocol::Profiler::ScriptCoverage>::create(); |
| 294 v8::HandleScope handle_scope(isolate); |
| 295 v8::debug::Coverage coverage = |
| 296 v8::debug::Coverage::Collect(isolate, reset_count); |
| 297 for (size_t i = 0; i < coverage.ScriptCount(); i++) { |
| 298 v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i); |
| 299 v8::Local<v8::debug::Script> script = script_data.GetScript(); |
| 300 std::unique_ptr<protocol::Array<protocol::Profiler::FunctionCoverage>> |
| 301 functions = |
| 302 protocol::Array<protocol::Profiler::FunctionCoverage>::create(); |
| 303 for (size_t j = 0; j < script_data.FunctionCount(); j++) { |
| 304 v8::debug::Coverage::FunctionData function_data = |
| 305 script_data.GetFunctionData(j); |
| 306 std::unique_ptr<protocol::Array<protocol::Profiler::CoverageRange>> |
| 307 ranges = protocol::Array<protocol::Profiler::CoverageRange>::create(); |
| 308 // At this point we only have per-function coverage data, so there is |
| 309 // only one range per function. |
| 310 ranges->addItem( |
| 311 protocol::Profiler::CoverageRange::create() |
| 312 .setStartLineNumber(function_data.Start().GetLineNumber()) |
| 313 .setStartColumnNumber(function_data.Start().GetColumnNumber()) |
| 314 .setEndLineNumber(function_data.End().GetLineNumber()) |
| 315 .setEndColumnNumber(function_data.End().GetColumnNumber()) |
| 316 .setCount(function_data.Count()) |
| 317 .build()); |
| 318 functions->addItem( |
| 319 protocol::Profiler::FunctionCoverage::create() |
| 320 .setFunctionName(toProtocolString( |
| 321 function_data.Name().FromMaybe(v8::Local<v8::String>()))) |
| 322 .setRanges(std::move(ranges)) |
| 323 .build()); |
| 324 } |
| 325 String16 url; |
| 326 v8::Local<v8::String> name; |
| 327 if (script->Name().ToLocal(&name) || script->SourceURL().ToLocal(&name)) { |
| 328 url = toProtocolString(name); |
| 329 } |
| 330 result->addItem(protocol::Profiler::ScriptCoverage::create() |
| 331 .setScriptId(String16::fromInteger(script->Id())) |
| 332 .setUrl(url) |
| 333 .setFunctions(std::move(functions)) |
| 334 .build()); |
| 335 } |
| 336 *out_result = std::move(result); |
| 337 return Response::OK(); |
| 338 } |
| 339 } // anonymous namespace |
| 340 |
| 341 Response V8ProfilerAgentImpl::takePreciseCoverage( |
| 342 std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| 343 out_result) { |
| 344 if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted, |
| 345 false)) { |
| 346 return Response::Error("Precise coverage has not been started."); |
| 347 } |
| 348 return takeCoverage(m_isolate, true, out_result); |
| 349 } |
| 350 |
| 351 Response V8ProfilerAgentImpl::getBestEffortCoverage( |
| 352 std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>* |
| 353 out_result) { |
| 354 return takeCoverage(m_isolate, false, out_result); |
| 355 } |
| 356 |
276 String16 V8ProfilerAgentImpl::nextProfileId() { | 357 String16 V8ProfilerAgentImpl::nextProfileId() { |
277 return String16::fromInteger( | 358 return String16::fromInteger( |
278 v8::base::NoBarrier_AtomicIncrement(&s_lastProfileId, 1)); | 359 v8::base::NoBarrier_AtomicIncrement(&s_lastProfileId, 1)); |
279 } | 360 } |
280 | 361 |
281 void V8ProfilerAgentImpl::startProfiling(const String16& title) { | 362 void V8ProfilerAgentImpl::startProfiling(const String16& title) { |
282 v8::HandleScope handleScope(m_isolate); | 363 v8::HandleScope handleScope(m_isolate); |
| 364 if (!m_startedProfilesCount) { |
| 365 DCHECK(!m_profiler); |
| 366 m_profiler = v8::CpuProfiler::New(m_isolate); |
| 367 m_profiler->SetIdle(m_idle); |
| 368 int interval = |
| 369 m_state->integerProperty(ProfilerAgentState::samplingInterval, 0); |
| 370 if (interval) m_profiler->SetSamplingInterval(interval); |
| 371 } |
| 372 ++m_startedProfilesCount; |
283 m_profiler->StartProfiling(toV8String(m_isolate, title), true); | 373 m_profiler->StartProfiling(toV8String(m_isolate, title), true); |
284 } | 374 } |
285 | 375 |
286 std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling( | 376 std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling( |
287 const String16& title, bool serialize) { | 377 const String16& title, bool serialize) { |
288 v8::HandleScope handleScope(m_isolate); | 378 v8::HandleScope handleScope(m_isolate); |
289 v8::CpuProfile* profile = | 379 v8::CpuProfile* profile = |
290 m_profiler->StopProfiling(toV8String(m_isolate, title)); | 380 m_profiler->StopProfiling(toV8String(m_isolate, title)); |
291 if (!profile) return nullptr; | |
292 std::unique_ptr<protocol::Profiler::Profile> result; | 381 std::unique_ptr<protocol::Profiler::Profile> result; |
293 if (serialize) result = createCPUProfile(m_isolate, profile); | 382 if (profile) { |
294 profile->Delete(); | 383 if (serialize) result = createCPUProfile(m_isolate, profile); |
| 384 profile->Delete(); |
| 385 } |
| 386 --m_startedProfilesCount; |
| 387 if (!m_startedProfilesCount) { |
| 388 m_profiler->Dispose(); |
| 389 m_profiler = nullptr; |
| 390 } |
295 return result; | 391 return result; |
296 } | 392 } |
297 | 393 |
298 bool V8ProfilerAgentImpl::isRecording() const { | |
299 return m_recordingCPUProfile || !m_startedProfiles.empty(); | |
300 } | |
301 | |
302 bool V8ProfilerAgentImpl::idleStarted() { | 394 bool V8ProfilerAgentImpl::idleStarted() { |
303 if (m_profiler) m_profiler->SetIdle(true); | 395 m_idle = true; |
| 396 if (m_profiler) m_profiler->SetIdle(m_idle); |
304 return m_profiler; | 397 return m_profiler; |
305 } | 398 } |
306 | 399 |
307 bool V8ProfilerAgentImpl::idleFinished() { | 400 bool V8ProfilerAgentImpl::idleFinished() { |
308 if (m_profiler) m_profiler->SetIdle(false); | 401 m_idle = false; |
| 402 if (m_profiler) m_profiler->SetIdle(m_idle); |
309 return m_profiler; | 403 return m_profiler; |
310 } | 404 } |
311 | 405 |
312 } // namespace v8_inspector | 406 } // namespace v8_inspector |
OLD | NEW |