mirror of
https://github.com/yse/easy_profiler.git
synced 2025-01-14 16:47:55 +08:00
Remastering profiler API (not compiling yet)
This commit is contained in:
parent
3a2c8aaef1
commit
439e1cfb44
@ -19,19 +19,31 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#ifndef ____PROFILER____H_______
|
#ifndef ____PROFILER____H_______
|
||||||
#define ____PROFILER____H_______
|
#define ____PROFILER____H_______
|
||||||
|
|
||||||
#define TOKEN_JOIN(x, y) x ## y
|
|
||||||
#define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y)
|
|
||||||
|
|
||||||
#if defined ( WIN32 )
|
#if defined ( WIN32 )
|
||||||
#define __func__ __FUNCTION__
|
#define __func__ __FUNCTION__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FULL_DISABLE_PROFILER
|
#ifndef FULL_DISABLE_PROFILER
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\defgroup profiler Profiler
|
\defgroup profiler Profiler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** 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"
|
||||||
|
|
||||||
|
|
||||||
/** Macro of beginning of block with custom name and default identification
|
/** Macro of beginning of block with custom name and default identification
|
||||||
|
|
||||||
\code
|
\code
|
||||||
@ -51,11 +63,26 @@ Block will be automatically completed by destructor
|
|||||||
|
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_BEGIN_BLOCK(name)\
|
#define PROFILER_BEGIN_BLOCK(compiletime_name)\
|
||||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)(compiletime_name, __FILE__, __LINE__,\
|
||||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,profiler::colors::Clay,profiler::BLOCK_TYPE_BLOCK,\
|
::profiler::BLOCK_TYPE_BLOCK, ::profiler::DefaultBlockColor);\
|
||||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(compiletime_name COMPILETIME_TEST, ::profiler::BLOCK_TYPE_BLOCK,\
|
||||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
PROFILER_UNIQUE_DESC(__LINE__).id(), compiletime_name);\
|
||||||
|
::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
|
||||||
|
|
||||||
|
#define EASY_BLOCK_DYNAMIC(compiletime_name, runtime_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(), runtime_name);\
|
||||||
|
::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||||
|
|
||||||
/** Macro of beginning of block with custom name and custom identification
|
/** Macro of beginning of block with custom name and custom identification
|
||||||
|
|
||||||
@ -65,7 +92,7 @@ Block will be automatically completed by destructor
|
|||||||
{
|
{
|
||||||
// some code ...
|
// some code ...
|
||||||
if(something){
|
if(something){
|
||||||
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()",profiler::colors::Red);
|
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()", ::profiler::colors::Red);
|
||||||
someThirdPartyLongFunction();
|
someThirdPartyLongFunction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -76,11 +103,12 @@ Block will be automatically completed by destructor
|
|||||||
|
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)\
|
#define PROFILER_BEGIN_BLOCK_GROUPED(compiletime_name, block_group)\
|
||||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)(compiletime_name, __FILE__, __LINE__,\
|
||||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK,\
|
::profiler::BLOCK_TYPE_BLOCK, block_group);\
|
||||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(compiletime_name COMPILETIME_TEST, ::profiler::BLOCK_TYPE_BLOCK,\
|
||||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
PROFILER_UNIQUE_DESC(__LINE__).id());\
|
||||||
|
::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||||
|
|
||||||
/** Macro of beginning of function block with default identification
|
/** Macro of beginning of function block with default identification
|
||||||
|
|
||||||
@ -114,7 +142,7 @@ Name of block automatically created with function name
|
|||||||
|
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_color) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_color)
|
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_color) PROFILER_BEGIN_BLOCK_GROUPED(__func__, block_color)
|
||||||
|
|
||||||
/** Macro of completion of last nearest open block
|
/** Macro of completion of last nearest open block
|
||||||
|
|
||||||
@ -134,56 +162,56 @@ void foo()
|
|||||||
|
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
#define PROFILER_END_BLOCK ::profiler::endBlock();
|
||||||
|
|
||||||
#define PROFILER_ADD_EVENT(name) \
|
#define PROFILER_ADD_EVENT(compiletime_name) \
|
||||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)(compiletime_name, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT);\
|
||||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_EVENT,\
|
::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(compiletime_name COMPILETIME_TEST, ::profiler::BLOCK_TYPE_EVENT,\
|
||||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
PROFILER_UNIQUE_DESC(__LINE__).id());\
|
||||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||||
|
|
||||||
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)\
|
#define PROFILER_ADD_EVENT_GROUPED(compiletime_name, block_group)\
|
||||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)(compiletime_name, __FILE__, __LINE__,\
|
||||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_EVENT,\
|
::profiler::BLOCK_TYPE_EVENT, block_group);\
|
||||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(compiletime_name COMPILETIME_TEST, ::profiler::BLOCK_TYPE_EVENT,\
|
||||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
PROFILER_UNIQUE_DESC(__LINE__).id());\
|
||||||
|
::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||||
|
|
||||||
/** Macro enabling profiler
|
/** Macro enabling profiler
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
#define PROFILER_ENABLE ::profiler::setEnabled(true);
|
||||||
|
|
||||||
/** Macro disabling profiler
|
/** Macro disabling profiler
|
||||||
\ingroup profiler
|
\ingroup profiler
|
||||||
*/
|
*/
|
||||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
#define PROFILER_DISABLE ::profiler::setEnabled(false);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define PROFILER_SET_THREAD_NAME(name) profiler::setThreadName(name);
|
#define PROFILER_SET_THREAD_NAME(name) ::profiler::setThreadName(name);
|
||||||
#else
|
#else
|
||||||
#define PROFILER_SET_THREAD_NAME(name) thread_local static const profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_,__LINE__)(name);
|
#define PROFILER_SET_THREAD_NAME(name) thread_local static const ::profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
|
#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define PROFILER_ADD_MARK(name)
|
|
||||||
#define PROFILER_ADD_MARK_GROUPED(name,block_group)
|
|
||||||
#define PROFILER_BEGIN_BLOCK(name)
|
#define PROFILER_BEGIN_BLOCK(name)
|
||||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)
|
#define PROFILER_BEGIN_BLOCK_GROUPED(name, block_group)
|
||||||
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
|
#define PROFILER_BEGIN_FUNCTION_BLOCK
|
||||||
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_group)
|
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group)
|
||||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
#define PROFILER_END_BLOCK
|
||||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
#define PROFILER_ENABLE
|
||||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
#define PROFILER_DISABLE
|
||||||
#define PROFILER_ADD_EVENT(name)
|
#define PROFILER_ADD_EVENT(name)
|
||||||
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)
|
#define PROFILER_ADD_EVENT_GROUPED(name, block_group)
|
||||||
#define PROFILER_SET_THREAD_NAME(name)
|
#define PROFILER_SET_THREAD_NAME(name)
|
||||||
#define PROFILER_SET_MAIN_THREAD
|
#define PROFILER_SET_MAIN_THREAD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include "profiler/profiler_colors.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef _BUILD_PROFILER
|
#ifdef _BUILD_PROFILER
|
||||||
@ -196,62 +224,12 @@ void foo()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
class ProfileManager;
|
class ProfileManager;
|
||||||
|
class ThreadStorage;
|
||||||
|
|
||||||
namespace profiler
|
namespace profiler {
|
||||||
{
|
|
||||||
typedef uint8_t color_t; //RRR-GGG-BB
|
|
||||||
|
|
||||||
namespace colors{
|
|
||||||
|
|
||||||
const color_t Black = 0x00;
|
|
||||||
const color_t Lightgray = 0x6E;
|
|
||||||
const color_t Darkgray = 0x25;
|
|
||||||
const color_t White = 0xFF;
|
|
||||||
const color_t Red = 0xE0;
|
|
||||||
const color_t Green = 0x1C;
|
|
||||||
const color_t Blue = 0x03;
|
|
||||||
const color_t Magenta = (Red | Blue);
|
|
||||||
const color_t Cyan = (Green | Blue);
|
|
||||||
const color_t Yellow = (Red | Green);
|
|
||||||
const color_t Darkred = 0x60;
|
|
||||||
const color_t Darkgreen = 0x0C;
|
|
||||||
const color_t Darkblue = 0x01;
|
|
||||||
const color_t Darkmagenta = (Darkred | Darkblue);
|
|
||||||
const color_t Darkcyan = (Darkgreen | Darkblue);
|
|
||||||
const color_t Darkyellow = (Darkred | Darkgreen);
|
|
||||||
const color_t Navy = 0x02;
|
|
||||||
const color_t Teal = 0x12;
|
|
||||||
const color_t Maroon = 0x80;
|
|
||||||
const color_t Purple = 0x82;
|
|
||||||
const color_t Olive = 0x90;
|
|
||||||
const color_t Grey = 0x92;
|
|
||||||
const color_t Silver = 0xDB;
|
|
||||||
const color_t Orange = 0xF4;
|
|
||||||
const color_t Coral = 0xF6;
|
|
||||||
const color_t Brick = 0xED;
|
|
||||||
const color_t Clay = 0xD6;
|
|
||||||
const color_t Skin = 0xFA;
|
|
||||||
const color_t Palegold = 0xFE;
|
|
||||||
|
|
||||||
inline int get_red(color_t color){
|
|
||||||
return (color >> 5) * 0x20;
|
|
||||||
}
|
|
||||||
inline int get_green(color_t color){
|
|
||||||
return ((color & 0x1C) >> 2) * 0x20;
|
|
||||||
}
|
|
||||||
inline int get_blue(color_t color){
|
|
||||||
return (color & 3) * 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int convert_to_rgb(color_t color){
|
|
||||||
return ((get_red(color) & 0xFF) << 16) | ((get_green(color) & 0xFF) << 8) | (get_blue(color) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Block;
|
class Block;
|
||||||
class BlockSourceInfo;
|
class StaticBlockDescriptor;
|
||||||
|
|
||||||
extern "C"{
|
extern "C"{
|
||||||
void PROFILER_API beginBlock(Block& _block);
|
void PROFILER_API beginBlock(Block& _block);
|
||||||
@ -261,115 +239,104 @@ namespace profiler
|
|||||||
void PROFILER_API setThreadName(const char* name);
|
void PROFILER_API setThreadName(const char* name);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef uint8_t block_type_t;
|
|
||||||
typedef uint64_t timestamp_t;
|
typedef uint64_t timestamp_t;
|
||||||
typedef uint32_t thread_id_t;
|
typedef uint32_t thread_id_t;
|
||||||
typedef uint32_t source_id_t;
|
typedef uint32_t block_id_t;
|
||||||
|
|
||||||
const block_type_t BLOCK_TYPE_EVENT = 1;
|
enum BlockType : uint8_t
|
||||||
const block_type_t BLOCK_TYPE_BLOCK = 2;
|
{
|
||||||
const block_type_t BLOCK_TYPE_THREAD_SIGN = 3;
|
BLOCK_TYPE_EVENT = 0,
|
||||||
|
BLOCK_TYPE_BLOCK,
|
||||||
|
BLOCK_TYPE_THREAD_SIGN,
|
||||||
|
BLOCK_TYPE_CONTEXT_SWITCH,
|
||||||
|
|
||||||
#define EASY_USE_OLD_FILE_FORMAT
|
BLOCK_TYPES_NUMBER
|
||||||
|
};
|
||||||
|
typedef BlockType block_type_t;
|
||||||
|
|
||||||
#pragma pack(push,1)
|
#pragma pack(push,1)
|
||||||
class PROFILER_API BaseBlockData
|
class PROFILER_API BaseBlockDescriptor
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
int m_line; ///< Line number in the source file
|
||||||
block_type_t type;
|
block_type_t m_type; ///< Type of the block (See BlockType)
|
||||||
color_t color;
|
color_t m_color; ///< Color of the block packed into 1-byte structure
|
||||||
timestamp_t begin;
|
|
||||||
timestamp_t end;
|
|
||||||
thread_id_t thread_id;
|
|
||||||
#else
|
|
||||||
timestamp_t begin;
|
|
||||||
timestamp_t end;
|
|
||||||
thread_id_t thread_id;
|
|
||||||
source_id_t source_id;
|
|
||||||
block_type_t type;
|
|
||||||
color_t color;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void tick(timestamp_t& stamp);
|
BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color);
|
||||||
public:
|
|
||||||
|
|
||||||
BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id = 0);
|
public:
|
||||||
|
|
||||||
inline block_type_t getType() const { return type; }
|
inline int line() const { return m_line; }
|
||||||
inline color_t getColor() const { return color; }
|
inline block_type_t type() const { return m_type; }
|
||||||
inline timestamp_t getBegin() const { return begin; }
|
inline color_t color() const { return m_color; }
|
||||||
inline thread_id_t getThreadId() const { return thread_id; }
|
inline rgb32_t rgb() const { return ::profiler::colors::convert_to_rgb(m_color); }
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
|
||||||
inline source_id_t getSourceId() const { return -1; }
|
{
|
||||||
#else
|
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
|
||||||
inline source_id_t getSourceId() const { return source_id; }
|
const char* m_filename; ///< Source file name where this block is declared
|
||||||
#endif
|
|
||||||
|
|
||||||
inline timestamp_t getEnd() const { return end; }
|
public:
|
||||||
inline bool isFinished() const { return end != 0; }
|
|
||||||
inline bool isCleared() const { return end >= begin; }
|
|
||||||
inline void finish(){ tick(end); }
|
|
||||||
timestamp_t duration() const { return (end - begin); }
|
|
||||||
|
|
||||||
inline bool startsEarlierThan(const BaseBlockData& another) const {return this->begin < another.begin;}
|
BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
|
||||||
inline bool endsEarlierThan(const BaseBlockData& another) const {return this->end < another.end;}
|
|
||||||
inline bool startsLaterThan(const BaseBlockData& another) const {return !this->startsEarlierThan(another);}
|
const char* name() const { return m_name; }
|
||||||
inline bool endsLaterThan(const BaseBlockData& another) const {return !this->endsEarlierThan(another);}
|
const char* file() const { return m_filename; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PROFILER_API BaseBlockData
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
timestamp_t m_begin;
|
||||||
|
timestamp_t m_end;
|
||||||
|
block_id_t m_id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
BaseBlockData(timestamp_t _begin_time, block_id_t _id);
|
||||||
|
|
||||||
|
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; }
|
||||||
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
class PROFILER_API Block final : public BaseBlockData
|
class PROFILER_API Block final : public BaseBlockData
|
||||||
{
|
|
||||||
const char* m_name;
|
|
||||||
public:
|
|
||||||
|
|
||||||
Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id);
|
|
||||||
Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id);
|
|
||||||
~Block();
|
|
||||||
|
|
||||||
inline const char* getName() const { return m_name; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class PROFILER_API SourceBlock final
|
|
||||||
{
|
|
||||||
const char* m_filename;
|
|
||||||
int m_line;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SourceBlock(const char* _filename, int _line);
|
|
||||||
|
|
||||||
const char* file() const { return m_filename; }
|
|
||||||
int line() const { return m_line; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class PROFILER_API SerializedBlock final : public BaseBlockData
|
|
||||||
{
|
{
|
||||||
friend ::ProfileManager;
|
friend ::ProfileManager;
|
||||||
|
|
||||||
public:
|
const char* m_name;
|
||||||
|
|
||||||
///< Deprecated. For backward compatibility.
|
|
||||||
inline const BaseBlockData* block() const { return this; }
|
|
||||||
|
|
||||||
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
|
||||||
inline const char* getName() const { return data() + sizeof(BaseBlockData); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static SerializedBlock* create(const Block &block, uint64_t& memory_size);
|
void finish();
|
||||||
static void destroy(SerializedBlock* that);
|
inline bool isFinished() const { return m_end >= m_begin; }
|
||||||
|
|
||||||
SerializedBlock(const profiler::Block& block, uint16_t name_length);
|
public:
|
||||||
|
|
||||||
SerializedBlock(const SerializedBlock&) = delete;
|
Block(const char*, block_type_t _block_type, block_id_t _id, const char* _name = "");
|
||||||
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
~Block();
|
||||||
~SerializedBlock() = delete;
|
|
||||||
|
inline const char* name() const { return m_name; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class PROFILER_API StaticBlockDescriptor final
|
||||||
|
{
|
||||||
|
block_id_t m_id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
struct PROFILER_API ThreadNameSetter final
|
struct PROFILER_API ThreadNameSetter final
|
||||||
{
|
{
|
||||||
ThreadNameSetter(const char* _name)
|
ThreadNameSetter(const char* _name)
|
||||||
@ -377,17 +344,9 @@ namespace profiler
|
|||||||
setThreadName(_name);
|
setThreadName(_name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class PROFILER_API BlockSourceInfo final
|
//////////////////////////////////////////////////////////////////////
|
||||||
{
|
|
||||||
unsigned int m_id;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
BlockSourceInfo(const char* _filename, int _linenumber);
|
|
||||||
|
|
||||||
unsigned int id() const { return m_id; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // END of namespace profiler.
|
} // END of namespace profiler.
|
||||||
|
|
||||||
|
109
include/profiler/profiler_colors.h
Normal file
109
include/profiler/profiler_colors.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
Lightweight profiler library for c++
|
||||||
|
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef EASY_PROFILER__COLORS__H_______
|
||||||
|
#define EASY_PROFILER__COLORS__H_______
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace profiler {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef uint8_t color_t; // One-byte RGB color format: RRR-GGG-BB
|
||||||
|
typedef uint32_t rgb32_t; // Standard four-byte RGB color format
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace colors {
|
||||||
|
|
||||||
|
///< Extracts [0 .. 224] Red value from one-byte RGB format. Possible values are: [0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xe0].
|
||||||
|
inline rgb32_t get_red(color_t color) { return color & 0xe0; }
|
||||||
|
|
||||||
|
///< Extracts [0 .. 224] Green value from one-byte RGB format. Possible values are: [0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xe0].
|
||||||
|
inline rgb32_t get_green(color_t color) { return (color & 0x1c) << 3; }
|
||||||
|
|
||||||
|
///< Extracts [0 .. 192] Blue value from one-byte RGB format. Possible values are: [0x0, 0x40, 0x80, 0xc0]
|
||||||
|
inline rgb32_t get_blue(color_t color) { return (color & 3) << 6; }
|
||||||
|
|
||||||
|
|
||||||
|
///< Extracts [0 .. 255] Red value from four-byte RGB format.
|
||||||
|
inline rgb32_t rgb_red(rgb32_t color) { return (color & 0x00ff0000) >> 16; }
|
||||||
|
|
||||||
|
///< Extracts [0 .. 255] Green value from four-byte RGB format.
|
||||||
|
inline rgb32_t rgb_green(rgb32_t color) { return (color & 0x0000ff00) >> 8; }
|
||||||
|
|
||||||
|
///< Extracts [0 .. 255] Blue value from four-byte RGB format.
|
||||||
|
inline rgb32_t rgb_blue(rgb32_t color) { return color & 0x000000ff; }
|
||||||
|
|
||||||
|
///< Unpacks one-byte RGB value into standard four-byte RGB value.
|
||||||
|
inline rgb32_t convert_to_rgb(color_t color) { return (get_red(color) << 16) | ((color & 0x1c) << 11) | get_blue(color); }
|
||||||
|
|
||||||
|
///< Packs standard four-byte RGB value into one-byte RGB value. R & G values packed with 0x20 (32) step, B value is packed with 0x40 (64) step.
|
||||||
|
inline color_t from_rgb(rgb32_t color) { return (rgb_red(color) & 0xe0) | (((color & 0x0000ff00) >> 11) & 0x1c) | (rgb_blue(color) >> 6); }
|
||||||
|
|
||||||
|
///< Packs standard four-byte RGB value into one-byte RGB value. R & G values packed with 0x20 (32) step, B value is packed with 0x40 (64) step.
|
||||||
|
inline color_t from_rgb(color_t red, color_t green, color_t blue) { return (red & 0xe0) | ((green >> 3) & 0x1c) | (blue >> 6); }
|
||||||
|
|
||||||
|
|
||||||
|
const color_t Black = 0x00; // 0x00000000
|
||||||
|
const color_t Random = Black; // Black // Currently GUI interprets Black color as permission to select random color for block
|
||||||
|
const color_t Lightgray = 0x6E; // 0x00606080
|
||||||
|
const color_t Darkgray = 0x25; // 0x00202040
|
||||||
|
const color_t White = 0xFF; // 0x00E0E0C0
|
||||||
|
const color_t Red = 0xE0; // 0x00E00000
|
||||||
|
const color_t Green = 0x1C; // 0x0000E000
|
||||||
|
const color_t Blue = 0x03; // 0x000000C0
|
||||||
|
const color_t Magenta = (Red | Blue); // 0x00E000C0
|
||||||
|
const color_t Cyan = (Green | Blue); // 0x0000E0C0
|
||||||
|
const color_t Yellow = (Red | Green); // 0x00E0E000
|
||||||
|
const color_t Darkred = 0x60; // 0x00600000
|
||||||
|
const color_t Darkgreen = 0x0C; // 0x00006000
|
||||||
|
const color_t Darkblue = 0x01; // 0x00000040
|
||||||
|
const color_t Darkmagenta = (Darkred | Darkblue); // 0x00600040
|
||||||
|
const color_t Darkcyan = (Darkgreen | Darkblue); // 0x00006040
|
||||||
|
const color_t Darkyellow = (Darkred | Darkgreen); // 0x00606000
|
||||||
|
const color_t Navy = 0x02; // 0x00000080
|
||||||
|
const color_t Teal = 0x12; // 0x00008080
|
||||||
|
const color_t Maroon = 0x80; // 0x00800000
|
||||||
|
const color_t Purple = 0x82; // 0x00800080
|
||||||
|
const color_t Olive = 0x90; // 0x00808000
|
||||||
|
const color_t Grey = 0x92; // 0x00808080
|
||||||
|
const color_t Silver = 0xDB; // 0x00C0C0C0
|
||||||
|
const color_t Orange = 0xF4; // 0x00E0A000
|
||||||
|
const color_t Coral = 0xF6; // 0x00E0A080
|
||||||
|
const color_t Brick = 0xED; // 0x00E06040
|
||||||
|
const color_t Clay = 0xD6; // 0x00C0A080
|
||||||
|
const color_t Skin = 0xFA; // 0x00E0C080
|
||||||
|
const color_t Palegold = 0xFE; // 0x00E0E080
|
||||||
|
|
||||||
|
} // END of namespace colors.
|
||||||
|
|
||||||
|
const color_t DefaultBlockColor = colors::Clay;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
} // END of namespace profiler.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif // EASY_PROFILER__COLORS__H_______
|
@ -25,6 +25,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "profiler/profiler.h"
|
#include "profiler/profiler.h"
|
||||||
|
#include "profiler/serialized_block.h"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
81
include/profiler/serialized_block.h
Normal file
81
include/profiler/serialized_block.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
Lightweight profiler library for c++
|
||||||
|
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef EASY_PROFILER_SERIALIZED_BLOCK__H_______
|
||||||
|
#define EASY_PROFILER_SERIALIZED_BLOCK__H_______
|
||||||
|
|
||||||
|
#include "profiler/profiler.h"
|
||||||
|
|
||||||
|
namespace profiler {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class PROFILER_API SerializedBlock final : public BaseBlockData
|
||||||
|
{
|
||||||
|
friend ::ProfileManager;
|
||||||
|
friend ::ThreadStorage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
||||||
|
inline const char* name() const { return data() + sizeof(BaseBlockData); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SerializedBlock(const ::profiler::Block& block, uint16_t name_length);
|
||||||
|
|
||||||
|
SerializedBlock(const SerializedBlock&) = delete;
|
||||||
|
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
||||||
|
~SerializedBlock() = delete;
|
||||||
|
|
||||||
|
}; // END of SerializedBlock.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class PROFILER_API SerializedBlockDescriptor final : public BaseBlockDescriptor
|
||||||
|
{
|
||||||
|
uint16_t m_nameLength;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline const char* data() const {
|
||||||
|
return reinterpret_cast<const char*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* name() const {
|
||||||
|
static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength));
|
||||||
|
return data() + shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* file() const {
|
||||||
|
return name() + m_nameLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete;
|
||||||
|
SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete;
|
||||||
|
~SerializedBlockDescriptor() = delete;
|
||||||
|
|
||||||
|
}; // END of SerializedBlockDescriptor.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
} // END of namespace profiler.
|
||||||
|
|
||||||
|
#endif // EASY_PROFILER_SERIALIZED_BLOCK__H_______
|
@ -13,35 +13,6 @@ struct ProfPerformanceFrequency {
|
|||||||
} const WINDOWS_CPU_INFO;
|
} const WINDOWS_CPU_INFO;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BaseBlockData::BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id)
|
|
||||||
: begin(0)
|
|
||||||
, end(0)
|
|
||||||
, thread_id(_thread_id)
|
|
||||||
#ifndef EASY_USE_OLD_FILE_FORMAT
|
|
||||||
, source_id(_source_id)
|
|
||||||
#endif
|
|
||||||
, type(_type)
|
|
||||||
, color(_color)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Block::Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id)
|
|
||||||
: Block(_name, getCurrentThreadId(), _color, _type, _source_id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Block::Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id)
|
|
||||||
: BaseBlockData(_source_id, _color, _type, _thread_id)
|
|
||||||
, m_name(_name)
|
|
||||||
{
|
|
||||||
tick(begin);
|
|
||||||
if (BLOCK_TYPE_BLOCK != this->type)
|
|
||||||
{
|
|
||||||
end = begin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline timestamp_t getCurrentTime()
|
inline timestamp_t getCurrentTime()
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -59,20 +30,31 @@ inline timestamp_t getCurrentTime()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseBlockData::tick(timestamp_t& stamp)
|
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
|
||||||
|
: m_begin(_begin_time)
|
||||||
|
, m_end(0)
|
||||||
|
, m_id(_descriptor_id)
|
||||||
{
|
{
|
||||||
stamp = getCurrentTime();
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Block::Block(const char*, block_type_t _block_type, block_id_t _descriptor_id, const char* _name)
|
||||||
|
: BaseBlockData(getCurrentTime(), _descriptor_id)
|
||||||
|
, m_name(_name)
|
||||||
|
{
|
||||||
|
if (_block_type != BLOCK_TYPE_BLOCK)
|
||||||
|
{
|
||||||
|
m_end = m_begin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Block::finish()
|
||||||
|
{
|
||||||
|
m_end = getCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::~Block()
|
Block::~Block()
|
||||||
{
|
{
|
||||||
if (this->type == BLOCK_TYPE_BLOCK)
|
if (!isFinished())
|
||||||
{
|
::profiler::endBlock();
|
||||||
if (this->isCleared())//this block was cleared by END_BLOCK macros
|
|
||||||
return;
|
|
||||||
if (!this->isFinished())
|
|
||||||
this->finish();
|
|
||||||
|
|
||||||
endBlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "profile_manager.h"
|
#include "profile_manager.h"
|
||||||
|
#include "profiler/serialized_block.h"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -36,39 +37,47 @@ extern "C"{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializedBlock* SerializedBlock::create(const Block& block, uint64_t& memory_size)
|
|
||||||
{
|
|
||||||
auto name_length = static_cast<uint16_t>(strlen(block.getName()));
|
|
||||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
|
||||||
auto data = ::new char[size];
|
|
||||||
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
|
|
||||||
memory_size += size;
|
|
||||||
return reinterpret_cast<SerializedBlock*>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerializedBlock::destroy(SerializedBlock* that)
|
|
||||||
{
|
|
||||||
::delete[] reinterpret_cast<char*>(that);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
||||||
: BaseBlockData(block)
|
: BaseBlockData(block)
|
||||||
{
|
{
|
||||||
auto name = const_cast<char*>(getName());
|
auto pName = const_cast<char*>(name());
|
||||||
strncpy(name, block.getName(), name_length);
|
if (name_length) strncpy(pName, block.name(), name_length);
|
||||||
name[name_length] = 0;
|
pName[name_length] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
BlockSourceInfo::BlockSourceInfo(const char* _filename, int _linenumber) : m_id(MANAGER.addSource(_filename, _linenumber))
|
StaticBlockDescriptor::StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||||
|
: m_id(MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceBlock::SourceBlock(const char* _filename, int _line) : m_filename(_filename), m_line(_line)
|
BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||||
|
: BaseBlockDescriptor(_line, _block_type, _color)
|
||||||
|
, m_name(_name)
|
||||||
|
, m_filename(_filename)
|
||||||
{
|
{
|
||||||
|
_used_mem += sizeof(profiler::BaseBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ThreadStorage::store(const profiler::Block& block)
|
||||||
|
{
|
||||||
|
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
||||||
|
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
||||||
|
auto data = m_allocator.allocate(size);
|
||||||
|
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
|
||||||
|
usedMemorySize += size;
|
||||||
|
closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadStorage::clearClosed()
|
||||||
|
{
|
||||||
|
serialized_list_t().swap(closedList);
|
||||||
|
m_allocator.clear();
|
||||||
|
usedMemorySize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -94,37 +103,31 @@ ProfileManager& ProfileManager::instance()
|
|||||||
void ProfileManager::beginBlock(Block& _block)
|
void ProfileManager::beginBlock(Block& _block)
|
||||||
{
|
{
|
||||||
if (!m_isEnabled)
|
if (!m_isEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (BLOCK_TYPE_BLOCK == _block.getType()){
|
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||||
guard_lock_t lock(m_spin);
|
|
||||||
m_openedBracketsMap[_block.getThreadId()].emplace(_block);
|
if (!_block.isFinished())
|
||||||
}
|
thread_storage.openedList.emplace(_block);
|
||||||
else{
|
else
|
||||||
_internalInsertBlock(_block);
|
thread_storage.store(_block);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::endBlock()
|
void ProfileManager::endBlock()
|
||||||
{
|
{
|
||||||
|
if (!m_isEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!m_isEnabled)
|
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||||
return;
|
if (thread_storage.openedList.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
uint32_t threadId = getCurrentThreadId();
|
Block& lastBlock = thread_storage.openedList.top();
|
||||||
|
if (!lastBlock.isFinished())
|
||||||
guard_lock_t lock(m_spin);
|
|
||||||
auto& stackOfOpenedBlocks = m_openedBracketsMap[threadId];
|
|
||||||
|
|
||||||
if (stackOfOpenedBlocks.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Block& lastBlock = stackOfOpenedBlocks.top();
|
|
||||||
if(!lastBlock.isFinished())
|
|
||||||
lastBlock.finish();
|
lastBlock.finish();
|
||||||
_internalInsertBlock(lastBlock);
|
|
||||||
|
|
||||||
stackOfOpenedBlocks.pop();
|
thread_storage.store(lastBlock);
|
||||||
|
thread_storage.openedList.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::setEnabled(bool isEnable)
|
void ProfileManager::setEnabled(bool isEnable)
|
||||||
@ -132,58 +135,63 @@ void ProfileManager::setEnabled(bool isEnable)
|
|||||||
m_isEnabled = isEnable;
|
m_isEnabled = isEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::_internalInsertBlock(const profiler::Block& _block)
|
uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
|
||||||
{
|
{
|
||||||
guard_lock_t lock(m_storedSpin);
|
std::ofstream of(filename, std::fstream::binary);
|
||||||
m_blocks.emplace_back(SerializedBlock::create(_block, m_blocksMemorySize));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ProfileManager::dumpBlocksToFile(const char* filename)
|
uint64_t usedMemorySize = 0;
|
||||||
{
|
uint32_t blocks_number = 0;
|
||||||
::std::ofstream of(filename, std::fstream::binary);
|
for (const auto& thread_storage : m_threads)
|
||||||
|
|
||||||
auto blocks_number = static_cast<uint32_t>(m_blocks.size());
|
|
||||||
//of.write((const char*)&blocks_number, sizeof(uint32_t));
|
|
||||||
of.write((const char*)&m_blocksMemorySize, sizeof(uint64_t));
|
|
||||||
|
|
||||||
for (auto b : m_blocks)
|
|
||||||
{
|
{
|
||||||
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(b->getName()) + 1);
|
usedMemorySize += thread_storage.second.usedMemorySize;
|
||||||
|
blocks_number += static_cast<uint32_t>(thread_storage.second.closedList.size());
|
||||||
of.write((const char*)&sz, sizeof(uint16_t));
|
|
||||||
of.write(b->data(), sz);
|
|
||||||
|
|
||||||
SerializedBlock::destroy(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_blocksMemorySize = 0;
|
of.write((const char*)&blocks_number, sizeof(decltype(blocks_number)));
|
||||||
m_blocks.clear();
|
of.write((const char*)&usedMemorySize, sizeof(decltype(usedMemorySize)));
|
||||||
|
|
||||||
|
auto descriptors_number = static_cast<uint32_t>(m_descriptors.size());
|
||||||
|
of.write((const char*)&descriptors_number, sizeof(decltype(descriptors_number)));
|
||||||
|
of.write((const char*)&m_usedMemorySize, sizeof(decltype(m_usedMemorySize)));
|
||||||
|
for (const auto& descriptor : m_descriptors)
|
||||||
|
{
|
||||||
|
const auto name_size = static_cast<uint16_t>(strlen(descriptor.name()) + 1);
|
||||||
|
const auto filename_size = static_cast<uint16_t>(strlen(descriptor.file()) + 1);
|
||||||
|
const auto size = static_cast<uint16_t>(sizeof(profiler::BaseBlockDescriptor)) + name_size + filename_size + sizeof(uint16_t);
|
||||||
|
|
||||||
|
of.write((const char*)&size, sizeof(uint16_t));
|
||||||
|
of.write((const char*)&descriptor, sizeof(profiler::BaseBlockDescriptor));
|
||||||
|
of.write((const char*)&name_size, sizeof(uint16_t));
|
||||||
|
of.write(descriptor.name(), name_size);
|
||||||
|
of.write(descriptor.file(), filename_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& thread_storage : m_threads)
|
||||||
|
{
|
||||||
|
of.write((const char*)&thread_storage.first, sizeof(decltype(thread_storage.first)));
|
||||||
|
|
||||||
|
for (auto b : thread_storage.second.closedList)
|
||||||
|
{
|
||||||
|
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(b->name()) + 1);
|
||||||
|
of.write((const char*)&sz, sizeof(uint16_t));
|
||||||
|
of.write(b->data(), sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_storage.second.clearClosed();
|
||||||
|
}
|
||||||
|
|
||||||
return blocks_number;
|
return blocks_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::setThreadName(const char* name)
|
void ProfileManager::setThreadName(const char* name)
|
||||||
{
|
{
|
||||||
auto current_thread_id = getCurrentThreadId();
|
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||||
|
if (thread_storage.named)
|
||||||
guard_lock_t lock(m_storedSpin);
|
|
||||||
auto find_it = m_namedThreades.find(current_thread_id);
|
|
||||||
if (find_it != m_namedThreades.end())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
profiler::Block block(name, current_thread_id, 0, profiler::BLOCK_TYPE_THREAD_SIGN);
|
const auto id = addBlockDescriptor("ThreadName", __FILE__, __LINE__, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random);
|
||||||
m_blocks.emplace_back(SerializedBlock::create(block, m_blocksMemorySize));
|
thread_storage.store(profiler::Block(nullptr, profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
|
||||||
m_namedThreades.insert(current_thread_id);
|
thread_storage.named = true;
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
unsigned int ProfileManager::addSource(const char* _filename, int _line)
|
|
||||||
{
|
|
||||||
guard_lock_t lock(m_storedSpin);
|
|
||||||
const auto id = static_cast<unsigned int>(m_sources.size());
|
|
||||||
m_sources.emplace_back(_filename, _line);
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -30,6 +30,8 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#else
|
#else
|
||||||
@ -46,36 +48,89 @@ inline uint32_t getCurrentThreadId()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace profiler { class SerializedBlock; }
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <class T, uint16_t N>
|
||||||
|
class chunk_allocator final
|
||||||
|
{
|
||||||
|
struct chunk {
|
||||||
|
T data[N] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<chunk> m_chunks;
|
||||||
|
uint16_t m_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
chunk_allocator() : m_size(0)
|
||||||
|
{
|
||||||
|
m_chunks.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* allocate(uint16_t n)
|
||||||
|
{
|
||||||
|
if (m_size + n <= N)
|
||||||
|
{
|
||||||
|
T* data = m_chunks.back().data + m_size;
|
||||||
|
m_size += n;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = 0;
|
||||||
|
m_chunks.emplace_back();
|
||||||
|
return m_chunks.back().data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_size = 0;
|
||||||
|
m_chunks.clear();
|
||||||
|
m_chunks.emplace_back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class ThreadStorage
|
||||||
|
{
|
||||||
|
typedef std::stack<std::reference_wrapper<profiler::Block> > stack_of_blocks_t;
|
||||||
|
typedef std::vector<profiler::SerializedBlock*> serialized_list_t;
|
||||||
|
|
||||||
|
chunk_allocator<char, 1024> m_allocator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
stack_of_blocks_t openedList;
|
||||||
|
serialized_list_t closedList;
|
||||||
|
uint64_t usedMemorySize = 0;
|
||||||
|
bool named = false;
|
||||||
|
|
||||||
|
void store(const profiler::Block& _block);
|
||||||
|
void clearClosed();
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class ProfileManager
|
class ProfileManager
|
||||||
{
|
{
|
||||||
ProfileManager();
|
friend profiler::StaticBlockDescriptor;
|
||||||
ProfileManager(const ProfileManager& p) = delete;
|
|
||||||
ProfileManager& operator=(const ProfileManager&) = delete;
|
|
||||||
static ProfileManager m_profileManager;
|
|
||||||
|
|
||||||
bool m_isEnabled = false;
|
ProfileManager();
|
||||||
|
ProfileManager(const ProfileManager& p) = delete;
|
||||||
|
ProfileManager& operator=(const ProfileManager&) = delete;
|
||||||
|
|
||||||
typedef std::stack<::std::reference_wrapper<profiler::Block> > stack_of_blocks_t;
|
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
||||||
typedef std::map<size_t, stack_of_blocks_t> map_of_threads_stacks;
|
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
|
||||||
typedef std::set<size_t> set_of_thread_id;
|
typedef std::vector<profiler::BlockDescriptor> block_descriptors_t;
|
||||||
typedef std::vector<profiler::SourceBlock> sources;
|
|
||||||
|
|
||||||
map_of_threads_stacks m_openedBracketsMap;
|
map_of_threads_stacks m_threads;
|
||||||
|
block_descriptors_t m_descriptors;
|
||||||
profiler::spin_lock m_spin;
|
uint64_t m_usedMemorySize = 0;
|
||||||
profiler::spin_lock m_storedSpin;
|
profiler::spin_lock m_spin;
|
||||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
profiler::spin_lock m_storedSpin;
|
||||||
|
bool m_isEnabled = false;
|
||||||
void _internalInsertBlock(const profiler::Block &_block);
|
|
||||||
|
|
||||||
sources m_sources;
|
|
||||||
|
|
||||||
typedef std::list<profiler::SerializedBlock*> serialized_list_t;
|
|
||||||
serialized_list_t m_blocks;
|
|
||||||
|
|
||||||
set_of_thread_id m_namedThreades;
|
|
||||||
|
|
||||||
uint64_t m_blocksMemorySize = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -85,9 +140,25 @@ public:
|
|||||||
void beginBlock(profiler::Block& _block);
|
void beginBlock(profiler::Block& _block);
|
||||||
void endBlock();
|
void endBlock();
|
||||||
void setEnabled(bool isEnable);
|
void setEnabled(bool isEnable);
|
||||||
unsigned int dumpBlocksToFile(const char* filename);
|
uint32_t dumpBlocksToFile(const char* filename);
|
||||||
void setThreadName(const char* name);
|
void setThreadName(const char* name);
|
||||||
unsigned int addSource(const char* _filename, int _line);
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
template <class ... TArgs>
|
||||||
|
uint32_t addBlockDescriptor(TArgs ... _args)
|
||||||
|
{
|
||||||
|
guard_lock_t lock(m_storedSpin);
|
||||||
|
const auto id = static_cast<uint32_t>(m_descriptors.size());
|
||||||
|
m_descriptors.emplace_back(m_usedMemorySize, _args...);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
|
||||||
|
{
|
||||||
|
guard_lock_t lock(m_spin);
|
||||||
|
return m_threads[_thread_id];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user