2016-02-16 23:21:12 +03:00
/**
Lightweight profiler library for c + +
2016-08-11 23:52:33 +03:00
Copyright ( C ) 2016 Sergey Yagovtsev , Victor Zarubkin
2016-02-16 23:21:12 +03:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2016-02-17 23:43:37 +03:00
* */
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
# ifndef EASY_PROFILER____H_______
# define EASY_PROFILER____H_______
2016-02-16 23:21:12 +03:00
2016-09-01 22:22:58 +03:00
# ifdef _WIN32
2016-09-06 23:03:05 +03:00
# define __func__ __FUNCTION__
# if defined(_MSC_VER) && _MSC_VER <= 1800
// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
# define EASY_THREAD_LOCAL __declspec(thread)
# endif
# elif defined(__GNUC__)
2016-09-07 21:29:37 +03:00
# ifndef __clang__
2016-09-06 23:03:05 +03:00
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
2016-09-07 21:29:37 +03:00
# endif
2016-09-06 23:03:05 +03:00
# endif
2016-09-07 21:29:37 +03:00
# if defined ( __clang__ )
# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
# define EASY_THREAD_LOCAL __thread
# endif
2016-09-06 23:03:05 +03:00
# endif
# endif
2016-09-07 21:29:37 +03:00
// TODO: Check thread local support for clanv earlier than 3.3
2016-09-06 23:03:05 +03:00
# ifndef EASY_THREAD_LOCAL
# define EASY_THREAD_LOCAL thread_local
# define EASY_THREAD_LOCAL_CPP11
2016-02-16 23:21:12 +03:00
# endif
2016-08-31 21:51:22 +03:00
# if defined ( __clang__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
# endif
2016-02-18 23:50:06 +03:00
# ifndef FULL_DISABLE_PROFILER
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
# include <type_traits>
# define EASY_TOKEN_JOIN(x, y) x ## y
# define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
# define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
# define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
2016-08-28 02:41:02 +03:00
2016-03-03 14:55:38 +03:00
/**
\ defgroup profiler Profiler
*/
2016-08-28 23:40:23 +03:00
namespace profiler {
2016-09-04 14:48:35 +03:00
template < const bool IS_REF > struct NameSwitch final {
2016-08-30 20:46:39 +03:00
static const char * runtime_name ( const char * name ) { return name ; }
static const char * compiletime_name ( const char * ) { return " " ; }
2016-08-28 23:40:23 +03:00
} ;
2016-08-28 02:41:02 +03:00
2016-08-28 23:40:23 +03:00
template < > struct NameSwitch < true > final {
2016-08-30 20:46:39 +03:00
static const char * runtime_name ( const char * ) { return " " ; }
static const char * compiletime_name ( const char * name ) { return name ; }
2016-08-28 23:40:23 +03:00
} ;
} // END of namespace profiler.
2016-03-03 14:55:38 +03:00
2016-08-28 23:40:23 +03:00
# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name)
# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
2016-03-03 14:55:38 +03:00
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of beginning of block with custom name and color.
2016-03-03 14:55:38 +03:00
\ code
2016-09-07 21:32:14 +03:00
# include "profiler/profiler.h"
void foo ( )
{
// some code ...
if ( something ) {
EASY_BLOCK ( " Calling bar() " ) ; // Block with default color
bar ( ) ;
}
2016-08-28 23:40:23 +03:00
else {
EASY_BLOCK ( " Calling baz() " , profiler : : colors : : Red ) ; // Red block
baz ( ) ;
}
2016-09-07 21:32:14 +03:00
}
2016-03-03 14:55:38 +03:00
\ endcode
2016-08-28 23:40:23 +03:00
Block will be automatically completed by destructor .
2016-03-03 14:55:38 +03:00
\ ingroup profiler
*/
2016-08-28 23:40:23 +03:00
# define EASY_BLOCK(name, ...)\
2016-09-09 00:09:47 +03:00
static const : : profiler : : BaseBlockDescriptor & EASY_UNIQUE_DESC ( __LINE__ ) = : : profiler : : registerDescription ( EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , \
2016-08-28 23:40:23 +03:00
: : profiler : : BLOCK_TYPE_BLOCK , # # __VA_ARGS__ ) ; \
2016-09-09 00:09:47 +03:00
: : profiler : : Block EASY_UNIQUE_BLOCK ( __LINE__ ) ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) ) ; \
2016-08-28 23:40:23 +03:00
: : profiler : : beginBlock ( EASY_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of beginning of block with function name and custom color.
2016-03-03 14:55:38 +03:00
\ code
2016-09-07 21:32:14 +03:00
# include "profiler/profiler.h"
void foo ( ) {
EASY_FUNCTION ( ) ; // Block with name="foo" and default color
//some code...
}
2016-03-03 14:55:38 +03:00
2016-08-28 23:40:23 +03:00
void bar ( ) {
EASY_FUNCTION ( profiler : : colors : : Green ) ; // Green block with name="bar"
//some code...
}
2016-03-03 14:55:38 +03:00
\ endcode
2016-08-28 23:40:23 +03:00
Name of the block automatically created with function name .
2016-03-03 14:55:38 +03:00
\ ingroup profiler
*/
2016-08-31 21:51:00 +03:00
# define EASY_FUNCTION(...)\
2016-09-09 00:09:47 +03:00
static const : : profiler : : BaseBlockDescriptor & EASY_UNIQUE_DESC ( __LINE__ ) = : : profiler : : registerDescription ( __func__ , __FILE__ , __LINE__ , \
2016-08-31 21:51:00 +03:00
: : profiler : : BLOCK_TYPE_BLOCK , # # __VA_ARGS__ ) ; \
2016-09-09 00:09:47 +03:00
: : profiler : : Block EASY_UNIQUE_BLOCK ( __LINE__ ) ( EASY_UNIQUE_DESC ( __LINE__ ) , " " ) ; \
2016-08-31 21:51:00 +03:00
: : profiler : : beginBlock ( EASY_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-03-03 14:55:38 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of completion of last nearest open block.
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
\ code
# include "profiler/profiler.h"
2016-08-28 23:40:23 +03:00
int foo ( )
2016-03-03 14:55:38 +03:00
{
2016-08-28 23:40:23 +03:00
// some code ...
2016-09-07 21:32:14 +03:00
int sum = 0 ;
EASY_BLOCK ( " Calculating sum " ) ;
for ( int i = 0 ; i < 10 ; + + i ) {
sum + = i ;
}
EASY_END_BLOCK ;
2016-08-28 23:40:23 +03:00
// some antoher code here ...
return sum ;
2016-03-03 14:55:38 +03:00
}
\ endcode
\ ingroup profiler
*/
2016-08-28 23:40:23 +03:00
# define EASY_END_BLOCK ::profiler::endBlock();
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of creating event with custom name and color.
2016-03-03 14:55:38 +03:00
2016-08-28 23:40:23 +03:00
Event is a block with zero duration and special type .
\ warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT
will end previously opened EASY_BLOCK or EASY_FUNCTION .
\ ingroup profiler
*/
# define EASY_EVENT(name, ...)\
2016-09-09 00:09:47 +03:00
static const : : profiler : : BaseBlockDescriptor & EASY_UNIQUE_DESC ( __LINE__ ) = \
: : profiler : : registerDescription ( EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT , # # __VA_ARGS__ ) ; \
: : profiler : : storeBlock ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) ) ;
2016-03-03 14:55:38 +03:00
/** Macro enabling profiler
\ ingroup profiler
*/
2016-08-28 23:40:23 +03:00
# define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
/** Macro disabling profiler
\ ingroup profiler
*/
2016-08-28 23:40:23 +03:00
# define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
2016-02-16 23:21:12 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of naming current thread.
If this thread has been already named then nothing changes .
\ ingroup profiler
*/
2016-09-06 23:03:05 +03:00
# define EASY_THREAD(name)\
EASY_THREAD_LOCAL static const char * EASY_TOKEN_CONCATENATE ( unique_profiler_thread_name , __LINE__ ) = nullptr ; \
if ( EASY_TOKEN_CONCATENATE ( unique_profiler_thread_name , __LINE__ ) = = nullptr ) \
EASY_TOKEN_CONCATENATE ( unique_profiler_thread_name , __LINE__ ) = : : profiler : : setThreadName ( name , __FILE__ , __func__ , __LINE__ ) ;
2016-07-31 22:12:11 +03:00
2016-08-28 23:40:23 +03:00
/** Macro of naming main thread.
This is only for user comfort . There is no difference for EasyProfiler GUI between different threads .
\ ingroup profiler
*/
# define EASY_MAIN_THREAD EASY_THREAD("Main")
2016-07-31 22:12:11 +03:00
2016-02-18 23:50:06 +03:00
# else
2016-08-28 23:40:23 +03:00
# define EASY_BLOCK(...)
# define EASY_FUNCTION(...)
# define EASY_END_BLOCK
# define EASY_PROFILER_ENABLE
# define EASY_PROFILER_DISABLE
# define EASY_EVENT(...)
# define EASY_THREAD(...)
# define EASY_MAIN_THREAD
2016-02-18 23:50:06 +03:00
# endif
2016-02-16 23:21:12 +03:00
# include <stdint.h>
2016-02-17 23:24:35 +03:00
# include <cstddef>
2016-08-28 02:41:02 +03:00
# include "profiler/profiler_colors.h"
2016-02-16 23:21:12 +03:00
# ifdef _WIN32
2016-09-07 21:32:14 +03:00
# ifdef _BUILD_PROFILER
# define PROFILER_API __declspec(dllexport)
2016-02-16 23:21:12 +03:00
# else
2016-09-07 21:32:14 +03:00
# define PROFILER_API __declspec(dllimport)
2016-02-16 23:21:12 +03:00
# endif
# else
# define PROFILER_API
# endif
2016-08-14 22:22:44 +03:00
class ProfileManager ;
2016-08-28 02:41:02 +03:00
namespace profiler {
2016-03-04 11:59:36 +03:00
2016-09-07 21:32:14 +03:00
class Block ;
2016-09-09 00:09:47 +03:00
class BaseBlockDescriptor ;
2016-02-16 23:21:12 +03:00
2016-09-06 23:03:05 +03:00
typedef uint64_t timestamp_t ;
typedef uint32_t thread_id_t ;
2016-08-28 02:41:02 +03:00
typedef uint32_t block_id_t ;
2016-03-03 15:48:00 +03:00
2016-08-28 02:41:02 +03:00
enum BlockType : uint8_t
{
BLOCK_TYPE_EVENT = 0 ,
BLOCK_TYPE_THREAD_SIGN ,
2016-09-04 14:48:35 +03:00
BLOCK_TYPE_BLOCK ,
2016-08-28 02:41:02 +03:00
BLOCK_TYPE_CONTEXT_SWITCH ,
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
BLOCK_TYPES_NUMBER
} ;
typedef BlockType block_type_t ;
2016-09-07 21:32:14 +03:00
extern " C " {
2016-09-09 00:09:47 +03:00
PROFILER_API const BaseBlockDescriptor & registerDescription ( const char * _compiletimeName , const char * _filename , int _line , block_type_t _block_type , color_t _color = : : profiler : : colors : : Default ) ;
PROFILER_API void storeBlock ( const BaseBlockDescriptor & _desc , const char * _runtimeName ) ;
2016-09-06 23:03:05 +03:00
PROFILER_API void beginBlock ( Block & _block ) ;
PROFILER_API void endBlock ( ) ;
2016-09-09 00:09:47 +03:00
PROFILER_API void setEnabled ( bool _isEnable ) ;
PROFILER_API uint32_t dumpBlocksToFile ( const char * _filename ) ;
PROFILER_API const char * setThreadName ( const char * _name , const char * _filename , const char * _funcname , int _line ) ;
PROFILER_API void setContextSwitchLogFilename ( const char * _name ) ;
2016-09-06 23:03:05 +03:00
PROFILER_API const char * getContextSwitchLogFilename ( ) ;
2016-09-07 21:32:14 +03:00
}
2016-02-20 05:24:12 +03:00
# pragma pack(push,1)
2016-08-28 02:41:02 +03:00
class PROFILER_API BaseBlockDescriptor
{
2016-09-09 00:09:47 +03:00
friend : : ProfileManager ;
2016-08-28 02:41:02 +03:00
protected :
2016-02-20 05:24:12 +03:00
2016-09-09 00:09:47 +03:00
block_id_t m_id ; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors)
2016-08-28 02:41:02 +03:00
int m_line ; ///< Line number in the source file
color_t m_color ; ///< Color of the block packed into 1-byte structure
2016-09-07 21:48:50 +03:00
block_type_t m_type ; ///< Type of the block (See BlockType)
2016-09-09 00:09:47 +03:00
bool m_enabled ; ///< If false then blocks with such id() will not be stored by profiler during profile session
2016-03-03 14:55:38 +03:00
2016-09-09 00:09:47 +03:00
BaseBlockDescriptor ( block_id_t _id , int _line , block_type_t _block_type , color_t _color ) ;
2016-02-24 06:31:05 +03:00
2016-08-28 02:41:02 +03:00
public :
2016-03-03 14:55:38 +03:00
2016-09-09 00:09:47 +03:00
inline block_id_t id ( ) const { return m_id ; }
2016-08-28 02:41:02 +03:00
inline int line ( ) const { return m_line ; }
inline color_t color ( ) const { return m_color ; }
2016-09-09 00:09:47 +03:00
inline block_type_t type ( ) const { return m_type ; }
inline bool enabled ( ) const { return m_enabled ; }
2016-08-28 02:41:02 +03:00
} ;
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
{
2016-09-09 00:09:47 +03:00
friend : : ProfileManager ;
2016-08-28 02:41:02 +03:00
const char * m_name ; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
const char * m_filename ; ///< Source file name where this block is declared
2016-02-20 05:24:12 +03:00
2016-08-28 02:41:02 +03:00
public :
2016-02-18 19:27:17 +03:00
2016-09-09 00:09:47 +03:00
BlockDescriptor ( uint64_t & _used_mem , block_id_t _id , const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color ) ;
2016-02-20 05:24:12 +03:00
2016-09-04 14:48:35 +03:00
inline const char * name ( ) const { return m_name ; }
inline const char * file ( ) const { return m_filename ; }
2016-08-28 02:41:02 +03:00
} ;
2016-02-20 05:24:12 +03:00
2016-08-28 02:41:02 +03:00
class PROFILER_API BaseBlockData
2016-08-11 23:52:33 +03:00
{
2016-09-04 14:48:35 +03:00
friend : : ProfileManager ;
2016-08-28 02:41:02 +03:00
protected :
timestamp_t m_begin ;
timestamp_t m_end ;
block_id_t m_id ;
2016-08-11 23:52:33 +03:00
public :
2016-09-04 19:35:58 +03:00
BaseBlockData ( const BaseBlockData & ) = default ;
2016-08-28 02:41:02 +03:00
BaseBlockData ( timestamp_t _begin_time , block_id_t _id ) ;
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
inline timestamp_t begin ( ) const { return m_begin ; }
inline timestamp_t end ( ) const { return m_end ; }
inline block_id_t id ( ) const { return m_id ; }
2016-09-04 14:48:35 +03:00
inline timestamp_t duration ( ) const { return m_end - m_begin ; }
2016-08-28 18:19:12 +03:00
2016-09-04 14:48:35 +03:00
inline void setId ( block_id_t _id ) { m_id = _id ; }
2016-09-04 19:35:58 +03:00
private :
BaseBlockData ( ) = delete ;
2016-08-11 23:52:33 +03:00
} ;
2016-08-28 02:41:02 +03:00
# pragma pack(pop)
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
class PROFILER_API Block final : public BaseBlockData
2016-08-14 22:22:44 +03:00
{
friend : : ProfileManager ;
2016-08-14 16:05:10 +03:00
2016-08-28 02:41:02 +03:00
const char * m_name ;
2016-09-09 00:09:47 +03:00
bool m_enabled ;
2016-08-28 02:41:02 +03:00
private :
void finish ( ) ;
2016-09-04 14:48:35 +03:00
void finish ( timestamp_t _end_time ) ;
2016-09-09 00:09:47 +03:00
inline bool finished ( ) const { return m_end > = m_begin ; }
inline bool enabled ( ) const { return m_enabled ; }
2016-08-28 02:41:02 +03:00
2016-08-14 22:22:44 +03:00
public :
2016-08-14 16:05:10 +03:00
2016-09-04 14:48:35 +03:00
Block ( Block & & that ) ;
2016-09-09 00:09:47 +03:00
Block ( const BaseBlockDescriptor & _desc , const char * _runtimeName ) ;
Block ( timestamp_t _begin_time , block_id_t _id , bool _enabled , const char * _runtimeName ) ;
2016-08-28 02:41:02 +03:00
~ Block ( ) ;
2016-02-24 06:31:05 +03:00
2016-08-28 02:41:02 +03:00
inline const char * name ( ) const { return m_name ; }
} ;
2016-02-24 06:31:05 +03:00
2016-08-28 02:41:02 +03:00
//////////////////////////////////////////////////////////////////////
2016-08-14 22:22:44 +03:00
2016-08-02 21:18:04 +03:00
} // END of namespace profiler.
2016-02-16 23:21:12 +03:00
2016-08-31 21:51:22 +03:00
# if defined ( __clang__ )
# pragma clang diagnostic pop
# endif
2016-08-28 23:40:23 +03:00
# endif // EASY_PROFILER____H_______