From 439e1cfb4431d119d5a371b3cacff0eba6707367 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 02:41:02 +0300 Subject: [PATCH 01/37] Remastering profiler API (not compiling yet) --- include/profiler/profiler.h | 329 ++++++++++++---------------- include/profiler/profiler_colors.h | 109 +++++++++ include/profiler/reader.h | 1 + include/profiler/serialized_block.h | 81 +++++++ src/block.cpp | 62 ++---- src/profile_manager.cpp | 172 ++++++++------- src/profile_manager.h | 125 ++++++++--- 7 files changed, 545 insertions(+), 334 deletions(-) create mode 100644 include/profiler/profiler_colors.h create mode 100644 include/profiler/serialized_block.h diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 971cd39..340d230 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -19,19 +19,31 @@ along with this program.If not, see . #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 #include +#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(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. diff --git a/include/profiler/profiler_colors.h b/include/profiler/profiler_colors.h new file mode 100644 index 0000000..e89e95f --- /dev/null +++ b/include/profiler/profiler_colors.h @@ -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 . +**/ + +#ifndef EASY_PROFILER__COLORS__H_______ +#define EASY_PROFILER__COLORS__H_______ + +#include + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +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_______ diff --git a/include/profiler/reader.h b/include/profiler/reader.h index 72a0e8c..b85dca3 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -25,6 +25,7 @@ along with this program.If not, see . #include #include #include "profiler/profiler.h" +#include "profiler/serialized_block.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/profiler/serialized_block.h b/include/profiler/serialized_block.h new file mode 100644 index 0000000..7df4386 --- /dev/null +++ b/include/profiler/serialized_block.h @@ -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 . +**/ + +#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(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(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_______ diff --git a/src/block.cpp b/src/block.cpp index 59cd0c3..2acd3d5 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -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(); } diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 1b1cfbe..d963d71 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -1,4 +1,5 @@ #include "profile_manager.h" +#include "profiler/serialized_block.h" #include #include @@ -36,39 +37,47 @@ extern "C"{ } } -SerializedBlock* SerializedBlock::create(const Block& block, uint64_t& memory_size) -{ - auto name_length = static_cast(strlen(block.getName())); - auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); - auto data = ::new char[size]; - ::new (static_cast(data)) SerializedBlock(block, name_length); - memory_size += size; - return reinterpret_cast(data); -} - -void SerializedBlock::destroy(SerializedBlock* that) -{ - ::delete[] reinterpret_cast(that); -} - SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) : BaseBlockData(block) { - auto name = const_cast(getName()); - strncpy(name, block.getName(), name_length); - name[name_length] = 0; + auto pName = const_cast(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(strlen(block.name())); + auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); + auto data = m_allocator.allocate(size); + ::new (static_cast(data)) SerializedBlock(block, name_length); + usedMemorySize += size; + closedList.emplace_back(reinterpret_cast(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(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(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(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(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(strlen(descriptor.name()) + 1); + const auto filename_size = static_cast(strlen(descriptor.file()) + 1); + const auto size = static_cast(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(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(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; } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.h b/src/profile_manager.h index db89922..c5e0547 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -30,6 +30,8 @@ along with this program.If not, see . #include #include +////////////////////////////////////////////////////////////////////////// + #ifdef WIN32 #include #else @@ -46,36 +48,89 @@ inline uint32_t getCurrentThreadId() #endif } +namespace profiler { class SerializedBlock; } + +////////////////////////////////////////////////////////////////////////// + +template +class chunk_allocator final +{ + struct chunk { + T data[N] = {}; + }; + + std::list 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 > stack_of_blocks_t; + typedef std::vector serialized_list_t; + + chunk_allocator 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 > stack_of_blocks_t; - typedef std::map map_of_threads_stacks; - typedef std::set set_of_thread_id; - typedef std::vector sources; + typedef profiler::guard_lock guard_lock_t; + typedef std::map map_of_threads_stacks; + typedef std::vector block_descriptors_t; - map_of_threads_stacks m_openedBracketsMap; - - profiler::spin_lock m_spin; - profiler::spin_lock m_storedSpin; - typedef profiler::guard_lock guard_lock_t; - - void _internalInsertBlock(const profiler::Block &_block); - - sources m_sources; - - typedef std::list 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 + uint32_t addBlockDescriptor(TArgs ... _args) + { + guard_lock_t lock(m_storedSpin); + const auto id = static_cast(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 From aa0d96d0e624fd47cd6f83e5bd2b072361bbd5fc Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 18:19:12 +0300 Subject: [PATCH 02/37] Remastering profiler API. All projects are compiled successfully, but there is an error occured during read/write .prof file --- include/profiler/profiler.h | 10 +- include/profiler/reader.h | 63 ++--- include/profiler/serialized_block.h | 2 + profiler_gui/blocks_graphics_view.cpp | 18 +- profiler_gui/globals.h | 1 + profiler_gui/main_window.cpp | 51 ++-- profiler_gui/main_window.h | 34 +-- profiler_gui/tree_widget_item.cpp | 2 +- profiler_gui/tree_widget_loader.cpp | 33 +-- reader/main.cpp | 51 ++-- src/profile_manager.cpp | 51 +++- src/reader.cpp | 331 +++++++++++++++++--------- 12 files changed, 380 insertions(+), 267 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 340d230..9d666c5 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -67,7 +67,7 @@ Block will be automatically completed by destructor 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_UNIQUE_DESC(__LINE__).id());\ ::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable #define EASY_BLOCK(compiletime_name)\ @@ -77,10 +77,10 @@ Block will be automatically completed by destructor 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__,\ +#define EASY_BLOCK_RUNTIME(runtime_name)\ + static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)("", __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_BLOCK, ::profiler::DefaultBlockColor);\ - ::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(compiletime_name COMPILETIME_TEST, ::profiler::BLOCK_TYPE_BLOCK,\ + ::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(nullptr, ::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 @@ -302,6 +302,8 @@ namespace profiler { 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; } + + void setId(block_id_t _id) { m_id = _id; } }; #pragma pack(pop) diff --git a/include/profiler/reader.h b/include/profiler/reader.h index b85dca3..b851350 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -62,20 +62,7 @@ namespace profiler { }; // END of struct BlockStatistics. #pragma pack(pop) - inline void release(BlockStatistics*& _stats) - { - if (!_stats) - { - return; - } - - if (--_stats->calls_number == 0) - { - delete _stats; - } - - _stats = nullptr; - } + extern "C" void PROFILER_API release_stats(BlockStatistics*& _stats); ////////////////////////////////////////////////////////////////////////// @@ -120,14 +107,9 @@ namespace profiler { ~BlocksTree() { - //if (node) - //{ - // delete node; - //} - - release(per_thread_stats); - release(per_parent_stats); - release(per_frame_stats); + release_stats(per_thread_stats); + release_stats(per_parent_stats); + release_stats(per_frame_stats); } bool operator < (const This& other) const @@ -136,7 +118,7 @@ namespace profiler { { return false; } - return node->block()->getBegin() < other.node->block()->getBegin(); + return node->begin() < other.node->begin(); } void shrink_to_fit() @@ -168,17 +150,17 @@ namespace profiler { if (per_thread_stats != that.per_thread_stats) { - release(per_thread_stats); + release_stats(per_thread_stats); } if (per_parent_stats != that.per_parent_stats) { - release(per_parent_stats); + release_stats(per_parent_stats); } if (per_frame_stats != that.per_frame_stats) { - release(per_frame_stats); + release_stats(per_frame_stats); } children = ::std::move(that.children); @@ -242,7 +224,7 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// - class SerializedData final + class PROFILER_API SerializedData final { char* m_data; @@ -262,10 +244,11 @@ namespace profiler { clear(); } + void set(char* _data); + SerializedData& operator = (SerializedData&& that) { - clear(); - m_data = that.m_data; + set(that.m_data); that.m_data = nullptr; return *this; } @@ -277,17 +260,7 @@ namespace profiler { void clear() { - if (m_data) - { - delete[] m_data; - m_data = nullptr; - } - } - - void set(char* _data) - { - clear(); - m_data = _data; + set(nullptr); } void swap(SerializedData& other) @@ -306,15 +279,15 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// + typedef ::std::vector descriptors_list_t; + } // END of namespace profiler. -extern "C"{ - unsigned int PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); -} +extern "C" unsigned int PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); -inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) { +inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) { ::std::atomic progress = ATOMIC_VAR_INIT(0); - return fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, gather_statistics); + return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, threaded_trees, gather_statistics); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/profiler/serialized_block.h b/include/profiler/serialized_block.h index 7df4386..c8dd1e8 100644 --- a/include/profiler/serialized_block.h +++ b/include/profiler/serialized_block.h @@ -47,6 +47,7 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// +#pragma pack(push, 1) class PROFILER_API SerializedBlockDescriptor final : public BaseBlockDescriptor { uint16_t m_nameLength; @@ -73,6 +74,7 @@ namespace profiler { ~SerializedBlockDescriptor() = delete; }; // END of SerializedBlockDescriptor. +#pragma pack(pop) ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index b5fcb51..e2d16d7 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -422,7 +422,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(textColor); // drawing text - _painter->drawText(rect, flags, ::profiler_gui::toUnicode(item.block->node->getName())); + auto name = *item.block->node->name() != 0 ? item.block->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[item.block->node->id()]->name(); + _painter->drawText(rect, flags, ::profiler_gui::toUnicode(name)); // restore previous pen color if (previousPenStyle == Qt::NoPen) @@ -481,7 +482,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(textColor); // drawing text - _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(item.block->node->getName())); + auto name = *item.block->node->name() != 0 ? item.block->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[item.block->node->id()]->name(); + _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name)); // END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } } @@ -1365,8 +1367,8 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr for (const auto& threadTree : _blocksTree) { const auto& tree = threadTree.second.tree; - const auto timestart = tree.children.front().node->block()->getBegin(); - const auto timefinish = tree.children.back().node->block()->getEnd(); + const auto timestart = tree.children.front().node->begin(); + const auto timefinish = tree.children.back().node->end(); if (m_beginTime > timestart) { @@ -1393,7 +1395,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // fill scene with new items const auto& tree = threadTree.second.tree; - qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin()); + qreal h = 0, x = time2position(tree.children.front().node->begin()); auto item = new EasyGraphicsItem(static_cast(m_items.size()), &threadTree.second); item->setLevels(tree.depth); item->setPos(0, y); @@ -1469,13 +1471,13 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block qreal start_time = -1; for (const auto& child : _children) { - auto xbegin = time2position(child.node->block()->getBegin()); + auto xbegin = time2position(child.node->begin()); if (start_time < 0) { start_time = xbegin; } - auto duration = time2position(child.node->block()->getEnd()) - xbegin; + auto duration = time2position(child.node->end()) - xbegin; //const auto dt = xbegin - prev_end; //if (dt < 0) @@ -1529,7 +1531,7 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block maxh = h; } - const auto color = child.node->block()->getColor(); + const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); b.block = &child; b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); b.setPos(xbegin, duration); diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 771c37f..ca2a1d4 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -79,6 +79,7 @@ namespace profiler_gui { EasyGlobalSignals events; ///< Global signals ::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file + ::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI ::profiler::thread_id_t selected_thread; ///< Current selected thread id unsigned int selected_block; ///< Current selected profiler block index diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index a688455..625c9a9 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -219,26 +219,6 @@ void EasyMainWindow::loadFile(const QString& filename) //m_progress->show(); m_readerTimer.start(LOADER_TIMER_INTERVAL); m_reader.load(filename); - -// ::profiler::SerializedData data; -// ::profiler::thread_blocks_tree_t prof_blocks; -// auto nblocks = fillTreesFromFile(stdfilename.c_str(), data, prof_blocks, true); -// -// if (nblocks != 0) -// { -// static_cast(m_treeWidget->widget())->clearSilent(true); -// -// m_lastFile = stdfilename; -// m_serializedData = ::std::move(data); -// ::profiler_gui::EASY_GLOBALS.selected_thread = 0; -// ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); -// ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); -// ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); -// memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); -// for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); -// -// static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); -// } } ////////////////////////////////////////////////////////////////////////// @@ -420,10 +400,11 @@ void EasyMainWindow::onFileReaderTimeout() { static_cast(m_treeWidget->widget())->clearSilent(true); - ::profiler::SerializedData data; + ::profiler::SerializedData serialized_blocks, serialized_descriptors; + ::profiler::descriptors_list_t descriptors; ::profiler::thread_blocks_tree_t prof_blocks; QString filename; - m_reader.get(data, prof_blocks, filename); + m_reader.get(serialized_blocks, serialized_descriptors, descriptors, prof_blocks, filename); if (prof_blocks.size() > 0xff) { @@ -432,10 +413,12 @@ void EasyMainWindow::onFileReaderTimeout() } m_lastFile = ::std::move(filename); - m_serializedData = ::std::move(data); + m_serializedBlocks = ::std::move(serialized_blocks); + m_serializedDescriptors = ::std::move(serialized_descriptors); ::profiler_gui::EASY_GLOBALS.selected_thread = 0; ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); + ::profiler_gui::EASY_GLOBALS.descriptors.swap(descriptors); ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); @@ -444,7 +427,7 @@ void EasyMainWindow::onFileReaderTimeout() } else { - qWarning() << "Warning: Can not open file " << m_reader.filename(); + qWarning() << "Warning: Can not open file " << m_reader.filename() << " or file is corrupted"; } m_reader.interrupt(); @@ -509,10 +492,11 @@ void EasyFileReader::load(const QString& _filename) interrupt(); m_filename = _filename; - m_thread = ::std::move(::std::thread([](::std::atomic_bool& isDone, ::std::atomic& blocks_number, ::std::atomic& progress, const QString& filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees) { - blocks_number.store(fillTreesFromFile(progress, filename.toStdString().c_str(), serialized_blocks, threaded_trees, true)); - isDone.store(true); - }, ::std::ref(m_bDone), ::std::ref(m_size), ::std::ref(m_progress), ::std::ref(m_filename), ::std::ref(m_serializedData), ::std::ref(m_blocksTree))); + m_thread = ::std::move(::std::thread([this]() { + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocksTree, true)); + m_progress.store(100); + m_bDone.store(true); + })); } void EasyFileReader::interrupt() @@ -524,15 +508,20 @@ void EasyFileReader::interrupt() m_bDone.store(false); m_progress.store(0); m_size.store(0); - m_serializedData.clear(); + m_serializedBlocks.clear(); + m_serializedDescriptors.clear(); + m_descriptors.clear(); m_blocksTree.clear(); } -void EasyFileReader::get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, QString& _filename) +void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, + ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename) { if (done()) { - m_serializedData.swap(_data); + m_serializedBlocks.swap(_serializedBlocks); + m_serializedDescriptors.swap(_serializedDescriptors); + ::profiler::descriptors_list_t(m_descriptors).swap(_descriptors); m_blocksTree.swap(_tree); m_filename.swap(_filename); } diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 4e64c25..138ca85 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -32,13 +32,15 @@ class QDockWidget; class EasyFileReader final { - ::profiler::SerializedData m_serializedData; ///< - ::profiler::thread_blocks_tree_t m_blocksTree; ///< - QString m_filename; ///< - ::std::thread m_thread; ///< - ::std::atomic_bool m_bDone; ///< - ::std::atomic m_progress; ///< - ::std::atomic m_size; ///< + ::profiler::SerializedData m_serializedBlocks; ///< + ::profiler::SerializedData m_serializedDescriptors; ///< + ::profiler::descriptors_list_t m_descriptors; ///< + ::profiler::thread_blocks_tree_t m_blocksTree; ///< + QString m_filename; ///< + ::std::thread m_thread; ///< + ::std::atomic_bool m_bDone; ///< + ::std::atomic m_progress; ///< + ::std::atomic m_size; ///< public: @@ -52,7 +54,8 @@ public: void load(const QString& _filename); void interrupt(); - void get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, QString& _filename); + void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, + ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename); }; // END of class EasyFileReader. @@ -67,13 +70,14 @@ protected: typedef EasyMainWindow This; typedef QMainWindow Parent; - QString m_lastFile; - QDockWidget* m_treeWidget; - QDockWidget* m_graphicsView; - class QProgressDialog* m_progress; - QTimer m_readerTimer; - ::profiler::SerializedData m_serializedData; - EasyFileReader m_reader; + QString m_lastFile; + QDockWidget* m_treeWidget; + QDockWidget* m_graphicsView; + class QProgressDialog* m_progress; + QTimer m_readerTimer; + ::profiler::SerializedData m_serializedBlocks; + ::profiler::SerializedData m_serializedDescriptors; + EasyFileReader m_reader; public: diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp index c3a04b1..003fc1d 100644 --- a/profiler_gui/tree_widget_item.cpp +++ b/profiler_gui/tree_widget_item.cpp @@ -83,7 +83,7 @@ const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const ::profiler::timestamp_t EasyTreeWidgetItem::duration() const { if (m_block->node) - return m_block->node->block()->duration(); + return m_block->node->duration(); return data(COL_DURATION, Qt::UserRole).toULongLong(); } diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index b0bf140..f4f872f 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -126,9 +126,9 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI ::profiler::timestamp_t finishtime = 0; for (const auto& threadTree : _blocksTree) { - const auto node_block = threadTree.second.tree.children.front().node->block(); - const auto startTime = node_block->getBegin(); - const auto endTime = node_block->getEnd(); + const auto node_block = threadTree.second.tree.children.front().node; + const auto startTime = node_block->begin(); + const auto endTime = node_block->end(); if (_beginTime > startTime) _beginTime = startTime; @@ -160,7 +160,7 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI ::profiler::timestamp_t duration = 0; if (!block.children.empty()) { - duration = block.children.back().node->block()->getEnd() - block.children.front().node->block()->getBegin(); + duration = block.children.back().node->end() - block.children.front().node->begin(); } item->setTimeSmart(COL_DURATION, duration); @@ -172,7 +172,7 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) ::profiler::timestamp_t children_duration = 0; for (const auto& child : block.children) - children_duration += child.node->block()->duration(); + children_duration += child.node->duration(); item->setTimeSmart(COL_SELF_DURATION, children_duration); children_duration = 0; @@ -226,8 +226,8 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI if (_safelocker.interrupted()) break; - const auto startTime = block.tree->node->block()->getBegin(); - const auto endTime = block.tree->node->block()->getEnd(); + const auto startTime = block.tree->node->begin(); + const auto endTime = block.tree->node->end(); if (startTime > _right || endTime < _left) { _safelocker.setProgress((90 * ++i) / total); @@ -256,7 +256,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI if (!block.root->tree.children.empty()) { - duration = block.root->tree.children.back().node->block()->getEnd() - block.root->tree.children.front().node->block()->getBegin(); + duration = block.root->tree.children.back().node->end() - block.root->tree.children.front().node->begin(); } thread_item->setTimeSmart(COL_DURATION, duration); @@ -266,7 +266,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI // Calculate clean duration (sum of all children durations) ::profiler::timestamp_t children_duration = 0; for (const auto& child : block.root->tree.children) - children_duration += child.node->block()->duration(); + children_duration += child.node->duration(); thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); @@ -275,7 +275,8 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI auto item = new EasyTreeWidgetItem(block.tree, thread_item); duration = endTime - startTime; - item->setText(COL_NAME, ::profiler_gui::toUnicode(block.tree->node->getName())); + auto name = *block.tree->node->name() != 0 ? block.tree->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->name(); + item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); item->setTimeSmart(COL_DURATION, duration); item->setTimeMs(COL_BEGIN, startTime - _beginTime); item->setTimeMs(COL_END, endTime - _beginTime); @@ -338,7 +339,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setText(COL_PERCENT_SUM_PER_THREAD, ""); } - const auto color = block.tree->node->block()->getColor(); + const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->color(); const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); const auto fgColor = 0x00ffffff - bgColor; item->setBackgroundColor(bgColor); @@ -425,8 +426,8 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: if (_safelocker.interrupted()) break; - const auto startTime = child.node->block()->getBegin(); - const auto endTime = child.node->block()->getEnd(); + const auto startTime = child.node->begin(); + const auto endTime = child.node->end(); const auto duration = endTime - startTime; _duration += duration; @@ -436,7 +437,9 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: } auto item = new EasyTreeWidgetItem(&child, _parent); - item->setText(COL_NAME, ::profiler_gui::toUnicode(child.node->getName())); + + auto name = *child.node->name() != 0 ? child.node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->name(); + item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); item->setTimeSmart(COL_DURATION, duration); item->setTimeMs(COL_BEGIN, startTime - _beginTime); item->setTimeMs(COL_END, endTime - _beginTime); @@ -529,7 +532,7 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: item->setText(COL_PERCENT_SUM_PER_THREAD, ""); } - const auto color = child.node->block()->getColor(); + const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); const auto fgColor = 0x00ffffff - bgColor; item->setBackgroundColor(bgColor); diff --git a/reader/main.cpp b/reader/main.cpp index 9562641..c356840 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -42,31 +42,31 @@ public: void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int level = 0, profiler::timestamp_t parent_dur = 0, profiler::timestamp_t root_dur = 0) { - - if (tree.node){ - auto duration = tree.node->block()->duration(); - float duration_ms = duration / 1e6f; - float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f; - float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f; - std::cout << std::string(level, '\t') << tree.node->getName() - << std::string(5 - level, '\t') - /*<< std::string(level, ' ')*/ << percent << "%| " - << rpercent << "%| " - << duration_ms << " ms" - << std::endl; - if (root_dur == 0){ - root_dur = tree.node->block()->duration(); - } - } - else{ - root_dur = 0; - } - + // + //if (tree.node){ + // auto duration = tree.node->block()->duration(); + // float duration_ms = duration / 1e6f; + // float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f; + // float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f; + // std::cout << std::string(level, '\t') << tree.node->getName() + // << std::string(5 - level, '\t') + // /*<< std::string(level, ' ')*/ << percent << "%| " + // << rpercent << "%| " + // << duration_ms << " ms" + // << std::endl; + // if (root_dur == 0){ + // root_dur = tree.node->block()->duration(); + // } + //} + //else{ + // root_dur = 0; + //} + // - for (const auto& i : tree.children){ + //for (const auto& i : tree.children){ - printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur); - } + // printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur); + //} } int main(int argc, char* argv[]) @@ -110,8 +110,9 @@ int main(int argc, char* argv[]) auto start = std::chrono::system_clock::now(); - ::profiler::SerializedData data; - auto blocks_counter = fillTreesFromFile(filename.c_str(), data, threaded_trees, true); + ::profiler::SerializedData serialized_blocks, serialized_descriptors; + ::profiler::descriptors_list_t descriptors; + auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, threaded_trees, true); auto end = std::chrono::system_clock::now(); diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index d963d71..e5662aa 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -53,6 +53,14 @@ StaticBlockDescriptor::StaticBlockDescriptor(const char* _name, const char* _fil } +BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color) + : m_line(_line) + , m_type(_block_type) + , m_color(_color) +{ + +} + 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) @@ -135,9 +143,30 @@ void ProfileManager::setEnabled(bool isEnable) m_isEnabled = isEnable; } +////////////////////////////////////////////////////////////////////////// + +class FileWriter final +{ + std::ofstream m_file; + +public: + + FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { } + + template void write(const char* _data, T _size) { + m_file.write(_data, _size); + } + + template void write(const T& _data) { + m_file.write((const char*)&_data, sizeof(T)); + } +}; + +////////////////////////////////////////////////////////////////////////// + uint32_t ProfileManager::dumpBlocksToFile(const char* filename) { - std::ofstream of(filename, std::fstream::binary); + FileWriter of(filename); uint64_t usedMemorySize = 0; uint32_t blocks_number = 0; @@ -147,33 +176,33 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) blocks_number += static_cast(thread_storage.second.closedList.size()); } - of.write((const char*)&blocks_number, sizeof(decltype(blocks_number))); - of.write((const char*)&usedMemorySize, sizeof(decltype(usedMemorySize))); + of.write(blocks_number); + of.write(usedMemorySize); + of.write(static_cast(m_descriptors.size())); + of.write(m_usedMemorySize); - auto descriptors_number = static_cast(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(strlen(descriptor.name()) + 1); const auto filename_size = static_cast(strlen(descriptor.file()) + 1); const auto size = static_cast(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(size); + of.write(static_cast(descriptor)); + of.write(name_size); 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))); + of.write(thread_storage.first); + of.write(static_cast(thread_storage.second.closedList.size())); for (auto b : thread_storage.second.closedList) { auto sz = static_cast(sizeof(BaseBlockData) + strlen(b->name()) + 1); - of.write((const char*)&sz, sizeof(uint16_t)); + of.write(sz); of.write(b->data(), sz); } diff --git a/src/reader.cpp b/src/reader.cpp index 675d6a1..dc30d61 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -38,6 +38,42 @@ ////////////////////////////////////////////////////////////////////////// +struct passthrough_hash { + template inline size_t operator () (T _value) const { + return static_cast(_value); + } +}; + +////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + void SerializedData::set(char* _data) + { + if (m_data != nullptr) + delete[] m_data; + m_data = _data; + } + + extern "C" void release_stats(BlockStatistics*& _stats) + { + if (!_stats) + { + return; + } + + if (--_stats->calls_number == 0) + { + delete _stats; + } + + _stats = nullptr; + } + +} + +////////////////////////////////////////////////////////////////////////// + #ifdef _WIN32 /** \brief Simple C-string pointer with length. @@ -128,24 +164,23 @@ public: namespace std { /** \brief Simply returns precalculated hash of a C-string. */ - template <> - struct hash - { - inline size_t operator () (const hashed_cstr& _str) const - { + template <> struct hash { + inline size_t operator () (const hashed_cstr& _str) const { return _str.str_hash; } }; } -typedef ::std::unordered_map StatsMap; +typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; +typedef ::std::unordered_map IdMap; #else // TODO: optimize for Linux too #include -typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsMap; +typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; +typedef ::std::unordered_map<::std::string, ::profiler::block_id_t> IdMap; #endif @@ -165,9 +200,10 @@ automatically receive statistics update. */ ::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current) { - auto duration = _current.node->block()->duration(); - StatsMap::key_type key(_current.node->getName()); - auto it = _stats_map.find(key); + auto duration = _current.node->duration(); + //StatsMap::key_type key(_current.node->name()); + //auto it = _stats_map.find(key); + auto it = _stats_map.find(_current.node->id()); if (it != _stats_map.end()) { // Update already existing statistics @@ -199,7 +235,8 @@ automatically receive statistics update. // This is first time the block appear in the file. // Create new statistics. auto stats = new ::profiler::BlockStatistics(duration, _current.block_index); - _stats_map.insert(::std::make_pair(key, stats)); + //_stats_map.emplace(key, stats); + _stats_map.emplace(_current.node->id(), stats); return stats; } @@ -219,9 +256,9 @@ void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _ typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; -extern "C"{ +extern "C" { - unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) + unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) { PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan) @@ -229,134 +266,206 @@ extern "C"{ progress.store(0); if (!inFile.is_open()) - { - progress.store(100); return 0; - } PerThreadStats thread_statistics, parent_statistics, frame_statistics; unsigned int blocks_counter = 0; - uint64_t memory_size = 0; - inFile.read((char*)&memory_size, sizeof(uint64_t)); - if (memory_size == 0) - { - progress.store(100); + uint32_t total_blocks_number = 0; + inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); + if (total_blocks_number == 0) + return 0; + + uint64_t memory_size = 0; + inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); + if (memory_size == 0) return 0; - } serialized_blocks.set(new char[memory_size]); //memset(serialized_blocks[0], 0, memory_size); + + + uint32_t total_descriptors_number = 0; + inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); + if (total_descriptors_number == 0) + return 0; + + uint64_t descriptors_memory_size = 0; + inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); + if (descriptors_memory_size == 0) + return 0; + + descriptors.reserve(total_descriptors_number); + serialized_descriptors.set(new char[descriptors_memory_size]); + uint64_t i = 0; - - while (!inFile.eof()) + uint32_t read_number = 0; + while (!inFile.eof() && read_number < total_descriptors_number) { - PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green) - uint16_t sz = 0; - inFile.read((char*)&sz, sizeof(sz)); - if (sz == 0) - { - inFile.read((char*)&sz, sizeof(sz)); - continue; - } + ++read_number; - // TODO: use salloc::shared_allocator for allocation/deallocation safety - char* data = serialized_blocks[i];//new char[sz]; - inFile.read(data, sz); + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) + return 0; + + char* data = serialized_descriptors[i]; + inFile.read(data, sz); + //auto base_offset = data; + //inFile.read(data, sizeof(::profiler::BaseBlockDescriptor)); + //auto base = reinterpret_cast<::profiler::BaseBlockDescriptor*>(data); + //data = data + sizeof(::profiler::BaseBlockDescriptor); + //inFile.read(data, sizeof(uint16_t)); + //auto name_len = reinterpret_cast(data); + //data = data + sizeof(uint16_t); + //inFile.read(data, *name_len); + //data = data + *name_len; + //inFile.read(data, sz - ::std::distance(base_offset, data)); i += sz; - auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); + auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); + descriptors.push_back(descriptor); - ::profiler::BlocksTree tree; - tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); - tree.block_index = blocks_counter++; + progress.store(static_cast(10 * i / descriptors_memory_size)); + } - auto block_thread_id = baseData->getThreadId(); - auto& root = threaded_trees[block_thread_id]; - auto& per_parent_statistics = parent_statistics[block_thread_id]; - auto& per_thread_statistics = thread_statistics[block_thread_id]; + IdMap identification_table; - if (::profiler::BLOCK_TYPE_THREAD_SIGN == baseData->getType()) + i = 0; + read_number = 0; + while (!inFile.eof() && read_number < total_blocks_number) + { + PROFILER_BEGIN_BLOCK_GROUPED("Read thread from file", ::profiler::colors::Darkgreen) + + ::profiler::thread_id_t thread_id = 0; + inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); + + uint32_t blocks_number_in_thread = 0; + inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); + + auto& root = threaded_trees[thread_id]; + const auto threshold = read_number + blocks_number_in_thread; + while (!inFile.eof() && read_number < threshold) { - root.thread_name = tree.node->getName(); - } + PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green) - if (!root.tree.children.empty()) - { - auto& back = root.tree.children.back(); - auto t1 = back.node->block()->getEnd(); - auto mt0 = tree.node->block()->getBegin(); - if (mt0 < t1)//parent - starts earlier than last ends + ++read_number; + + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) + return 0; + + char* data = serialized_blocks[i]; + inFile.read(data, sz); + i += sz; + auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); + + ::profiler::BlocksTree tree; + tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); + tree.block_index = blocks_counter++; + + auto& per_parent_statistics = parent_statistics[thread_id]; + auto& per_thread_statistics = thread_statistics[thread_id]; + auto descriptor = descriptors[baseData->id()]; + + if (descriptor->type() == ::profiler::BLOCK_TYPE_THREAD_SIGN) { - //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); - /**/ - PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue) - auto rlower1 = ++root.tree.children.rbegin(); - for(; rlower1 != root.tree.children.rend(); ++rlower1){ - if(mt0 > rlower1->node->block()->getBegin()) - { - break; - } - } - auto lower = rlower1.base(); - ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); + root.thread_name = tree.node->name(); + } - root.tree.children.erase(lower, root.tree.children.end()); - - ::profiler::timestamp_t children_duration = 0; - if (gather_statistics) + if (*tree.node->name() != 0) + { + IdMap::key_type key(tree.node->name()); + auto it = identification_table.find(key); + if (it != identification_table.end()) { - PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta) - per_parent_statistics.clear(); - - //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows - //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows - // TODO: check this behavior on Linux - - for (auto& child : tree.children) - { - child.per_parent_stats = update_statistics(per_parent_statistics, child); - - children_duration += child.node->block()->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } + baseData->setId(it->second); } else { - for (const auto& child : tree.children) - { - children_duration += child.node->block()->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } + auto id = static_cast<::profiler::block_id_t>(descriptors.size()); + identification_table.emplace(key, id); + descriptors.push_back(descriptors[baseData->id()]); + baseData->setId(id); } - - ++tree.depth; } + + if (!root.tree.children.empty()) + { + auto& back = root.tree.children.back(); + auto t1 = back.node->end(); + auto mt0 = tree.node->begin(); + if (mt0 < t1)//parent - starts earlier than last ends + { + //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); + /**/ + PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue) + auto rlower1 = ++root.tree.children.rbegin(); + for (; rlower1 != root.tree.children.rend(); ++rlower1) + { + if (mt0 > rlower1->node->begin()) + { + break; + } + } + auto lower = rlower1.base(); + ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); + + root.tree.children.erase(lower, root.tree.children.end()); + PROFILER_END_BLOCK + + ::profiler::timestamp_t children_duration = 0; + if (gather_statistics) + { + PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta) + per_parent_statistics.clear(); + + //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows + //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows + // TODO: check this behavior on Linux + + for (auto& child : tree.children) + { + child.per_parent_stats = update_statistics(per_parent_statistics, child); + + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } + } + else + { + for (const auto& child : tree.children) + { + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } + } + + ++tree.depth; + } + } + + root.tree.children.emplace_back(::std::move(tree)); + + + + if (gather_statistics) + { + PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral) + auto& current = root.tree.children.back(); + current.per_thread_stats = update_statistics(per_thread_statistics, current); + } + + if (progress.load() < 0) + break; + progress.store(10 + static_cast(80 * i / memory_size)); } - - root.tree.children.emplace_back(::std::move(tree)); - - - //delete[] data; - - - - if (gather_statistics) - { - PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral) - auto& current = root.tree.children.back(); - current.per_thread_stats = update_statistics(per_thread_statistics, current); - } - - if (progress.load() < 0) - break; - progress.store(static_cast(90 * i / memory_size)); } if (progress.load() < 0) { - progress.store(100); serialized_blocks.clear(); threaded_trees.clear(); return 0; @@ -384,7 +493,6 @@ extern "C"{ { frame.per_parent_stats = update_statistics(per_parent_statistics, frame); - // TODO: Optimize per frame stats gathering per_frame_statistics.clear(); update_statistics_recursive(per_frame_statistics, frame); @@ -426,7 +534,6 @@ extern "C"{ PROFILER_END_BLOCK // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors - progress.store(100); return blocks_counter; } } From 4ff13053eca957922120451d33ba8ffe4fcf79f4 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 21:06:23 +0300 Subject: [PATCH 03/37] Remastering profiler API. Fixed read/write --- profiler_gui/main_window.cpp | 1060 ++++++++++++++++----------------- src/profile_manager.cpp | 454 +++++++-------- src/profile_manager.h | 4 +- src/reader.cpp | 1068 +++++++++++++++++----------------- 4 files changed, 1287 insertions(+), 1299 deletions(-) diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 625c9a9..8edf2da 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -1,530 +1,530 @@ -/************************************************************************ -* file name : main_window.cpp -* ----------------- : -* creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin -* author : Victor Zarubkin -* email : v.s.zarubkin@gmail.com -* ----------------- : -* description : The file contains implementation of MainWindow for easy_profiler GUI. -* ----------------- : -* change log : * 2016/06/26 Victor Zarubkin: Initial commit. -* : -* : * 2016/06/27 Victor Zarubkin: Passing blocks number to EasyTreeWidget::setTree(). -* : -* : * 2016/06/29 Victor Zarubkin: Added menu with tests. -* : -* : * 2016/06/30 Sergey Yagovtsev: Open file by command line argument -* : -* : * -* ----------------- : -* license : TODO: add license text -************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "main_window.h" -#include "blocks_tree_widget.h" -#include "blocks_graphics_view.h" -#include "globals.h" - -////////////////////////////////////////////////////////////////////////// - -const int LOADER_TIMER_INTERVAL = 40; - -////////////////////////////////////////////////////////////////////////// - -EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr) -{ - setObjectName("ProfilerGUI_MainWindow"); - setWindowTitle("EasyProfiler Reader v0.2.0"); - setDockNestingEnabled(true); - resize(800, 600); - - setStatusBar(new QStatusBar()); - - auto graphicsView = new EasyGraphicsViewWidget(); - m_graphicsView = new QDockWidget("Blocks diagram"); - m_graphicsView->setMinimumHeight(50); - m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas); - m_graphicsView->setWidget(graphicsView); - - auto treeWidget = new EasyTreeWidget(); - m_treeWidget = new QDockWidget("Blocks hierarchy"); - m_treeWidget->setMinimumHeight(50); - m_treeWidget->setAllowedAreas(Qt::AllDockWidgetAreas); - m_treeWidget->setWidget(treeWidget); - - addDockWidget(Qt::TopDockWidgetArea, m_graphicsView); - addDockWidget(Qt::BottomDockWidgetArea, m_treeWidget); - - loadSettings(); - - - - auto menu = new QMenu("&File"); - - auto action = menu->addAction("&Open"); - connect(action, &QAction::triggered, this, &This::onOpenFileClicked); - - action = menu->addAction("&Reload"); - connect(action, &QAction::triggered, this, &This::onReloadFileClicked); - - menu->addSeparator(); - action = menu->addAction("&Exit"); - connect(action, &QAction::triggered, this, &This::onExitClicked); - - menuBar()->addMenu(menu); - - - - menu = new QMenu("&View"); - - action = menu->addAction("Expand all"); - connect(action, &QAction::triggered, this, &This::onExpandAllClicked); - - action = menu->addAction("Collapse all"); - connect(action, &QAction::triggered, this, &This::onCollapseAllClicked); - - menu->addSeparator(); - action = menu->addAction("Draw items' borders"); - action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); - connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); - - action = menu->addAction("Collapse items on tree reset"); - action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); - connect(action, &QAction::triggered, this, &This::onCollapseItemsAfterCloseChanged); - - action = menu->addAction("Expand all on file open"); - action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); - connect(action, &QAction::triggered, this, &This::onAllItemsExpandedByDefaultChange); - - action = menu->addAction("Bind scene and tree expand"); - action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); - connect(action, &QAction::triggered, this, &This::onBindExpandStatusChange); - - menu->addSeparator(); - auto submenu = menu->addMenu("Chronometer text"); - auto actionGroup = new QActionGroup(this); - actionGroup->setExclusive(true); - - action = new QAction("At top", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Top)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - action = new QAction("At center", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Center)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - action = new QAction("At bottom", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Bottom)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - menuBar()->addMenu(menu); - - - - menu = new QMenu("&Settings"); - submenu = menu->addMenu("&Encoding"); - actionGroup = new QActionGroup(this); - actionGroup->setExclusive(true); - - auto default_codec_mib = QTextCodec::codecForLocale()->mibEnum(); - foreach (int mib, QTextCodec::availableMibs()) - { - auto codec = QTextCodec::codecForMib(mib)->name(); - - action = new QAction(codec, actionGroup); - action->setCheckable(true); - if (mib == default_codec_mib) - action->setChecked(true); - - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onEncodingChanged); - } - - menuBar()->addMenu(menu); - - connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget, &EasyTreeWidget::setTreeBlocks); - connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout); - - - m_progress = new QProgressDialog("Loading file...", "Cancel", 0, 100, this); - m_progress->setFixedWidth(300); - m_progress->setWindowTitle("EasyProfiler"); - m_progress->setModal(true); - m_progress->setValue(100); - //m_progress->hide(); - connect(m_progress, &QProgressDialog::canceled, this, &This::onFileReaderCancel); - - - loadGeometry(); - - if(QCoreApplication::arguments().size() > 1) - { - auto opened_filename = QCoreApplication::arguments().at(1); - loadFile(opened_filename); - } -} - -EasyMainWindow::~EasyMainWindow() -{ - delete m_progress; -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onOpenFileClicked(bool) -{ - auto filename = QFileDialog::getOpenFileName(this, "Open profiler log", m_lastFile, "Profiler Log File (*.prof);;All Files (*.*)"); - loadFile(filename); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::loadFile(const QString& filename) -{ - const auto i = filename.lastIndexOf(QChar('/')); - const auto j = filename.lastIndexOf(QChar('\\')); - m_progress->setLabelText(QString("Loading %1...").arg(filename.mid(::std::max(i, j) + 1))); - - m_progress->setValue(0); - //m_progress->show(); - m_readerTimer.start(LOADER_TIMER_INTERVAL); - m_reader.load(filename); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onReloadFileClicked(bool) -{ - if (m_lastFile.isEmpty()) - return; - loadFile(m_lastFile); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onExitClicked(bool) -{ - close(); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onEncodingChanged(bool) -{ - auto _sender = qobject_cast(sender()); - auto name = _sender->text(); - QTextCodec *codec = QTextCodec::codecForName(name.toStdString().c_str()); - QTextCodec::setCodecForLocale(codec); -} - -void EasyMainWindow::onChronoTextPosChanged(bool) -{ - auto _sender = qobject_cast(sender()); - ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt()); - emit ::profiler_gui::EASY_GLOBALS.events.chronoPositionChanged(); -} - -void EasyMainWindow::onDrawBordersChanged(bool _checked) -{ - ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = _checked; - emit ::profiler_gui::EASY_GLOBALS.events.drawBordersChanged(); -} - -void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked) -{ - ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = _checked; -} - -void EasyMainWindow::onAllItemsExpandedByDefaultChange(bool _checked) -{ - ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = _checked; -} - -void EasyMainWindow::onBindExpandStatusChange(bool _checked) -{ - ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = _checked; -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onExpandAllClicked(bool) -{ - for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) - block.expanded = true; - - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); - - auto tree = static_cast(m_treeWidget->widget()); - const QSignalBlocker b(tree); - tree->expandAll(); -} - -void EasyMainWindow::onCollapseAllClicked(bool) -{ - for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) - block.expanded = false; - - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); - - auto tree = static_cast(m_treeWidget->widget()); - const QSignalBlocker b(tree); - tree->collapseAll(); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::closeEvent(QCloseEvent* close_event) -{ - saveSettingsAndGeometry(); - Parent::closeEvent(close_event); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::loadSettings() -{ - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); - settings.beginGroup("main"); - - auto last_file = settings.value("last_file"); - if (!last_file.isNull()) - { - m_lastFile = last_file.toString(); - } - - - auto val = settings.value("chrono_text_position"); - if (!val.isNull()) - { - ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(val.toInt()); - } - - - auto flag = settings.value("draw_graphics_items_borders"); - if (!flag.isNull()) - { - ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = flag.toBool(); - } - - flag = settings.value("collapse_items_on_tree_close"); - if (!flag.isNull()) - { - ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); - } - - flag = settings.value("all_items_expanded_by_default"); - if (!flag.isNull()) - { - ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = flag.toBool(); - } - - flag = settings.value("bind_scene_and_tree_expand_status"); - if (!flag.isNull()) - { - ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool(); - } - - QString encoding = settings.value("encoding", "UTF-8").toString(); - auto default_codec_mib = QTextCodec::codecForName(encoding.toStdString().c_str())->mibEnum(); - auto default_codec = QTextCodec::codecForMib(default_codec_mib); - QTextCodec::setCodecForLocale(default_codec); - - settings.endGroup(); -} - -void EasyMainWindow::loadGeometry() -{ - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); - settings.beginGroup("main"); - auto geometry = settings.value("geometry").toByteArray(); - if (!geometry.isEmpty()) - restoreGeometry(geometry); - settings.endGroup(); -} - -void EasyMainWindow::saveSettingsAndGeometry() -{ - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); - settings.beginGroup("main"); - - settings.setValue("geometry", this->saveGeometry()); - settings.setValue("last_file", m_lastFile); - settings.setValue("chrono_text_position", static_cast(::profiler_gui::EASY_GLOBALS.chrono_text_position)); - settings.setValue("draw_graphics_items_borders", ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); - settings.setValue("collapse_items_on_tree_close", ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); - settings.setValue("all_items_expanded_by_default", ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); - settings.setValue("bind_scene_and_tree_expand_status", ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); - settings.setValue("encoding", QTextCodec::codecForLocale()->name()); - - settings.endGroup(); -} - -////////////////////////////////////////////////////////////////////////// - -void EasyMainWindow::onFileReaderTimeout() -{ - if (m_reader.done()) - { - auto nblocks = m_reader.size(); - if (nblocks != 0) - { - static_cast(m_treeWidget->widget())->clearSilent(true); - - ::profiler::SerializedData serialized_blocks, serialized_descriptors; - ::profiler::descriptors_list_t descriptors; - ::profiler::thread_blocks_tree_t prof_blocks; - QString filename; - m_reader.get(serialized_blocks, serialized_descriptors, descriptors, prof_blocks, filename); - - if (prof_blocks.size() > 0xff) - { - qWarning() << "Warning: file " << filename << " contains " << prof_blocks.size() << " threads!"; - qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed."; - } - - m_lastFile = ::std::move(filename); - m_serializedBlocks = ::std::move(serialized_blocks); - m_serializedDescriptors = ::std::move(serialized_descriptors); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); - ::profiler_gui::EASY_GLOBALS.descriptors.swap(descriptors); - ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); - memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); - for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); - - static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); - } - else - { - qWarning() << "Warning: Can not open file " << m_reader.filename() << " or file is corrupted"; - } - - m_reader.interrupt(); - - m_readerTimer.stop(); - m_progress->setValue(100); - //m_progress->hide(); - - if (::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default) - { - onExpandAllClicked(true); - } - } - else - { - m_progress->setValue(m_reader.progress()); - } -} - -void EasyMainWindow::onFileReaderCancel() -{ - m_readerTimer.stop(); - m_reader.interrupt(); - m_progress->setValue(100); - //m_progress->hide(); -} - -////////////////////////////////////////////////////////////////////////// - -EasyFileReader::EasyFileReader() -{ - -} - -EasyFileReader::~EasyFileReader() -{ - interrupt(); -} - -bool EasyFileReader::done() const -{ - return m_bDone.load(); -} - -int EasyFileReader::progress() const -{ - return m_progress.load(); -} - -unsigned int EasyFileReader::size() const -{ - return m_size.load(); -} - -const QString& EasyFileReader::filename() const -{ - return m_filename; -} - -void EasyFileReader::load(const QString& _filename) -{ - interrupt(); - - m_filename = _filename; - m_thread = ::std::move(::std::thread([this]() { - m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocksTree, true)); - m_progress.store(100); - m_bDone.store(true); - })); -} - -void EasyFileReader::interrupt() -{ - m_progress.store(-100); - if (m_thread.joinable()) - m_thread.join(); - - m_bDone.store(false); - m_progress.store(0); - m_size.store(0); - m_serializedBlocks.clear(); - m_serializedDescriptors.clear(); - m_descriptors.clear(); - m_blocksTree.clear(); -} - -void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, - ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename) -{ - if (done()) - { - m_serializedBlocks.swap(_serializedBlocks); - m_serializedDescriptors.swap(_serializedDescriptors); - ::profiler::descriptors_list_t(m_descriptors).swap(_descriptors); - m_blocksTree.swap(_tree); - m_filename.swap(_filename); - } -} - -////////////////////////////////////////////////////////////////////////// +/************************************************************************ +* file name : main_window.cpp +* ----------------- : +* creation time : 2016/06/26 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of MainWindow for easy_profiler GUI. +* ----------------- : +* change log : * 2016/06/26 Victor Zarubkin: Initial commit. +* : +* : * 2016/06/27 Victor Zarubkin: Passing blocks number to EasyTreeWidget::setTree(). +* : +* : * 2016/06/29 Victor Zarubkin: Added menu with tests. +* : +* : * 2016/06/30 Sergey Yagovtsev: Open file by command line argument +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "main_window.h" +#include "blocks_tree_widget.h" +#include "blocks_graphics_view.h" +#include "globals.h" + +////////////////////////////////////////////////////////////////////////// + +const int LOADER_TIMER_INTERVAL = 40; + +////////////////////////////////////////////////////////////////////////// + +EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr) +{ + setObjectName("ProfilerGUI_MainWindow"); + setWindowTitle("EasyProfiler Reader v0.2.0"); + setDockNestingEnabled(true); + resize(800, 600); + + setStatusBar(new QStatusBar()); + + auto graphicsView = new EasyGraphicsViewWidget(); + m_graphicsView = new QDockWidget("Blocks diagram"); + m_graphicsView->setMinimumHeight(50); + m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas); + m_graphicsView->setWidget(graphicsView); + + auto treeWidget = new EasyTreeWidget(); + m_treeWidget = new QDockWidget("Blocks hierarchy"); + m_treeWidget->setMinimumHeight(50); + m_treeWidget->setAllowedAreas(Qt::AllDockWidgetAreas); + m_treeWidget->setWidget(treeWidget); + + addDockWidget(Qt::TopDockWidgetArea, m_graphicsView); + addDockWidget(Qt::BottomDockWidgetArea, m_treeWidget); + + loadSettings(); + + + + auto menu = new QMenu("&File"); + + auto action = menu->addAction("&Open"); + connect(action, &QAction::triggered, this, &This::onOpenFileClicked); + + action = menu->addAction("&Reload"); + connect(action, &QAction::triggered, this, &This::onReloadFileClicked); + + menu->addSeparator(); + action = menu->addAction("&Exit"); + connect(action, &QAction::triggered, this, &This::onExitClicked); + + menuBar()->addMenu(menu); + + + + menu = new QMenu("&View"); + + action = menu->addAction("Expand all"); + connect(action, &QAction::triggered, this, &This::onExpandAllClicked); + + action = menu->addAction("Collapse all"); + connect(action, &QAction::triggered, this, &This::onCollapseAllClicked); + + menu->addSeparator(); + action = menu->addAction("Draw items' borders"); + action->setCheckable(true); + action->setChecked(::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); + connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); + + action = menu->addAction("Collapse items on tree reset"); + action->setCheckable(true); + action->setChecked(::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); + connect(action, &QAction::triggered, this, &This::onCollapseItemsAfterCloseChanged); + + action = menu->addAction("Expand all on file open"); + action->setCheckable(true); + action->setChecked(::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); + connect(action, &QAction::triggered, this, &This::onAllItemsExpandedByDefaultChange); + + action = menu->addAction("Bind scene and tree expand"); + action->setCheckable(true); + action->setChecked(::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); + connect(action, &QAction::triggered, this, &This::onBindExpandStatusChange); + + menu->addSeparator(); + auto submenu = menu->addMenu("Chronometer text"); + auto actionGroup = new QActionGroup(this); + actionGroup->setExclusive(true); + + action = new QAction("At top", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Top)); + if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + action = new QAction("At center", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Center)); + if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + action = new QAction("At bottom", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Bottom)); + if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + menuBar()->addMenu(menu); + + + + menu = new QMenu("&Settings"); + submenu = menu->addMenu("&Encoding"); + actionGroup = new QActionGroup(this); + actionGroup->setExclusive(true); + + auto default_codec_mib = QTextCodec::codecForLocale()->mibEnum(); + foreach (int mib, QTextCodec::availableMibs()) + { + auto codec = QTextCodec::codecForMib(mib)->name(); + + action = new QAction(codec, actionGroup); + action->setCheckable(true); + if (mib == default_codec_mib) + action->setChecked(true); + + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onEncodingChanged); + } + + menuBar()->addMenu(menu); + + connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget, &EasyTreeWidget::setTreeBlocks); + connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout); + + + m_progress = new QProgressDialog("Loading file...", "Cancel", 0, 100, this); + m_progress->setFixedWidth(300); + m_progress->setWindowTitle("EasyProfiler"); + m_progress->setModal(true); + m_progress->setValue(100); + //m_progress->hide(); + connect(m_progress, &QProgressDialog::canceled, this, &This::onFileReaderCancel); + + + loadGeometry(); + + if(QCoreApplication::arguments().size() > 1) + { + auto opened_filename = QCoreApplication::arguments().at(1); + loadFile(opened_filename); + } +} + +EasyMainWindow::~EasyMainWindow() +{ + delete m_progress; +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onOpenFileClicked(bool) +{ + auto filename = QFileDialog::getOpenFileName(this, "Open profiler log", m_lastFile, "Profiler Log File (*.prof);;All Files (*.*)"); + loadFile(filename); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::loadFile(const QString& filename) +{ + const auto i = filename.lastIndexOf(QChar('/')); + const auto j = filename.lastIndexOf(QChar('\\')); + m_progress->setLabelText(QString("Loading %1...").arg(filename.mid(::std::max(i, j) + 1))); + + m_progress->setValue(0); + m_progress->show(); + m_readerTimer.start(LOADER_TIMER_INTERVAL); + m_reader.load(filename); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onReloadFileClicked(bool) +{ + if (m_lastFile.isEmpty()) + return; + loadFile(m_lastFile); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onExitClicked(bool) +{ + close(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onEncodingChanged(bool) +{ + auto _sender = qobject_cast(sender()); + auto name = _sender->text(); + QTextCodec *codec = QTextCodec::codecForName(name.toStdString().c_str()); + QTextCodec::setCodecForLocale(codec); +} + +void EasyMainWindow::onChronoTextPosChanged(bool) +{ + auto _sender = qobject_cast(sender()); + ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt()); + emit ::profiler_gui::EASY_GLOBALS.events.chronoPositionChanged(); +} + +void EasyMainWindow::onDrawBordersChanged(bool _checked) +{ + ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = _checked; + emit ::profiler_gui::EASY_GLOBALS.events.drawBordersChanged(); +} + +void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked) +{ + ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = _checked; +} + +void EasyMainWindow::onAllItemsExpandedByDefaultChange(bool _checked) +{ + ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = _checked; +} + +void EasyMainWindow::onBindExpandStatusChange(bool _checked) +{ + ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = _checked; +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onExpandAllClicked(bool) +{ + for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) + block.expanded = true; + + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + + auto tree = static_cast(m_treeWidget->widget()); + const QSignalBlocker b(tree); + tree->expandAll(); +} + +void EasyMainWindow::onCollapseAllClicked(bool) +{ + for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) + block.expanded = false; + + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + + auto tree = static_cast(m_treeWidget->widget()); + const QSignalBlocker b(tree); + tree->collapseAll(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::closeEvent(QCloseEvent* close_event) +{ + saveSettingsAndGeometry(); + Parent::closeEvent(close_event); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::loadSettings() +{ + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("main"); + + auto last_file = settings.value("last_file"); + if (!last_file.isNull()) + { + m_lastFile = last_file.toString(); + } + + + auto val = settings.value("chrono_text_position"); + if (!val.isNull()) + { + ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(val.toInt()); + } + + + auto flag = settings.value("draw_graphics_items_borders"); + if (!flag.isNull()) + { + ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = flag.toBool(); + } + + flag = settings.value("collapse_items_on_tree_close"); + if (!flag.isNull()) + { + ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); + } + + flag = settings.value("all_items_expanded_by_default"); + if (!flag.isNull()) + { + ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = flag.toBool(); + } + + flag = settings.value("bind_scene_and_tree_expand_status"); + if (!flag.isNull()) + { + ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool(); + } + + QString encoding = settings.value("encoding", "UTF-8").toString(); + auto default_codec_mib = QTextCodec::codecForName(encoding.toStdString().c_str())->mibEnum(); + auto default_codec = QTextCodec::codecForMib(default_codec_mib); + QTextCodec::setCodecForLocale(default_codec); + + settings.endGroup(); +} + +void EasyMainWindow::loadGeometry() +{ + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("main"); + auto geometry = settings.value("geometry").toByteArray(); + if (!geometry.isEmpty()) + restoreGeometry(geometry); + settings.endGroup(); +} + +void EasyMainWindow::saveSettingsAndGeometry() +{ + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("main"); + + settings.setValue("geometry", this->saveGeometry()); + settings.setValue("last_file", m_lastFile); + settings.setValue("chrono_text_position", static_cast(::profiler_gui::EASY_GLOBALS.chrono_text_position)); + settings.setValue("draw_graphics_items_borders", ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); + settings.setValue("collapse_items_on_tree_close", ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); + settings.setValue("all_items_expanded_by_default", ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); + settings.setValue("bind_scene_and_tree_expand_status", ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); + settings.setValue("encoding", QTextCodec::codecForLocale()->name()); + + settings.endGroup(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onFileReaderTimeout() +{ + if (m_reader.done()) + { + auto nblocks = m_reader.size(); + if (nblocks != 0) + { + static_cast(m_treeWidget->widget())->clearSilent(true); + + ::profiler::SerializedData serialized_blocks, serialized_descriptors; + ::profiler::descriptors_list_t descriptors; + ::profiler::thread_blocks_tree_t prof_blocks; + QString filename; + m_reader.get(serialized_blocks, serialized_descriptors, descriptors, prof_blocks, filename); + + if (prof_blocks.size() > 0xff) + { + qWarning() << "Warning: file " << filename << " contains " << prof_blocks.size() << " threads!"; + qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed."; + } + + m_lastFile = ::std::move(filename); + m_serializedBlocks = ::std::move(serialized_blocks); + m_serializedDescriptors = ::std::move(serialized_descriptors); + ::profiler_gui::EASY_GLOBALS.selected_thread = 0; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); + ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); + ::profiler_gui::EASY_GLOBALS.descriptors.swap(descriptors); + ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); + memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); + for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); + + static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); + } + else + { + qWarning() << "Warning: Can not open file " << m_reader.filename() << " or file is corrupted"; + } + + m_reader.interrupt(); + + m_readerTimer.stop(); + m_progress->setValue(100); + //m_progress->hide(); + + if (::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default) + { + onExpandAllClicked(true); + } + } + else + { + m_progress->setValue(m_reader.progress()); + } +} + +void EasyMainWindow::onFileReaderCancel() +{ + m_readerTimer.stop(); + m_reader.interrupt(); + m_progress->setValue(100); + //m_progress->hide(); +} + +////////////////////////////////////////////////////////////////////////// + +EasyFileReader::EasyFileReader() +{ + +} + +EasyFileReader::~EasyFileReader() +{ + interrupt(); +} + +bool EasyFileReader::done() const +{ + return m_bDone.load(); +} + +int EasyFileReader::progress() const +{ + return m_progress.load(); +} + +unsigned int EasyFileReader::size() const +{ + return m_size.load(); +} + +const QString& EasyFileReader::filename() const +{ + return m_filename; +} + +void EasyFileReader::load(const QString& _filename) +{ + interrupt(); + + m_filename = _filename; + m_thread = ::std::move(::std::thread([this]() { + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocksTree, true)); + m_progress.store(100); + m_bDone.store(true); + })); +} + +void EasyFileReader::interrupt() +{ + m_progress.store(-100); + if (m_thread.joinable()) + m_thread.join(); + + m_bDone.store(false); + m_progress.store(0); + m_size.store(0); + m_serializedBlocks.clear(); + m_serializedDescriptors.clear(); + m_descriptors.clear(); + m_blocksTree.clear(); +} + +void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, + ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename) +{ + if (done()) + { + m_serializedBlocks.swap(_serializedBlocks); + m_serializedDescriptors.swap(_serializedDescriptors); + ::profiler::descriptors_list_t(m_descriptors).swap(_descriptors); + m_blocksTree.swap(_tree); + m_filename.swap(_filename); + } +} + +////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index e5662aa..85e5e52 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -1,227 +1,227 @@ -#include "profile_manager.h" -#include "profiler/serialized_block.h" - -#include -#include - -#include - -using namespace profiler; - -auto& MANAGER = ProfileManager::instance(); - -extern "C"{ - - void PROFILER_API endBlock() - { - MANAGER.endBlock(); - } - - void PROFILER_API setEnabled(bool isEnable) - { - MANAGER.setEnabled(isEnable); - } - void PROFILER_API beginBlock(Block& _block) - { - MANAGER.beginBlock(_block); - } - - unsigned int PROFILER_API dumpBlocksToFile(const char* filename) - { - return MANAGER.dumpBlocksToFile(filename); - } - - void PROFILER_API setThreadName(const char* name) - { - return MANAGER.setThreadName(name); - } -} - -SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) - : BaseBlockData(block) -{ - auto pName = const_cast(name()); - if (name_length) strncpy(pName, block.name(), name_length); - pName[name_length] = 0; -} - -////////////////////////////////////////////////////////////////////////// - -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)) -{ - -} - -BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color) - : m_line(_line) - , m_type(_block_type) - , m_color(_color) -{ - -} - -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(strlen(block.name())); - auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); - auto data = m_allocator.allocate(size); - ::new (static_cast(data)) SerializedBlock(block, name_length); - usedMemorySize += size; - closedList.emplace_back(reinterpret_cast(data)); -} - -void ThreadStorage::clearClosed() -{ - serialized_list_t().swap(closedList); - m_allocator.clear(); - usedMemorySize = 0; -} - -////////////////////////////////////////////////////////////////////////// - -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; - - 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; - - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.openedList.empty()) - return; - - Block& lastBlock = thread_storage.openedList.top(); - if (!lastBlock.isFinished()) - lastBlock.finish(); - - thread_storage.store(lastBlock); - thread_storage.openedList.pop(); -} - -void ProfileManager::setEnabled(bool isEnable) -{ - m_isEnabled = isEnable; -} - -////////////////////////////////////////////////////////////////////////// - -class FileWriter final -{ - std::ofstream m_file; - -public: - - FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { } - - template void write(const char* _data, T _size) { - m_file.write(_data, _size); - } - - template void write(const T& _data) { - m_file.write((const char*)&_data, sizeof(T)); - } -}; - -////////////////////////////////////////////////////////////////////////// - -uint32_t ProfileManager::dumpBlocksToFile(const char* filename) -{ - FileWriter of(filename); - - uint64_t usedMemorySize = 0; - uint32_t blocks_number = 0; - for (const auto& thread_storage : m_threads) - { - usedMemorySize += thread_storage.second.usedMemorySize; - blocks_number += static_cast(thread_storage.second.closedList.size()); - } - - of.write(blocks_number); - of.write(usedMemorySize); - of.write(static_cast(m_descriptors.size())); - of.write(m_usedMemorySize); - - for (const auto& descriptor : m_descriptors) - { - const auto name_size = static_cast(strlen(descriptor.name()) + 1); - const auto filename_size = static_cast(strlen(descriptor.file()) + 1); - const auto size = static_cast(sizeof(profiler::BaseBlockDescriptor)) + name_size + filename_size + sizeof(uint16_t); - - of.write(size); - of.write(static_cast(descriptor)); - of.write(name_size); - of.write(descriptor.name(), name_size); - of.write(descriptor.file(), filename_size); - } - - for (auto& thread_storage : m_threads) - { - of.write(thread_storage.first); - of.write(static_cast(thread_storage.second.closedList.size())); - - for (auto b : thread_storage.second.closedList) - { - auto sz = static_cast(sizeof(BaseBlockData) + strlen(b->name()) + 1); - of.write(sz); - of.write(b->data(), sz); - } - - thread_storage.second.clearClosed(); - } - - return blocks_number; -} - -void ProfileManager::setThreadName(const char* name) -{ - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.named) - return; - - 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; -} - -////////////////////////////////////////////////////////////////////////// - +#include "profile_manager.h" +#include "profiler/serialized_block.h" + +#include +#include + +#include + +using namespace profiler; + +auto& MANAGER = ProfileManager::instance(); + +extern "C"{ + + void PROFILER_API endBlock() + { + MANAGER.endBlock(); + } + + void PROFILER_API setEnabled(bool isEnable) + { + MANAGER.setEnabled(isEnable); + } + void PROFILER_API beginBlock(Block& _block) + { + MANAGER.beginBlock(_block); + } + + unsigned int PROFILER_API dumpBlocksToFile(const char* filename) + { + return MANAGER.dumpBlocksToFile(filename); + } + + void PROFILER_API setThreadName(const char* name) + { + return MANAGER.setThreadName(name); + } +} + +SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) + : BaseBlockData(block) +{ + auto pName = const_cast(name()); + if (name_length) strncpy(pName, block.name(), name_length); + pName[name_length] = 0; +} + +////////////////////////////////////////////////////////////////////////// + +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)) +{ + +} + +BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color) + : m_line(_line) + , m_type(_block_type) + , m_color(_color) +{ + +} + +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(strlen(block.name())); + auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); + auto data = m_allocator.allocate(size); + ::new (static_cast(data)) SerializedBlock(block, name_length); + usedMemorySize += size; + closedList.emplace_back(reinterpret_cast(data)); +} + +void ThreadStorage::clearClosed() +{ + serialized_list_t().swap(closedList); + m_allocator.clear(); + usedMemorySize = 0; +} + +////////////////////////////////////////////////////////////////////////// + +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; + + 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; + + auto& thread_storage = threadStorage(getCurrentThreadId()); + if (thread_storage.openedList.empty()) + return; + + Block& lastBlock = thread_storage.openedList.top(); + if (!lastBlock.isFinished()) + lastBlock.finish(); + + thread_storage.store(lastBlock); + thread_storage.openedList.pop(); +} + +void ProfileManager::setEnabled(bool isEnable) +{ + m_isEnabled = isEnable; +} + +////////////////////////////////////////////////////////////////////////// + +class FileWriter final +{ + std::ofstream m_file; + +public: + + FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { } + + template void write(const char* _data, T _size) { + m_file.write(_data, _size); + } + + template void write(const T& _data) { + m_file.write((const char*)&_data, sizeof(T)); + } +}; + +////////////////////////////////////////////////////////////////////////// + +uint32_t ProfileManager::dumpBlocksToFile(const char* filename) +{ + FileWriter of(filename); + + uint64_t usedMemorySize = 0; + uint32_t blocks_number = 0; + for (const auto& thread_storage : m_threads) + { + usedMemorySize += thread_storage.second.usedMemorySize; + blocks_number += static_cast(thread_storage.second.closedList.size()); + } + + of.write(blocks_number); + of.write(usedMemorySize); + of.write(static_cast(m_descriptors.size())); + of.write(m_usedMemorySize); + + for (const auto& descriptor : m_descriptors) + { + const auto name_size = static_cast(strlen(descriptor.name()) + 1); + const auto filename_size = static_cast(strlen(descriptor.file()) + 1); + const auto size = static_cast(sizeof(profiler::BaseBlockDescriptor) + name_size + filename_size + sizeof(uint16_t)); + + of.write(size); + of.write(descriptor); + of.write(name_size); + of.write(descriptor.name(), name_size); + of.write(descriptor.file(), filename_size); + } + + for (auto& thread_storage : m_threads) + { + of.write(thread_storage.first); + of.write(static_cast(thread_storage.second.closedList.size())); + + for (auto b : thread_storage.second.closedList) + { + auto sz = static_cast(sizeof(BaseBlockData) + strlen(b->name()) + 1); + of.write(sz); + of.write(b->data(), sz); + } + + thread_storage.second.clearClosed(); + } + + return blocks_number; +} + +void ProfileManager::setThreadName(const char* name) +{ + auto& thread_storage = threadStorage(getCurrentThreadId()); + if (thread_storage.named) + return; + + 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; +} + +////////////////////////////////////////////////////////////////////////// + diff --git a/src/profile_manager.h b/src/profile_manager.h index c5e0547..abc1da5 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -55,9 +55,7 @@ namespace profiler { class SerializedBlock; } template class chunk_allocator final { - struct chunk { - T data[N] = {}; - }; + struct chunk { T data[N]; }; std::list m_chunks; uint16_t m_size; diff --git a/src/reader.cpp b/src/reader.cpp index dc30d61..893148e 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1,539 +1,529 @@ -/************************************************************************ -* file name : reader.cpp -* ----------------- : -* creation time : 2016/06/19 -* copyright : (c) 2016 Sergey Yagovtsev, Victor Zarubkin -* authors : Sergey Yagovtsev, Victor Zarubkin -* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com -* ----------------- : -* description : The file contains implementation of fillTreesFromFile function -* : which reads profiler file and fill profiler blocks tree. -* ----------------- : -* change log : * 2016/06/19 Sergey Yagovtsev: First fillTreesFromFile implementation. -* : -* : * 2016/06/25 Victor Zarubkin: Removed unnecessary memory allocation and copy -* : when creating and inserting blocks into the tree. -* : -* : * 2016/06/26 Victor Zarubkin: Added statistics gathering (min, max, average duration, -* : number of block calls). -* : * 2016/06/26 Victor Zarubkin, Sergey Yagovtsev: Added statistics gathering for root -* : blocks in the tree. -* : -* : * 2016/06/29 Victor Zarubkin: Added calculaton of total children number for blocks. -* : -* : * 2016/06/30 Victor Zarubkin: Added this header. -* : Added tree depth calculation. -* : -* : * -* ----------------- : -* license : TODO: add license text -************************************************************************/ - -#include "profiler/reader.h" -#include -#include -#include -#include -#include - -////////////////////////////////////////////////////////////////////////// - -struct passthrough_hash { - template inline size_t operator () (T _value) const { - return static_cast(_value); - } -}; - -////////////////////////////////////////////////////////////////////////// - -namespace profiler { - - void SerializedData::set(char* _data) - { - if (m_data != nullptr) - delete[] m_data; - m_data = _data; - } - - extern "C" void release_stats(BlockStatistics*& _stats) - { - if (!_stats) - { - return; - } - - if (--_stats->calls_number == 0) - { - delete _stats; - } - - _stats = nullptr; - } - -} - -////////////////////////////////////////////////////////////////////////// - -#ifdef _WIN32 - -/** \brief Simple C-string pointer with length. - -It is used as base class for a key in std::unordered_map. -It is used to get better performance than std::string. -It simply stores a pointer and a length, there is no -any memory allocation and copy. - -\note It is absolutely safe to store pointer because std::unordered_map, -which uses it as a key, exists only inside fillTreesFromFile function. - -*/ -class cstring -{ -protected: - - const char* str; - size_t str_len; - -public: - - explicit cstring(const char* _str) : str(_str), str_len(strlen(_str)) - { - } - - cstring(const cstring& _other) : str(_other.str), str_len(_other.str_len) - { - } - - inline bool operator == (const cstring& _other) const - { - return str_len == _other.str_len && !strncmp(str, _other.str, str_len); - } - - inline bool operator != (const cstring& _other) const - { - return !operator == (_other); - } - - inline bool operator < (const cstring& _other) const - { - if (str_len == _other.str_len) - { - return strncmp(str, _other.str, str_len) < 0; - } - - return str_len < _other.str_len; - } -}; - -/** \brief cstring with precalculated hash. - -This is used to calculate hash for C-string and to cache it -to be used in the future without recurring hash calculatoin. - -\note This class is used as a key in std::unordered_map. - -*/ -class hashed_cstr : public cstring -{ - typedef cstring Parent; - -public: - - size_t str_hash; - - explicit hashed_cstr(const char* _str) : Parent(_str), str_hash(0) - { - str_hash = ::std::_Hash_seq((const unsigned char *)str, str_len); - } - - hashed_cstr(const hashed_cstr& _other) : Parent(_other), str_hash(_other.str_hash) - { - } - - inline bool operator == (const hashed_cstr& _other) const - { - return str_hash == _other.str_hash && Parent::operator == (_other); - } - - inline bool operator != (const hashed_cstr& _other) const - { - return !operator == (_other); - } -}; - -namespace std { - - /** \brief Simply returns precalculated hash of a C-string. */ - template <> struct hash { - inline size_t operator () (const hashed_cstr& _str) const { - return _str.str_hash; - } - }; - -} - -typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; -typedef ::std::unordered_map IdMap; - -#else - -// TODO: optimize for Linux too -#include -typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; -typedef ::std::unordered_map<::std::string, ::profiler::block_id_t> IdMap; - -#endif - -////////////////////////////////////////////////////////////////////////// - -/** \brief Updates statistics for a profiler block. - -\param _stats_map Storage of statistics for blocks. -\param _current Pointer to the current block. -\param _stats Reference to the variable where pointer to the block statistics must be written. - -\note All blocks with similar name have the same pointer to statistics information. - -\note As all profiler block keeps a pointer to it's statistics, all similar blocks -automatically receive statistics update. - -*/ -::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current) -{ - auto duration = _current.node->duration(); - //StatsMap::key_type key(_current.node->name()); - //auto it = _stats_map.find(key); - auto it = _stats_map.find(_current.node->id()); - if (it != _stats_map.end()) - { - // Update already existing statistics - - auto stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats) - - ++stats->calls_number; // update calls number of this block - stats->total_duration += duration; // update summary duration of all block calls - - if (duration > stats->max_duration) - { - // update max duration - stats->max_duration_block = _current.block_index; - stats->max_duration = duration; - } - - if (duration < stats->min_duration) - { - // update min duraton - stats->min_duration_block = _current.block_index; - stats->min_duration = duration; - } - - // average duration is calculated inside average_duration() method by dividing total_duration to the calls_number - - return stats; - } - - // This is first time the block appear in the file. - // Create new statistics. - auto stats = new ::profiler::BlockStatistics(duration, _current.block_index); - //_stats_map.emplace(key, stats); - _stats_map.emplace(_current.node->id(), stats); - - return stats; -} - -////////////////////////////////////////////////////////////////////////// - -void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current) -{ - _current.per_frame_stats = update_statistics(_stats_map, _current); - for (auto& child : _current.children) - { - update_statistics_recursive(_stats_map, child); - } -} - -////////////////////////////////////////////////////////////////////////// - -typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; - -extern "C" { - - unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) - { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan) - - ::std::ifstream inFile(filename, ::std::fstream::binary); - progress.store(0); - - if (!inFile.is_open()) - return 0; - - PerThreadStats thread_statistics, parent_statistics, frame_statistics; - unsigned int blocks_counter = 0; - - uint32_t total_blocks_number = 0; - inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); - if (total_blocks_number == 0) - return 0; - - uint64_t memory_size = 0; - inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); - if (memory_size == 0) - return 0; - - serialized_blocks.set(new char[memory_size]); - //memset(serialized_blocks[0], 0, memory_size); - - - uint32_t total_descriptors_number = 0; - inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); - if (total_descriptors_number == 0) - return 0; - - uint64_t descriptors_memory_size = 0; - inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); - if (descriptors_memory_size == 0) - return 0; - - descriptors.reserve(total_descriptors_number); - serialized_descriptors.set(new char[descriptors_memory_size]); - - uint64_t i = 0; - uint32_t read_number = 0; - while (!inFile.eof() && read_number < total_descriptors_number) - { - ++read_number; - - uint16_t sz = 0; - inFile.read((char*)&sz, sizeof(sz)); - if (sz == 0) - return 0; - - char* data = serialized_descriptors[i]; - inFile.read(data, sz); - //auto base_offset = data; - //inFile.read(data, sizeof(::profiler::BaseBlockDescriptor)); - //auto base = reinterpret_cast<::profiler::BaseBlockDescriptor*>(data); - //data = data + sizeof(::profiler::BaseBlockDescriptor); - //inFile.read(data, sizeof(uint16_t)); - //auto name_len = reinterpret_cast(data); - //data = data + sizeof(uint16_t); - //inFile.read(data, *name_len); - //data = data + *name_len; - //inFile.read(data, sz - ::std::distance(base_offset, data)); - i += sz; - auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); - descriptors.push_back(descriptor); - - progress.store(static_cast(10 * i / descriptors_memory_size)); - } - - IdMap identification_table; - - i = 0; - read_number = 0; - while (!inFile.eof() && read_number < total_blocks_number) - { - PROFILER_BEGIN_BLOCK_GROUPED("Read thread from file", ::profiler::colors::Darkgreen) - - ::profiler::thread_id_t thread_id = 0; - inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); - - uint32_t blocks_number_in_thread = 0; - inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); - - auto& root = threaded_trees[thread_id]; - const auto threshold = read_number + blocks_number_in_thread; - while (!inFile.eof() && read_number < threshold) - { - PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green) - - ++read_number; - - uint16_t sz = 0; - inFile.read((char*)&sz, sizeof(sz)); - if (sz == 0) - return 0; - - char* data = serialized_blocks[i]; - inFile.read(data, sz); - i += sz; - auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - - ::profiler::BlocksTree tree; - tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); - tree.block_index = blocks_counter++; - - auto& per_parent_statistics = parent_statistics[thread_id]; - auto& per_thread_statistics = thread_statistics[thread_id]; - auto descriptor = descriptors[baseData->id()]; - - if (descriptor->type() == ::profiler::BLOCK_TYPE_THREAD_SIGN) - { - root.thread_name = tree.node->name(); - } - - if (*tree.node->name() != 0) - { - IdMap::key_type key(tree.node->name()); - auto it = identification_table.find(key); - if (it != identification_table.end()) - { - baseData->setId(it->second); - } - else - { - auto id = static_cast<::profiler::block_id_t>(descriptors.size()); - identification_table.emplace(key, id); - descriptors.push_back(descriptors[baseData->id()]); - baseData->setId(id); - } - } - - if (!root.tree.children.empty()) - { - auto& back = root.tree.children.back(); - auto t1 = back.node->end(); - auto mt0 = tree.node->begin(); - if (mt0 < t1)//parent - starts earlier than last ends - { - //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); - /**/ - PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue) - auto rlower1 = ++root.tree.children.rbegin(); - for (; rlower1 != root.tree.children.rend(); ++rlower1) - { - if (mt0 > rlower1->node->begin()) - { - break; - } - } - auto lower = rlower1.base(); - ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); - - root.tree.children.erase(lower, root.tree.children.end()); - PROFILER_END_BLOCK - - ::profiler::timestamp_t children_duration = 0; - if (gather_statistics) - { - PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta) - per_parent_statistics.clear(); - - //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows - //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows - // TODO: check this behavior on Linux - - for (auto& child : tree.children) - { - child.per_parent_stats = update_statistics(per_parent_statistics, child); - - children_duration += child.node->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } - } - else - { - for (const auto& child : tree.children) - { - children_duration += child.node->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } - } - - ++tree.depth; - } - } - - root.tree.children.emplace_back(::std::move(tree)); - - - - if (gather_statistics) - { - PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral) - auto& current = root.tree.children.back(); - current.per_thread_stats = update_statistics(per_thread_statistics, current); - } - - if (progress.load() < 0) - break; - progress.store(10 + static_cast(80 * i / memory_size)); - } - } - - if (progress.load() < 0) - { - serialized_blocks.clear(); - threaded_trees.clear(); - return 0; - } - - PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple) - if (gather_statistics) - { - ::std::vector<::std::thread> statistics_threads; - statistics_threads.reserve(threaded_trees.size()); - - for (auto& it : threaded_trees) - { - auto& root = it.second; - root.thread_id = it.first; - root.tree.shrink_to_fit(); - - auto& per_frame_statistics = frame_statistics[root.thread_id]; - auto& per_parent_statistics = parent_statistics[it.first]; - per_parent_statistics.clear(); - - statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics](::profiler::BlocksTreeRoot& root) - { - for (auto& frame : root.tree.children) - { - frame.per_parent_stats = update_statistics(per_parent_statistics, frame); - - per_frame_statistics.clear(); - update_statistics_recursive(per_frame_statistics, frame); - - if (root.tree.depth < frame.depth) - root.tree.depth = frame.depth; - } - - ++root.tree.depth; - }, ::std::ref(root))); - } - - int j = 0, n = static_cast(statistics_threads.size()); - for (auto& t : statistics_threads) - { - t.join(); - progress.store(90 + (10 * ++j) / n); - } - } - else - { - int j = 0, n = static_cast(threaded_trees.size()); - for (auto& it : threaded_trees) - { - auto& root = it.second; - root.thread_id = it.first; - - root.tree.shrink_to_fit(); - for (auto& frame : root.tree.children) - { - if (root.tree.depth < frame.depth) - root.tree.depth = frame.depth; - } - - ++root.tree.depth; - - progress.store(90 + (10 * ++j) / n); - } - } - PROFILER_END_BLOCK - // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors - - return blocks_counter; - } -} +/************************************************************************ +* file name : reader.cpp +* ----------------- : +* creation time : 2016/06/19 +* copyright : (c) 2016 Sergey Yagovtsev, Victor Zarubkin +* authors : Sergey Yagovtsev, Victor Zarubkin +* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of fillTreesFromFile function +* : which reads profiler file and fill profiler blocks tree. +* ----------------- : +* change log : * 2016/06/19 Sergey Yagovtsev: First fillTreesFromFile implementation. +* : +* : * 2016/06/25 Victor Zarubkin: Removed unnecessary memory allocation and copy +* : when creating and inserting blocks into the tree. +* : +* : * 2016/06/26 Victor Zarubkin: Added statistics gathering (min, max, average duration, +* : number of block calls). +* : * 2016/06/26 Victor Zarubkin, Sergey Yagovtsev: Added statistics gathering for root +* : blocks in the tree. +* : +* : * 2016/06/29 Victor Zarubkin: Added calculaton of total children number for blocks. +* : +* : * 2016/06/30 Victor Zarubkin: Added this header. +* : Added tree depth calculation. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#include "profiler/reader.h" +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////// + +struct passthrough_hash { + template inline size_t operator () (T _value) const { + return static_cast(_value); + } +}; + +////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + void SerializedData::set(char* _data) + { + if (m_data != nullptr) + delete[] m_data; + m_data = _data; + } + + extern "C" void release_stats(BlockStatistics*& _stats) + { + if (!_stats) + { + return; + } + + if (--_stats->calls_number == 0) + { + delete _stats; + } + + _stats = nullptr; + } + +} + +////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + +/** \brief Simple C-string pointer with length. + +It is used as base class for a key in std::unordered_map. +It is used to get better performance than std::string. +It simply stores a pointer and a length, there is no +any memory allocation and copy. + +\note It is absolutely safe to store pointer because std::unordered_map, +which uses it as a key, exists only inside fillTreesFromFile function. + +*/ +class cstring +{ +protected: + + const char* str; + size_t str_len; + +public: + + explicit cstring(const char* _str) : str(_str), str_len(strlen(_str)) + { + } + + cstring(const cstring& _other) : str(_other.str), str_len(_other.str_len) + { + } + + inline bool operator == (const cstring& _other) const + { + return str_len == _other.str_len && !strncmp(str, _other.str, str_len); + } + + inline bool operator != (const cstring& _other) const + { + return !operator == (_other); + } + + inline bool operator < (const cstring& _other) const + { + if (str_len == _other.str_len) + { + return strncmp(str, _other.str, str_len) < 0; + } + + return str_len < _other.str_len; + } +}; + +/** \brief cstring with precalculated hash. + +This is used to calculate hash for C-string and to cache it +to be used in the future without recurring hash calculatoin. + +\note This class is used as a key in std::unordered_map. + +*/ +class hashed_cstr : public cstring +{ + typedef cstring Parent; + +public: + + size_t str_hash; + + explicit hashed_cstr(const char* _str) : Parent(_str), str_hash(0) + { + str_hash = ::std::_Hash_seq((const unsigned char *)str, str_len); + } + + hashed_cstr(const hashed_cstr& _other) : Parent(_other), str_hash(_other.str_hash) + { + } + + inline bool operator == (const hashed_cstr& _other) const + { + return str_hash == _other.str_hash && Parent::operator == (_other); + } + + inline bool operator != (const hashed_cstr& _other) const + { + return !operator == (_other); + } +}; + +namespace std { + + /** \brief Simply returns precalculated hash of a C-string. */ + template <> struct hash { + inline size_t operator () (const hashed_cstr& _str) const { + return _str.str_hash; + } + }; + +} + +typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; +typedef ::std::unordered_map IdMap; + +#else + +// TODO: optimize for Linux too +#include +typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, passthrough_hash> StatsMap; +typedef ::std::unordered_map<::std::string, ::profiler::block_id_t> IdMap; + +#endif + +////////////////////////////////////////////////////////////////////////// + +/** \brief Updates statistics for a profiler block. + +\param _stats_map Storage of statistics for blocks. +\param _current Pointer to the current block. +\param _stats Reference to the variable where pointer to the block statistics must be written. + +\note All blocks with similar name have the same pointer to statistics information. + +\note As all profiler block keeps a pointer to it's statistics, all similar blocks +automatically receive statistics update. + +*/ +::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current) +{ + auto duration = _current.node->duration(); + //StatsMap::key_type key(_current.node->name()); + //auto it = _stats_map.find(key); + auto it = _stats_map.find(_current.node->id()); + if (it != _stats_map.end()) + { + // Update already existing statistics + + auto stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats) + + ++stats->calls_number; // update calls number of this block + stats->total_duration += duration; // update summary duration of all block calls + + if (duration > stats->max_duration) + { + // update max duration + stats->max_duration_block = _current.block_index; + stats->max_duration = duration; + } + + if (duration < stats->min_duration) + { + // update min duraton + stats->min_duration_block = _current.block_index; + stats->min_duration = duration; + } + + // average duration is calculated inside average_duration() method by dividing total_duration to the calls_number + + return stats; + } + + // This is first time the block appear in the file. + // Create new statistics. + auto stats = new ::profiler::BlockStatistics(duration, _current.block_index); + //_stats_map.emplace(key, stats); + _stats_map.emplace(_current.node->id(), stats); + + return stats; +} + +////////////////////////////////////////////////////////////////////////// + +void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current) +{ + _current.per_frame_stats = update_statistics(_stats_map, _current); + for (auto& child : _current.children) + { + update_statistics_recursive(_stats_map, child); + } +} + +////////////////////////////////////////////////////////////////////////// + +typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; + +extern "C" { + + unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) + { + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan) + + ::std::ifstream inFile(filename, ::std::fstream::binary); + progress.store(0); + + if (!inFile.is_open()) + return 0; + + PerThreadStats thread_statistics, parent_statistics, frame_statistics; + unsigned int blocks_counter = 0; + + uint32_t total_blocks_number = 0; + inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); + if (total_blocks_number == 0) + return 0; + + uint64_t memory_size = 0; + inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); + if (memory_size == 0) + return 0; + + serialized_blocks.set(new char[memory_size]); + //memset(serialized_blocks[0], 0, memory_size); + + + uint32_t total_descriptors_number = 0; + inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); + if (total_descriptors_number == 0) + return 0; + + uint64_t descriptors_memory_size = 0; + inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); + if (descriptors_memory_size == 0) + return 0; + + descriptors.reserve(total_descriptors_number); + serialized_descriptors.set(new char[descriptors_memory_size]); + + uint64_t i = 0; + uint32_t read_number = 0; + while (!inFile.eof() && read_number < total_descriptors_number) + { + ++read_number; + + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) + return 0; + + char* data = serialized_descriptors[i]; + inFile.read(data, sz); + auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); + descriptors.push_back(descriptor); + + i += sz; + progress.store(static_cast(10 * i / descriptors_memory_size)); + } + + IdMap identification_table; + + i = 0; + read_number = 0; + while (!inFile.eof() && read_number < total_blocks_number) + { + PROFILER_BEGIN_BLOCK_GROUPED("Read thread from file", ::profiler::colors::Darkgreen) + + ::profiler::thread_id_t thread_id = 0; + inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); + + uint32_t blocks_number_in_thread = 0; + inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); + + auto& root = threaded_trees[thread_id]; + const auto threshold = read_number + blocks_number_in_thread; + while (!inFile.eof() && read_number < threshold) + { + PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green) + + ++read_number; + + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) + return 0; + + char* data = serialized_blocks[i]; + inFile.read(data, sz); + i += sz; + auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); + + ::profiler::BlocksTree tree; + tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); + tree.block_index = blocks_counter++; + + auto& per_parent_statistics = parent_statistics[thread_id]; + auto& per_thread_statistics = thread_statistics[thread_id]; + auto descriptor = descriptors[baseData->id()]; + + if (descriptor->type() == ::profiler::BLOCK_TYPE_THREAD_SIGN) + { + root.thread_name = tree.node->name(); + } + + if (*tree.node->name() != 0) + { + IdMap::key_type key(tree.node->name()); + auto it = identification_table.find(key); + if (it != identification_table.end()) + { + baseData->setId(it->second); + } + else + { + auto id = static_cast<::profiler::block_id_t>(descriptors.size()); + identification_table.emplace(key, id); + descriptors.push_back(descriptors[baseData->id()]); + baseData->setId(id); + } + } + + if (!root.tree.children.empty()) + { + auto& back = root.tree.children.back(); + auto t1 = back.node->end(); + auto mt0 = tree.node->begin(); + if (mt0 < t1)//parent - starts earlier than last ends + { + //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); + /**/ + PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue) + auto rlower1 = ++root.tree.children.rbegin(); + for (; rlower1 != root.tree.children.rend(); ++rlower1) + { + if (mt0 > rlower1->node->begin()) + { + break; + } + } + auto lower = rlower1.base(); + ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); + + root.tree.children.erase(lower, root.tree.children.end()); + PROFILER_END_BLOCK + + ::profiler::timestamp_t children_duration = 0; + if (gather_statistics) + { + PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta) + per_parent_statistics.clear(); + + //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows + //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows + // TODO: check this behavior on Linux + + for (auto& child : tree.children) + { + child.per_parent_stats = update_statistics(per_parent_statistics, child); + + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } + } + else + { + for (const auto& child : tree.children) + { + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } + } + + ++tree.depth; + } + } + + root.tree.children.emplace_back(::std::move(tree)); + + + + if (gather_statistics) + { + PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral) + auto& current = root.tree.children.back(); + current.per_thread_stats = update_statistics(per_thread_statistics, current); + } + + if (progress.load() < 0) + break; + progress.store(10 + static_cast(80 * i / memory_size)); + } + } + + if (progress.load() < 0) + { + serialized_blocks.clear(); + threaded_trees.clear(); + return 0; + } + + PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple) + if (gather_statistics) + { + ::std::vector<::std::thread> statistics_threads; + statistics_threads.reserve(threaded_trees.size()); + + for (auto& it : threaded_trees) + { + auto& root = it.second; + root.thread_id = it.first; + root.tree.shrink_to_fit(); + + auto& per_frame_statistics = frame_statistics[root.thread_id]; + auto& per_parent_statistics = parent_statistics[it.first]; + per_parent_statistics.clear(); + + statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics](::profiler::BlocksTreeRoot& root) + { + for (auto& frame : root.tree.children) + { + frame.per_parent_stats = update_statistics(per_parent_statistics, frame); + + per_frame_statistics.clear(); + update_statistics_recursive(per_frame_statistics, frame); + + if (root.tree.depth < frame.depth) + root.tree.depth = frame.depth; + } + + ++root.tree.depth; + }, ::std::ref(root))); + } + + int j = 0, n = static_cast(statistics_threads.size()); + for (auto& t : statistics_threads) + { + t.join(); + progress.store(90 + (10 * ++j) / n); + } + } + else + { + int j = 0, n = static_cast(threaded_trees.size()); + for (auto& it : threaded_trees) + { + auto& root = it.second; + root.thread_id = it.first; + + root.tree.shrink_to_fit(); + for (auto& frame : root.tree.children) + { + if (root.tree.depth < frame.depth) + root.tree.depth = frame.depth; + } + + ++root.tree.depth; + + progress.store(90 + (10 * ++j) / n); + } + } + PROFILER_END_BLOCK + // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors + + return blocks_counter; + } +} From 988d9da391c52c8e39b128dac2f426582b0e4c14 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 21:10:16 +0300 Subject: [PATCH 04/37] (EasyTreeWidget) Trying to fix slow clear() --- profiler_gui/blocks_tree_widget.cpp | 20 +- profiler_gui/tree_widget_loader.cpp | 1180 +++++++++++++-------------- 2 files changed, 607 insertions(+), 593 deletions(-) diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 79e6c04..877c723 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "blocks_tree_widget.h" #include "tree_widget_item.h" #include "globals.h" @@ -115,7 +116,7 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent) m_progress->setValue(100); //m_progress->hide(); - QTimer::singleShot(40, this, &This::alignProgressBar); + QTimer::singleShot(1500, this, &This::alignProgressBar); } EasyTreeWidget::~EasyTreeWidget() @@ -244,6 +245,8 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, :: void EasyTreeWidget::clearSilent(bool _global) { + const QSignalBlocker b(this); + m_hierarchyBuilder.interrupt(); if (m_progress) @@ -277,10 +280,21 @@ void EasyTreeWidget::clearSilent(bool _global) m_items.clear(); m_roots.clear(); - { const QSignalBlocker b(this); clear(); } // clear without emitting any signals + ::std::vector topLevelItems; + topLevelItems.reserve(topLevelItemCount()); + for (int i = topLevelItemCount() - 1; i >= 0; --i) + topLevelItems.push_back(takeTopLevelItem(i)); + + auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) { + for (auto item : _items) + delete item; + }, ::std::move(topLevelItems)); + deleter_thread.detach(); + + //clear(); if (!_global) - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index f4f872f..8248e81 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -1,590 +1,590 @@ -/************************************************************************ -* file name : tree_widget_loader.h -* ----------------- : -* creation time : 2016/08/18 -* copyright : (c) 2016 Victor Zarubkin -* author : Victor Zarubkin -* email : v.s.zarubkin@gmail.com -* ----------------- : -* description : The file contains implementation of EasyTreeWidgetLoader which aim is -* : to load EasyProfiler blocks hierarchy in separate thread. -* ----------------- : -* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp -* : and renamed Prof* to Easy*. -* : -* : * -* ----------------- : -* license : TODO: add license text -************************************************************************/ - -#include "tree_widget_loader.h" -#include "tree_widget_item.h" -#include "globals.h" - -#ifdef max -#undef max -#endif - -#ifdef min -#undef min -#endif - -////////////////////////////////////////////////////////////////////////// - -EasyTreeWidgetLoader::EasyTreeWidgetLoader() : m_bDone(ATOMIC_VAR_INIT(false)), m_bInterrupt(ATOMIC_VAR_INIT(false)), m_progress(ATOMIC_VAR_INIT(0)) -{ -} - -EasyTreeWidgetLoader::~EasyTreeWidgetLoader() -{ - interrupt(); -} - -bool EasyTreeWidgetLoader::done() const -{ - return m_bDone.load(); -} - -void EasyTreeWidgetLoader::setDone() -{ - m_bDone.store(true); - //m_progress.store(100); -} - -void EasyTreeWidgetLoader::setProgress(int _progress) -{ - m_progress.store(_progress); -} - -bool EasyTreeWidgetLoader::interrupted() const -{ - return m_bInterrupt.load(); -} - -int EasyTreeWidgetLoader::progress() const -{ - return m_progress.load(); -} - -void EasyTreeWidgetLoader::takeTopLevelItems(ThreadedItems& _output) -{ - if (done()) - { - _output = ::std::move(m_topLevelItems); - m_topLevelItems.clear(); - } -} - -void EasyTreeWidgetLoader::takeItems(Items& _output) -{ - if (done()) - { - _output = ::std::move(m_items); - m_items.clear(); - } -} - -void EasyTreeWidgetLoader::interrupt() -{ - m_bInterrupt.store(true); - if (m_thread.joinable()) - m_thread.join(); - - m_bInterrupt.store(false); - m_bDone.store(false); - m_progress.store(0); - - for (auto item : m_topLevelItems) - { - //qDeleteAll(item.second->takeChildren()); - delete item.second; - } - - m_items.clear(); - m_topLevelItems.clear(); -} - -void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) -{ - interrupt(); - m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal1, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), ::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows)); -} - -void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) -{ - interrupt(); - m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal2, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), _beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows)); -} - -////////////////////////////////////////////////////////////////////////// - -template -void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) -{ - _items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks - - ::profiler::timestamp_t finishtime = 0; - for (const auto& threadTree : _blocksTree) - { - const auto node_block = threadTree.second.tree.children.front().node; - const auto startTime = node_block->begin(); - const auto endTime = node_block->end(); - - if (_beginTime > startTime) - _beginTime = startTime; - - if (finishtime < endTime) - finishtime = endTime; - } - - //const QSignalBlocker b(this); - int i = 0; - const int total = static_cast(_blocksTree.size()); - for (const auto& threadTree : _blocksTree) - { - if (_safelocker.interrupted()) - break; - - auto& block = threadTree.second.tree; - auto item = new EasyTreeWidgetItem(&block); - - if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0) - { - item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first)); - } - else - { - item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first)); - } - - ::profiler::timestamp_t duration = 0; - if (!block.children.empty()) - { - duration = block.children.back().node->end() - block.children.front().node->begin(); - } - - item->setTimeSmart(COL_DURATION, duration); - item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); - item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); - - _items.push_back(item); - - // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) - ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.children) - children_duration += child.node->duration(); - item->setTimeSmart(COL_SELF_DURATION, children_duration); - - children_duration = 0; - const auto children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows); - - if (children_items_number > 0) - { - //total_items += children_items_number + 1; - //addTopLevelItem(item); - //m_roots[threadTree.first] = item; - _topLevelItems.emplace_back(threadTree.first, item); - } - else - { - _items.pop_back(); - delete item; - } - - _safelocker.setProgress((100 * ++i) / total); - } - - _safelocker.setDone(); - //return total_items; -} - -////////////////////////////////////////////////////////////////////////// - -auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size()) -{ - auto children_number = _tree->children.size(); - for (const auto& child : _tree->children) - children_number += calculateTotalChildrenNumber(&child); - return children_number; -} - -template -void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) -{ - //size_t blocksNumber = 0; - //for (const auto& block : _blocks) - // blocksNumber += calculateTotalChildrenNumber(block.tree); - // //blocksNumber += block.tree->total_children_number; - //m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks - - RootsMap threadsMap; - - int i = 0, total = static_cast(_blocks.size()); - //const QSignalBlocker b(this); - for (const auto& block : _blocks) - { - if (_safelocker.interrupted()) - break; - - const auto startTime = block.tree->node->begin(); - const auto endTime = block.tree->node->end(); - if (startTime > _right || endTime < _left) - { - _safelocker.setProgress((90 * ++i) / total); - continue; - } - - ::profiler::timestamp_t duration = 0; - EasyTreeWidgetItem* thread_item = nullptr; - auto thread_item_it = threadsMap.find(block.root->thread_id); - if (thread_item_it != threadsMap.end()) - { - thread_item = thread_item_it->second; - } - else - { - thread_item = new EasyTreeWidgetItem(&block.root->tree); - - if (block.root->thread_name && block.root->thread_name[0] != 0) - { - thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->thread_name).arg(block.root->thread_id)); - } - else - { - thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); - } - - if (!block.root->tree.children.empty()) - { - duration = block.root->tree.children.back().node->end() - block.root->tree.children.front().node->begin(); - } - - thread_item->setTimeSmart(COL_DURATION, duration); - thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); - thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); - - // Calculate clean duration (sum of all children durations) - ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.root->tree.children) - children_duration += child.node->duration(); - thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); - - threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); - } - - auto item = new EasyTreeWidgetItem(block.tree, thread_item); - duration = endTime - startTime; - - auto name = *block.tree->node->name() != 0 ? block.tree->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->name(); - item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); - item->setTimeSmart(COL_DURATION, duration); - item->setTimeMs(COL_BEGIN, startTime - _beginTime); - item->setTimeMs(COL_END, endTime - _beginTime); - - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_PARENT, ""); - - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_FRAME, ""); - - if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also - { - const auto& per_thread_stats = block.tree->per_thread_stats; - const auto& per_parent_stats = block.tree->per_parent_stats; - const auto& per_frame_stats = block.tree->per_frame_stats; - - - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); - item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); - - auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(thread_item->selfDuration())); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); - item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); - - - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); - item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - - - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); - item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); - } - else - { - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_THREAD, ""); - } - - const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->color(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); - item->setTextColor(fgColor); - - auto item_index = static_cast(_items.size()); - _items.push_back(item); - - size_t children_items_number = 0; - ::profiler::timestamp_t children_duration = 0; - if (!block.tree->children.empty()) - { - children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows); - if (_safelocker.interrupted()) - break; - } - - int percentage = 100; - auto self_duration = duration - children_duration; - if (children_duration > 0 && duration > 0) - { - percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); - } - - item->setTimeSmart(COL_SELF_DURATION, self_duration); - item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); - item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); - - if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) - { - //total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item_index; - - if (_colorizeRows) - item->colorize(_colorizeRows); - - if (::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].expanded) - item->setExpanded(true); - - } - else - { - _items.pop_back(); - delete item; - } - - _safelocker.setProgress((90 * ++i) / total); - } - - i = 0; - total = static_cast(threadsMap.size()); - for (auto& it : threadsMap) - { - auto item = it.second; - - if (item->childCount() > 0) - { - //addTopLevelItem(item); - //m_roots[it.first] = item; - - _items.push_back(item); - _topLevelItems.emplace_back(it.first, item); - - //++total_items; - } - else - { - delete item; - } - - _safelocker.setProgress(90 + (10 * ++i) / total); - } - - _safelocker.setDone(); - //return total_items; -} - -template -size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows) -{ - size_t total_items = 0; - for (const auto& child : _children) - { - if (_safelocker.interrupted()) - break; - - const auto startTime = child.node->begin(); - const auto endTime = child.node->end(); - const auto duration = endTime - startTime; - _duration += duration; - - if (startTime > _right || endTime < _left) - { - continue; - } - - auto item = new EasyTreeWidgetItem(&child, _parent); - - auto name = *child.node->name() != 0 ? child.node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->name(); - item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); - item->setTimeSmart(COL_DURATION, duration); - item->setTimeMs(COL_BEGIN, startTime - _beginTime); - item->setTimeMs(COL_END, endTime - _beginTime); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - - if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also - { - const auto& per_thread_stats = child.per_thread_stats; - const auto& per_parent_stats = child.per_parent_stats; - const auto& per_frame_stats = child.per_frame_stats; - - auto percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_parent->duration())); - auto percentage_sum = static_cast(0.5 + 100. * static_cast(per_parent_stats->total_duration) / static_cast(_parent->duration())); - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage); - item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage)); - item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum); - item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum)); - - if (_frame != nullptr) - { - if (_parent != _frame) - { - percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_frame->duration())); - percentage_sum = static_cast(0.5 + 100. * static_cast(per_frame_stats->total_duration) / static_cast(_frame->duration())); - } - - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage); - item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage)); - item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum); - item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum)); - } - else - { - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_FRAME, ""); - item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_FRAME, ""); - } - - - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); - item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); - - if (_thread) - { - auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(_thread->selfDuration())); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); - item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); - } - - - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); - item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - - - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); - item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); - } - else - { - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_PARENT, ""); - item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_PARENT, ""); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_THREAD, ""); - } - - const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); - item->setTextColor(fgColor); - - auto item_index = static_cast(_items.size()); - _items.push_back(item); - - size_t children_items_number = 0; - ::profiler::timestamp_t children_duration = 0; - if (!child.children.empty()) - { - children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows); - if (_safelocker.interrupted()) - break; - } - - int percentage = 100; - auto self_duration = duration - children_duration; - if (children_duration > 0 && duration > 0) - { - percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); - } - - item->setTimeSmart(COL_SELF_DURATION, self_duration); - item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); - item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); - - if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) - { - total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item_index; - - if (_colorizeRows) - item->colorize(_colorizeRows); - - if (::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].expanded) - item->setExpanded(true); - } - else - { - _items.pop_back(); - delete item; - } - } - - return total_items; -} - -////////////////////////////////////////////////////////////////////////// - -template struct FillTreeClass; -template struct FillTreeClass; - -////////////////////////////////////////////////////////////////////////// +/************************************************************************ +* file name : tree_widget_loader.h +* ----------------- : +* creation time : 2016/08/18 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of EasyTreeWidgetLoader which aim is +* : to load EasyProfiler blocks hierarchy in separate thread. +* ----------------- : +* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp +* : and renamed Prof* to Easy*. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#include "tree_widget_loader.h" +#include "tree_widget_item.h" +#include "globals.h" + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +////////////////////////////////////////////////////////////////////////// + +EasyTreeWidgetLoader::EasyTreeWidgetLoader() : m_bDone(ATOMIC_VAR_INIT(false)), m_bInterrupt(ATOMIC_VAR_INIT(false)), m_progress(ATOMIC_VAR_INIT(0)) +{ +} + +EasyTreeWidgetLoader::~EasyTreeWidgetLoader() +{ + interrupt(); +} + +bool EasyTreeWidgetLoader::done() const +{ + return m_bDone.load(); +} + +void EasyTreeWidgetLoader::setDone() +{ + m_bDone.store(true); + //m_progress.store(100); +} + +void EasyTreeWidgetLoader::setProgress(int _progress) +{ + m_progress.store(_progress); +} + +bool EasyTreeWidgetLoader::interrupted() const +{ + return m_bInterrupt.load(); +} + +int EasyTreeWidgetLoader::progress() const +{ + return m_progress.load(); +} + +void EasyTreeWidgetLoader::takeTopLevelItems(ThreadedItems& _output) +{ + if (done()) + { + _output = ::std::move(m_topLevelItems); + m_topLevelItems.clear(); + } +} + +void EasyTreeWidgetLoader::takeItems(Items& _output) +{ + if (done()) + { + _output = ::std::move(m_items); + m_items.clear(); + } +} + +void EasyTreeWidgetLoader::interrupt() +{ + m_bInterrupt.store(true); + if (m_thread.joinable()) + m_thread.join(); + + m_bInterrupt.store(false); + m_bDone.store(false); + m_progress.store(0); + + auto deleter_thread = ::std::thread([](decltype(m_topLevelItems) _items) { + for (auto item : _items) + delete item.second; + }, ::std::move(m_topLevelItems)); + deleter_thread.detach(); + + m_items.clear(); + m_topLevelItems.clear(); +} + +void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) +{ + interrupt(); + m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal1, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), ::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows)); +} + +void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) +{ + interrupt(); + m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal2, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), _beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows)); +} + +////////////////////////////////////////////////////////////////////////// + +template +void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) +{ + _items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks + + ::profiler::timestamp_t finishtime = 0; + for (const auto& threadTree : _blocksTree) + { + const auto node_block = threadTree.second.tree.children.front().node; + const auto startTime = node_block->begin(); + const auto endTime = node_block->end(); + + if (_beginTime > startTime) + _beginTime = startTime; + + if (finishtime < endTime) + finishtime = endTime; + } + + //const QSignalBlocker b(this); + int i = 0; + const int total = static_cast(_blocksTree.size()); + for (const auto& threadTree : _blocksTree) + { + if (_safelocker.interrupted()) + break; + + auto& block = threadTree.second.tree; + auto item = new EasyTreeWidgetItem(&block); + + if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0) + { + item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first)); + } + else + { + item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first)); + } + + ::profiler::timestamp_t duration = 0; + if (!block.children.empty()) + { + duration = block.children.back().node->end() - block.children.front().node->begin(); + } + + item->setTimeSmart(COL_DURATION, duration); + item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); + item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); + + _items.push_back(item); + + // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) + ::profiler::timestamp_t children_duration = 0; + for (const auto& child : block.children) + children_duration += child.node->duration(); + item->setTimeSmart(COL_SELF_DURATION, children_duration); + + children_duration = 0; + const auto children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows); + + if (children_items_number > 0) + { + //total_items += children_items_number + 1; + //addTopLevelItem(item); + //m_roots[threadTree.first] = item; + _topLevelItems.emplace_back(threadTree.first, item); + } + else + { + _items.pop_back(); + delete item; + } + + _safelocker.setProgress((100 * ++i) / total); + } + + _safelocker.setDone(); + //return total_items; +} + +////////////////////////////////////////////////////////////////////////// + +auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size()) +{ + auto children_number = _tree->children.size(); + for (const auto& child : _tree->children) + children_number += calculateTotalChildrenNumber(&child); + return children_number; +} + +template +void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) +{ + //size_t blocksNumber = 0; + //for (const auto& block : _blocks) + // blocksNumber += calculateTotalChildrenNumber(block.tree); + // //blocksNumber += block.tree->total_children_number; + //m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks + + RootsMap threadsMap; + + int i = 0, total = static_cast(_blocks.size()); + //const QSignalBlocker b(this); + for (const auto& block : _blocks) + { + if (_safelocker.interrupted()) + break; + + const auto startTime = block.tree->node->begin(); + const auto endTime = block.tree->node->end(); + if (startTime > _right || endTime < _left) + { + _safelocker.setProgress((90 * ++i) / total); + continue; + } + + ::profiler::timestamp_t duration = 0; + EasyTreeWidgetItem* thread_item = nullptr; + auto thread_item_it = threadsMap.find(block.root->thread_id); + if (thread_item_it != threadsMap.end()) + { + thread_item = thread_item_it->second; + } + else + { + thread_item = new EasyTreeWidgetItem(&block.root->tree); + + if (block.root->thread_name && block.root->thread_name[0] != 0) + { + thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->thread_name).arg(block.root->thread_id)); + } + else + { + thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); + } + + if (!block.root->tree.children.empty()) + { + duration = block.root->tree.children.back().node->end() - block.root->tree.children.front().node->begin(); + } + + thread_item->setTimeSmart(COL_DURATION, duration); + thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); + thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); + + // Calculate clean duration (sum of all children durations) + ::profiler::timestamp_t children_duration = 0; + for (const auto& child : block.root->tree.children) + children_duration += child.node->duration(); + thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); + + threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); + } + + auto item = new EasyTreeWidgetItem(block.tree, thread_item); + duration = endTime - startTime; + + auto name = *block.tree->node->name() != 0 ? block.tree->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->name(); + item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); + item->setTimeSmart(COL_DURATION, duration); + item->setTimeMs(COL_BEGIN, startTime - _beginTime); + item->setTimeMs(COL_END, endTime - _beginTime); + + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_PARENT, ""); + + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_FRAME, ""); + + if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also + { + const auto& per_thread_stats = block.tree->per_thread_stats; + const auto& per_parent_stats = block.tree->per_parent_stats; + const auto& per_frame_stats = block.tree->per_frame_stats; + + + if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); + item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); + + auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(thread_item->selfDuration())); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); + item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); + + + if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); + item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); + + + if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); + item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); + } + else + { + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_THREAD, ""); + } + + const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->color(); + const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = 0x00ffffff - bgColor; + item->setBackgroundColor(bgColor); + item->setTextColor(fgColor); + + auto item_index = static_cast(_items.size()); + _items.push_back(item); + + size_t children_items_number = 0; + ::profiler::timestamp_t children_duration = 0; + if (!block.tree->children.empty()) + { + children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows); + if (_safelocker.interrupted()) + break; + } + + int percentage = 100; + auto self_duration = duration - children_duration; + if (children_duration > 0 && duration > 0) + { + percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); + } + + item->setTimeSmart(COL_SELF_DURATION, self_duration); + item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); + item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); + + if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) + { + //total_items += children_items_number + 1; + ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item_index; + + if (_colorizeRows) + item->colorize(_colorizeRows); + + if (::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].expanded) + item->setExpanded(true); + + } + else + { + _items.pop_back(); + delete item; + } + + _safelocker.setProgress((90 * ++i) / total); + } + + i = 0; + total = static_cast(threadsMap.size()); + for (auto& it : threadsMap) + { + auto item = it.second; + + if (item->childCount() > 0) + { + //addTopLevelItem(item); + //m_roots[it.first] = item; + + _items.push_back(item); + _topLevelItems.emplace_back(it.first, item); + + //++total_items; + } + else + { + delete item; + } + + _safelocker.setProgress(90 + (10 * ++i) / total); + } + + _safelocker.setDone(); + //return total_items; +} + +template +size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows) +{ + size_t total_items = 0; + for (const auto& child : _children) + { + if (_safelocker.interrupted()) + break; + + const auto startTime = child.node->begin(); + const auto endTime = child.node->end(); + const auto duration = endTime - startTime; + _duration += duration; + + if (startTime > _right || endTime < _left) + { + continue; + } + + auto item = new EasyTreeWidgetItem(&child, _parent); + + auto name = *child.node->name() != 0 ? child.node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->name(); + item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); + item->setTimeSmart(COL_DURATION, duration); + item->setTimeMs(COL_BEGIN, startTime - _beginTime); + item->setTimeMs(COL_END, endTime - _beginTime); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + + if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also + { + const auto& per_thread_stats = child.per_thread_stats; + const auto& per_parent_stats = child.per_parent_stats; + const auto& per_frame_stats = child.per_frame_stats; + + auto percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_parent->duration())); + auto percentage_sum = static_cast(0.5 + 100. * static_cast(per_parent_stats->total_duration) / static_cast(_parent->duration())); + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage); + item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage)); + item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum); + item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum)); + + if (_frame != nullptr) + { + if (_parent != _frame) + { + percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_frame->duration())); + percentage_sum = static_cast(0.5 + 100. * static_cast(per_frame_stats->total_duration) / static_cast(_frame->duration())); + } + + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage); + item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage)); + item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum); + item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum)); + } + else + { + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_FRAME, ""); + item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_FRAME, ""); + } + + + if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); + item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); + + if (_thread) + { + auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(_thread->selfDuration())); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); + item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); + } + + + if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); + item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); + + + if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); + item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); + } + else + { + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_PARENT, ""); + item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_PARENT, ""); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_THREAD, ""); + } + + const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); + const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = 0x00ffffff - bgColor; + item->setBackgroundColor(bgColor); + item->setTextColor(fgColor); + + auto item_index = static_cast(_items.size()); + _items.push_back(item); + + size_t children_items_number = 0; + ::profiler::timestamp_t children_duration = 0; + if (!child.children.empty()) + { + children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows); + if (_safelocker.interrupted()) + break; + } + + int percentage = 100; + auto self_duration = duration - children_duration; + if (children_duration > 0 && duration > 0) + { + percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); + } + + item->setTimeSmart(COL_SELF_DURATION, self_duration); + item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); + item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); + + if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) + { + total_items += children_items_number + 1; + ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item_index; + + if (_colorizeRows) + item->colorize(_colorizeRows); + + if (::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].expanded) + item->setExpanded(true); + } + else + { + _items.pop_back(); + delete item; + } + } + + return total_items; +} + +////////////////////////////////////////////////////////////////////////// + +template struct FillTreeClass; +template struct FillTreeClass; + +////////////////////////////////////////////////////////////////////////// From 71f95f2c874e24eef0cb627ffc520dbf3f91c007 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 23:40:23 +0300 Subject: [PATCH 05/37] (profiler_core) Simplifying API: there are ~1.5 times lower macros number for using profiler. --- include/profiler/profiler.h | 225 ++++++++++++++++-------------------- reader/main.cpp | 2 +- sample/main.cpp | 56 ++++----- src/block.cpp | 2 +- src/profile_manager.cpp | 14 +-- src/profile_manager.h | 2 +- src/reader.cpp | 30 ++--- 7 files changed, 153 insertions(+), 178 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 9d666c5..31f1535 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -16,8 +16,8 @@ You should have received a copy of the GNU General Public License along with this program.If not, see . **/ -#ifndef ____PROFILER____H_______ -#define ____PROFILER____H_______ +#ifndef EASY_PROFILER____H_______ +#define EASY_PROFILER____H_______ #if defined ( WIN32 ) #define __func__ __FUNCTION__ @@ -25,26 +25,34 @@ along with this program.If not, see . #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) +#include + +#define EASY_TOKEN_JOIN(x, y) x ## y +#define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y) +#define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x) +#define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x) /** \defgroup profiler Profiler */ -/** Macro used to check compile-time strings. +namespace profiler { + template struct NameSwitch final { + static const char* runtime_name(const char*) { return ""; } + static const char* compiletime_name(const char* name) { return name; } + }; -Compiler automatically concatenates "A" "B" into "AB" if both A and B strings -can be identified at compile-time. + template <> struct NameSwitch final { + static const char* runtime_name(const char* name) { return name; } + static const char* compiletime_name(const char*) { return ""; } + }; +} // END of namespace profiler. -\ingroup profiler -*/ -#define COMPILETIME_TEST "_compiletime_test" +#define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::compiletime_name(name) +#define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::runtime_name(name) -/** Macro of beginning of block with custom name and default identification +/** Macro of beginning of block with custom name and color. \code #include "profiler/profiler.h" @@ -52,161 +60,126 @@ can be identified at compile-time. { // some code ... if(something){ - PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()"); - someThirdPartyLongFunction(); - return; + EASY_BLOCK("Calling bar()"); // Block with default color + bar(); } + else{ + EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block + baz(); + } } \endcode -Block will be automatically completed by destructor +Block will be automatically completed by destructor. \ingroup profiler */ -#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());\ - ::profiler::beginBlock(PROFILER_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable +#define EASY_BLOCK(name, ...)\ + static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::beginBlock(EASY_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_RUNTIME(runtime_name)\ - static const ::profiler::StaticBlockDescriptor PROFILER_UNIQUE_DESC(__LINE__)("", __FILE__, __LINE__,\ - ::profiler::BLOCK_TYPE_BLOCK, ::profiler::DefaultBlockColor);\ - ::profiler::Block PROFILER_UNIQUE_BLOCK(__LINE__)(nullptr, ::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 +/** Macro of beginning of block with function name and custom color. \code #include "profiler/profiler.h" - void foo() - { - // some code ... - if(something){ - PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()", ::profiler::colors::Red); - someThirdPartyLongFunction(); - return; - } - } -\endcode - -Block will be automatically completed by destructor - -\ingroup profiler -*/ -#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 - -\code - #include "profiler/profiler.h" - void foo() - { - PROFILER_BEGIN_FUNCTION_BLOCK; + void foo(){ + EASY_FUNCTION(); // Block with name="foo" and default color //some code... } + + void bar(){ + EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar" + //some code... + } \endcode -Name of block automatically created with function name +Name of the block automatically created with function name. \ingroup profiler */ -#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__) +#define EASY_FUNCTION(...) EASY_BLOCK(__func__ , ## __VA_ARGS__) -/** Macro of beginning of function block with custom identification - -\code - #include "profiler/profiler.h" - void foo() - { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - //some code... - } -\endcode - -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) - -/** Macro of completion of last nearest open block +/** Macro of completion of last nearest open block. \code #include "profiler/profiler.h" -void foo() +int foo() { -// some code ... + // some code ... + int sum = 0; - PROFILER_BEGIN_BLOCK("Calculating summ"); - for(int i = 0; i < 10; i++){ + EASY_BLOCK("Calculating sum"); + for (int i = 0; i < 10; ++i){ sum += i; } - PROFILER_END_BLOCK; + EASY_END_BLOCK; + + // some antoher code here ... + + return sum; } \endcode \ingroup profiler */ -#define PROFILER_END_BLOCK ::profiler::endBlock(); +#define EASY_END_BLOCK ::profiler::endBlock(); -#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 +/** Macro of creating event with custom name and color. -#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 +Event is a block with zero duration and special type. + +\warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT +will end previously opened EASY_BLOCK or EASY_FUNCTION. + +\ingroup profiler +*/ +#define EASY_EVENT(name, ...)\ + static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + ::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro enabling profiler \ingroup profiler */ -#define PROFILER_ENABLE ::profiler::setEnabled(true); +#define EASY_PROFILER_ENABLE ::profiler::setEnabled(true); /** Macro disabling profiler \ingroup profiler */ -#define PROFILER_DISABLE ::profiler::setEnabled(false); +#define EASY_PROFILER_DISABLE ::profiler::setEnabled(false); +/** Macro of naming current thread. + +If this thread has been already named then nothing changes. + +\ingroup profiler +*/ #ifdef WIN32 -#define PROFILER_SET_THREAD_NAME(name) ::profiler::setThreadName(name); +#define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #else -#define PROFILER_SET_THREAD_NAME(name) thread_local static const ::profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name); +#define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__); #endif -#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main") +/** Macro of naming main thread. + +This is only for user comfort. There is no difference for EasyProfiler GUI between different threads. + +\ingroup profiler +*/ +#define EASY_MAIN_THREAD EASY_THREAD("Main") #else -#define PROFILER_BEGIN_BLOCK(name) -#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_SET_THREAD_NAME(name) -#define PROFILER_SET_MAIN_THREAD +#define EASY_BLOCK(...) +#define EASY_FUNCTION(...) +#define EASY_END_BLOCK +#define EASY_PROFILER_ENABLE +#define EASY_PROFILER_DISABLE +#define EASY_EVENT(...) +#define EASY_THREAD(...) +#define EASY_MAIN_THREAD #endif #include @@ -236,7 +209,7 @@ namespace profiler { void PROFILER_API endBlock(); void PROFILER_API setEnabled(bool isEnable); unsigned int PROFILER_API dumpBlocksToFile(const char* filename); - void PROFILER_API setThreadName(const char* name); + void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); } typedef uint64_t timestamp_t; @@ -320,7 +293,7 @@ namespace profiler { public: - Block(const char*, block_type_t _block_type, block_id_t _id, const char* _name = ""); + Block(block_type_t _block_type, block_id_t _id, const char* _name = ""); ~Block(); inline const char* name() const { return m_name; } @@ -334,16 +307,16 @@ namespace profiler { public: - StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = colors::Random); + StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); block_id_t id() const { return m_id; } }; #ifndef WIN32 struct PROFILER_API ThreadNameSetter final { - ThreadNameSetter(const char* _name) + ThreadNameSetter(const char* _name, const char* _filename, const char* _funcname, int _line) { - setThreadName(_name); + setThreadName(_name, _filename, _funcname, _line); } }; #endif @@ -352,4 +325,4 @@ namespace profiler { } // END of namespace profiler. -#endif +#endif // EASY_PROFILER____H_______ diff --git a/reader/main.cpp b/reader/main.cpp index c356840..ed696d1 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -99,7 +99,7 @@ int main(int argc, char* argv[]) if (dump_filename.size() > 2) { - PROFILER_ENABLE + EASY_PROFILER_ENABLE; std::cout << "Will dump reader prof file to " << dump_filename << std::endl; } else diff --git a/sample/main.cpp b/sample/main.cpp index 3513020..7ef3014 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -26,13 +26,13 @@ void localSleep(int magic=200000) } void loadingResources(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan); + EASY_FUNCTION(profiler::colors::Darkcyan); localSleep(); // std::this_thread::sleep_for(std::chrono::milliseconds(50)); } void prepareMath(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); int* intarray = new int[OBJECTS]; for (int i = 0; i < OBJECTS; ++i) intarray[i] = i * i; @@ -41,7 +41,7 @@ void prepareMath(){ } void calcIntersect(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); //int* intarray = new int[OBJECTS * OBJECTS]; int* intarray = new int[OBJECTS]; for (int i = 0; i < OBJECTS; ++i) @@ -56,12 +56,12 @@ void calcIntersect(){ double multModel(double i) { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); return i * sin(i) * cos(i); } void calcPhys(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); double* intarray = new double[OBJECTS]; for (int i = 0; i < OBJECTS; ++i) intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2); @@ -71,12 +71,12 @@ void calcPhys(){ double calcSubbrain(int i) { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); return i * i * i - i / 10 + (OBJECTS - i) * 7 ; } void calcBrain(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + EASY_FUNCTION(profiler::colors::Blue); double* intarray = new double[OBJECTS]; for (int i = 0; i < OBJECTS; ++i) intarray[i] = calcSubbrain(i) + double(i * 180 / 3); @@ -85,19 +85,19 @@ void calcBrain(){ } void calculateBehavior(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue); + EASY_FUNCTION(profiler::colors::Darkblue); calcPhys(); calcBrain(); } void modellingStep(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy); + EASY_FUNCTION(profiler::colors::Navy); prepareMath(); calculateBehavior(); } void prepareRender(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred); + EASY_FUNCTION(profiler::colors::Darkred); localSleep(); //std::this_thread::sleep_for(std::chrono::milliseconds(8)); @@ -105,18 +105,18 @@ void prepareRender(){ int multPhys(int i) { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); return i * i * i * i / 100; } int calcPhysicForObject(int i) { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); return multPhys(i) + i / 3 - (OBJECTS - i) * 15; } void calculatePhysics(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); unsigned int* intarray = new unsigned int[OBJECTS]; for (int i = 0; i < OBJECTS; ++i) intarray[i] = calcPhysicForObject(i); @@ -125,7 +125,7 @@ void calculatePhysics(){ } void frame(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta); + EASY_FUNCTION(profiler::colors::Magenta); prepareRender(); calculatePhysics(); } @@ -133,10 +133,10 @@ void frame(){ void loadingResourcesThread(){ //std::unique_lock lk(cv_m); //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Resource loading") + EASY_THREAD("Resource loading"); for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ loadingResources(); - PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan); + EASY_EVENT("Resources Loading!", profiler::colors::Cyan); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); } @@ -145,8 +145,8 @@ void loadingResourcesThread(){ void modellingThread(){ //std::unique_lock lk(cv_m); //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Modelling") - for (int i = 0; i < RENDER_SPEPS; i++){ + EASY_THREAD("Modelling"); + for (int i = 0; i < RENDER_SPEPS; i++){ modellingStep(); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); @@ -156,7 +156,7 @@ void modellingThread(){ void renderThread(){ //std::unique_lock lk(cv_m); //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Render") + EASY_THREAD("Render"); for (int i = 0; i < MODELLING_STEPS; i++){ frame(); localSleep(1200000); @@ -166,24 +166,24 @@ void renderThread(){ void four() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); std::this_thread::sleep_for(std::chrono::milliseconds(37)); } void five() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } void six() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); std::this_thread::sleep_for(std::chrono::milliseconds(42)); } void three() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); four(); five(); six(); @@ -191,19 +191,19 @@ void three() void seven() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); std::this_thread::sleep_for(std::chrono::milliseconds(147)); } void two() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); std::this_thread::sleep_for(std::chrono::milliseconds(26)); } void one() { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + EASY_FUNCTION(profiler::colors::Red); two(); three(); seven(); @@ -240,8 +240,8 @@ int main(int argc, char* argv[]) std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; auto start = std::chrono::system_clock::now(); - PROFILER_ENABLE; - PROFILER_SET_MAIN_THREAD; + EASY_PROFILER_ENABLE; + EASY_MAIN_THREAD; //one(); //one(); /**/ diff --git a/src/block.cpp b/src/block.cpp index 2acd3d5..7acad7b 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -38,7 +38,7 @@ BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) } -Block::Block(const char*, block_type_t _block_type, block_id_t _descriptor_id, const char* _name) +Block::Block(block_type_t _block_type, block_id_t _descriptor_id, const char* _name) : BaseBlockData(getCurrentTime(), _descriptor_id) , m_name(_name) { diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 85e5e52..ffce286 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -31,9 +31,9 @@ extern "C"{ return MANAGER.dumpBlocksToFile(filename); } - void PROFILER_API setThreadName(const char* name) + void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line) { - return MANAGER.setThreadName(name); + return MANAGER.setThreadName(name, filename, _funcname, line); } } @@ -66,7 +66,7 @@ BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const c , m_name(_name) , m_filename(_filename) { - _used_mem += sizeof(profiler::BaseBlockDescriptor) + strlen(_name) + strlen(_filename) + 2; + _used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2; } ////////////////////////////////////////////////////////////////////////// @@ -185,7 +185,7 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) { const auto name_size = static_cast(strlen(descriptor.name()) + 1); const auto filename_size = static_cast(strlen(descriptor.file()) + 1); - const auto size = static_cast(sizeof(profiler::BaseBlockDescriptor) + name_size + filename_size + sizeof(uint16_t)); + const auto size = static_cast(sizeof(profiler::SerializedBlockDescriptor) + name_size + filename_size); of.write(size); of.write(descriptor); @@ -212,14 +212,14 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) return blocks_number; } -void ProfileManager::setThreadName(const char* name) +void ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line) { auto& thread_storage = threadStorage(getCurrentThreadId()); if (thread_storage.named) return; - 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)); + const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); + thread_storage.store(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); thread_storage.named = true; } diff --git a/src/profile_manager.h b/src/profile_manager.h index abc1da5..df72031 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -139,7 +139,7 @@ public: void endBlock(); void setEnabled(bool isEnable); uint32_t dumpBlocksToFile(const char* filename); - void setThreadName(const char* name); + void setThreadName(const char* name, const char* filename, const char* _funcname, int line); private: diff --git a/src/reader.cpp b/src/reader.cpp index 893148e..aee8d86 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -260,7 +260,7 @@ extern "C" { unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) { - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan) + EASY_FUNCTION(::profiler::colors::Cyan); ::std::ifstream inFile(filename, ::std::fstream::binary); progress.store(0); @@ -299,16 +299,19 @@ extern "C" { serialized_descriptors.set(new char[descriptors_memory_size]); uint64_t i = 0; - uint32_t read_number = 0; - while (!inFile.eof() && read_number < total_descriptors_number) + while (!inFile.eof() && descriptors.size() < total_descriptors_number) { - ++read_number; - uint16_t sz = 0; inFile.read((char*)&sz, sizeof(sz)); if (sz == 0) return 0; + //if (i + sz > descriptors_memory_size) + //{ + // printf("FILE CORRUPTED\n"); + // return 0; + //} + char* data = serialized_descriptors[i]; inFile.read(data, sz); auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); @@ -321,10 +324,10 @@ extern "C" { IdMap identification_table; i = 0; - read_number = 0; + uint32_t read_number = 0; while (!inFile.eof() && read_number < total_blocks_number) { - PROFILER_BEGIN_BLOCK_GROUPED("Read thread from file", ::profiler::colors::Darkgreen) + EASY_BLOCK("Read thread data", ::profiler::colors::Darkgreen); ::profiler::thread_id_t thread_id = 0; inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); @@ -336,7 +339,7 @@ extern "C" { const auto threshold = read_number + blocks_number_in_thread; while (!inFile.eof() && read_number < threshold) { - PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green) + EASY_BLOCK("Read block", ::profiler::colors::Green); ++read_number; @@ -389,7 +392,7 @@ extern "C" { { //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); /**/ - PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue) + EASY_BLOCK("Find children", ::profiler::colors::Blue); auto rlower1 = ++root.tree.children.rbegin(); for (; rlower1 != root.tree.children.rend(); ++rlower1) { @@ -402,12 +405,12 @@ extern "C" { ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); root.tree.children.erase(lower, root.tree.children.end()); - PROFILER_END_BLOCK + EASY_END_BLOCK; ::profiler::timestamp_t children_duration = 0; if (gather_statistics) { - PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta) + EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta); per_parent_statistics.clear(); //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows @@ -443,7 +446,7 @@ extern "C" { if (gather_statistics) { - PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral) + EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral); auto& current = root.tree.children.back(); current.per_thread_stats = update_statistics(per_thread_statistics, current); } @@ -461,7 +464,7 @@ extern "C" { return 0; } - PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple) + EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple); if (gather_statistics) { ::std::vector<::std::thread> statistics_threads; @@ -521,7 +524,6 @@ extern "C" { progress.store(90 + (10 * ++j) / n); } } - PROFILER_END_BLOCK // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors return blocks_counter; From 61c40c2512dea3a9457f97fd861d45eb0cceb605 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 28 Aug 2016 23:40:51 +0300 Subject: [PATCH 06/37] (EasyGraphicsView) Design tweaking --- profiler_gui/blocks_graphics_view.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index e2d16d7..b20bcf3 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -831,12 +831,18 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt // instead of scrollbar we're using manual offset _painter->setTransform(QTransform::fromTranslate(-x(), -y()), true); + if (m_left < sceneLeft) + rect.setLeft(0); + + if (m_right > sceneRight) + rect.setWidth((sceneRight - offset) * currentScale - rect.left()); + // draw transparent rectangle auto vcenter = rect.top() + rect.height() * 0.5; QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter); g.setColorAt(0, m_color); - g.setColorAt(0.15, QColor::fromRgba(0x14000000 | rgb)); - g.setColorAt(0.85, QColor::fromRgba(0x14000000 | rgb)); + g.setColorAt(0.15, QColor::fromRgba(0x10000000 | rgb)); + g.setColorAt(0.85, QColor::fromRgba(0x10000000 | rgb)); g.setColorAt(1, m_color); _painter->setBrush(g); _painter->setPen(Qt::NoPen); @@ -855,16 +861,6 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt _painter->setPen(0xffffffff - rgb); _painter->setFont(CHRONOMETER_FONT); - if (m_left < sceneLeft) - { - rect.setLeft(0); - } - - if (m_right > sceneRight) - { - rect.setWidth((sceneRight - offset) * currentScale - rect.left()); - } - int textFlags = 0; switch (::profiler_gui::EASY_GLOBALS.chrono_text_position) { From eaa79a4c4c47c0160623bdc7c222a5467659b3cb Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 30 Aug 2016 20:46:39 +0300 Subject: [PATCH 07/37] (profiler_core) Fixed logic mistake in base api --- include/profiler/profiler.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 31f1535..0d94583 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -38,13 +38,13 @@ along with this program.If not, see . namespace profiler { template struct NameSwitch final { - static const char* runtime_name(const char*) { return ""; } - static const char* compiletime_name(const char* name) { return name; } + static const char* runtime_name(const char* name) { return name; } + static const char* compiletime_name(const char*) { return ""; } }; template <> struct NameSwitch final { - static const char* runtime_name(const char* name) { return name; } - static const char* compiletime_name(const char*) { return ""; } + static const char* runtime_name(const char*) { return ""; } + static const char* compiletime_name(const char* name) { return name; } }; } // END of namespace profiler. From 245bc6c3864236256ff32c989301399e4b7d3251 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 30 Aug 2016 20:47:49 +0300 Subject: [PATCH 08/37] (EasyChronometerItem) Fixed an error of displaying text on large scale --- profiler_gui/blocks_graphics_view.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index b20bcf3..dfa3dea 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -888,14 +888,15 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt return; } - if (m_right + textRect.width() < sceneRight) + const auto w = textRect.width() / currentScale; + if (m_right + w < sceneRight) { // Text will be drawed to the right of rectangle rect.translate(rect.width(), 0); textFlags &= ~Qt::AlignHCenter; textFlags |= Qt::AlignLeft; } - else if (m_left - textRect.width() > sceneLeft) + else if (m_left - w > sceneLeft) { // Text will be drawed to the left of rectangle rect.translate(-rect.width(), 0); From 9560c5b5cff8a4145bee6c20cd01ad9c96f9eb95 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 30 Aug 2016 22:51:18 +0300 Subject: [PATCH 09/37] (profiler_gui) Memory consumption optimization + File reading speed-up. --- include/profiler/reader.h | 50 ++- profiler_gui/blocks_graphics_view.cpp | 118 +++---- profiler_gui/blocks_graphics_view.h | 8 +- profiler_gui/blocks_tree_widget.cpp | 94 ++--- profiler_gui/common_types.h | 62 +++- profiler_gui/globals.h | 32 +- profiler_gui/graphics_scrollbar.cpp | 14 +- profiler_gui/graphics_scrollbar.h | 8 +- profiler_gui/main_window.cpp | 97 +++--- profiler_gui/main_window.h | 4 +- profiler_gui/tree_widget_item.cpp | 24 +- profiler_gui/tree_widget_item.h | 8 +- profiler_gui/tree_widget_loader.cpp | 103 +++--- reader/main.cpp | 3 +- src/reader.cpp | 475 +++++++++++++------------- 15 files changed, 581 insertions(+), 519 deletions(-) diff --git a/include/profiler/reader.h b/include/profiler/reader.h index b851350..c46acbd 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -72,23 +72,21 @@ namespace profiler { public: - typedef ::std::vector children_t; + typedef ::std::vector blocks_t; + typedef ::std::vector<::profiler::block_index_t> children_t; children_t children; ///< List of children blocks. May be empty. ::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.) ::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread - - ::profiler::block_index_t block_index; ///< Index of this block - unsigned short depth; ///< Maximum number of sublevels (maximum children depth) + uint16_t depth; ///< Maximum number of sublevels (maximum children depth) BlocksTree() : node(nullptr) , per_parent_stats(nullptr) , per_frame_stats(nullptr) , per_thread_stats(nullptr) - , block_index(0) , depth(0) { @@ -143,33 +141,20 @@ namespace profiler { void makeMove(This&& that) { - //if (node && node != that.node) - //{ - // delete node; - //} - if (per_thread_stats != that.per_thread_stats) - { release_stats(per_thread_stats); - } if (per_parent_stats != that.per_parent_stats) - { release_stats(per_parent_stats); - } if (per_frame_stats != that.per_frame_stats) - { release_stats(per_frame_stats); - } children = ::std::move(that.children); node = that.node; per_parent_stats = that.per_parent_stats; per_frame_stats = that.per_frame_stats; per_thread_stats = that.per_thread_stats; - - block_index = that.block_index; depth = that.depth; that.node = nullptr; @@ -188,29 +173,31 @@ namespace profiler { public: - BlocksTree tree; + BlocksTree::children_t children; const char* thread_name; ::profiler::thread_id_t thread_id; + uint16_t depth; - BlocksTreeRoot() : thread_name(""), thread_id(0) + BlocksTreeRoot() : thread_name(""), thread_id(0), depth(0) { } - BlocksTreeRoot(This&& that) : tree(::std::move(that.tree)), thread_name(that.thread_name), thread_id(that.thread_id) + BlocksTreeRoot(This&& that) : children(::std::move(that.children)), thread_name(that.thread_name), thread_id(that.thread_id), depth(that.depth) { } This& operator = (This&& that) { - tree = ::std::move(that.tree); + children = ::std::move(that.children); thread_name = that.thread_name; thread_id = that.thread_id; + depth = that.depth; return *this; } bool operator < (const This& other) const { - return tree < other.tree; + return thread_id < other.thread_id; } private: @@ -220,6 +207,7 @@ namespace profiler { }; // END of class BlocksTreeRoot. + typedef ::profiler::BlocksTree::blocks_t blocks_t; typedef ::std::map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot> thread_blocks_tree_t; ////////////////////////////////////////////////////////////////////////// @@ -283,11 +271,21 @@ namespace profiler { } // END of namespace profiler. -extern "C" unsigned int PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); +extern "C" ::profiler::block_index_t PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics = false); -inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) { +inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics = false) +{ ::std::atomic progress = ATOMIC_VAR_INIT(0); - return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, threaded_trees, gather_statistics); + return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index dfa3dea..14f8808 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -153,7 +153,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Search for first visible top-level item auto& level0 = m_levels.front(); - auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value) + auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value) { return _item.left() < _value; }); @@ -183,7 +183,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true); - if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders) + if (EASY_GLOBALS.draw_graphics_items_borders) { previousPenStyle = Qt::SolidLine; _painter->setPen(BORDERS_COLOR); @@ -194,8 +194,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } - static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); - auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::ProfBlockItem::children_begin) children_begin) + static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); + auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::EasyBlockItem::children_begin) children_begin) { // Mark that we would not paint children of current item if (next_level < levelsNumber && children_begin != MAX_CHILD_INDEX) @@ -243,8 +243,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* continue; } + const auto& itemBlock = easyBlock(item.block); int h = 0, flags = 0; - if (w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded) + if (w < 20 || !itemBlock.expanded) { // Items which width is less than 20 will be painted as big rectangles which are hiding it's children @@ -255,7 +256,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* h -= dh; bool changepen = false; - if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) + if (item.block == EASY_GLOBALS.selected_block) { selectedItemsWasPainted = true; changepen = true; @@ -281,7 +282,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setBrush(brush); } - if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders) + if (EASY_GLOBALS.draw_graphics_items_borders) { //if (w < 2) //{ @@ -349,7 +350,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* m_levels[next_level][item.children_begin].state = BLOCK_ITEM_DO_PAINT; } - if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) + if (item.block == EASY_GLOBALS.selected_block) { selectedItemsWasPainted = true; QPen pen(Qt::SolidLine); @@ -374,7 +375,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setBrush(brush); } - if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange)) + if (EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange)) { // Restore pen for item which is wide enough to paint borders previousPenStyle = Qt::SolidLine; @@ -422,7 +423,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(textColor); // drawing text - auto name = *item.block->node->name() != 0 ? item.block->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[item.block->node->id()]->name(); + auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name(); _painter->drawText(rect, flags, ::profiler_gui::toUnicode(name)); // restore previous pen color @@ -434,9 +435,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } } - if (!selectedItemsWasPainted && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) + if (!selectedItemsWasPainted && EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size()) { - const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[::profiler_gui::EASY_GLOBALS.selected_block]; + const auto& guiblock = EASY_GLOBALS.gui_blocks[EASY_GLOBALS.selected_block]; if (guiblock.graphics_item == m_index) { const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index]; @@ -482,7 +483,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(textColor); // drawing text - auto name = *item.block->node->name() != 0 ? item.block->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[item.block->node->id()]->name(); + const auto& itemBlock = easyBlock(item.block); + auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name(); _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name)); // END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } @@ -511,7 +513,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree // Search for first visible top-level item auto& level0 = m_levels.front(); - auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value) + auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value) { return _item.left() < _value; }); @@ -552,7 +554,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree ////////////////////////////////////////////////////////////////////////// -const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const +const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const { if (m_levels.empty() || m_levels.front().empty()) { @@ -588,7 +590,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& const auto& level = m_levels[i]; // Search for first visible item - auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::ProfBlockItem& _item, qreal _value) + auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::EasyBlockItem& _item, qreal _value) { return _item.left() < _value; }); @@ -620,7 +622,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& } const auto w = item.width() * currentScale; - if (i == levelIndex || w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded) + if (i == levelIndex || w < 20 || !easyBlock(item.block).expanded) { return &item; } @@ -725,12 +727,12 @@ const EasyGraphicsItem::Children& EasyGraphicsItem::items(unsigned char _level) return m_levels[_level]; } -const ::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const +const ::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const { return m_levels[_level][_index]; } -::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) +::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) { return m_levels[_level][_index]; } @@ -862,7 +864,7 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt _painter->setFont(CHRONOMETER_FONT); int textFlags = 0; - switch (::profiler_gui::EASY_GLOBALS.chrono_text_position) + switch (EASY_GLOBALS.chrono_text_position) { case ::profiler_gui::ChronoTextPosition_Top: textFlags = Qt::AlignTop | Qt::AlignHCenter; @@ -1001,7 +1003,7 @@ void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte if (top > h || bottom < 0) continue; - if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread) + if (item->threadId() == EASY_GLOBALS.selected_thread) _painter->setBrush(QBrush(QColor::fromRgb(::profiler_gui::SELECTED_THREAD_BACKGROUND))); else _painter->setBrush(brushes[i & 1]); @@ -1291,8 +1293,8 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite if (longestItem != nullptr) { m_pScrollbar->setMinimapFrom(0, longestItem->items(0)); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0); + EASY_GLOBALS.selected_thread = 0; + emitEASY_GLOBALS.events.selectedThreadChanged(0); } // Create new chronometer item (previous item was destroyed by scene on scene()->clear()). @@ -1359,13 +1361,13 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // Calculating start and end time ::profiler::timestamp_t finish = 0; - const ::profiler::BlocksTree* longestTree = nullptr; + ::profiler::thread_id_t longestTree = 0; const EasyGraphicsItem* longestItem = nullptr; for (const auto& threadTree : _blocksTree) { - const auto& tree = threadTree.second.tree; - const auto timestart = tree.children.front().node->begin(); - const auto timefinish = tree.children.back().node->end(); + const auto& tree = threadTree.second.children; + const auto timestart = blocksTree(tree.front()).node->begin(); + const auto timefinish = blocksTree(tree.back()).node->end(); if (m_beginTime > timestart) { @@ -1375,7 +1377,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr if (finish < timefinish) { finish = timefinish; - longestTree = &tree; + longestTree = threadTree.first; } } @@ -1391,13 +1393,13 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr } // fill scene with new items - const auto& tree = threadTree.second.tree; - qreal h = 0, x = time2position(tree.children.front().node->begin()); + const auto& tree = threadTree.second.children; + qreal h = 0, x = time2position(blocksTree(tree.front()).node->begin()); auto item = new EasyGraphicsItem(static_cast(m_items.size()), &threadTree.second); - item->setLevels(tree.depth); + item->setLevels(threadTree.second.depth); item->setPos(0, y); - const auto children_duration = setTree(item, tree.children, h, y, 0); + const auto children_duration = setTree(item, tree, h, y, 0); item->setBoundingRect(0, 0, children_duration + x, h); m_items.push_back(item); @@ -1405,7 +1407,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr y += h + THREADS_ROW_SPACING; - if (longestTree == &tree) + if (longestTree == threadTree.first) { longestItem = item; } @@ -1424,8 +1426,8 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr if (longestItem != nullptr) { m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0)); - ::profiler_gui::EASY_GLOBALS.selected_thread = longestItem->threadId(); - emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId()); + EASY_GLOBALS.selected_thread = longestItem->threadId(); + emit EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId()); } // Create new chronometer item (previous item was destroyed by scene on scene()->clear()). @@ -1466,8 +1468,11 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block bool warned = false; qreal total_duration = 0, prev_end = 0, maxh = 0; qreal start_time = -1; - for (const auto& child : _children) + for (auto child_index : _children) { + auto& gui_block = easyBlock(child_index); + const auto& child = gui_block.tree; + auto xbegin = time2position(child.node->begin()); if (start_time < 0) { @@ -1491,7 +1496,6 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block auto i = _item->addItem(level); auto& b = _item->getItem(level, i); - auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index]; gui_block.graphics_item = _item->index(); gui_block.graphics_item_level = level; gui_block.graphics_item_index = i; @@ -1528,8 +1532,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block maxh = h; } - const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); - b.block = &child; + const auto color = EASY_GLOBALS.descriptors[child.node->id()]->color(); + b.block = child_index;// &child; b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); b.setPos(xbegin, duration); b.totalHeight = GRAPHICS_ROW_SIZE + h; @@ -1570,8 +1574,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar) connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel); } - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0); + EASY_GLOBALS.selected_thread = 0; + emit EASY_GLOBALS.events.selectedThreadChanged(0); } ////////////////////////////////////////////////////////////////////////// @@ -1646,7 +1650,7 @@ void EasyGraphicsView::onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta) { for (auto item : m_items) { - if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread) + if (item->threadId() == EASY_GLOBALS.selected_thread) { m_bUpdatingRect = true; auto vbar = verticalScrollBar(); @@ -1779,8 +1783,8 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event) } } - const ::profiler_gui::ProfBlockItem* selectedBlock = nullptr; - const auto previouslySelectedBlock = ::profiler_gui::EASY_GLOBALS.selected_block; + const ::profiler_gui::EasyBlockItem* selectedBlock = nullptr; + const auto previouslySelectedBlock = EASY_GLOBALS.selected_block; if (m_mouseButtons & Qt::LeftButton) { bool clicked = false; @@ -1813,15 +1817,15 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event) { changedSelectedItem = true; selectedBlock = block; - ::profiler_gui::EASY_GLOBALS.selected_block = block->block->block_index; + EASY_GLOBALS.selected_block = block->block; break; } } - if (!changedSelectedItem && ::profiler_gui::EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(::profiler_gui::EASY_GLOBALS.selected_block)) + if (!changedSelectedItem && EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(EASY_GLOBALS.selected_block)) { changedSelectedItem = true; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); + ::profiler_gui::set_max(EASY_GLOBALS.selected_block); } } } @@ -1841,12 +1845,12 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event) if (changedSelectedItem) { m_bUpdatingRect = true; - if (selectedBlock != nullptr && previouslySelectedBlock == ::profiler_gui::EASY_GLOBALS.selected_block && !selectedBlock->block->children.empty()) + if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !blocksTree(selectedBlock->block).children.empty()) { - ::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded; + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } - emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block); + emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block); m_bUpdatingRect = false; updateScene(); @@ -1998,7 +2002,7 @@ void EasyGraphicsView::initMode() connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange); connect(&m_flickerTimer, &QTimer::timeout, this, &This::onFlickerTimeout); - auto globalSignals = &::profiler_gui::EASY_GLOBALS.events; + auto globalSignals = &EASY_GLOBALS.events; connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange); @@ -2101,11 +2105,11 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index) { if (!m_bUpdatingRect) { - if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) + if (_block_index < EASY_GLOBALS.gui_blocks.size()) { // Scroll to item - const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index]; + const auto& guiblock = EASY_GLOBALS.gui_blocks[_block_index]; const auto thread_item = m_items[guiblock.graphics_item]; const auto& item = thread_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index]; @@ -2180,7 +2184,7 @@ EasyThreadViewWidget::EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* vi //m_layout->addWidget(m_label); //setLayout(m_layout); //show(); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); } EasyThreadViewWidget::~EasyThreadViewWidget() @@ -2191,14 +2195,14 @@ EasyThreadViewWidget::~EasyThreadViewWidget() void EasyThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id) { /* - auto threadName = ::profiler_gui::EASY_GLOBALS.profiler_blocks[::profiler_gui::EASY_GLOBALS.selected_thread].thread_name; + auto threadName = EASY_GLOBALS.profiler_blocks[EASY_GLOBALS.selected_thread].thread_name; if(threadName[0]!=0) { m_label->setText(threadName); } else { - m_label->setText(QString("Thread %1").arg(::profiler_gui::EASY_GLOBALS.selected_thread)); + m_label->setText(QString("Thread %1").arg(EASY_GLOBALS.selected_thread)); } */ QLayoutItem *ditem; diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index e51522d..e0ceb31 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -58,7 +58,7 @@ inline qreal microseconds2units(qreal _value) class EasyGraphicsItem : public QGraphicsItem { - typedef ::profiler_gui::ProfItems Children; + typedef ::profiler_gui::EasyItems Children; typedef ::std::vector DrawIndexes; typedef ::std::vector Sublevels; @@ -118,13 +118,13 @@ public: \param _level Index of the level \param _index Index of required item */ - const ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index) const; + const ::profiler_gui::EasyBlockItem& getItem(unsigned char _level, unsigned int _index) const; /**\brief Returns reference to the item with required index on specified level. \param _level Index of the level \param _index Index of required item */ - ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index); + ::profiler_gui::EasyBlockItem& getItem(unsigned char _level, unsigned int _index); /** \brief Adds new item to required level. @@ -142,7 +142,7 @@ public: \param _blocks Reference to the array of selected blocks */ void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const; - const ::profiler_gui::ProfBlockItem* intersect(const QPointF& _pos) const; + const ::profiler_gui::EasyBlockItem* intersect(const QPointF& _pos) const; private: diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 877c723..a64931b 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -104,8 +104,8 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent) setHeaderItem(header); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout); loadSettings(); @@ -163,8 +163,8 @@ void EasyTreeWidget::onFillTimerTimeout() connect(this, &Parent::itemExpanded, this, &This::onItemExpand); connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange); - onSelectedThreadChange(::profiler_gui::EASY_GLOBALS.selected_thread); - onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); + onSelectedThreadChange(EASY_GLOBALS.selected_thread); + onSelectedBlockChange(EASY_GLOBALS.selected_block); } else { @@ -194,7 +194,7 @@ void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler: // { // addTopLevelItem(item.second); // m_roots[item.first] = item.second; - // if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread) + // if (item.first == EASY_GLOBALS.selected_thread) // item.second->colorize(true); // } //} @@ -227,7 +227,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, :: // { // addTopLevelItem(item.second); // m_roots[item.first] = item.second; - // if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread) + // if (item.first == EASY_GLOBALS.selected_thread) // item.second->colorize(true); // } //} @@ -238,7 +238,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, :: //connect(this, &Parent::itemExpanded, this, &This::onItemExpand); //connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); - //onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); + //onSelectedBlockChange(EASY_GLOBALS.selected_block); } ////////////////////////////////////////////////////////////////////////// @@ -265,15 +265,15 @@ void EasyTreeWidget::clearSilent(bool _global) if (!_global) { - if (::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items) + if (EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items) { - auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index]; + auto& gui_block = item->guiBlock(); ::profiler_gui::set_max(gui_block.tree_item); gui_block.expanded = false; } else for (auto item : m_items) { - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item); + ::profiler_gui::set_max(item->guiBlock().tree_item); } } @@ -294,7 +294,7 @@ void EasyTreeWidget::clearSilent(bool _global) //clear(); if (!_global) - emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } ////////////////////////////////////////////////////////////////////////// @@ -339,7 +339,7 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) action->setChecked(m_bColorRows); connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered); - if (item != nullptr) + if (item != nullptr && item->parent() != nullptr) { //auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index); //itemAction->setToolTip("Scroll graphics scene to current item in the tree"); @@ -357,16 +357,16 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) case COL_MAX_PER_PARENT: case COL_MAX_PER_FRAME: { - auto block = item->block(); + auto& block = item->block(); auto i = ::profiler_gui::numeric_max(); switch (col) { - case COL_MIN_PER_THREAD: i = block->per_thread_stats->min_duration_block; break; - case COL_MIN_PER_PARENT: i = block->per_parent_stats->min_duration_block; break; - case COL_MIN_PER_FRAME: i = block->per_frame_stats->min_duration_block; break; - case COL_MAX_PER_THREAD: i = block->per_thread_stats->max_duration_block; break; - case COL_MAX_PER_PARENT: i = block->per_parent_stats->max_duration_block; break; - case COL_MAX_PER_FRAME: i = block->per_frame_stats->max_duration_block; break; + case COL_MIN_PER_THREAD: i = block.per_thread_stats->min_duration_block; break; + case COL_MIN_PER_PARENT: i = block.per_parent_stats->min_duration_block; break; + case COL_MIN_PER_FRAME: i = block.per_frame_stats->min_duration_block; break; + case COL_MAX_PER_THREAD: i = block.per_thread_stats->max_duration_block; break; + case COL_MAX_PER_PARENT: i = block.per_parent_stats->max_duration_block; break; + case COL_MAX_PER_FRAME: i = block.per_frame_stats->max_duration_block; break; } if (i != ::profiler_gui::numeric_max(i)) @@ -427,8 +427,8 @@ void EasyTreeWidget::alignProgressBar() void EasyTreeWidget::onJumpToItemClicked(unsigned int _block_index) { - ::profiler_gui::EASY_GLOBALS.selected_block = _block_index; - emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(_block_index); + EASY_GLOBALS.selected_block = _block_index; + emit EASY_GLOBALS.events.selectedBlockChanged(_block_index); } void EasyTreeWidget::onCollapseAllClicked(bool) @@ -439,11 +439,11 @@ void EasyTreeWidget::onCollapseAllClicked(bool) collapseAll(); m_bSilentExpandCollapse = false; - if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (EASY_GLOBALS.bind_scene_and_tree_expand_status) { for (auto item : m_items) - ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = false; - emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + item->guiBlock().expanded = false; + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } @@ -456,11 +456,15 @@ void EasyTreeWidget::onExpandAllClicked(bool) resizeColumnsToContents(); m_bSilentExpandCollapse = false; - if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (EASY_GLOBALS.bind_scene_and_tree_expand_status) { for (auto item : m_items) - ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = !item->block()->children.empty(); - emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + { + auto& b = item->guiBlock(); + b.expanded = !b.tree.children.empty(); + } + + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } @@ -475,7 +479,7 @@ void EasyTreeWidget::onCollapseAllChildrenClicked(bool) current->collapseAll(); m_bSilentExpandCollapse = false; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } @@ -491,7 +495,7 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool) resizeColumnsToContents(); m_bSilentExpandCollapse = false; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } @@ -499,30 +503,30 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool) void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item) { - if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (!EASY_GLOBALS.bind_scene_and_tree_expand_status) { resizeColumnsToContents(); return; } - ::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast(_item)->block()->block_index].expanded = true; + static_cast(_item)->guiBlock().expanded = true; if (!m_bSilentExpandCollapse) { resizeColumnsToContents(); - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item) { - if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (!EASY_GLOBALS.bind_scene_and_tree_expand_status) return; - ::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast(_item)->block()->block_index].expanded = false; + static_cast(_item)->guiBlock().expanded = false; if (!m_bSilentExpandCollapse) - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } ////////////////////////////////////////////////////////////////////////// @@ -530,13 +534,13 @@ void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item) void EasyTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem*) { if (_item == nullptr) - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); + ::profiler_gui::set_max(EASY_GLOBALS.selected_block); else - ::profiler_gui::EASY_GLOBALS.selected_block = static_cast(_item)->block()->block_index; + EASY_GLOBALS.selected_block = static_cast(_item)->block_index(); - disconnect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); - emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + disconnect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); } ////////////////////////////////////////////////////////////////////////// @@ -581,9 +585,9 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index) EasyTreeWidgetItem* item = nullptr; - if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) + if (_block_index < EASY_GLOBALS.gui_blocks.size()) { - const auto i = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index].tree_item; + const auto i = easyBlock(_block_index).tree_item; if (i < m_items.size()) item = m_items[i]; } @@ -592,19 +596,19 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index) { //const QSignalBlocker b(this); - if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (EASY_GLOBALS.bind_scene_and_tree_expand_status) { m_bSilentExpandCollapse = true; setCurrentItem(item); scrollToItem(item, QAbstractItemView::PositionAtCenter); - if (::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded) + if (item->guiBlock().expanded) expandItem(item); else collapseItem(item); resizeColumnsToContents(); m_bSilentExpandCollapse = false; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); } else { diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 1b48127..fa07d8b 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -105,14 +105,15 @@ inline QRgb fromProfilerRgb(unsigned int _red, unsigned int _green, unsigned int ////////////////////////////////////////////////////////////////////////// #pragma pack(push, 1) -struct ProfBlockItem final +struct EasyBlockItem final { - const ::profiler::BlocksTree* block; ///< Pointer to profiler block + //const ::profiler::BlocksTree* block; ///< Pointer to profiler block qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene) float w; ///< Width of the item QRgb color; ///< Background color of the item - unsigned int children_begin; ///< Index of first child item on the next sublevel - unsigned short totalHeight; ///< Total height of the item including heights of all it's children + ::profiler::block_index_t block; ///< Index of profiler block + uint32_t children_begin; ///< Index of first child item on the next sublevel + uint16_t totalHeight; ///< Total height of the item including heights of all it's children char state; ///< 0 = no change, 1 = paint, -1 = do not paint // Possible optimizations: @@ -125,31 +126,58 @@ struct ProfBlockItem final inline qreal right() const { return x + w; } inline float width() const { return w; } -}; // END of struct ProfBlockItem. -#pragma pack(pop) +}; // END of struct EasyBlockItem. -typedef ::std::vector ProfItems; - -////////////////////////////////////////////////////////////////////////// - -struct ProfSelectedBlock final +struct EasyBlock final { - const ::profiler::BlocksTreeRoot* root; - const ::profiler::BlocksTree* tree; + ::profiler::BlocksTree tree; + uint32_t tree_item; + uint32_t graphics_item_index; + uint8_t graphics_item_level; + uint8_t graphics_item; + bool expanded; - ProfSelectedBlock() : root(nullptr), tree(nullptr) + EasyBlock() = default; + + EasyBlock(EasyBlock&& that) + : tree(::std::move(tree)) + , tree_item(that.tree_item) + , graphics_item_index(that.graphics_item_index) + , graphics_item_level(that.graphics_item_level) + , graphics_item(that.graphics_item) + , expanded(that.expanded) { } - ProfSelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::BlocksTree* _tree) +private: + + EasyBlock(const EasyBlock&) = delete; +}; +#pragma pack(pop) + +typedef ::std::vector EasyItems; +typedef ::std::vector EasyBlocks; + +////////////////////////////////////////////////////////////////////////// + +struct EasySelectedBlock final +{ + const ::profiler::BlocksTreeRoot* root; + ::profiler::block_index_t tree; + + EasySelectedBlock() : root(nullptr), tree(0xffffffff) + { + } + + EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree) : root(_root) , tree(_tree) { } -}; // END of struct ProfSelectedBlock. +}; // END of struct EasySelectedBlock. -typedef ::std::vector TreeBlocks; +typedef ::std::vector TreeBlocks; ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index ca2a1d4..0a0eee8 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -42,19 +42,6 @@ namespace profiler_gui { ////////////////////////////////////////////////////////////////////////// -#pragma pack(push, 1) - struct EasyBlock final - { - unsigned int tree_item; - unsigned int graphics_item_index; - unsigned char graphics_item_level; - unsigned char graphics_item; - bool expanded; - }; -#pragma pack(pop) - - typedef ::std::vector EasyBlocks; - template inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString)) { @@ -97,13 +84,26 @@ namespace profiler_gui { }; // END of struct EasyGlobals. -#ifndef IGNORE_GLOBALS_DECLARATION - static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance(); -#endif ////////////////////////////////////////////////////////////////////////// } // END of namespace profiler_gui. +#ifndef IGNORE_GLOBALS_DECLARATION +static ::profiler_gui::EasyGlobals& EASY_GLOBALS = ::profiler_gui::EasyGlobals::instance(); + +inline ::profiler_gui::EasyBlock& easyBlock(::profiler::block_index_t i) { + return EASY_GLOBALS.gui_blocks[i]; +} + +inline ::profiler::SerializedBlockDescriptor& easyDescriptor(::profiler::block_id_t i) { + return *EASY_GLOBALS.descriptors[i]; +} + +inline ::profiler::BlocksTree& blocksTree(::profiler::block_index_t i) { + return easyBlock(i).tree; +} +#endif + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/graphics_scrollbar.cpp b/profiler_gui/graphics_scrollbar.cpp index 88d5fec..2260857 100644 --- a/profiler_gui/graphics_scrollbar.cpp +++ b/profiler_gui/graphics_scrollbar.cpp @@ -238,7 +238,7 @@ void EasyMinimapItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) m_boundingRect.setRect(x, y, w, h); } -void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) +void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items) { m_pSource = _items; m_threadId = _thread_id; @@ -428,7 +428,7 @@ void EasyGraphicsScrollbar::hideChrono() ////////////////////////////////////////////////////////////////////////// -void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) +void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items) { m_minimap->setSource(_thread_id, _items); m_slider->setVisible(m_minimap->isVisible()); @@ -493,14 +493,14 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event) void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) { - if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty()) + if (EASY_GLOBALS.profiler_blocks.empty()) { return; } QMenu menu; - for (const auto& it : ::profiler_gui::EASY_GLOBALS.profiler_blocks) + for (const auto& it : EASY_GLOBALS.profiler_blocks) { QString label; if (it.second.thread_name && it.second.thread_name[0] != 0) @@ -514,7 +514,7 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) auto action = new EasyIdAction(label, it.first); action->setCheckable(true); - action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread); + action->setChecked(it.first == EASY_GLOBALS.selected_thread); connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked); menu.addAction(action); @@ -530,8 +530,8 @@ void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id) { if (_id != m_minimap->threadId()) { - ::profiler_gui::EASY_GLOBALS.selected_thread = _id; - emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(_id); + EASY_GLOBALS.selected_thread = _id; + emit EASY_GLOBALS.events.selectedThreadChanged(_id); } } diff --git a/profiler_gui/graphics_scrollbar.h b/profiler_gui/graphics_scrollbar.h index b70a1af..85e19a9 100644 --- a/profiler_gui/graphics_scrollbar.h +++ b/profiler_gui/graphics_scrollbar.h @@ -66,7 +66,7 @@ class EasyMinimapItem : public QGraphicsItem QRectF m_boundingRect; qreal m_maxDuration; qreal m_minDuration; - const ::profiler_gui::ProfItems* m_pSource; + const ::profiler_gui::EasyItems* m_pSource; ::profiler::thread_id_t m_threadId; public: @@ -88,7 +88,7 @@ public: void setBoundingRect(const QRectF& _rect); void setBoundingRect(qreal x, qreal y, qreal w, qreal h); - void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items); + void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items); }; // END of class EasyMinimapItem. @@ -190,9 +190,9 @@ public: void showChrono(); void hideChrono(); - void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::ProfItems* _items); + void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::EasyItems* _items); - inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems& _items) + inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems& _items) { setMinimapFrom(_thread_id, &_items); } diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 8edf2da..945ab3f 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -100,22 +100,22 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsVi menu->addSeparator(); action = menu->addAction("Draw items' borders"); action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); + action->setChecked(EASY_GLOBALS.draw_graphics_items_borders); connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); action = menu->addAction("Collapse items on tree reset"); action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); + action->setChecked(EASY_GLOBALS.collapse_items_on_tree_close); connect(action, &QAction::triggered, this, &This::onCollapseItemsAfterCloseChanged); action = menu->addAction("Expand all on file open"); action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); + action->setChecked(EASY_GLOBALS.all_items_expanded_by_default); connect(action, &QAction::triggered, this, &This::onAllItemsExpandedByDefaultChange); action = menu->addAction("Bind scene and tree expand"); action->setCheckable(true); - action->setChecked(::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); + action->setChecked(EASY_GLOBALS.bind_scene_and_tree_expand_status); connect(action, &QAction::triggered, this, &This::onBindExpandStatusChange); menu->addSeparator(); @@ -126,7 +126,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsVi action = new QAction("At top", actionGroup); action->setCheckable(true); action->setData(static_cast(::profiler_gui::ChronoTextPosition_Top)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) action->setChecked(true); submenu->addAction(action); connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); @@ -134,7 +134,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsVi action = new QAction("At center", actionGroup); action->setCheckable(true); action->setData(static_cast(::profiler_gui::ChronoTextPosition_Center)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) action->setChecked(true); submenu->addAction(action); connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); @@ -142,7 +142,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsVi action = new QAction("At bottom", actionGroup); action->setCheckable(true); action->setData(static_cast(::profiler_gui::ChronoTextPosition_Bottom)); - if (::profiler_gui::EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) action->setChecked(true); submenu->addAction(action); connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); @@ -250,39 +250,39 @@ void EasyMainWindow::onEncodingChanged(bool) void EasyMainWindow::onChronoTextPosChanged(bool) { auto _sender = qobject_cast(sender()); - ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt()); - emit ::profiler_gui::EASY_GLOBALS.events.chronoPositionChanged(); + EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt()); + emit EASY_GLOBALS.events.chronoPositionChanged(); } void EasyMainWindow::onDrawBordersChanged(bool _checked) { - ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = _checked; - emit ::profiler_gui::EASY_GLOBALS.events.drawBordersChanged(); + EASY_GLOBALS.draw_graphics_items_borders = _checked; + emit EASY_GLOBALS.events.drawBordersChanged(); } void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked) { - ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = _checked; + EASY_GLOBALS.collapse_items_on_tree_close = _checked; } void EasyMainWindow::onAllItemsExpandedByDefaultChange(bool _checked) { - ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = _checked; + EASY_GLOBALS.all_items_expanded_by_default = _checked; } void EasyMainWindow::onBindExpandStatusChange(bool _checked) { - ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = _checked; + EASY_GLOBALS.bind_scene_and_tree_expand_status = _checked; } ////////////////////////////////////////////////////////////////////////// void EasyMainWindow::onExpandAllClicked(bool) { - for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) + for (auto& block : EASY_GLOBALS.gui_blocks) block.expanded = true; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); auto tree = static_cast(m_treeWidget->widget()); const QSignalBlocker b(tree); @@ -291,10 +291,10 @@ void EasyMainWindow::onExpandAllClicked(bool) void EasyMainWindow::onCollapseAllClicked(bool) { - for (auto& block : ::profiler_gui::EASY_GLOBALS.gui_blocks) + for (auto& block : EASY_GLOBALS.gui_blocks) block.expanded = false; - emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + emit EASY_GLOBALS.events.itemsExpandStateChanged(); auto tree = static_cast(m_treeWidget->widget()); const QSignalBlocker b(tree); @@ -326,32 +326,32 @@ void EasyMainWindow::loadSettings() auto val = settings.value("chrono_text_position"); if (!val.isNull()) { - ::profiler_gui::EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(val.toInt()); + EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(val.toInt()); } auto flag = settings.value("draw_graphics_items_borders"); if (!flag.isNull()) { - ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = flag.toBool(); + EASY_GLOBALS.draw_graphics_items_borders = flag.toBool(); } flag = settings.value("collapse_items_on_tree_close"); if (!flag.isNull()) { - ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); + EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); } flag = settings.value("all_items_expanded_by_default"); if (!flag.isNull()) { - ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default = flag.toBool(); + EASY_GLOBALS.all_items_expanded_by_default = flag.toBool(); } flag = settings.value("bind_scene_and_tree_expand_status"); if (!flag.isNull()) { - ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool(); + EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool(); } QString encoding = settings.value("encoding", "UTF-8").toString(); @@ -379,11 +379,11 @@ void EasyMainWindow::saveSettingsAndGeometry() settings.setValue("geometry", this->saveGeometry()); settings.setValue("last_file", m_lastFile); - settings.setValue("chrono_text_position", static_cast(::profiler_gui::EASY_GLOBALS.chrono_text_position)); - settings.setValue("draw_graphics_items_borders", ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); - settings.setValue("collapse_items_on_tree_close", ::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close); - settings.setValue("all_items_expanded_by_default", ::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default); - settings.setValue("bind_scene_and_tree_expand_status", ::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status); + settings.setValue("chrono_text_position", static_cast(EASY_GLOBALS.chrono_text_position)); + settings.setValue("draw_graphics_items_borders", EASY_GLOBALS.draw_graphics_items_borders); + settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close); + settings.setValue("all_items_expanded_by_default", EASY_GLOBALS.all_items_expanded_by_default); + settings.setValue("bind_scene_and_tree_expand_status", EASY_GLOBALS.bind_scene_and_tree_expand_status); settings.setValue("encoding", QTextCodec::codecForLocale()->name()); settings.endGroup(); @@ -402,28 +402,34 @@ void EasyMainWindow::onFileReaderTimeout() ::profiler::SerializedData serialized_blocks, serialized_descriptors; ::profiler::descriptors_list_t descriptors; - ::profiler::thread_blocks_tree_t prof_blocks; + ::profiler::blocks_t blocks; + ::profiler::thread_blocks_tree_t threads_map; QString filename; - m_reader.get(serialized_blocks, serialized_descriptors, descriptors, prof_blocks, filename); + m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, filename); - if (prof_blocks.size() > 0xff) + if (threads_map.size() > 0xff) { - qWarning() << "Warning: file " << filename << " contains " << prof_blocks.size() << " threads!"; + qWarning() << "Warning: file " << filename << " contains " << threads_map.size() << " threads!"; qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed."; } m_lastFile = ::std::move(filename); m_serializedBlocks = ::std::move(serialized_blocks); m_serializedDescriptors = ::std::move(serialized_descriptors); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); - ::profiler_gui::EASY_GLOBALS.descriptors.swap(descriptors); - ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); - memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); - for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); + EASY_GLOBALS.selected_thread = 0; + ::profiler_gui::set_max(EASY_GLOBALS.selected_block); + EASY_GLOBALS.profiler_blocks.swap(threads_map); + EASY_GLOBALS.descriptors.swap(descriptors); - static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); + EASY_GLOBALS.gui_blocks.resize(nblocks); + memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); + for (decltype(nblocks) i = 0; i < nblocks; ++i) { + auto& guiblock = EASY_GLOBALS.gui_blocks[i]; + guiblock.tree = ::std::move(blocks[i]); + ::profiler_gui::set_max(guiblock.tree_item); + } + + static_cast(m_graphicsView->widget())->view()->setTree(EASY_GLOBALS.profiler_blocks); } else { @@ -436,7 +442,7 @@ void EasyMainWindow::onFileReaderTimeout() m_progress->setValue(100); //m_progress->hide(); - if (::profiler_gui::EASY_GLOBALS.all_items_expanded_by_default) + if (EASY_GLOBALS.all_items_expanded_by_default) { onExpandAllClicked(true); } @@ -493,7 +499,7 @@ void EasyFileReader::load(const QString& _filename) m_filename = _filename; m_thread = ::std::move(::std::thread([this]() { - m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocksTree, true)); + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, true)); m_progress.store(100); m_bDone.store(true); })); @@ -511,17 +517,20 @@ void EasyFileReader::interrupt() m_serializedBlocks.clear(); m_serializedDescriptors.clear(); m_descriptors.clear(); + m_blocks.clear(); m_blocksTree.clear(); } void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, - ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename) + ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree, + QString& _filename) { if (done()) { m_serializedBlocks.swap(_serializedBlocks); m_serializedDescriptors.swap(_serializedDescriptors); - ::profiler::descriptors_list_t(m_descriptors).swap(_descriptors); + ::profiler::descriptors_list_t(::std::move(m_descriptors)).swap(_descriptors); + m_blocks.swap(_blocks); m_blocksTree.swap(_tree); m_filename.swap(_filename); } diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 138ca85..91160d4 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -35,6 +35,7 @@ class EasyFileReader final ::profiler::SerializedData m_serializedBlocks; ///< ::profiler::SerializedData m_serializedDescriptors; ///< ::profiler::descriptors_list_t m_descriptors; ///< + ::profiler::blocks_t m_blocks; ///< ::profiler::thread_blocks_tree_t m_blocksTree; ///< QString m_filename; ///< ::std::thread m_thread; ///< @@ -55,7 +56,8 @@ public: void load(const QString& _filename); void interrupt(); void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, - ::profiler::descriptors_list_t& _descriptors, ::profiler::thread_blocks_tree_t& _tree, QString& _filename); + ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree, + QString& _filename); }; // END of class EasyFileReader. diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp index 003fc1d..1a2c0a6 100644 --- a/profiler_gui/tree_widget_item.cpp +++ b/profiler_gui/tree_widget_item.cpp @@ -21,7 +21,7 @@ ////////////////////////////////////////////////////////////////////////// -EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent) +EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock, Parent* _parent) : Parent(_parent) , m_block(_treeBlock) , m_customBGColor(0) @@ -75,15 +75,25 @@ bool EasyTreeWidgetItem::operator < (const Parent& _other) const return false; } -const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const +::profiler::block_index_t EasyTreeWidgetItem::block_index() const { return m_block; } +::profiler_gui::EasyBlock& EasyTreeWidgetItem::guiBlock() +{ + return easyBlock(m_block); +} + +const ::profiler::BlocksTree& EasyTreeWidgetItem::block() const +{ + return blocksTree(m_block); +} + ::profiler::timestamp_t EasyTreeWidgetItem::duration() const { - if (m_block->node) - return m_block->node->duration(); + if (parent() != nullptr) + return block().node->duration(); return data(COL_DURATION, Qt::UserRole).toULongLong(); } @@ -173,7 +183,8 @@ void EasyTreeWidgetItem::collapseAll() } setExpanded(false); - ::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false; + if (parent() != nullptr) + guiBlock().expanded = false; } void EasyTreeWidgetItem::expandAll() @@ -184,7 +195,8 @@ void EasyTreeWidgetItem::expandAll() } setExpanded(true); - ::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = true; + if (parent() != nullptr) + guiBlock().expanded = true; } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_item.h b/profiler_gui/tree_widget_item.h index 466b9f6..1b12d21 100644 --- a/profiler_gui/tree_widget_item.h +++ b/profiler_gui/tree_widget_item.h @@ -75,7 +75,7 @@ class EasyTreeWidgetItem : public QTreeWidgetItem typedef QTreeWidgetItem Parent; typedef EasyTreeWidgetItem This; - const ::profiler::BlocksTree* m_block; + const ::profiler::block_index_t m_block; QRgb m_customBGColor; QRgb m_customTextColor; @@ -84,14 +84,16 @@ public: using Parent::setBackgroundColor; using Parent::setTextColor; - EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr); + EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max(), Parent* _parent = nullptr); virtual ~EasyTreeWidgetItem(); bool operator < (const Parent& _other) const override; public: - const ::profiler::BlocksTree* block() const; + ::profiler::block_index_t block_index() const; + ::profiler_gui::EasyBlock& guiBlock(); + const ::profiler::BlocksTree& block() const; ::profiler::timestamp_t duration() const; ::profiler::timestamp_t selfDuration() const; diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index 8248e81..2931382 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -126,7 +126,7 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI ::profiler::timestamp_t finishtime = 0; for (const auto& threadTree : _blocksTree) { - const auto node_block = threadTree.second.tree.children.front().node; + const auto node_block = blocksTree(threadTree.second.children.front()).node; const auto startTime = node_block->begin(); const auto endTime = node_block->end(); @@ -145,49 +145,49 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI if (_safelocker.interrupted()) break; - auto& block = threadTree.second.tree; - auto item = new EasyTreeWidgetItem(&block); + const auto& root = threadTree.second; + auto item = new EasyTreeWidgetItem(); - if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0) + if (root.thread_name && root.thread_name[0] != 0) { - item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first)); + item->setText(COL_NAME, QString("%1 Thread %2").arg(root.thread_name).arg(root.thread_id)); } else { - item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first)); + item->setText(COL_NAME, QString("Thread %1").arg(root.thread_id)); } ::profiler::timestamp_t duration = 0; - if (!block.children.empty()) + if (!root.children.empty()) { - duration = block.children.back().node->end() - block.children.front().node->begin(); + duration = blocksTree(root.children.back()).node->end() - blocksTree(root.children.front()).node->begin(); } item->setTimeSmart(COL_DURATION, duration); item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); - _items.push_back(item); + //_items.push_back(item); // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.children) - children_duration += child.node->duration(); + for (auto i : root.children) + children_duration += blocksTree(i).node->duration(); item->setTimeSmart(COL_SELF_DURATION, children_duration); children_duration = 0; - const auto children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows); + const auto children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, root.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows); if (children_items_number > 0) { //total_items += children_items_number + 1; //addTopLevelItem(item); //m_roots[threadTree.first] = item; - _topLevelItems.emplace_back(threadTree.first, item); + _topLevelItems.emplace_back(root.thread_id, item); } else { - _items.pop_back(); + //_items.pop_back(); delete item; } @@ -200,11 +200,11 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI ////////////////////////////////////////////////////////////////////////// -auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size()) +auto calculateTotalChildrenNumber(const ::profiler::BlocksTree& _tree) -> decltype(_tree.children.size()) { - auto children_number = _tree->children.size(); - for (const auto& child : _tree->children) - children_number += calculateTotalChildrenNumber(&child); + auto children_number = _tree.children.size(); + for (auto i : _tree.children) + children_number += calculateTotalChildrenNumber(blocksTree(i)); return children_number; } @@ -213,7 +213,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI { //size_t blocksNumber = 0; //for (const auto& block : _blocks) - // blocksNumber += calculateTotalChildrenNumber(block.tree); + // blocksNumber += calculateTotalChildrenNumber(*block.tree); // //blocksNumber += block.tree->total_children_number; //m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks @@ -226,8 +226,9 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI if (_safelocker.interrupted()) break; - const auto startTime = block.tree->node->begin(); - const auto endTime = block.tree->node->end(); + auto& gui_block = easyBlock(block.tree); + const auto startTime = gui_block.tree.node->begin(); + const auto endTime = gui_block.tree.node->end(); if (startTime > _right || endTime < _left) { _safelocker.setProgress((90 * ++i) / total); @@ -243,7 +244,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI } else { - thread_item = new EasyTreeWidgetItem(&block.root->tree); + thread_item = new EasyTreeWidgetItem(); if (block.root->thread_name && block.root->thread_name[0] != 0) { @@ -254,9 +255,9 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); } - if (!block.root->tree.children.empty()) + if (!block.root->children.empty()) { - duration = block.root->tree.children.back().node->end() - block.root->tree.children.front().node->begin(); + duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin(); } thread_item->setTimeSmart(COL_DURATION, duration); @@ -265,8 +266,8 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI // Calculate clean duration (sum of all children durations) ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.root->tree.children) - children_duration += child.node->duration(); + for (auto i : block.root->children) + children_duration += blocksTree(i).node->duration(); thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); @@ -275,7 +276,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI auto item = new EasyTreeWidgetItem(block.tree, thread_item); duration = endTime - startTime; - auto name = *block.tree->node->name() != 0 ? block.tree->node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->name(); + auto name = *gui_block.tree.node->name() != 0 ? gui_block.tree.node->name() : easyDescriptor(gui_block.tree.node->id()).name(); item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); item->setTimeSmart(COL_DURATION, duration); item->setTimeMs(COL_BEGIN, startTime - _beginTime); @@ -287,14 +288,14 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); item->setText(COL_PERCENT_PER_FRAME, ""); - if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also + if (gui_block.tree.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also { - const auto& per_thread_stats = block.tree->per_thread_stats; - const auto& per_parent_stats = block.tree->per_parent_stats; - const auto& per_frame_stats = block.tree->per_frame_stats; + const auto& per_thread_stats = gui_block.tree.per_thread_stats; + const auto& per_parent_stats = gui_block.tree.per_parent_stats; + const auto& per_frame_stats = gui_block.tree.per_frame_stats; - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); @@ -310,7 +311,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); @@ -322,7 +323,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); @@ -339,7 +340,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setText(COL_PERCENT_SUM_PER_THREAD, ""); } - const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[block.tree->node->id()]->color(); + const auto color = easyDescriptor(gui_block.tree.node->id()).color(); const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); const auto fgColor = 0x00ffffff - bgColor; item->setBackgroundColor(bgColor); @@ -350,9 +351,9 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI size_t children_items_number = 0; ::profiler::timestamp_t children_duration = 0; - if (!block.tree->children.empty()) + if (!gui_block.tree.children.empty()) { - children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows); + children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, gui_block.tree.children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows); if (_safelocker.interrupted()) break; } @@ -371,12 +372,12 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) { //total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item_index; + gui_block.tree_item = item_index; if (_colorizeRows) item->colorize(_colorizeRows); - if (::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].expanded) + if (gui_block.expanded) item->setExpanded(true); } @@ -400,7 +401,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI //addTopLevelItem(item); //m_roots[it.first] = item; - _items.push_back(item); + //_items.push_back(item); _topLevelItems.emplace_back(it.first, item); //++total_items; @@ -421,11 +422,13 @@ template size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows) { size_t total_items = 0; - for (const auto& child : _children) + for (auto child_index : _children) { if (_safelocker.interrupted()) break; + auto& gui_block = easyBlock(child_index); + const auto& child = gui_block.tree; const auto startTime = child.node->begin(); const auto endTime = child.node->end(); const auto duration = endTime - startTime; @@ -436,9 +439,9 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: continue; } - auto item = new EasyTreeWidgetItem(&child, _parent); + auto item = new EasyTreeWidgetItem(child_index, _parent); - auto name = *child.node->name() != 0 ? child.node->name() : ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->name(); + auto name = *child.node->name() != 0 ? child.node->name() : easyDescriptor(child.node->id()).name(); item->setText(COL_NAME, ::profiler_gui::toUnicode(name)); item->setTimeSmart(COL_DURATION, duration); item->setTimeMs(COL_BEGIN, startTime - _beginTime); @@ -480,7 +483,7 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: } - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); @@ -499,7 +502,7 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: } - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); @@ -511,7 +514,7 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats) { item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); @@ -532,13 +535,13 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: item->setText(COL_PERCENT_SUM_PER_THREAD, ""); } - const auto color = ::profiler_gui::EASY_GLOBALS.descriptors[child.node->id()]->color(); + const auto color = easyDescriptor(child.node->id()).color(); const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); const auto fgColor = 0x00ffffff - bgColor; item->setBackgroundColor(bgColor); item->setTextColor(fgColor); - auto item_index = static_cast(_items.size()); + auto item_index = static_cast(_items.size()); _items.push_back(item); size_t children_items_number = 0; @@ -564,12 +567,12 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) { total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item_index; + gui_block.tree_item = item_index; if (_colorizeRows) item->colorize(_colorizeRows); - if (::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].expanded) + if (gui_block.expanded) item->setExpanded(true); } else diff --git a/reader/main.cpp b/reader/main.cpp index ed696d1..6170bcb 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -112,7 +112,8 @@ int main(int argc, char* argv[]) ::profiler::SerializedData serialized_blocks, serialized_descriptors; ::profiler::descriptors_list_t descriptors; - auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, threaded_trees, true); + ::profiler::blocks_t blocks; + auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true); auto end = std::chrono::system_clock::now(); diff --git a/src/reader.cpp b/src/reader.cpp index aee8d86..d3ba142 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -198,7 +198,7 @@ typedef ::std::unordered_map<::std::string, ::profiler::block_id_t> IdMap; automatically receive statistics update. */ -::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current) +::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index) { auto duration = _current.node->duration(); //StatsMap::key_type key(_current.node->name()); @@ -216,14 +216,14 @@ automatically receive statistics update. if (duration > stats->max_duration) { // update max duration - stats->max_duration_block = _current.block_index; + stats->max_duration_block = _current_index; stats->max_duration = duration; } if (duration < stats->min_duration) { // update min duraton - stats->min_duration_block = _current.block_index; + stats->min_duration_block = _current_index; stats->min_duration = duration; } @@ -234,7 +234,7 @@ automatically receive statistics update. // This is first time the block appear in the file. // Create new statistics. - auto stats = new ::profiler::BlockStatistics(duration, _current.block_index); + auto stats = new ::profiler::BlockStatistics(duration, _current_index); //_stats_map.emplace(key, stats); _stats_map.emplace(_current.node->id(), stats); @@ -243,289 +243,288 @@ automatically receive statistics update. ////////////////////////////////////////////////////////////////////////// -void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current) +void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::blocks_t& _blocks) { - _current.per_frame_stats = update_statistics(_stats_map, _current); - for (auto& child : _current.children) + _current.per_frame_stats = update_statistics(_stats_map, _current, _current_index); + for (auto i : _current.children) { - update_statistics_recursive(_stats_map, child); + update_statistics_recursive(_stats_map, _blocks[i], i, _blocks); } } ////////////////////////////////////////////////////////////////////////// -typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; +extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) +{ + EASY_FUNCTION(::profiler::colors::Cyan); -extern "C" { + ::std::ifstream inFile(filename, ::std::fstream::binary); + progress.store(0); - unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) - { - EASY_FUNCTION(::profiler::colors::Cyan); + if (!inFile.is_open()) + return 0; - ::std::ifstream inFile(filename, ::std::fstream::binary); - progress.store(0); + uint32_t total_blocks_number = 0; + inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); + if (total_blocks_number == 0) + return 0; - if (!inFile.is_open()) + uint64_t memory_size = 0; + inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); + if (memory_size == 0) + return 0; + + serialized_blocks.set(new char[memory_size]); + //memset(serialized_blocks[0], 0, memory_size); + + + uint32_t total_descriptors_number = 0; + inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); + if (total_descriptors_number == 0) + return 0; + + uint64_t descriptors_memory_size = 0; + inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); + if (descriptors_memory_size == 0) + return 0; + + descriptors.reserve(total_descriptors_number); + serialized_descriptors.set(new char[descriptors_memory_size]); + + uint64_t i = 0; + while (!inFile.eof() && descriptors.size() < total_descriptors_number) + { + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) return 0; - PerThreadStats thread_statistics, parent_statistics, frame_statistics; - unsigned int blocks_counter = 0; + //if (i + sz > descriptors_memory_size) + //{ + // printf("FILE CORRUPTED\n"); + // return 0; + //} - uint32_t total_blocks_number = 0; - inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); - if (total_blocks_number == 0) - return 0; + char* data = serialized_descriptors[i]; + inFile.read(data, sz); + auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); + descriptors.push_back(descriptor); - uint64_t memory_size = 0; - inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); - if (memory_size == 0) - return 0; + i += sz; + progress.store(static_cast(10 * i / descriptors_memory_size)); + } - serialized_blocks.set(new char[memory_size]); - //memset(serialized_blocks[0], 0, memory_size); + typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; + PerThreadStats thread_statistics, parent_statistics, frame_statistics; + IdMap identification_table; + i = 0; + uint32_t read_number = 0; + ::profiler::block_index_t blocks_counter = 0; + _blocks.reserve(total_blocks_number); + while (!inFile.eof() && read_number < total_blocks_number) + { + EASY_BLOCK("Read thread data", ::profiler::colors::Darkgreen); - uint32_t total_descriptors_number = 0; - inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); - if (total_descriptors_number == 0) - return 0; + ::profiler::thread_id_t thread_id = 0; + inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); - uint64_t descriptors_memory_size = 0; - inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); - if (descriptors_memory_size == 0) - return 0; + uint32_t blocks_number_in_thread = 0; + inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); - descriptors.reserve(total_descriptors_number); - serialized_descriptors.set(new char[descriptors_memory_size]); - - uint64_t i = 0; - while (!inFile.eof() && descriptors.size() < total_descriptors_number) + auto& root = threaded_trees[thread_id]; + const auto threshold = read_number + blocks_number_in_thread; + while (!inFile.eof() && read_number < threshold) { + EASY_BLOCK("Read block", ::profiler::colors::Green); + + ++read_number; + uint16_t sz = 0; inFile.read((char*)&sz, sizeof(sz)); if (sz == 0) return 0; - //if (i + sz > descriptors_memory_size) - //{ - // printf("FILE CORRUPTED\n"); - // return 0; - //} - - char* data = serialized_descriptors[i]; + char* data = serialized_blocks[i]; inFile.read(data, sz); - auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); - descriptors.push_back(descriptor); - i += sz; - progress.store(static_cast(10 * i / descriptors_memory_size)); - } + auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - IdMap identification_table; + _blocks.emplace_back(); + ::profiler::BlocksTree& tree = _blocks.back(); + tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); + const auto block_index = blocks_counter++; - i = 0; - uint32_t read_number = 0; - while (!inFile.eof() && read_number < total_blocks_number) - { - EASY_BLOCK("Read thread data", ::profiler::colors::Darkgreen); + auto& per_parent_statistics = parent_statistics[thread_id]; + auto& per_thread_statistics = thread_statistics[thread_id]; + auto descriptor = descriptors[baseData->id()]; - ::profiler::thread_id_t thread_id = 0; - inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); - - uint32_t blocks_number_in_thread = 0; - inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); - - auto& root = threaded_trees[thread_id]; - const auto threshold = read_number + blocks_number_in_thread; - while (!inFile.eof() && read_number < threshold) + if (descriptor->type() == ::profiler::BLOCK_TYPE_THREAD_SIGN) { - EASY_BLOCK("Read block", ::profiler::colors::Green); + root.thread_name = tree.node->name(); + } - ++read_number; + if (*tree.node->name() != 0) + { + // If block has runtime name then generate new id for such block. + // Blocks with the same name will have same id. - uint16_t sz = 0; - inFile.read((char*)&sz, sizeof(sz)); - if (sz == 0) - return 0; - - char* data = serialized_blocks[i]; - inFile.read(data, sz); - i += sz; - auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - - ::profiler::BlocksTree tree; - tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); - tree.block_index = blocks_counter++; - - auto& per_parent_statistics = parent_statistics[thread_id]; - auto& per_thread_statistics = thread_statistics[thread_id]; - auto descriptor = descriptors[baseData->id()]; - - if (descriptor->type() == ::profiler::BLOCK_TYPE_THREAD_SIGN) + IdMap::key_type key(tree.node->name()); + auto it = identification_table.find(key); + if (it != identification_table.end()) { - root.thread_name = tree.node->name(); + // There is already block with such name, use it's id + baseData->setId(it->second); } - - if (*tree.node->name() != 0) + else { - IdMap::key_type key(tree.node->name()); - auto it = identification_table.find(key); - if (it != identification_table.end()) + // There were no blocks with such name, generate new id and save it in the table for further usage. + auto id = static_cast<::profiler::block_id_t>(descriptors.size()); + identification_table.emplace(key, id); + descriptors.push_back(descriptors[baseData->id()]); + baseData->setId(id); + } + } + + if (!root.children.empty()) + { + auto& back = _blocks[root.children.back()]; + auto t1 = back.node->end(); + auto mt0 = tree.node->begin(); + if (mt0 < t1)//parent - starts earlier than last ends + { + //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); + /**/ + EASY_BLOCK("Find children", ::profiler::colors::Blue); + auto rlower1 = ++root.children.rbegin(); + for (; rlower1 != root.children.rend() && !(mt0 > _blocks[*rlower1].node->begin()); ++rlower1); + auto lower = rlower1.base(); + ::std::move(lower, root.children.end(), ::std::back_inserter(tree.children)); + + root.children.erase(lower, root.children.end()); + EASY_END_BLOCK; + + ::profiler::timestamp_t children_duration = 0; + if (gather_statistics) { - baseData->setId(it->second); + EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta); + per_parent_statistics.clear(); + + //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows + //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows + // TODO: check this behavior on Linux + + for (auto i : tree.children) + { + auto& child = _blocks[i]; + child.per_parent_stats = update_statistics(per_parent_statistics, child, i); + + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } } else { - auto id = static_cast<::profiler::block_id_t>(descriptors.size()); - identification_table.emplace(key, id); - descriptors.push_back(descriptors[baseData->id()]); - baseData->setId(id); + for (auto i : tree.children) + { + const auto& child = _blocks[i]; + children_duration += child.node->duration(); + if (tree.depth < child.depth) + tree.depth = child.depth; + } } + + ++tree.depth; } - - if (!root.tree.children.empty()) - { - auto& back = root.tree.children.back(); - auto t1 = back.node->end(); - auto mt0 = tree.node->begin(); - if (mt0 < t1)//parent - starts earlier than last ends - { - //auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree); - /**/ - EASY_BLOCK("Find children", ::profiler::colors::Blue); - auto rlower1 = ++root.tree.children.rbegin(); - for (; rlower1 != root.tree.children.rend(); ++rlower1) - { - if (mt0 > rlower1->node->begin()) - { - break; - } - } - auto lower = rlower1.base(); - ::std::move(lower, root.tree.children.end(), ::std::back_inserter(tree.children)); - - root.tree.children.erase(lower, root.tree.children.end()); - EASY_END_BLOCK; - - ::profiler::timestamp_t children_duration = 0; - if (gather_statistics) - { - EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta); - per_parent_statistics.clear(); - - //per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows - //per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows - // TODO: check this behavior on Linux - - for (auto& child : tree.children) - { - child.per_parent_stats = update_statistics(per_parent_statistics, child); - - children_duration += child.node->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } - } - else - { - for (const auto& child : tree.children) - { - children_duration += child.node->duration(); - if (tree.depth < child.depth) - tree.depth = child.depth; - } - } - - ++tree.depth; - } - } - - root.tree.children.emplace_back(::std::move(tree)); - - - - if (gather_statistics) - { - EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral); - auto& current = root.tree.children.back(); - current.per_thread_stats = update_statistics(per_thread_statistics, current); - } - - if (progress.load() < 0) - break; - progress.store(10 + static_cast(80 * i / memory_size)); } - } - if (progress.load() < 0) + root.children.emplace_back(block_index);// ::std::move(tree)); + + + + if (gather_statistics) + { + EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral); + tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index); + } + + if (progress.load() < 0) + break; + progress.store(10 + static_cast(80 * i / memory_size)); + } + } + + if (progress.load() < 0) + { + serialized_blocks.clear(); + threaded_trees.clear(); + return 0; + } + + EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple); + if (gather_statistics) + { + ::std::vector<::std::thread> statistics_threads; + statistics_threads.reserve(threaded_trees.size()); + + for (auto& it : threaded_trees) { - serialized_blocks.clear(); - threaded_trees.clear(); - return 0; + auto& root = it.second; + root.thread_id = it.first; + //root.tree.shrink_to_fit(); + + auto& per_frame_statistics = frame_statistics[root.thread_id]; + auto& per_parent_statistics = parent_statistics[it.first]; + per_parent_statistics.clear(); + + statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &_blocks](::profiler::BlocksTreeRoot& root) + { + for (auto i : root.children) + { + auto& frame = _blocks[i]; + frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i); + + per_frame_statistics.clear(); + update_statistics_recursive(per_frame_statistics, frame, i, _blocks); + + if (root.depth < frame.depth) + root.depth = frame.depth; + } + + ++root.depth; + }, ::std::ref(root))); } - EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple); - if (gather_statistics) - { - ::std::vector<::std::thread> statistics_threads; - statistics_threads.reserve(threaded_trees.size()); - - for (auto& it : threaded_trees) - { - auto& root = it.second; - root.thread_id = it.first; - root.tree.shrink_to_fit(); - - auto& per_frame_statistics = frame_statistics[root.thread_id]; - auto& per_parent_statistics = parent_statistics[it.first]; - per_parent_statistics.clear(); - - statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics](::profiler::BlocksTreeRoot& root) - { - for (auto& frame : root.tree.children) - { - frame.per_parent_stats = update_statistics(per_parent_statistics, frame); - - per_frame_statistics.clear(); - update_statistics_recursive(per_frame_statistics, frame); - - if (root.tree.depth < frame.depth) - root.tree.depth = frame.depth; - } - - ++root.tree.depth; - }, ::std::ref(root))); - } - - int j = 0, n = static_cast(statistics_threads.size()); - for (auto& t : statistics_threads) - { - t.join(); - progress.store(90 + (10 * ++j) / n); - } - } - else + int j = 0, n = static_cast(statistics_threads.size()); + for (auto& t : statistics_threads) { - int j = 0, n = static_cast(threaded_trees.size()); - for (auto& it : threaded_trees) - { - auto& root = it.second; - root.thread_id = it.first; - - root.tree.shrink_to_fit(); - for (auto& frame : root.tree.children) - { - if (root.tree.depth < frame.depth) - root.tree.depth = frame.depth; - } - - ++root.tree.depth; - - progress.store(90 + (10 * ++j) / n); - } + t.join(); + progress.store(90 + (10 * ++j) / n); } - // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors + } + else + { + int j = 0, n = static_cast(threaded_trees.size()); + for (auto& it : threaded_trees) + { + auto& root = it.second; + root.thread_id = it.first; - return blocks_counter; - } + //root.tree.shrink_to_fit(); + for (auto i : root.children) + { + auto& frame = _blocks[i]; + if (root.depth < frame.depth) + root.depth = frame.depth; + } + + ++root.depth; + + progress.store(90 + (10 * ++j) / n); + } + } + // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors + + return blocks_counter; } From cbcfe4c1847305c253c05cdddcc74b7f8fccaab8 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 30 Aug 2016 23:15:16 +0300 Subject: [PATCH 10/37] (EasyMainWindow) Memory leak issue --- profiler_gui/main_window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 945ab3f..ad4cae6 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -421,6 +421,9 @@ void EasyMainWindow::onFileReaderTimeout() EASY_GLOBALS.profiler_blocks.swap(threads_map); EASY_GLOBALS.descriptors.swap(descriptors); + typedef decltype(EASY_GLOBALS.gui_blocks) gui_blocks_t; + gui_blocks_t().swap(EASY_GLOBALS.gui_blocks); + EASY_GLOBALS.gui_blocks.resize(nblocks); memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); for (decltype(nblocks) i = 0; i < nblocks; ++i) { From d8f44ba5598040b5f8158bbe039351496bb716f1 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 31 Aug 2016 21:51:00 +0300 Subject: [PATCH 11/37] Gcc compile fix --- CMakeLists.txt | 4 ++-- include/profiler/profiler.h | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86c1add..3367ed5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,8 +27,8 @@ include_directories( ) if(UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" ) else() add_definitions( -D_CRT_SECURE_NO_WARNINGS diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 0d94583..85ca848 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -99,7 +99,11 @@ Name of the block automatically created with function name. \ingroup profiler */ -#define EASY_FUNCTION(...) EASY_BLOCK(__func__ , ## __VA_ARGS__) +#define EASY_FUNCTION(...)\ + static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(__func__, __FILE__, __LINE__,\ + ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), "");\ + ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro of completion of last nearest open block. From 88de665df9074a10516fb0a4300d62cc2b8bce4d Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 31 Aug 2016 21:51:22 +0300 Subject: [PATCH 12/37] clang warning fix --- include/profiler/profiler.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 85ca848..fde01ca 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -23,6 +23,11 @@ along with this program.If not, see . #define __func__ __FUNCTION__ #endif +#if defined ( __clang__ ) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#endif + #ifndef FULL_DISABLE_PROFILER #include @@ -329,4 +334,8 @@ namespace profiler { } // END of namespace profiler. +#if defined ( __clang__ ) +#pragma clang diagnostic pop +#endif + #endif // EASY_PROFILER____H_______ From 937f7d8fec84942d0d6101c330fd144ef716f4d4 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 1 Sep 2016 22:22:58 +0300 Subject: [PATCH 13/37] (profiler_core) Correcting: checking built-in "_WIN32" instead of compiler dependant "WIN32" --- include/profiler/profiler.h | 6 +++--- profiler_gui/main.cpp | 2 +- src/block.cpp | 4 ++-- src/profile_manager.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 0d94583..da46d7b 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -19,7 +19,7 @@ along with this program.If not, see . #ifndef EASY_PROFILER____H_______ #define EASY_PROFILER____H_______ -#if defined ( WIN32 ) +#ifdef _WIN32 #define __func__ __FUNCTION__ #endif @@ -157,7 +157,7 @@ If this thread has been already named then nothing changes. \ingroup profiler */ -#ifdef WIN32 +#ifdef _WIN32 #define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #else #define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__); @@ -311,7 +311,7 @@ namespace profiler { block_id_t id() const { return m_id; } }; -#ifndef WIN32 +#ifndef _WIN32 struct PROFILER_API ThreadNameSetter final { ThreadNameSetter(const char* _name, const char* _filename, const char* _funcname, int _line) diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index 8ac8ed1..9d7fcd3 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -6,7 +6,7 @@ #include "main_window.h" #include "profiler/reader.h" -//#ifdef WIN32 +//#ifdef _WIN32 //#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") //#endif diff --git a/src/block.cpp b/src/block.cpp index 7acad7b..2d4e03f 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -6,7 +6,7 @@ using namespace profiler; -#ifdef WIN32 +#ifdef _WIN32 struct ProfPerformanceFrequency { LARGE_INTEGER frequency; ProfPerformanceFrequency() { QueryPerformanceFrequency(&frequency); } @@ -15,7 +15,7 @@ struct ProfPerformanceFrequency { inline timestamp_t getCurrentTime() { -#ifdef WIN32 +#ifdef _WIN32 //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx LARGE_INTEGER elapsedMicroseconds; if (!QueryPerformanceCounter(&elapsedMicroseconds)) diff --git a/src/profile_manager.h b/src/profile_manager.h index df72031..6576a6e 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -32,7 +32,7 @@ along with this program.If not, see . ////////////////////////////////////////////////////////////////////////// -#ifdef WIN32 +#ifdef _WIN32 #include #else #include @@ -40,7 +40,7 @@ along with this program.If not, see . inline uint32_t getCurrentThreadId() { -#ifdef WIN32 +#ifdef _WIN32 return (uint32_t)::GetCurrentThreadId(); #else thread_local static uint32_t _id = (uint32_t)std::hash()(std::this_thread::get_id()); From b90e13509e0f1c5f75356a746349e748d228fe16 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 1 Sep 2016 22:24:13 +0300 Subject: [PATCH 14/37] small refactoring --- include/profiler/reader.h | 2 +- profiler_gui/main_window.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/profiler/reader.h b/include/profiler/reader.h index c46acbd..f388090 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -66,7 +66,7 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// - class BlocksTree + class BlocksTree final { typedef BlocksTree This; diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index ad4cae6..9abe5cc 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -421,9 +421,7 @@ void EasyMainWindow::onFileReaderTimeout() EASY_GLOBALS.profiler_blocks.swap(threads_map); EASY_GLOBALS.descriptors.swap(descriptors); - typedef decltype(EASY_GLOBALS.gui_blocks) gui_blocks_t; - gui_blocks_t().swap(EASY_GLOBALS.gui_blocks); - + EASY_GLOBALS.gui_blocks.clear(); EASY_GLOBALS.gui_blocks.resize(nblocks); memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); for (decltype(nblocks) i = 0; i < nblocks; ++i) { From 7086592e6b23f81a33bfea0f58c14cf37499cd68 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 1 Sep 2016 22:24:42 +0300 Subject: [PATCH 15/37] (profiler_gui) Typo fixed! --- profiler_gui/common_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index fa07d8b..9c7c134 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -140,7 +140,7 @@ struct EasyBlock final EasyBlock() = default; EasyBlock(EasyBlock&& that) - : tree(::std::move(tree)) + : tree(::std::move(that.tree)) , tree_item(that.tree_item) , graphics_item_index(that.graphics_item_index) , graphics_item_level(that.graphics_item_level) From 05b56dcec01b304bb938f2dfe4093527edef2891 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 4 Sep 2016 14:48:35 +0300 Subject: [PATCH 16/37] First debuggable version of system event tracing for visualizing thread context switches --- include/profiler/event_trace_status.h | 27 ++++ include/profiler/profiler.h | 23 +-- include/profiler/reader.h | 18 ++- profiler_gui/blocks_graphics_view.cpp | 104 +++++++++++--- profiler_gui/blocks_graphics_view.h | 24 ++-- src/CMakeLists.txt | 3 + src/block.cpp | 30 ++-- src/event_trace_win.cpp | 197 ++++++++++++++++++++++++++ src/event_trace_win.h | 66 +++++++++ src/profile_manager.cpp | 172 ++++++++++++++++++---- src/profile_manager.h | 44 ++++-- src/reader.cpp | 112 +++++++++++++-- 12 files changed, 717 insertions(+), 103 deletions(-) create mode 100644 include/profiler/event_trace_status.h create mode 100644 src/event_trace_win.cpp create mode 100644 src/event_trace_win.h diff --git a/include/profiler/event_trace_status.h b/include/profiler/event_trace_status.h new file mode 100644 index 0000000..4a9f42d --- /dev/null +++ b/include/profiler/event_trace_status.h @@ -0,0 +1,27 @@ + + + +#ifndef EASY_PROFILER__EVENT_TRACE_STATUS__H_ +#define EASY_PROFILER__EVENT_TRACE_STATUS__H_ + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + enum EventTracingEnableStatus : unsigned char + { + EVENT_TRACING_LAUNCHED_SUCCESSFULLY = 0, + EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS, + EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE, + EVENT_TRACING_BAD_PROPERTIES_SIZE, + EVENT_TRACING_OPEN_TRACE_ERROR, + EVENT_TRACING_MISTERIOUS_ERROR, + }; + +} // END of namespace profiler. + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +#endif // EASY_PROFILER__EVENT_TRACE_STATUS__H_ diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 69e6e10..416e613 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -42,7 +42,7 @@ along with this program.If not, see . */ namespace profiler { - template struct NameSwitch final { + template struct NameSwitch final { static const char* runtime_name(const char* name) { return name; } static const char* compiletime_name(const char*) { return ""; } }; @@ -217,7 +217,7 @@ namespace profiler { void PROFILER_API beginBlock(Block& _block); void PROFILER_API endBlock(); void PROFILER_API setEnabled(bool isEnable); - unsigned int PROFILER_API dumpBlocksToFile(const char* filename); + uint32_t PROFILER_API dumpBlocksToFile(const char* filename); void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); } @@ -228,8 +228,8 @@ namespace profiler { enum BlockType : uint8_t { BLOCK_TYPE_EVENT = 0, - BLOCK_TYPE_BLOCK, BLOCK_TYPE_THREAD_SIGN, + BLOCK_TYPE_BLOCK, BLOCK_TYPE_CONTEXT_SWITCH, BLOCK_TYPES_NUMBER @@ -264,12 +264,14 @@ namespace profiler { 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; } + inline const char* name() const { return m_name; } + inline const char* file() const { return m_filename; } }; class PROFILER_API BaseBlockData { + friend ::ProfileManager; + protected: timestamp_t m_begin; @@ -283,9 +285,9 @@ namespace profiler { 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; } + inline timestamp_t duration() const { return m_end - m_begin; } - void setId(block_id_t _id) { m_id = _id; } + inline void setId(block_id_t _id) { m_id = _id; } }; #pragma pack(pop) @@ -298,11 +300,14 @@ namespace profiler { private: void finish(); + void finish(timestamp_t _end_time); inline bool isFinished() const { return m_end >= m_begin; } public: - Block(block_type_t _block_type, block_id_t _id, const char* _name = ""); + Block(Block&& that); + Block(block_type_t _block_type, block_id_t _id, const char* _name); + Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _id, const char* _name); ~Block(); inline const char* name() const { return m_name; } @@ -317,7 +322,7 @@ namespace profiler { public: StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); - block_id_t id() const { return m_id; } + inline block_id_t id() const { return m_id; } }; #ifndef _WIN32 diff --git a/include/profiler/reader.h b/include/profiler/reader.h index f388090..3bf0e9e 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -167,6 +167,9 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// +#define EASY_STORE_CSWITCH_SEPARATELY +//#undef EASY_STORE_CSWITCH_SEPARATELY + class BlocksTreeRoot final { typedef BlocksTreeRoot This; @@ -174,6 +177,9 @@ namespace profiler { public: BlocksTree::children_t children; +#ifdef EASY_STORE_CSWITCH_SEPARATELY + BlocksTree::children_t sync; +#endif const char* thread_name; ::profiler::thread_id_t thread_id; uint16_t depth; @@ -182,13 +188,23 @@ namespace profiler { { } - BlocksTreeRoot(This&& that) : children(::std::move(that.children)), thread_name(that.thread_name), thread_id(that.thread_id), depth(that.depth) + BlocksTreeRoot(This&& that) + : children(::std::move(that.children)) +#ifdef EASY_STORE_CSWITCH_SEPARATELY + , sync(::std::move(that.sync)) +#endif + , thread_name(that.thread_name) + , thread_id(that.thread_id) + , depth(that.depth) { } This& operator = (This&& that) { children = ::std::move(that.children); +#ifdef EASY_STORE_CSWITCH_SEPARATELY + sync = ::std::move(that.sync); +#endif thread_name = that.thread_name; thread_id = that.thread_id; depth = that.depth; diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 14f8808..0f31c47 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -76,7 +76,7 @@ const unsigned int TEST_PROGRESSION_BASE = 4; const int FLICKER_INTERVAL = 16; // 60Hz const auto CHRONOMETER_FONT = QFont("CourierNew", 16, 2); -const auto ITEMS_FONT = QFont("CourierNew", 10);// , 2); +const auto ITEMS_FONT = QFont("CourierNew", 9);// , 2); ////////////////////////////////////////////////////////////////////////// @@ -95,7 +95,7 @@ inline T logn(T _value) ////////////////////////////////////////////////////////////////////////// -EasyGraphicsItem::EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root) +EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root) : QGraphicsItem(nullptr) , m_pRoot(_root) , m_index(_index) @@ -148,7 +148,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Reset indices of first visible item for each layer const auto levelsNumber = levels(); - for (unsigned char i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]); + for (uint8_t i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]); // Search for first visible top-level item @@ -170,6 +170,24 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } +#ifdef EASY_STORE_CSWITCH_SEPARATELY + auto firstSync = ::std::lower_bound(m_pRoot->sync.begin(), m_pRoot->sync.end(), sceneLeft, [&sceneView](::profiler::block_index_t _index, qreal _value) + { + return sceneView->time2position(easyBlock(_index).tree.node->begin()) < _value; + }); + + if (firstSync != m_pRoot->sync.end()) + { + if (firstSync != m_pRoot->sync.begin()) + --firstSync; + } + else if (!m_pRoot->sync.empty()) + { + firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1; + } + firstSync = m_pRoot->sync.begin(); +#endif + // This is to make _painter->drawText() work properly // (it seems there is a bug in Qt5.6 when drawText called for big coordinates, @@ -206,7 +224,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Iterate through layers and draw visible items bool selectedItemsWasPainted = false; const auto visibleBottom = visibleSceneRect.bottom() - 1; - for (unsigned char l = 0; l < levelsNumber; ++l) + for (uint8_t l = 0; l < levelsNumber; ++l) { auto& level = m_levels[l]; const short next_level = l + 1; @@ -492,6 +510,46 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } } + +#ifdef EASY_STORE_CSWITCH_SEPARATELY + if (!m_pRoot->sync.empty()) + { + _painter->setBrush(Qt::NoBrush); + QPen pen(QColor::fromRgba(0x40f08040)); + pen.setWidth(3); + _painter->setPen(pen); + + qreal prevRight = -1e100, top = y() - 1; + for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it) + { + const auto& item = easyBlock(*it).tree; + auto begin = sceneView->time2position(item.node->begin()); + + if (begin > sceneRight) + break; // This is first totally invisible item. No need to check other items. + + decltype(begin) width = item.node->duration(); + auto r = begin + width; +// if (r < sceneLeft) // This item is not visible +// continue; + + begin *= currentScale; + begin -= dx; + width *= currentScale; +// r = begin + width; +// if (r <= prevRight) // This item is not visible +// continue; + + if (width < 1) + width = 1; + + _painter->drawLine(QLineF(begin, top, begin + width, top)); + prevRight = begin + width; + } + } +#endif + + _painter->restore(); } @@ -696,17 +754,17 @@ void EasyGraphicsItem::setBoundingRect(const QRectF& _rect) ////////////////////////////////////////////////////////////////////////// -unsigned char EasyGraphicsItem::levels() const +uint8_t EasyGraphicsItem::levels() const { - return static_cast(m_levels.size()); + return static_cast(m_levels.size()); } -float EasyGraphicsItem::levelY(unsigned char _level) const +float EasyGraphicsItem::levelY(uint8_t _level) const { return y() + static_cast(_level) * static_cast(GRAPHICS_ROW_SIZE_FULL); } -void EasyGraphicsItem::setLevels(unsigned char _levels) +void EasyGraphicsItem::setLevels(uint8_t _levels) { typedef decltype(m_levelsIndexes) IndexesT; static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); @@ -715,29 +773,29 @@ void EasyGraphicsItem::setLevels(unsigned char _levels) m_levelsIndexes.resize(_levels, MAX_CHILD_INDEX); } -void EasyGraphicsItem::reserve(unsigned char _level, unsigned int _items) +void EasyGraphicsItem::reserve(uint8_t _level, unsigned int _items) { m_levels[_level].reserve(_items); } ////////////////////////////////////////////////////////////////////////// -const EasyGraphicsItem::Children& EasyGraphicsItem::items(unsigned char _level) const +const EasyGraphicsItem::Children& EasyGraphicsItem::items(uint8_t _level) const { return m_levels[_level]; } -const ::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const +const ::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index) const { return m_levels[_level][_index]; } -::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) +::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index) { return m_levels[_level][_index]; } -unsigned int EasyGraphicsItem::addItem(unsigned char _level) +unsigned int EasyGraphicsItem::addItem(uint8_t _level) { m_levels[_level].emplace_back(); return static_cast(m_levels[_level].size() - 1); @@ -1194,7 +1252,7 @@ EasyChronometerItem* EasyGraphicsView::createChronometer(bool _main) } } -void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows) +void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, uint8_t _rows) { static const qreal X_BEGIN = 50; static const qreal Y_BEGIN = 0; @@ -1202,9 +1260,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite clearSilent(); // Clear scene // Calculate items number for first level - _rows = ::std::max((unsigned char)1, _rows); + _rows = ::std::max((uint8_t)1, _rows); const auto children_per_frame = static_cast(0.5 + static_cast(_total_items_number_estimate) / static_cast(_rows * _frames_number)); - const unsigned char max_depth = ::std::min(254, static_cast(logn(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1))); + const uint8_t max_depth = ::std::min(254, static_cast(logn(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1))); const auto first_level_children_count = static_cast(static_cast(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5); @@ -1213,7 +1271,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite ::std::vector thread_items(_rows); - for (unsigned char i = 0; i < _rows; ++i) + for (uint8_t i = 0; i < _rows; ++i) { auto item = new EasyGraphicsItem(i, true); thread_items[i] = item; @@ -1226,9 +1284,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite // Calculate items number for each sublevel auto chldrn = first_level_children_count; - for (unsigned char i = 1; i <= max_depth; ++i) + for (uint8_t i = 1; i <= max_depth; ++i) { - for (unsigned char j = 0; j < _rows; ++j) + for (uint8_t j = 0; j < _rows; ++j) { auto item = thread_items[j]; item->reserve(i, chldrn * _frames_number); @@ -1241,7 +1299,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite unsigned int total_items = 0; qreal maxX = 0; const EasyGraphicsItem* longestItem = nullptr; - for (unsigned char i = 0; i < _rows; ++i) + for (uint8_t i = 0; i < _rows; ++i) { auto item = thread_items[i]; qreal x = X_BEGIN, y = item->y(); @@ -1395,7 +1453,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // fill scene with new items const auto& tree = threadTree.second.children; qreal h = 0, x = time2position(blocksTree(tree.front()).node->begin()); - auto item = new EasyGraphicsItem(static_cast(m_items.size()), &threadTree.second); + auto item = new EasyGraphicsItem(static_cast(m_items.size()), &threadTree.second); item->setLevels(threadTree.second.depth); item->setPos(0, y); @@ -1461,7 +1519,7 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block return 0; } - const auto level = static_cast(_level); + const auto level = static_cast(_level); _item->reserve(level, static_cast(_children.size())); const short next_level = _level + 1; @@ -1502,7 +1560,7 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block if (next_level < 256 && next_level < _item->levels() && !child.children.empty()) { - b.children_begin = static_cast(_item->items(static_cast(next_level)).size()); + b.children_begin = static_cast(_item->items(static_cast(next_level)).size()); } else { diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index e0ceb31..7d74eb8 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -67,11 +67,11 @@ class EasyGraphicsItem : public QGraphicsItem QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy. - unsigned char m_index; ///< This item's index in the list of items of EasyGraphicsView + uint8_t m_index; ///< This item's index in the list of items of EasyGraphicsView public: - EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root); + EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root); virtual ~EasyGraphicsItem(); // Public virtual methods @@ -92,46 +92,46 @@ public: ::profiler::thread_id_t threadId() const; ///< Returns number of levels - unsigned char levels() const; + uint8_t levels() const; - float levelY(unsigned char _level) const; + float levelY(uint8_t _level) const; /** \brief Sets number of levels. \note Must be set before doing anything else. \param _levels Desired number of levels */ - void setLevels(unsigned char _levels); + void setLevels(uint8_t _levels); /** \brief Reserves memory for desired number of items on specified level. \param _level Index of the level \param _items Desired number of items on this level */ - void reserve(unsigned char _level, unsigned int _items); + void reserve(uint8_t _level, unsigned int _items); /**\brief Returns reference to the array of items of specified level. \param _level Index of the level */ - const Children& items(unsigned char _level) const; + const Children& items(uint8_t _level) const; /**\brief Returns reference to the item with required index on specified level. \param _level Index of the level \param _index Index of required item */ - const ::profiler_gui::EasyBlockItem& getItem(unsigned char _level, unsigned int _index) const; + const ::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index) const; /**\brief Returns reference to the item with required index on specified level. \param _level Index of the level \param _index Index of required item */ - ::profiler_gui::EasyBlockItem& getItem(unsigned char _level, unsigned int _index); + ::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index); /** \brief Adds new item to required level. \param _level Index of the level \retval Index of the new created item */ - unsigned int addItem(unsigned char _level); + unsigned int addItem(uint8_t _level); /** \brief Finds top-level blocks which are intersects with required selection zone. @@ -154,7 +154,7 @@ public: // Public inline methods ///< Returns this item's index in the list of graphics items of EasyGraphicsView - inline unsigned char index() const + inline uint8_t index() const { return m_index; } @@ -363,7 +363,7 @@ public: return m_timelineStep; } -private: +//private: // Private inline methods diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11ec401..3eaa04f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,13 +4,16 @@ set(CPP_FILES block.cpp profile_manager.cpp reader.cpp + event_trace_win.cpp ) set(H_FILES ${ROOT}/include/profiler/profiler.h ${ROOT}/include/profiler/reader.h + ${ROOT}/include/profiler/event_trace_status.h profile_manager.h spin_lock.h + event_trace_win.h ) set(SOURCES diff --git a/src/block.cpp b/src/block.cpp index 2d4e03f..5193b94 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -7,10 +7,7 @@ using namespace profiler; #ifdef _WIN32 -struct ProfPerformanceFrequency { - LARGE_INTEGER frequency; - ProfPerformanceFrequency() { QueryPerformanceFrequency(&frequency); } -} const WINDOWS_CPU_INFO; +decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })(); #endif inline timestamp_t getCurrentTime() @@ -20,8 +17,8 @@ inline timestamp_t getCurrentTime() LARGE_INTEGER elapsedMicroseconds; if (!QueryPerformanceCounter(&elapsedMicroseconds)) return 0; - elapsedMicroseconds.QuadPart *= 1000000000LL; - elapsedMicroseconds.QuadPart /= WINDOWS_CPU_INFO.frequency.QuadPart; + //elapsedMicroseconds.QuadPart *= 1000000000LL; + //elapsedMicroseconds.QuadPart /= CPU_FREQUENCY; return (timestamp_t)elapsedMicroseconds.QuadPart; #else std::chrono::time_point time_point; @@ -38,11 +35,23 @@ BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) } +Block::Block(Block&& that) + : BaseBlockData(that.m_begin, that.m_id) + , m_name(that.m_name) +{ + m_end = that.m_end; +} + Block::Block(block_type_t _block_type, block_id_t _descriptor_id, const char* _name) - : BaseBlockData(getCurrentTime(), _descriptor_id) + : Block(getCurrentTime(), _block_type, _descriptor_id, _name) +{ +} + +Block::Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _descriptor_id, const char* _name) + : BaseBlockData(_begin_time, _descriptor_id) , m_name(_name) { - if (_block_type != BLOCK_TYPE_BLOCK) + if (static_cast(_block_type) < BLOCK_TYPE_BLOCK) { m_end = m_begin; } @@ -53,6 +62,11 @@ void Block::finish() m_end = getCurrentTime(); } +void Block::finish(timestamp_t _end_time) +{ + m_end = _end_time; +} + Block::~Block() { if (!isFinished()) diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp new file mode 100644 index 0000000..ad40b97 --- /dev/null +++ b/src/event_trace_win.cpp @@ -0,0 +1,197 @@ + + +#ifdef _WIN32 +#include +#include +#include +#include "event_trace_win.h" +#include "profiler/profiler.h" +#include "profile_manager.h" + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; +//extern ProfileManager& MANAGER; +#define MANAGER ProfileManager::instance() + +namespace profiler { + + struct CSwitch final + { + uint32_t NewThreadId; + uint32_t OldThreadId; + int8_t NewThreadPriority; + int8_t OldThreadPriority; + uint8_t PreviousCState; + int8_t SpareByte; + int8_t OldThreadWaitReason; + int8_t OldThreadWaitMode; + int8_t OldThreadState; + int8_t OldThreadWaitIdealProcessor; + uint32_t NewThreadWaitTime; + uint32_t Reserved; + }; + + void WINAPI processTraceEvent(PEVENT_RECORD _traceEvent) + { + //static ::std::ofstream outputFile("csw.csv", ::std::fstream::app); + + static const decltype(_traceEvent->EventHeader.EventDescriptor.Opcode) SWITCH_CONTEXT_OPCODE = 36; + if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE) + return; + + if (sizeof(CSwitch) != _traceEvent->UserDataLength) + return; + + auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); + + auto timestampValue = _traceEvent->EventHeader.TimeStamp.QuadPart; + + //LARGE_INTEGER currtime; + //if (QueryPerformanceCounter(&currtime)) + // timestampValue = currtime.QuadPart; + + //timestampValue *= 1000000000LL; + //timestampValue /= CPU_FREQUENCY; + const auto time = (::profiler::timestamp_t)timestampValue; + + static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + + //if (_contextSwitchEvent->OldThreadId != 0) + MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); + + //if (_contextSwitchEvent->NewThreadId != 0) + MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); + + //static const auto firstTime = time; + //outputFile << _contextSwitchEvent->OldThreadId << "\t" << _contextSwitchEvent->NewThreadId << "\t" << (((time - firstTime) * 1000000000LL) / CPU_FREQUENCY) << ::std::endl; + //outputFile << _contextSwitchEvent->OldThreadId << "\t" << _contextSwitchEvent->NewThreadId << "\t" << time << ::std::endl; + } + + ////////////////////////////////////////////////////////////////////////// + + EasyEventTracer& EasyEventTracer::instance() + { + static EasyEventTracer tracer; + return tracer; + } + + EasyEventTracer::EasyEventTracer() + { + } + + EasyEventTracer::~EasyEventTracer() + { + disable(); + } + + ::profiler::EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step) + { + auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props()); + switch (startTraceResult) + { + case ERROR_SUCCESS: + return EVENT_TRACING_LAUNCHED_SUCCESSFULLY; + + case ERROR_ALREADY_EXISTS: + { + if (_force) + { + // Try to stop another event tracing session to force launch self session. + + if ((_step == 0 && 32 < (int)ShellExecute(NULL, NULL, "logman", "stop \"" KERNEL_LOGGER_NAME "\" -ets", NULL, SW_HIDE)) || (_step > 0 && _step < 6)) + { + // Command executed successfully. Wait for a few time until tracing session finish. + ::std::this_thread::sleep_for(::std::chrono::milliseconds(500)); + return startTrace(true, ++_step); + } + } + + return EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE; + } + + case ERROR_ACCESS_DENIED: + return EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS; + + case ERROR_BAD_LENGTH: + return EVENT_TRACING_BAD_PROPERTIES_SIZE; + } + + return EVENT_TRACING_MISTERIOUS_ERROR; + } + + ::profiler::EventTracingEnableStatus EasyEventTracer::enable(bool _force) + { + static const decltype(m_properties.base.Wnode.ClientContext) RAW_TIMESTAMP_TIME_TYPE = 1; + + if (m_bEnabled) + return EVENT_TRACING_LAUNCHED_SUCCESSFULLY; + + // Clear properties + memset(&m_properties, 0, sizeof(m_properties)); + m_properties.base.Wnode.BufferSize = sizeof(m_properties); + m_properties.base.Wnode.Flags = WNODE_FLAG_TRACED_GUID; + m_properties.base.Wnode.ClientContext = RAW_TIMESTAMP_TIME_TYPE; + m_properties.base.Wnode.Guid = SystemTraceControlGuid; + m_properties.base.LoggerNameOffset = sizeof(m_properties.base); + m_properties.base.EnableFlags = EVENT_TRACE_FLAG_CSWITCH; + m_properties.base.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + + auto res = startTrace(_force); + if (res != EVENT_TRACING_LAUNCHED_SUCCESSFULLY) + return res; + + memset(&m_trace, 0, sizeof(m_trace)); + m_trace.LoggerName = KERNEL_LOGGER_NAME; + m_trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP; + m_trace.EventRecordCallback = ::profiler::processTraceEvent; + + m_openedHandle = OpenTrace(&m_trace); + if (m_openedHandle == INVALID_PROCESSTRACE_HANDLE) + return EVENT_TRACING_OPEN_TRACE_ERROR; + + // Have to launch a thread to process events because according to MSDN documentation: + // + // The ProcessTrace function blocks the thread until it delivers all events, the BufferCallback function returns FALSE, + // or you call CloseTrace. If the consumer is consuming events in real time, the ProcessTrace function returns after + // the controller stops the trace session. (Note that there may be a several-second delay before the function returns.) + // + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx + m_stubThread = ::std::move(::std::thread([this]() + { +// EASY_THREAD("ProcessTrace"); +// EASY_BLOCK("ProcessTrace", ::profiler::colors::Red); + ProcessTrace(&m_openedHandle, 1, 0, 0); + })); + + m_bEnabled = true; + + return EVENT_TRACING_LAUNCHED_SUCCESSFULLY; + } + + void EasyEventTracer::disable() + { + if (!m_bEnabled) + return; + + auto controlTraceResult = ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP); + + // ERROR_CTX_CLOSE_PENDING(7007L): The call was successful. The ProcessTrace function will stop after it has processed all real-time events in its buffers (it will not receive any new events). + // ERROR_BUSY(170L): Prior to Windows Vista, you cannot close the trace until the ProcessTrace function completes. + // ERROR_INVALID_HANDLE(6L): One of the following is true: TraceHandle is NULL. TraceHandle is INVALID_HANDLE_VALUE. + auto closeTraceStatus = CloseTrace(m_openedHandle); + + // Wait for ProcessThread to finish + if (m_stubThread.joinable()) + m_stubThread.join(); + + m_bEnabled = false; + } + +} // END of namespace profiler. + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +#endif // _WIN32 diff --git a/src/event_trace_win.h b/src/event_trace_win.h new file mode 100644 index 0000000..a8aa11a --- /dev/null +++ b/src/event_trace_win.h @@ -0,0 +1,66 @@ + + + +#ifndef EASY_PROFILER__EVENT_TRACE_WINDOWS__H_ +#define EASY_PROFILER__EVENT_TRACE_WINDOWS__H_ +#ifdef _WIN32 + +#define INITGUID // This is to enable using SystemTraceControlGuid in evntrace.h. +#include +//#include +#include +#include +#include +#include +#include "profiler/event_trace_status.h" + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + class EasyEventTracer final + { + +#pragma pack(push, 1) + struct Properties final { + EVENT_TRACE_PROPERTIES base; + char sessionName[sizeof(KERNEL_LOGGER_NAME)]; + }; +#pragma pack(pop) + + ::std::thread m_stubThread; + Properties m_properties; + EVENT_TRACE_LOGFILE m_trace; + TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE; + TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE; + bool m_bEnabled = false; + + public: + + static EasyEventTracer& instance(); + ~EasyEventTracer(); + + ::profiler::EventTracingEnableStatus enable(bool _force = false); + void disable(); + + private: + + EasyEventTracer(); + + inline EVENT_TRACE_PROPERTIES* props() + { + return reinterpret_cast(&m_properties); + } + + ::profiler::EventTracingEnableStatus startTrace(bool _force, int _step = 0); + + }; // END of class EasyEventTracer. + +} // END of namespace profiler. + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +#endif // _WIN32 +#endif // EASY_PROFILER__EVENT_TRACE_WINDOWS__H_ diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index ffce286..e4e0a46 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -1,5 +1,6 @@ #include "profile_manager.h" #include "profiler/serialized_block.h" +#include "event_trace_win.h" #include #include @@ -8,7 +9,12 @@ using namespace profiler; -auto& MANAGER = ProfileManager::instance(); +#ifdef _WIN32 +extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; +#endif + +//auto& MANAGER = ProfileManager::instance(); +#define MANAGER ProfileManager::instance() extern "C"{ @@ -20,13 +26,18 @@ extern "C"{ void PROFILER_API setEnabled(bool isEnable) { MANAGER.setEnabled(isEnable); + if (isEnable) + EasyEventTracer::instance().enable(true); + else + EasyEventTracer::instance().disable(); } + void PROFILER_API beginBlock(Block& _block) { MANAGER.beginBlock(_block); } - unsigned int PROFILER_API dumpBlocksToFile(const char* filename) + uint32_t PROFILER_API dumpBlocksToFile(const char* filename) { return MANAGER.dumpBlocksToFile(filename); } @@ -35,6 +46,7 @@ extern "C"{ { return MANAGER.setThreadName(name, filename, _funcname, line); } + } SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) @@ -71,28 +83,53 @@ BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const c ////////////////////////////////////////////////////////////////////////// -void ThreadStorage::store(const profiler::Block& block) +void ThreadStorage::storeBlock(const profiler::Block& block) { auto name_length = static_cast(strlen(block.name())); auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); - auto data = m_allocator.allocate(size); + auto data = blocks.alloc.allocate(size); ::new (static_cast(data)) SerializedBlock(block, name_length); - usedMemorySize += size; - closedList.emplace_back(reinterpret_cast(data)); + blocks.usedMemorySize += size; + blocks.closedList.emplace_back(reinterpret_cast(data)); +} + +void ThreadStorage::storeCSwitch(const profiler::Block& block) +{ + auto name_length = static_cast(strlen(block.name())); + auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); + auto data = sync.alloc.allocate(size); + ::new (static_cast(data)) SerializedBlock(block, name_length); + sync.usedMemorySize += size; + sync.closedList.emplace_back(reinterpret_cast(data)); } void ThreadStorage::clearClosed() { - serialized_list_t().swap(closedList); - m_allocator.clear(); - usedMemorySize = 0; + blocks.clearClosed(); + sync.clearClosed(); } ////////////////////////////////////////////////////////////////////////// +// #ifdef _WIN32 +// LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL; +// LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) +// { +// std::ofstream testexp("TEST_EXP.txt", std::fstream::binary); +// testexp.write("APPLICATION CRASHED!", strlen("APPLICATION CRASHED!")); +// +// EasyEventTracer::instance().disable(); +// if (PREVIOUS_FILTER) +// return PREVIOUS_FILTER(ExceptionInfo); +// return EXCEPTION_CONTINUE_SEARCH; +// } +// #endif + ProfileManager::ProfileManager() { - +// #ifdef _WIN32 +// PREVIOUS_FILTER = SetUnhandledExceptionFilter(easyTopLevelExceptionFilter); +// #endif } ProfileManager::~ProfileManager() @@ -116,9 +153,16 @@ void ProfileManager::beginBlock(Block& _block) auto& thread_storage = threadStorage(getCurrentThreadId()); if (!_block.isFinished()) - thread_storage.openedList.emplace(_block); + thread_storage.blocks.openedList.emplace(_block); else - thread_storage.store(_block); + thread_storage.storeBlock(_block); +} + +void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +{ + auto thread_storage = _threadStorage(_thread_id); + if (thread_storage != nullptr) + thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } void ProfileManager::endBlock() @@ -127,15 +171,28 @@ void ProfileManager::endBlock() return; auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.openedList.empty()) + if (thread_storage.blocks.openedList.empty()) return; - Block& lastBlock = thread_storage.openedList.top(); + Block& lastBlock = thread_storage.blocks.openedList.top(); if (!lastBlock.isFinished()) lastBlock.finish(); - thread_storage.store(lastBlock); - thread_storage.openedList.pop(); + thread_storage.storeBlock(lastBlock); + thread_storage.blocks.openedList.pop(); +} + +void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) +{ + auto thread_storage = _threadStorage(_thread_id); + if (thread_storage == nullptr || thread_storage->sync.openedList.empty()) + return; + + Block& lastBlock = thread_storage->sync.openedList.top(); + lastBlock.finish(_endtime); + + thread_storage->storeCSwitch(lastBlock); + thread_storage->sync.openedList.pop(); } void ProfileManager::setEnabled(bool isEnable) @@ -160,22 +217,42 @@ public: template void write(const T& _data) { m_file.write((const char*)&_data, sizeof(T)); } + + void writeBlock(const profiler::SerializedBlock* _block) + { + auto sz = static_cast(sizeof(BaseBlockData) + strlen(_block->name()) + 1); + write(sz); + write(_block->data(), sz); + } }; ////////////////////////////////////////////////////////////////////////// +#define STORE_CSWITCHES_SEPARATELY + uint32_t ProfileManager::dumpBlocksToFile(const char* filename) { + const bool wasEnabled = m_isEnabled; + if (wasEnabled) + ::profiler::setEnabled(false); + FileWriter of(filename); uint64_t usedMemorySize = 0; uint32_t blocks_number = 0; for (const auto& thread_storage : m_threads) { - usedMemorySize += thread_storage.second.usedMemorySize; - blocks_number += static_cast(thread_storage.second.closedList.size()); + const auto& t = thread_storage.second; + usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize; + blocks_number += static_cast(t.blocks.closedList.size()) + static_cast(t.sync.closedList.size()); } +#ifdef _WIN32 + of.write(CPU_FREQUENCY); +#else + of.write(0LL); +#endif + of.write(blocks_number); of.write(usedMemorySize); of.write(static_cast(m_descriptors.size())); @@ -194,21 +271,64 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) of.write(descriptor.file(), filename_size); } + //::std::ofstream outputFile("csw2.csv", ::std::fstream::app); + for (auto& thread_storage : m_threads) { - of.write(thread_storage.first); - of.write(static_cast(thread_storage.second.closedList.size())); + auto& t = thread_storage.second; - for (auto b : thread_storage.second.closedList) + //outputFile << thread_storage.first << std::endl; + + of.write(thread_storage.first); +#ifdef STORE_CSWITCHES_SEPARATELY + of.write(static_cast(t.blocks.closedList.size())); +#else + of.write(static_cast(t.blocks.closedList.size()) + static_cast(t.sync.closedList.size())); + uint32_t i = 0; +#endif + + for (auto b : t.blocks.closedList) { - auto sz = static_cast(sizeof(BaseBlockData) + strlen(b->name()) + 1); - of.write(sz); - of.write(b->data(), sz); +#ifndef STORE_CSWITCHES_SEPARATELY + if (i < t.sync.closedList.size()) + { + auto s = t.sync.closedList[i]; + if (s->end() <= b->end())// || s->begin() >= b->begin()) + //if (((s->end() <= b->end() && s->end() >= b->begin()) || (s->begin() >= b->begin() && s->begin() <= b->end()))) + { + if (s->m_begin < b->m_begin) + s->m_begin = b->m_begin; + if (s->m_end > b->m_end) + s->m_end = b->m_end; + of.writeBlock(s); + ++i; + } + } +#endif + + of.writeBlock(b); } - thread_storage.second.clearClosed(); +#ifdef STORE_CSWITCHES_SEPARATELY + of.write(static_cast(t.sync.closedList.size())); + for (auto b : t.sync.closedList) + { +#else + for (; i < t.sync.closedList.size(); ++i) + { + auto b = t.sync.closedList[i]; +#endif + //outputFile << b->begin() << "\t" << b->end() << std::endl; + + of.writeBlock(b); + } + + t.clearClosed(); } +// if (wasEnabled) +// ::profiler::setEnabled(true); + return blocks_number; } @@ -219,7 +339,7 @@ void ProfileManager::setThreadName(const char* name, const char* filename, const return; const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); - thread_storage.store(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); + thread_storage.storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); thread_storage.named = true; } diff --git a/src/profile_manager.h b/src/profile_manager.h index 6576a6e..311ef19 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -52,7 +52,7 @@ namespace profiler { class SerializedBlock; } ////////////////////////////////////////////////////////////////////////// -template +template class chunk_allocator final { struct chunk { T data[N]; }; @@ -91,27 +91,41 @@ public: ////////////////////////////////////////////////////////////////////////// -class ThreadStorage +class ThreadStorage final { - typedef std::stack > stack_of_blocks_t; typedef std::vector serialized_list_t; - chunk_allocator m_allocator; + template + struct BlocksList final + { + typedef std::stack stack_of_blocks_t; + + chunk_allocator alloc; + stack_of_blocks_t openedList; + serialized_list_t closedList; + uint64_t usedMemorySize = 0; + + void clearClosed() { + serialized_list_t().swap(closedList); + alloc.clear(); + usedMemorySize = 0; + } + }; public: - stack_of_blocks_t openedList; - serialized_list_t closedList; - uint64_t usedMemorySize = 0; - bool named = false; + BlocksList, 1024> blocks; + BlocksList sync; + bool named = false; - void store(const profiler::Block& _block); + void storeBlock(const profiler::Block& _block); + void storeCSwitch(const profiler::Block& _block); void clearClosed(); }; ////////////////////////////////////////////////////////////////////////// -class ProfileManager +class ProfileManager final { friend profiler::StaticBlockDescriptor; @@ -141,6 +155,9 @@ public: uint32_t dumpBlocksToFile(const char* filename); void setThreadName(const char* name, const char* filename, const char* _funcname, int line); + void _cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); + void _cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); + private: template @@ -157,6 +174,13 @@ private: guard_lock_t lock(m_spin); return m_threads[_thread_id]; } + + ThreadStorage* _threadStorage(profiler::thread_id_t _thread_id) + { + guard_lock_t lock(m_spin); + auto it = m_threads.find(_thread_id); + return it != m_threads.end() ? &it->second : nullptr; + } }; #endif diff --git a/src/reader.cpp b/src/reader.cpp index d3ba142..3d05b01 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1,6 +1,6 @@ /************************************************************************ * file name : reader.cpp -* ----------------- : +* ----------------- : * creation time : 2016/06/19 * copyright : (c) 2016 Sergey Yagovtsev, Victor Zarubkin * authors : Sergey Yagovtsev, Victor Zarubkin @@ -254,7 +254,7 @@ void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _ ////////////////////////////////////////////////////////////////////////// -extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) +extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) { EASY_FUNCTION(::profiler::colors::Cyan); @@ -264,6 +264,9 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr if (!inFile.is_open()) return 0; + int64_t cpu_frequency = 0LL; + inFile.read((char*)&cpu_frequency, sizeof(int64_t)); + uint32_t total_blocks_number = 0; inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); if (total_blocks_number == 0) @@ -321,7 +324,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr i = 0; uint32_t read_number = 0; ::profiler::block_index_t blocks_counter = 0; - _blocks.reserve(total_blocks_number); + blocks.reserve(total_blocks_number); while (!inFile.eof() && read_number < total_blocks_number) { EASY_BLOCK("Read thread data", ::profiler::colors::Darkgreen); @@ -333,7 +336,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); auto& root = threaded_trees[thread_id]; - const auto threshold = read_number + blocks_number_in_thread; + auto threshold = read_number + blocks_number_in_thread; while (!inFile.eof() && read_number < threshold) { EASY_BLOCK("Read block", ::profiler::colors::Green); @@ -350,8 +353,20 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr i += sz; auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - _blocks.emplace_back(); - ::profiler::BlocksTree& tree = _blocks.back(); + if (cpu_frequency != 0) + { + auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data); + auto t_end = t_begin + 1; + + *t_begin *= 1000000000LL; + *t_begin /= cpu_frequency; + + *t_end *= 1000000000LL; + *t_end /= cpu_frequency; + } + + blocks.emplace_back(); + ::profiler::BlocksTree& tree = blocks.back(); tree.node = baseData;// new ::profiler::SerializedBlock(sz, data); const auto block_index = blocks_counter++; @@ -388,7 +403,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr if (!root.children.empty()) { - auto& back = _blocks[root.children.back()]; + auto& back = blocks[root.children.back()]; auto t1 = back.node->end(); auto mt0 = tree.node->begin(); if (mt0 < t1)//parent - starts earlier than last ends @@ -397,7 +412,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr /**/ EASY_BLOCK("Find children", ::profiler::colors::Blue); auto rlower1 = ++root.children.rbegin(); - for (; rlower1 != root.children.rend() && !(mt0 > _blocks[*rlower1].node->begin()); ++rlower1); + for (; rlower1 != root.children.rend() && !(mt0 > blocks[*rlower1].node->begin()); ++rlower1); auto lower = rlower1.base(); ::std::move(lower, root.children.end(), ::std::back_inserter(tree.children)); @@ -416,7 +431,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr for (auto i : tree.children) { - auto& child = _blocks[i]; + auto& child = blocks[i]; child.per_parent_stats = update_statistics(per_parent_statistics, child, i); children_duration += child.node->duration(); @@ -428,7 +443,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr { for (auto i : tree.children) { - const auto& child = _blocks[i]; + const auto& child = blocks[i]; children_duration += child.node->duration(); if (tree.depth < child.depth) tree.depth = child.depth; @@ -453,12 +468,67 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr break; progress.store(10 + static_cast(80 * i / memory_size)); } + + if (progress.load() < 0 || inFile.eof()) + break; + +#ifdef EASY_STORE_CSWITCH_SEPARATELY + blocks_number_in_thread = 0; + inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); + + threshold = read_number + blocks_number_in_thread; + while (!inFile.eof() && read_number < threshold) + { + EASY_BLOCK("Read context switch", ::profiler::colors::Green); + + ++read_number; + + uint16_t sz = 0; + inFile.read((char*)&sz, sizeof(sz)); + if (sz == 0) + return 0; + + char* data = serialized_blocks[i]; + inFile.read(data, sz); + i += sz; + auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); + + if (cpu_frequency != 0) + { + auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data); + auto t_end = t_begin + 1; + + *t_begin *= 1000000000LL; + *t_begin /= cpu_frequency; + + *t_end *= 1000000000LL; + *t_end /= cpu_frequency; + } + + blocks.emplace_back(); + ::profiler::BlocksTree& tree = blocks.back(); + tree.node = baseData; + const auto block_index = blocks_counter++; + + auto descriptor = descriptors[baseData->id()]; + if (descriptor->type() != ::profiler::BLOCK_TYPE_CONTEXT_SWITCH) + continue; + + root.sync.emplace_back(block_index); + + if (progress.load() < 0) + break; + + progress.store(10 + static_cast(80 * i / memory_size)); + } +#endif } if (progress.load() < 0) { serialized_blocks.clear(); threaded_trees.clear(); + blocks.clear(); return 0; } @@ -478,15 +548,22 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr auto& per_parent_statistics = parent_statistics[it.first]; per_parent_statistics.clear(); - statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &_blocks](::profiler::BlocksTreeRoot& root) + statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks](::profiler::BlocksTreeRoot& root) { +#ifdef EASY_STORE_CSWITCH_SEPARATELY + ::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right) + { + return blocks[left].node->begin() < blocks[right].node->begin(); + }); +#endif + for (auto i : root.children) { - auto& frame = _blocks[i]; + auto& frame = blocks[i]; frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i); per_frame_statistics.clear(); - update_statistics_recursive(per_frame_statistics, frame, i, _blocks); + update_statistics_recursive(per_frame_statistics, frame, i, blocks); if (root.depth < frame.depth) root.depth = frame.depth; @@ -511,10 +588,17 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr auto& root = it.second; root.thread_id = it.first; +#ifdef EASY_STORE_CSWITCH_SEPARATELY + ::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right) + { + return blocks[left].node->begin() < blocks[right].node->begin(); + }); +#endif + //root.tree.shrink_to_fit(); for (auto i : root.children) { - auto& frame = _blocks[i]; + auto& frame = blocks[i]; if (root.depth < frame.depth) root.depth = frame.depth; } From f5ed51e13aec75aeeb971d2d9b19799aa512ec9a Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 4 Sep 2016 19:35:58 +0300 Subject: [PATCH 17/37] Event tracing fixes! Now working :) --- include/profiler/profiler.h | 5 +++++ profiler_gui/blocks_graphics_view.cpp | 16 +++++++++++----- sample/main.cpp | 5 +++++ src/event_trace_win.cpp | 16 ++-------------- src/profile_manager.cpp | 5 ----- src/profile_manager.h | 8 +++++--- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 416e613..d3a6eab 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -280,6 +280,7 @@ namespace profiler { public: + BaseBlockData(const BaseBlockData&) = default; BaseBlockData(timestamp_t _begin_time, block_id_t _id); inline timestamp_t begin() const { return m_begin; } @@ -288,6 +289,10 @@ namespace profiler { inline timestamp_t duration() const { return m_end - m_begin; } inline void setId(block_id_t _id) { m_id = _id; } + + private: + + BaseBlockData() = delete; }; #pragma pack(pop) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 0f31c47..f781eeb 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -515,7 +515,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* if (!m_pRoot->sync.empty()) { _painter->setBrush(Qt::NoBrush); - QPen pen(QColor::fromRgba(0x40f08040)); + QPen pen(QColor::fromRgba(0xe0f08040)); pen.setWidth(3); _painter->setPen(pen); @@ -528,10 +528,10 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* if (begin > sceneRight) break; // This is first totally invisible item. No need to check other items. - decltype(begin) width = item.node->duration(); + decltype(begin) width = sceneView->time2position(item.node->end()) - begin; auto r = begin + width; -// if (r < sceneLeft) // This item is not visible -// continue; + if (r < sceneLeft) // This item is not visible + continue; begin *= currentScale; begin -= dx; @@ -1424,7 +1424,13 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr for (const auto& threadTree : _blocksTree) { const auto& tree = threadTree.second.children; - const auto timestart = blocksTree(tree.front()).node->begin(); + auto timestart = blocksTree(tree.front()).node->begin(); + +#ifdef EASY_STORE_CSWITCH_SEPARATELY + if (!threadTree.second.sync.empty()) + timestart = ::std::min(timestart, blocksTree(threadTree.second.sync.front()).node->begin()); +#endif + const auto timefinish = blocksTree(tree.back()).node->end(); if (m_beginTime > timestart) diff --git a/sample/main.cpp b/sample/main.cpp index 7ef3014..32de060 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -262,6 +262,11 @@ int main(int argc, char* argv[]) } cv.notify_all(); + for (int i = 0; i < RENDER_SPEPS; ++i) { + modellingStep(); + localSleep(1200000); + } + render.join(); modelling.join(); for(auto& t : threads){ diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index ad40b97..78c436a 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -3,7 +3,6 @@ #ifdef _WIN32 #include #include -#include #include "event_trace_win.h" #include "profiler/profiler.h" #include "profile_manager.h" @@ -35,8 +34,6 @@ namespace profiler { void WINAPI processTraceEvent(PEVENT_RECORD _traceEvent) { - //static ::std::ofstream outputFile("csw.csv", ::std::fstream::app); - static const decltype(_traceEvent->EventHeader.EventDescriptor.Opcode) SWITCH_CONTEXT_OPCODE = 36; if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE) return; @@ -47,11 +44,6 @@ namespace profiler { auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); auto timestampValue = _traceEvent->EventHeader.TimeStamp.QuadPart; - - //LARGE_INTEGER currtime; - //if (QueryPerformanceCounter(&currtime)) - // timestampValue = currtime.QuadPart; - //timestampValue *= 1000000000LL; //timestampValue /= CPU_FREQUENCY; const auto time = (::profiler::timestamp_t)timestampValue; @@ -59,14 +51,10 @@ namespace profiler { static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); //if (_contextSwitchEvent->OldThreadId != 0) - MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); + MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); //if (_contextSwitchEvent->NewThreadId != 0) - MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); - - //static const auto firstTime = time; - //outputFile << _contextSwitchEvent->OldThreadId << "\t" << _contextSwitchEvent->NewThreadId << "\t" << (((time - firstTime) * 1000000000LL) / CPU_FREQUENCY) << ::std::endl; - //outputFile << _contextSwitchEvent->OldThreadId << "\t" << _contextSwitchEvent->NewThreadId << "\t" << time << ::std::endl; + MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index e4e0a46..bc4bd9e 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -271,14 +271,10 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) of.write(descriptor.file(), filename_size); } - //::std::ofstream outputFile("csw2.csv", ::std::fstream::app); - for (auto& thread_storage : m_threads) { auto& t = thread_storage.second; - //outputFile << thread_storage.first << std::endl; - of.write(thread_storage.first); #ifdef STORE_CSWITCHES_SEPARATELY of.write(static_cast(t.blocks.closedList.size())); @@ -318,7 +314,6 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) { auto b = t.sync.closedList[i]; #endif - //outputFile << b->begin() << "\t" << b->end() << std::endl; of.writeBlock(b); } diff --git a/src/profile_manager.h b/src/profile_manager.h index 311ef19..9622910 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -76,7 +76,7 @@ public: return data; } - m_size = 0; + m_size = n; m_chunks.emplace_back(); return m_chunks.back().data; } @@ -91,6 +91,8 @@ public: ////////////////////////////////////////////////////////////////////////// +const uint16_t SIZEOF_CSWITCH = sizeof(profiler::BaseBlockData) + 1; + class ThreadStorage final { typedef std::vector serialized_list_t; @@ -114,8 +116,8 @@ class ThreadStorage final public: - BlocksList, 1024> blocks; - BlocksList sync; + BlocksList, SIZEOF_CSWITCH * (uint16_t)1024U> blocks; + BlocksList sync; bool named = false; void storeBlock(const profiler::Block& _block); From 6d1b9915d2cc9f12abc12d3e298de7e4838cb100 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Mon, 5 Sep 2016 22:02:32 +0300 Subject: [PATCH 18/37] Get thread id on linux by syscall instead of std::this_thread --- src/profile_manager.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/profile_manager.h b/src/profile_manager.h index 9622910..38c1c04 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -36,6 +36,9 @@ along with this program.If not, see . #include #else #include +#include +#include +#include #endif inline uint32_t getCurrentThreadId() @@ -43,8 +46,9 @@ inline uint32_t getCurrentThreadId() #ifdef _WIN32 return (uint32_t)::GetCurrentThreadId(); #else - thread_local static uint32_t _id = (uint32_t)std::hash()(std::this_thread::get_id()); - return _id; + thread_local static pid_t x = syscall(__NR_gettid); + thread_local static uint32_t _id = (uint32_t)x;//std::hash()(std::this_thread::get_id()); + return _id; #endif } @@ -108,8 +112,8 @@ class ThreadStorage final uint64_t usedMemorySize = 0; void clearClosed() { - serialized_list_t().swap(closedList); - alloc.clear(); + serialized_list_t().swap(closedList); + alloc.clear(); usedMemorySize = 0; } }; From 9521f8ac02ec63e6ae06f0456f2afb2edad5d867 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Mon, 5 Sep 2016 22:11:03 +0300 Subject: [PATCH 19/37] Store context switch timestamp on linux. It's need to run systemtap util for loading kernel module. This kernel module capture context switch timestamp and systemtap store it in the temp file. Before running profiling application you should run systemtap script with root privileges as following: \# stap -o /tmp/cs_profiling_info.log scripts/context_switch_logger.stp name APPLICATION_NAME where APPLICATION_NAME is profiling application --- include/profiler/profiler.h | 12 +++++---- scripts/context_switch_logger.stp | 36 +++++++++++++++++++++++++++ src/profile_manager.cpp | 41 +++++++++++++++++++++++++++++++ src/profile_manager.h | 13 ++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 scripts/context_switch_logger.stp diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index d3a6eab..cd1e5d0 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -214,11 +214,13 @@ namespace profiler { class StaticBlockDescriptor; extern "C"{ - void PROFILER_API beginBlock(Block& _block); - void PROFILER_API endBlock(); - void PROFILER_API setEnabled(bool isEnable); - uint32_t PROFILER_API dumpBlocksToFile(const char* filename); - void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); + void PROFILER_API beginBlock(Block& _block); + void PROFILER_API endBlock(); + void PROFILER_API setEnabled(bool isEnable); + uint32_t PROFILER_API dumpBlocksToFile(const char* filename); + void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); + void PROFILER_API setContextSwitchLogFilename(const char* name); + const char* PROFILER_API getContextSwitchLogFilename(); } typedef uint64_t timestamp_t; diff --git a/scripts/context_switch_logger.stp b/scripts/context_switch_logger.stp new file mode 100644 index 0000000..b9f8c7a --- /dev/null +++ b/scripts/context_switch_logger.stp @@ -0,0 +1,36 @@ +global target_pid +global target_name + +probe scheduler.ctxswitch { + + if (target_pid != 0 + && next_pid != target_pid + && prev_pid != target_pid) + next + + if (target_name != "" + && prev_task_name != target_name + && next_task_name != target_name) + next + + //printf("Switch from %d(%s) to %d(%s) at %d\n",prev_tid, prev_task_name,next_tid,next_task_name, gettimeofday_ns()) + printf("%d %d %d\n",gettimeofday_ns(),prev_tid, next_tid ) +} + +probe begin +{ + target_pid = 0 + target_name = "" + + %( $# == 1 || $# > 2 %? + log("Wrong number of arguments, use none, 'pid nr' or 'name proc'") + exit() + %) + + %( $# == 2 %? + if(@1 == "pid") + target_pid = strtol(@2, 10) + if(@1 == "name") + target_name = @2 + %) +} diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index bc4bd9e..c95536c 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -26,10 +26,12 @@ extern "C"{ void PROFILER_API setEnabled(bool isEnable) { MANAGER.setEnabled(isEnable); +#ifdef _WIN32 if (isEnable) EasyEventTracer::instance().enable(true); else EasyEventTracer::instance().disable(); +#endif } void PROFILER_API beginBlock(Block& _block) @@ -47,6 +49,16 @@ extern "C"{ return MANAGER.setThreadName(name, filename, _funcname, line); } + void PROFILER_API setContextSwitchLogFilename(const char* name) + { + return MANAGER.setContextSwitchLogFilename(name); + } + + const char* PROFILER_API getContextSwitchLogFilename() + { + return MANAGER.getContextSwitchLogFilename(); + } + } SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) @@ -165,6 +177,16 @@ void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::b thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } +void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +{ + auto thread_storage = _threadStorage(_thread_id); + if (thread_storage != nullptr){ + profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); + lastBlock.finish(_time); + thread_storage->storeCSwitch(lastBlock); + } +} + void ProfileManager::endBlock() { if (!m_isEnabled) @@ -236,6 +258,25 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) if (wasEnabled) ::profiler::setEnabled(false); +#ifndef _WIN32 + uint64_t timestamp; + uint32_t thread_from, thread_to; + + std::ifstream infile(m_csInfoFilename.c_str()); + + if(infile.is_open()) + { + while (infile >> timestamp >> thread_from >> thread_to ) + { + static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + _cswitchBeginBlock(timestamp, desc.id(), thread_from); + _cswitchEndBlock(thread_to, timestamp); + } + } + +#endif + + FileWriter of(filename); uint64_t usedMemorySize = 0; diff --git a/src/profile_manager.h b/src/profile_manager.h index 38c1c04..6151691 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -150,6 +150,8 @@ class ProfileManager final profiler::spin_lock m_storedSpin; bool m_isEnabled = false; + std::string m_csInfoFilename = "/tmp/cs_profiling_info.log"; + public: static ProfileManager& instance(); @@ -161,7 +163,18 @@ public: uint32_t dumpBlocksToFile(const char* filename); void setThreadName(const char* name, const char* filename, const char* _funcname, int line); + void setContextSwitchLogFilename(const char* name) + { + m_csInfoFilename = name; + } + + const char* getContextSwitchLogFilename() const + { + return m_csInfoFilename.c_str(); + } + void _cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); + void _cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); void _cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); private: From 33946770bb4c0ddabf1defe8ccfa76a9053faa2f Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 00:22:26 +0300 Subject: [PATCH 20/37] (profiler_core) Windows build fix --- include/profiler/profiler.h | 2 +- src/profile_manager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index cd1e5d0..55e9b74 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -220,7 +220,7 @@ namespace profiler { uint32_t PROFILER_API dumpBlocksToFile(const char* filename); void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); void PROFILER_API setContextSwitchLogFilename(const char* name); - const char* PROFILER_API getContextSwitchLogFilename(); + PROFILER_API const char* getContextSwitchLogFilename(); } typedef uint64_t timestamp_t; diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index c95536c..a9ad6a7 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -54,7 +54,7 @@ extern "C"{ return MANAGER.setContextSwitchLogFilename(name); } - const char* PROFILER_API getContextSwitchLogFilename() + PROFILER_API const char* getContextSwitchLogFilename() { return MANAGER.getContextSwitchLogFilename(); } From d8d9a2fd32f1e4b6f2ab2ef016607bd224c1d221 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 00:23:46 +0300 Subject: [PATCH 21/37] (EasyGraphicsView) Painting context switches with outlined rectangles --- profiler_gui/blocks_graphics_view.cpp | 57 ++++++++++++++++----------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index f781eeb..04bc07e 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -514,37 +514,46 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* #ifdef EASY_STORE_CSWITCH_SEPARATELY if (!m_pRoot->sync.empty()) { - _painter->setBrush(Qt::NoBrush); - QPen pen(QColor::fromRgba(0xe0f08040)); - pen.setWidth(3); - _painter->setPen(pen); + _painter->setBrush(QColor::fromRgba(0xfff08040)); + _painter->setPen(QColor::fromRgb(0x00505050)); - qreal prevRight = -1e100, top = y() - 1; - for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it) + qreal prevRight = -1e100, top = y() - 4, h = 3; + if (top + h < visibleBottom) { - const auto& item = easyBlock(*it).tree; - auto begin = sceneView->time2position(item.node->begin()); + for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it) + { + const auto& item = easyBlock(*it).tree; + auto begin = sceneView->time2position(item.node->begin()); - if (begin > sceneRight) - break; // This is first totally invisible item. No need to check other items. + if (begin > sceneRight) + break; // This is first totally invisible item. No need to check other items. - decltype(begin) width = sceneView->time2position(item.node->end()) - begin; - auto r = begin + width; - if (r < sceneLeft) // This item is not visible - continue; + decltype(begin) width = sceneView->time2position(item.node->end()) - begin; + auto r = begin + width; + if (r < sceneLeft) // This item is not visible + continue; - begin *= currentScale; - begin -= dx; - width *= currentScale; -// r = begin + width; -// if (r <= prevRight) // This item is not visible -// continue; + begin *= currentScale; + begin -= dx; + width *= currentScale; + r = begin + width; + if (r <= prevRight) // This item is not visible + continue; - if (width < 1) - width = 1; + if (begin < prevRight) + { + width -= prevRight - begin; + begin = prevRight; + } - _painter->drawLine(QLineF(begin, top, begin + width, top)); - prevRight = begin + width; + if (width < 2) + width = 2; + + //_painter->drawLine(QLineF(::std::max(begin, prevRight), top, begin + width, top)); + rect.setRect(begin, top, width, h); + _painter->drawRect(rect); + prevRight = begin + width; + } } } #endif From f25ba79636305842dcb5751ade8345a349f59bb9 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 00:24:21 +0300 Subject: [PATCH 22/37] (profiler_core) Event tracing clean-up --- src/event_trace_win.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index 78c436a..8657874 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -16,6 +16,9 @@ extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; namespace profiler { + // CSwitch class + // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964744(v=vs.85).aspx + // EventType = 36 struct CSwitch final { uint32_t NewThreadId; @@ -41,20 +44,14 @@ namespace profiler { if (sizeof(CSwitch) != _traceEvent->UserDataLength) return; - auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); + //EASY_FUNCTION(::profiler::colors::Red); - auto timestampValue = _traceEvent->EventHeader.TimeStamp.QuadPart; - //timestampValue *= 1000000000LL; - //timestampValue /= CPU_FREQUENCY; - const auto time = (::profiler::timestamp_t)timestampValue; + auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); + const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart); static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); - - //if (_contextSwitchEvent->OldThreadId != 0) - MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); - - //if (_contextSwitchEvent->NewThreadId != 0) - MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); + MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); + MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); } ////////////////////////////////////////////////////////////////////////// @@ -148,8 +145,8 @@ namespace profiler { // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx m_stubThread = ::std::move(::std::thread([this]() { -// EASY_THREAD("ProcessTrace"); -// EASY_BLOCK("ProcessTrace", ::profiler::colors::Red); + EASY_THREAD("EasyProfiler.EventTracing"); + //EASY_BLOCK("ProcessTrace()", ::profiler::colors::Red); ProcessTrace(&m_openedHandle, 1, 0, 0); })); From 591f613ff64702c52beafdfacf8c8ca533aaf564 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 21:49:32 +0300 Subject: [PATCH 23/37] License text + small clean-up --- profiler_gui/blocks_graphics_view.cpp | 17 +++++++- profiler_gui/blocks_graphics_view.h | 17 +++++++- profiler_gui/blocks_tree_widget.cpp | 57 ++++++++++++++++-------- profiler_gui/blocks_tree_widget.h | 42 ++++++++---------- profiler_gui/common_types.h | 17 +++++++- profiler_gui/globals.cpp | 17 +++++++- profiler_gui/globals.h | 17 +++++++- profiler_gui/globals_qobjects.cpp | 21 +++++++-- profiler_gui/globals_qobjects.h | 36 ++++++++++++++-- profiler_gui/graphics_scrollbar.cpp | 35 +++++++++++---- profiler_gui/graphics_scrollbar.h | 62 ++++++++------------------- profiler_gui/main.cpp | 33 ++++++++++++-- profiler_gui/main_window.cpp | 17 +++++++- profiler_gui/main_window.h | 17 +++++++- profiler_gui/tree_widget_item.cpp | 17 +++++++- profiler_gui/tree_widget_item.h | 17 +++++++- profiler_gui/tree_widget_loader.cpp | 17 +++++++- profiler_gui/tree_widget_loader.h | 17 +++++++- src/event_trace_win.cpp | 9 +--- src/reader.cpp | 17 +++++++- 20 files changed, 362 insertions(+), 137 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 04bc07e..b920e95 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -2,7 +2,6 @@ * file name : blocks_graphics_view.cpp * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -22,7 +21,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 7d74eb8..54a27ef 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -2,7 +2,6 @@ * file name : blocks_graphics_view.h * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -18,7 +17,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY__GRAPHICS_VIEW__H_ diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index a64931b..d5e5201 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -2,7 +2,6 @@ * file name : blocks_tree_widget.cpp * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -21,7 +20,21 @@ * : * : * 2016/08/18 Victor Zarubkin: Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include @@ -358,7 +371,7 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) case COL_MAX_PER_FRAME: { auto& block = item->block(); - auto i = ::profiler_gui::numeric_max(); + auto i = ::profiler_gui::numeric_max(); switch (col) { case COL_MIN_PER_THREAD: i = block.per_thread_stats->min_duration_block; break; @@ -372,9 +385,10 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (i != ::profiler_gui::numeric_max(i)) { menu.addSeparator(); - auto itemAction = new EasyItemAction("Jump to such item", i); + auto itemAction = new QAction("Jump to such item", nullptr); + itemAction->setData(i); itemAction->setToolTip("Jump to item with min/max duration (depending on clicked column)"); - connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked); + connect(itemAction, &QAction::triggered, this, &This::onJumpToItemClicked); menu.addAction(itemAction); } @@ -391,10 +405,11 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) { - auto columnAction = new EasyHideShowColumnAction(hdr->text(i), i); + auto columnAction = new QAction(hdr->text(i), nullptr); + columnAction->setData(i); columnAction->setCheckable(true); columnAction->setChecked(!isColumnHidden(i)); - connect(columnAction, &EasyHideShowColumnAction::clicked, this, &This::onHideShowColumn); + connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn); hidemenu->addAction(columnAction); } @@ -425,10 +440,15 @@ void EasyTreeWidget::alignProgressBar() ////////////////////////////////////////////////////////////////////////// -void EasyTreeWidget::onJumpToItemClicked(unsigned int _block_index) +void EasyTreeWidget::onJumpToItemClicked(bool) { - EASY_GLOBALS.selected_block = _block_index; - emit EASY_GLOBALS.events.selectedBlockChanged(_block_index); + auto action = qobject_cast(sender()); + if (action == nullptr) + return; + + auto block_index = action->data().toUInt(); + EASY_GLOBALS.selected_block = block_index; + emit EASY_GLOBALS.events.selectedBlockChanged(block_index); } void EasyTreeWidget::onCollapseAllClicked(bool) @@ -639,16 +659,17 @@ void EasyTreeWidget::resizeColumnsToContents() ////////////////////////////////////////////////////////////////////////// -void EasyTreeWidget::onHideShowColumn(int _column) +void EasyTreeWidget::onHideShowColumn(bool) { - if (isColumnHidden(_column)) - { - showColumn(_column); - } + auto action = qobject_cast(sender()); + if (action == nullptr) + return; + + auto col = action->data().toInt(); + if (isColumnHidden(col)) + showColumn(col); else - { - hideColumn(_column); - } + hideColumn(col); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index 7f4a3d9..f5d2dbd 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -2,7 +2,6 @@ * file name : blocks_tree_widget.h * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -20,7 +19,21 @@ * : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread; * : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY__TREE_WIDGET__H_ @@ -34,27 +47,6 @@ ////////////////////////////////////////////////////////////////////////// -#define DECLARE_QACTION(ClassName, DataType) \ -class ClassName : public QAction { \ - Q_OBJECT \ -private: \ - DataType m_item; \ -public: \ - ClassName(const char* _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \ - connect(this, &QAction::triggered, this, &ClassName::onToggle); } \ - ClassName(const QString& _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \ - connect(this, &QAction::triggered, this, &ClassName::onToggle); } \ - virtual ~ClassName() {} \ -private: \ - void onToggle(bool) { emit clicked(m_item); } - -DECLARE_QACTION(EasyItemAction, unsigned int) signals: void clicked(unsigned int _item); }; -DECLARE_QACTION(EasyHideShowColumnAction, int) signals: void clicked(int _item); }; - -#undef DECLARE_QACTION - -////////////////////////////////////////////////////////////////////////// - class EasyTreeWidget : public QTreeWidget { Q_OBJECT @@ -96,7 +88,7 @@ protected: private slots: - void onJumpToItemClicked(unsigned int _block_index); + void onJumpToItemClicked(bool); void onCollapseAllClicked(bool); @@ -118,7 +110,7 @@ private slots: void resizeColumnsToContents(); - void onHideShowColumn(int _column); + void onHideShowColumn(bool); void onFillTimerTimeout(); diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 9c7c134..5be5d8f 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -2,7 +2,6 @@ * file name : common_types.h * ----------------- : * creation time : 2016/07/31 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -13,7 +12,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY_PROFILER__GUI_COMMON_TYPES_H diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index f4efb63..a5021e1 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -2,7 +2,6 @@ * file name : globals.cpp * ----------------- : * creation time : 2016/08/03 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -12,7 +11,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #define IGNORE_GLOBALS_DECLARATION diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 0a0eee8..1116a81 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -2,7 +2,6 @@ * file name : globals.h * ----------------- : * creation time : 2016/08/03 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -12,7 +11,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY_PROFILER__GUI_GLOBALS_H diff --git a/profiler_gui/globals_qobjects.cpp b/profiler_gui/globals_qobjects.cpp index 3f9879f..9ada430 100644 --- a/profiler_gui/globals_qobjects.cpp +++ b/profiler_gui/globals_qobjects.cpp @@ -2,9 +2,8 @@ * file name : globals_qobjects.cpp * ----------------- : * creation time : 2016/08/08 -* copyright : (c) 2016 Victor Zarubkin, Sergey Yagovtsev -* author : Victor Zarubkin -* email : v.s.zarubkin@gmail.com +* authors : Victor Zarubkin, Sergey Yagovtsev +* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com * ----------------- : * description : The file contains implementation of EasyGlobalSignals QObject class. * ----------------- : @@ -12,7 +11,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include "globals_qobjects.h" diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index b69f031..ccf2010 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -1,5 +1,35 @@ -#ifndef GLOBALS_QOBJECTS_H -#define GLOBALS_QOBJECTS_H +/************************************************************************ +* file name : globals_qobjects.h +* ----------------- : +* creation time : 2016/08/08 +* authors : Victor Zarubkin, Sergey Yagovtsev +* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com +* ----------------- : +* description : The file contains declaration of EasyGlobalSignals QObject class. +* ----------------- : +* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.h +* : +* : * +* ----------------- : +* license : 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 . +************************************************************************/ + +#ifndef EASY__GLOBALS_QOBJECTS_H___ +#define EASY__GLOBALS_QOBJECTS_H___ #include #include "profiler/profiler.h" @@ -27,4 +57,4 @@ namespace profiler_gui { } // END of namespace profiler_gui. -#endif // GLOBALS_QOBJECTS_H +#endif // EASY__GLOBALS_QOBJECTS_H___ diff --git a/profiler_gui/graphics_scrollbar.cpp b/profiler_gui/graphics_scrollbar.cpp index 2260857..10e1d5b 100644 --- a/profiler_gui/graphics_scrollbar.cpp +++ b/profiler_gui/graphics_scrollbar.cpp @@ -2,7 +2,6 @@ * file name : graphics_scrollbar.cpp * ----------------- : * creation time : 2016/07/04 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -12,7 +11,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include @@ -512,10 +525,11 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) label = ::std::move(QString("Thread %1").arg(it.first)); } - auto action = new EasyIdAction(label, it.first); + auto action = new QAction(label, nullptr); + action->setData(it.first); action->setCheckable(true); action->setChecked(it.first == EASY_GLOBALS.selected_thread); - connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked); + connect(action, &QAction::triggered, this, &This::onThreadActionClicked); menu.addAction(action); } @@ -526,12 +540,17 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) ////////////////////////////////////////////////////////////////////////// -void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id) +void EasyGraphicsScrollbar::onThreadActionClicked(bool) { - if (_id != m_minimap->threadId()) + auto action = qobject_cast(sender()); + if (action == nullptr) + return; + + const auto thread_id = action->data().toUInt(); + if (thread_id != m_minimap->threadId()) { - EASY_GLOBALS.selected_thread = _id; - emit EASY_GLOBALS.events.selectedThreadChanged(_id); + EASY_GLOBALS.selected_thread = thread_id; + emit EASY_GLOBALS.events.selectedThreadChanged(thread_id); } } diff --git a/profiler_gui/graphics_scrollbar.h b/profiler_gui/graphics_scrollbar.h index 85e19a9..4615090 100644 --- a/profiler_gui/graphics_scrollbar.h +++ b/profiler_gui/graphics_scrollbar.h @@ -2,17 +2,30 @@ * file name : graphics_scrollbar.h * ----------------- : * creation time : 2016/07/04 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : -* description : . +* description : This file contains declaration of * ----------------- : * change log : * 2016/07/04 Victor Zarubkin: Initial commit. * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY__GRAPHICS_SCROLLBAR__H @@ -94,47 +107,6 @@ public: ////////////////////////////////////////////////////////////////////////// -class EasyIdAction : public QAction -{ - Q_OBJECT - -private: - - typedef QAction Parent; - typedef EasyIdAction This; - - ::profiler::thread_id_t m_id; - -public: - - EasyIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) - { - connect(this, &Parent::triggered, this, &This::onToggle); - } - - EasyIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) - { - connect(this, &Parent::triggered, this, &This::onToggle); - } - - virtual ~EasyIdAction() - { - } - -private: - - void onToggle(bool) - { - emit clicked(m_id); - } - -signals: - - void clicked(::profiler::thread_id_t _id); -}; - -////////////////////////////////////////////////////////////////////////// - class EasyGraphicsScrollbar : public QGraphicsView { Q_OBJECT @@ -205,7 +177,7 @@ signals: private slots: - void onThreadActionClicked(::profiler::thread_id_t _id); + void onThreadActionClicked(bool); void onWindowWidthChange(qreal _width); }; // END of class EasyGraphicsScrollbar. diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index 9d7fcd3..f38a574 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -1,11 +1,38 @@ -#include -#include -#include +/************************************************************************ +* file name : main.cpp +* ----------------- : +* creation time : 2016/04/29 +* authors : Sergey Yagovtsev, Victor Zarubkin +* email : yse.sey@gmail.com, v.s.zarubkin@gmail.com +* ----------------- : +* description : Main file for EasyProfiler GUI. +* ----------------- : +* license : 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 . +************************************************************************/ + #include +#include +//#include +//#include //#include "treemodel.h" #include "main_window.h" #include "profiler/reader.h" + //#ifdef _WIN32 //#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") //#endif diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 9abe5cc..e7ddfa0 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -2,7 +2,6 @@ * file name : main_window.cpp * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -18,7 +17,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 91160d4..752f39e 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -2,7 +2,6 @@ * file name : main_window.h * ----------------- : * creation time : 2016/06/26 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -11,7 +10,21 @@ * change log : * 2016/06/26 Victor Zarubkin: initial commit. * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp index 1a2c0a6..78fa97c 100644 --- a/profiler_gui/tree_widget_item.cpp +++ b/profiler_gui/tree_widget_item.cpp @@ -2,7 +2,6 @@ * file name : tree_widget_item.cpp * ----------------- : * creation time : 2016/08/18 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -13,7 +12,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include "tree_widget_item.h" diff --git a/profiler_gui/tree_widget_item.h b/profiler_gui/tree_widget_item.h index 1b12d21..182eca8 100644 --- a/profiler_gui/tree_widget_item.h +++ b/profiler_gui/tree_widget_item.h @@ -2,7 +2,6 @@ * file name : tree_widget_item.h * ----------------- : * creation time : 2016/08/18 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -14,7 +13,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY__TREE_WIDGET_ITEM__H_ diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index 2931382..b388f81 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -2,7 +2,6 @@ * file name : tree_widget_loader.h * ----------------- : * creation time : 2016/08/18 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -14,7 +13,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include "tree_widget_loader.h" diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h index 1de12ee..6104c67 100644 --- a/profiler_gui/tree_widget_loader.h +++ b/profiler_gui/tree_widget_loader.h @@ -2,7 +2,6 @@ * file name : tree_widget_loader.h * ----------------- : * creation time : 2016/08/18 -* copyright : (c) 2016 Victor Zarubkin * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : @@ -14,7 +13,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #ifndef EASY__TREE_WIDGET_LOADER__H_ diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index 8657874..2480434 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -10,7 +10,6 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; //extern ProfileManager& MANAGER; #define MANAGER ProfileManager::instance() @@ -160,12 +159,8 @@ namespace profiler { if (!m_bEnabled) return; - auto controlTraceResult = ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP); - - // ERROR_CTX_CLOSE_PENDING(7007L): The call was successful. The ProcessTrace function will stop after it has processed all real-time events in its buffers (it will not receive any new events). - // ERROR_BUSY(170L): Prior to Windows Vista, you cannot close the trace until the ProcessTrace function completes. - // ERROR_INVALID_HANDLE(6L): One of the following is true: TraceHandle is NULL. TraceHandle is INVALID_HANDLE_VALUE. - auto closeTraceStatus = CloseTrace(m_openedHandle); + ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP); + CloseTrace(m_openedHandle); // Wait for ProcessThread to finish if (m_stubThread.joinable()) diff --git a/src/reader.cpp b/src/reader.cpp index 3d05b01..f6f02d9 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2,7 +2,6 @@ * file name : reader.cpp * ----------------- : * creation time : 2016/06/19 -* copyright : (c) 2016 Sergey Yagovtsev, Victor Zarubkin * authors : Sergey Yagovtsev, Victor Zarubkin * emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com * ----------------- : @@ -26,7 +25,21 @@ * : * : * * ----------------- : -* license : TODO: add license text +* license : 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 . ************************************************************************/ #include "profiler/reader.h" From e4db8cabe487f55af2eee3fbc1dd0914625fe7d7 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 21:52:56 +0300 Subject: [PATCH 24/37] (profiler_core) Measure core functions work time --- src/profile_manager.cpp | 37 +++++++++++++++++++++++++++---------- src/profile_manager.h | 28 +++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index a9ad6a7..de082dd 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -7,6 +7,19 @@ #include +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +#define EASY_INTERNAL_BLOCK(name, easyType, CODE) CODE +//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\ +// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\ +// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\ +// CODE\ +// EASY_UNIQUE_BLOCK(__LINE__).finish();\ +// thread_storage.storeBlock(EASY_UNIQUE_BLOCK(__LINE__)) + +////////////////////////////////////////////////////////////////////////// + using namespace profiler; #ifdef _WIN32 @@ -162,19 +175,23 @@ void ProfileManager::beginBlock(Block& _block) if (!m_isEnabled) return; - auto& thread_storage = threadStorage(getCurrentThreadId()); + EASY_INTERNAL_BLOCK("Easy.Spin", profiler::BLOCK_TYPE_BLOCK,\ + auto& thread_storage = threadStorage(getCurrentThreadId());\ + ); - if (!_block.isFinished()) - thread_storage.blocks.openedList.emplace(_block); - else - thread_storage.storeBlock(_block); + EASY_INTERNAL_BLOCK("Easy.Insert", profiler::BLOCK_TYPE_BLOCK,\ + if (!_block.isFinished()) + thread_storage.blocks.emplace(_block); + else + thread_storage.storeBlock(_block);\ + ); } void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) { auto thread_storage = _threadStorage(_thread_id); if (thread_storage != nullptr) - thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); + thread_storage->sync.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) @@ -196,12 +213,12 @@ void ProfileManager::endBlock() if (thread_storage.blocks.openedList.empty()) return; - Block& lastBlock = thread_storage.blocks.openedList.top(); + Block& lastBlock = thread_storage.blocks.top(); if (!lastBlock.isFinished()) lastBlock.finish(); thread_storage.storeBlock(lastBlock); - thread_storage.blocks.openedList.pop(); + thread_storage.blocks.pop(); } void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) @@ -210,11 +227,11 @@ void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler if (thread_storage == nullptr || thread_storage->sync.openedList.empty()) return; - Block& lastBlock = thread_storage->sync.openedList.top(); + Block& lastBlock = thread_storage->sync.top(); lastBlock.finish(_endtime); thread_storage->storeCSwitch(lastBlock); - thread_storage->sync.openedList.pop(); + thread_storage->sync.pop(); } void ProfileManager::setEnabled(bool isEnable) diff --git a/src/profile_manager.h b/src/profile_manager.h index 6151691..ee1047f 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -104,7 +104,8 @@ class ThreadStorage final template struct BlocksList final { - typedef std::stack stack_of_blocks_t; + //typedef std::stack stack_of_blocks_t; + typedef std::vector stack_of_blocks_t; chunk_allocator alloc; stack_of_blocks_t openedList; @@ -116,6 +117,31 @@ class ThreadStorage final alloc.clear(); usedMemorySize = 0; } + + void emplace(profiler::Block& _block) + { + //openedList.emplace(_block); + openedList.emplace_back(_block); + } + + template + void emplace(TArgs&& ... _args) + { + //openedList.emplace(std::forward(_args)); + openedList.emplace_back(std::forward(_args)...); + } + + T& top() + { + //return openedList.top(); + return openedList.back(); + } + + void pop() + { + //openedList.pop(); + openedList.pop_back(); + } }; public: From 31705d5daf2514a80a63e4dd9283656a18c64719 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 22:00:53 +0300 Subject: [PATCH 25/37] (profiler_core) Better way of declaring generic stack --- src/profile_manager.cpp | 12 ++++----- src/profile_manager.h | 58 +++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index de082dd..4dc6bb5 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -181,7 +181,7 @@ void ProfileManager::beginBlock(Block& _block) EASY_INTERNAL_BLOCK("Easy.Insert", profiler::BLOCK_TYPE_BLOCK,\ if (!_block.isFinished()) - thread_storage.blocks.emplace(_block); + thread_storage.blocks.openedList.emplace(_block); else thread_storage.storeBlock(_block);\ ); @@ -191,7 +191,7 @@ void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::b { auto thread_storage = _threadStorage(_thread_id); if (thread_storage != nullptr) - thread_storage->sync.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); + thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) @@ -213,12 +213,12 @@ void ProfileManager::endBlock() if (thread_storage.blocks.openedList.empty()) return; - Block& lastBlock = thread_storage.blocks.top(); + Block& lastBlock = thread_storage.blocks.openedList.top(); if (!lastBlock.isFinished()) lastBlock.finish(); thread_storage.storeBlock(lastBlock); - thread_storage.blocks.pop(); + thread_storage.blocks.openedList.pop(); } void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) @@ -227,11 +227,11 @@ void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler if (thread_storage == nullptr || thread_storage->sync.openedList.empty()) return; - Block& lastBlock = thread_storage->sync.top(); + Block& lastBlock = thread_storage->sync.openedList.top(); lastBlock.finish(_endtime); thread_storage->storeCSwitch(lastBlock); - thread_storage->sync.pop(); + thread_storage->sync.openedList.pop(); } void ProfileManager::setEnabled(bool isEnable) diff --git a/src/profile_manager.h b/src/profile_manager.h index ee1047f..7244e43 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -104,11 +104,38 @@ class ThreadStorage final template struct BlocksList final { - //typedef std::stack stack_of_blocks_t; - typedef std::vector stack_of_blocks_t; + class Stack final { + //std::stack m_stack; + std::vector m_stack; + + public: + + inline void clear() { m_stack.clear(); } + inline bool empty() const { return m_stack.empty(); } + + inline void emplace(profiler::Block& _block) { + //m_stack.emplace(_block); + m_stack.emplace_back(_block); + } + + template inline void emplace(TArgs ... _args) { + //m_stack.emplace(_args); + m_stack.emplace_back(_args...); + } + + inline T& top() { + //return m_stack.top(); + return m_stack.back(); + } + + inline void pop() { + //m_stack.pop(); + m_stack.pop_back(); + } + }; chunk_allocator alloc; - stack_of_blocks_t openedList; + Stack openedList; serialized_list_t closedList; uint64_t usedMemorySize = 0; @@ -117,31 +144,6 @@ class ThreadStorage final alloc.clear(); usedMemorySize = 0; } - - void emplace(profiler::Block& _block) - { - //openedList.emplace(_block); - openedList.emplace_back(_block); - } - - template - void emplace(TArgs&& ... _args) - { - //openedList.emplace(std::forward(_args)); - openedList.emplace_back(std::forward(_args)...); - } - - T& top() - { - //return openedList.top(); - return openedList.back(); - } - - void pop() - { - //openedList.pop(); - openedList.pop_back(); - } }; public: From ede383be3c7964ec4a6d4f88aa3565f0337f6777 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Tue, 6 Sep 2016 22:15:50 +0300 Subject: [PATCH 26/37] Add licence text to some file --- src/block.cpp | 25 +++++++++++++++++++++++++ src/profile_manager.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/block.cpp b/src/block.cpp index 5193b94..140f6b6 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -1,3 +1,28 @@ +/************************************************************************ +* file name : block.cpp +* ----------------- : +* creation time : 2016/02/16 +* authors : Sergey Yagovtsev, Victor Zarubkin +* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of profiling blocks +* : +* license : 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 . +************************************************************************/ #include "profiler/profiler.h" #include "profile_manager.h" #include diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 4dc6bb5..b70d142 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -1,3 +1,28 @@ +/************************************************************************ +* file name : profile_manager.cpp +* ----------------- : +* creation time : 2016/02/16 +* authors : Sergey Yagovtsev, Victor Zarubkin +* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of Profile manager and implement access c-function +* : +* license : 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 . +************************************************************************/ #include "profile_manager.h" #include "profiler/serialized_block.h" #include "event_trace_win.h" @@ -11,9 +36,9 @@ ////////////////////////////////////////////////////////////////////////// #define EASY_INTERNAL_BLOCK(name, easyType, CODE) CODE -//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\ -// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\ -// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\ +//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\ +// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\ +// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\ // CODE\ // EASY_UNIQUE_BLOCK(__LINE__).finish();\ // thread_storage.storeBlock(EASY_UNIQUE_BLOCK(__LINE__)) From 68ee40a5ad9f2ab587e1916bcc5b54751d2671f8 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Tue, 6 Sep 2016 22:23:55 +0300 Subject: [PATCH 27/37] Replace tab to whitespaces --- profiler_gui/blocks_tree_widget.cpp | 32 ++--- profiler_gui/blocks_tree_widget.h | 2 +- profiler_gui/globals.h | 4 +- profiler_gui/main.cpp | 24 ++-- profiler_gui/main_window.cpp | 36 +++--- profiler_gui/main_window.h | 2 +- reader/CMakeLists.txt | 6 +- reader/main.cpp | 84 ++++++------- sample/CMakeLists.txt | 8 +- sample/main.cpp | 186 ++++++++++++++-------------- src/CMakeLists.txt | 20 +-- 11 files changed, 202 insertions(+), 202 deletions(-) diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index d5e5201..3418eed 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -134,7 +134,7 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent) EasyTreeWidget::~EasyTreeWidget() { - saveSettings(); + saveSettings(); delete m_progress; } @@ -298,10 +298,10 @@ void EasyTreeWidget::clearSilent(bool _global) for (int i = topLevelItemCount() - 1; i >= 0; --i) topLevelItems.push_back(takeTopLevelItem(i)); - auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) { - for (auto item : _items) - delete item; - }, ::std::move(topLevelItems)); + auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) { + for (auto item : _items) + delete item; + }, ::std::move(topLevelItems)); deleter_thread.detach(); //clear(); @@ -403,12 +403,12 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) auto hidemenu = menu.addMenu("Select columns"); auto hdr = headerItem(); - for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) + for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) { auto columnAction = new QAction(hdr->text(i), nullptr); columnAction->setData(i); columnAction->setCheckable(true); - columnAction->setChecked(!isColumnHidden(i)); + columnAction->setChecked(!isColumnHidden(i)); connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn); hidemenu->addAction(columnAction); } @@ -434,7 +434,7 @@ void EasyTreeWidget::moveEvent(QMoveEvent* _event) void EasyTreeWidget::alignProgressBar() { - auto pos = mapToGlobal(rect().center()); + auto pos = mapToGlobal(rect().center()); m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1)); } @@ -694,17 +694,17 @@ void EasyTreeWidget::loadSettings() void EasyTreeWidget::saveSettings() { - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); - settings.beginGroup("tree_widget"); + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("tree_widget"); - settings.setValue("color_rows", m_bColorRows); + settings.setValue("color_rows", m_bColorRows); - for (int i = 0; i < columnCount(); i++) - { - settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i)); - } + for (int i = 0; i < columnCount(); i++) + { + settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i)); + } - settings.endGroup(); + settings.endGroup(); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index f5d2dbd..dd2ba85 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -117,7 +117,7 @@ private slots: protected: void loadSettings(); - void saveSettings(); + void saveSettings(); void alignProgressBar(); }; // END of class EasyTreeWidget. diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 1116a81..30357b9 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -43,8 +43,8 @@ namespace profiler_gui { - const QString ORGANAZATION_NAME = "EasyProfiler"; - const QString APPLICATION_NAME = "Easy profiler gui application"; + const QString ORGANAZATION_NAME = "EasyProfiler"; + const QString APPLICATION_NAME = "Easy profiler gui application"; const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0); const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060; diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index f38a574..43f77b7 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -39,27 +39,27 @@ int main(int argc, char **argv) { - QApplication app(argc, argv); + QApplication app(argc, argv); - //QFileSystemModel *model = new QFileSystemModel; - //model->setRootPath(QDir::currentPath()); -// const char* filename = 0; + //QFileSystemModel *model = new QFileSystemModel; + //model->setRootPath(QDir::currentPath()); +// const char* filename = 0; // if(argc > 1 && argv[1]){ -// filename = argv[1]; +// filename = argv[1]; // }else{ -// return 255; -// } +// return 255; +// } // QFile file(filename); -// file.open(QIODevice::ReadOnly); +// file.open(QIODevice::ReadOnly); // TreeModel model(file.readAll()); -// file.close(); +// file.close(); -// QTreeView *tree = new QTreeView(); -// tree->setModel(&model); +// QTreeView *tree = new QTreeView(); +// tree->setModel(&model); // -// tree->show(); +// tree->show(); auto now = ::std::chrono::duration_cast(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1; srand((unsigned int)now); diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index e7ddfa0..527dda1 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -17,20 +17,20 @@ * : * : * * ----------------- : -* license : 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 +* license : 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 . ************************************************************************/ @@ -387,10 +387,10 @@ void EasyMainWindow::loadGeometry() void EasyMainWindow::saveSettingsAndGeometry() { - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); - settings.beginGroup("main"); + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("main"); - settings.setValue("geometry", this->saveGeometry()); + settings.setValue("geometry", this->saveGeometry()); settings.setValue("last_file", m_lastFile); settings.setValue("chrono_text_position", static_cast(EASY_GLOBALS.chrono_text_position)); settings.setValue("draw_graphics_items_borders", EASY_GLOBALS.draw_graphics_items_borders); @@ -399,7 +399,7 @@ void EasyMainWindow::saveSettingsAndGeometry() settings.setValue("bind_scene_and_tree_expand_status", EASY_GLOBALS.bind_scene_and_tree_expand_status); settings.setValue("encoding", QTextCodec::codecForLocale()->name()); - settings.endGroup(); + settings.endGroup(); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 752f39e..2be7882 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -127,7 +127,7 @@ private: void loadSettings(); void loadGeometry(); - void saveSettingsAndGeometry(); + void saveSettingsAndGeometry(); }; // END of class EasyMainWindow. diff --git a/reader/CMakeLists.txt b/reader/CMakeLists.txt index 5f85ee4..d25ff8d 100644 --- a/reader/CMakeLists.txt +++ b/reader/CMakeLists.txt @@ -1,17 +1,17 @@ project(profiler_reader) set(CPP_FILES - main.cpp + main.cpp ) set(SOURCES - ${CPP_FILES} + ${CPP_FILES} ) add_executable(${PROJECT_NAME} ${SOURCES}) if(UNIX) - set(SPEC_LIB pthread) + set(SPEC_LIB pthread) endif(UNIX) target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB}) diff --git a/reader/main.cpp b/reader/main.cpp index 6170bcb..f61ac49 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -16,57 +16,57 @@ class TreePrinter { - struct Info{ - std::string name; - std::string info; - }; - std::vector m_rows; + struct Info{ + std::string name; + std::string info; + }; + std::vector m_rows; public: - TreePrinter(){ + TreePrinter(){ - } - void addNewRow(int level) - { + } + void addNewRow(int level) + { - } + } - void printTree() - { - for (auto& row : m_rows){ - std::cout << row.name << " " << row.info << std::endl; - } - } + void printTree() + { + for (auto& row : m_rows){ + std::cout << row.name << " " << row.info << std::endl; + } + } }; void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int level = 0, profiler::timestamp_t parent_dur = 0, profiler::timestamp_t root_dur = 0) { - // - //if (tree.node){ - // auto duration = tree.node->block()->duration(); - // float duration_ms = duration / 1e6f; - // float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f; - // float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f; - // std::cout << std::string(level, '\t') << tree.node->getName() - // << std::string(5 - level, '\t') - // /*<< std::string(level, ' ')*/ << percent << "%| " - // << rpercent << "%| " - // << duration_ms << " ms" - // << std::endl; - // if (root_dur == 0){ - // root_dur = tree.node->block()->duration(); - // } - //} - //else{ - // root_dur = 0; - //} - // + // + //if (tree.node){ + // auto duration = tree.node->block()->duration(); + // float duration_ms = duration / 1e6f; + // float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f; + // float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f; + // std::cout << std::string(level, '\t') << tree.node->getName() + // << std::string(5 - level, '\t') + // /*<< std::string(level, ' ')*/ << percent << "%| " + // << rpercent << "%| " + // << duration_ms << " ms" + // << std::endl; + // if (root_dur == 0){ + // root_dur = tree.node->block()->duration(); + // } + //} + //else{ + // root_dur = 0; + //} + // - //for (const auto& i : tree.children){ + //for (const auto& i : tree.children){ - // printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur); - //} + // printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur); + //} } int main(int argc, char* argv[]) @@ -120,9 +120,9 @@ int main(int argc, char* argv[]) std::cout << "Blocks count: " << blocks_counter << std::endl; std::cout << "dT = " << std::chrono::duration_cast(end - start).count() << " usec" << std::endl; //for (const auto & i : threaded_trees){ - // TreePrinter p; - // std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl; - // printTree(p, i.second.tree,-1); + // TreePrinter p; + // std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl; + // printTree(p, i.second.tree,-1); //} if (!dump_filename.empty()) diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index dcb08bf..7106410 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -1,22 +1,22 @@ project(profiler_sample) set(CPP_FILES - main.cpp + main.cpp ) set(SOURCES - ${CPP_FILES} + ${CPP_FILES} ) add_executable(${PROJECT_NAME} ${SOURCES}) set(DISABLED_PROFILER_NAME - "${PROJECT_NAME}_disabled_profiler" + "${PROJECT_NAME}_disabled_profiler" ) add_executable(${DISABLED_PROFILER_NAME} ${SOURCES}) if(UNIX) - set(SPEC_LIB pthread) + set(SPEC_LIB pthread) endif(UNIX) target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB}) diff --git a/sample/main.cpp b/sample/main.cpp index 32de060..e9f33c3 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -26,9 +26,9 @@ void localSleep(int magic=200000) } void loadingResources(){ - EASY_FUNCTION(profiler::colors::Darkcyan); + EASY_FUNCTION(profiler::colors::Darkcyan); localSleep(); -// std::this_thread::sleep_for(std::chrono::milliseconds(50)); +// std::this_thread::sleep_for(std::chrono::milliseconds(50)); } void prepareMath(){ @@ -37,7 +37,7 @@ void prepareMath(){ for (int i = 0; i < OBJECTS; ++i) intarray[i] = i * i; delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(3)); + //std::this_thread::sleep_for(std::chrono::milliseconds(3)); } void calcIntersect(){ @@ -51,7 +51,7 @@ void calcIntersect(){ intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5; } delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(4)); + //std::this_thread::sleep_for(std::chrono::milliseconds(4)); } double multModel(double i) @@ -81,7 +81,7 @@ void calcBrain(){ for (int i = 0; i < OBJECTS; ++i) intarray[i] = calcSubbrain(i) + double(i * 180 / 3); delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(3)); + //std::this_thread::sleep_for(std::chrono::milliseconds(3)); } void calculateBehavior(){ @@ -92,14 +92,14 @@ void calculateBehavior(){ void modellingStep(){ EASY_FUNCTION(profiler::colors::Navy); - prepareMath(); - calculateBehavior(); + prepareMath(); + calculateBehavior(); } void prepareRender(){ EASY_FUNCTION(profiler::colors::Darkred); localSleep(); - //std::this_thread::sleep_for(std::chrono::milliseconds(8)); + //std::this_thread::sleep_for(std::chrono::milliseconds(8)); } @@ -121,168 +121,168 @@ void calculatePhysics(){ for (int i = 0; i < OBJECTS; ++i) intarray[i] = calcPhysicForObject(i); delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(8)); + //std::this_thread::sleep_for(std::chrono::milliseconds(8)); } void frame(){ EASY_FUNCTION(profiler::colors::Magenta); - prepareRender(); - calculatePhysics(); + prepareRender(); + calculatePhysics(); } void loadingResourcesThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); EASY_THREAD("Resource loading"); - for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ - loadingResources(); - EASY_EVENT("Resources Loading!", profiler::colors::Cyan); + for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ + loadingResources(); + EASY_EVENT("Resources Loading!", profiler::colors::Cyan); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } + } } void modellingThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); EASY_THREAD("Modelling"); - for (int i = 0; i < RENDER_SPEPS; i++){ - modellingStep(); + for (int i = 0; i < RENDER_SPEPS; i++){ + modellingStep(); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } + } } void renderThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); EASY_THREAD("Render"); - for (int i = 0; i < MODELLING_STEPS; i++){ - frame(); + for (int i = 0; i < MODELLING_STEPS; i++){ + frame(); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } + } } void four() { EASY_FUNCTION(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(37)); + std::this_thread::sleep_for(std::chrono::milliseconds(37)); } void five() { EASY_FUNCTION(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } void six() { EASY_FUNCTION(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(42)); + std::this_thread::sleep_for(std::chrono::milliseconds(42)); } void three() { EASY_FUNCTION(profiler::colors::Red); - four(); - five(); - six(); + four(); + five(); + six(); } void seven() { EASY_FUNCTION(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(147)); + std::this_thread::sleep_for(std::chrono::milliseconds(147)); } void two() { EASY_FUNCTION(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(26)); + std::this_thread::sleep_for(std::chrono::milliseconds(26)); } void one() { EASY_FUNCTION(profiler::colors::Red); - two(); - three(); - seven(); + two(); + three(); + seven(); } /* one - two - three - four - five - six - seven + two + three + four + five + six + seven */ int main(int argc, char* argv[]) { - if (argc > 1 && argv[1]){ - OBJECTS = std::atoi(argv[1]); - } - if (argc > 2 && argv[2]){ - RENDER_SPEPS = std::atoi(argv[2]); - } - if (argc > 3 && argv[3]){ - MODELLING_STEPS = std::atoi(argv[3]); - } - if (argc > 4 && argv[4]){ - RESOURCE_LOADING_COUNT = std::atoi(argv[4]); - } + if (argc > 1 && argv[1]){ + OBJECTS = std::atoi(argv[1]); + } + if (argc > 2 && argv[2]){ + RENDER_SPEPS = std::atoi(argv[2]); + } + if (argc > 3 && argv[3]){ + MODELLING_STEPS = std::atoi(argv[3]); + } + if (argc > 4 && argv[4]){ + RESOURCE_LOADING_COUNT = std::atoi(argv[4]); + } - std::cout << "Objects count: " << OBJECTS << std::endl; - std::cout << "Render steps: " << RENDER_SPEPS << std::endl; - std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; - std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; + std::cout << "Objects count: " << OBJECTS << std::endl; + std::cout << "Render steps: " << RENDER_SPEPS << std::endl; + std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; + std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; - auto start = std::chrono::system_clock::now(); - EASY_PROFILER_ENABLE; - EASY_MAIN_THREAD; - //one(); - //one(); - /**/ - std::vector threads; + auto start = std::chrono::system_clock::now(); + EASY_PROFILER_ENABLE; + EASY_MAIN_THREAD; + //one(); + //one(); + /**/ + std::vector threads; - std::thread render = std::thread(renderThread); - std::thread modelling = std::thread(modellingThread); + std::thread render = std::thread(renderThread); + std::thread modelling = std::thread(modellingThread); - - for(int i=0; i < 3; i++){ - threads.emplace_back(std::thread(loadingResourcesThread)); - threads.emplace_back(std::thread(renderThread)); - threads.emplace_back(std::thread(modellingThread)); - } - { - std::lock_guard lk(cv_m); - g_i = 1; - } - cv.notify_all(); + + for(int i=0; i < 3; i++){ + threads.emplace_back(std::thread(loadingResourcesThread)); + threads.emplace_back(std::thread(renderThread)); + threads.emplace_back(std::thread(modellingThread)); + } + { + std::lock_guard lk(cv_m); + g_i = 1; + } + cv.notify_all(); for (int i = 0; i < RENDER_SPEPS; ++i) { modellingStep(); localSleep(1200000); } - render.join(); - modelling.join(); - for(auto& t : threads){ - t.join(); - } - /**/ + render.join(); + modelling.join(); + for(auto& t : threads){ + t.join(); + } + /**/ - auto end = std::chrono::system_clock::now(); - auto elapsed = - std::chrono::duration_cast(end - start); + auto end = std::chrono::system_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); - std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl; + std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl; - auto blocks_count = profiler::dumpBlocksToFile("test.prof"); + auto blocks_count = profiler::dumpBlocksToFile("test.prof"); - std::cout << "Blocks count: " << blocks_count << std::endl; + std::cout << "Blocks count: " << blocks_count << std::endl; - return 0; + return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3eaa04f..63499d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,27 +1,27 @@ project(easy_profiler) set(CPP_FILES - block.cpp - profile_manager.cpp - reader.cpp + block.cpp + profile_manager.cpp + reader.cpp event_trace_win.cpp ) set(H_FILES - ${ROOT}/include/profiler/profiler.h - ${ROOT}/include/profiler/reader.h + ${ROOT}/include/profiler/profiler.h + ${ROOT}/include/profiler/reader.h ${ROOT}/include/profiler/event_trace_status.h - profile_manager.h - spin_lock.h + profile_manager.h + spin_lock.h event_trace_win.h ) set(SOURCES - ${CPP_FILES} - ${H_FILES} + ${CPP_FILES} + ${H_FILES} ) add_definitions( - -D_BUILD_PROFILER + -D_BUILD_PROFILER ) add_library(${PROJECT_NAME} SHARED ${SOURCES}) From 10bb3da45b1e6740f4d841eb4e56a53d4779ccd1 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 23:03:05 +0300 Subject: [PATCH 28/37] (profiler_core) !! Non-blocking API using Thread-Local-Storage (threal_local or __declspec(thread) or __thread) --- include/profiler/profiler.h | 89 +++++++++++++------------ src/event_trace_win.cpp | 6 +- src/profile_manager.cpp | 119 ++++++++++++++++----------------- src/profile_manager.h | 39 ++++++----- src/spin_lock.h | 128 +++++++++++++++++++++++------------- 5 files changed, 204 insertions(+), 177 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 55e9b74..42c2887 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -20,7 +20,23 @@ along with this program.If not, see . #define EASY_PROFILER____H_______ #ifdef _WIN32 -#define __func__ __FUNCTION__ +# define __func__ __FUNCTION__ +# if defined(_MSC_VER) && _MSC_VER <= 1800 +// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead. +# define EASY_THREAD_LOCAL __declspec(thread) +# endif +#elif defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4) +// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead. +# define EASY_THREAD_LOCAL __thread +# endif +#endif + +// TODO: Check thread_local support for Clang! + +#ifndef EASY_THREAD_LOCAL +# define EASY_THREAD_LOCAL thread_local +# define EASY_THREAD_LOCAL_CPP11 #endif #if defined ( __clang__ ) @@ -80,9 +96,9 @@ Block will be automatically completed by destructor. \ingroup profiler */ #define EASY_BLOCK(name, ...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro of beginning of block with function name and custom color. @@ -105,9 +121,9 @@ Name of the block automatically created with function name. \ingroup profiler */ #define EASY_FUNCTION(...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(__func__, __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), "");\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro of completion of last nearest open block. @@ -145,9 +161,9 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION. \ingroup profiler */ #define EASY_EVENT(name, ...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro enabling profiler @@ -166,10 +182,15 @@ If this thread has been already named then nothing changes. \ingroup profiler */ -#ifdef _WIN32 -#define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); +#ifdef EASY_THREAD_LOCAL_CPP11 +#define EASY_THREAD(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = \ + ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #else -#define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__); +#define EASY_THREAD(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\ + if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #endif /** Macro of naming main thread. @@ -211,20 +232,9 @@ class ThreadStorage; namespace profiler { class Block; - class StaticBlockDescriptor; - - extern "C"{ - void PROFILER_API beginBlock(Block& _block); - void PROFILER_API endBlock(); - void PROFILER_API setEnabled(bool isEnable); - uint32_t PROFILER_API dumpBlocksToFile(const char* filename); - void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); - void PROFILER_API setContextSwitchLogFilename(const char* name); - PROFILER_API const char* getContextSwitchLogFilename(); - } - typedef uint64_t timestamp_t; - typedef uint32_t thread_id_t; + typedef uint64_t timestamp_t; + typedef uint32_t thread_id_t; typedef uint32_t block_id_t; enum BlockType : uint8_t @@ -237,6 +247,17 @@ namespace profiler { BLOCK_TYPES_NUMBER }; typedef BlockType block_type_t; + + extern "C" { + PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); + PROFILER_API void beginBlock(Block& _block); + PROFILER_API void endBlock(); + PROFILER_API void setEnabled(bool isEnable); + PROFILER_API uint32_t dumpBlocksToFile(const char* filename); + PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); + PROFILER_API void setContextSwitchLogFilename(const char* name); + PROFILER_API const char* getContextSwitchLogFilename(); + } #pragma pack(push,1) class PROFILER_API BaseBlockDescriptor @@ -322,28 +343,6 @@ namespace profiler { ////////////////////////////////////////////////////////////////////// - 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 = DefaultBlockColor); - inline block_id_t id() const { return m_id; } - }; - -#ifndef _WIN32 - struct PROFILER_API ThreadNameSetter final - { - ThreadNameSetter(const char* _name, const char* _filename, const char* _funcname, int _line) - { - setThreadName(_name, _filename, _funcname, _line); - } - }; -#endif - - ////////////////////////////////////////////////////////////////////// - } // END of namespace profiler. #if defined ( __clang__ ) diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index 2480434..804d4f3 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -48,9 +48,9 @@ namespace profiler { auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart); - static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); - MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); - MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); + static const auto desc = MANAGER.addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, desc); + MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 4dc6bb5..9b482c0 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -10,16 +10,6 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -#define EASY_INTERNAL_BLOCK(name, easyType, CODE) CODE -//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\ -// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\ -// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\ -// CODE\ -// EASY_UNIQUE_BLOCK(__LINE__).finish();\ -// thread_storage.storeBlock(EASY_UNIQUE_BLOCK(__LINE__)) - -////////////////////////////////////////////////////////////////////////// - using namespace profiler; #ifdef _WIN32 @@ -29,14 +19,19 @@ extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; //auto& MANAGER = ProfileManager::instance(); #define MANAGER ProfileManager::instance() -extern "C"{ +extern "C" { - void PROFILER_API endBlock() + PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) + { + return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color); + } + + PROFILER_API void endBlock() { MANAGER.endBlock(); } - void PROFILER_API setEnabled(bool isEnable) + PROFILER_API void setEnabled(bool isEnable) { MANAGER.setEnabled(isEnable); #ifdef _WIN32 @@ -47,22 +42,22 @@ extern "C"{ #endif } - void PROFILER_API beginBlock(Block& _block) + PROFILER_API void beginBlock(Block& _block) { MANAGER.beginBlock(_block); } - uint32_t PROFILER_API dumpBlocksToFile(const char* filename) + PROFILER_API uint32_t dumpBlocksToFile(const char* filename) { return MANAGER.dumpBlocksToFile(filename); } - void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line) + PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line) { return MANAGER.setThreadName(name, filename, _funcname, line); } - void PROFILER_API setContextSwitchLogFilename(const char* name) + PROFILER_API void setContextSwitchLogFilename(const char* name) { return MANAGER.setContextSwitchLogFilename(name); } @@ -84,12 +79,6 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) ////////////////////////////////////////////////////////////////////////// -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)) -{ - -} - BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color) : m_line(_line) , m_type(_block_type) @@ -136,6 +125,8 @@ void ThreadStorage::clearClosed() ////////////////////////////////////////////////////////////////////////// +EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr; + // #ifdef _WIN32 // LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL; // LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) @@ -175,32 +166,30 @@ void ProfileManager::beginBlock(Block& _block) if (!m_isEnabled) return; - EASY_INTERNAL_BLOCK("Easy.Spin", profiler::BLOCK_TYPE_BLOCK,\ - auto& thread_storage = threadStorage(getCurrentThreadId());\ - ); + if (THREAD_STORAGE == nullptr) + THREAD_STORAGE = &threadStorage(getCurrentThreadId()); - EASY_INTERNAL_BLOCK("Easy.Insert", profiler::BLOCK_TYPE_BLOCK,\ - if (!_block.isFinished()) - thread_storage.blocks.openedList.emplace(_block); - else - thread_storage.storeBlock(_block);\ - ); + if (!_block.isFinished()) + THREAD_STORAGE->blocks.openedList.emplace(_block); + else + THREAD_STORAGE->storeBlock(_block); } -void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage != nullptr) - thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); + auto ts = findThreadStorage(_thread_id); + if (ts != nullptr) + ts->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } -void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage != nullptr){ + auto ts = findThreadStorage(_thread_id); + if (ts != nullptr) + { profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); lastBlock.finish(_time); - thread_storage->storeCSwitch(lastBlock); + ts->storeCSwitch(lastBlock); } } @@ -209,29 +198,28 @@ void ProfileManager::endBlock() if (!m_isEnabled) return; - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.blocks.openedList.empty()) + if (THREAD_STORAGE->blocks.openedList.empty()) return; - Block& lastBlock = thread_storage.blocks.openedList.top(); + Block& lastBlock = THREAD_STORAGE->blocks.openedList.top(); if (!lastBlock.isFinished()) lastBlock.finish(); - thread_storage.storeBlock(lastBlock); - thread_storage.blocks.openedList.pop(); + THREAD_STORAGE->storeBlock(lastBlock); + THREAD_STORAGE->blocks.openedList.pop(); } -void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) +void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage == nullptr || thread_storage->sync.openedList.empty()) + auto ts = findThreadStorage(_thread_id); + if (ts == nullptr || ts->sync.openedList.empty()) return; - Block& lastBlock = thread_storage->sync.openedList.top(); + Block& lastBlock = ts->sync.openedList.top(); lastBlock.finish(_endtime); - thread_storage->storeCSwitch(lastBlock); - thread_storage->sync.openedList.pop(); + ts->storeCSwitch(lastBlock); + ts->sync.openedList.pop(); } void ProfileManager::setEnabled(bool isEnable) @@ -283,11 +271,11 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) if(infile.is_open()) { - while (infile >> timestamp >> thread_from >> thread_to ) + static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + while (infile >> timestamp >> thread_from >> thread_to) { - static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); - _cswitchBeginBlock(timestamp, desc.id(), thread_from); - _cswitchEndBlock(thread_to, timestamp); + beginContextSwitch(thread_from, timestamp, desc); + endContextSwitch(thread_to, timestamp); } } @@ -385,15 +373,22 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) return blocks_number; } -void ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line) +const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line) { - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.named) - return; + if (THREAD_STORAGE == nullptr) + { + THREAD_STORAGE = &threadStorage(getCurrentThreadId()); + } - const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); - thread_storage.storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); - thread_storage.named = true; + if (!THREAD_STORAGE->named) + { + const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); + THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); + THREAD_STORAGE->name = name; + THREAD_STORAGE->named = true; + } + + return THREAD_STORAGE->name.c_str(); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.h b/src/profile_manager.h index 7244e43..2408471 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -26,8 +26,8 @@ along with this program.If not, see . #include #include #include -#include #include +#include #include ////////////////////////////////////////////////////////////////////////// @@ -44,10 +44,10 @@ along with this program.If not, see . inline uint32_t getCurrentThreadId() { #ifdef _WIN32 - return (uint32_t)::GetCurrentThreadId(); + return (uint32_t)::GetCurrentThreadId(); #else - thread_local static pid_t x = syscall(__NR_gettid); - thread_local static uint32_t _id = (uint32_t)x;//std::hash()(std::this_thread::get_id()); + EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid); + EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash()(std::this_thread::get_id()); return _id; #endif } @@ -150,6 +150,7 @@ public: BlocksList, SIZEOF_CSWITCH * (uint16_t)1024U> blocks; BlocksList sync; + std::string name; bool named = false; void storeBlock(const profiler::Block& _block); @@ -161,8 +162,6 @@ public: class ProfileManager final { - friend profiler::StaticBlockDescriptor; - ProfileManager(); ProfileManager(const ProfileManager& p) = delete; ProfileManager& operator=(const ProfileManager&) = delete; @@ -185,11 +184,20 @@ public: static ProfileManager& instance(); ~ProfileManager(); + template + uint32_t addBlockDescriptor(TArgs ... _args) + { + guard_lock_t lock(m_storedSpin); + const auto id = static_cast(m_descriptors.size()); + m_descriptors.emplace_back(m_usedMemorySize, _args...); + return id; + } + void beginBlock(profiler::Block& _block); void endBlock(); void setEnabled(bool isEnable); uint32_t dumpBlocksToFile(const char* filename); - void setThreadName(const char* name, const char* filename, const char* _funcname, int line); + const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); void setContextSwitchLogFilename(const char* name) { @@ -201,28 +209,19 @@ public: return m_csInfoFilename.c_str(); } - void _cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); - void _cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); - void _cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); + void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id); + void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id); + void endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); private: - template - uint32_t addBlockDescriptor(TArgs ... _args) - { - guard_lock_t lock(m_storedSpin); - const auto id = static_cast(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]; } - ThreadStorage* _threadStorage(profiler::thread_id_t _thread_id) + ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id) { guard_lock_t lock(m_spin); auto it = m_threads.find(_thread_id); diff --git a/src/spin_lock.h b/src/spin_lock.h index 803ef51..21ab16c 100644 --- a/src/spin_lock.h +++ b/src/spin_lock.h @@ -16,53 +16,87 @@ 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______ +#ifndef EASY_PROFILER__SPIN_LOCK__________H______ +#define EASY_PROFILER__SPIN_LOCK__________H______ +#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag + +#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION) +#include +#else #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: - explicit 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 + +namespace profiler { + +#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION) + // std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag... + // By the way, Windows critical sections are slower than std::atomic_flag on Unix. + class spin_lock final { CRITICAL_SECTION m_lock; public: + + void lock() { + EnterCriticalSection(&m_lock); + } + + void unlock() { + LeaveCriticalSection(&m_lock); + } + + spin_lock() { + InitializeCriticalSection(&m_lock); + } + + ~spin_lock() { + DeleteCriticalSection(&m_lock); + } + }; +#else + // std::atomic_flag on Unix works fine and very fast (almost instant!) + class spin_lock final { ::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(); + } + }; +#endif + + template + class guard_lock final + { + T& m_lock; + bool m_isLocked = false; + + public: + + explicit guard_lock(T& m) : m_lock(m) { + m_lock.lock(); + m_isLocked = true; + } + + ~guard_lock() { + unlock(); + } + + inline void unlock() { + if (m_isLocked) { + m_lock.unlock(); + m_isLocked = false; + } + } + }; + +} // END of namespace profiler. + +#ifdef EASY_USE_CRITICAL_SECTION +# undef EASY_USE_CRITICAL_SECTION +#endif + +#endif // EASY_PROFILER__SPIN_LOCK__________H______ From 449610028a833a686e9012dbd56c0eda7280a3d4 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 6 Sep 2016 23:16:15 +0300 Subject: [PATCH 29/37] (profiler_core) Linux build: avoid gcc warning about unused variable --- include/profiler/profiler.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 42c2887..135ad91 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -182,16 +182,10 @@ If this thread has been already named then nothing changes. \ingroup profiler */ -#ifdef EASY_THREAD_LOCAL_CPP11 -#define EASY_THREAD(name)\ - EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = \ - ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); -#else #define EASY_THREAD(name)\ EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\ if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\ EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); -#endif /** Macro of naming main thread. From d39fecaac1f755319ad6b9608aa6b298a09b9461 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:29:37 +0300 Subject: [PATCH 30/37] Clang build --- include/profiler/profiler.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 135ad91..1cd489f 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -26,13 +26,21 @@ along with this program.If not, see . # define EASY_THREAD_LOCAL __declspec(thread) # endif #elif defined(__GNUC__) +#ifndef __clang__ # if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4) // There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead. # define EASY_THREAD_LOCAL __thread +#endif # endif +#if defined ( __clang__ ) +# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3) +# define EASY_THREAD_LOCAL __thread +#endif #endif -// TODO: Check thread_local support for Clang! +#endif + +// TODO: Check thread local support for clanv earlier than 3.3 #ifndef EASY_THREAD_LOCAL # define EASY_THREAD_LOCAL thread_local From cd395073898510b36914db11e20e63f4da59440d Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:32:14 +0300 Subject: [PATCH 31/37] Replace tab to whitespaces --- CMakeLists.txt | 12 ++++---- include/profiler/profiler.h | 56 ++++++++++++++++++------------------- src/block.cpp | 16 +++++------ src/profile_manager.cpp | 18 ++++++------ src/profile_manager.h | 6 ++-- 5 files changed, 54 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3367ed5..78876ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ project(profiling_tool) cmake_minimum_required(VERSION 2.8) set( - ROOT - ${CMAKE_CURRENT_LIST_DIR} + ROOT + ${CMAKE_CURRENT_LIST_DIR} ) set(OUTPUT_DIR @@ -23,16 +23,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ) include_directories( - include + include ) if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" ) else() - add_definitions( - -D_CRT_SECURE_NO_WARNINGS - ) + add_definitions( + -D_CRT_SECURE_NO_WARNINGS + ) endif(UNIX) add_subdirectory(src) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 1cd489f..3720dfd 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -84,19 +84,19 @@ namespace profiler { /** Macro of beginning of block with custom name and color. \code - #include "profiler/profiler.h" - void foo() - { - // some code ... - if(something){ - EASY_BLOCK("Calling bar()"); // Block with default color - bar(); - } + #include "profiler/profiler.h" + void foo() + { + // some code ... + if(something){ + EASY_BLOCK("Calling bar()"); // Block with default color + bar(); + } else{ EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block baz(); } - } + } \endcode Block will be automatically completed by destructor. @@ -112,11 +112,11 @@ Block will be automatically completed by destructor. /** Macro of beginning of block with function name and custom color. \code - #include "profiler/profiler.h" - void foo(){ - EASY_FUNCTION(); // Block with name="foo" and default color - //some code... - } + #include "profiler/profiler.h" + void foo(){ + EASY_FUNCTION(); // Block with name="foo" and default color + //some code... + } void bar(){ EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar" @@ -142,12 +142,12 @@ int foo() { // some code ... - int sum = 0; - EASY_BLOCK("Calculating sum"); - for (int i = 0; i < 10; ++i){ - sum += i; - } - EASY_END_BLOCK; + int sum = 0; + EASY_BLOCK("Calculating sum"); + for (int i = 0; i < 10; ++i){ + sum += i; + } + EASY_END_BLOCK; // some antoher code here ... @@ -219,10 +219,10 @@ This is only for user comfort. There is no difference for EasyProfiler GUI betwe #include "profiler/profiler_colors.h" #ifdef _WIN32 -#ifdef _BUILD_PROFILER -#define PROFILER_API __declspec(dllexport) +#ifdef _BUILD_PROFILER +#define PROFILER_API __declspec(dllexport) #else -#define PROFILER_API __declspec(dllimport) +#define PROFILER_API __declspec(dllimport) #endif #else #define PROFILER_API @@ -233,7 +233,7 @@ class ThreadStorage; namespace profiler { - class Block; + class Block; typedef uint64_t timestamp_t; typedef uint32_t thread_id_t; @@ -249,8 +249,8 @@ namespace profiler { BLOCK_TYPES_NUMBER }; typedef BlockType block_type_t; - - extern "C" { + + extern "C" { PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); PROFILER_API void beginBlock(Block& _block); PROFILER_API void endBlock(); @@ -259,8 +259,8 @@ namespace profiler { PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); PROFILER_API void setContextSwitchLogFilename(const char* name); PROFILER_API const char* getContextSwitchLogFilename(); - } - + } + #pragma pack(push,1) class PROFILER_API BaseBlockDescriptor { diff --git a/src/block.cpp b/src/block.cpp index 140f6b6..1fca4cc 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -38,17 +38,17 @@ decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; Que inline timestamp_t getCurrentTime() { #ifdef _WIN32 - //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx - LARGE_INTEGER elapsedMicroseconds; - if (!QueryPerformanceCounter(&elapsedMicroseconds)) - return 0; + //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx + LARGE_INTEGER elapsedMicroseconds; + if (!QueryPerformanceCounter(&elapsedMicroseconds)) + return 0; //elapsedMicroseconds.QuadPart *= 1000000000LL; //elapsedMicroseconds.QuadPart /= CPU_FREQUENCY; - return (timestamp_t)elapsedMicroseconds.QuadPart; + return (timestamp_t)elapsedMicroseconds.QuadPart; #else - std::chrono::time_point time_point; - time_point = std::chrono::time_point_cast(std::chrono::system_clock::now()); - return time_point.time_since_epoch().count(); + std::chrono::time_point time_point; + time_point = std::chrono::time_point_cast(std::chrono::system_clock::now()); + return time_point.time_since_epoch().count(); #endif } diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 48dd0e7..3a365e8 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -68,19 +68,19 @@ extern "C" { } PROFILER_API void beginBlock(Block& _block) - { + { MANAGER.beginBlock(_block); - } + } - PROFILER_API uint32_t dumpBlocksToFile(const char* filename) - { + PROFILER_API uint32_t dumpBlocksToFile(const char* filename) + { return MANAGER.dumpBlocksToFile(filename); - } + } PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line) - { + { return MANAGER.setThreadName(name, filename, _funcname, line); - } + } PROFILER_API void setContextSwitchLogFilename(const char* name) { @@ -175,7 +175,7 @@ ProfileManager::ProfileManager() ProfileManager::~ProfileManager() { - //dumpBlocksToFile("test.prof"); + //dumpBlocksToFile("test.prof"); } ProfileManager& ProfileManager::instance() @@ -249,7 +249,7 @@ void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler void ProfileManager::setEnabled(bool isEnable) { - m_isEnabled = isEnable; + m_isEnabled = isEnable; } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.h b/src/profile_manager.h index 2408471..4851c59 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -182,7 +182,7 @@ class ProfileManager final public: static ProfileManager& instance(); - ~ProfileManager(); + ~ProfileManager(); template uint32_t addBlockDescriptor(TArgs ... _args) @@ -194,8 +194,8 @@ public: } void beginBlock(profiler::Block& _block); - void endBlock(); - void setEnabled(bool isEnable); + void endBlock(); + void setEnabled(bool isEnable); uint32_t dumpBlocksToFile(const char* filename); const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); From 19d757f2317da297599d7eabf1010ad94d7f25de Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:33:10 +0300 Subject: [PATCH 32/37] gcc warning fix --- profiler_gui/graphics_scrollbar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/profiler_gui/graphics_scrollbar.cpp b/profiler_gui/graphics_scrollbar.cpp index 10e1d5b..092adc2 100644 --- a/profiler_gui/graphics_scrollbar.cpp +++ b/profiler_gui/graphics_scrollbar.cpp @@ -490,7 +490,6 @@ void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event) void EasyGraphicsScrollbar::wheelEvent(QWheelEvent* _event) { - qreal deltaSign = _event->delta() < 0 ? -1 : 1; auto w = m_slider->halfwidth() * (_event->delta() < 0 ? ::profiler_gui::SCALING_COEFFICIENT : ::profiler_gui::SCALING_COEFFICIENT_INV); setValue(mapToScene(_event->pos()).x() - m_minimumValue - w); emit wheeled(w * m_windowScale, _event->delta()); From e1d95e0d3b68462d82ffb5c6d0bb46ee50b73596 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:37:13 +0300 Subject: [PATCH 33/37] clang some warning fix --- profiler_gui/blocks_graphics_view.cpp | 2 +- profiler_gui/blocks_graphics_view.h | 2 +- profiler_gui/graphics_scrollbar.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index b920e95..6a9d208 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -84,7 +84,7 @@ const QRgb TIMELINE_BACKGROUND = 0x20303030; const QRgb SELECTED_ITEM_COLOR = 0x000050a0; const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40408040); -const unsigned int TEST_PROGRESSION_BASE = 4; +//const unsigned int TEST_PROGRESSION_BASE = 4; const int FLICKER_INTERVAL = 16; // 60Hz diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 54a27ef..26d57dc 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -211,7 +211,7 @@ public: void setHover(bool _hover); - bool contains(const QPointF& _pos) const; + bool contains(const QPointF& _pos) const override; inline bool hoverIndicator() const { diff --git a/profiler_gui/graphics_scrollbar.cpp b/profiler_gui/graphics_scrollbar.cpp index 092adc2..0cf6c96 100644 --- a/profiler_gui/graphics_scrollbar.cpp +++ b/profiler_gui/graphics_scrollbar.cpp @@ -41,7 +41,7 @@ ////////////////////////////////////////////////////////////////////////// const qreal SCALING_COEFFICIENT = 1.25; -const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT; +//const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT; const int DEFAULT_TOP = -40; const int DEFAULT_HEIGHT = 80; const int INDICATOR_SIZE = 8; From 26fe3ca7e00d1a3442520f74b438a2b6421bfe65 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:40:40 +0300 Subject: [PATCH 34/37] ci clang compiler fix attempt --- src/profile_manager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/profile_manager.h b/src/profile_manager.h index 4851c59..8094f8d 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -156,6 +156,8 @@ public: void storeBlock(const profiler::Block& _block); void storeCSwitch(const profiler::Block& _block); void clearClosed(); + + ThreadStorage() = default; }; ////////////////////////////////////////////////////////////////////////// From 9eb02316ba9d5fe30984c7ee23ac509d4bc5688f Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:45:25 +0300 Subject: [PATCH 35/37] ci clang compiler fix attempt number two =) --- src/profile_manager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/profile_manager.h b/src/profile_manager.h index 8094f8d..2a0fb47 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -104,6 +104,8 @@ class ThreadStorage final template struct BlocksList final { + BlocksList() = default; + class Stack final { //std::stack m_stack; std::vector m_stack; From 6e845eece2a278b53d7b4d11c351b96ec721a1e4 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Wed, 7 Sep 2016 21:48:50 +0300 Subject: [PATCH 36/37] Using Google Material Design colors; * At last, fixed bug with text paint on very large scene scale. Now you can scale the scene up to 10 ns scale! --- include/profiler/profiler.h | 3 +- include/profiler/profiler_colors.h | 446 ++++++++++++++++++++++---- profiler_gui/blocks_graphics_view.cpp | 151 +++++---- profiler_gui/common_types.h | 8 +- profiler_gui/tree_widget_loader.cpp | 12 +- sample/main.cpp | 6 +- src/profile_manager.cpp | 2 +- src/reader.cpp | 2 +- 8 files changed, 491 insertions(+), 139 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 135ad91..b95ff9c 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -259,8 +259,8 @@ namespace profiler { protected: 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 + block_type_t m_type; ///< Type of the block (See BlockType) BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color); @@ -269,7 +269,6 @@ namespace profiler { 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); } }; class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor diff --git a/include/profiler/profiler_colors.h b/include/profiler/profiler_colors.h index e89e95f..8b69439 100644 --- a/include/profiler/profiler_colors.h +++ b/include/profiler/profiler_colors.h @@ -28,76 +28,406 @@ 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 + typedef uint32_t color_t; // Standard four-byte ARGB color format + + //typedef uint8_t color_t; // One-byte RGB color format: RRR-GGG-BB + //typedef uint32_t rgb32_t; // Standard four-byte ARGB 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 .. 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); } - ///< 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 - 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 + + // Google Material Design colors + // See https://material.google.com/style/color.html + + const color_t Red50 = 0xffffebee; + const color_t Red100 = 0xffffcdd2; + const color_t Red200 = 0xffef9a9a; + const color_t Red300 = 0xffe57373; + const color_t Red400 = 0xffef5350; + const color_t Red500 = 0xfff44336; + const color_t Red600 = 0xffe53935; + const color_t Red700 = 0xffd32f2f; + const color_t Red800 = 0xffc62828; + const color_t Red900 = 0xffb71c1c; + const color_t RedA100 = 0xffff8a80; + const color_t RedA200 = 0xffff5252; + const color_t RedA400 = 0xffff1744; + const color_t RedA700 = 0xffd50000; + + const color_t Pink50 = 0xfffce4ec; + const color_t Pink100 = 0xfff8bbd0; + const color_t Pink200 = 0xfff48fb1; + const color_t Pink300 = 0xfff06292; + const color_t Pink400 = 0xffec407a; + const color_t Pink500 = 0xffe91e63; + const color_t Pink600 = 0xffd81b60; + const color_t Pink700 = 0xffc2185b; + const color_t Pink800 = 0xffad1457; + const color_t Pink900 = 0xff880e4f; + const color_t PinkA100 = 0xffff80ab; + const color_t PinkA200 = 0xffff4081; + const color_t PinkA400 = 0xfff50057; + const color_t PinkA700 = 0xffc51162; + + const color_t Purple50 = 0xfff3e5f5; + const color_t Purple100 = 0xffe1bee7; + const color_t Purple200 = 0xffce93d8; + const color_t Purple300 = 0xffba68c8; + const color_t Purple400 = 0xffab47bc; + const color_t Purple500 = 0xff9c27b0; + const color_t Purple600 = 0xff8e24aa; + const color_t Purple700 = 0xff7b1fa2; + const color_t Purple800 = 0xff6a1b9a; + const color_t Purple900 = 0xff4a148c; + const color_t PurpleA100 = 0xffea80fc; + const color_t PurpleA200 = 0xffe040fb; + const color_t PurpleA400 = 0xffd500f9; + const color_t PurpleA700 = 0xffaa00ff; + + const color_t DeepPurple50 = 0xffede7f6; + const color_t DeepPurple100 = 0xffd1c4e9; + const color_t DeepPurple200 = 0xffb39ddb; + const color_t DeepPurple300 = 0xff9575cd; + const color_t DeepPurple400 = 0xff7e57c2; + const color_t DeepPurple500 = 0xff673ab7; + const color_t DeepPurple600 = 0xff5e35b1; + const color_t DeepPurple700 = 0xff512da8; + const color_t DeepPurple800 = 0xff4527a0; + const color_t DeepPurple900 = 0xff311b92; + const color_t DeepPurpleA100 = 0xffb388ff; + const color_t DeepPurpleA200 = 0xff7c4dff; + const color_t DeepPurpleA400 = 0xff651fff; + const color_t DeepPurpleA700 = 0xff6200ea; + + const color_t Indigo50 = 0xffe8eaf6; + const color_t Indigo100 = 0xffc5cae9; + const color_t Indigo200 = 0xff9fa8da; + const color_t Indigo300 = 0xff7986cb; + const color_t Indigo400 = 0xff5c6bc0; + const color_t Indigo500 = 0xff3f51b5; + const color_t Indigo600 = 0xff3949ab; + const color_t Indigo700 = 0xff303f9f; + const color_t Indigo800 = 0xff283593; + const color_t Indigo900 = 0xff1a237e; + const color_t IndigoA100 = 0xff8c9eff; + const color_t IndigoA200 = 0xff536dfe; + const color_t IndigoA400 = 0xff3d5afe; + const color_t IndigoA700 = 0xff304ffe; + + const color_t Blue50 = 0xffe3f2fd; + const color_t Blue100 = 0xffbbdefb; + const color_t Blue200 = 0xff90caf9; + const color_t Blue300 = 0xff64b5f6; + const color_t Blue400 = 0xff42a5f5; + const color_t Blue500 = 0xff2196f3; + const color_t Blue600 = 0xff1e88e5; + const color_t Blue700 = 0xff1976d2; + const color_t Blue800 = 0xff1565c0; + const color_t Blue900 = 0xff0d47a1; + const color_t BlueA100 = 0xff82b1ff; + const color_t BlueA200 = 0xff448aff; + const color_t BlueA400 = 0xff2979ff; + const color_t BlueA700 = 0xff2962ff; + + const color_t LightBlue50 = 0xffe1f5fe; + const color_t LightBlue100 = 0xffb3e5fc; + const color_t LightBlue200 = 0xff81d4fa; + const color_t LightBlue300 = 0xff4fc3f7; + const color_t LightBlue400 = 0xff29b6f6; + const color_t LightBlue500 = 0xff03a9f4; + const color_t LightBlue600 = 0xff039be5; + const color_t LightBlue700 = 0xff0288d1; + const color_t LightBlue800 = 0xff0277bd; + const color_t LightBlue900 = 0xff01579b; + const color_t LightBlueA100 = 0xff80d8ff; + const color_t LightBlueA200 = 0xff40c4ff; + const color_t LightBlueA400 = 0xff00b0ff; + const color_t LightBlueA700 = 0xff0091ea; + + const color_t Cyan50 = 0xffe0f7fa; + const color_t Cyan100 = 0xffb2ebf2; + const color_t Cyan200 = 0xff80deea; + const color_t Cyan300 = 0xff4dd0e1; + const color_t Cyan400 = 0xff26c6da; + const color_t Cyan500 = 0xff00bcd4; + const color_t Cyan600 = 0xff00acc1; + const color_t Cyan700 = 0xff0097a7; + const color_t Cyan800 = 0xff00838f; + const color_t Cyan900 = 0xff006064; + const color_t CyanA100 = 0xff84ffff; + const color_t CyanA200 = 0xff18ffff; + const color_t CyanA400 = 0xff00e5ff; + const color_t CyanA700 = 0xff00b8d4; + + const color_t Teal50 = 0xffe0f2f1; + const color_t Teal100 = 0xffb2dfdb; + const color_t Teal200 = 0xff80cbc4; + const color_t Teal300 = 0xff4db6ac; + const color_t Teal400 = 0xff26a69a; + const color_t Teal500 = 0xff009688; + const color_t Teal600 = 0xff00897b; + const color_t Teal700 = 0xff00796b; + const color_t Teal800 = 0xff00695c; + const color_t Teal900 = 0xff004d40; + const color_t TealA100 = 0xffa7ffeb; + const color_t TealA200 = 0xff64ffda; + const color_t TealA400 = 0xff1de9b6; + const color_t TealA700 = 0xff00bfa5; + + const color_t Green50 = 0xffe8f5e9; + const color_t Green100 = 0xffc8e6c9; + const color_t Green200 = 0xffa5d6a7; + const color_t Green300 = 0xff81c784; + const color_t Green400 = 0xff66bb6a; + const color_t Green500 = 0xff4caf50; + const color_t Green600 = 0xff43a047; + const color_t Green700 = 0xff388e3c; + const color_t Green800 = 0xff2e7d32; + const color_t Green900 = 0xff1b5e20; + const color_t GreenA100 = 0xffb9f6ca; + const color_t GreenA200 = 0xff69f0ae; + const color_t GreenA400 = 0xff00e676; + const color_t GreenA700 = 0xff00c853; + + const color_t LightGreen50 = 0xfff1f8e9; + const color_t LightGreen100 = 0xffdcedc8; + const color_t LightGreen200 = 0xffc5e1a5; + const color_t LightGreen300 = 0xffaed581; + const color_t LightGreen400 = 0xff9ccc65; + const color_t LightGreen500 = 0xff8bc34a; + const color_t LightGreen600 = 0xff7cb342; + const color_t LightGreen700 = 0xff689f38; + const color_t LightGreen800 = 0xff558b2f; + const color_t LightGreen900 = 0xff33691e; + const color_t LightGreenA100 = 0xffccff90; + const color_t LightGreenA200 = 0xffb2ff59; + const color_t LightGreenA400 = 0xff76ff03; + const color_t LightGreenA700 = 0xff64dd17; + + const color_t Lime50 = 0xfff9ebe7; + const color_t Lime100 = 0xfff0f4c3; + const color_t Lime200 = 0xffe6ee9c; + const color_t Lime300 = 0xffdce775; + const color_t Lime400 = 0xffd4e157; + const color_t Lime500 = 0xffcddc39; + const color_t Lime600 = 0xffc0ca33; + const color_t Lime700 = 0xffafb42b; + const color_t Lime800 = 0xff9e9d24; + const color_t Lime900 = 0xff827717; + const color_t LimeA100 = 0xfff4ff81; + const color_t LimeA200 = 0xffeeff41; + const color_t LimeA400 = 0xffc6ff00; + const color_t LimeA700 = 0xffaeea00; + + const color_t Yellow50 = 0xfffffde7; + const color_t Yellow100 = 0xfffff9c4; + const color_t Yellow200 = 0xfffff59d; + const color_t Yellow300 = 0xfffff176; + const color_t Yellow400 = 0xffffee58; + const color_t Yellow500 = 0xffffeb3b; + const color_t Yellow600 = 0xfffdd835; + const color_t Yellow700 = 0xfffbc02d; + const color_t Yellow800 = 0xfff9a825; + const color_t Yellow900 = 0xfff57f17; + const color_t YellowA100 = 0xffffff8d; + const color_t YellowA200 = 0xffffff00; + const color_t YellowA400 = 0xffffea00; + const color_t YellowA700 = 0xffffd600; + + const color_t Amber50 = 0xfffff8e1; + const color_t Amber100 = 0xffffecb3; + const color_t Amber200 = 0xffffe082; + const color_t Amber300 = 0xffffd54f; + const color_t Amber400 = 0xffffca28; + const color_t Amber500 = 0xffffc107; + const color_t Amber600 = 0xffffb300; + const color_t Amber700 = 0xffffa000; + const color_t Amber800 = 0xffff8f00; + const color_t Amber900 = 0xffff6f00; + const color_t AmberA100 = 0xffffe57f; + const color_t AmberA200 = 0xffffd740; + const color_t AmberA400 = 0xffffc400; + const color_t AmberA700 = 0xffffab00; + + const color_t Orange50 = 0xfffff3e0; + const color_t Orange100 = 0xffffe0b2; + const color_t Orange200 = 0xffffcc80; + const color_t Orange300 = 0xffffb74d; + const color_t Orange400 = 0xffffa726; + const color_t Orange500 = 0xffff9800; + const color_t Orange600 = 0xfffb8c00; + const color_t Orange700 = 0xfff57c00; + const color_t Orange800 = 0xffef6c00; + const color_t Orange900 = 0xffe65100; + const color_t OrangeA100 = 0xffffd180; + const color_t OrangeA200 = 0xffffab40; + const color_t OrangeA400 = 0xffff9100; + const color_t OrangeA700 = 0xffff6d00; + + const color_t DeepOrange50 = 0xfffbe9e7; + const color_t DeepOrange100 = 0xffffccbc; + const color_t DeepOrange200 = 0xffffab91; + const color_t DeepOrange300 = 0xffff8a65; + const color_t DeepOrange400 = 0xffff7043; + const color_t DeepOrange500 = 0xffff5722; + const color_t DeepOrange600 = 0xfff4511e; + const color_t DeepOrange700 = 0xffe64a19; + const color_t DeepOrange800 = 0xffd84315; + const color_t DeepOrange900 = 0xffbf360c; + const color_t DeepOrangeA100 = 0xffff9e80; + const color_t DeepOrangeA200 = 0xffff6e40; + const color_t DeepOrangeA400 = 0xffff3d00; + const color_t DeepOrangeA700 = 0xffdd2c00; + + const color_t Brown50 = 0xffefebe9; + const color_t Brown100 = 0xffd7ccc8; + const color_t Brown200 = 0xffbcaaa4; + const color_t Brown300 = 0xffa1887f; + const color_t Brown400 = 0xff8d6e63; + const color_t Brown500 = 0xff795548; + const color_t Brown600 = 0xff6d4c41; + const color_t Brown700 = 0xff5d4037; + const color_t Brown800 = 0xff4e342e; + const color_t Brown900 = 0xff3e2723; + + const color_t Grey50 = 0xfffafafa; + const color_t Grey100 = 0xfff5f5f5; + const color_t Grey200 = 0xffeeeeee; + const color_t Grey300 = 0xffe0e0e0; + const color_t Grey400 = 0xffbdbdbd; + const color_t Grey500 = 0xff9e9e9e; + const color_t Grey600 = 0xff757575; + const color_t Grey700 = 0xff616161; + const color_t Grey800 = 0xff424242; + const color_t Grey900 = 0xff212121; + + const color_t BlueGrey50 = 0xffeceff1; + const color_t BlueGrey100 = 0xffcfd8dc; + const color_t BlueGrey200 = 0xffb0bec5; + const color_t BlueGrey300 = 0xff90a4ae; + const color_t BlueGrey400 = 0xff78909c; + const color_t BlueGrey500 = 0xff607d8b; + const color_t BlueGrey600 = 0xff546e7a; + const color_t BlueGrey700 = 0xff455a64; + const color_t BlueGrey800 = 0xff37474f; + const color_t BlueGrey900 = 0xff263238; + + const color_t Black = 0xff000000; + const color_t White = 0xffffffff; + const color_t Null = 0x00000000; + + + const color_t Red = Red500; + const color_t DarkRed = Red900; + const color_t RichRed = 0xffff0000; + const color_t Pink = Pink500; + const color_t Rose = PinkA100; + const color_t Purple = Purple500; + const color_t Magenta = PurpleA200; + const color_t DarkMagenta = PurpleA700; + const color_t DeepPurple = DeepPurple500; + const color_t Indigo = Indigo500; + const color_t Blue = Blue500; + const color_t DarkBlue = Blue900; + const color_t RichBlue = 0xff0000ff; + const color_t LightBlue = LightBlue500; + const color_t SkyBlue = LightBlueA100; + const color_t Navy = LightBlue800; + const color_t Cyan = Cyan500; + const color_t DarkCyan = Cyan900; + const color_t Teal = Teal500; + const color_t DarkTeal = Teal900; + const color_t Green = Green500; + const color_t DarkGreen = Green900; + const color_t RichGreen = 0xff00ff00; + const color_t LightGreen = LightGreen500; + const color_t Mint = LightGreen900; + const color_t Lime = Lime500; + const color_t Olive = Lime900; + const color_t Yellow = Yellow500; + const color_t DarkYellow = DarkRed | DarkGreen; + const color_t RichYellow = YellowA200; + const color_t Amber = Amber500; + const color_t Gold = Amber300; + const color_t PaleGold = AmberA100; + const color_t Orange = Orange500; + const color_t Skin = Orange100; + const color_t DeepOrange = DeepOrange500; + const color_t Brick = DeepOrange900; + const color_t Coral = DeepOrange200; + const color_t Brown = Brown500; + const color_t DarkBrown = Brown900; + const color_t CreamWhite = Brown50; + const color_t Grey = Grey500; + const color_t Silver = Grey300; + const color_t BlueGrey = BlueGrey500; } // END of namespace colors. - const color_t DefaultBlockColor = colors::Clay; + const color_t DefaultBlockColor = colors::OrangeA100; ////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index b920e95..0494880 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -67,8 +67,8 @@ enum BlockItemState ////////////////////////////////////////////////////////////////////////// -const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70); -const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 30); // ~800 +const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70); // Up to 1000 sec scale +const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 45); // ~23000 --- Up to 10 ns scale const qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003 const unsigned short GRAPHICS_ROW_SIZE = 18; @@ -88,8 +88,8 @@ const unsigned int TEST_PROGRESSION_BASE = 4; const int FLICKER_INTERVAL = 16; // 60Hz -const auto CHRONOMETER_FONT = QFont("CourierNew", 16, 2); -const auto ITEMS_FONT = QFont("CourierNew", 9);// , 2); +const auto CHRONOMETER_FONT = QFont("CourierNew", 18, 2); +const auto ITEMS_FONT = QFont("CourierNew", 10);// , 2); ////////////////////////////////////////////////////////////////////////// @@ -152,7 +152,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* QRectF rect; QBrush brush; - QRgb previousColor = 0, inverseColor = 0x00ffffff; + QRgb previousColor = 0, inverseColor = 0xffffffff, textColor = 0; Qt::PenStyle previousPenStyle = Qt::NoPen; brush.setStyle(Qt::SolidPattern); @@ -206,12 +206,14 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // (it seems there is a bug in Qt5.6 when drawText called for big coordinates, // drawRect at the same time called for actually same coordinates // works fine without using this additional shifting) - auto dx = level0[m_levelsIndexes[0]].left() * currentScale; + //const auto dx = level0[m_levelsIndexes[0]].left() * currentScale; + const auto dx = offset * currentScale; // Shifting coordinates to current screen offset - _painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true); + //_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true); + _painter->setTransform(QTransform::fromTranslate(0, -y()), true); if (EASY_GLOBALS.draw_graphics_items_borders) @@ -297,7 +299,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(pen); previousColor = SELECTED_ITEM_COLOR; - inverseColor = 0x00ffffff - previousColor; + inverseColor = 0xffffffff - previousColor; + textColor = ::profiler_gui::textColorForRgb(previousColor); brush.setColor(previousColor); _painter->setBrush(brush); } @@ -308,7 +311,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* { // Set background color brush for rectangle previousColor = item.color; - inverseColor = 0x00ffffff - previousColor; + inverseColor = 0xffffffff - previousColor; + textColor = ::profiler_gui::textColorForRgb(previousColor); brush.setColor(previousColor); _painter->setBrush(brush); } @@ -390,7 +394,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(pen); previousColor = SELECTED_ITEM_COLOR; - inverseColor = 0x00ffffff - previousColor; + inverseColor = 0xffffffff - previousColor; + textColor = ::profiler_gui::textColorForRgb(previousColor); brush.setColor(previousColor); _painter->setBrush(brush); } @@ -401,7 +406,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* { // Set background color brush for rectangle previousColor = item.color; - inverseColor = 0x00ffffff - previousColor; + inverseColor = 0xffffffff - previousColor; + textColor = ::profiler_gui::textColorForRgb(previousColor); brush.setColor(previousColor); _painter->setBrush(brush); } @@ -449,9 +455,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* rect.setRect(xtext + 1, top, w - 1, h); // text will be painted with inverse color - auto textColor = inverseColor; - if (textColor == previousColor) textColor = 0; - _painter->setPen(textColor); + //auto textColor = inverseColor < 0x00808080 ? profiler::colors::Black : profiler::colors::White; + //if (textColor == previousColor) textColor = 0; + _painter->setPen(QColor::fromRgb(textColor)); // drawing text auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name(); @@ -474,50 +480,60 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index]; if (item.left() < sceneRight && item.right() > sceneLeft) { - QPen pen(Qt::SolidLine); - pen.setColor(Qt::red); - pen.setWidth(2); - _painter->setPen(pen); - - brush.setColor(SELECTED_ITEM_COLOR); - _painter->setBrush(brush); - auto top = levelY(guiblock.graphics_item_level); - auto x = item.left() * currentScale - dx; - auto w = ::std::max(item.width() * currentScale, 1.0); - rect.setRect(x, top, w, item.totalHeight); - _painter->drawRect(rect); + decltype(top) h = item.totalHeight; - if (w > 20) + auto dh = top + h - visibleBottom; + if (dh < h) { - // Draw text----------------------------------- - // calculating text coordinates - auto xtext = x; - if (item.left() < sceneLeft) + if (dh > 0) + h -= dh; + + QPen pen(Qt::SolidLine); + pen.setColor(Qt::red); + pen.setWidth(2); + _painter->setPen(pen); + + brush.setColor(SELECTED_ITEM_COLOR); + _painter->setBrush(brush); + + auto x = item.left() * currentScale - dx; + auto w = ::std::max(item.width() * currentScale, 1.0); + rect.setRect(x, top, w, h); + _painter->drawRect(rect); + + if (w > 20) { - // if item left border is out of screen then attach text to the left border of the screen - // to ensure text is always visible for items presenting on the screen. - w += (item.left() - sceneLeft) * currentScale; - xtext = sceneLeft * currentScale - dx; + // Draw text----------------------------------- + // calculating text coordinates + auto xtext = x; + if (item.left() < sceneLeft) + { + // if item left border is out of screen then attach text to the left border of the screen + // to ensure text is always visible for items presenting on the screen. + w += (item.left() - sceneLeft) * currentScale; + xtext = sceneLeft * currentScale - dx; + } + + if (item.right() > sceneRight) + { + w -= (item.right() - sceneRight) * currentScale; + } + + rect.setRect(xtext + 1, top, w - 1, h); + + // text will be painted with inverse color + //auto textColor = 0x00ffffff - previousColor; + //if (textColor == previousColor) textColor = 0; + textColor = ::profiler_gui::textColorForRgb(SELECTED_ITEM_COLOR); + _painter->setPen(textColor); + + // drawing text + const auto& itemBlock = easyBlock(item.block); + auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name(); + _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name)); + // END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } - - if (item.right() > sceneRight) - { - w -= (item.right() - sceneRight) * currentScale; - } - - rect.setRect(xtext + 1, top, w - 1, item.totalHeight); - - // text will be painted with inverse color - auto textColor = 0x00ffffff - previousColor; - if (textColor == previousColor) textColor = 0; - _painter->setPen(textColor); - - // drawing text - const auto& itemBlock = easyBlock(item.block); - auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name(); - _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name)); - // END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } } } @@ -527,7 +543,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* #ifdef EASY_STORE_CSWITCH_SEPARATELY if (!m_pRoot->sync.empty()) { - _painter->setBrush(QColor::fromRgba(0xfff08040)); + _painter->setBrush(QColor::fromRgba(0xfffe6030)); _painter->setPen(QColor::fromRgb(0x00505050)); qreal prevRight = -1e100, top = y() - 4, h = 3; @@ -923,8 +939,8 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt auto vcenter = rect.top() + rect.height() * 0.5; QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter); g.setColorAt(0, m_color); - g.setColorAt(0.15, QColor::fromRgba(0x10000000 | rgb)); - g.setColorAt(0.85, QColor::fromRgba(0x10000000 | rgb)); + g.setColorAt(0.25, QColor::fromRgba(0x20000000 | rgb)); + g.setColorAt(0.75, QColor::fromRgba(0x20000000 | rgb)); g.setColorAt(1, m_color); _painter->setBrush(g); _painter->setPen(Qt::NoPen); @@ -940,7 +956,8 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt // draw text _painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background - _painter->setPen(0xffffffff - rgb); + _painter->setRenderHint(QPainter::TextAntialiasing); + _painter->setPen(0x00ffffff - rgb); _painter->setFont(CHRONOMETER_FONT); int textFlags = 0; @@ -1173,13 +1190,10 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap // Draw scale indicator _painter->save(); _painter->setTransform(QTransform::fromTranslate(-x(), -y())); - _painter->setCompositionMode(QPainter::CompositionMode_Difference); + //_painter->setCompositionMode(QPainter::CompositionMode_Difference); _painter->setBrush(Qt::NoBrush); - //_painter->setBrush(Qt::white); - //_painter->setPen(Qt::NoPen); - - QPen pen(Qt::white); + QPen pen(Qt::black); pen.setWidth(2); pen.setJoinStyle(Qt::MiterJoin); _painter->setPen(pen); @@ -1188,7 +1202,6 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap const auto rect_right = rect.right(); const QPointF points[] = {{rect.left(), rect.bottom()}, {rect.left(), rect.top()}, {rect_right, rect.top()}, {rect_right, rect.top() + 5}}; _painter->drawPolyline(points, sizeof(points) / sizeof(QPointF)); - //_painter->drawRect(rect); rect.translate(0, 3); _painter->drawText(rect, Qt::AlignRight | Qt::TextDontClip, text); @@ -1443,6 +1456,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr ::profiler::timestamp_t finish = 0; ::profiler::thread_id_t longestTree = 0; const EasyGraphicsItem* longestItem = nullptr; + const EasyGraphicsItem* mainThreadItem = nullptr; for (const auto& threadTree : _blocksTree) { const auto& tree = threadTree.second.children; @@ -1494,9 +1508,10 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr y += h + THREADS_ROW_SPACING; if (longestTree == threadTree.first) - { longestItem = item; - } + + if (mainThreadItem == nullptr && !strcmp(threadTree.second.thread_name, "Main")) + mainThreadItem = item; } // Calculating scene rect @@ -1509,6 +1524,9 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr updateVisibleSceneRect(); setScrollbar(m_pScrollbar); + if (mainThreadItem != nullptr) + longestItem = mainThreadItem; + if (longestItem != nullptr) { m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0)); @@ -1618,9 +1636,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block maxh = h; } - const auto color = EASY_GLOBALS.descriptors[child.node->id()]->color(); b.block = child_index;// &child; - b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + b.color = EASY_GLOBALS.descriptors[child.node->id()]->color();// ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); b.setPos(xbegin, duration); b.totalHeight = GRAPHICS_ROW_SIZE + h; b.state = BLOCK_ITEM_UNCHANGED; diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 5be5d8f..7a195c6 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -101,7 +101,7 @@ struct do_no_hash { ////////////////////////////////////////////////////////////////////////// -const QRgb DEFAULT_COLOR = 0x00d4b494;//0x00f0e094; +const QRgb DEFAULT_COLOR = profiler::DefaultBlockColor;// 0x00d4b494; inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue) { @@ -115,6 +115,12 @@ inline QRgb fromProfilerRgb(unsigned int _red, unsigned int _green, unsigned int return toRgb(_red, _green, _blue) | 0x00141414; } +inline QRgb textColorForRgb(QRgb _color) +{ + const QRgb sum = 0xff - ((_color & 0xff000000) >> 24) + ((_color & 0x00ff0000) >> 16) + ((_color & 0x0000ff00) >> 8) + (_color & 0x000000ff); + return sum > 0x215 ? ::profiler::colors::Black : ::profiler::colors::White; +} + ////////////////////////////////////////////////////////////////////////// #pragma pack(push, 1) diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index b388f81..a0076e7 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -354,9 +354,9 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI } const auto color = easyDescriptor(gui_block.tree.node->id()).color(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); + //const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = ::profiler_gui::textColorForRgb(color);//0x00ffffff - bgColor; + item->setBackgroundColor(color); item->setTextColor(fgColor); auto item_index = static_cast(_items.size()); @@ -549,9 +549,9 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: } const auto color = easyDescriptor(child.node->id()).color(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); + //const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = ::profiler_gui::textColorForRgb(color);// 0x00ffffff - bgColor; + item->setBackgroundColor(color); item->setTextColor(fgColor); auto item_index = static_cast(_items.size()); diff --git a/sample/main.cpp b/sample/main.cpp index e9f33c3..1773295 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -26,7 +26,7 @@ void localSleep(int magic=200000) } void loadingResources(){ - EASY_FUNCTION(profiler::colors::Darkcyan); + EASY_FUNCTION(profiler::colors::DarkCyan); localSleep(); // std::this_thread::sleep_for(std::chrono::milliseconds(50)); } @@ -85,7 +85,7 @@ void calcBrain(){ } void calculateBehavior(){ - EASY_FUNCTION(profiler::colors::Darkblue); + EASY_FUNCTION(profiler::colors::DarkBlue); calcPhys(); calcBrain(); } @@ -97,7 +97,7 @@ void modellingStep(){ } void prepareRender(){ - EASY_FUNCTION(profiler::colors::Darkred); + EASY_FUNCTION(profiler::colors::DarkRed); localSleep(); //std::this_thread::sleep_for(std::chrono::milliseconds(8)); diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 48dd0e7..4e13ec7 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -407,7 +407,7 @@ const char* ProfileManager::setThreadName(const char* name, const char* filename if (!THREAD_STORAGE->named) { - const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); + const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Black); THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); THREAD_STORAGE->name = name; THREAD_STORAGE->named = true; diff --git a/src/reader.cpp b/src/reader.cpp index f6f02d9..7d3348b 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -340,7 +340,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr blocks.reserve(total_blocks_number); while (!inFile.eof() && read_number < total_blocks_number) { - EASY_BLOCK("Read thread data", ::profiler::colors::Darkgreen); + EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen); ::profiler::thread_id_t thread_id = 0; inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); From 39e68b4adcb62a839b85fa313ebcd3c8cc7713e2 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Wed, 7 Sep 2016 21:50:42 +0300 Subject: [PATCH 37/37] ci clang compiler fix attempt number three =| --- src/profile_manager.h | 81 ++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/src/profile_manager.h b/src/profile_manager.h index 2a0fb47..0259cbb 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -97,57 +97,58 @@ public: const uint16_t SIZEOF_CSWITCH = sizeof(profiler::BaseBlockData) + 1; -class ThreadStorage final +typedef std::vector serialized_list_t; + +template +struct BlocksList final { - typedef std::vector serialized_list_t; + BlocksList() = default; - template - struct BlocksList final - { - BlocksList() = default; + class Stack final { + //std::stack m_stack; + std::vector m_stack; - class Stack final { - //std::stack m_stack; - std::vector m_stack; + public: - public: + inline void clear() { m_stack.clear(); } + inline bool empty() const { return m_stack.empty(); } - inline void clear() { m_stack.clear(); } - inline bool empty() const { return m_stack.empty(); } + inline void emplace(profiler::Block& _block) { + //m_stack.emplace(_block); + m_stack.emplace_back(_block); + } - inline void emplace(profiler::Block& _block) { - //m_stack.emplace(_block); - m_stack.emplace_back(_block); - } + template inline void emplace(TArgs ... _args) { + //m_stack.emplace(_args); + m_stack.emplace_back(_args...); + } - template inline void emplace(TArgs ... _args) { - //m_stack.emplace(_args); - m_stack.emplace_back(_args...); - } + inline T& top() { + //return m_stack.top(); + return m_stack.back(); + } - inline T& top() { - //return m_stack.top(); - return m_stack.back(); - } - - inline void pop() { - //m_stack.pop(); - m_stack.pop_back(); - } - }; - - chunk_allocator alloc; - Stack openedList; - serialized_list_t closedList; - uint64_t usedMemorySize = 0; - - void clearClosed() { - serialized_list_t().swap(closedList); - alloc.clear(); - usedMemorySize = 0; + inline void pop() { + //m_stack.pop(); + m_stack.pop_back(); } }; + chunk_allocator alloc; + Stack openedList; + serialized_list_t closedList; + uint64_t usedMemorySize = 0; + + void clearClosed() { + serialized_list_t().swap(closedList); + alloc.clear(); + usedMemorySize = 0; + } +}; + + +class ThreadStorage final +{ public: BlocksList, SIZEOF_CSWITCH * (uint16_t)1024U> blocks;