diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index cfffbb7..7c8bead 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -90,6 +90,12 @@ namespace profiler Mark(const char* _name, color_t _color = 0); + inline unsigned char getType() const { return type; } + inline color_t getColor() const { return color; } + inline timestamp_t getBegin() const { return begin; } + inline size_t getThreadId() const { return thread_id; } + inline const char* getName() const { return name; } + }; class PROFILER_API Block : public Mark @@ -98,6 +104,11 @@ namespace profiler 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); } }; } diff --git a/sample/main.cpp b/sample/main.cpp index 9de56e4..5a177b2 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -4,12 +4,12 @@ void shortTimeFunction(){ PROFILER_BEGIN_FUNCTION_BLOCK; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } void longTimeFunction(){ PROFILER_BEGIN_FUNCTION_BLOCK; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); } @@ -21,10 +21,19 @@ int main() //profiler::registerMark(&bl); + PROFILER_ENABLE; + longTimeFunction(); + shortTimeFunction(); + PROFILER_BEGIN_BLOCK("block1"); + PROFILER_BEGIN_BLOCK("block2"); + PROFILER_BEGIN_BLOCK("block3"); + PROFILER_BEGIN_BLOCK("block4"); + PROFILER_END_BLOCK; + //PROFILER_END_BLOCK; PROFILER_ADD_MARK("mark1"); PROFILER_ADD_MARK_GROUPED("mark1",1); - PROFILER_DISABLE; + //PROFILER_DISABLE; return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6f6fb3..5b776a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ set(CPP_FILES set(H_FILES ${ROOT}/include/profiler/profiler.h profile_manager.h + spin_lock.h ) set(SOURCES diff --git a/src/block.cpp b/src/block.cpp index 86efa7c..2571038 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -33,12 +33,17 @@ void Mark::tick(timestamp_t& stamp) Block::Block(const char* _name, color_t _color) : Mark(_name, _color), - end(begin) + end(0) { } Block::~Block() { - tick(end); + if (this->isCleared()) + return; + if (!this->isFinished()) + this->finish(); + + endBlock(); } diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index e838a4a..2dc6412 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -1,6 +1,8 @@ #include "profile_manager.h" #include "profiler/profiler.h" +#include + using namespace profiler; extern "C"{ @@ -39,19 +41,41 @@ ProfileManager& ProfileManager::instance() return m_profileManager; } -void ProfileManager::registerMark(profiler::Mark* _mark) +void ProfileManager::registerMark(Mark* _mark) { - + if (!m_isEnabled) + return; } -void ProfileManager::beginBlock(profiler::Block* _block) +void ProfileManager::beginBlock(Block* _block) { + if (!m_isEnabled) + return; + guard_lock_t lock(m_spin); + m_openedBracketsMap[_block->getThreadId()].push(_block); } void ProfileManager::endBlock() { + if (!m_isEnabled) + return; + size_t threadId = std::hash()(std::this_thread::get_id()); + + 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(); + } + + stackOfOpenedBlocks.pop(); } void ProfileManager::setEnabled(bool isEnable) diff --git a/src/profile_manager.h b/src/profile_manager.h index 849a2d4..cdffe57 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -21,6 +21,11 @@ along with this program.If not, see . #include "profiler/profiler.h" +#include "spin_lock.h" + +#include +#include + class ProfileManager { ProfileManager(); @@ -29,6 +34,14 @@ class ProfileManager static ProfileManager m_profileManager; bool m_isEnabled = false; + + typedef std::stack stack_of_blocks_t; + typedef std::map map_of_threads_stacks; + + map_of_threads_stacks m_openedBracketsMap; + + profiler::spin_lock m_spin; + typedef profiler::guard_lock guard_lock_t; public: static ProfileManager& instance(); diff --git a/src/spin_lock.h b/src/spin_lock.h new file mode 100644 index 0000000..ed484d2 --- /dev/null +++ b/src/spin_lock.h @@ -0,0 +1,68 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016 Sergey Yagovtsev + +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 . +**/ + +#ifndef ________SPIN_LOCK__________H______ +#define ________SPIN_LOCK__________H______ + +#include + +namespace profiler{ + + class spin_lock + { + std::atomic_flag m_lock; + public: + void lock() + { + while (m_lock.test_and_set(std::memory_order_acquire)){} + } + + void unlock() + { + m_lock.clear(std::memory_order_release); + } + + spin_lock(){ + m_lock.clear(); + } + }; + + template + class guard_lock + { + T& m_mutex; + bool m_isLocked = false; + public: + guard_lock(T& m) :m_mutex(m){ + m_mutex.lock(); + m_isLocked = true; + } + ~guard_lock(){ + this->release(); + } + inline void release(){ + if (m_isLocked){ + m_mutex.unlock(); + m_isLocked = false; + } + + } + }; +} + +#endif