mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 00:31:02 +08:00
1) Removed Mark entity. Only Block with type
2) Added simple implementation of serializing blocks and storing it.
This commit is contained in:
parent
d12ff7fb67
commit
9cf3ca02b7
@ -27,16 +27,16 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
#endif
|
||||
|
||||
#ifndef FULL_DISABLE_PROFILER
|
||||
#define PROFILER_ADD_MARK(name) profiler::Mark TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name);\
|
||||
profiler::registerMark(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_ADD_MARK_GROUPED(name,block_group) profiler::Mark TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group);\
|
||||
profiler::registerMark(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_BEGIN_BLOCK(name) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name);\
|
||||
#define PROFILER_ADD_MARK(name) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_MARK);\
|
||||
profiler::beginBlock(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group);\
|
||||
#define PROFILER_ADD_MARK_GROUPED(name,block_group) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_MARK);\
|
||||
profiler::beginBlock(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_BEGIN_BLOCK(name) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_BLOCK);\
|
||||
profiler::beginBlock(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group) profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK);\
|
||||
profiler::beginBlock(&TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
|
||||
@ -76,32 +76,42 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
class Mark;
|
||||
class Block;
|
||||
|
||||
extern "C"{
|
||||
void PROFILER_API registerMark(Mark* _mark);
|
||||
void PROFILER_API beginBlock(Block* _block);
|
||||
void PROFILER_API endBlock();
|
||||
void PROFILER_API setEnabled(bool isEnable);
|
||||
|
||||
}
|
||||
|
||||
typedef uint8_t block_type_t;
|
||||
typedef uint64_t timestamp_t;
|
||||
typedef unsigned char color_t;
|
||||
typedef uint16_t color_t;
|
||||
typedef uint32_t thread_id_t;
|
||||
|
||||
class PROFILER_API Mark
|
||||
const block_type_t BLOCK_TYPE_MARK = 1;
|
||||
const block_type_t BLOCK_TYPE_BLOCK = 2;
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct PROFILER_API BaseBlockData
|
||||
{
|
||||
block_type_t type;
|
||||
color_t color;
|
||||
timestamp_t begin;
|
||||
timestamp_t end;
|
||||
thread_id_t thread_id;
|
||||
|
||||
BaseBlockData(color_t _color, block_type_t _type);
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class PROFILER_API Block : public BaseBlockData
|
||||
{
|
||||
protected:
|
||||
unsigned char type;
|
||||
color_t color;
|
||||
timestamp_t begin;
|
||||
size_t thread_id;
|
||||
const char *name;
|
||||
void tick(timestamp_t& stamp);
|
||||
public:
|
||||
|
||||
Mark(const char* _name, color_t _color = 0);
|
||||
Block(const char* _name, color_t _color = 0, block_type_t _type = BLOCK_TYPE_MARK);
|
||||
|
||||
inline unsigned char getType() const { return type; }
|
||||
inline color_t getColor() const { return color; }
|
||||
@ -109,19 +119,13 @@ namespace profiler
|
||||
inline size_t getThreadId() const { return thread_id; }
|
||||
inline const char* getName() const { return name; }
|
||||
|
||||
};
|
||||
|
||||
class PROFILER_API Block : public Mark
|
||||
{
|
||||
timestamp_t end;
|
||||
public:
|
||||
Block(const char* _name, color_t _color = 0);
|
||||
~Block();
|
||||
|
||||
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); }
|
||||
|
||||
~Block();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,44 +6,41 @@
|
||||
|
||||
using namespace profiler;
|
||||
|
||||
const int NAME_LENGTH = 64;
|
||||
|
||||
const unsigned char MARK_TYPE_LOCAL_EVENT = 1;
|
||||
const unsigned char MARK_TYPE_GLOBAL_EVENT = 2;
|
||||
const unsigned char MARK_TYPE_BEGIN = 3;
|
||||
const unsigned char MARK_TYPE_END = 4;
|
||||
|
||||
Mark::Mark(const char* _name, color_t _color) :
|
||||
type(0),
|
||||
BaseBlockData::BaseBlockData(color_t _color, block_type_t _type) :
|
||||
type(_type),
|
||||
color(_color),
|
||||
begin(0),
|
||||
thread_id(0),
|
||||
end(0),
|
||||
thread_id(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(const char* _name, color_t _color, block_type_t _type) :
|
||||
BaseBlockData(_color,_type),
|
||||
name(_name)
|
||||
{
|
||||
tick(begin);
|
||||
thread_id = std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||
}
|
||||
|
||||
void Mark::tick(timestamp_t& stamp)
|
||||
void Block::tick(timestamp_t& stamp)
|
||||
{
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
|
||||
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
|
||||
stamp = time_point.time_since_epoch().count();
|
||||
}
|
||||
|
||||
Block::Block(const char* _name, color_t _color) :
|
||||
Mark(_name, _color),
|
||||
end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
if (this->isCleared())
|
||||
return;
|
||||
if (!this->isFinished())
|
||||
this->finish();
|
||||
if (this->type == BLOCK_TYPE_BLOCK)
|
||||
{
|
||||
if (this->isCleared())//this block was cleared by END_BLOCK macros
|
||||
return;
|
||||
if (!this->isFinished())
|
||||
this->finish();
|
||||
|
||||
endBlock();
|
||||
}
|
||||
|
||||
endBlock();
|
||||
}
|
||||
|
@ -6,11 +6,6 @@ using namespace profiler;
|
||||
|
||||
extern "C"{
|
||||
|
||||
void PROFILER_API registerMark(Mark* _mark)
|
||||
{
|
||||
ProfileManager::instance().registerMark(_mark);
|
||||
}
|
||||
|
||||
void PROFILER_API endBlock()
|
||||
{
|
||||
ProfileManager::instance().endBlock();
|
||||
@ -26,12 +21,41 @@ extern "C"{
|
||||
}
|
||||
}
|
||||
|
||||
SerilizedBlock::SerilizedBlock(Block* block):
|
||||
m_size(0),
|
||||
m_data(nullptr)
|
||||
{
|
||||
m_size += sizeof(BaseBlockData);
|
||||
auto name_len = strlen(block->getName()) + 1;
|
||||
m_size += name_len;
|
||||
|
||||
m_data = new char[m_size];
|
||||
memcpy(&m_data[0], block, sizeof(BaseBlockData));
|
||||
strncpy(&m_data[sizeof(BaseBlockData)], block->getName(), name_len);
|
||||
|
||||
}
|
||||
|
||||
SerilizedBlock::~SerilizedBlock()
|
||||
{
|
||||
if (m_data){
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ProfileManager::ProfileManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ProfileManager::~ProfileManager()
|
||||
{
|
||||
for (auto* b : m_blocks){
|
||||
delete b;
|
||||
}
|
||||
}
|
||||
|
||||
ProfileManager& ProfileManager::instance()
|
||||
{
|
||||
///C++11 makes possible to create Singleton without any warry about thread-safeness
|
||||
@ -40,19 +64,18 @@ ProfileManager& ProfileManager::instance()
|
||||
return m_profileManager;
|
||||
}
|
||||
|
||||
void ProfileManager::registerMark(Mark* _mark)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
}
|
||||
|
||||
void ProfileManager::beginBlock(Block* _block)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
if (_block->getType() != BLOCK_TYPE_MARK){
|
||||
guard_lock_t lock(m_spin);
|
||||
m_openedBracketsMap[_block->getThreadId()].push(_block);
|
||||
}
|
||||
else{
|
||||
_internalInsertBlock(_block);
|
||||
}
|
||||
|
||||
guard_lock_t lock(m_spin);
|
||||
m_openedBracketsMap[_block->getThreadId()].push(_block);
|
||||
}
|
||||
|
||||
void ProfileManager::endBlock()
|
||||
@ -73,6 +96,7 @@ void ProfileManager::endBlock()
|
||||
if (lastBlock && !lastBlock->isFinished()){
|
||||
lastBlock->finish();
|
||||
}
|
||||
_internalInsertBlock(lastBlock);
|
||||
stackOfOpenedBlocks.pop();
|
||||
}
|
||||
|
||||
@ -80,3 +104,9 @@ void ProfileManager::setEnabled(bool isEnable)
|
||||
{
|
||||
m_isEnabled = isEnable;
|
||||
}
|
||||
|
||||
void ProfileManager::_internalInsertBlock(profiler::Block* _block)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
m_blocks.emplace_back(new SerilizedBlock(_block));
|
||||
}
|
@ -25,6 +25,20 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
class SerilizedBlock
|
||||
{
|
||||
uint16_t m_size;
|
||||
char* m_data;
|
||||
public:
|
||||
|
||||
SerilizedBlock(profiler::Block* block);
|
||||
~SerilizedBlock();
|
||||
|
||||
const char* const data() { return m_data; }
|
||||
uint16_t size() const { return m_size; }
|
||||
};
|
||||
|
||||
class ProfileManager
|
||||
{
|
||||
@ -41,11 +55,16 @@ class ProfileManager
|
||||
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(profiler::Block* _block);
|
||||
|
||||
typedef std::list<SerilizedBlock*> serialized_list_t;
|
||||
serialized_list_t m_blocks;
|
||||
public:
|
||||
static ProfileManager& instance();
|
||||
|
||||
void registerMark(profiler::Mark* _mark);
|
||||
~ProfileManager();
|
||||
void beginBlock(profiler::Block* _block);
|
||||
void endBlock();
|
||||
void setEnabled(bool isEnable);
|
||||
|
Loading…
x
Reference in New Issue
Block a user