Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: src/profile-generator.cc

Issue 1547023: C++ profiler: publish the new API, make compatible with WebKit / Chromium. (Closed)
Patch Set: comments addressed Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698