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

Side by Side Diff: runtime/vm/profiler.cc

Issue 151143003: Improve CodeRegionTable build time by 30x (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 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 | Annotate | Revision Log
« runtime/vm/profiler.h ('K') | « runtime/vm/profiler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/utils.h" 5 #include "platform/utils.h"
6 6
7 #include "vm/allocation.h" 7 #include "vm/allocation.h"
8 #include "vm/atomic.h" 8 #include "vm/atomic.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 return; 141 return;
142 } 142 }
143 if (!FLAG_profile) { 143 if (!FLAG_profile) {
144 return; 144 return;
145 } 145 }
146 ASSERT(initialized_); 146 ASSERT(initialized_);
147 ThreadInterrupter::Unregister(); 147 ThreadInterrupter::Unregister();
148 } 148 }
149 149
150 150
151 void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state,
152 void* data) {
153 Isolate* isolate = reinterpret_cast<Isolate*>(data);
154 if (isolate == NULL) {
155 return;
156 }
157 IsolateProfilerData* profiler_data = isolate->profiler_data();
158 if (profiler_data == NULL) {
159 return;
160 }
161 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
162 if (sample_buffer == NULL) {
163 return;
164 }
165 Sample* sample = sample_buffer->ReserveSample();
166 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
167 state.tid);
168 }
169
170
171 void Profiler::RecordSampleInterruptCallback(
172 const InterruptedThreadState& state,
173 void* data) {
174 Isolate* isolate = reinterpret_cast<Isolate*>(data);
175 if (isolate == NULL) {
176 return;
177 }
178 IsolateProfilerData* profiler_data = isolate->profiler_data();
179 if (profiler_data == NULL) {
180 return;
181 }
182 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
183 if (sample_buffer == NULL) {
184 return;
185 }
186 Sample* sample = sample_buffer->ReserveSample();
187 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
188 state.tid);
189 uintptr_t stack_lower = 0;
190 uintptr_t stack_upper = 0;
191 isolate->GetStackBounds(&stack_lower, &stack_upper);
192 if ((stack_lower == 0) || (stack_upper == 0)) {
193 stack_lower = 0;
194 stack_upper = 0;
195 }
196 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
197 state.pc, state.fp, state.sp);
198 stackWalker.walk();
199 }
200
201
202 struct AddressEntry { 151 struct AddressEntry {
203 uintptr_t pc; 152 uword pc;
204 uintptr_t ticks; 153 intptr_t ticks;
205 }; 154 };
206 155
156 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
207 157
208 // A region of code. Each region is a kind of code (Dart, Collected, or Native). 158 // A region of code. Each region is a kind of code (Dart, Collected, or Native).
209 class CodeRegion : public ZoneAllocated { 159 class CodeRegion : public ZoneAllocated {
210 public: 160 public:
211 enum Kind { 161 enum Kind {
212 kDartCode, 162 kDartCode,
213 kCollectedCode, 163 kCollectedCode,
214 kNativeCode 164 kNativeCode
215 }; 165 };
216 166
217 CodeRegion(Kind kind, uintptr_t start, uintptr_t end) : 167 CodeRegion(Kind kind, uword start, uword end) :
218 kind_(kind), 168 kind_(kind),
219 start_(start), 169 start_(start),
220 end_(end), 170 end_(end),
221 inclusive_ticks_(0), 171 inclusive_ticks_(0),
222 exclusive_ticks_(0), 172 exclusive_ticks_(0),
223 name_(NULL), 173 name_(NULL),
224 address_table_(new ZoneGrowableArray<AddressEntry>()) { 174 address_table_(new ZoneGrowableArray<AddressEntry>()) {
175 ASSERT(start_ < end_);
225 } 176 }
226 177
227 ~CodeRegion() { 178 ~CodeRegion() {
228 } 179 }
229 180
230 uintptr_t start() const { return start_; } 181 uword start() const { return start_; }
231 void set_start(uintptr_t start) { 182 void set_start(uword start) {
232 start_ = start; 183 start_ = start;
233 } 184 }
234 185
235 uintptr_t end() const { return end_; } 186 uword end() const { return end_; }
236 void set_end(uintptr_t end) { 187 void set_end(uword end) {
237 end_ = end; 188 end_ = end;
238 } 189 }
239 190
240 void AdjustExtent(uintptr_t start, uintptr_t end) { 191 void AdjustExtent(uword start, uword end) {
241 if (start < start_) { 192 if (start < start_) {
242 start_ = start; 193 start_ = start;
243 } 194 }
244 if (end > end_) { 195 if (end > end_) {
245 end_ = end; 196 end_ = end;
246 } 197 }
198 ASSERT(start_ < end_);
247 } 199 }
248 200
249 bool contains(uintptr_t pc) const { 201 bool contains(uword pc) const {
250 return (pc >= start_) && (pc < end_); 202 return (pc >= start_) && (pc < end_);
251 } 203 }
252 204
205 bool overlaps(const CodeRegion* other) const {
206 ASSERT(other != NULL);
207 return other->contains(start_) ||
208 other->contains(end_ - 1) ||
209 contains(other->start()) ||
210 contains(other->end() - 1);
211 }
212
253 intptr_t inclusive_ticks() const { return inclusive_ticks_; } 213 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
254 void set_inclusive_ticks(intptr_t inclusive_ticks) { 214 void set_inclusive_ticks(intptr_t inclusive_ticks) {
255 inclusive_ticks_ = inclusive_ticks; 215 inclusive_ticks_ = inclusive_ticks;
256 } 216 }
257 217
258 intptr_t exclusive_ticks() const { return exclusive_ticks_; } 218 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
259 void set_exclusive_ticks(intptr_t exclusive_ticks) { 219 void set_exclusive_ticks(intptr_t exclusive_ticks) {
260 exclusive_ticks_ = exclusive_ticks; 220 exclusive_ticks_ = exclusive_ticks;
261 } 221 }
262 222
(...skipping 24 matching lines...) Expand all
287 } 247 }
288 248
289 void AddTick(bool exclusive) { 249 void AddTick(bool exclusive) {
290 if (exclusive) { 250 if (exclusive) {
291 exclusive_ticks_++; 251 exclusive_ticks_++;
292 } else { 252 } else {
293 inclusive_ticks_++; 253 inclusive_ticks_++;
294 } 254 }
295 } 255 }
296 256
297 void DebugPrint() { 257 void DebugPrint() const {
298 printf("%s [%" Px ", %" Px ") %s\n", name_, start(), end(), 258 printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(),
299 KindToCString(kind_)); 259 name_);
300 } 260 }
301 261
302 void AddTickAtAddress(uintptr_t pc) { 262 void AddTickAtAddress(uword pc) {
303 const intptr_t length = address_table_->length(); 263 const intptr_t length = address_table_->length();
304 intptr_t i = 0; 264 intptr_t i = 0;
305 for (; i < length; i++) { 265 for (; i < length; i++) {
306 AddressEntry& entry = (*address_table_)[i]; 266 AddressEntry& entry = (*address_table_)[i];
307 if (entry.pc == pc) { 267 if (entry.pc == pc) {
308 entry.ticks++; 268 entry.ticks++;
309 return; 269 return;
310 } 270 }
311 if (entry.pc > pc) { 271 if (entry.pc > pc) {
312 break; 272 break;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 private: 336 private:
377 void GenerateAndSetSymbolName(const char* prefix) { 337 void GenerateAndSetSymbolName(const char* prefix) {
378 const intptr_t kBuffSize = 512; 338 const intptr_t kBuffSize = 512;
379 char buff[kBuffSize]; 339 char buff[kBuffSize];
380 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", 340 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
381 prefix, start(), end()); 341 prefix, start(), end());
382 SetName(buff); 342 SetName(buff);
383 } 343 }
384 344
385 Kind kind_; 345 Kind kind_;
386 uintptr_t start_; 346 uword start_;
387 uintptr_t end_; 347 uword end_;
388 intptr_t inclusive_ticks_; 348 intptr_t inclusive_ticks_;
389 intptr_t exclusive_ticks_; 349 intptr_t exclusive_ticks_;
390 const char* name_; 350 const char* name_;
391 ZoneGrowableArray<AddressEntry>* address_table_; 351 ZoneGrowableArray<AddressEntry>* address_table_;
392 352
393 DISALLOW_COPY_AND_ASSIGN(CodeRegion); 353 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
394 }; 354 };
395 355
396 356
357 class ScopeStopwatch : public ValueObject {
358 public:
359 explicit ScopeStopwatch(const char* name) : name_(name) {
360 start_ = OS::GetCurrentTimeMillis();
361 }
362
363 intptr_t GetElapsed() const {
364 intptr_t end = OS::GetCurrentTimeMillis();
365 ASSERT(end >= start_);
366 return end - start_;
367 }
368
369 ~ScopeStopwatch() {
370 if (FLAG_trace_profiled_isolates) {
371 intptr_t elapsed = GetElapsed();
372 OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
373 }
374 }
375
376 private:
377 const char* name_;
378 intptr_t start_;
379 };
siva 2014/02/19 18:09:54 Can this be just another timer, i.e: the code bel
380
381
397 // All code regions. Code region tables are built on demand when a profile 382 // All code regions. Code region tables are built on demand when a profile
398 // is requested (through the service or on isolate shutdown). 383 // is requested (through the service or on isolate shutdown).
399 class ProfilerCodeRegionTable : public ValueObject { 384 class ProfilerCodeRegionTable : public ValueObject {
400 public: 385 public:
401 explicit ProfilerCodeRegionTable(Isolate* isolate) : 386 explicit ProfilerCodeRegionTable(Isolate* isolate) :
402 heap_(isolate->heap()), 387 heap_(isolate->heap()),
403 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { 388 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
404 } 389 }
405 390
406 ~ProfilerCodeRegionTable() { 391 ~ProfilerCodeRegionTable() {
407 } 392 }
408 393
409 void AddTick(uintptr_t pc, bool exclusive, bool tick_address) { 394 void AddTick(uword pc, bool exclusive, bool tick_address) {
410 intptr_t index = FindIndex(pc); 395 intptr_t index = FindIndex(pc);
411 if (index < 0) { 396 if (index < 0) {
412 CodeRegion* code_region = CreateCodeRegion(pc); 397 CodeRegion* code_region = CreateCodeRegion(pc);
413 ASSERT(code_region != NULL); 398 ASSERT(code_region != NULL);
414 index = InsertCodeRegion(code_region); 399 index = InsertCodeRegion(code_region);
415 } 400 }
416 ASSERT(index >= 0); 401 ASSERT(index >= 0);
417 ASSERT(index < code_region_table_->length()); 402 ASSERT(index < code_region_table_->length());
418 (*code_region_table_)[index]->AddTick(exclusive); 403 (*code_region_table_)[index]->AddTick(exclusive);
419 if (tick_address) { 404 if (tick_address) {
420 (*code_region_table_)[index]->AddTickAtAddress(pc); 405 (*code_region_table_)[index]->AddTickAtAddress(pc);
421 } 406 }
422 } 407 }
423 408
424 intptr_t Length() const { return code_region_table_->length(); } 409 intptr_t Length() const { return code_region_table_->length(); }
425 410
426 CodeRegion* At(intptr_t idx) { 411 CodeRegion* At(intptr_t idx) {
427 return (*code_region_table_)[idx]; 412 return (*code_region_table_)[idx];
428 } 413 }
429 414
415 #if defined(DEBUG)
416 void Verify() {
417 VerifyOrder();
418 VerifyOverlap();
419 }
420 #endif
421
430 private: 422 private:
431 intptr_t FindIndex(uintptr_t pc) { 423 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) {
432 const intptr_t length = code_region_table_->length(); 424 ASSERT(comparator != NULL);
433 for (intptr_t i = 0; i < length; i++) { 425 intptr_t count = code_region_table_->length();
434 const CodeRegion* code_region = (*code_region_table_)[i]; 426 intptr_t first = 0;
435 if (code_region->contains(pc)) { 427 while (count > 0) {
436 return i; 428 intptr_t it = first;
429 intptr_t step = count / 2;
430 it += step;
431 const CodeRegion* code_region = (*code_region_table_)[it];
432 if (comparator(pc, code_region->start(), code_region->end())) {
433 first = ++it;
434 count -= (step + 1);
435 } else {
436 count = step;
437 } 437 }
438 } 438 }
439 return first;
440 }
441
442 static bool CompareUpperBound(uword pc, uword start, uword end) {
443 return pc >= end;
444 }
445
446 static bool CompareLowerBound(uword pc, uword start, uword end) {
447 return end <= pc;
448 }
449
450 intptr_t FindIndex(uword pc) {
451 intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
452 const CodeRegion* code_region = NULL;
453 if (index == code_region_table_->length()) {
454 // Not present.
455 return -1;
456 }
457 code_region = (*code_region_table_)[index];
458 if (code_region->contains(pc)) {
459 // Found at index.
460 return index;
461 }
439 return -1; 462 return -1;
440 } 463 }
441 464
442 CodeRegion* CreateCodeRegion(uintptr_t pc) { 465 CodeRegion* CreateCodeRegion(uword pc) {
443 Code& code = Code::Handle(Code::LookupCode(pc)); 466 Code& code = Code::Handle(Code::LookupCode(pc));
444 if (!code.IsNull()) { 467 if (!code.IsNull()) {
445 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), 468 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
446 code.EntryPoint() + code.Size()); 469 code.EntryPoint() + code.Size());
447 } 470 }
448 if (heap_->CodeContains(pc)) { 471 if (heap_->CodeContains(pc)) {
449 const intptr_t kDartCodeAlignment = 0x10; 472 const intptr_t kDartCodeAlignment = 0x10;
450 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); 473 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
451 return new CodeRegion(CodeRegion::kCollectedCode, 474 return new CodeRegion(CodeRegion::kCollectedCode, pc,
452 (pc & kDartCodeAlignmentMask),
453 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment); 475 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment);
454 } 476 }
455 uintptr_t native_start = 0; 477 uintptr_t native_start = 0;
456 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, 478 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
457 &native_start); 479 &native_start);
458 if (native_name == NULL) { 480 if (native_name == NULL) {
459 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1); 481 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1);
460 } 482 }
461 ASSERT(pc >= native_start); 483 ASSERT(pc >= native_start);
462 CodeRegion* code_region = 484 CodeRegion* code_region =
463 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1); 485 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1);
464 code_region->SetName(native_name); 486 code_region->SetName(native_name);
465 free(native_name); 487 free(native_name);
466 return code_region; 488 return code_region;
467 } 489 }
468 490
491 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
492 uword start, uword end) {
493 // We should never see overlapping Dart code regions.
494 ASSERT(region->kind() != CodeRegion::kDartCode);
495 // When code regions overlap, they should be of the same kind.
496 ASSERT(region->kind() == code_region->kind());
497 region->AdjustExtent(start, end);
498 }
499
469 intptr_t InsertCodeRegion(CodeRegion* code_region) { 500 intptr_t InsertCodeRegion(CodeRegion* code_region) {
501 const uword start = code_region->start();
502 const uword end = code_region->end();
470 const intptr_t length = code_region_table_->length(); 503 const intptr_t length = code_region_table_->length();
471 const uintptr_t start = code_region->start(); 504 if (length == 0) {
472 const uintptr_t end = code_region->end(); 505 code_region_table_->Add(code_region);
473 intptr_t i = 0; 506 return length;
474 for (; i < length; i++) { 507 }
475 CodeRegion* region = (*code_region_table_)[i]; 508 // Determine the correct place to insert or merge code_region into table.
476 if (region->contains(start) || region->contains(end - 1)) { 509 intptr_t lo = FindRegionIndex(start, &CompareLowerBound);
477 // We should only see overlapping native code regions. 510 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound);
478 ASSERT(region->kind() == CodeRegion::kNativeCode); 511 if ((lo == length) && (hi == length)) {
479 // When code regions overlap, they should be of the same kind. 512 lo = length - 1;
480 ASSERT(region->kind() == code_region->kind()); 513 }
481 // Overlapping code region. 514 if (lo == length) {
482 region->AdjustExtent(start, end); 515 CodeRegion* region = (*code_region_table_)[hi];
483 return i; 516 if (region->overlaps(code_region)) {
484 } else if (start >= region->end()) { 517 HandleOverlap(region, code_region, start, end);
485 // Insert here. 518 return hi;
486 break; 519 }
520 code_region_table_->Add(code_region);
521 return length;
522 } else if (hi == length) {
523 CodeRegion* region = (*code_region_table_)[lo];
524 if (region->overlaps(code_region)) {
525 HandleOverlap(region, code_region, start, end);
526 return lo;
527 }
528 code_region_table_->Add(code_region);
529 return length;
530 } else if (lo == hi) {
531 CodeRegion* region = (*code_region_table_)[lo];
532 if (region->overlaps(code_region)) {
533 HandleOverlap(region, code_region, start, end);
534 return lo;
535 }
536 code_region_table_->InsertAt(lo, code_region);
537 return lo;
538 } else {
539 CodeRegion* region = (*code_region_table_)[lo];
540 if (region->overlaps(code_region)) {
541 HandleOverlap(region, code_region, start, end);
542 return lo;
543 }
544 region = (*code_region_table_)[hi];
545 if (region->overlaps(code_region)) {
546 HandleOverlap(region, code_region, start, end);
547 return hi;
548 }
549 code_region_table_->InsertAt(hi, code_region);
550 return hi;
551 }
552 UNREACHABLE();
553 }
554
555 #if defined(DEBUG)
556 void VerifyOrder() {
557 const intptr_t length = code_region_table_->length();
558 if (length == 0) {
559 return;
560 }
561 uword last = (*code_region_table_)[0]->end();
562 for (intptr_t i = 1; i < length; i++) {
563 CodeRegion* a = (*code_region_table_)[i];
564 ASSERT(last <= a->start());
565 last = a->end();
566 }
567 }
568
569 void VerifyOverlap() {
570 const intptr_t length = code_region_table_->length();
571 for (intptr_t i = 0; i < length; i++) {
572 CodeRegion* a = (*code_region_table_)[i];
573 for (intptr_t j = i+1; j < length; j++) {
574 CodeRegion* b = (*code_region_table_)[j];
575 ASSERT(!a->contains(b->start()) &&
576 !a->contains(b->end() - 1) &&
577 !b->contains(a->start()) &&
578 !b->contains(a->end() - 1));
487 } 579 }
488 } 580 }
489 if (i != length) {
490 code_region_table_->InsertAt(i, code_region);
491 return i;
492 }
493 code_region_table_->Add(code_region);
494 return code_region_table_->length() - 1;
495 } 581 }
582 #endif
496 583
497 Heap* heap_; 584 Heap* heap_;
498 ZoneGrowableArray<CodeRegion*>* code_region_table_; 585 ZoneGrowableArray<CodeRegion*>* code_region_table_;
499 }; 586 };
500 587
501 588
589 class CodeRegionTableBuilder : public SampleVisitor {
590 public:
591 CodeRegionTableBuilder(Isolate* isolate,
592 ProfilerCodeRegionTable* code_region_table)
593 : SampleVisitor(isolate), code_region_table_(code_region_table) {
594 frames_ = 0;
595 }
596
597 void VisitSample(Sample* sample) {
598 code_region_table_->AddTick(sample->At(0), true, false);
599 // Give all frames an inclusive tick and tick the address.
600 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
601 if (sample->At(i) == 0) {
602 break;
603 }
604 frames_++;
605 code_region_table_->AddTick(sample->At(i), false, true);
606 }
607 }
608
609 intptr_t frames() const { return frames_; }
610 private:
611 intptr_t frames_;
612 ProfilerCodeRegionTable* code_region_table_;
613 };
614
615
502 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, 616 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
503 bool full) { 617 bool full) {
504 ASSERT(isolate == Isolate::Current()); 618 ASSERT(isolate == Isolate::Current());
505 // Disable profile interrupts while processing the buffer. 619 // Disable profile interrupts while processing the buffer.
506 EndExecution(isolate); 620 EndExecution(isolate);
507 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 621 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
508 IsolateProfilerData* profiler_data = isolate->profiler_data(); 622 IsolateProfilerData* profiler_data = isolate->profiler_data();
509 if (profiler_data == NULL) { 623 if (profiler_data == NULL) {
510 JSONObject error(stream); 624 JSONObject error(stream);
511 error.AddProperty("type", "Error"); 625 error.AddProperty("type", "Error");
512 error.AddProperty("text", "Isolate does not have profiling enabled."); 626 error.AddProperty("text", "Isolate does not have profiling enabled.");
513 return; 627 return;
514 } 628 }
515 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 629 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
516 ASSERT(sample_buffer != NULL); 630 ASSERT(sample_buffer != NULL);
517 { 631 {
518 StackZone zone(isolate); 632 StackZone zone(isolate);
519 { 633 {
520 // Build code region table. 634 // Build code region table.
521 ProfilerCodeRegionTable code_region_table(isolate); 635 ProfilerCodeRegionTable code_region_table(isolate);
522 intptr_t samples = 636 CodeRegionTableBuilder builder(isolate, &code_region_table);
523 ProcessSamples(isolate, &code_region_table, sample_buffer);
524 { 637 {
638 ScopeStopwatch sw("CodeTableBuild");
639 sample_buffer->VisitSamples(&builder);
640 }
641 #if defined(DEBUG)
642 code_region_table.Verify();
643 #endif
644 // Number of samples we processed.
645 intptr_t samples = builder.visited();
646 intptr_t frames = builder.frames();
647 if (FLAG_trace_profiled_isolates) {
648 OS::Print("%" Pd " frames produced %" Pd " code objects.\n",
649 frames, code_region_table.Length());
650 }
651 {
652 ScopeStopwatch sw("CodeTableStream");
525 // Serialize to JSON. 653 // Serialize to JSON.
526 JSONObject obj(stream); 654 JSONObject obj(stream);
527 obj.AddProperty("type", "Profile"); 655 obj.AddProperty("type", "Profile");
528 obj.AddProperty("samples", samples); 656 obj.AddProperty("samples", samples);
529 JSONArray codes(&obj, "codes"); 657 JSONArray codes(&obj, "codes");
530 for (intptr_t i = 0; i < code_region_table.Length(); i++) { 658 for (intptr_t i = 0; i < code_region_table.Length(); i++) {
531 CodeRegion* region = code_region_table.At(i); 659 CodeRegion* region = code_region_table.At(i);
532 ASSERT(region != NULL); 660 ASSERT(region != NULL);
533 region->PrintToJSONArray(&codes, full); 661 region->PrintToJSONArray(&codes, false);
534 } 662 }
535 } 663 }
536 } 664 }
537 } 665 }
538 // Enable profile interrupts. 666 // Enable profile interrupts.
539 BeginExecution(isolate); 667 BeginExecution(isolate);
540 } 668 }
541 669
542 670
543 intptr_t Profiler::ProcessSamples(Isolate* isolate,
544 ProfilerCodeRegionTable* code_region_table,
545 SampleBuffer* sample_buffer) {
546 int64_t start = OS::GetCurrentTimeMillis();
547 intptr_t samples = 0;
548 Sample* sample = Sample::Allocate();
549 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
550 sample_buffer->CopySample(i, sample);
551 if (sample->isolate() != isolate) {
552 continue;
553 }
554 if (sample->timestamp() == 0) {
555 continue;
556 }
557 samples += ProcessSample(isolate, code_region_table, sample);
558 }
559 free(sample);
560 int64_t end = OS::GetCurrentTimeMillis();
561 if (FLAG_trace_profiled_isolates) {
562 int64_t delta = end - start;
563 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n",
564 samples,
565 isolate->name(),
566 delta);
567 }
568 return samples;
569 }
570
571
572 intptr_t Profiler::ProcessSample(Isolate* isolate,
573 ProfilerCodeRegionTable* code_region_table,
574 Sample* sample) {
575 if (sample->type() != Sample::kIsolateSample) {
576 return 0;
577 }
578 if (sample->At(0) == 0) {
579 // No frames in this sample.
580 return 0;
581 }
582 // i points to the leaf (exclusive) PC sample. Do not tick the address.
583 code_region_table->AddTick(sample->At(0), true, false);
584 // Give all frames an inclusive tick and tick the address.
585 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
586 if (sample->At(i) == 0) {
587 break;
588 }
589 code_region_table->AddTick(sample->At(i), false, true);
590 }
591 return 1;
592 }
593
594
595 void Profiler::WriteProfile(Isolate* isolate) { 671 void Profiler::WriteProfile(Isolate* isolate) {
596 if (isolate == NULL) { 672 if (isolate == NULL) {
597 return; 673 return;
598 } 674 }
599 if (!FLAG_profile) { 675 if (!FLAG_profile) {
600 return; 676 return;
601 } 677 }
602 ASSERT(initialized_); 678 ASSERT(initialized_);
603 if (FLAG_profile_dir == NULL) { 679 if (FLAG_profile_dir == NULL) {
604 return; 680 return;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 728
653 intptr_t Sample::instance_size_ = 0; 729 intptr_t Sample::instance_size_ = 0;
654 730
655 void Sample::InitOnce() { 731 void Sample::InitOnce() {
656 ASSERT(FLAG_profile_depth >= 1); 732 ASSERT(FLAG_profile_depth >= 1);
657 instance_size_ = 733 instance_size_ =
658 sizeof(Sample) + (sizeof(intptr_t) * FLAG_profile_depth); // NOLINT. 734 sizeof(Sample) + (sizeof(intptr_t) * FLAG_profile_depth); // NOLINT.
659 } 735 }
660 736
661 737
662 uintptr_t Sample::At(intptr_t i) const { 738 uword Sample::At(intptr_t i) const {
663 ASSERT(i >= 0); 739 ASSERT(i >= 0);
664 ASSERT(i < FLAG_profile_depth); 740 ASSERT(i < FLAG_profile_depth);
665 return pcs_[i]; 741 return pcs_[i];
666 } 742 }
667 743
668 744
669 void Sample::SetAt(intptr_t i, uintptr_t pc) { 745 void Sample::SetAt(intptr_t i, uword pc) {
670 ASSERT(i >= 0); 746 ASSERT(i >= 0);
671 ASSERT(i < FLAG_profile_depth); 747 ASSERT(i < FLAG_profile_depth);
672 pcs_[i] = pc; 748 pcs_[i] = pc;
673 } 749 }
674 750
675 751
676 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, 752 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
677 ThreadId tid) { 753 ThreadId tid) {
678 timestamp_ = timestamp; 754 timestamp_ = timestamp;
679 tid_ = tid; 755 tid_ = tid;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 812
737 Sample* SampleBuffer::At(intptr_t idx) const { 813 Sample* SampleBuffer::At(intptr_t idx) const {
738 ASSERT(idx >= 0); 814 ASSERT(idx >= 0);
739 ASSERT(idx < capacity_); 815 ASSERT(idx < capacity_);
740 intptr_t offset = idx * Sample::instance_size(); 816 intptr_t offset = idx * Sample::instance_size();
741 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); 817 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_);
742 return reinterpret_cast<Sample*>(samples + offset); 818 return reinterpret_cast<Sample*>(samples + offset);
743 } 819 }
744 820
745 821
746 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, 822 void SampleBuffer::VisitSamples(SampleVisitor* visitor) {
747 uintptr_t stack_lower, 823 ASSERT(visitor != NULL);
748 uintptr_t stack_upper, 824 Sample* sample = Sample::Allocate();
749 uintptr_t pc, 825 const intptr_t length = capacity();
750 uintptr_t fp, 826 for (intptr_t i = 0; i < length; i++) {
751 uintptr_t sp) : 827 CopySample(i, sample);
752 sample_(sample), 828 if (sample->isolate() != visitor->isolate()) {
753 stack_lower_(stack_lower), 829 // Another isolate.
754 stack_upper_(stack_upper), 830 continue;
755 original_pc_(pc), 831 }
756 original_fp_(fp), 832 if (sample->timestamp() == 0) {
757 original_sp_(sp), 833 // Empty.
758 lower_bound_(stack_lower) { 834 continue;
759 ASSERT(sample_ != NULL); 835 }
836 if (sample->At(0) == 0) {
837 // No frames.
838 continue;
839 }
840 visitor->IncrementVisited();
841 visitor->VisitSample(sample);
842 }
843 free(sample);
760 } 844 }
761 845
762 846
763 // Notes on stack frame walking: 847 // Notes on stack frame walking:
764 // 848 //
765 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames 849 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames
766 // The stack frame walking code uses the frame pointer to traverse the stack. 850 // The stack frame walking code uses the frame pointer to traverse the stack.
767 // If the VM is compiled without frame pointers (which is the default on 851 // If the VM is compiled without frame pointers (which is the default on
768 // recent GCC versions with optimizing enabled) the stack walking code may 852 // recent GCC versions with optimizing enabled) the stack walking code may
769 // fail (sometimes leading to a crash). 853 // fail (sometimes leading to a crash).
770 // 854 //
855 class ProfilerSampleStackWalker : public ValueObject {
856 public:
857 ProfilerSampleStackWalker(Sample* sample,
858 uword stack_lower,
859 uword stack_upper,
860 uword pc,
861 uword fp,
862 uword sp)
863 : sample_(sample),
864 stack_lower_(stack_lower),
865 stack_upper_(stack_upper),
866 original_pc_(pc),
867 original_fp_(fp),
868 original_sp_(sp),
869 lower_bound_(stack_lower) {
870 ASSERT(sample_ != NULL);
871 }
771 872
772 int ProfilerSampleStackWalker::walk() { 873 int walk() {
773 const intptr_t kMaxStep = 0x1000; // 4K. 874 const intptr_t kMaxStep = 0x1000; // 4K.
774 const bool kWalkStack = true; // Walk the stack. 875 const bool kWalkStack = true; // Walk the stack.
775 // Always store the exclusive PC. 876 // Always store the exclusive PC.
776 sample_->SetAt(0, original_pc_); 877 sample_->SetAt(0, original_pc_);
777 if (!kWalkStack) { 878 if (!kWalkStack) {
778 // Not walking the stack, only took exclusive sample. 879 // Not walking the stack, only took exclusive sample.
779 return 1; 880 return 1;
881 }
882 uword* pc = reinterpret_cast<uword*>(original_pc_);
883 uword* fp = reinterpret_cast<uword*>(original_fp_);
884 uword* previous_fp = fp;
885 if (original_sp_ > original_fp_) {
886 // Stack pointer should not be above frame pointer.
887 return 1;
888 }
889 intptr_t gap = original_fp_ - original_sp_;
890 if (gap >= kMaxStep) {
891 // Gap between frame pointer and stack pointer is
892 // too large.
893 return 1;
894 }
895 if (original_sp_ < lower_bound_) {
896 // The stack pointer gives us a better lower bound than
897 // the isolates stack limit.
898 lower_bound_ = original_sp_;
899 }
900 int i = 0;
901 for (; i < FLAG_profile_depth; i++) {
902 sample_->SetAt(i, reinterpret_cast<uword>(pc));
903 if (!ValidFramePointer(fp)) {
904 return i + 1;
905 }
906 pc = CallerPC(fp);
907 previous_fp = fp;
908 fp = CallerFP(fp);
909 intptr_t step = fp - previous_fp;
910 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) {
911 // Frame pointer step is too large.
912 // Frame pointer did not move to a higher address.
913 // Frame pointer is outside of isolate stack bounds.
914 return i + 1;
915 }
916 // Move the lower bound up.
917 lower_bound_ = reinterpret_cast<uword>(fp);
918 }
919 return i;
780 } 920 }
781 uword* pc = reinterpret_cast<uword*>(original_pc_); 921
782 uword* fp = reinterpret_cast<uword*>(original_fp_); 922 private:
783 uword* previous_fp = fp; 923 uword* CallerPC(uword* fp) const {
784 if (original_sp_ > original_fp_) { 924 ASSERT(fp != NULL);
785 // Stack pointer should not be above frame pointer. 925 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp));
786 return 1;
787 } 926 }
788 intptr_t gap = original_fp_ - original_sp_; 927
789 if (gap >= kMaxStep) { 928 uword* CallerFP(uword* fp) const {
790 // Gap between frame pointer and stack pointer is 929 ASSERT(fp != NULL);
791 // too large. 930 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
792 return 1;
793 } 931 }
794 if (original_sp_ < lower_bound_) { 932
795 // The stack pointer gives us a better lower bound than 933 bool ValidFramePointer(uword* fp) const {
796 // the isolates stack limit. 934 if (fp == NULL) {
797 lower_bound_ = original_sp_; 935 return false;
936 }
937 uword cursor = reinterpret_cast<uword>(fp);
938 cursor += sizeof(fp);
939 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
940 return r;
798 } 941 }
799 int i = 0; 942
800 for (; i < FLAG_profile_depth; i++) { 943 Sample* sample_;
801 sample_->SetAt(i, reinterpret_cast<uintptr_t>(pc)); 944 const uword stack_lower_;
802 if (!ValidFramePointer(fp)) { 945 const uword stack_upper_;
803 return i + 1; 946 const uword original_pc_;
804 } 947 const uword original_fp_;
805 pc = CallerPC(fp); 948 const uword original_sp_;
806 previous_fp = fp; 949 uword lower_bound_;
807 fp = CallerFP(fp); 950 };
808 intptr_t step = fp - previous_fp; 951
809 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { 952 void Profiler::RecordSampleInterruptCallback(
810 // Frame pointer step is too large. 953 const InterruptedThreadState& state,
811 // Frame pointer did not move to a higher address. 954 void* data) {
812 // Frame pointer is outside of isolate stack bounds. 955 Isolate* isolate = reinterpret_cast<Isolate*>(data);
813 return i + 1; 956 if (isolate == NULL) {
814 } 957 return;
815 // Move the lower bound up.
816 lower_bound_ = reinterpret_cast<uintptr_t>(fp);
817 } 958 }
818 return i; 959 IsolateProfilerData* profiler_data = isolate->profiler_data();
960 if (profiler_data == NULL) {
961 return;
962 }
963 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
964 if (sample_buffer == NULL) {
965 return;
966 }
967 Sample* sample = sample_buffer->ReserveSample();
968 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
969 state.tid);
970 uword stack_lower = 0;
971 uword stack_upper = 0;
972 isolate->GetStackBounds(&stack_lower, &stack_upper);
973 if ((stack_lower == 0) || (stack_upper == 0)) {
974 stack_lower = 0;
975 stack_upper = 0;
976 }
977 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
978 state.pc, state.fp, state.sp);
979 stackWalker.walk();
819 } 980 }
820 981
821 982
822 uword* ProfilerSampleStackWalker::CallerPC(uword* fp) {
823 ASSERT(fp != NULL);
824 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp));
825 }
826
827
828 uword* ProfilerSampleStackWalker::CallerFP(uword* fp) {
829 ASSERT(fp != NULL);
830 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
831 }
832
833
834 bool ProfilerSampleStackWalker::ValidFramePointer(uword* fp) {
835 if (fp == NULL) {
836 return false;
837 }
838 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp);
839 cursor += sizeof(fp);
840 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
841 return r;
842 }
843
844
845 } // namespace dart 983 } // namespace dart
OLDNEW
« runtime/vm/profiler.h ('K') | « runtime/vm/profiler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698