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-11 16:57:35 +03:00
# include "profiler/profiler_aux.h"
2016-02-16 23:21:12 +03:00
2016-08-31 21:51:22 +03:00
# if defined ( __clang__ )
2016-09-11 16:57:35 +03:00
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
2016-08-31 21:51:22 +03:00
# endif
2016-02-18 23:50:06 +03:00
# ifndef FULL_DISABLE_PROFILER
2016-02-16 23:21:12 +03:00
2016-03-03 14:55:38 +03:00
/**
\ defgroup profiler Profiler
*/
2016-09-11 16:57:35 +03:00
/** If != 0 then EasyProfiler will measure time for blocks storage expansion.
If 0 then EasyProfiler will be compiled without blocks of code responsible
for measuring these events .
2016-08-28 02:41:02 +03:00
2016-09-11 16:57:35 +03:00
These are " EasyProfiler.ExpandStorage " blocks on a diagram .
2016-03-03 14:55:38 +03:00
2016-09-11 16:57:35 +03:00
\ ingroup profiler
*/
# define EASY_MEASURE_STORAGE_EXPAND 0
2016-03-03 14:55:38 +03:00
2016-09-11 16:57:35 +03:00
/** If true then "EasyProfiler.ExpandStorage" events are enabled by default and will be
writed to output file or translated over the net .
If false then you need to enable these events via GUI if you ' ll want to see them .
\ ingroup profiler
*/
# define EASY_STORAGE_EXPAND_ENABLED true
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 ...
2016-09-11 16:57:35 +03:00
EASY_BLOCK ( " Check something " , profiler : : DISABLED ) ; // Disabled block (There is possibility to enable this block later via GUI)
2016-09-07 21:32:14 +03:00
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-11 16:57:35 +03:00
EASY_END_BLOCK ; // End of "Check something" block (Even if "Check something" is disabled, this EASY_END_BLOCK will not end any other block).
EASY_BLOCK ( " Some another block " , profiler : : colors : : Blue , profiler : : DISABLED ) ; // Disabled block with Blue color
// some another code...
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-09-11 16:57:35 +03:00
# define EASY_BLOCK(name, ...)\
2016-09-11 19:34:01 +03:00
static const : : profiler : : BlockDescRef EASY_UNIQUE_DESC ( __LINE__ ) ( : : profiler : : registerDescription ( : : profiler : : extract_enable_flag ( __VA_ARGS__ ) , \
EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_BLOCK , : : profiler : : extract_color ( __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-09-11 16:57:35 +03:00
void baz ( ) {
EASY_FUNCTION ( profiler : : DISABLED ) ; // Disabled block with name="baz" and default color (There is possibility to enable this block later via GUI)
// som 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-09-11 16:57:35 +03:00
# define EASY_FUNCTION(...)\
2016-09-11 19:34:01 +03:00
static const : : profiler : : BlockDescRef EASY_UNIQUE_DESC ( __LINE__ ) ( : : profiler : : registerDescription ( : : profiler : : extract_enable_flag ( __VA_ARGS__ ) , \
__func__ , __FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_BLOCK , : : profiler : : extract_color ( __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-09-11 16:57:35 +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
*/
2016-09-11 16:57:35 +03:00
# define EASY_EVENT(name, ...)\
2016-09-11 19:34:01 +03:00
static const : : profiler : : BlockDescRef EASY_UNIQUE_DESC ( __LINE__ ) ( \
2016-09-11 16:57:35 +03:00
: : profiler : : registerDescription ( : : profiler : : extract_enable_flag ( __VA_ARGS__ ) , EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , \
2016-09-11 19:34:01 +03:00
: : profiler : : BLOCK_TYPE_EVENT , : : profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
2016-09-09 00:09:47 +03:00
: : profiler : : storeBlock ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) ) ;
2016-03-03 14:55:38 +03:00
/** Macro enabling profiler
2016-09-11 16:57:35 +03:00
2016-03-03 14:55:38 +03:00
\ ingroup profiler
*/
2016-09-11 16:57:35 +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
2016-09-11 16:57:35 +03:00
2016-03-03 14:55:38 +03:00
\ ingroup profiler
*/
2016-09-11 16:57:35 +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-11 16:57:35 +03:00
# define EASY_THREAD(name)\
2016-09-06 23:03:05 +03:00
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
*/
2016-09-11 16:57:35 +03:00
# 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-09-11 16:57:35 +03:00
# define EASY_MEASURE_STORAGE_EXPAND 0
# define EASY_STORAGE_EXPAND_ENABLED false
# 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-09-11 16:57:35 +03:00
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
2016-02-16 23:21:12 +03:00
2016-08-14 22:22:44 +03:00
class ProfileManager ;
2016-09-11 16:57:35 +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-09-11 16:57:35 +03:00
//////////////////////////////////////////////////////////////////////
// Core types
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
2016-09-11 16:57:35 +03:00
//***********************************************
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-11 16:57:35 +03:00
BaseBlockDescriptor ( block_id_t _id , bool _enabled , 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-02-20 05:24:12 +03:00
2016-09-11 16:57:35 +03:00
} ; // END of class BaseBlockDescriptor.
2016-02-18 19:27:17 +03:00
2016-09-11 16:57:35 +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-09-11 16:57:35 +03:00
} ; // END of class BaseBlockData.
2016-08-28 02:41:02 +03:00
# pragma pack(pop)
2016-08-11 23:52:33 +03:00
2016-09-11 16:57:35 +03:00
//***********************************************
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
{
friend : : ProfileManager ;
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
BlockDescriptor ( uint64_t & _used_mem , bool _enabled , const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color ) ;
void setId ( block_id_t _id ) ;
public :
BlockDescriptor ( uint64_t & _used_mem , block_id_t _id , bool _enabled , const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color ) ;
inline const char * name ( ) const {
return m_name ;
}
inline const char * file ( ) const {
return m_filename ;
}
} ; // END of class BlockDescriptor.
//***********************************************
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-09-11 16:57:35 +03:00
friend : : ThreadStorage ;
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 :
2016-09-11 16:57:35 +03:00
void start ( ) ;
void start ( timestamp_t _time ) ;
2016-08-28 02:41:02 +03:00
void finish ( ) ;
2016-09-11 16:57:35 +03:00
void finish ( timestamp_t _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 ) ;
2016-09-11 16:57:35 +03:00
Block ( timestamp_t _begin_time , block_id_t _id , 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-09-11 16:57:35 +03:00
} ; // END of class Block.
//***********************************************
class PROFILER_API BlockDescRef final
{
const BaseBlockDescriptor & m_desc ;
public :
2016-09-11 19:34:01 +03:00
explicit BlockDescRef ( const BaseBlockDescriptor & _desc ) : m_desc ( _desc ) { }
2016-09-11 16:57:35 +03:00
inline operator const BaseBlockDescriptor & ( ) const { return m_desc ; }
~ BlockDescRef ( ) ;
private :
BlockDescRef ( ) = delete ;
BlockDescRef ( const BlockDescRef & ) = delete ;
BlockDescRef & operator = ( const BlockDescRef & ) = delete ;
} ; // END of class BlockDescRef.
//////////////////////////////////////////////////////////////////////
// Core API
extern " C " {
PROFILER_API const BaseBlockDescriptor & registerDescription ( bool _enabled , const char * _compiletimeName , const char * _filename , int _line , block_type_t _block_type , color_t _color ) ;
PROFILER_API void storeBlock ( const BaseBlockDescriptor & _desc , const char * _runtimeName ) ;
PROFILER_API void beginBlock ( Block & _block ) ;
PROFILER_API void endBlock ( ) ;
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 ) ;
PROFILER_API const char * getContextSwitchLogFilename ( ) ;
}
inline void setEnabled ( : : profiler : : EasyEnableFlag _isEnable ) {
setEnabled ( _isEnable = = : : profiler : : ENABLED ) ;
}
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__ )
2016-09-11 16:57:35 +03:00
# pragma clang diagnostic pop
2016-08-31 21:51:22 +03:00
# endif
2016-08-28 23:40:23 +03:00
# endif // EASY_PROFILER____H_______