OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 20 matching lines...) Expand all Loading... |
31 #include <ucontext.h> | 31 #include <ucontext.h> |
32 #include <unistd.h> | 32 #include <unistd.h> |
33 #include <sys/mman.h> | 33 #include <sys/mman.h> |
34 #include <mach/mach_init.h> | 34 #include <mach/mach_init.h> |
35 | 35 |
36 #include <AvailabilityMacros.h> | 36 #include <AvailabilityMacros.h> |
37 | 37 |
38 #include <pthread.h> | 38 #include <pthread.h> |
39 #include <semaphore.h> | 39 #include <semaphore.h> |
40 #include <signal.h> | 40 #include <signal.h> |
| 41 #include <mach/mach.h> |
41 #include <mach/semaphore.h> | 42 #include <mach/semaphore.h> |
42 #include <mach/task.h> | 43 #include <mach/task.h> |
43 #include <sys/time.h> | 44 #include <sys/time.h> |
44 #include <sys/resource.h> | 45 #include <sys/resource.h> |
45 #include <sys/types.h> | 46 #include <sys/types.h> |
46 #include <stdarg.h> | 47 #include <stdarg.h> |
47 #include <stdlib.h> | 48 #include <stdlib.h> |
48 | 49 |
49 #include <errno.h> | 50 #include <errno.h> |
50 | 51 |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 } | 469 } |
469 | 470 |
470 | 471 |
471 Semaphore* OS::CreateSemaphore(int count) { | 472 Semaphore* OS::CreateSemaphore(int count) { |
472 return new MacOSSemaphore(count); | 473 return new MacOSSemaphore(count); |
473 } | 474 } |
474 | 475 |
475 | 476 |
476 #ifdef ENABLE_LOGGING_AND_PROFILING | 477 #ifdef ENABLE_LOGGING_AND_PROFILING |
477 | 478 |
478 static Sampler* active_sampler_ = NULL; | 479 class Sampler::PlatformData : public Malloced { |
| 480 public: |
| 481 explicit PlatformData(Sampler* sampler) |
| 482 : sampler_(sampler), |
| 483 task_self_(mach_task_self()), |
| 484 profiled_thread_(0), |
| 485 sampler_thread_(0) { |
| 486 } |
479 | 487 |
480 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 488 Sampler* sampler_; |
481 USE(info); | 489 // Note: for profiled_thread_ Mach primitives are used instead of PThread's |
482 if (signal != SIGPROF) return; | 490 // because the latter doesn't provide thread manipulation primitives required. |
483 if (active_sampler_ == NULL) return; | 491 // For details, consult "Mac OS X Internals" book, Section 7.3. |
| 492 mach_port_t task_self_; |
| 493 thread_act_t profiled_thread_; |
| 494 pthread_t sampler_thread_; |
484 | 495 |
485 TickSample sample; | 496 // Sampler thread handler. |
| 497 void Runner() { |
| 498 // Loop until the sampler is disengaged. |
| 499 while (sampler_->IsActive()) { |
| 500 TickSample sample; |
486 | 501 |
487 // If profiling, we extract the current pc and sp. | 502 // If profiling, we record the pc and sp of the profiled thread. |
488 if (active_sampler_->IsProfiling()) { | 503 if (sampler_->IsProfiling() |
489 // Extracting the sample from the context is extremely machine dependent. | 504 && KERN_SUCCESS == thread_suspend(profiled_thread_)) { |
490 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
491 mcontext_t& mcontext = ucontext->uc_mcontext; | |
492 #if V8_HOST_ARCH_X64 | 505 #if V8_HOST_ARCH_X64 |
493 UNIMPLEMENTED(); | 506 thread_state_flavor_t flavor = x86_THREAD_STATE64; |
494 USE(mcontext); | 507 x86_thread_state64_t state; |
495 sample.pc = 0; | 508 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; |
496 sample.sp = 0; | 509 #elif V8_HOST_ARCH_IA32 |
497 sample.fp = 0; | 510 thread_state_flavor_t flavor = i386_THREAD_STATE; |
| 511 i386_thread_state_t state; |
| 512 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; |
| 513 #else |
| 514 #error Unsupported Mac OS X host architecture. |
| 515 #endif // V8_TARGET_ARCH_IA32 |
| 516 if (KERN_SUCCESS == thread_get_state(profiled_thread_, |
| 517 flavor, |
| 518 (natural_t*)&state, |
| 519 &count)) { |
| 520 #if V8_HOST_ARCH_X64 |
| 521 UNIMPLEMENTED(); |
| 522 sample.pc = 0; |
| 523 sample.sp = 0; |
| 524 sample.fp = 0; |
498 #elif V8_HOST_ARCH_IA32 | 525 #elif V8_HOST_ARCH_IA32 |
499 #if __DARWIN_UNIX03 | 526 #if __DARWIN_UNIX03 |
500 sample.pc = mcontext->__ss.__eip; | 527 sample.pc = state.__eip; |
501 sample.sp = mcontext->__ss.__esp; | 528 sample.sp = state.__esp; |
502 sample.fp = mcontext->__ss.__ebp; | 529 sample.fp = state.__ebp; |
503 #else // !__DARWIN_UNIX03 | 530 #else // !__DARWIN_UNIX03 |
504 sample.pc = mcontext->ss.eip; | 531 sample.pc = state.eip; |
505 sample.sp = mcontext->ss.esp; | 532 sample.sp = state.esp; |
506 sample.fp = mcontext->ss.ebp; | 533 sample.fp = state.ebp; |
507 #endif // __DARWIN_UNIX03 | 534 #endif // __DARWIN_UNIX03 |
508 #else | 535 #else |
509 #error Unsupported Mac OS X host architecture. | 536 #error Unsupported Mac OS X host architecture. |
510 #endif // V8_HOST_ARCH_IA32 | 537 #endif // V8_HOST_ARCH_IA32 |
| 538 sampler_->SampleStack(&sample); |
| 539 } |
| 540 thread_resume(profiled_thread_); |
| 541 } |
| 542 |
| 543 // We always sample the VM state. |
| 544 sample.state = Logger::state(); |
| 545 // Invoke tick handler with program counter and stack pointer. |
| 546 sampler_->Tick(&sample); |
| 547 |
| 548 // Wait until next sampling. |
| 549 usleep(sampler_->interval_ * 1000); |
| 550 } |
511 } | 551 } |
512 | 552 }; |
513 // We always sample the VM state. | |
514 sample.state = Logger::state(); | |
515 | |
516 active_sampler_->Tick(&sample); | |
517 } | |
518 | 553 |
519 | 554 |
520 class Sampler::PlatformData : public Malloced { | 555 // Entry point for sampler thread. |
521 public: | 556 static void* SamplerEntry(void* arg) { |
522 PlatformData() { | 557 Sampler::PlatformData* data = |
523 signal_handler_installed_ = false; | 558 reinterpret_cast<Sampler::PlatformData*>(arg); |
524 } | 559 data->Runner(); |
525 | 560 return 0; |
526 bool signal_handler_installed_; | 561 } |
527 struct sigaction old_signal_handler_; | |
528 struct itimerval old_timer_value_; | |
529 }; | |
530 | 562 |
531 | 563 |
532 Sampler::Sampler(int interval, bool profiling) | 564 Sampler::Sampler(int interval, bool profiling) |
533 : interval_(interval), profiling_(profiling), active_(false) { | 565 : interval_(interval), profiling_(profiling), active_(false) { |
534 data_ = new PlatformData(); | 566 data_ = new PlatformData(this); |
535 } | 567 } |
536 | 568 |
537 | 569 |
538 Sampler::~Sampler() { | 570 Sampler::~Sampler() { |
539 delete data_; | 571 delete data_; |
540 } | 572 } |
541 | 573 |
542 | 574 |
543 void Sampler::Start() { | 575 void Sampler::Start() { |
544 // There can only be one active sampler at the time on POSIX | 576 // If we are profiling, we need to be able to access the calling |
545 // platforms. | 577 // thread. |
546 if (active_sampler_ != NULL) return; | 578 if (IsProfiling()) { |
| 579 data_->profiled_thread_ = mach_thread_self(); |
| 580 } |
547 | 581 |
548 // Request profiling signals. | 582 // Create sampler thread with high priority. |
549 struct sigaction sa; | 583 // According to POSIX spec, when SCHED_FIFO policy is used, a thread |
550 sa.sa_sigaction = ProfilerSignalHandler; | 584 // runs until it exits or blocks. |
551 sigemptyset(&sa.sa_mask); | 585 pthread_attr_t sched_attr; |
552 sa.sa_flags = SA_SIGINFO; | 586 sched_param fifo_param; |
553 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | 587 pthread_attr_init(&sched_attr); |
554 data_->signal_handler_installed_ = true; | 588 pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED); |
| 589 pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO); |
| 590 fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO); |
| 591 pthread_attr_setschedparam(&sched_attr, &fifo_param); |
555 | 592 |
556 // Set the itimer to generate a tick for each interval. | |
557 itimerval itimer; | |
558 itimer.it_interval.tv_sec = interval_ / 1000; | |
559 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | |
560 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | |
561 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | |
562 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | |
563 | |
564 // Set this sampler as the active sampler. | |
565 active_sampler_ = this; | |
566 active_ = true; | 593 active_ = true; |
| 594 pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry, data_); |
567 } | 595 } |
568 | 596 |
569 | 597 |
570 void Sampler::Stop() { | 598 void Sampler::Stop() { |
571 // Restore old signal handler | 599 // Seting active to false triggers termination of the sampler |
572 if (data_->signal_handler_installed_) { | 600 // thread. |
573 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); | 601 active_ = false; |
574 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | 602 |
575 data_->signal_handler_installed_ = false; | 603 // Wait for sampler thread to terminate. |
| 604 pthread_join(data_->sampler_thread_, NULL); |
| 605 |
| 606 // Deallocate Mach port for thread. |
| 607 if (IsProfiling()) { |
| 608 mach_port_deallocate(data_->task_self_, data_->profiled_thread_); |
576 } | 609 } |
577 | |
578 // This sampler is no longer the active sampler. | |
579 active_sampler_ = NULL; | |
580 active_ = false; | |
581 } | 610 } |
582 | 611 |
583 #endif // ENABLE_LOGGING_AND_PROFILING | 612 #endif // ENABLE_LOGGING_AND_PROFILING |
584 | 613 |
585 } } // namespace v8::internal | 614 } } // namespace v8::internal |
OLD | NEW |