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

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

Issue 928833003: Add Function based profile tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 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
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/address_sanitizer.h" 5 #include "platform/address_sanitizer.h"
6 #include "platform/memory_sanitizer.h" 6 #include "platform/memory_sanitizer.h"
7 #include "platform/utils.h" 7 #include "platform/utils.h"
8 8
9 #include "vm/allocation.h" 9 #include "vm/allocation.h"
10 #include "vm/atomic.h" 10 #include "vm/atomic.h"
11 #include "vm/code_patcher.h" 11 #include "vm/code_patcher.h"
12 #include "vm/instructions.h"
12 #include "vm/isolate.h" 13 #include "vm/isolate.h"
13 #include "vm/json_stream.h" 14 #include "vm/json_stream.h"
14 #include "vm/lockers.h" 15 #include "vm/lockers.h"
15 #include "vm/native_symbol.h" 16 #include "vm/native_symbol.h"
16 #include "vm/object.h" 17 #include "vm/object.h"
17 #include "vm/os.h" 18 #include "vm/os.h"
18 #include "vm/profiler.h" 19 #include "vm/profiler.h"
19 #include "vm/reusable_handles.h" 20 #include "vm/reusable_handles.h"
20 #include "vm/signal_handler.h" 21 #include "vm/signal_handler.h"
21 #include "vm/simulator.h" 22 #include "vm/simulator.h"
22 #include "vm/stack_frame.h" 23 #include "vm/stack_frame.h"
23 24
24 namespace dart { 25 namespace dart {
25 26
26 27
27 #if defined(TARGET_OS_ANDROID) || defined(HOST_ARCH_ARM64) 28 #if defined(TARGET_OS_ANDROID) || defined(HOST_ARCH_ARM64)
28 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); 29 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
29 #else 30 #else
30 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); 31 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
31 #endif 32 #endif
32 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); 33 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
33 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler.");
34 DEFINE_FLAG(int, profile_period, 1000, 34 DEFINE_FLAG(int, profile_period, 1000,
35 "Time between profiler samples in microseconds. Minimum 50."); 35 "Time between profiler samples in microseconds. Minimum 50.");
36 DEFINE_FLAG(int, profile_depth, 8, 36 DEFINE_FLAG(int, profile_depth, 8,
37 "Maximum number stack frames walked. Minimum 1. Maximum 255."); 37 "Maximum number stack frames walked. Minimum 1. Maximum 255.");
38 #if defined(PROFILE_NATIVE_CODE) || defined(USING_SIMULATOR) 38 #if defined(PROFILE_NATIVE_CODE) || defined(USING_SIMULATOR)
39 DEFINE_FLAG(bool, profile_vm, true, 39 DEFINE_FLAG(bool, profile_vm, true,
40 "Always collect native stack traces."); 40 "Always collect native stack traces.");
41 #else 41 #else
42 DEFINE_FLAG(bool, profile_vm, false, 42 DEFINE_FLAG(bool, profile_vm, false,
43 "Always collect native stack traces."); 43 "Always collect native stack traces.");
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 246
247 Sample* SampleBuffer::ReserveSample() { 247 Sample* SampleBuffer::ReserveSample() {
248 ASSERT(samples_ != NULL); 248 ASSERT(samples_ != NULL);
249 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); 249 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
250 // Map back into sample buffer range. 250 // Map back into sample buffer range.
251 cursor = cursor % capacity_; 251 cursor = cursor % capacity_;
252 return At(cursor); 252 return At(cursor);
253 } 253 }
254 254
255 255
256 static void SetPCMarkerIfSafe(Sample* sample) { 256 // Used to locate the stack slot in Dart code that contains the return address.
257 ASSERT(sample != NULL); 257 // NOTE: Only handles the prologue.
258 258 // NOTE: Architecture specific implementations below.
259 uword* fp = reinterpret_cast<uword*>(sample->fp()); 259 class ReturnAddressLocator : public ValueObject {
260 uword* sp = reinterpret_cast<uword*>(sample->sp()); 260 public:
261 261 ReturnAddressLocator(uword pc, const Code& code)
262 // If FP == SP, the pc marker hasn't been pushed. 262 : pc_(pc),
263 if (fp > sp) { 263 code_(Code::ZoneHandle(code.raw())),
264 #if defined(TARGET_OS_WINDOWS) 264 is_optimized_(code.is_optimized()) {
265 // If the fp is at the beginning of a page, it may be unsafe to access 265 ASSERT(!code_.IsNull());
266 // the pc marker, because we are reading it from a different thread on 266 ASSERT(code_.ContainsInstructionAt(pc_));
267 // Windows. The marker is below fp and the previous page may be a guard 267 }
268 // page. 268
269 const intptr_t kPageMask = VirtualMemory::PageSize() - 1; 269 bool is_code_optimized() {
270 if ((sample->fp() & kPageMask) == 0) { 270 return is_optimized_;
271 }
272
273 // Returns -1 on failure.
274 intptr_t ReturnAddressRelativeToSP();
275
276 // Returns offset into code object.
277 uword RelativePC() {
278 return pc_ - code_.EntryPoint();
279 }
280
281 uint8_t* CodePointer(uword offset) {
282 const uword size = code_.Size();
283 ASSERT(offset < size);
284 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code_.EntryPoint());
285 code_pointer += offset;
286 return code_pointer;
287 }
288
289 private:
290 const uword pc_;
291 const Code& code_;
292 const bool is_optimized_;
293 };
294
295
296 #if defined(TARGET_ARCH_IA32)
297 intptr_t ReturnAddressLocator::ReturnAddressRelativeToSP() {
298 const uword offset = RelativePC();
299 const uword size = code_.Size();
300 if (is_optimized_) {
301 // 0: push ebp
302 // 1: mov ebp, esp
303 // 3: ...
304 if (offset == 0x0) {
305 // Stack layout:
306 // 0 RETURN ADDRESS.
307 return 0;
308 }
309 if (offset == 0x1) {
310 // Stack layout:
311 // 0 CALLER FRAME POINTER
312 // 1 RETURN ADDRESS
313 return 1;
314 }
315 return -1;
316 } else {
317 // 0x00: mov edi, function
318 // 0x05: incl (inc usage count) <-- this is optional.
319 // 0x08: cmpl (compare usage count)
320 // 0x0f: jump to optimize function
321 // 0x15: push ebp
322 // 0x16: mov ebp, esp
323 // 0x18: ...
324 ASSERT(size >= 0x08);
325 const uword incl_offset = 0x05;
326 const uword incl_length = 0x03;
327 const uint8_t incl_op_code = 0xFF;
328 const bool has_incl = (*CodePointer(incl_offset) == incl_op_code);
329 const uword push_fp_offset = has_incl ? 0x15 : 0x15 - incl_length;
330 if (offset <= push_fp_offset) {
331 // Stack layout:
332 // 0 RETURN ADDRESS.
333 return 0;
334 }
335 if (offset == (push_fp_offset + 1)) {
336 // Stack layout:
337 // 0 CALLER FRAME POINTER
338 // 1 RETURN ADDRESS
339 return 1;
340 }
341 return -1;
342 }
343 UNREACHABLE();
344 return -1;
345 }
346 #elif defined(TARGET_ARCH_X64)
347 intptr_t ReturnAddressLocator::ReturnAddressRelativeToSP() {
348 const uword offset = RelativePC();
349 const uword size = code_.Size();
350 if (is_optimized_) {
351 // 0x00: leaq (load pc marker)
352 // 0x07: movq (load pool pointer)
353 // 0x0c: push rpb
354 // 0x0d: movq rbp, rsp
355 // 0x10: ...
356 const uword push_fp_offset = 0x0c;
357 if (offset <= push_fp_offset) {
358 // Stack layout:
359 // 0 RETURN ADDRESS.
360 return 0;
361 }
362 if (offset == (push_fp_offset + 1)) {
363 // Stack layout:
364 // 0 CALLER FRAME POINTER
365 // 1 RETURN ADDRESS
366 return 1;
367 }
368 return -1;
369 } else {
370 // 0x00: leaq (load pc marker)
371 // 0x07: movq (load pool pointer)
372 // 0x0c: movq (load function)
373 // 0x13: incl (inc usage count) <-- this is optional.
374 // 0x16: cmpl (compare usage count)
375 // 0x1d: jl + 0x
376 // 0x23: jmp [pool pointer]
377 // 0x27: push rbp
378 // 0x28: movq rbp, rsp
379 // 0x2b: ...
380 ASSERT(size >= 0x16);
381 const uword incl_offset = 0x13;
382 const uword incl_length = 0x03;
383 const uint8_t incl_op_code = 0xFF;
384 const bool has_incl = (*CodePointer(incl_offset) == incl_op_code);
385 const uword push_fp_offset = has_incl ? 0x27 : 0x27 - incl_length;
386 if (offset <= push_fp_offset) {
387 // Stack layout:
388 // 0 RETURN ADDRESS.
389 return 0;
390 }
391 if (offset == (push_fp_offset + 1)) {
392 // Stack layout:
393 // 0 CALLER FRAME POINTER
394 // 1 RETURN ADDRESS
395 return 1;
396 }
397 return -1;
398 }
399 UNREACHABLE();
400 return -1;
401 }
402 #elif defined(TARGET_ARCH_ARM)
403 intptr_t ReturnAddressLocator::ReturnAddressRelativeToSP() {
404 return -1;
405 }
406 #elif defined(TARGET_ARCH_ARM64)
407 intptr_t ReturnAddressLocator::ReturnAddressRelativeToSP() {
408 return -1;
409 }
410 #elif defined(TARGET_ARCH_MIPS)
411 intptr_t ReturnAddressLocator::ReturnAddressRelativeToSP() {
412 return -1;
413 }
414 #else
415 #error ReturnAddressLocator implementation missing for this architecture.
416 #endif
417
418
419 FixTopFrameVisitor::FixTopFrameVisitor(Isolate* isolate)
420 : SampleVisitor(isolate),
421 vm_isolate_(Dart::vm_isolate()) {
422 }
423
424
425 void FixTopFrameVisitor::VisitSample(Sample* sample) {
426 if (sample->processed()) {
427 // Already processed.
428 return;
429 }
430 REUSABLE_CODE_HANDLESCOPE(isolate());
431 // Mark that we've processed this sample.
432 sample->set_processed(true);
433 // Lookup code object for leaf frame.
434 Code& code = reused_code_handle.Handle();
435 code = FindCodeForPC(sample->At(0));
436 sample->set_leaf_frame_is_dart(!code.IsNull());
437 if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) {
438 // Code compiled after sample. Ignore.
439 return;
440 }
441 if (sample->leaf_frame_is_dart()) {
442 CheckForMissingDartFrame(code, sample);
443 }
444 }
445
446
447 void FixTopFrameVisitor::CheckForMissingDartFrame(const Code& code,
448 Sample* sample) const {
449 // Some stubs (and intrinsics) do not push a frame onto the stack leaving
450 // the frame pointer in the caller.
451 //
452 // PC -> STUB
453 // FP -> DART3 <-+
454 // DART2 <-| <- TOP FRAME RETURN ADDRESS.
455 // DART1 <-|
456 // .....
457 //
458 // In this case, traversing the linked stack frames will not collect a PC
459 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1.
460 // In Dart code, after pushing the FP onto the stack, an IP in the current
461 // function is pushed onto the stack as well. This stack slot is called
462 // the PC marker. We can use the PC marker to insert DART3 into the stack
463 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the
464 // inserted PC may not accurately reflect the true return address into DART3.
465 ASSERT(!code.IsNull());
466
467 // The pc marker is our current best guess of a return address.
468 uword return_address = sample->pc_marker();
469
470 // Attempt to find a better return address.
471 ReturnAddressLocator ral(sample->At(0), code);
472 ReturnPattern rp(sample->At(0));
473
474 intptr_t return_address_slot = ral.ReturnAddressRelativeToSP();
475 if (return_address_slot != -1) {
476 // In prologue, located the return address.
477 ASSERT(return_address_slot >= 0);
478 ASSERT(return_address_slot < Sample::kStackBufferSizeInWords);
479 return_address = sample->GetStackBuffer()[return_address_slot];
480 } else if (rp.IsValid()) {
481 // In epilogue, located the return address.
482 return_address = sample->possible_return_address();
483 } else {
484 // Could not find a better return address than the pc_marker.
485 if (code.ContainsInstructionAt(return_address)) {
486 // PC marker is in the same code as pc, no missing frame.
271 return; 487 return;
272 } 488 }
273 #endif 489 }
274 uword* pc_marker_ptr = fp + kPcMarkerSlotFromFp; 490
275 // MSan/ASan are unaware of frames initialized by generated code. 491 if (return_address != 0) {
276 MSAN_UNPOISON(pc_marker_ptr, kWordSize); 492 sample->InsertCallerForTopFrame(return_address);
277 ASAN_UNPOISON(pc_marker_ptr, kWordSize); 493 }
278 sample->set_pc_marker(*pc_marker_ptr); 494 }
279 } 495
496
497 bool FixTopFrameVisitor::ContainedInDartCodeHeaps(uword pc) const {
498 return isolate()->heap()->CodeContains(pc) ||
499 vm_isolate()->heap()->CodeContains(pc);
500 }
501
502
503 RawCode* FixTopFrameVisitor::FindCodeForPC(uword pc) const {
504 // Check current isolate for pc.
505 if (isolate()->heap()->CodeContains(pc)) {
506 return Code::LookupCode(pc);
507 }
508 // Check VM isolate for pc.
509 if (vm_isolate()->heap()->CodeContains(pc)) {
510 return Code::LookupCodeInVmIsolate(pc);
511 }
512 return Code::null();
280 } 513 }
281 514
282 515
283 // Given an exit frame, walk the Dart stack. 516 // Given an exit frame, walk the Dart stack.
284 class ProfilerDartExitStackWalker : public ValueObject { 517 class ProfilerDartExitStackWalker : public ValueObject {
285 public: 518 public:
286 ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample) 519 ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample)
287 : sample_(sample), 520 : sample_(sample),
288 frame_iterator_(isolate) { 521 frame_iterator_(isolate) {
289 ASSERT(sample_ != NULL); 522 ASSERT(sample_ != NULL);
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 801
569 Sample* sample_; 802 Sample* sample_;
570 const uword stack_upper_; 803 const uword stack_upper_;
571 const uword original_pc_; 804 const uword original_pc_;
572 const uword original_fp_; 805 const uword original_fp_;
573 const uword original_sp_; 806 const uword original_sp_;
574 uword lower_bound_; 807 uword lower_bound_;
575 }; 808 };
576 809
577 810
811 static void SetPCMarkerIfSafe(Sample* sample) {
812 ASSERT(sample != NULL);
813
814 uword* fp = reinterpret_cast<uword*>(sample->fp());
815 uword* sp = reinterpret_cast<uword*>(sample->sp());
816
817 // If FP == SP, the pc marker hasn't been pushed.
818 if (fp > sp) {
819 #if defined(TARGET_OS_WINDOWS)
820 // If the fp is at the beginning of a page, it may be unsafe to access
821 // the pc marker, because we are reading it from a different thread on
822 // Windows. The marker is below fp and the previous page may be a guard
823 // page.
824 const intptr_t kPageMask = VirtualMemory::PageSize() - 1;
825 if ((sample->fp() & kPageMask) == 0) {
826 return;
827 }
828 #endif
829 uword* pc_marker_ptr = fp + kPcMarkerSlotFromFp;
830 // MSan/ASan are unaware of frames initialized by generated code.
831 MSAN_UNPOISON(pc_marker_ptr, kWordSize);
832 ASAN_UNPOISON(pc_marker_ptr, kWordSize);
833 sample->set_pc_marker(*pc_marker_ptr);
834 }
835 }
836
837
838 static void GrabPossibleReturnValue(Sample* sample) {
839 ASSERT(sample != NULL);
840 // On other architectures possible_return_address is filled in from a
841 // register that was captured by the signal handler.
842 #if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32) || \
843 defined(USING_SIMULATOR)
844 uword* sp = reinterpret_cast<uword*>(sample->sp());
845 if (sp != NULL) {
846 sample->set_possible_return_address(*sp);
847 }
848 #endif
849 }
850
851
852 static void FillStackBuffer(Sample* sample) {
853 ASSERT(sample != NULL);
854 uword* sp = reinterpret_cast<uword*>(sample->sp());
855 uword* stack_buffer = sample->GetStackBuffer();
856 if (sp != NULL) {
857 for (intptr_t i = 0; i < Sample::kStackBufferSizeInWords; i++) {
858 stack_buffer[i] = *sp;
859 sp++;
860 }
861 }
862 }
863
864
578 void Profiler::RecordSampleInterruptCallback( 865 void Profiler::RecordSampleInterruptCallback(
579 const InterruptedThreadState& state, 866 const InterruptedThreadState& state,
580 void* data) { 867 void* data) {
581 Isolate* isolate = reinterpret_cast<Isolate*>(data); 868 Isolate* isolate = reinterpret_cast<Isolate*>(data);
582 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { 869 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
583 // No isolate. 870 // No isolate.
584 return; 871 return;
585 } 872 }
586 873
587 ASSERT(isolate != Dart::vm_isolate()); 874 ASSERT(isolate != Dart::vm_isolate());
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 } 959 }
673 #endif 960 #endif
674 // Increment counter for vm tag. 961 // Increment counter for vm tag.
675 VMTagCounters* counters = isolate->vm_tag_counters(); 962 VMTagCounters* counters = isolate->vm_tag_counters();
676 ASSERT(counters != NULL); 963 ASSERT(counters != NULL);
677 counters->Increment(vm_tag); 964 counters->Increment(vm_tag);
678 sample->set_vm_tag(vm_tag); 965 sample->set_vm_tag(vm_tag);
679 sample->set_user_tag(isolate->user_tag()); 966 sample->set_user_tag(isolate->user_tag());
680 sample->set_sp(sp); 967 sample->set_sp(sp);
681 sample->set_fp(state.fp); 968 sample->set_fp(state.fp);
969 sample->set_possible_return_address(state.ra);
970 GrabPossibleReturnValue(sample);
971 FillStackBuffer(sample);
682 #if !(defined(TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64)) 972 #if !(defined(TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64))
683 // It is never safe to read other thread's stack unless on Win64 973 // It is never safe to read other thread's stack unless on Win64
684 // other thread is inside Dart code. 974 // other thread is inside Dart code.
685 SetPCMarkerIfSafe(sample); 975 SetPCMarkerIfSafe(sample);
686 #endif 976 #endif
687 977
688 // Walk the call stack. 978 // Walk the call stack.
689 if (FLAG_profile_vm) { 979 if (FLAG_profile_vm) {
690 // Always walk the native stack collecting both native and Dart frames. 980 // Always walk the native stack collecting both native and Dart frames.
691 ProfilerNativeStackWalker stackWalker(sample, 981 ProfilerNativeStackWalker stackWalker(sample,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 state.pc, 1019 state.pc,
730 state.fp, 1020 state.fp,
731 sp); 1021 sp);
732 stackWalker.walk(); 1022 stackWalker.walk();
733 #endif 1023 #endif
734 } 1024 }
735 } 1025 }
736 } 1026 }
737 1027
738 } // namespace dart 1028 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698