mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-29 10:05:48 +08:00
208 lines
4.6 KiB
C++
208 lines
4.6 KiB
C++
#include "profile_manager.h"
|
|
|
|
#include <thread>
|
|
#include <string.h>
|
|
|
|
#include <fstream>
|
|
|
|
using namespace profiler;
|
|
|
|
extern "C"{
|
|
|
|
void PROFILER_API endBlock()
|
|
{
|
|
ProfileManager::instance().endBlock();
|
|
}
|
|
|
|
void PROFILER_API setEnabled(bool isEnable)
|
|
{
|
|
ProfileManager::instance().setEnabled(isEnable);
|
|
}
|
|
void PROFILER_API beginBlock(Block* _block)
|
|
{
|
|
ProfileManager::instance().beginBlock(_block);
|
|
}
|
|
|
|
unsigned int PROFILER_API dumpBlocksToFile(const char* filename)
|
|
{
|
|
return ProfileManager::instance().dumpBlocksToFile(filename);
|
|
}
|
|
|
|
void PROFILER_API setThreadName(const char* name)
|
|
{
|
|
return ProfileManager::instance().setThreadName(name);
|
|
}
|
|
}
|
|
|
|
SerializedBlock::SerializedBlock(const Block* block)
|
|
: m_size(sizeof(BaseBlockData))
|
|
, m_data(nullptr)
|
|
{
|
|
uint16_t name_len = static_cast<uint16_t>(strlen(block->getName()) + 1);
|
|
m_size += name_len;
|
|
|
|
m_data = new char[m_size];
|
|
memcpy(m_data, block, sizeof(BaseBlockData));
|
|
strncpy(m_data + sizeof(BaseBlockData), block->getName(), name_len);
|
|
}
|
|
|
|
SerializedBlock::SerializedBlock(uint16_t _size, char* _data)
|
|
: m_size(_size)
|
|
, m_data(_data)
|
|
{
|
|
}
|
|
|
|
SerializedBlock::~SerializedBlock()
|
|
{
|
|
if (m_data != nullptr)
|
|
delete[] m_data;
|
|
}
|
|
|
|
SerializedBlock::SerializedBlock(const SerializedBlock& other)
|
|
: m_size(other.m_size)
|
|
, m_data(new char[other.m_size])
|
|
{
|
|
memcpy(m_data, other.m_data, m_size);
|
|
}
|
|
|
|
SerializedBlock::SerializedBlock(SerializedBlock&& that)
|
|
: m_size(that.m_size)
|
|
, m_data(that.m_data)
|
|
{
|
|
that.m_size = 0;
|
|
that.m_data = nullptr;
|
|
}
|
|
|
|
const BaseBlockData * SerializedBlock::block() const
|
|
{
|
|
return reinterpret_cast<const BaseBlockData*>(m_data);
|
|
}
|
|
|
|
const char* SerializedBlock::getBlockName() const
|
|
{
|
|
return m_data + sizeof(BaseBlockData);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
BlockSourceInfo::BlockSourceInfo(const char* _filename, int _linenumber) : m_id(ProfileManager::instance().addSource(_filename, _linenumber))
|
|
{
|
|
|
|
}
|
|
|
|
SourceBlock::SourceBlock(const char* _filename, int _line) : m_filename(_filename), m_line(_line)
|
|
{
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
ProfileManager::ProfileManager()
|
|
{
|
|
|
|
}
|
|
|
|
ProfileManager::~ProfileManager()
|
|
{
|
|
//dumpBlocksToFile("test.prof");
|
|
}
|
|
|
|
ProfileManager& ProfileManager::instance()
|
|
{
|
|
///C++11 makes possible to create Singleton without any warry about thread-safeness
|
|
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
|
static ProfileManager m_profileManager;
|
|
return m_profileManager;
|
|
}
|
|
|
|
void ProfileManager::beginBlock(Block* _block)
|
|
{
|
|
if (!m_isEnabled)
|
|
return;
|
|
if (BLOCK_TYPE_BLOCK == _block->getType()){
|
|
guard_lock_t lock(m_spin);
|
|
m_openedBracketsMap[_block->getThreadId()].push(_block);
|
|
}
|
|
else{
|
|
_internalInsertBlock(_block);
|
|
}
|
|
|
|
}
|
|
void ProfileManager::endBlock()
|
|
{
|
|
|
|
if (!m_isEnabled)
|
|
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 && !lastBlock->isFinished()){
|
|
lastBlock->finish();
|
|
}
|
|
_internalInsertBlock(lastBlock);
|
|
stackOfOpenedBlocks.pop();
|
|
}
|
|
|
|
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 SerializedBlock(_block));
|
|
}
|
|
|
|
unsigned int ProfileManager::dumpBlocksToFile(const char* filename)
|
|
{
|
|
std::ofstream of(filename, std::fstream::binary);
|
|
|
|
for (auto* b : m_blocks){
|
|
uint16_t sz = b->size();
|
|
of.write((const char*)&sz, sizeof(uint16_t));
|
|
of.write(b->data(), b->size());
|
|
delete b;
|
|
}
|
|
unsigned int size = (unsigned int)m_blocks.size();
|
|
|
|
m_blocks.clear();
|
|
|
|
return size;
|
|
}
|
|
|
|
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())
|
|
return;
|
|
|
|
profiler::Block block(name, current_thread_id, 0, profiler::BLOCK_TYPE_THREAD_SIGN);
|
|
m_blocks.emplace_back(new SerializedBlock(&block));
|
|
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;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|