/** Lightweight profiler library for c++ Copyright(C) 2016 Sergey Yagovtsev This program is free software : you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see . **/ #ifndef PROFILER_READER____H #define PROFILER_READER____H ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include "profiler/profiler.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace profiler { typedef uint32_t calls_number_t; struct BlockStatistics final { ::profiler::timestamp_t total_duration; ///< Summary duration of all block calls ::profiler::timestamp_t min_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high ::profiler::timestamp_t max_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high unsigned int min_duration_block; ///< Will be used in GUI to jump to the block with min duration unsigned int max_duration_block; ///< Will be used in GUI to jump to the block with max duration ::profiler::calls_number_t calls_number; ///< Block calls number // TODO: It is better to replace SerilizedBlock* with BlocksTree*, but this requires to store pointers in children list. BlockStatistics() : total_duration(0) , min_duration(0) , max_duration(0) , min_duration_block(0) , max_duration_block(0) , calls_number(1) { } BlockStatistics(::profiler::timestamp_t _duration, unsigned int _block_index) : total_duration(_duration) , min_duration(_duration) , max_duration(_duration) , min_duration_block(_block_index) , max_duration_block(_block_index) , calls_number(1) { } inline ::profiler::timestamp_t average_duration() const { return total_duration / calls_number; } }; // END of struct BlockStatistics. inline void release(BlockStatistics*& _stats) { if (!_stats) { return; } if (--_stats->calls_number == 0) { delete _stats; } _stats = nullptr; } ////////////////////////////////////////////////////////////////////////// class BlocksTree { typedef BlocksTree This; public: typedef ::std::list children_t; children_t children; ///< List of children blocks. May be empty. ::profiler::SerilizedBlock* 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 unsigned int block_index; ///< Index of this block unsigned int total_children_number; ///< Number of all children including number of grandchildren (and so on) unsigned short 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) , total_children_number(0) , depth(0) { } BlocksTree(This&& that) : BlocksTree() { makeMove(::std::forward(that)); } This& operator = (This&& that) { makeMove(::std::forward(that)); return *this; } ~BlocksTree() { if (node) { delete node; } release(per_thread_stats); release(per_parent_stats); release(per_frame_stats); } bool operator < (const This& other) const { if (!node || !other.node) { return false; } return node->block()->getBegin() < other.node->block()->getBegin(); } private: BlocksTree(const This&) = delete; This& operator = (const This&) = delete; void makeMove(This&& that) { if (node && node != that.node) { delete node; } if (per_thread_stats != that.per_thread_stats) { release(per_thread_stats); } if (per_parent_stats != that.per_parent_stats) { release(per_parent_stats); } if (per_frame_stats != that.per_frame_stats) { release(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; total_children_number = that.total_children_number; depth = that.depth; that.node = nullptr; that.per_parent_stats = nullptr; that.per_frame_stats = nullptr; that.per_thread_stats = nullptr; } }; // END of class BlocksTree. ////////////////////////////////////////////////////////////////////////// class BlocksTreeRoot final { typedef BlocksTreeRoot This; public: BlocksTree tree; const char* thread_name; ::profiler::thread_id_t thread_id; BlocksTreeRoot() : thread_name(""), thread_id(0) { } BlocksTreeRoot(This&& that) : tree(::std::move(that.tree)), thread_name(that.thread_name), thread_id(that.thread_id) { } This& operator = (This&& that) { tree = ::std::move(that.tree); thread_name = that.thread_name; return *this; } bool operator < (const This& other) const { return tree < other.tree; } private: BlocksTreeRoot(const This&) = delete; This& operator = (const This&) = delete; }; // END of class BlocksTreeRoot. typedef ::std::map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot> thread_blocks_tree_t; } // END of namespace profiler. extern "C"{ unsigned int PROFILER_API fillTreesFromFile(const char* filename, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif // PROFILER_READER____H