| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #ifdef ENABLE_CPP_PROFILES_PROCESSOR | 28 #ifdef ENABLE_CPP_PROFILES_PROCESSOR |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 | 31 |
| 32 #include "profile-generator-inl.h" | 32 #include "profile-generator-inl.h" |
| 33 | 33 |
| 34 #include "../include/v8-profiler.h" |
| 35 |
| 34 namespace v8 { | 36 namespace v8 { |
| 35 namespace internal { | 37 namespace internal { |
| 36 | 38 |
| 37 | 39 |
| 38 const char* CodeEntry::kEmptyNamePrefix = ""; | 40 const char* CodeEntry::kEmptyNamePrefix = ""; |
| 39 const int CodeEntry::kNoLineNumberInfo = -1; | 41 unsigned long CodeEntry::next_call_uid_ = 1; |
| 40 | 42 |
| 41 | 43 |
| 42 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 44 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
| 43 HashMap::Entry* map_entry = | 45 HashMap::Entry* map_entry = |
| 44 children_.Lookup(entry, CodeEntryHash(entry), false); | 46 children_.Lookup(entry, CodeEntryHash(entry), false); |
| 45 return map_entry != NULL ? | 47 return map_entry != NULL ? |
| 46 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 48 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
| 47 } | 49 } |
| 48 | 50 |
| 49 | 51 |
| 50 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 52 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
| 51 HashMap::Entry* map_entry = | 53 HashMap::Entry* map_entry = |
| 52 children_.Lookup(entry, CodeEntryHash(entry), true); | 54 children_.Lookup(entry, CodeEntryHash(entry), true); |
| 53 if (map_entry->value == NULL) { | 55 if (map_entry->value == NULL) { |
| 54 // New node added. | 56 // New node added. |
| 55 ProfileNode* new_node = new ProfileNode(entry); | 57 ProfileNode* new_node = new ProfileNode(entry); |
| 56 map_entry->value = new_node; | 58 map_entry->value = new_node; |
| 57 children_list_.Add(new_node); | 59 children_list_.Add(new_node); |
| 58 } | 60 } |
| 59 return reinterpret_cast<ProfileNode*>(map_entry->value); | 61 return reinterpret_cast<ProfileNode*>(map_entry->value); |
| 60 } | 62 } |
| 61 | 63 |
| 62 | 64 |
| 63 void ProfileNode::Print(int indent) { | 65 void ProfileNode::Print(int indent) { |
| 64 OS::Print("%5u %5u %*c %s%s\n", | 66 OS::Print("%5u %5u %*c %s%s", |
| 65 total_ticks_, self_ticks_, | 67 total_ticks_, self_ticks_, |
| 66 indent, ' ', | 68 indent, ' ', |
| 67 entry_ != NULL ? entry_->name_prefix() : "", | 69 entry_->name_prefix(), |
| 68 entry_ != NULL ? entry_->name() : ""); | 70 entry_->name()); |
| 71 if (entry_->resource_name()[0] != '\0') |
| 72 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
| 73 OS::Print("\n"); |
| 69 for (HashMap::Entry* p = children_.Start(); | 74 for (HashMap::Entry* p = children_.Start(); |
| 70 p != NULL; | 75 p != NULL; |
| 71 p = children_.Next(p)) { | 76 p = children_.Next(p)) { |
| 72 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); | 77 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); |
| 73 } | 78 } |
| 74 } | 79 } |
| 75 | 80 |
| 76 | 81 |
| 77 namespace { | 82 namespace { |
| 78 | 83 |
| 79 class DeleteNodesCallback { | 84 class DeleteNodesCallback { |
| 80 public: | 85 public: |
| 81 void AfterAllChildrenTraversed(ProfileNode* node) { | 86 void AfterAllChildrenTraversed(ProfileNode* node) { |
| 82 delete node; | 87 delete node; |
| 83 } | 88 } |
| 84 | 89 |
| 85 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 90 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
| 86 }; | 91 }; |
| 87 | 92 |
| 88 } // namespace | 93 } // namespace |
| 89 | 94 |
| 90 | 95 |
| 96 ProfileTree::ProfileTree() |
| 97 : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0), |
| 98 root_(new ProfileNode(&root_entry_)) { |
| 99 } |
| 100 |
| 101 |
| 91 ProfileTree::~ProfileTree() { | 102 ProfileTree::~ProfileTree() { |
| 92 DeleteNodesCallback cb; | 103 DeleteNodesCallback cb; |
| 93 TraverseBreadthFirstPostOrder(&cb); | 104 TraverseBreadthFirstPostOrder(&cb); |
| 94 } | 105 } |
| 95 | 106 |
| 96 | 107 |
| 97 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { | 108 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { |
| 98 ProfileNode* node = root_; | 109 ProfileNode* node = root_; |
| 99 for (CodeEntry** entry = path.start() + path.length() - 1; | 110 for (CodeEntry** entry = path.start() + path.length() - 1; |
| 100 entry != path.start() - 1; | 111 entry != path.start() - 1; |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; | 364 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; |
| 354 } | 365 } |
| 355 | 366 |
| 356 | 367 |
| 357 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 368 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
| 358 String* name, | 369 String* name, |
| 359 String* resource_name, | 370 String* resource_name, |
| 360 int line_number) { | 371 int line_number) { |
| 361 CodeEntry* entry = new CodeEntry(tag, | 372 CodeEntry* entry = new CodeEntry(tag, |
| 362 CodeEntry::kEmptyNamePrefix, | 373 CodeEntry::kEmptyNamePrefix, |
| 363 GetName(name), | 374 GetFunctionName(name), |
| 364 GetName(resource_name), | 375 GetName(resource_name), |
| 365 line_number); | 376 line_number); |
| 366 code_entries_.Add(entry); | 377 code_entries_.Add(entry); |
| 367 return entry; | 378 return entry; |
| 368 } | 379 } |
| 369 | 380 |
| 370 | 381 |
| 371 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 382 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
| 372 const char* name) { | 383 const char* name) { |
| 373 CodeEntry* entry = new CodeEntry(tag, | 384 CodeEntry* entry = new CodeEntry(tag, |
| 374 CodeEntry::kEmptyNamePrefix, | 385 CodeEntry::kEmptyNamePrefix, |
| 375 name, | 386 name, |
| 376 "", | 387 "", |
| 377 CodeEntry::kNoLineNumberInfo); | 388 v8::CpuProfileNode::kNoLineNumberInfo); |
| 378 code_entries_.Add(entry); | 389 code_entries_.Add(entry); |
| 379 return entry; | 390 return entry; |
| 380 } | 391 } |
| 381 | 392 |
| 382 | 393 |
| 383 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 394 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
| 384 const char* name_prefix, | 395 const char* name_prefix, |
| 385 String* name) { | 396 String* name) { |
| 386 CodeEntry* entry = new CodeEntry(tag, | 397 CodeEntry* entry = new CodeEntry(tag, |
| 387 name_prefix, | 398 name_prefix, |
| 388 GetName(name), | 399 GetName(name), |
| 389 "", | 400 "", |
| 390 CodeEntry::kNoLineNumberInfo); | 401 v8::CpuProfileNode::kNoLineNumberInfo); |
| 391 code_entries_.Add(entry); | 402 code_entries_.Add(entry); |
| 392 return entry; | 403 return entry; |
| 393 } | 404 } |
| 394 | 405 |
| 395 | 406 |
| 396 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 407 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
| 397 int args_count) { | 408 int args_count) { |
| 398 CodeEntry* entry = new CodeEntry(tag, | 409 CodeEntry* entry = new CodeEntry(tag, |
| 399 "args_count: ", | 410 "args_count: ", |
| 400 GetName(args_count), | 411 GetName(args_count), |
| 401 "", | 412 "", |
| 402 CodeEntry::kNoLineNumberInfo); | 413 v8::CpuProfileNode::kNoLineNumberInfo); |
| 403 code_entries_.Add(entry); | 414 code_entries_.Add(entry); |
| 404 return entry; | 415 return entry; |
| 405 } | 416 } |
| 406 | 417 |
| 407 | 418 |
| 419 const char* CpuProfilesCollection::GetFunctionName(String* name) { |
| 420 const char* maybe_empty_name = GetName(name); |
| 421 return strlen(maybe_empty_name) > 0 ? |
| 422 maybe_empty_name : "(anonymous function)"; |
| 423 } |
| 424 |
| 425 |
| 408 const char* CpuProfilesCollection::GetName(String* name) { | 426 const char* CpuProfilesCollection::GetName(String* name) { |
| 409 if (name->IsString()) { | 427 if (name->IsString()) { |
| 410 char* c_name = | 428 char* c_name = |
| 411 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); | 429 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); |
| 412 HashMap::Entry* cache_entry = | 430 HashMap::Entry* cache_entry = |
| 413 function_and_resource_names_.Lookup(c_name, | 431 function_and_resource_names_.Lookup(c_name, |
| 414 name->Hash(), | 432 name->Hash(), |
| 415 true); | 433 true); |
| 416 if (cache_entry->value == NULL) { | 434 if (cache_entry->value == NULL) { |
| 417 // New entry added. | 435 // New entry added. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 448 // method, we don't bother minimizing the duration of lock holding, | 466 // method, we don't bother minimizing the duration of lock holding, |
| 449 // e.g. copying contents of the list to a local vector. | 467 // e.g. copying contents of the list to a local vector. |
| 450 current_profiles_semaphore_->Wait(); | 468 current_profiles_semaphore_->Wait(); |
| 451 for (int i = 0; i < current_profiles_.length(); ++i) { | 469 for (int i = 0; i < current_profiles_.length(); ++i) { |
| 452 current_profiles_[i]->AddPath(path); | 470 current_profiles_[i]->AddPath(path); |
| 453 } | 471 } |
| 454 current_profiles_semaphore_->Signal(); | 472 current_profiles_semaphore_->Signal(); |
| 455 } | 473 } |
| 456 | 474 |
| 457 | 475 |
| 476 |
| 458 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 477 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
| 459 : profiles_(profiles) { | 478 : profiles_(profiles), |
| 479 program_entry_( |
| 480 profiles->NewCodeEntry(Logger::FUNCTION_TAG, "(program)")) { |
| 460 } | 481 } |
| 461 | 482 |
| 462 | 483 |
| 463 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 484 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| 464 // Allocate space for stack frames + pc + function. | 485 // Allocate space for stack frames + pc + function + (program). |
| 465 ScopedVector<CodeEntry*> entries(sample.frames_count + 2); | 486 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); |
| 466 CodeEntry** entry = entries.start(); | 487 CodeEntry** entry = entries.start(); |
| 467 *entry++ = code_map_.FindEntry(sample.pc); | 488 *entry++ = code_map_.FindEntry(sample.pc); |
| 468 | 489 |
| 469 if (sample.function != NULL) { | 490 if (sample.function != NULL) { |
| 470 *entry = code_map_.FindEntry(sample.function); | 491 *entry = code_map_.FindEntry(sample.function); |
| 471 if (*entry != NULL && !(*entry)->is_js_function()) { | 492 if (*entry != NULL && !(*entry)->is_js_function()) { |
| 472 *entry = NULL; | 493 *entry = NULL; |
| 473 } else { | 494 } else { |
| 474 CodeEntry* pc_entry = *entries.start(); | 495 CodeEntry* pc_entry = *entries.start(); |
| 475 if (pc_entry == NULL || pc_entry->is_js_function()) | 496 if (pc_entry == NULL || pc_entry->is_js_function()) |
| 476 *entry = NULL; | 497 *entry = NULL; |
| 477 } | 498 } |
| 478 entry++; | 499 entry++; |
| 479 } else { | 500 } else { |
| 480 *entry++ = NULL; | 501 *entry++ = NULL; |
| 481 } | 502 } |
| 482 | 503 |
| 483 for (const Address *stack_pos = sample.stack, | 504 for (const Address *stack_pos = sample.stack, |
| 484 *stack_end = stack_pos + sample.frames_count; | 505 *stack_end = stack_pos + sample.frames_count; |
| 485 stack_pos != stack_end; | 506 stack_pos != stack_end; |
| 486 ++stack_pos) { | 507 ++stack_pos) { |
| 487 *entry++ = code_map_.FindEntry(*stack_pos); | 508 *entry++ = code_map_.FindEntry(*stack_pos); |
| 488 } | 509 } |
| 489 | 510 |
| 511 // WebKit CPU profiles visualization requires "(program)" to be the |
| 512 // topmost entry. |
| 513 *entry++ = FLAG_prof_browser_mode ? program_entry_ : NULL; |
| 514 |
| 490 profiles_->AddPathToCurrentProfiles(entries); | 515 profiles_->AddPathToCurrentProfiles(entries); |
| 491 } | 516 } |
| 492 | 517 |
| 493 } } // namespace v8::internal | 518 } } // namespace v8::internal |
| 494 | 519 |
| 495 #endif // ENABLE_CPP_PROFILES_PROCESSOR | 520 #endif // ENABLE_CPP_PROFILES_PROCESSOR |
| OLD | NEW |