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

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

Issue 2396733002: [profiler] Tracing-based CPU profiler. (Closed)
Patch Set: Addressing comments + moving traced-value back to src/tracing Created 4 years, 2 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/profiler/profile-generator.h ('k') | src/profiler/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 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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/profiler/profile-generator.h ('k') | src/profiler/profile-generator-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698