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
# 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 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 {
template < 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
# include "profiler/profiler.h"
void foo ( )
{
// some code ...
if ( something ) {
2016-08-28 23:40:23 +03:00
EASY_BLOCK ( " Calling bar() " ) ; // Block with default color
bar ( ) ;
2016-03-03 14:55:38 +03:00
}
2016-08-28 23:40:23 +03:00
else {
EASY_BLOCK ( " Calling baz() " , profiler : : colors : : Red ) ; // Red block
baz ( ) ;
}
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, ...)\
static const : : profiler : : StaticBlockDescriptor EASY_UNIQUE_DESC ( __LINE__ ) ( EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_BLOCK , # # __VA_ARGS__ ) ; \
: : profiler : : Block EASY_UNIQUE_BLOCK ( __LINE__ ) ( : : profiler : : BLOCK_TYPE_BLOCK , EASY_UNIQUE_DESC ( __LINE__ ) . id ( ) , EASY_RUNTIME_NAME ( name ) ) ; \
: : 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
# include "profiler/profiler.h"
2016-08-28 23:40:23 +03:00
void foo ( ) {
EASY_FUNCTION ( ) ; // Block with name="foo" and default color
2016-03-03 14:55:38 +03:00
//some code...
}
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-28 23:40:23 +03:00
# define EASY_FUNCTION(...) EASY_BLOCK(__func__ , ## __VA_ARGS__)
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-03-03 14:55:38 +03:00
int sum = 0 ;
2016-08-28 23:40:23 +03:00
EASY_BLOCK ( " Calculating sum " ) ;
for ( int i = 0 ; i < 10 ; + + i ) {
2016-03-03 14:55:38 +03:00
sum + = i ;
}
2016-08-28 23:40:23 +03:00
EASY_END_BLOCK ;
// 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, ...)\
static const : : profiler : : StaticBlockDescriptor EASY_UNIQUE_DESC ( __LINE__ ) ( EASY_COMPILETIME_NAME ( name ) , __FILE__ , __LINE__ , \
: : profiler : : BLOCK_TYPE_EVENT , # # __VA_ARGS__ ) ; \
: : profiler : : Block EASY_UNIQUE_BLOCK ( __LINE__ ) ( : : profiler : : BLOCK_TYPE_EVENT , EASY_UNIQUE_DESC ( __LINE__ ) . id ( ) , EASY_RUNTIME_NAME ( name ) ) ; \
: : profiler : : beginBlock ( EASY_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 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-08-02 21:44:11 +03:00
# ifdef WIN32
2016-08-28 23:40:23 +03:00
# define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__);
2016-08-02 21:44:11 +03:00
# else
2016-08-28 23:40:23 +03:00
# define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__);
2016-08-02 21:44:11 +03:00
# endif
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
# 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-08-28 23:40:23 +03:00
void PROFILER_API setThreadName ( const char * name , const char * filename , const char * _funcname , int line ) ;
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 23:40:23 +03:00
Block ( block_type_t _block_type , block_id_t _id , const char * _name = " " ) ;
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-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 23:40:23 +03:00
StaticBlockDescriptor ( const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color = DefaultBlockColor ) ;
2016-08-28 02:41:02 +03:00
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
{
2016-08-28 23:40:23 +03:00
ThreadNameSetter ( const char * _name , const char * _filename , const char * _funcname , int _line )
2016-08-02 21:18:04 +03:00
{
2016-08-28 23:40:23 +03:00
setThreadName ( _name , _filename , _funcname , _line ) ;
2016-08-02 21:18:04 +03:00
}
} ;
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-08-28 23:40:23 +03:00
# endif // EASY_PROFILER____H_______