LCOV - code coverage report
Current view: directory - tools/profiler - sps_sampler.h (source / functions) Found Hit Coverage
Test: app.info Lines: 13 3 23.1 %
Date: 2012-06-02 Functions: 3 1 33.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Mozilla Foundation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Benoit Girard <bgirard@mozilla.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include <stdlib.h>
      40                 : #include <signal.h>
      41                 : #include "thread_helper.h"
      42                 : #include "nscore.h"
      43                 : #include "jsapi.h"
      44                 : #include "mozilla/TimeStamp.h"
      45                 : 
      46                 : using mozilla::TimeStamp;
      47                 : using mozilla::TimeDuration;
      48                 : 
      49                 : extern mozilla::tls::key pkey_stack;
      50                 : extern mozilla::tls::key pkey_ticker;
      51                 : extern bool stack_key_initialized;
      52                 : 
      53                 : #ifndef SAMPLE_FUNCTION_NAME
      54                 : # ifdef __GNUC__
      55                 : #  define SAMPLE_FUNCTION_NAME __FUNCTION__
      56                 : # elif defined(_MSC_VER)
      57                 : #  define SAMPLE_FUNCTION_NAME __FUNCTION__
      58                 : # else
      59                 : #  define SAMPLE_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
      60                 : # endif
      61                 : #endif
      62                 : 
      63                 : #define SAMPLER_INIT() mozilla_sampler_init()
      64                 : #define SAMPLER_DEINIT() mozilla_sampler_deinit()
      65                 : #define SAMPLER_START(entries, interval, features, featureCount) mozilla_sampler_start(entries, interval, features, featureCount)
      66                 : #define SAMPLER_STOP() mozilla_sampler_stop()
      67                 : #define SAMPLER_IS_ACTIVE() mozilla_sampler_is_active()
      68                 : #define SAMPLER_RESPONSIVENESS(time) mozilla_sampler_responsiveness(time)
      69                 : #define SAMPLER_GET_RESPONSIVENESS() mozilla_sampler_get_responsiveness()
      70                 : #define SAMPLER_SAVE() mozilla_sampler_save()
      71                 : #define SAMPLER_GET_PROFILE() mozilla_sampler_get_profile()
      72                 : #define SAMPLER_GET_PROFILE_DATA(ctx) mozilla_sampler_get_profile_data(ctx)
      73                 : #define SAMPLER_GET_FEATURES() mozilla_sampler_get_features()
      74                 : // we want the class and function name but can't easily get that using preprocessor macros
      75                 : // __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
      76                 : #define SAMPLE_LABEL(name_space, info) mozilla::SamplerStackFrameRAII only_one_sampleraii_per_scope(name_space "::" info)
      77                 : #define SAMPLE_MARKER(info) mozilla_sampler_add_marker(info)
      78                 : 
      79                 : /* we duplicate this code here to avoid header dependencies
      80                 :  * which make it more difficult to include in other places */
      81                 : #if defined(_M_X64) || defined(__x86_64__)
      82                 : #define V8_HOST_ARCH_X64 1
      83                 : #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
      84                 : #define V8_HOST_ARCH_IA32 1
      85                 : #elif defined(__ARMEL__)
      86                 : #define V8_HOST_ARCH_ARM 1
      87                 : #else
      88                 : #warning Please add support for your architecture in chromium_types.h
      89                 : #endif
      90                 : 
      91                 : 
      92                 : // STORE_SEQUENCER: Because signals can interrupt our profile modification
      93                 : //                  we need to make stores are not re-ordered by the compiler
      94                 : //                  or hardware to make sure the profile is consistent at
      95                 : //                  every point the signal can fire.
      96                 : #ifdef V8_HOST_ARCH_ARM
      97                 : // TODO Is there something cheaper that will prevent
      98                 : //      memory stores from being reordered
      99                 : 
     100                 : typedef void (*LinuxKernelMemoryBarrierFunc)(void);
     101                 : LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
     102                 :     (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
     103                 : 
     104                 : # define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
     105                 : #elif defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
     106                 : # if defined(_MSC_VER)
     107                 :     // MSVC2005 has a name collision bug caused when both <intrin.h> and <winnt.h> are included together.
     108                 : #ifdef _WINNT_
     109                 : #  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
     110                 : #  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
     111                 : #  include <intrin.h>
     112                 : #else
     113                 : #  include <intrin.h>
     114                 : #  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
     115                 : #  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
     116                 : #endif
     117                 :    // Even though MSVC2005 has the intrinsic _ReadWriteBarrier, it fails to link to it when it's
     118                 :    // not explicitly declared.
     119                 : #  pragma intrinsic(_ReadWriteBarrier)
     120                 : #  define STORE_SEQUENCER() _ReadWriteBarrier();
     121                 : # elif defined(__INTEL_COMPILER)
     122                 : #  define STORE_SEQUENCER() __memory_barrier();
     123                 : # elif __GNUC__
     124                 : #  define STORE_SEQUENCER() asm volatile("" ::: "memory");
     125                 : # else
     126                 : #  error "Memory clobber not supported for your compiler."
     127                 : # endif
     128                 : #else
     129                 : # error "Memory clobber not supported for your platform."
     130                 : #endif
     131                 : 
     132                 : // Returns a handdle to pass on exit. This can check that we are popping the
     133                 : // correct callstack.
     134                 : inline void* mozilla_sampler_call_enter(const char *aInfo);
     135                 : inline void  mozilla_sampler_call_exit(void* handle);
     136                 : inline void  mozilla_sampler_add_marker(const char *aInfo);
     137                 : 
     138                 : void mozilla_sampler_start(int aEntries, int aInterval, const char** aFeatures, uint32_t aFeatureCount);
     139                 : void mozilla_sampler_stop();
     140                 : bool mozilla_sampler_is_active();
     141                 : void mozilla_sampler_responsiveness(TimeStamp time);
     142                 : const double* mozilla_sampler_get_responsiveness();
     143                 : void mozilla_sampler_save();
     144                 : char* mozilla_sampler_get_profile();
     145                 : JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
     146                 : const char** mozilla_sampler_get_features();
     147                 : void mozilla_sampler_init();
     148                 : 
     149                 : namespace mozilla {
     150                 : 
     151                 : class NS_STACK_CLASS SamplerStackFrameRAII {
     152                 : public:
     153                 :   // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
     154                 :   SamplerStackFrameRAII(const char *aInfo) {
     155                 :     mHandle = mozilla_sampler_call_enter(aInfo);
     156                 :   }
     157                 :   ~SamplerStackFrameRAII() {
     158                 :     mozilla_sampler_call_exit(mHandle);
     159                 :   }
     160                 : private:
     161                 :   void* mHandle;
     162                 : };
     163                 : 
     164                 : } //mozilla
     165                 : 
     166                 : // the SamplerStack members are read by signal
     167                 : // handlers, so the mutation of them needs to be signal-safe.
     168                 : struct ProfileStack
     169                 : {
     170                 : public:
     171              23 :   ProfileStack()
     172                 :     : mStackPointer(0)
     173                 :     , mMarkerPointer(0)
     174                 :     , mDroppedStackEntries(0)
     175              23 :     , mQueueClearMarker(false)
     176              23 :   { }
     177                 : 
     178                 :   void addMarker(const char *aMarker)
     179                 :   {
     180                 :     if (mQueueClearMarker) {
     181                 :       clearMarkers();
     182                 :     }
     183                 :     if (!aMarker) {
     184                 :       return; //discard
     185                 :     }
     186                 :     if (mMarkerPointer == 1024) {
     187                 :       return; //array full, silently drop
     188                 :     }
     189                 :     mMarkers[mMarkerPointer] = aMarker;
     190                 :     STORE_SEQUENCER();
     191                 :     mMarkerPointer++;
     192                 :   }
     193                 : 
     194                 :   // called within signal. Function must be reentrant
     195               0 :   const char* getMarker(int aMarkerId)
     196                 :   {
     197               0 :     if (mQueueClearMarker) {
     198               0 :       clearMarkers();
     199                 :     }
     200               0 :     if (aMarkerId >= mMarkerPointer) {
     201               0 :       return NULL;
     202                 :     }
     203               0 :     return mMarkers[aMarkerId];
     204                 :   }
     205                 : 
     206                 :   // called within signal. Function must be reentrant
     207               0 :   void clearMarkers()
     208                 :   {
     209               0 :     mMarkerPointer = 0;
     210               0 :     mQueueClearMarker = false;
     211               0 :   }
     212                 : 
     213                 :   void push(const char *aName)
     214                 :   {
     215                 :     if (mStackPointer >= 1024) {
     216                 :       mDroppedStackEntries++;
     217                 :       return;
     218                 :     }
     219                 : 
     220                 :     // Make sure we increment the pointer after the name has
     221                 :     // been written such that mStack is always consistent.
     222                 :     mStack[mStackPointer] = aName;
     223                 :     // Prevent the optimizer from re-ordering these instructions
     224                 :     STORE_SEQUENCER();
     225                 :     mStackPointer++;
     226                 :   }
     227                 :   void pop()
     228                 :   {
     229                 :     if (mDroppedStackEntries > 0) {
     230                 :       mDroppedStackEntries--;
     231                 :     } else {
     232                 :       mStackPointer--;
     233                 :     }
     234                 :   }
     235                 :   bool isEmpty()
     236                 :   {
     237                 :     return mStackPointer == 0;
     238                 :   }
     239                 : 
     240                 :   // Keep a list of active checkpoints
     241                 :   char const * volatile mStack[1024];
     242                 :   // Keep a list of active markers to be applied to the next sample taken
     243                 :   char const * volatile mMarkers[1024];
     244                 :   volatile mozilla::sig_safe_t mStackPointer;
     245                 :   volatile mozilla::sig_safe_t mMarkerPointer;
     246                 :   volatile mozilla::sig_safe_t mDroppedStackEntries;
     247                 :   // We don't want to modify _markers from within the signal so we allow
     248                 :   // it to queue a clear operation.
     249                 :   volatile mozilla::sig_safe_t mQueueClearMarker;
     250                 : };
     251                 : 
     252                 : inline void* mozilla_sampler_call_enter(const char *aInfo)
     253                 : {
     254                 :   // check if we've been initialized to avoid calling pthread_getspecific
     255                 :   // with a null pkey_stack which will return undefined results.
     256                 :   if (!stack_key_initialized)
     257                 :     return NULL;
     258                 : 
     259                 :   ProfileStack *stack = mozilla::tls::get<ProfileStack>(pkey_stack);
     260                 :   // we can't infer whether 'stack' has been initialized
     261                 :   // based on the value of stack_key_intiailized because
     262                 :   // 'stack' is only intialized when a thread is being
     263                 :   // profiled.
     264                 :   if (!stack) {
     265                 :     return stack;
     266                 :   }
     267                 :   stack->push(aInfo);
     268                 : 
     269                 :   // The handle is meant to support future changes
     270                 :   // but for now it is simply use to save a call to
     271                 :   // pthread_getspecific on exit. It also supports the
     272                 :   // case where the sampler is initialized between
     273                 :   // enter and exit.
     274                 :   return stack;
     275                 : }
     276                 : 
     277                 : inline void mozilla_sampler_call_exit(void *aHandle)
     278                 : {
     279                 :   if (!aHandle)
     280                 :     return;
     281                 : 
     282                 :   ProfileStack *stack = (ProfileStack*)aHandle;
     283                 :   stack->pop();
     284                 : }
     285                 : 
     286                 : inline void mozilla_sampler_add_marker(const char *aMarker)
     287                 : {
     288                 :   ProfileStack *stack = mozilla::tls::get<ProfileStack>(pkey_stack);
     289                 :   if (!stack) {
     290                 :     return;
     291                 :   }
     292                 :   stack->addMarker(aMarker);
     293                 : }
     294                 : 

Generated by: LCOV version 1.7