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-09-29 23:29:57 +03:00
# include "easy/profiler.h"
# include "easy/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-09-22 23:06:43 +03:00
struct BlockStatistics EASY_FINAL
2016-08-07 21:40:23 +03:00
{
: : 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 )
{
}
2016-09-21 22:09:04 +03:00
//BlockStatistics() = default;
2016-08-07 21:40:23 +03:00
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-09-21 22:09:04 +03:00
extern " C " PROFILER_API void release_stats ( BlockStatistics * & _stats ) ;
2016-08-07 21:40:23 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-22 23:06:43 +03:00
class BlocksTree EASY_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-09-22 23:06:43 +03:00
children_t children ; ///< List of children blocks. May be empty.
: : profiler : : SerializedBlock * node ; ///< Pointer to serilized data (type, name, begin, end etc.)
2016-09-29 23:29:57 +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-09-22 23:06:43 +03:00
: : profiler : : BlockStatistics * per_thread_stats ; ///< Pointer to statistics for this block within the bounds of all frames per current thread
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-09-22 23:06:43 +03:00
class BlocksTreeRoot EASY_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
2016-09-23 23:50:43 +03:00
BlocksTree : : children_t events ; ///< List of events indexes
2016-09-13 23:40:58 +03:00
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-23 23:50:43 +03:00
, events ( : : std : : move ( that . events ) )
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-23 23:50:43 +03:00
events = : : std : : move ( that . events ) ;
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 . front ( ) ! = 0 ;
}
inline const char * name ( ) const
{
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-09-22 23:06:43 +03:00
class PROFILER_API SerializedData EASY_FINAL
2016-08-14 22:22:44 +03:00
{
2016-09-21 22:09:04 +03:00
char * m_data ;
size_t m_size ;
2016-08-14 22:22:44 +03:00
public :
2016-09-21 22:09:04 +03:00
SerializedData ( ) : m_data ( nullptr ) , m_size ( 0 )
2016-08-14 22:22:44 +03:00
{
}
2016-09-21 22:09:04 +03:00
SerializedData ( SerializedData & & that ) : m_data ( that . m_data ) , m_size ( that . m_size )
2016-08-14 22:22:44 +03:00
{
that . m_data = nullptr ;
2016-09-21 22:09:04 +03:00
that . m_size = 0 ;
2016-08-14 22:22:44 +03:00
}
~ SerializedData ( )
{
clear ( ) ;
}
2016-09-29 22:40:19 +03:00
void set ( uint64_t _size ) ;
void extend ( uint64_t _size ) ;
2016-08-28 18:19:12 +03:00
2016-08-14 22:22:44 +03:00
SerializedData & operator = ( SerializedData & & that )
{
2016-09-21 22:09:04 +03:00
set ( that . m_data , that . m_size ) ;
2016-08-14 22:22:44 +03:00
that . m_data = nullptr ;
2016-09-21 22:09:04 +03:00
that . m_size = 0 ;
2016-08-14 22:22:44 +03:00
return * this ;
}
2016-09-21 22:09:04 +03:00
char * operator [ ] ( uint64_t i )
2016-08-14 22:22:44 +03:00
{
return m_data + i ;
}
2016-09-29 22:40:19 +03:00
const char * operator [ ] ( uint64_t i ) const
{
return m_data + i ;
}
bool empty ( ) const
{
return m_size = = 0 ;
}
uint64_t size ( ) const
2016-09-21 22:09:04 +03:00
{
return m_size ;
}
char * data ( )
{
return m_data ;
}
const char * data ( ) const
{
return m_data ;
}
2016-08-14 22:22:44 +03:00
void clear ( )
{
2016-09-21 22:09:04 +03:00
set ( nullptr , 0 ) ;
2016-08-14 22:22:44 +03:00
}
2016-08-18 23:26:41 +03:00
void swap ( SerializedData & other )
{
2016-09-21 22:09:04 +03:00
char * d = other . m_data ;
2016-09-29 22:40:19 +03:00
uint64_t sz = other . m_size ;
2016-09-21 22:09:04 +03:00
2016-08-18 23:26:41 +03:00
other . m_data = m_data ;
2016-09-21 22:09:04 +03:00
other . m_size = m_size ;
m_data = d ;
m_size = sz ;
2016-08-18 23:26:41 +03:00
}
2016-08-14 22:22:44 +03:00
private :
2016-09-29 22:40:19 +03:00
void set ( char * _data , uint64_t _size ) ;
2016-09-21 22:09:04 +03:00
2016-08-14 22:22:44 +03:00
SerializedData ( const SerializedData & ) = delete ;
SerializedData & operator = ( const SerializedData & ) = delete ;
} ; // END of class SerializedData.
//////////////////////////////////////////////////////////////////////////
2016-09-29 22:40:19 +03:00
struct FileData
{
: : profiler : : SerializedData serialized_blocks ;
: : profiler : : SerializedData serialized_descriptors ;
: : std : : vector < : : profiler : : thread_id_t > threads_order ;
: : profiler : : timestamp_t begin_time = 0ULL ;
: : profiler : : timestamp_t end_time = 0ULL ;
int64_t cpu_frequency = 0LL ;
uint32_t total_blocks_number = 0 ;
uint32_t total_descriptors_number = 0 ;
FileData ( ) = default ;
FileData ( FileData & & _other )
: serialized_blocks ( : : std : : move ( _other . serialized_blocks ) )
, serialized_descriptors ( : : std : : move ( _other . serialized_descriptors ) )
, threads_order ( : : std : : move ( _other . threads_order ) )
, begin_time ( _other . begin_time )
, end_time ( _other . end_time )
, cpu_frequency ( _other . cpu_frequency )
, total_blocks_number ( _other . total_blocks_number )
, total_descriptors_number ( _other . total_descriptors_number )
{
}
FileData & operator = ( FileData & & _other )
{
serialized_blocks = : : std : : move ( _other . serialized_blocks ) ;
serialized_descriptors = : : std : : move ( _other . serialized_descriptors ) ;
threads_order = : : std : : move ( _other . threads_order ) ;
begin_time = _other . begin_time ;
end_time = _other . end_time ;
cpu_frequency = _other . cpu_frequency ;
total_blocks_number = _other . total_blocks_number ;
total_descriptors_number = _other . total_descriptors_number ;
return * this ;
}
private :
FileData ( const FileData & ) = delete ;
FileData & operator = ( const FileData & ) = delete ;
} ;
//////////////////////////////////////////////////////////////////////////
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-09-25 11:49:49 +03:00
extern " C " {
PROFILER_API : : profiler : : block_index_t fillTreesFromFile ( : : std : : atomic < int > & progress , const char * filename ,
2016-10-02 12:13:12 +03:00
: : profiler : : SerializedData & serialized_blocks ,
: : profiler : : SerializedData & serialized_descriptors ,
2016-09-29 22:40:19 +03:00
: : profiler : : descriptors_list_t & descriptors ,
: : profiler : : blocks_t & _blocks ,
: : profiler : : thread_blocks_tree_t & threaded_trees ,
2016-10-02 12:13:12 +03:00
uint32_t & total_descriptors_number ,
2016-09-29 22:40:19 +03:00
bool gather_statistics ,
: : std : : stringstream & _log ) ;
2016-09-25 11:49:49 +03:00
PROFILER_API : : profiler : : block_index_t fillTreesFromStream ( : : std : : atomic < int > & progress , : : std : : stringstream & str ,
2016-10-02 12:13:12 +03:00
: : profiler : : SerializedData & serialized_blocks ,
: : profiler : : SerializedData & serialized_descriptors ,
2016-09-29 22:40:19 +03:00
: : profiler : : descriptors_list_t & descriptors ,
: : profiler : : blocks_t & _blocks ,
: : profiler : : thread_blocks_tree_t & threaded_trees ,
2016-10-02 12:13:12 +03:00
uint32_t & total_descriptors_number ,
2016-09-29 22:40:19 +03:00
bool gather_statistics ,
: : std : : stringstream & _log ) ;
2016-09-25 11:49:49 +03:00
PROFILER_API bool readDescriptionsFromStream ( : : std : : atomic < int > & progress , : : std : : stringstream & str ,
: : profiler : : SerializedData & serialized_descriptors ,
2016-09-27 22:28:04 +03:00
: : profiler : : descriptors_list_t & descriptors ,
: : std : : stringstream & _log ) ;
2016-09-25 11:49:49 +03:00
}
2016-08-30 22:51:18 +03:00
inline : : profiler : : block_index_t fillTreesFromFile ( const char * filename , : : profiler : : SerializedData & serialized_blocks ,
2016-10-02 12:13:12 +03:00
: : profiler : : SerializedData & serialized_descriptors ,
2016-09-29 22:40:19 +03:00
: : profiler : : descriptors_list_t & descriptors , : : profiler : : blocks_t & _blocks ,
2016-10-02 12:13:12 +03:00
: : profiler : : thread_blocks_tree_t & threaded_trees ,
uint32_t & total_descriptors_number ,
2016-09-27 22:28:04 +03:00
bool gather_statistics ,
: : std : : stringstream & _log )
2016-08-30 22:51:18 +03:00
{
2016-08-18 23:26:41 +03:00
: : std : : atomic < int > progress = ATOMIC_VAR_INIT ( 0 ) ;
2016-10-02 12:13:12 +03:00
return fillTreesFromFile ( progress , filename , serialized_blocks , serialized_descriptors , descriptors , _blocks , threaded_trees , total_descriptors_number , gather_statistics , _log ) ;
2016-08-18 23:26:41 +03:00
}
2016-06-19 23:46:42 +03:00
2016-09-27 22:28:04 +03:00
inline bool readDescriptionsFromStream ( : : std : : stringstream & str ,
: : profiler : : SerializedData & serialized_descriptors ,
: : profiler : : descriptors_list_t & descriptors ,
: : std : : stringstream & _log )
2016-09-25 11:49:49 +03:00
{
: : std : : atomic < int > progress = ATOMIC_VAR_INIT ( 0 ) ;
2016-09-27 22:28:04 +03:00
return readDescriptionsFromStream ( progress , str , serialized_descriptors , descriptors , _log ) ;
2016-09-25 11:49:49 +03:00
}
2016-06-19 23:01:49 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# endif // PROFILER_READER____H