LCOV - code coverage report
Current view: directory - tools/profiler - platform-linux.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 80 0 0.0 %
Date: 2012-06-02 Functions: 12 0 0.0 %

       1                 : // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
       2                 : // Use of this source code is governed by a BSD-style license that can be
       3                 : // found in the LICENSE file.
       4                 : 
       5                 : /*
       6                 : # vim: sw=2
       7                 : */
       8                 : #include <stdio.h>
       9                 : 
      10                 : #include <pthread.h>
      11                 : #include <semaphore.h>
      12                 : #include <signal.h>
      13                 : #include <sys/time.h>
      14                 : #include <sys/resource.h>
      15                 : #include <sys/syscall.h>
      16                 : #include <sys/types.h>
      17                 : #include <stdlib.h>
      18                 : #ifdef ANDROID
      19                 : #include <android/log.h>
      20                 : #else
      21                 : #define __android_log_print(a, ...)
      22                 : #endif
      23                 : // Ubuntu Dapper requires memory pages to be marked as
      24                 : // executable. Otherwise, OS raises an exception when executing code
      25                 : // in that page.
      26                 : #include <sys/types.h>  // mmap & munmap
      27                 : #include <sys/mman.h>   // mmap & munmap
      28                 : #include <sys/stat.h>   // open
      29                 : #include <fcntl.h>      // open
      30                 : #include <unistd.h>     // sysconf
      31                 : #ifdef __GLIBC__
      32                 : #include <execinfo.h>   // backtrace, backtrace_symbols
      33                 : #endif  // def __GLIBC__
      34                 : #include <strings.h>    // index
      35                 : #include <errno.h>
      36                 : #include <stdarg.h>
      37                 : #include "platform.h"
      38                 : 
      39                 : #include <string.h>
      40                 : #include <stdio.h>
      41                 : 
      42                 : #define SIGNAL_SAVE_PROFILE SIGUSR2
      43                 : 
      44                 : #if defined(__GLIBC__)
      45                 : // glibc doesn't implement gettid(2).
      46                 : #include <sys/syscall.h>
      47               0 : pid_t gettid()
      48                 : {
      49               0 :   return (pid_t) syscall(SYS_gettid);
      50                 : }
      51                 : #endif
      52                 : 
      53                 : static Sampler* sActiveSampler = NULL;
      54                 : 
      55                 : 
      56                 : #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
      57                 : // Android runs a fairly new Linux kernel, so signal info is there,
      58                 : // but the C library doesn't have the structs defined.
      59                 : 
      60                 : struct sigcontext {
      61                 :   uint32_t trap_no;
      62                 :   uint32_t error_code;
      63                 :   uint32_t oldmask;
      64                 :   uint32_t gregs[16];
      65                 :   uint32_t arm_cpsr;
      66                 :   uint32_t fault_address;
      67                 : };
      68                 : typedef uint32_t __sigset_t;
      69                 : typedef struct sigcontext mcontext_t;
      70                 : typedef struct ucontext {
      71                 :   uint32_t uc_flags;
      72                 :   struct ucontext* uc_link;
      73                 :   stack_t uc_stack;
      74                 :   mcontext_t uc_mcontext;
      75                 :   __sigset_t uc_sigmask;
      76                 : } ucontext_t;
      77                 : enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
      78                 : 
      79                 : #endif
      80                 : 
      81               0 : static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context) {
      82               0 :   sActiveSampler->RequestSave();
      83               0 : }
      84                 : 
      85                 : #ifdef ANDROID
      86                 : #define V8_HOST_ARCH_ARM 1
      87                 : #define SYS_gettid __NR_gettid
      88                 : #define SYS_tgkill __NR_tgkill
      89                 : #else
      90                 : #define V8_HOST_ARCH_X64 1
      91                 : #endif
      92               0 : static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
      93               0 :   if (!sActiveSampler)
      94               0 :     return;
      95                 : 
      96               0 :   TickSample sample_obj;
      97               0 :   TickSample* sample = &sample_obj;
      98               0 :   sample->pc = 0;
      99                 : 
     100                 : #ifdef ENABLE_SPS_LEAF_DATA
     101                 :   // If profiling, we extract the current pc and sp.
     102                 :   if (sActiveSampler->IsProfiling()) {
     103                 :     // Extracting the sample from the context is extremely machine dependent.
     104                 :     ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
     105                 :     mcontext_t& mcontext = ucontext->uc_mcontext;
     106                 : #if V8_HOST_ARCH_IA32
     107                 :     sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
     108                 :     sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
     109                 :     sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
     110                 : #elif V8_HOST_ARCH_X64
     111                 :     sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
     112                 :     sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
     113                 :     sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
     114                 : #elif V8_HOST_ARCH_ARM
     115                 : // An undefined macro evaluates to 0, so this applies to Android's Bionic also.
     116                 : #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
     117                 :     sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
     118                 :     sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
     119                 :     sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
     120                 : #else
     121                 :     sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
     122                 :     sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
     123                 :     sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
     124                 : #endif
     125                 : #elif V8_HOST_ARCH_MIPS
     126                 :     // Implement this on MIPS.
     127                 :     UNIMPLEMENTED();
     128                 : #endif
     129                 :   }
     130                 : #endif
     131               0 :   sample->timestamp = mozilla::TimeStamp::Now();
     132                 : 
     133               0 :   sActiveSampler->Tick(sample);
     134                 : }
     135                 : 
     136                 : #ifndef XP_MACOSX
     137               0 : void tgkill(pid_t tgid, pid_t tid, int signalno) {
     138               0 :   syscall(SYS_tgkill, tgid, tid, signalno);
     139               0 : }
     140                 : #endif
     141                 : 
     142                 : class Sampler::PlatformData : public Malloced {
     143                 :  public:
     144               0 :   explicit PlatformData(Sampler* sampler)
     145                 :       : sampler_(sampler),
     146                 :         signal_handler_installed_(false),
     147               0 :         vm_tgid_(getpid()),
     148                 : #ifndef XP_MACOSX
     149               0 :         vm_tid_(gettid()),
     150                 : #endif
     151               0 :         signal_sender_launched_(false)
     152                 : #ifdef XP_MACOSX
     153                 :         , signal_receiver_(pthread_self())
     154                 : #endif
     155                 :   {
     156               0 :   }
     157                 : 
     158               0 :   void SignalSender() {
     159               0 :     while (sampler_->IsActive()) {
     160               0 :       sampler_->HandleSaveRequest();
     161                 : 
     162                 : #ifdef XP_MACOSX
     163                 :       pthread_kill(signal_receiver_, SIGPROF);
     164                 : #else
     165                 :       // Glibc doesn't provide a wrapper for tgkill(2).
     166               0 :       tgkill(vm_tgid_, vm_tid_, SIGPROF);
     167                 : #endif
     168                 :       // Convert ms to us and subtract 100 us to compensate delays
     169                 :       // occuring during signal delivery.
     170                 : 
     171                 :       // TODO measure and confirm this.
     172               0 :       const useconds_t interval = sampler_->interval_ * 1000 - 100;
     173                 :       //int result = usleep(interval);
     174               0 :       usleep(interval);
     175                 :       // sometimes usleep is defined as returning void
     176               0 :       int result = 0;
     177                 : #ifdef DEBUG
     178               0 :       if (result != 0 && errno != EINTR) {
     179               0 :         LOG("SignalSender usleep error");
     180               0 :         ASSERT(result == 0 || errno == EINTR);
     181                 :       }
     182                 : #endif
     183               0 :       mozilla::unused << result;
     184                 :     }
     185               0 :   }
     186                 : 
     187                 :   Sampler* sampler_;
     188                 :   bool signal_handler_installed_;
     189                 :   struct sigaction old_sigprof_signal_handler_;
     190                 :   struct sigaction old_sigsave_signal_handler_;
     191                 :   pid_t vm_tgid_;
     192                 :   pid_t vm_tid_;
     193                 :   bool signal_sender_launched_;
     194                 :   pthread_t signal_sender_thread_;
     195                 : #ifdef XP_MACOSX
     196                 :   pthread_t signal_receiver_;
     197                 : #endif
     198                 : };
     199                 : 
     200                 : 
     201               0 : static void* SenderEntry(void* arg) {
     202                 :   Sampler::PlatformData* data =
     203               0 :       reinterpret_cast<Sampler::PlatformData*>(arg);
     204               0 :   data->SignalSender();
     205               0 :   return 0;
     206                 : }
     207                 : 
     208                 : 
     209               0 : Sampler::Sampler(int interval, bool profiling)
     210                 :     : interval_(interval),
     211                 :       profiling_(profiling),
     212               0 :       active_(false) {
     213               0 :   data_ = new PlatformData(this);
     214               0 : }
     215                 : 
     216               0 : Sampler::~Sampler() {
     217               0 :   ASSERT(!data_->signal_sender_launched_);
     218               0 :   delete data_;
     219               0 : }
     220                 : 
     221                 : 
     222               0 : void Sampler::Start() {
     223               0 :   LOG("Sampler Started");
     224               0 :   if (sActiveSampler != NULL) return;
     225                 : 
     226                 :   // Request profiling signals.
     227               0 :   LOG("Request signal");
     228                 :   struct sigaction sa;
     229               0 :   sa.sa_sigaction = ProfilerSignalHandler;
     230               0 :   sigemptyset(&sa.sa_mask);
     231               0 :   sa.sa_flags = SA_RESTART | SA_SIGINFO;
     232               0 :   if (sigaction(SIGPROF, &sa, &data_->old_sigprof_signal_handler_) != 0) {
     233               0 :     LOG("Error installing signal");
     234               0 :     return;
     235                 :   }
     236                 : 
     237                 :   // Request save profile signals
     238                 :   struct sigaction sa2;
     239               0 :   sa2.sa_sigaction = ProfilerSaveSignalHandler;
     240               0 :   sigemptyset(&sa2.sa_mask);
     241               0 :   sa2.sa_flags = SA_RESTART | SA_SIGINFO;
     242               0 :   if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &data_->old_sigsave_signal_handler_) != 0) {
     243               0 :     LOG("Error installing start signal");
     244               0 :     return;
     245                 :   }
     246               0 :   LOG("Signal installed");
     247               0 :   data_->signal_handler_installed_ = true;
     248                 : 
     249                 :   // Start a thread that sends SIGPROF signal to VM thread.
     250                 :   // Sending the signal ourselves instead of relying on itimer provides
     251                 :   // much better accuracy.
     252               0 :   SetActive(true);
     253               0 :   if (pthread_create(
     254               0 :           &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
     255               0 :     data_->signal_sender_launched_ = true;
     256                 :   }
     257               0 :   LOG("Profiler thread started");
     258                 : 
     259                 :   // Set this sampler as the active sampler.
     260               0 :   sActiveSampler = this;
     261                 : }
     262                 : 
     263                 : 
     264               0 : void Sampler::Stop() {
     265               0 :   SetActive(false);
     266                 : 
     267                 :   // Wait for signal sender termination (it will exit after setting
     268                 :   // active_ to false).
     269               0 :   if (data_->signal_sender_launched_) {
     270               0 :     pthread_join(data_->signal_sender_thread_, NULL);
     271               0 :     data_->signal_sender_launched_ = false;
     272                 :   }
     273                 : 
     274                 :   // Restore old signal handler
     275               0 :   if (data_->signal_handler_installed_) {
     276               0 :     sigaction(SIGPROF, &data_->old_sigsave_signal_handler_, 0);
     277               0 :     sigaction(SIGPROF, &data_->old_sigprof_signal_handler_, 0);
     278               0 :     data_->signal_handler_installed_ = false;
     279                 :   }
     280                 : 
     281                 :   // This sampler is no longer the active sampler.
     282               0 :   sActiveSampler = NULL;
     283               0 : }
     284                 : 

Generated by: LCOV version 1.7