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

Side by Side Diff: src/sampler.cc

Issue 23115005: Use signals for cpu profiling on Mac OS X (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebase Created 7 years, 3 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
« no previous file with comments | « src/cpu-profiler.cc ('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 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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 11 matching lines...) Expand all
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
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 #include "sampler.h" 28 #include "sampler.h"
29 29
30 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ 30 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
31 || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \ 31 || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \
32 || defined(__native_client__) 32 || defined(__native_client__) || defined(__MACH__)
33 33
34 #define USE_SIGNALS 34 #define USE_SIGNALS
35 35
36 #include <errno.h> 36 #include <errno.h>
37 #include <pthread.h> 37 #include <pthread.h>
38 #include <signal.h> 38 #include <signal.h>
39 #include <sys/time.h> 39 #include <sys/time.h>
40 #include <sys/syscall.h> 40 #include <sys/syscall.h>
41
42 #if defined(__MACH__)
43 #include <mach/mach.h>
41 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> 44 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
42 // and is a typedef for struct sigcontext. There is no uc_mcontext. 45 // and is a typedef for struct sigcontext. There is no uc_mcontext.
43 #if (!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \ 46 #elif(!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \
44 && !defined(__OpenBSD__) 47 && !defined(__OpenBSD__)
45 #include <ucontext.h> 48 #include <ucontext.h>
46 #endif 49 #endif
47 #include <unistd.h> 50 #include <unistd.h>
48 51
49 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'. 52 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
50 // Old versions of the C library <signal.h> didn't define the type. 53 // Old versions of the C library <signal.h> didn't define the type.
51 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \ 54 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
52 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) 55 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
53 #include <asm/sigcontext.h> 56 #include <asm/sigcontext.h>
54 #endif 57 #endif
55 58
56 #elif defined(__MACH__)
57
58 #include <mach/mach.h>
59
60 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) 59 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
61 60
62 #include "win32-headers.h" 61 #include "win32-headers.h"
63 62
64 #endif 63 #endif
65 64
66 #include "v8.h" 65 #include "v8.h"
67 66
68 #include "cpu-profiler-inl.h" 67 #include "cpu-profiler-inl.h"
69 #include "flags.h" 68 #include "flags.h"
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 ThreadId profiled_thread_id_; 166 ThreadId profiled_thread_id_;
168 }; 167 };
169 168
170 } // namespace 169 } // namespace
171 170
172 #if defined(USE_SIGNALS) 171 #if defined(USE_SIGNALS)
173 172
174 class Sampler::PlatformData : public PlatformDataCommon { 173 class Sampler::PlatformData : public PlatformDataCommon {
175 public: 174 public:
176 PlatformData() : vm_tid_(pthread_self()) {} 175 PlatformData() : vm_tid_(pthread_self()) {}
177 176 pthread_t vm_tid() const { return vm_tid_; }
178 void SendProfilingSignal() const;
179 177
180 private: 178 private:
181 pthread_t vm_tid_; 179 pthread_t vm_tid_;
182 }; 180 };
183 181
184 #elif defined(__MACH__)
185
186 class Sampler::PlatformData : public PlatformDataCommon {
187 public:
188 PlatformData() : profiled_thread_(mach_thread_self()) {}
189
190 ~PlatformData() {
191 // Deallocate Mach port for thread.
192 mach_port_deallocate(mach_task_self(), profiled_thread_);
193 }
194
195 thread_act_t profiled_thread() { return profiled_thread_; }
196
197 private:
198 // Note: for profiled_thread_ Mach primitives are used instead of PThread's
199 // because the latter doesn't provide thread manipulation primitives required.
200 // For details, consult "Mac OS X Internals" book, Section 7.3.
201 thread_act_t profiled_thread_;
202 };
203
204 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) 182 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
205 183
206 // ---------------------------------------------------------------------------- 184 // ----------------------------------------------------------------------------
207 // Win32 profiler support. On Cygwin we use the same sampler implementation as 185 // Win32 profiler support. On Cygwin we use the same sampler implementation as
208 // on Win32. 186 // on Win32.
209 187
210 class Sampler::PlatformData : public PlatformDataCommon { 188 class Sampler::PlatformData : public PlatformDataCommon {
211 public: 189 public:
212 // Get a handle to the calling thread. This is the thread that we are 190 // Get a handle to the calling thread. This is the thread that we are
213 // going to profile. We need to make a copy of the handle because we are 191 // going to profile. We need to make a copy of the handle because we are
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 state.pc = reinterpret_cast<Address>(mcontext.arm_pc); 336 state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
359 state.sp = reinterpret_cast<Address>(mcontext.arm_sp); 337 state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
360 state.fp = reinterpret_cast<Address>(mcontext.arm_fp); 338 state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
361 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) && 339 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
362 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 340 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
363 #elif V8_HOST_ARCH_MIPS 341 #elif V8_HOST_ARCH_MIPS
364 state.pc = reinterpret_cast<Address>(mcontext.pc); 342 state.pc = reinterpret_cast<Address>(mcontext.pc);
365 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); 343 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
366 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); 344 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
367 #endif // V8_HOST_ARCH_* 345 #endif // V8_HOST_ARCH_*
346 #elif defined(__MACH__)
347 #if V8_HOST_ARCH_X64
348 #if __DARWIN_UNIX03
349 state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
350 state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
351 state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
352 #else // !__DARWIN_UNIX03
353 state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
354 state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
355 state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
356 #endif // __DARWIN_UNIX03
357 #elif V8_HOST_ARCH_IA32
358 #if __DARWIN_UNIX03
359 state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
360 state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
361 state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
362 #else // !__DARWIN_UNIX03
363 state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
364 state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
365 state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
366 #endif // __DARWIN_UNIX03
367 #endif // V8_HOST_ARCH_IA32
368 #elif defined(__FreeBSD__) 368 #elif defined(__FreeBSD__)
369 #if V8_HOST_ARCH_IA32 369 #if V8_HOST_ARCH_IA32
370 state.pc = reinterpret_cast<Address>(mcontext.mc_eip); 370 state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
371 state.sp = reinterpret_cast<Address>(mcontext.mc_esp); 371 state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
372 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp); 372 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
373 #elif V8_HOST_ARCH_X64 373 #elif V8_HOST_ARCH_X64
374 state.pc = reinterpret_cast<Address>(mcontext.mc_rip); 374 state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
375 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp); 375 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
376 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp); 376 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
377 #elif V8_HOST_ARCH_ARM 377 #elif V8_HOST_ARCH_ARM
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 while (true) { 475 while (true) {
476 { 476 {
477 ScopedLock lock(mutex_); 477 ScopedLock lock(mutex_);
478 if (active_samplers_.is_empty()) break; 478 if (active_samplers_.is_empty()) break;
479 // When CPU profiling is enabled both JavaScript and C++ code is 479 // When CPU profiling is enabled both JavaScript and C++ code is
480 // profiled. We must not suspend. 480 // profiled. We must not suspend.
481 for (int i = 0; i < active_samplers_.length(); ++i) { 481 for (int i = 0; i < active_samplers_.length(); ++i) {
482 Sampler* sampler = active_samplers_.at(i); 482 Sampler* sampler = active_samplers_.at(i);
483 if (!sampler->isolate()->IsInitialized()) continue; 483 if (!sampler->isolate()->IsInitialized()) continue;
484 if (!sampler->IsProfiling()) continue; 484 if (!sampler->IsProfiling()) continue;
485 SampleContext(sampler); 485 sampler->DoSample();
486 } 486 }
487 } 487 }
488 OS::Sleep(interval_); 488 OS::Sleep(interval_);
489 } 489 }
490 } 490 }
491 491
492 private: 492 private:
493 #if defined(USE_SIGNALS)
494
495 void SampleContext(Sampler* sampler) {
496 sampler->platform_data()->SendProfilingSignal();
497 }
498
499 #elif defined(__MACH__)
500
501 void SampleContext(Sampler* sampler) {
502 thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
503
504 #if defined(USE_SIMULATOR)
505 SimulatorHelper helper;
506 Isolate* isolate = sampler->isolate();
507 if (!helper.Init(sampler, isolate)) return;
508 #endif
509
510 if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
511
512 #if V8_HOST_ARCH_X64
513 thread_state_flavor_t flavor = x86_THREAD_STATE64;
514 x86_thread_state64_t thread_state;
515 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
516 #if __DARWIN_UNIX03
517 #define REGISTER_FIELD(name) __r ## name
518 #else
519 #define REGISTER_FIELD(name) r ## name
520 #endif // __DARWIN_UNIX03
521 #elif V8_HOST_ARCH_IA32
522 thread_state_flavor_t flavor = i386_THREAD_STATE;
523 i386_thread_state_t thread_state;
524 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
525 #if __DARWIN_UNIX03
526 #define REGISTER_FIELD(name) __e ## name
527 #else
528 #define REGISTER_FIELD(name) e ## name
529 #endif // __DARWIN_UNIX03
530 #else
531 #error Unsupported Mac OS X host architecture.
532 #endif // V8_HOST_ARCH
533
534 if (thread_get_state(profiled_thread,
535 flavor,
536 reinterpret_cast<natural_t*>(&thread_state),
537 &count) == KERN_SUCCESS) {
538 RegisterState state;
539 #if defined(USE_SIMULATOR)
540 helper.FillRegisters(&state);
541 #else
542 state.pc = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(ip));
543 state.sp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(sp));
544 state.fp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(bp));
545 #endif // USE_SIMULATOR
546 #undef REGISTER_FIELD
547 sampler->SampleStack(state);
548 }
549 thread_resume(profiled_thread);
550 }
551
552 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
553
554 void SampleContext(Sampler* sampler) {
555 HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
556 if (profiled_thread == NULL) return;
557
558 Isolate* isolate = sampler->isolate();
559 #if defined(USE_SIMULATOR)
560 SimulatorHelper helper;
561 if (!helper.Init(sampler, isolate)) return;
562 #endif
563
564 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
565 if (SuspendThread(profiled_thread) == kSuspendFailed) return;
566
567 // Context used for sampling the register state of the profiled thread.
568 CONTEXT context;
569 memset(&context, 0, sizeof(context));
570 context.ContextFlags = CONTEXT_FULL;
571 if (GetThreadContext(profiled_thread, &context) != 0) {
572 RegisterState state;
573 #if defined(USE_SIMULATOR)
574 helper.FillRegisters(&state);
575 #else
576 #if V8_HOST_ARCH_X64
577 state.pc = reinterpret_cast<Address>(context.Rip);
578 state.sp = reinterpret_cast<Address>(context.Rsp);
579 state.fp = reinterpret_cast<Address>(context.Rbp);
580 #else
581 state.pc = reinterpret_cast<Address>(context.Eip);
582 state.sp = reinterpret_cast<Address>(context.Esp);
583 state.fp = reinterpret_cast<Address>(context.Ebp);
584 #endif
585 #endif // USE_SIMULATOR
586 sampler->SampleStack(state);
587 }
588 ResumeThread(profiled_thread);
589 }
590
591 #endif // USE_SIGNALS
592
593
594 // Protects the process wide state below. 493 // Protects the process wide state below.
595 static Mutex* mutex_; 494 static Mutex* mutex_;
596 static SamplerThread* instance_; 495 static SamplerThread* instance_;
597 496
598 const int interval_; 497 const int interval_;
599 List<Sampler*> active_samplers_; 498 List<Sampler*> active_samplers_;
600 499
601 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 500 DISALLOW_COPY_AND_ASSIGN(SamplerThread);
602 }; 501 };
603 502
604 503
605 Mutex* SamplerThread::mutex_ = NULL; 504 Mutex* SamplerThread::mutex_ = NULL;
606 SamplerThread* SamplerThread::instance_ = NULL; 505 SamplerThread* SamplerThread::instance_ = NULL;
607 506
608 507
609 #if defined(USE_SIGNALS)
610 void Sampler::PlatformData::SendProfilingSignal() const {
611 if (!SignalHandler::Installed()) return;
612 pthread_kill(vm_tid_, SIGPROF);
613 }
614 #endif
615
616
617 // 508 //
618 // StackTracer implementation 509 // StackTracer implementation
619 // 510 //
620 DISABLE_ASAN void TickSample::Init(Isolate* isolate, 511 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
621 const RegisterState& regs) { 512 const RegisterState& regs) {
622 ASSERT(isolate->IsInitialized()); 513 ASSERT(isolate->IsInitialized());
623 pc = regs.pc; 514 pc = regs.pc;
624 state = isolate->current_vm_state(); 515 state = isolate->current_vm_state();
625 516
626 // Avoid collecting traces while doing GC. 517 // Avoid collecting traces while doing GC.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
719 610
720 bool Sampler::CanSampleOnProfilerEventsProcessorThread() { 611 bool Sampler::CanSampleOnProfilerEventsProcessorThread() {
721 #if defined(USE_SIGNALS) 612 #if defined(USE_SIGNALS)
722 return true; 613 return true;
723 #else 614 #else
724 return false; 615 return false;
725 #endif 616 #endif
726 } 617 }
727 618
728 619
620 #if defined(USE_SIGNALS)
621
729 void Sampler::DoSample() { 622 void Sampler::DoSample() {
730 #if defined(USE_SIGNALS) 623 if (!SignalHandler::Installed()) return;
731 platform_data()->SendProfilingSignal(); 624 pthread_kill(platform_data()->vm_tid(), SIGPROF);
732 #endif
733 } 625 }
734 626
627 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
628
629 void Sampler::DoSample() {
630 HANDLE profiled_thread = platform_data()->profiled_thread();
631 if (profiled_thread == NULL) return;
632
633 #if defined(USE_SIMULATOR)
634 SimulatorHelper helper;
635 if (!helper.Init(this, isolate())) return;
636 #endif
637
638 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
639 if (SuspendThread(profiled_thread) == kSuspendFailed) return;
640
641 // Context used for sampling the register state of the profiled thread.
642 CONTEXT context;
643 memset(&context, 0, sizeof(context));
644 context.ContextFlags = CONTEXT_FULL;
645 if (GetThreadContext(profiled_thread, &context) != 0) {
646 RegisterState state;
647 #if defined(USE_SIMULATOR)
648 helper.FillRegisters(&state);
649 #else
650 #if V8_HOST_ARCH_X64
651 state.pc = reinterpret_cast<Address>(context.Rip);
652 state.sp = reinterpret_cast<Address>(context.Rsp);
653 state.fp = reinterpret_cast<Address>(context.Rbp);
654 #else
655 state.pc = reinterpret_cast<Address>(context.Eip);
656 state.sp = reinterpret_cast<Address>(context.Esp);
657 state.fp = reinterpret_cast<Address>(context.Ebp);
658 #endif
659 #endif // USE_SIMULATOR
660 SampleStack(state);
661 }
662 ResumeThread(profiled_thread);
663 }
664
665 #endif // USE_SIGNALS
666
667
735 } } // namespace v8::internal 668 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/cpu-profiler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698