2011-08-26 17:05:37 -07:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2012-05-21 04:12:37 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
2013-08-21 23:31:21 -07:00
// IWYU pragma: private, include "GeckoProfiler.h"
2011-08-26 17:05:37 -07:00
2013-03-10 15:00:23 -07:00
# ifndef TOOLS_SPS_SAMPLER_H_
# define TOOLS_SPS_SAMPLER_H_
2011-12-04 11:09:00 -08:00
# include <stdlib.h>
2011-12-15 12:44:13 -08:00
# include <signal.h>
2012-06-26 20:25:14 -07:00
# include <stdarg.h>
2012-05-09 13:54:33 -07:00
# include "mozilla/ThreadLocal.h"
2013-01-18 15:47:31 -08:00
# include "mozilla/Assertions.h"
2013-03-15 17:48:56 -07:00
# include "nscore.h"
# include "GeckoProfilerFunc.h"
# include "PseudoStack.h"
2013-03-21 02:17:23 -07:00
# include "nsISupports.h"
2012-11-30 09:49:20 -08:00
2014-03-27 01:49:06 -07:00
# ifdef MOZ_TASK_TRACER
2014-10-13 19:47:59 -07:00
# include "GeckoTaskTracer.h"
2014-03-27 01:49:06 -07:00
# endif
2012-06-20 17:58:55 -07:00
/* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
* this variable name , causing compilation problems . Alleviate this for now by
* removing this # define */
# ifdef MOZ_WIDGET_QT
# undef slots
# endif
2013-03-18 07:10:25 -07:00
2013-03-16 12:12:19 -07:00
// Make sure that we can use std::min here without the Windows headers messing with us.
# ifdef min
# undef min
# endif
2012-05-09 13:54:33 -07:00
class TableTicker ;
2012-11-30 09:49:20 -08:00
class JSCustomObject ;
2012-05-09 13:54:33 -07:00
2013-08-23 23:12:51 -07:00
namespace mozilla {
class TimeStamp ;
}
2013-03-10 15:00:23 -07:00
extern mozilla : : ThreadLocal < PseudoStack * > tlsPseudoStack ;
2013-03-25 14:57:28 -07:00
extern mozilla : : ThreadLocal < TableTicker * > tlsTicker ;
2013-09-25 08:28:34 -07:00
extern mozilla : : ThreadLocal < void * > tlsStackTop ;
2011-12-08 07:46:02 -08:00
extern bool stack_key_initialized ;
2011-08-26 17:05:37 -07:00
2012-01-17 12:33:04 -08:00
# ifndef SAMPLE_FUNCTION_NAME
# ifdef __GNUC__
# define SAMPLE_FUNCTION_NAME __FUNCTION__
# elif defined(_MSC_VER)
# define SAMPLE_FUNCTION_NAME __FUNCTION__
# else
# define SAMPLE_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name.
# endif
# endif
2013-03-15 12:17:50 -07:00
static inline
2013-05-28 05:03:38 -07:00
void profiler_init ( void * stackTop )
2013-03-15 12:17:50 -07:00
{
2014-03-27 01:49:06 -07:00
# ifdef MOZ_TASK_TRACER
mozilla : : tasktracer : : InitTaskTracer ( ) ;
# endif
2013-05-28 05:03:38 -07:00
mozilla_sampler_init ( stackTop ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_shutdown ( )
{
2014-03-27 01:49:06 -07:00
# ifdef MOZ_TASK_TRACER
mozilla : : tasktracer : : ShutdownTaskTracer ( ) ;
# endif
2013-03-25 14:57:28 -07:00
mozilla_sampler_shutdown ( ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_start ( int aProfileEntries , int aInterval ,
2013-05-16 13:31:50 -07:00
const char * * aFeatures , uint32_t aFeatureCount ,
const char * * aThreadNameFilters , uint32_t aFilterCount )
2013-03-15 12:17:50 -07:00
{
2013-05-16 13:31:50 -07:00
mozilla_sampler_start ( aProfileEntries , aInterval , aFeatures , aFeatureCount , aThreadNameFilters , aFilterCount ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_stop ( )
{
2013-03-25 14:57:28 -07:00
mozilla_sampler_stop ( ) ;
2013-03-15 12:17:50 -07:00
}
2014-02-28 12:16:38 -08:00
static inline
bool profiler_is_paused ( )
{
return mozilla_sampler_is_paused ( ) ;
}
static inline
void profiler_pause ( )
{
mozilla_sampler_pause ( ) ;
}
static inline
void profiler_resume ( )
{
mozilla_sampler_resume ( ) ;
}
2013-09-25 08:28:34 -07:00
static inline
ProfilerBacktrace * profiler_get_backtrace ( )
{
return mozilla_sampler_get_backtrace ( ) ;
}
static inline
void profiler_free_backtrace ( ProfilerBacktrace * aBacktrace )
{
mozilla_sampler_free_backtrace ( aBacktrace ) ;
}
2013-03-15 12:17:50 -07:00
static inline
bool profiler_is_active ( )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_is_active ( ) ;
2013-03-15 12:17:50 -07:00
}
2014-05-24 09:14:14 -07:00
static inline
bool profiler_feature_active ( const char * aName )
{
return mozilla_sampler_feature_active ( aName ) ;
}
2013-03-15 12:17:50 -07:00
static inline
2013-09-25 08:28:34 -07:00
void profiler_responsiveness ( const mozilla : : TimeStamp & aTime )
2013-03-15 12:17:50 -07:00
{
2013-03-25 14:57:28 -07:00
mozilla_sampler_responsiveness ( aTime ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_set_frame_number ( int frameNumber )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_frame_number ( frameNumber ) ;
2013-03-15 12:17:50 -07:00
}
static inline
char * profiler_get_profile ( )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_get_profile ( ) ;
2013-03-15 12:17:50 -07:00
}
2013-03-15 21:47:02 -07:00
static inline
JSObject * profiler_get_profile_jsobject ( JSContext * aCx )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_get_profile_data ( aCx ) ;
2013-03-15 21:47:02 -07:00
}
2014-04-21 13:48:47 -07:00
static inline
void profiler_save_profile_to_file ( const char * aFilename )
{
return mozilla_sampler_save_profile_to_file ( aFilename ) ;
}
2013-03-15 12:17:50 -07:00
static inline
const char * * profiler_get_features ( )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_get_features ( ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_print_location ( )
{
if ( ! sps_version2 ( ) ) {
return mozilla_sampler_print_location1 ( ) ;
} else {
return mozilla_sampler_print_location2 ( ) ;
}
}
static inline
void profiler_lock ( )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_lock ( ) ;
2013-03-15 12:17:50 -07:00
}
static inline
void profiler_unlock ( )
{
2013-03-25 14:57:28 -07:00
return mozilla_sampler_unlock ( ) ;
2013-03-15 12:17:50 -07:00
}
2013-03-10 15:00:23 -07:00
2013-03-29 12:34:49 -07:00
static inline
2013-05-28 05:03:38 -07:00
void profiler_register_thread ( const char * name , void * stackTop )
2013-03-29 12:34:49 -07:00
{
2013-05-28 05:03:38 -07:00
mozilla_sampler_register_thread ( name , stackTop ) ;
2013-03-29 12:34:49 -07:00
}
static inline
void profiler_unregister_thread ( )
{
mozilla_sampler_unregister_thread ( ) ;
}
2014-03-28 13:08:22 -07:00
static inline
void profiler_sleep_start ( )
{
mozilla_sampler_sleep_start ( ) ;
}
static inline
void profiler_sleep_end ( )
{
mozilla_sampler_sleep_end ( ) ;
}
2013-04-03 15:59:17 -07:00
static inline
void profiler_js_operation_callback ( )
{
PseudoStack * stack = tlsPseudoStack . get ( ) ;
if ( ! stack ) {
return ;
}
stack - > jsOperationCallback ( ) ;
}
2013-04-23 10:10:29 -07:00
static inline
double profiler_time ( )
{
return mozilla_sampler_time ( ) ;
}
2013-09-25 08:28:34 -07:00
static inline
double profiler_time ( const mozilla : : TimeStamp & aTime )
{
return mozilla_sampler_time ( aTime ) ;
}
2013-06-14 09:42:10 -07:00
static inline
bool profiler_in_privacy_mode ( )
{
PseudoStack * stack = tlsPseudoStack . get ( ) ;
if ( ! stack ) {
return false ;
}
return stack - > mPrivacyMode ;
}
2014-04-22 11:13:00 -07:00
static inline void profiler_tracing ( const char * aCategory , const char * aInfo ,
ProfilerBacktrace * aCause ,
TracingMetadata aMetaData = TRACING_DEFAULT )
{
if ( ! stack_key_initialized )
return ;
// Don't insert a marker if we're not profiling to avoid
// the heap copy (malloc).
if ( ! profiler_is_active ( ) ) {
return ;
}
mozilla_sampler_tracing ( aCategory , aInfo , aCause , aMetaData ) ;
}
2013-09-27 09:08:45 -07:00
static inline void profiler_tracing ( const char * aCategory , const char * aInfo ,
TracingMetadata aMetaData = TRACING_DEFAULT )
{
if ( ! stack_key_initialized )
return ;
// Don't insert a marker if we're not profiling to avoid
// the heap copy (malloc).
if ( ! profiler_is_active ( ) ) {
return ;
}
mozilla_sampler_tracing ( aCategory , aInfo , aMetaData ) ;
}
2014-01-08 08:12:02 -08:00
// Uncomment this to turn on systrace or build with
// ac_add_options --enable-systace
//#define MOZ_USE_SYSTRACE
# ifdef MOZ_USE_SYSTRACE
2014-05-27 00:12:21 -07:00
# define ATRACE_TAG ATRACE_TAG_ALWAYS
2014-01-08 08:12:02 -08:00
// We need HAVE_ANDROID_OS to be defined for Trace.h.
// If its not set we will set it temporary and remove it.
# ifndef HAVE_ANDROID_OS
# define HAVE_ANDROID_OS
# define REMOVE_HAVE_ANDROID_OS
# endif
2014-05-27 00:12:21 -07:00
// Android source code will include <cutils/trace.h> before this. There is no
// HAVE_ANDROID_OS defined in Firefox OS build at that time. Enabled it globally
// will cause other build break. So atrace_begin and atrace_end are not defined.
// It will cause a build-break when we include <utils/Trace.h>. Use undef
// _LIBS_CUTILS_TRACE_H will force <cutils/trace.h> to define atrace_begin and
// atrace_end with defined HAVE_ANDROID_OS again. Then there is no build-break.
# undef _LIBS_CUTILS_TRACE_H
2014-01-08 08:12:02 -08:00
# include <utils / Trace.h>
2014-05-27 00:12:21 -07:00
# define MOZ_PLATFORM_TRACING(name) ATRACE_NAME(name);
2014-01-08 08:12:02 -08:00
# ifdef REMOVE_HAVE_ANDROID_OS
# undef HAVE_ANDROID_OS
# undef REMOVE_HAVE_ANDROID_OS
# endif
# else
2014-05-27 00:12:21 -07:00
# define MOZ_PLATFORM_TRACING(name)
2014-01-08 08:12:02 -08:00
# endif
2012-01-17 12:33:04 -08:00
// we want the class and function name but can't easily get that using preprocessor macros
// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
2012-04-17 13:21:23 -07:00
# define SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
# define SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, line) SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line)
# define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
2014-05-30 18:41:11 -07:00
# define PROFILER_LABEL(name_space, info, category) MOZ_PLATFORM_TRACING(name_space "::" info) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__)
2014-10-14 20:20:16 -07:00
# define PROFILER_LABEL_FUNC(category) MOZ_PLATFORM_TRACING(SAMPLE_FUNCTION_NAME) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(SAMPLE_FUNCTION_NAME, category, __LINE__)
2014-05-30 18:41:11 -07:00
# define PROFILER_LABEL_PRINTF(name_space, info, category, ...) MOZ_PLATFORM_TRACING(name_space "::" info) mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__, __VA_ARGS__)
2013-09-27 09:08:45 -07:00
2013-03-15 12:17:50 -07:00
# define PROFILER_MARKER(info) mozilla_sampler_add_marker(info)
2013-07-10 21:27:04 -07:00
# define PROFILER_MARKER_PAYLOAD(info, payload) mozilla_sampler_add_marker(info, payload)
2013-09-27 09:08:45 -07:00
# define PROFILER_MAIN_THREAD_MARKER(info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info)
2014-05-30 18:41:11 -07:00
# define PROFILER_MAIN_THREAD_LABEL(name_space, info, category) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__)
# define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, category, ...) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__, __VA_ARGS__)
2012-11-19 15:13:28 -08:00
2013-03-29 12:34:49 -07:00
2012-09-24 15:38:07 -07:00
/* FIXME/bug 789667: memory constraints wouldn't much of a problem for
* this small a sample buffer size , except that serializing the
* profile data is extremely , unnecessarily memory intensive . */
# ifdef MOZ_WIDGET_GONK
# define PLATFORM_LIKELY_MEMORY_CONSTRAINED
# endif
2012-10-18 08:12:53 -07:00
# if !defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) && !defined(ARCH_ARMV6)
2012-09-24 15:38:07 -07:00
# define PROFILE_DEFAULT_ENTRY 1000000
# else
# define PROFILE_DEFAULT_ENTRY 100000
# endif
2013-09-25 08:28:34 -07:00
// In the case of profiler_get_backtrace we know that we only need enough space
// for a single backtrace.
# define GET_BACKTRACE_DEFAULT_ENTRY 1000
2012-09-24 15:38:07 -07:00
# if defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED)
/* A 1ms sampling interval has been shown to be a large perf hit
* ( 10f ps ) on memory - contrained ( low - end ) platforms , and additionally
* to yield different results from the profiler . Where this is the
* important case , b2g , there are also many gecko processes which
* magnify these effects . */
# define PROFILE_DEFAULT_INTERVAL 10
# elif defined(ANDROID)
2012-03-02 11:11:47 -08:00
// We use a lower frequency on Android, in order to make things work
// more smoothly on phones. This value can be adjusted later with
// some libunwind optimizations.
// In one sample measurement on Galaxy Nexus, out of about 700 backtraces,
// 60 of them took more than 25ms, and the average and standard deviation
// were 6.17ms and 9.71ms respectively.
2012-04-20 08:31:09 -07:00
// For now since we don't support stackwalking let's use 1ms since it's fast
// enough.
# define PROFILE_DEFAULT_INTERVAL 1
2012-03-02 11:11:47 -08:00
# else
2012-04-20 08:31:09 -07:00
# define PROFILE_DEFAULT_INTERVAL 1
2012-03-02 11:11:47 -08:00
# endif
# define PROFILE_DEFAULT_FEATURES NULL
# define PROFILE_DEFAULT_FEATURE_COUNT 0
2011-12-02 14:05:33 -08:00
2011-08-26 17:05:37 -07:00
namespace mozilla {
2013-04-11 20:22:09 -07:00
class MOZ_STACK_CLASS SamplerStackFrameRAII {
2011-08-26 17:05:37 -07:00
public :
2012-01-17 12:33:04 -08:00
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
2014-05-30 18:41:11 -07:00
SamplerStackFrameRAII ( const char * aInfo ,
js : : ProfileEntry : : Category aCategory , uint32_t line )
{
mHandle = mozilla_sampler_call_enter ( aInfo , aCategory , this , false , line ) ;
2011-08-26 17:05:37 -07:00
}
~ SamplerStackFrameRAII ( ) {
mozilla_sampler_call_exit ( mHandle ) ;
}
private :
void * mHandle ;
} ;
2012-06-26 20:25:14 -07:00
static const int SAMPLER_MAX_STRING = 128 ;
2013-04-11 20:22:09 -07:00
class MOZ_STACK_CLASS SamplerStackFramePrintfRAII {
2012-06-26 20:25:14 -07:00
public :
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
2014-05-30 18:41:11 -07:00
SamplerStackFramePrintfRAII ( const char * aInfo ,
js : : ProfileEntry : : Category aCategory , uint32_t line , const char * aFormat , . . . )
{
2013-06-14 09:42:10 -07:00
if ( profiler_is_active ( ) & & ! profiler_in_privacy_mode ( ) ) {
2012-06-26 20:25:14 -07:00
va_list args ;
va_start ( args , aFormat ) ;
char buff [ SAMPLER_MAX_STRING ] ;
// We have to use seperate printf's because we're using
// the vargs.
# if _MSC_VER
_vsnprintf ( buff , SAMPLER_MAX_STRING , aFormat , args ) ;
2014-05-30 18:41:11 -07:00
_snprintf ( mDest , SAMPLER_MAX_STRING , " %s %s " , aInfo , buff ) ;
2012-06-26 20:25:14 -07:00
# else
2013-12-02 09:29:49 -08:00
: : vsnprintf ( buff , SAMPLER_MAX_STRING , aFormat , args ) ;
2014-05-30 18:41:11 -07:00
: : snprintf ( mDest , SAMPLER_MAX_STRING , " %s %s " , aInfo , buff ) ;
2012-06-26 20:25:14 -07:00
# endif
2014-05-30 18:41:11 -07:00
mHandle = mozilla_sampler_call_enter ( mDest , aCategory , this , true , line ) ;
2012-06-26 20:25:14 -07:00
va_end ( args ) ;
} else {
2014-05-30 18:41:11 -07:00
mHandle = mozilla_sampler_call_enter ( aInfo , aCategory , this , false , line ) ;
2012-06-26 20:25:14 -07:00
}
}
~ SamplerStackFramePrintfRAII ( ) {
mozilla_sampler_call_exit ( mHandle ) ;
}
private :
char mDest [ SAMPLER_MAX_STRING ] ;
void * mHandle ;
} ;
2011-08-26 17:05:37 -07:00
} //mozilla
2013-03-10 15:00:23 -07:00
inline PseudoStack * mozilla_get_pseudo_stack ( void )
2012-06-20 17:58:55 -07:00
{
if ( ! stack_key_initialized )
2013-11-11 11:16:31 -08:00
return nullptr ;
2013-03-10 15:00:23 -07:00
return tlsPseudoStack . get ( ) ;
2012-06-20 17:58:55 -07:00
}
2014-05-30 18:41:11 -07:00
inline void * mozilla_sampler_call_enter ( const char * aInfo ,
js : : ProfileEntry : : Category aCategory , void * aFrameAddress , bool aCopy , uint32_t line )
2011-08-26 17:05:37 -07:00
{
2011-12-08 07:46:02 -08:00
// check if we've been initialized to avoid calling pthread_getspecific
2012-05-16 14:20:06 -07:00
// with a null tlsStack which will return undefined results.
2011-12-08 07:46:02 -08:00
if ( ! stack_key_initialized )
2013-11-11 11:16:31 -08:00
return nullptr ;
2011-12-08 07:46:02 -08:00
2013-03-10 15:00:23 -07:00
PseudoStack * stack = tlsPseudoStack . get ( ) ;
2011-12-08 07:46:02 -08:00
// we can't infer whether 'stack' has been initialized
// based on the value of stack_key_intiailized because
// 'stack' is only intialized when a thread is being
// profiled.
2011-08-26 17:05:37 -07:00
if ( ! stack ) {
return stack ;
}
2014-05-30 18:41:11 -07:00
stack - > push ( aInfo , aCategory , aFrameAddress , aCopy , line ) ;
2011-08-26 17:05:37 -07:00
// The handle is meant to support future changes
// but for now it is simply use to save a call to
// pthread_getspecific on exit. It also supports the
// case where the sampler is initialized between
// enter and exit.
return stack ;
}
inline void mozilla_sampler_call_exit ( void * aHandle )
{
if ( ! aHandle )
return ;
2013-03-10 15:00:23 -07:00
PseudoStack * stack = ( PseudoStack * ) aHandle ;
2011-08-26 17:05:37 -07:00
stack - > pop ( ) ;
}
2013-12-10 13:34:19 -08:00
void mozilla_sampler_add_marker ( const char * aMarker , ProfilerMarkerPayload * aPayload ) ;
2011-08-26 17:05:37 -07:00
2013-03-10 15:00:23 -07:00
# endif /* ndef TOOLS_SPS_SAMPLER_H_ */