2016-06-19 23:01:49 +03:00
/**
Lightweight profiler library for c + +
2016-08-11 23:52:33 +03:00
Copyright ( C ) 2016 Sergey Yagovtsev , Victor Zarubkin
2016-06-19 23:01:49 +03:00
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 < http : //www.gnu.org/licenses/>.
2016-08-07 21:40:23 +03:00
* */
# ifndef PROFILER_READER____H
# define PROFILER_READER____H
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-09-13 23:03:01 +03:00
# include <unordered_map>
2016-08-14 16:05:10 +03:00
# include <vector>
2016-09-13 23:03:01 +03:00
# include <string>
2016-08-18 23:26:41 +03:00
# include <atomic>
2016-08-07 21:40:23 +03:00
# include "profiler/profiler.h"
2016-08-28 02:41:02 +03:00
# include "profiler/serialized_block.h"
2016-08-07 21:40:23 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace profiler {
typedef uint32_t calls_number_t ;
2016-08-14 16:05:10 +03:00
typedef uint32_t block_index_t ;
2016-08-07 21:40:23 +03:00
2016-08-14 16:05:10 +03:00
# pragma pack(push, 1)
2016-08-07 21:40:23 +03:00
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
2016-08-14 16:05:10 +03:00
: : profiler : : block_index_t min_duration_block ; ///< Will be used in GUI to jump to the block with min duration
: : profiler : : block_index_t max_duration_block ; ///< Will be used in GUI to jump to the block with max duration
2016-09-13 23:40:58 +03:00
: : profiler : : block_index_t parent_block ; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats"
2016-08-07 21:40:23 +03:00
: : profiler : : calls_number_t calls_number ; ///< Block calls number
2016-09-13 23:40:58 +03:00
explicit BlockStatistics ( : : profiler : : timestamp_t _duration , : : profiler : : block_index_t _block_index , : : profiler : : block_index_t _parent_index )
2016-08-07 21:40:23 +03:00
: total_duration ( _duration )
, min_duration ( _duration )
, max_duration ( _duration )
, min_duration_block ( _block_index )
, max_duration_block ( _block_index )
2016-09-13 23:40:58 +03:00
, parent_block ( _parent_index )
2016-08-07 21:40:23 +03:00
, calls_number ( 1 )
{
}
inline : : profiler : : timestamp_t average_duration ( ) const
{
return total_duration / calls_number ;
}
} ; // END of struct BlockStatistics.
2016-08-14 16:05:10 +03:00
# pragma pack(pop)
2016-08-07 21:40:23 +03:00
2016-08-28 18:19:12 +03:00
extern " C " void PROFILER_API release_stats ( BlockStatistics * & _stats ) ;
2016-08-07 21:40:23 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-01 22:24:13 +03:00
class BlocksTree final
2016-06-19 23:01:49 +03:00
{
2016-08-03 23:00:04 +03:00
typedef BlocksTree This ;
2016-06-19 23:01:49 +03:00
2016-08-03 23:00:04 +03:00
public :
2016-06-19 23:01:49 +03:00
2016-08-30 22:51:18 +03:00
typedef : : std : : vector < This > blocks_t ;
typedef : : std : : vector < : : profiler : : block_index_t > children_t ;
2016-08-03 23:00:04 +03:00
2016-08-07 19:38:31 +03:00
children_t children ; ///< List of children blocks. May be empty.
2016-08-14 16:05:10 +03:00
: : profiler : : SerializedBlock * node ; ///< Pointer to serilized data (type, name, begin, end etc.)
2016-08-18 23:26:41 +03:00
: : 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)
2016-08-07 19:38:31 +03:00
: : profiler : : BlockStatistics * per_thread_stats ; ///< Pointer to statistics for this block within the bounds of all frames per current thread
2016-08-30 22:51:18 +03:00
uint16_t depth ; ///< Maximum number of sublevels (maximum children depth)
2016-08-03 23:00:04 +03:00
BlocksTree ( )
2016-08-04 22:38:45 +03:00
: node ( nullptr )
2016-08-07 19:38:31 +03:00
, per_parent_stats ( nullptr )
, per_frame_stats ( nullptr )
, per_thread_stats ( nullptr )
2016-08-03 23:00:04 +03:00
, depth ( 0 )
2016-06-19 23:01:49 +03:00
{
2016-08-03 23:00:04 +03:00
2016-06-19 23:01:49 +03:00
}
2016-06-26 00:56:24 +03:00
2016-08-03 23:00:04 +03:00
BlocksTree ( This & & that ) : BlocksTree ( )
{
2016-09-13 23:40:58 +03:00
make_move ( : : std : : forward < This & & > ( that ) ) ;
2016-08-03 23:00:04 +03:00
}
2016-06-19 23:01:49 +03:00
2016-08-03 23:00:04 +03:00
This & operator = ( This & & that )
2016-06-19 23:01:49 +03:00
{
2016-09-13 23:40:58 +03:00
make_move ( : : std : : forward < This & & > ( that ) ) ;
2016-08-03 23:00:04 +03:00
return * this ;
2016-06-19 23:01:49 +03:00
}
2016-08-03 23:00:04 +03:00
~ BlocksTree ( )
{
2016-08-28 18:19:12 +03:00
release_stats ( per_thread_stats ) ;
release_stats ( per_parent_stats ) ;
release_stats ( per_frame_stats ) ;
2016-08-03 23:00:04 +03:00
}
bool operator < ( const This & other ) const
2016-06-25 17:30:39 +03:00
{
2016-08-03 23:00:04 +03:00
if ( ! node | | ! other . node )
return false ;
2016-08-28 18:19:12 +03:00
return node - > begin ( ) < other . node - > begin ( ) ;
2016-06-25 17:30:39 +03:00
}
2016-08-14 16:05:10 +03:00
void shrink_to_fit ( )
{
//for (auto& child : children)
// child.shrink_to_fit();
// shrink version 1:
//children.shrink_to_fit();
// shrink version 2:
//children_t new_children;
//new_children.reserve(children.size());
//::std::move(children.begin(), children.end(), ::std::back_inserter(new_children));
//new_children.swap(children);
}
2016-08-03 23:00:04 +03:00
private :
BlocksTree ( const This & ) = delete ;
This & operator = ( const This & ) = delete ;
2016-09-13 23:40:58 +03:00
void make_move ( This & & that )
2016-06-26 00:56:24 +03:00
{
2016-08-07 19:38:31 +03:00
if ( per_thread_stats ! = that . per_thread_stats )
2016-08-28 18:19:12 +03:00
release_stats ( per_thread_stats ) ;
2016-08-03 23:00:04 +03:00
2016-08-07 19:38:31 +03:00
if ( per_parent_stats ! = that . per_parent_stats )
2016-08-28 18:19:12 +03:00
release_stats ( per_parent_stats ) ;
2016-08-07 19:38:31 +03:00
if ( per_frame_stats ! = that . per_frame_stats )
2016-08-28 18:19:12 +03:00
release_stats ( per_frame_stats ) ;
2016-08-03 23:00:04 +03:00
children = : : std : : move ( that . children ) ;
node = that . node ;
2016-08-07 19:38:31 +03:00
per_parent_stats = that . per_parent_stats ;
per_frame_stats = that . per_frame_stats ;
per_thread_stats = that . per_thread_stats ;
2016-08-03 23:00:04 +03:00
depth = that . depth ;
that . node = nullptr ;
2016-08-07 19:38:31 +03:00
that . per_parent_stats = nullptr ;
that . per_frame_stats = nullptr ;
that . per_thread_stats = nullptr ;
2016-06-26 00:56:24 +03:00
}
2016-08-03 23:00:04 +03:00
} ; // END of class BlocksTree.
//////////////////////////////////////////////////////////////////////////
2016-08-04 22:38:45 +03:00
class BlocksTreeRoot final
2016-08-03 23:00:04 +03:00
{
typedef BlocksTreeRoot This ;
public :
2016-09-13 23:40:58 +03:00
BlocksTree : : children_t children ; ///< List of children indexes
BlocksTree : : children_t sync ; ///< List of context-switch events
std : : string thread_name ; ///< Name of this thread
: : profiler : : timestamp_t active_time ; ///< Active time of this thread (sum of all children duration)
: : profiler : : thread_id_t thread_id ; ///< System Id of this thread
uint16_t depth ; ///< Maximum stack depth (number of levels)
2016-08-03 23:00:04 +03:00
2016-09-13 23:40:58 +03:00
BlocksTreeRoot ( ) : thread_name ( " " ) , active_time ( 0 ) , thread_id ( 0 ) , depth ( 0 )
2016-08-03 23:00:04 +03:00
{
}
2016-09-04 14:48:35 +03:00
BlocksTreeRoot ( This & & that )
: children ( : : std : : move ( that . children ) )
, sync ( : : std : : move ( that . sync ) )
2016-09-13 23:03:01 +03:00
, thread_name ( : : std : : move ( that . thread_name ) )
2016-09-13 23:40:58 +03:00
, active_time ( that . active_time )
2016-09-04 14:48:35 +03:00
, thread_id ( that . thread_id )
, depth ( that . depth )
2016-06-26 00:56:24 +03:00
{
}
2016-08-03 23:00:04 +03:00
This & operator = ( This & & that )
{
2016-08-30 22:51:18 +03:00
children = : : std : : move ( that . children ) ;
2016-09-04 14:48:35 +03:00
sync = : : std : : move ( that . sync ) ;
2016-09-13 23:03:01 +03:00
thread_name = : : std : : move ( that . thread_name ) ;
2016-09-13 23:40:58 +03:00
active_time = that . active_time ;
2016-08-14 16:05:10 +03:00
thread_id = that . thread_id ;
2016-08-30 22:51:18 +03:00
depth = that . depth ;
2016-08-03 23:00:04 +03:00
return * this ;
}
2016-07-27 21:50:11 +03:00
2016-09-13 23:40:58 +03:00
inline bool got_name ( ) const
2016-09-13 23:03:01 +03:00
{
//return thread_name && *thread_name != 0;
return thread_name . front ( ) ! = 0 ;
}
inline const char * name ( ) const
{
//return thread_name;
return thread_name . c_str ( ) ;
}
2016-08-03 23:00:04 +03:00
bool operator < ( const This & other ) const
{
2016-08-30 22:51:18 +03:00
return thread_id < other . thread_id ;
2016-08-03 23:00:04 +03:00
}
2016-07-27 21:50:11 +03:00
2016-08-03 23:00:04 +03:00
private :
2016-06-19 23:01:49 +03:00
2016-08-03 23:00:04 +03:00
BlocksTreeRoot ( const This & ) = delete ;
This & operator = ( const This & ) = delete ;
2016-06-19 23:01:49 +03:00
2016-08-03 23:00:04 +03:00
} ; // END of class BlocksTreeRoot.
2016-06-19 23:01:49 +03:00
2016-08-30 22:51:18 +03:00
typedef : : profiler : : BlocksTree : : blocks_t blocks_t ;
2016-09-13 23:03:01 +03:00
typedef : : std : : unordered_map < : : profiler : : thread_id_t , : : profiler : : BlocksTreeRoot , : : profiler : : passthrough_hash > thread_blocks_tree_t ;
2016-06-19 23:46:42 +03:00
2016-08-14 22:22:44 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-28 18:19:12 +03:00
class PROFILER_API SerializedData final
2016-08-14 22:22:44 +03:00
{
char * m_data ;
public :
SerializedData ( ) : m_data ( nullptr )
{
}
SerializedData ( SerializedData & & that ) : m_data ( that . m_data )
{
that . m_data = nullptr ;
}
~ SerializedData ( )
{
clear ( ) ;
}
2016-08-28 18:19:12 +03:00
void set ( char * _data ) ;
2016-08-14 22:22:44 +03:00
SerializedData & operator = ( SerializedData & & that )
{
2016-08-28 18:19:12 +03:00
set ( that . m_data ) ;
2016-08-14 22:22:44 +03:00
that . m_data = nullptr ;
return * this ;
}
char * operator [ ] ( uint64_t i )
{
return m_data + i ;
}
void clear ( )
{
2016-08-28 18:19:12 +03:00
set ( nullptr ) ;
2016-08-14 22:22:44 +03:00
}
2016-08-18 23:26:41 +03:00
void swap ( SerializedData & other )
{
auto temp = other . m_data ;
other . m_data = m_data ;
m_data = temp ;
}
2016-08-14 22:22:44 +03:00
private :
SerializedData ( const SerializedData & ) = delete ;
SerializedData & operator = ( const SerializedData & ) = delete ;
} ; // END of class SerializedData.
//////////////////////////////////////////////////////////////////////////
2016-08-28 18:19:12 +03:00
typedef : : std : : vector < SerializedBlockDescriptor * > descriptors_list_t ;
2016-08-03 23:00:04 +03:00
} // END of namespace profiler.
2016-06-19 23:46:42 +03:00
2016-08-30 22:51:18 +03:00
extern " C " : : profiler : : block_index_t PROFILER_API fillTreesFromFile ( : : std : : atomic < int > & 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 : : 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 )
{
2016-08-18 23:26:41 +03:00
: : std : : atomic < int > progress = ATOMIC_VAR_INIT ( 0 ) ;
2016-08-30 22:51:18 +03:00
return fillTreesFromFile ( progress , filename , serialized_blocks , serialized_descriptors , descriptors , _blocks , threaded_trees , gather_statistics ) ;
2016-08-18 23:26:41 +03:00
}
2016-06-19 23:46:42 +03:00
2016-06-19 23:01:49 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# endif // PROFILER_READER____H