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
# ifndef ____PROFILER____H_______
# define ____PROFILER____H_______
# if defined ( WIN32 )
# define __func__ __FUNCTION__
# endif
2016-02-18 23:50:06 +03:00
# ifndef FULL_DISABLE_PROFILER
2016-02-16 23:21:12 +03:00
2016-08-28 02:41:02 +03:00
# define TOKEN_JOIN(x, y) x ## y
# define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y)
# define PROFILER_UNIQUE_BLOCK(x) TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
# define PROFILER_UNIQUE_DESC(x) TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
2016-03-03 14:55:38 +03:00
/**
\ defgroup profiler Profiler
*/
2016-08-28 02:41:02 +03:00
/** Macro used to check compile-time strings.
Compiler automatically concatenates " A " " B " into " AB " if both A and B strings
can be identified at compile - time .
\ ingroup profiler
*/
# define COMPILETIME_TEST "_compiletime_test"
2016-03-03 14:55:38 +03:00
/** Macro of beginning of block with custom name and default identification
\ code
# include "profiler/profiler.h"
void foo ( )
{
// some code ...
if ( something ) {
PROFILER_BEGIN_BLOCK ( " Calling someThirdPartyLongFunction() " ) ;
someThirdPartyLongFunction ( ) ;
return ;
}
}
\ endcode
Block will be automatically completed by destructor
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
\ ingroup profiler
*/
2016-08-28 02:41:02 +03:00
# define PROFILER_BEGIN_BLOCK(compiletime_name)\
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( compiletime_name , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_BLOCK , : : profiler : : DefaultBlockColor ) ; \
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( compiletime_name COMPILETIME_TEST , : : profiler : : BLOCK_TYPE_BLOCK , \
2016-08-28 18:19:12 +03:00
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) ) ; \
2016-08-28 02:41:02 +03:00
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
# define EASY_BLOCK(compiletime_name)\
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( compiletime_name , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_BLOCK , : : profiler : : DefaultBlockColor ) ; \
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( compiletime_name COMPILETIME_TEST , : : profiler : : BLOCK_TYPE_BLOCK , \
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) ) ; \
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-08-28 18:19:12 +03:00
# define EASY_BLOCK_RUNTIME(runtime_name)\
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( " " , __FILE__ , __LINE__ , \
2016-08-28 02:41:02 +03:00
: : profiler : : BLOCK_TYPE_BLOCK , : : profiler : : DefaultBlockColor ) ; \
2016-08-28 18:19:12 +03:00
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( nullptr , : : profiler : : BLOCK_TYPE_BLOCK , \
2016-08-28 02:41:02 +03:00
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) , runtime_name ) ; \
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
/** Macro of beginning of block with custom name and custom identification
\ code
# include "profiler/profiler.h"
void foo ( )
{
// some code ...
if ( something ) {
2016-08-28 02:41:02 +03:00
PROFILER_BEGIN_BLOCK ( " Calling someThirdPartyLongFunction() " , : : profiler : : colors : : Red ) ;
2016-03-03 14:55:38 +03:00
someThirdPartyLongFunction ( ) ;
return ;
}
}
\ endcode
Block will be automatically completed by destructor
\ ingroup profiler
*/
2016-08-28 02:41:02 +03:00
# define PROFILER_BEGIN_BLOCK_GROUPED(compiletime_name, block_group)\
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( compiletime_name , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_BLOCK , block_group ) ; \
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( compiletime_name COMPILETIME_TEST , : : profiler : : BLOCK_TYPE_BLOCK , \
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) ) ; \
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
/** Macro of beginning of function block with default identification
\ code
# include "profiler/profiler.h"
void foo ( )
{
PROFILER_BEGIN_FUNCTION_BLOCK ;
//some code...
}
\ endcode
Name of block automatically created with function name
\ ingroup profiler
*/
2016-02-16 23:21:12 +03:00
# define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
2016-03-03 14:55:38 +03:00
/** Macro of beginning of function block with custom identification
\ code
# include "profiler/profiler.h"
void foo ( )
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED ( profiler : : colors : : Red ) ;
//some code...
}
\ endcode
Name of block automatically created with function name
\ ingroup profiler
*/
2016-08-28 02:41:02 +03:00
# define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_color) PROFILER_BEGIN_BLOCK_GROUPED(__func__, block_color)
2016-03-03 14:55:38 +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"
void foo ( )
{
// some code ...
int sum = 0 ;
PROFILER_BEGIN_BLOCK ( " Calculating summ " ) ;
for ( int i = 0 ; i < 10 ; i + + ) {
sum + = i ;
}
PROFILER_END_BLOCK ;
}
\ endcode
\ ingroup profiler
*/
2016-08-28 02:41:02 +03:00
# define PROFILER_END_BLOCK ::profiler::endBlock();
2016-02-16 23:21:12 +03:00
2016-08-28 02:41:02 +03:00
# define PROFILER_ADD_EVENT(compiletime_name) \
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( compiletime_name , __FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT ) ; \
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( compiletime_name COMPILETIME_TEST , : : profiler : : BLOCK_TYPE_EVENT , \
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) ) ; \
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-03-03 14:55:38 +03:00
2016-08-28 02:41:02 +03:00
# define PROFILER_ADD_EVENT_GROUPED(compiletime_name, block_group)\
static const : : profiler : : StaticBlockDescriptor PROFILER_UNIQUE_DESC ( __LINE__ ) ( compiletime_name , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_EVENT , block_group ) ; \
: : profiler : : Block PROFILER_UNIQUE_BLOCK ( __LINE__ ) ( compiletime_name COMPILETIME_TEST , : : profiler : : BLOCK_TYPE_EVENT , \
PROFILER_UNIQUE_DESC ( __LINE__ ) . id ( ) ) ; \
: : profiler : : beginBlock ( PROFILER_UNIQUE_BLOCK ( __LINE__ ) ) ; // this is to avoid compiler warning about unused variable
2016-03-03 14:55:38 +03:00
/** Macro enabling profiler
\ ingroup profiler
*/
2016-08-28 02:41:02 +03:00
# define 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 02:41:02 +03:00
# define PROFILER_DISABLE ::profiler::setEnabled(false);
2016-02-16 23:21:12 +03:00
2016-08-02 21:44:11 +03:00
# ifdef WIN32
2016-08-28 02:41:02 +03:00
# define PROFILER_SET_THREAD_NAME(name) ::profiler::setThreadName(name);
2016-08-02 21:44:11 +03:00
# else
2016-08-28 02:41:02 +03:00
# define PROFILER_SET_THREAD_NAME(name) thread_local static const ::profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name);
2016-08-02 21:44:11 +03:00
# endif
2016-07-31 22:12:11 +03:00
# define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
2016-02-18 23:50:06 +03:00
# else
# define PROFILER_BEGIN_BLOCK(name)
2016-08-28 02:41:02 +03:00
# define PROFILER_BEGIN_BLOCK_GROUPED(name, block_group)
# define PROFILER_BEGIN_FUNCTION_BLOCK
# define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group)
# define PROFILER_END_BLOCK
# define PROFILER_ENABLE
# define PROFILER_DISABLE
2016-06-20 22:43:45 +03:00
# define PROFILER_ADD_EVENT(name)
2016-08-28 02:41:02 +03:00
# define PROFILER_ADD_EVENT_GROUPED(name, block_group)
2016-07-31 22:12:11 +03:00
# define PROFILER_SET_THREAD_NAME(name)
# define PROFILER_SET_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
# ifdef _BUILD_PROFILER
# define PROFILER_API __declspec(dllexport)
# else
# define PROFILER_API __declspec(dllimport)
# endif
# else
# define PROFILER_API
# endif
2016-08-14 22:22:44 +03:00
class ProfileManager ;
2016-08-28 02:41:02 +03:00
class ThreadStorage ;
2016-08-14 22:22:44 +03:00
2016-08-28 02:41:02 +03:00
namespace profiler {
2016-03-04 11:59:36 +03:00
2016-02-16 23:21:12 +03:00
class Block ;
2016-08-28 02:41:02 +03:00
class StaticBlockDescriptor ;
2016-02-16 23:21:12 +03:00
extern " C " {
2016-08-21 14:46:16 +03:00
void PROFILER_API beginBlock ( Block & _block ) ;
2016-02-16 23:21:12 +03:00
void PROFILER_API endBlock ( ) ;
void PROFILER_API setEnabled ( bool isEnable ) ;
2016-07-04 22:53:02 +03:00
unsigned int PROFILER_API dumpBlocksToFile ( const char * filename ) ;
2016-07-31 22:12:11 +03:00
void PROFILER_API setThreadName ( const char * name ) ;
2016-02-16 23:21:12 +03:00
}
typedef uint64_t timestamp_t ;
2016-02-20 05:24:12 +03:00
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_BLOCK ,
BLOCK_TYPE_THREAD_SIGN ,
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-03-03 15:48:00 +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
{
protected :
2016-02-20 05:24:12 +03:00
2016-08-28 02:41:02 +03:00
int m_line ; ///< Line number in the source file
block_type_t m_type ; ///< Type of the block (See BlockType)
color_t m_color ; ///< Color of the block packed into 1-byte structure
2016-03-03 14:55:38 +03:00
2016-08-28 02:41:02 +03:00
BaseBlockDescriptor ( 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-08-28 02:41:02 +03:00
inline int line ( ) const { return m_line ; }
inline block_type_t type ( ) const { return m_type ; }
inline color_t color ( ) const { return m_color ; }
inline rgb32_t rgb ( ) const { return : : profiler : : colors : : convert_to_rgb ( m_color ) ; }
} ;
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
{
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-08-28 02:41:02 +03:00
BlockDescriptor ( uint64_t & _used_mem , 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-08-28 02:41:02 +03:00
const char * name ( ) const { return m_name ; }
const char * file ( ) const { return m_filename ; }
} ;
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-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-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 ; }
timestamp_t duration ( ) const { return m_end - m_begin ; }
2016-08-28 18:19:12 +03:00
void setId ( block_id_t _id ) { m_id = _id ; }
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 ;
private :
void finish ( ) ;
inline bool isFinished ( ) const { return m_end > = m_begin ; }
2016-08-14 22:22:44 +03:00
public :
2016-08-14 16:05:10 +03:00
2016-08-28 02:41:02 +03:00
Block ( const char * , block_type_t _block_type , block_id_t _id , const char * _name = " " ) ;
~ 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-28 02:41:02 +03:00
class PROFILER_API StaticBlockDescriptor final
{
block_id_t m_id ;
2016-08-14 22:22:44 +03:00
2016-08-28 02:41:02 +03:00
public :
2016-08-14 22:22:44 +03:00
2016-08-28 02:41:02 +03:00
StaticBlockDescriptor ( const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color = colors : : Random ) ;
block_id_t id ( ) const { return m_id ; }
2016-08-14 22:22:44 +03:00
} ;
2016-02-24 06:31:05 +03:00
2016-08-28 02:41:02 +03:00
# ifndef WIN32
2016-08-11 23:52:33 +03:00
struct PROFILER_API ThreadNameSetter final
2016-08-02 21:18:04 +03:00
{
ThreadNameSetter ( const char * _name )
{
setThreadName ( _name ) ;
}
} ;
2016-08-28 02:41:02 +03:00
# endif
2016-08-11 23:52:33 +03:00
2016-08-28 02:41:02 +03:00
//////////////////////////////////////////////////////////////////////
2016-02-24 06:31:05 +03:00
2016-08-02 21:18:04 +03:00
} // END of namespace profiler.
2016-02-16 23:21:12 +03:00
2016-02-16 23:25:12 +03:00
# endif