LCOV - app.info - tools/profiler/platform-linux.cc

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-04-21 | 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