mirror of
https://github.com/yse/easy_profiler.git
synced 2025-01-14 00:27: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_______
|
||||
#define ____PROFILER____H_______
|
||||
|
||||
#define TOKEN_JOIN(x, y) x ## y
|
||||
#define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y)
|
||||
|
||||
#if defined ( WIN32 )
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
/** 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
|
||||
|
||||
\code
|
||||
@ -51,11 +63,26 @@ Block will be automatically completed by destructor
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_BLOCK(name)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,profiler::colors::Clay,profiler::BLOCK_TYPE_BLOCK,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#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,\
|
||||
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
|
||||
|
||||
@ -65,7 +92,7 @@ Block will be automatically completed by destructor
|
||||
{
|
||||
// some code ...
|
||||
if(something){
|
||||
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()",profiler::colors::Red);
|
||||
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()", ::profiler::colors::Red);
|
||||
someThirdPartyLongFunction();
|
||||
return;
|
||||
}
|
||||
@ -76,11 +103,12 @@ Block will be automatically completed by destructor
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#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
|
||||
|
||||
/** Macro of beginning of function block with default identification
|
||||
|
||||
@ -114,7 +142,7 @@ Name of block automatically created with function name
|
||||
|
||||
\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
|
||||
|
||||
@ -134,56 +162,56 @@ void foo()
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
||||
#define PROFILER_END_BLOCK ::profiler::endBlock();
|
||||
|
||||
#define PROFILER_ADD_EVENT(name) \
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_EVENT,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#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
|
||||
|
||||
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_EVENT,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#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
|
||||
|
||||
/** Macro enabling profiler
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
||||
#define PROFILER_ENABLE ::profiler::setEnabled(true);
|
||||
|
||||
/** Macro disabling profiler
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
||||
#define PROFILER_DISABLE ::profiler::setEnabled(false);
|
||||
|
||||
#ifdef WIN32
|
||||
#define PROFILER_SET_THREAD_NAME(name) profiler::setThreadName(name);
|
||||
#define PROFILER_SET_THREAD_NAME(name) ::profiler::setThreadName(name);
|
||||
#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
|
||||
|
||||
#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
|
||||
|
||||
#else
|
||||
#define PROFILER_ADD_MARK(name)
|
||||
#define PROFILER_ADD_MARK_GROUPED(name,block_group)
|
||||
#define PROFILER_BEGIN_BLOCK(name)
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_group)
|
||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
||||
#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
|
||||
#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_MAIN_THREAD
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include "profiler/profiler_colors.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _BUILD_PROFILER
|
||||
@ -196,62 +224,12 @@ void foo()
|
||||
#endif
|
||||
|
||||
class ProfileManager;
|
||||
class ThreadStorage;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace profiler {
|
||||
|
||||
class Block;
|
||||
class BlockSourceInfo;
|
||||
class StaticBlockDescriptor;
|
||||
|
||||
extern "C"{
|
||||
void PROFILER_API beginBlock(Block& _block);
|
||||
@ -261,115 +239,104 @@ namespace profiler
|
||||
void PROFILER_API setThreadName(const char* name);
|
||||
}
|
||||
|
||||
typedef uint8_t block_type_t;
|
||||
typedef uint64_t timestamp_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;
|
||||
const block_type_t BLOCK_TYPE_BLOCK = 2;
|
||||
const block_type_t BLOCK_TYPE_THREAD_SIGN = 3;
|
||||
enum BlockType : uint8_t
|
||||
{
|
||||
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)
|
||||
class PROFILER_API BaseBlockData
|
||||
{
|
||||
protected:
|
||||
class PROFILER_API BaseBlockDescriptor
|
||||
{
|
||||
protected:
|
||||
|
||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
||||
block_type_t type;
|
||||
color_t color;
|
||||
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
|
||||
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
|
||||
|
||||
void tick(timestamp_t& stamp);
|
||||
public:
|
||||
BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color);
|
||||
|
||||
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 color_t getColor() const { return color; }
|
||||
inline timestamp_t getBegin() const { return begin; }
|
||||
inline thread_id_t getThreadId() const { return thread_id; }
|
||||
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); }
|
||||
};
|
||||
|
||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
||||
inline source_id_t getSourceId() const { return -1; }
|
||||
#else
|
||||
inline source_id_t getSourceId() const { return source_id; }
|
||||
#endif
|
||||
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
|
||||
|
||||
inline timestamp_t getEnd() const { return end; }
|
||||
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); }
|
||||
public:
|
||||
|
||||
inline bool startsEarlierThan(const BaseBlockData& another) const {return this->begin < another.begin;}
|
||||
inline bool endsEarlierThan(const BaseBlockData& another) const {return this->end < another.end;}
|
||||
inline bool startsLaterThan(const BaseBlockData& another) const {return !this->startsEarlierThan(another);}
|
||||
inline bool endsLaterThan(const BaseBlockData& another) const {return !this->endsEarlierThan(another);}
|
||||
};
|
||||
BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
|
||||
|
||||
const char* name() const { return m_name; }
|
||||
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)
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
|
||||
///< 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); }
|
||||
const char* m_name;
|
||||
|
||||
private:
|
||||
|
||||
static SerializedBlock* create(const Block &block, uint64_t& memory_size);
|
||||
static void destroy(SerializedBlock* that);
|
||||
void finish();
|
||||
inline bool isFinished() const { return m_end >= m_begin; }
|
||||
|
||||
SerializedBlock(const profiler::Block& block, uint16_t name_length);
|
||||
public:
|
||||
|
||||
SerializedBlock(const SerializedBlock&) = delete;
|
||||
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
||||
~SerializedBlock() = delete;
|
||||
Block(const char*, block_type_t _block_type, block_id_t _id, const char* _name = "");
|
||||
~Block();
|
||||
|
||||
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
|
||||
{
|
||||
ThreadNameSetter(const char* _name)
|
||||
@ -377,17 +344,9 @@ namespace profiler
|
||||
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.
|
||||
|
||||
|
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 <atomic>
|
||||
#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;
|
||||
#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()
|
||||
{
|
||||
#ifdef WIN32
|
||||
@ -59,20 +30,31 @@ inline timestamp_t getCurrentTime()
|
||||
#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()
|
||||
{
|
||||
if (this->type == BLOCK_TYPE_BLOCK)
|
||||
{
|
||||
if (this->isCleared())//this block was cleared by END_BLOCK macros
|
||||
return;
|
||||
if (!this->isFinished())
|
||||
this->finish();
|
||||
|
||||
endBlock();
|
||||
}
|
||||
if (!isFinished())
|
||||
::profiler::endBlock();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "profile_manager.h"
|
||||
#include "profiler/serialized_block.h"
|
||||
|
||||
#include <thread>
|
||||
#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)
|
||||
: BaseBlockData(block)
|
||||
{
|
||||
auto name = const_cast<char*>(getName());
|
||||
strncpy(name, block.getName(), name_length);
|
||||
name[name_length] = 0;
|
||||
auto pName = const_cast<char*>(name());
|
||||
if (name_length) strncpy(pName, block.name(), name_length);
|
||||
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)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
return;
|
||||
|
||||
if (BLOCK_TYPE_BLOCK == _block.getType()){
|
||||
guard_lock_t lock(m_spin);
|
||||
m_openedBracketsMap[_block.getThreadId()].emplace(_block);
|
||||
}
|
||||
else{
|
||||
_internalInsertBlock(_block);
|
||||
}
|
||||
|
||||
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||
|
||||
if (!_block.isFinished())
|
||||
thread_storage.openedList.emplace(_block);
|
||||
else
|
||||
thread_storage.store(_block);
|
||||
}
|
||||
|
||||
void ProfileManager::endBlock()
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||
if (thread_storage.openedList.empty())
|
||||
return;
|
||||
|
||||
uint32_t threadId = getCurrentThreadId();
|
||||
|
||||
guard_lock_t lock(m_spin);
|
||||
auto& stackOfOpenedBlocks = m_openedBracketsMap[threadId];
|
||||
|
||||
if (stackOfOpenedBlocks.empty())
|
||||
return;
|
||||
|
||||
Block& lastBlock = stackOfOpenedBlocks.top();
|
||||
if(!lastBlock.isFinished())
|
||||
Block& lastBlock = thread_storage.openedList.top();
|
||||
if (!lastBlock.isFinished())
|
||||
lastBlock.finish();
|
||||
_internalInsertBlock(lastBlock);
|
||||
|
||||
stackOfOpenedBlocks.pop();
|
||||
thread_storage.store(lastBlock);
|
||||
thread_storage.openedList.pop();
|
||||
}
|
||||
|
||||
void ProfileManager::setEnabled(bool isEnable)
|
||||
@ -132,58 +135,63 @@ void ProfileManager::setEnabled(bool isEnable)
|
||||
m_isEnabled = isEnable;
|
||||
}
|
||||
|
||||
void ProfileManager::_internalInsertBlock(const profiler::Block& _block)
|
||||
uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
m_blocks.emplace_back(SerializedBlock::create(_block, m_blocksMemorySize));
|
||||
}
|
||||
std::ofstream of(filename, std::fstream::binary);
|
||||
|
||||
unsigned int ProfileManager::dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
::std::ofstream of(filename, std::fstream::binary);
|
||||
|
||||
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)
|
||||
uint64_t usedMemorySize = 0;
|
||||
uint32_t blocks_number = 0;
|
||||
for (const auto& thread_storage : m_threads)
|
||||
{
|
||||
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(b->getName()) + 1);
|
||||
|
||||
of.write((const char*)&sz, sizeof(uint16_t));
|
||||
of.write(b->data(), sz);
|
||||
|
||||
SerializedBlock::destroy(b);
|
||||
usedMemorySize += thread_storage.second.usedMemorySize;
|
||||
blocks_number += static_cast<uint32_t>(thread_storage.second.closedList.size());
|
||||
}
|
||||
|
||||
m_blocksMemorySize = 0;
|
||||
m_blocks.clear();
|
||||
of.write((const char*)&blocks_number, sizeof(decltype(blocks_number)));
|
||||
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;
|
||||
}
|
||||
|
||||
void ProfileManager::setThreadName(const char* name)
|
||||
{
|
||||
auto current_thread_id = getCurrentThreadId();
|
||||
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
auto find_it = m_namedThreades.find(current_thread_id);
|
||||
if (find_it != m_namedThreades.end())
|
||||
auto& thread_storage = threadStorage(getCurrentThreadId());
|
||||
if (thread_storage.named)
|
||||
return;
|
||||
|
||||
profiler::Block block(name, current_thread_id, 0, profiler::BLOCK_TYPE_THREAD_SIGN);
|
||||
m_blocks.emplace_back(SerializedBlock::create(block, m_blocksMemorySize));
|
||||
m_namedThreades.insert(current_thread_id);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
const auto id = addBlockDescriptor("ThreadName", __FILE__, __LINE__, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random);
|
||||
thread_storage.store(profiler::Block(nullptr, profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
|
||||
thread_storage.named = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -30,6 +30,8 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
@ -46,36 +48,89 @@ inline uint32_t getCurrentThreadId()
|
||||
#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
|
||||
{
|
||||
ProfileManager();
|
||||
ProfileManager(const ProfileManager& p) = delete;
|
||||
ProfileManager& operator=(const ProfileManager&) = delete;
|
||||
static ProfileManager m_profileManager;
|
||||
friend profiler::StaticBlockDescriptor;
|
||||
|
||||
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 std::map<size_t, stack_of_blocks_t> map_of_threads_stacks;
|
||||
typedef std::set<size_t> set_of_thread_id;
|
||||
typedef std::vector<profiler::SourceBlock> sources;
|
||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
||||
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
|
||||
typedef std::vector<profiler::BlockDescriptor> block_descriptors_t;
|
||||
|
||||
map_of_threads_stacks m_openedBracketsMap;
|
||||
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
||||
|
||||
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;
|
||||
map_of_threads_stacks m_threads;
|
||||
block_descriptors_t m_descriptors;
|
||||
uint64_t m_usedMemorySize = 0;
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
bool m_isEnabled = false;
|
||||
|
||||
public:
|
||||
|
||||
@ -85,9 +140,25 @@ public:
|
||||
void beginBlock(profiler::Block& _block);
|
||||
void endBlock();
|
||||
void setEnabled(bool isEnable);
|
||||
unsigned int dumpBlocksToFile(const char* filename);
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user