0
0
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:
Victor Zarubkin 2016-08-28 02:41:02 +03:00
parent 3a2c8aaef1
commit 439e1cfb44
7 changed files with 545 additions and 334 deletions

View File

@ -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.

View 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_______

View File

@ -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"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View 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_______

View File

@ -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();
}

View File

@ -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;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -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