| 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 | 
|---|