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 |