OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/profiler/profile-generator.h" | 5 #include "src/profiler/profile-generator.h" |
6 | 6 |
7 #include "src/base/adapters.h" | 7 #include "src/base/adapters.h" |
8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/global-handles.h" | 10 #include "src/global-handles.h" |
11 #include "src/profiler/cpu-profiler.h" | 11 #include "src/profiler/cpu-profiler.h" |
12 #include "src/profiler/profile-generator-inl.h" | 12 #include "src/profiler/profile-generator-inl.h" |
| 13 #include "src/tracing/trace-event.h" |
| 14 #include "src/tracing/traced-value.h" |
13 #include "src/unicode.h" | 15 #include "src/unicode.h" |
14 | 16 |
15 namespace v8 { | 17 namespace v8 { |
16 namespace internal { | 18 namespace internal { |
17 | 19 |
18 | 20 |
19 JITLineInfoTable::JITLineInfoTable() {} | 21 JITLineInfoTable::JITLineInfoTable() {} |
20 | 22 |
21 | 23 |
22 JITLineInfoTable::~JITLineInfoTable() {} | 24 JITLineInfoTable::~JITLineInfoTable() {} |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 children_.Lookup(entry, CodeEntryHash(entry)); | 209 children_.Lookup(entry, CodeEntryHash(entry)); |
208 return map_entry != NULL ? | 210 return map_entry != NULL ? |
209 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 211 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
210 } | 212 } |
211 | 213 |
212 | 214 |
213 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 215 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
214 base::HashMap::Entry* map_entry = | 216 base::HashMap::Entry* map_entry = |
215 children_.LookupOrInsert(entry, CodeEntryHash(entry)); | 217 children_.LookupOrInsert(entry, CodeEntryHash(entry)); |
216 ProfileNode* node = reinterpret_cast<ProfileNode*>(map_entry->value); | 218 ProfileNode* node = reinterpret_cast<ProfileNode*>(map_entry->value); |
217 if (node == NULL) { | 219 if (!node) { |
218 // New node added. | 220 node = new ProfileNode(tree_, entry, this); |
219 node = new ProfileNode(tree_, entry); | |
220 map_entry->value = node; | 221 map_entry->value = node; |
221 children_list_.Add(node); | 222 children_list_.Add(node); |
222 } | 223 } |
223 return node; | 224 return node; |
224 } | 225 } |
225 | 226 |
226 | 227 |
227 void ProfileNode::IncrementLineTicks(int src_line) { | 228 void ProfileNode::IncrementLineTicks(int src_line) { |
228 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return; | 229 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return; |
229 // Increment a hit counter of a certain source line. | 230 // Increment a hit counter of a certain source line. |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 void AfterAllChildrenTraversed(ProfileNode* node) { | 299 void AfterAllChildrenTraversed(ProfileNode* node) { |
299 delete node; | 300 delete node; |
300 } | 301 } |
301 | 302 |
302 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 303 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
303 }; | 304 }; |
304 | 305 |
305 ProfileTree::ProfileTree(Isolate* isolate) | 306 ProfileTree::ProfileTree(Isolate* isolate) |
306 : root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"), | 307 : root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"), |
307 next_node_id_(1), | 308 next_node_id_(1), |
308 root_(new ProfileNode(this, &root_entry_)), | 309 root_(new ProfileNode(this, &root_entry_, nullptr)), |
309 isolate_(isolate), | 310 isolate_(isolate), |
310 next_function_id_(1), | 311 next_function_id_(1), |
311 function_ids_(ProfileNode::CodeEntriesMatch) {} | 312 function_ids_(ProfileNode::CodeEntriesMatch) {} |
312 | 313 |
313 ProfileTree::~ProfileTree() { | 314 ProfileTree::~ProfileTree() { |
314 DeleteNodesCallback cb; | 315 DeleteNodesCallback cb; |
315 TraverseDepthFirst(&cb); | 316 TraverseDepthFirst(&cb); |
316 } | 317 } |
317 | 318 |
318 | 319 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 Position& parent = stack[stack.length() - 2]; | 391 Position& parent = stack[stack.length() - 2]; |
391 callback->AfterChildTraversed(parent.node, current.node); | 392 callback->AfterChildTraversed(parent.node, current.node); |
392 parent.next_child(); | 393 parent.next_child(); |
393 } | 394 } |
394 // Remove child from the stack. | 395 // Remove child from the stack. |
395 stack.RemoveLast(); | 396 stack.RemoveLast(); |
396 } | 397 } |
397 } | 398 } |
398 } | 399 } |
399 | 400 |
| 401 using v8::tracing::TracedValue; |
| 402 |
400 CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title, | 403 CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title, |
401 bool record_samples) | 404 bool record_samples) |
402 : title_(title), | 405 : title_(title), |
403 record_samples_(record_samples), | 406 record_samples_(record_samples), |
404 start_time_(base::TimeTicks::HighResolutionNow()), | 407 start_time_(base::TimeTicks::HighResolutionNow()), |
405 top_down_(profiler->isolate()), | 408 top_down_(profiler->isolate()), |
406 profiler_(profiler) {} | 409 profiler_(profiler), |
| 410 streaming_next_sample_(0) { |
| 411 auto value = TracedValue::Create(); |
| 412 value->SetDouble("startTime", |
| 413 (start_time_ - base::TimeTicks()).InMicroseconds()); |
| 414 TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"), |
| 415 "CpuProfile", this, "data", std::move(value)); |
| 416 } |
407 | 417 |
408 void CpuProfile::AddPath(base::TimeTicks timestamp, | 418 void CpuProfile::AddPath(base::TimeTicks timestamp, |
409 const std::vector<CodeEntry*>& path, int src_line, | 419 const std::vector<CodeEntry*>& path, int src_line, |
410 bool update_stats) { | 420 bool update_stats) { |
411 ProfileNode* top_frame_node = | 421 ProfileNode* top_frame_node = |
412 top_down_.AddPathFromEnd(path, src_line, update_stats); | 422 top_down_.AddPathFromEnd(path, src_line, update_stats); |
413 if (record_samples_ && !timestamp.IsNull()) { | 423 if (record_samples_ && !timestamp.IsNull()) { |
414 timestamps_.Add(timestamp); | 424 timestamps_.Add(timestamp); |
415 samples_.Add(top_frame_node); | 425 samples_.Add(top_frame_node); |
416 } | 426 } |
| 427 const int kSamplesFlushCount = 100; |
| 428 const int kNodesFlushCount = 10; |
| 429 if (samples_.length() - streaming_next_sample_ >= kSamplesFlushCount || |
| 430 top_down_.pending_nodes_count() >= kNodesFlushCount) { |
| 431 StreamPendingTraceEvents(); |
| 432 } |
417 } | 433 } |
418 | 434 |
419 void CpuProfile::CalculateTotalTicksAndSamplingRate() { | 435 namespace { |
| 436 |
| 437 void BuildNodeValue(const ProfileNode* node, TracedValue* value) { |
| 438 const CodeEntry* entry = node->entry(); |
| 439 value->BeginDictionary("callFrame"); |
| 440 value->SetString("functionName", entry->name()); |
| 441 if (*entry->resource_name()) { |
| 442 value->SetString("url", entry->resource_name()); |
| 443 } |
| 444 value->SetInteger("scriptId", entry->script_id()); |
| 445 if (entry->line_number()) { |
| 446 value->SetInteger("lineNumber", entry->line_number() - 1); |
| 447 } |
| 448 if (entry->column_number()) { |
| 449 value->SetInteger("columnNumber", entry->column_number() - 1); |
| 450 } |
| 451 value->EndDictionary(); |
| 452 value->SetInteger("id", node->id()); |
| 453 if (node->parent()) { |
| 454 value->SetInteger("parent", node->parent()->id()); |
| 455 } |
| 456 const char* deopt_reason = entry->bailout_reason(); |
| 457 if (deopt_reason && deopt_reason[0] && strcmp(deopt_reason, "no reason")) { |
| 458 value->SetString("deoptReason", deopt_reason); |
| 459 } |
| 460 } |
| 461 |
| 462 } // namespace |
| 463 |
| 464 void CpuProfile::StreamPendingTraceEvents() { |
| 465 std::vector<const ProfileNode*> pending_nodes = top_down_.TakePendingNodes(); |
| 466 if (pending_nodes.empty() && !samples_.length()) return; |
| 467 auto value = TracedValue::Create(); |
| 468 |
| 469 if (!pending_nodes.empty()) { |
| 470 value->BeginArray("nodes"); |
| 471 for (auto node : pending_nodes) { |
| 472 value->BeginDictionary(); |
| 473 BuildNodeValue(node, value.get()); |
| 474 value->EndDictionary(); |
| 475 } |
| 476 value->EndArray(); |
| 477 } |
| 478 |
| 479 if (streaming_next_sample_ != samples_.length()) { |
| 480 value->BeginArray("samples"); |
| 481 for (int i = streaming_next_sample_; i < samples_.length(); ++i) { |
| 482 value->AppendInteger(samples_[i]->id()); |
| 483 } |
| 484 value->EndArray(); |
| 485 value->BeginArray("timeDeltas"); |
| 486 base::TimeTicks lastTimestamp = |
| 487 streaming_next_sample_ ? timestamps_[streaming_next_sample_ - 1] |
| 488 : start_time(); |
| 489 for (int i = streaming_next_sample_; i < timestamps_.length(); ++i) { |
| 490 value->AppendInteger( |
| 491 static_cast<int>((timestamps_[i] - lastTimestamp).InMicroseconds())); |
| 492 lastTimestamp = timestamps_[i]; |
| 493 } |
| 494 value->EndArray(); |
| 495 DCHECK(samples_.length() == timestamps_.length()); |
| 496 streaming_next_sample_ = samples_.length(); |
| 497 } |
| 498 |
| 499 TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"), |
| 500 "CpuProfileChunk", this, "data", |
| 501 std::move(value)); |
| 502 } |
| 503 |
| 504 void CpuProfile::FinishProfile() { |
420 end_time_ = base::TimeTicks::HighResolutionNow(); | 505 end_time_ = base::TimeTicks::HighResolutionNow(); |
| 506 StreamPendingTraceEvents(); |
| 507 auto value = TracedValue::Create(); |
| 508 value->SetDouble("endTime", (end_time_ - base::TimeTicks()).InMicroseconds()); |
| 509 TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"), |
| 510 "CpuProfileChunk", this, "data", |
| 511 std::move(value)); |
421 } | 512 } |
422 | 513 |
423 void CpuProfile::Print() { | 514 void CpuProfile::Print() { |
424 base::OS::Print("[Top down]:\n"); | 515 base::OS::Print("[Top down]:\n"); |
425 top_down_.Print(); | 516 top_down_.Print(); |
426 } | 517 } |
427 | 518 |
428 void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { | 519 void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { |
429 DeleteAllCoveredCode(addr, addr + size); | 520 DeleteAllCoveredCode(addr, addr + size); |
430 code_map_.insert({addr, CodeEntryInfo(entry, size)}); | 521 code_map_.insert({addr, CodeEntryInfo(entry, size)}); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 } | 588 } |
498 } | 589 } |
499 current_profiles_.Add(new CpuProfile(profiler_, title, record_samples)); | 590 current_profiles_.Add(new CpuProfile(profiler_, title, record_samples)); |
500 current_profiles_semaphore_.Signal(); | 591 current_profiles_semaphore_.Signal(); |
501 return true; | 592 return true; |
502 } | 593 } |
503 | 594 |
504 | 595 |
505 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) { | 596 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) { |
506 const int title_len = StrLength(title); | 597 const int title_len = StrLength(title); |
507 CpuProfile* profile = NULL; | 598 CpuProfile* profile = nullptr; |
508 current_profiles_semaphore_.Wait(); | 599 current_profiles_semaphore_.Wait(); |
509 for (int i = current_profiles_.length() - 1; i >= 0; --i) { | 600 for (int i = current_profiles_.length() - 1; i >= 0; --i) { |
510 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { | 601 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { |
511 profile = current_profiles_.Remove(i); | 602 profile = current_profiles_.Remove(i); |
512 break; | 603 break; |
513 } | 604 } |
514 } | 605 } |
515 current_profiles_semaphore_.Signal(); | 606 current_profiles_semaphore_.Signal(); |
516 | 607 |
517 if (profile == NULL) return NULL; | 608 if (!profile) return nullptr; |
518 profile->CalculateTotalTicksAndSamplingRate(); | 609 profile->FinishProfile(); |
519 finished_profiles_.Add(profile); | 610 finished_profiles_.Add(profile); |
520 return profile; | 611 return profile; |
521 } | 612 } |
522 | 613 |
523 | 614 |
524 bool CpuProfilesCollection::IsLastProfile(const char* title) { | 615 bool CpuProfilesCollection::IsLastProfile(const char* title) { |
525 // Called from VM thread, and only it can mutate the list, | 616 // Called from VM thread, and only it can mutate the list, |
526 // so no locking is needed here. | 617 // so no locking is needed here. |
527 if (current_profiles_.length() != 1) return false; | 618 if (current_profiles_.length() != 1) return false; |
528 return StrLength(title) == 0 | 619 return StrLength(title) == 0 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 case EXTERNAL: | 767 case EXTERNAL: |
677 return CodeEntry::program_entry(); | 768 return CodeEntry::program_entry(); |
678 case IDLE: | 769 case IDLE: |
679 return CodeEntry::idle_entry(); | 770 return CodeEntry::idle_entry(); |
680 default: return NULL; | 771 default: return NULL; |
681 } | 772 } |
682 } | 773 } |
683 | 774 |
684 } // namespace internal | 775 } // namespace internal |
685 } // namespace v8 | 776 } // namespace v8 |
OLD | NEW |