2016-09-18 19:02:12 +03:00
/************************************************************************
* 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
* :
2016-11-13 16:39:59 +03:00
* :
* : Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* : you may not use this file except in compliance with the License .
* : You may obtain a copy of the License at
* :
* : http : //www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing , software
* : distributed under the License is distributed on an " AS IS " BASIS ,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* : See the License for the specific language governing permissions and
* : limitations under the License .
* :
* :
* : GNU General Public License Usage
* : Alternatively , this file may be used 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 .
2016-09-18 19:02:12 +03:00
* :
* : 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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <algorithm>
# include <fstream>
# include "profile_manager.h"
2016-09-29 23:29:57 +03:00
# include "easy/serialized_block.h"
# include "easy/easy_net.h"
# include "easy/easy_socket.h"
2016-09-18 19:02:12 +03:00
# include "event_trace_win.h"
2016-09-26 23:23:38 +03:00
# include "current_time.h"
2016-09-18 19:02:12 +03:00
2016-12-12 22:26:32 +03:00
# ifdef min
# undef min
2016-11-27 14:26:00 +03:00
# endif
2016-09-18 19:02:12 +03:00
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
using namespace profiler ;
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
# if !defined(EASY_PROFILER_VERSION_MAJOR) || !defined(EASY_PROFILER_VERSION_MINOR) || !defined(EASY_PROFILER_VERSION_PATCH)
2016-11-16 22:17:39 +03:00
# ifdef _WIN32
2016-11-20 13:42:05 +03:00
# error EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined
2016-11-16 22:17:39 +03:00
# else
2016-11-20 13:42:05 +03:00
# error "EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined"
2016-11-16 22:17:39 +03:00
# endif
# endif
2016-12-21 21:59:40 +03:00
# define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
EASY_STRINGIFICATION ( EASY_PROFILER_VERSION_MINOR ) " . " \
EASY_STRINGIFICATION ( EASY_PROFILER_VERSION_PATCH )
2016-12-04 16:40:00 +03:00
2016-11-20 13:42:05 +03:00
# define EASY_VERSION_INT(v_major, v_minor, v_patch) ((static_cast<uint32_t>(v_major) << 24) | (static_cast<uint32_t>(v_minor) << 16) | static_cast<uint32_t>(v_patch))
extern const uint32_t PROFILER_SIGNATURE = ( ' E ' < < 24 ) | ( ' a ' < < 16 ) | ( ' s ' < < 8 ) | ' y ' ;
extern const uint32_t EASY_CURRENT_VERSION = EASY_VERSION_INT ( EASY_PROFILER_VERSION_MAJOR , EASY_PROFILER_VERSION_MINOR , EASY_PROFILER_VERSION_PATCH ) ;
# undef EASY_VERSION_INT
2016-11-16 22:17:39 +03:00
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
2016-12-21 21:59:40 +03:00
# define EASY_PROF_DISABLED 0
# define EASY_PROF_ENABLED 1
# define EASY_PROF_DUMP 2
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
//auto& MANAGER = ProfileManager::instance();
2016-11-20 13:42:05 +03:00
# define MANAGER ProfileManager::instance()
const uint8_t FORCE_ON_FLAG = profiler : : FORCE_ON & ~ profiler : : ON ;
2016-09-20 22:57:34 +03:00
# ifdef _WIN32
2016-11-20 13:42:05 +03:00
decltype ( LARGE_INTEGER : : QuadPart ) const CPU_FREQUENCY = ( [ ] ( ) { LARGE_INTEGER freq ; QueryPerformanceFrequency ( & freq ) ; return freq . QuadPart ; } ) ( ) ;
2016-09-20 22:57:34 +03:00
# endif
2017-02-08 22:35:46 +03:00
extern const profiler : : color_t EASY_COLOR_INTERNAL_EVENT = 0xffffffff ; // profiler::colors::White
const profiler : : color_t EASY_COLOR_THREAD_END = 0xff212121 ; // profiler::colors::Dark
const profiler : : color_t EASY_COLOR_START = 0xff4caf50 ; // profiler::colors::Green
const profiler : : color_t EASY_COLOR_END = 0xfff44336 ; // profiler::colors::Red
2016-09-20 22:57:34 +03:00
//////////////////////////////////////////////////////////////////////////
2016-11-20 13:42:05 +03:00
EASY_THREAD_LOCAL static : : ThreadStorage * THREAD_STORAGE = nullptr ;
2016-12-21 21:59:40 +03:00
EASY_THREAD_LOCAL static int32_t THREAD_STACK_SIZE = 0 ;
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
# ifdef BUILD_WITH_EASY_PROFILER
2016-12-12 22:26:32 +03:00
# define EASY_EVENT_RES(res, name, ...)\
EASY_LOCAL_STATIC_PTR ( const : : profiler : : BaseBlockDescriptor * , EASY_UNIQUE_DESC ( __LINE__ ) , MANAGER . addBlockDescriptor ( \
: : profiler : : extract_enable_flag ( __VA_ARGS__ ) , EASY_UNIQUE_LINE_ID , EASY_COMPILETIME_NAME ( name ) , \
__FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT , : : profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
res = MANAGER . storeBlock ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) )
2016-11-20 13:42:05 +03:00
# define EASY_FORCE_EVENT(timestamp, name, ...)\
2016-09-28 00:37:20 +03:00
EASY_LOCAL_STATIC_PTR ( const : : profiler : : BaseBlockDescriptor * , EASY_UNIQUE_DESC ( __LINE__ ) , addBlockDescriptor ( \
: : profiler : : extract_enable_flag ( __VA_ARGS__ ) , EASY_UNIQUE_LINE_ID , EASY_COMPILETIME_NAME ( name ) , \
__FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT , : : profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
2016-12-12 22:26:32 +03:00
storeBlockForce ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) , timestamp )
2016-09-28 00:37:20 +03:00
2016-11-20 13:42:05 +03:00
# define EASY_FORCE_EVENT2(timestamp, name, ...)\
2016-09-28 00:37:20 +03:00
EASY_LOCAL_STATIC_PTR ( const : : profiler : : BaseBlockDescriptor * , EASY_UNIQUE_DESC ( __LINE__ ) , addBlockDescriptor ( \
: : profiler : : extract_enable_flag ( __VA_ARGS__ ) , EASY_UNIQUE_LINE_ID , EASY_COMPILETIME_NAME ( name ) , \
__FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT , : : profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
2016-12-12 22:26:32 +03:00
storeBlockForce2 ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) , timestamp )
# define EASY_FORCE_EVENT3(ts, timestamp, name, ...)\
EASY_LOCAL_STATIC_PTR ( const : : profiler : : BaseBlockDescriptor * , EASY_UNIQUE_DESC ( __LINE__ ) , addBlockDescriptor ( \
: : profiler : : extract_enable_flag ( __VA_ARGS__ ) , EASY_UNIQUE_LINE_ID , EASY_COMPILETIME_NAME ( name ) , \
__FILE__ , __LINE__ , : : profiler : : BLOCK_TYPE_EVENT , : : profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
storeBlockForce2 ( ts , EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) , timestamp )
2016-11-20 13:42:05 +03:00
# else
2016-12-12 22:26:32 +03:00
# define EASY_EVENT_RES(res, name, ...)
2016-11-20 13:42:05 +03:00
# define EASY_FORCE_EVENT(timestamp, name, ...)
# define EASY_FORCE_EVENT2(timestamp, name, ...)
2016-12-12 22:26:32 +03:00
# define EASY_FORCE_EVENT3(ts, timestamp, name, ...)
2016-11-20 13:42:05 +03:00
# endif
2016-09-28 00:37:20 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
extern " C " {
2016-11-20 13:42:05 +03:00
# if !defined(EASY_PROFILER_API_DISABLED)
2016-12-21 21:59:40 +03:00
PROFILER_API const BaseBlockDescriptor * registerDescription ( EasyBlockStatus _status , const char * _autogenUniqueId , const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color , bool _copyName )
2016-09-18 19:02:12 +03:00
{
2016-12-21 21:59:40 +03:00
return MANAGER . addBlockDescriptor ( _status , _autogenUniqueId , _name , _filename , _line , _block_type , _color , _copyName ) ;
2016-09-18 19:02:12 +03:00
}
PROFILER_API void endBlock ( )
{
MANAGER . endBlock ( ) ;
}
PROFILER_API void setEnabled ( bool isEnable )
{
MANAGER . setEnabled ( isEnable ) ;
}
2016-09-22 23:06:43 +03:00
PROFILER_API void storeEvent ( const BaseBlockDescriptor * _desc , const char * _runtimeName )
2016-09-18 19:02:12 +03:00
{
MANAGER . storeBlock ( _desc , _runtimeName ) ;
}
PROFILER_API void beginBlock ( Block & _block )
{
MANAGER . beginBlock ( _block ) ;
}
PROFILER_API uint32_t dumpBlocksToFile ( const char * filename )
{
return MANAGER . dumpBlocksToFile ( filename ) ;
}
2016-11-20 17:09:50 +03:00
PROFILER_API const char * registerThreadScoped ( const char * name , ThreadGuard & threadGuard )
2016-09-18 19:02:12 +03:00
{
2016-09-20 22:57:34 +03:00
return MANAGER . registerThread ( name , threadGuard ) ;
2016-09-18 19:02:12 +03:00
}
2016-11-20 17:09:50 +03:00
PROFILER_API const char * registerThread ( const char * name )
{
return MANAGER . registerThread ( name ) ;
}
2016-09-18 19:02:12 +03:00
PROFILER_API void setEventTracingEnabled ( bool _isEnable )
{
MANAGER . setEventTracingEnabled ( _isEnable ) ;
}
2016-11-20 13:42:05 +03:00
# ifdef _WIN32
2016-09-18 19:02:12 +03:00
PROFILER_API void setLowPriorityEventTracing ( bool _isLowPriority )
{
EasyEventTracer : : instance ( ) . setLowPriority ( _isLowPriority ) ;
}
2016-11-20 13:42:05 +03:00
# else
2016-09-18 19:02:12 +03:00
PROFILER_API void setLowPriorityEventTracing ( bool ) { }
2016-11-20 13:42:05 +03:00
# endif
2016-09-18 19:02:12 +03:00
PROFILER_API void setContextSwitchLogFilename ( const char * name )
{
return MANAGER . setContextSwitchLogFilename ( name ) ;
}
PROFILER_API const char * getContextSwitchLogFilename ( )
{
return MANAGER . getContextSwitchLogFilename ( ) ;
}
2016-12-01 23:25:54 +03:00
PROFILER_API void startListen ( uint16_t _port )
2016-09-18 19:02:12 +03:00
{
2016-12-01 23:30:43 +03:00
return MANAGER . startListen ( _port ) ;
2016-09-18 19:02:12 +03:00
}
2016-12-01 23:25:54 +03:00
PROFILER_API void stopListen ( )
2016-09-18 19:02:12 +03:00
{
2016-12-01 23:30:43 +03:00
return MANAGER . stopListen ( ) ;
2016-09-18 19:02:12 +03:00
}
2016-11-20 13:42:05 +03:00
# else
2016-12-21 21:59:40 +03:00
PROFILER_API const BaseBlockDescriptor * registerDescription ( EasyBlockStatus , const char * , const char * , const char * , int , block_type_t , color_t , bool ) { return reinterpret_cast < const BaseBlockDescriptor * > ( 0xbad ) ; }
2016-11-20 13:42:05 +03:00
PROFILER_API void endBlock ( ) { }
PROFILER_API void setEnabled ( bool ) { }
PROFILER_API void storeEvent ( const BaseBlockDescriptor * , const char * ) { }
PROFILER_API void beginBlock ( Block & ) { }
PROFILER_API uint32_t dumpBlocksToFile ( const char * ) { return 0 ; }
2016-11-20 17:09:50 +03:00
PROFILER_API const char * registerThreadScoped ( const char * , ThreadGuard & ) { return " " ; }
PROFILER_API const char * registerThread ( const char * ) { return " " ; }
2016-11-20 13:42:05 +03:00
PROFILER_API void setEventTracingEnabled ( bool ) { }
PROFILER_API void setLowPriorityEventTracing ( bool ) { }
PROFILER_API void setContextSwitchLogFilename ( const char * ) { }
PROFILER_API const char * getContextSwitchLogFilename ( ) { return " " ; }
2016-12-01 23:30:43 +03:00
PROFILER_API void startListen ( uint16_t ) { }
PROFILER_API void stopListen ( ) { }
2016-11-20 13:42:05 +03:00
# endif
2016-09-18 19:02:12 +03:00
2016-11-16 22:17:39 +03:00
PROFILER_API uint8_t versionMajor ( )
{
2016-11-20 13:42:05 +03:00
static_assert ( 0 < = EASY_PROFILER_VERSION_MAJOR & & EASY_PROFILER_VERSION_MAJOR < = 255 , " EASY_PROFILER_VERSION_MAJOR must be defined in range [0, 255] " ) ;
return EASY_PROFILER_VERSION_MAJOR ;
2016-11-16 22:17:39 +03:00
}
PROFILER_API uint8_t versionMinor ( )
{
2016-11-20 13:42:05 +03:00
static_assert ( 0 < = EASY_PROFILER_VERSION_MINOR & & EASY_PROFILER_VERSION_MINOR < = 255 , " EASY_PROFILER_VERSION_MINOR must be defined in range [0, 255] " ) ;
return EASY_PROFILER_VERSION_MINOR ;
2016-11-16 22:17:39 +03:00
}
2016-11-20 13:42:05 +03:00
PROFILER_API uint16_t versionPatch ( )
2016-11-16 22:17:39 +03:00
{
2016-11-20 13:42:05 +03:00
static_assert ( 0 < = EASY_PROFILER_VERSION_PATCH & & EASY_PROFILER_VERSION_PATCH < = 65535 , " EASY_PROFILER_VERSION_PATCH must be defined in range [0, 65535] " ) ;
return EASY_PROFILER_VERSION_PATCH ;
2016-11-16 22:17:39 +03:00
}
PROFILER_API uint32_t version ( )
{
return EASY_CURRENT_VERSION ;
}
PROFILER_API const char * versionName ( )
{
2016-11-20 13:42:05 +03:00
return EASY_PROFILER_PRODUCT_VERSION
# ifdef EASY_PROFILER_API_DISABLED
" _disabled "
# endif
;
2016-11-16 22:17:39 +03:00
}
2016-09-18 19:02:12 +03:00
}
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
SerializedBlock : : SerializedBlock ( const Block & block , uint16_t name_length )
: BaseBlockData ( block )
{
auto pName = const_cast < char * > ( name ( ) ) ;
if ( name_length ) strncpy ( pName , block . name ( ) , name_length ) ;
pName [ name_length ] = 0 ;
}
//////////////////////////////////////////////////////////////////////////
2016-09-20 22:57:34 +03:00
BaseBlockDescriptor : : BaseBlockDescriptor ( block_id_t _id , EasyBlockStatus _status , int _line , block_type_t _block_type , color_t _color )
2016-09-18 19:02:12 +03:00
: m_id ( _id )
, m_line ( _line )
, m_type ( _block_type )
, m_color ( _color )
2016-09-20 22:57:34 +03:00
, m_status ( _status )
2016-09-18 19:02:12 +03:00
{
}
2016-09-22 23:06:43 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
2016-09-22 23:06:43 +03:00
# ifndef EASY_BLOCK_DESC_FULL_COPY
# define EASY_BLOCK_DESC_FULL_COPY 0
# endif
# if EASY_BLOCK_DESC_FULL_COPY == 0
# define EASY_BLOCK_DESC_STRING const char*
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(strlen(s) + 1)
# define EASY_BLOCK_DESC_STRING_VAL(s) s
# else
# define EASY_BLOCK_DESC_STRING std::string
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(s.size() + 1)
# define EASY_BLOCK_DESC_STRING_VAL(s) s.c_str()
# endif
2016-09-18 19:02:12 +03:00
2016-09-22 23:06:43 +03:00
class BlockDescriptor : public BaseBlockDescriptor
2016-09-18 19:02:12 +03:00
{
2016-09-22 23:06:43 +03:00
friend ProfileManager ;
EASY_BLOCK_DESC_STRING m_filename ; ///< Source file name where this block is declared
2016-12-21 21:59:40 +03:00
EASY_BLOCK_DESC_STRING 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
2016-09-22 23:06:43 +03:00
public :
BlockDescriptor ( block_id_t _id , EasyBlockStatus _status , const char * _name , const char * _filename , int _line , block_type_t _block_type , color_t _color )
: BaseBlockDescriptor ( _id , _status , _line , _block_type , _color )
, m_filename ( _filename )
2016-12-21 21:59:40 +03:00
, m_name ( _name )
2016-09-22 23:06:43 +03:00
{
}
const char * name ( ) const {
return EASY_BLOCK_DESC_STRING_VAL ( m_name ) ;
}
const char * filename ( ) const {
return EASY_BLOCK_DESC_STRING_VAL ( m_filename ) ;
}
uint16_t nameSize ( ) const {
return EASY_BLOCK_DESC_STRING_LEN ( m_name ) ;
}
uint16_t filenameSize ( ) const {
return EASY_BLOCK_DESC_STRING_LEN ( m_filename ) ;
}
} ; // END of class BlockDescriptor.
2016-09-18 19:02:12 +03:00
//////////////////////////////////////////////////////////////////////////
2016-12-12 22:26:32 +03:00
ThreadStorage : : ThreadStorage ( ) : id ( getCurrentThreadId ( ) ) , allowChildren ( true ) , named ( false ) , guarded ( false )
2016-11-28 22:58:16 +03:00
# ifndef _WIN32
, pthread_id ( pthread_self ( ) )
# endif
2016-11-20 17:09:50 +03:00
{
2016-12-12 22:26:32 +03:00
expired = ATOMIC_VAR_INIT ( 0 ) ;
2016-12-21 21:59:40 +03:00
frame = ATOMIC_VAR_INIT ( false ) ;
2016-11-20 17:09:50 +03:00
}
2016-09-18 19:02:12 +03:00
void ThreadStorage : : storeBlock ( const profiler : : Block & block )
{
2016-12-13 21:53:29 +03:00
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
2016-09-22 23:06:43 +03:00
EASY_LOCAL_STATIC_PTR ( const BaseBlockDescriptor * , desc , \
2016-12-13 21:53:29 +03:00
MANAGER . addBlockDescriptor ( EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON ? profiler : : ON : profiler : : OFF , EASY_UNIQUE_LINE_ID , " EasyProfiler.ExpandStorage " , \
2017-02-08 22:35:46 +03:00
__FILE__ , __LINE__ , profiler : : BLOCK_TYPE_BLOCK , EASY_COLOR_INTERNAL_EVENT ) ) ;
2016-09-22 23:06:43 +03:00
EASY_THREAD_LOCAL static profiler : : timestamp_t beginTime = 0ULL ;
EASY_THREAD_LOCAL static profiler : : timestamp_t endTime = 0ULL ;
2016-09-18 19:02:12 +03:00
# endif
auto name_length = static_cast < uint16_t > ( strlen ( block . name ( ) ) ) ;
auto size = static_cast < uint16_t > ( sizeof ( BaseBlockData ) + name_length + 1 ) ;
2016-12-13 21:53:29 +03:00
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
2016-09-20 22:57:34 +03:00
const bool expanded = ( desc - > m_status & profiler : : ON ) & & blocks . closedList . need_expand ( size ) ;
2016-09-22 23:06:43 +03:00
if ( expanded ) beginTime = getCurrentTime ( ) ;
2016-09-18 19:02:12 +03:00
# endif
auto data = blocks . closedList . allocate ( size ) ;
2016-12-13 21:53:29 +03:00
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
2016-09-22 23:06:43 +03:00
if ( expanded ) endTime = getCurrentTime ( ) ;
2016-09-18 19:02:12 +03:00
# endif
: : new ( data ) SerializedBlock ( block , name_length ) ;
blocks . usedMemorySize + = size ;
2016-12-13 21:53:29 +03:00
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
2016-09-18 19:02:12 +03:00
if ( expanded )
{
2016-09-22 23:06:43 +03:00
profiler : : Block b ( beginTime , desc - > id ( ) , " " ) ;
b . finish ( endTime ) ;
2016-09-18 19:02:12 +03:00
size = static_cast < uint16_t > ( sizeof ( BaseBlockData ) + 1 ) ;
data = blocks . closedList . allocate ( size ) ;
2016-09-22 23:06:43 +03:00
: : new ( data ) SerializedBlock ( b , 0 ) ;
2016-09-18 19:02:12 +03:00
blocks . usedMemorySize + = size ;
}
# endif
}
void ThreadStorage : : storeCSwitch ( const profiler : : Block & block )
{
auto name_length = static_cast < uint16_t > ( strlen ( block . name ( ) ) ) ;
auto size = static_cast < uint16_t > ( sizeof ( BaseBlockData ) + name_length + 1 ) ;
auto data = sync . closedList . allocate ( size ) ;
: : new ( data ) SerializedBlock ( block , name_length ) ;
sync . usedMemorySize + = size ;
}
void ThreadStorage : : clearClosed ( )
{
blocks . clearClosed ( ) ;
sync . clearClosed ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2016-09-20 22:57:34 +03:00
ThreadGuard : : ~ ThreadGuard ( )
{
2016-11-20 13:42:05 +03:00
# ifndef EASY_PROFILER_API_DISABLED
2016-09-20 22:57:34 +03:00
if ( m_id ! = 0 & & THREAD_STORAGE ! = nullptr & & THREAD_STORAGE - > id = = m_id )
{
2016-12-12 22:26:32 +03:00
bool isMarked = false ;
2017-02-08 22:35:46 +03:00
EASY_EVENT_RES ( isMarked , " ThreadFinished " , EASY_COLOR_THREAD_END , : : profiler : : FORCE_ON ) ;
2016-12-21 21:59:40 +03:00
THREAD_STORAGE - > frame . store ( false , std : : memory_order_release ) ;
2016-12-12 22:26:32 +03:00
THREAD_STORAGE - > expired . store ( isMarked ? 2 : 1 , std : : memory_order_release ) ;
2016-09-20 22:57:34 +03:00
THREAD_STORAGE = nullptr ;
}
2016-11-20 13:42:05 +03:00
# endif
2016-09-20 22:57:34 +03:00
}
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
2016-12-12 22:26:32 +03:00
ProfileManager : : ProfileManager ( ) :
# ifdef _WIN32
m_processId ( GetProcessId ( GetCurrentProcess ( ) ) )
# else
m_processId ( ( processid_t ) getpid ( ) )
# endif
, m_usedMemorySize ( 0 )
, m_beginTime ( 0 )
, m_endTime ( 0 )
2016-09-17 11:10:25 +03:00
{
2016-12-21 21:59:40 +03:00
m_profilerStatus = ATOMIC_VAR_INIT ( EASY_PROF_DISABLED ) ;
2016-12-13 21:53:29 +03:00
m_isEventTracingEnabled = ATOMIC_VAR_INIT ( EASY_OPTION_EVENT_TRACING_ENABLED ) ;
2016-12-01 23:30:43 +03:00
m_isAlreadyListening = ATOMIC_VAR_INIT ( false ) ;
2016-09-18 19:02:12 +03:00
m_stopListen = ATOMIC_VAR_INIT ( false ) ;
2016-12-13 21:53:29 +03:00
# if !defined(EASY_PROFILER_API_DISABLED) && EASY_OPTION_START_LISTEN_ON_STARTUP != 0
startListen ( profiler : : DEFAULT_PORT ) ;
# endif
2016-09-18 19:02:12 +03:00
}
ProfileManager : : ~ ProfileManager ( )
{
2016-11-20 13:42:05 +03:00
# ifndef EASY_PROFILER_API_DISABLED
2016-12-01 23:30:43 +03:00
stopListen ( ) ;
2016-11-20 13:42:05 +03:00
# endif
2016-09-20 22:57:34 +03:00
2016-12-21 21:59:40 +03:00
for ( auto desc : m_descriptors ) {
# if EASY_BLOCK_DESC_FULL_COPY == 0
if ( desc )
desc - > ~ BlockDescriptor ( ) ;
free ( desc ) ;
# else
2016-12-08 22:19:45 +03:00
delete desc ;
2016-12-21 21:59:40 +03:00
# endif
}
2016-09-18 19:02:12 +03:00
}
2016-09-22 23:06:43 +03:00
# ifndef EASY_MAGIC_STATIC_CPP11
class ProfileManagerInstance {
friend ProfileManager ;
ProfileManager instance ;
} PROFILE_MANAGER ;
# endif
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
ProfileManager & ProfileManager : : instance ( )
{
2016-09-22 23:06:43 +03:00
# ifndef EASY_MAGIC_STATIC_CPP11
return PROFILE_MANAGER . instance ;
# else
2016-09-18 19:02:12 +03:00
///C++11 makes possible to create Singleton without any warry about thread-safeness
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
2016-09-22 23:06:43 +03:00
static ProfileManager profileManager ;
return profileManager ;
# endif
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
ThreadStorage & ProfileManager : : _threadStorage ( profiler : : thread_id_t _thread_id )
2016-09-11 16:57:35 +03:00
{
return m_threads [ _thread_id ] ;
}
2016-09-13 23:03:01 +03:00
ThreadStorage * ProfileManager : : _findThreadStorage ( profiler : : thread_id_t _thread_id )
2016-09-11 16:57:35 +03:00
{
auto it = m_threads . find ( _thread_id ) ;
return it ! = m_threads . end ( ) ? & it - > second : nullptr ;
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-22 23:06:43 +03:00
const BaseBlockDescriptor * ProfileManager : : addBlockDescriptor ( EasyBlockStatus _defaultStatus ,
const char * _autogenUniqueId ,
const char * _name ,
const char * _filename ,
int _line ,
block_type_t _block_type ,
2016-12-21 21:59:40 +03:00
color_t _color ,
bool _copyName )
2016-09-22 23:06:43 +03:00
{
guard_lock_t lock ( m_storedSpin ) ;
descriptors_map_t : : key_type key ( _autogenUniqueId ) ;
auto it = m_descriptorsMap . find ( key ) ;
if ( it ! = m_descriptorsMap . end ( ) )
return m_descriptors [ it - > second ] ;
2016-12-21 21:59:40 +03:00
const auto nameLen = strlen ( _name ) ;
m_usedMemorySize + = sizeof ( profiler : : SerializedBlockDescriptor ) + nameLen + strlen ( _filename ) + 2 ;
# if EASY_BLOCK_DESC_FULL_COPY == 0
BlockDescriptor * desc = nullptr ;
if ( _copyName )
{
void * data = malloc ( sizeof ( BlockDescriptor ) + nameLen + 1 ) ;
char * name = reinterpret_cast < char * > ( data ) + sizeof ( BlockDescriptor ) ;
strncpy ( name , _name , nameLen ) ;
desc = : : new ( data ) BlockDescriptor ( static_cast < block_id_t > ( m_descriptors . size ( ) ) , _defaultStatus , name , _filename , _line , _block_type , _color ) ;
}
else
{
void * data = malloc ( sizeof ( BlockDescriptor ) ) ;
desc = : : new ( data ) BlockDescriptor ( static_cast < block_id_t > ( m_descriptors . size ( ) ) , _defaultStatus , _name , _filename , _line , _block_type , _color ) ;
}
# else
2016-09-22 23:06:43 +03:00
auto desc = new BlockDescriptor ( static_cast < block_id_t > ( m_descriptors . size ( ) ) , _defaultStatus , _name , _filename , _line , _block_type , _color ) ;
2016-12-21 21:59:40 +03:00
# endif
2016-09-22 23:06:43 +03:00
m_descriptors . emplace_back ( desc ) ;
m_descriptorsMap . emplace ( key , desc - > id ( ) ) ;
return desc ;
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
bool ProfileManager : : storeBlock ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName )
2016-09-18 19:02:12 +03:00
{
2016-12-21 21:59:40 +03:00
const auto state = m_profilerStatus . load ( std : : memory_order_acquire ) ;
if ( state = = EASY_PROF_DISABLED | | ! ( _desc - > m_status & profiler : : ON ) )
2016-12-12 22:26:32 +03:00
return false ;
2016-09-18 19:02:12 +03:00
2016-12-21 21:59:40 +03:00
if ( state = = EASY_PROF_DUMP )
{
if ( THREAD_STORAGE = = nullptr | | THREAD_STORAGE - > blocks . openedList . empty ( ) )
return false ;
}
else if ( THREAD_STORAGE = = nullptr )
{
2016-09-18 19:02:12 +03:00
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-12-21 21:59:40 +03:00
}
2016-09-18 19:02:12 +03:00
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2016-12-12 22:26:32 +03:00
if ( ! THREAD_STORAGE - > allowChildren & & ! ( _desc - > m_status & FORCE_ON_FLAG ) )
return false ;
2016-09-20 22:57:34 +03:00
# endif
profiler : : Block b ( _desc , _runtimeName ) ;
b . start ( ) ;
b . m_end = b . m_begin ;
2016-09-18 19:02:12 +03:00
THREAD_STORAGE - > storeBlock ( b ) ;
2016-12-12 22:26:32 +03:00
return true ;
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-28 00:37:20 +03:00
void ProfileManager : : storeBlockForce ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName , : : profiler : : timestamp_t & _timestamp )
{
if ( ! ( _desc - > m_status & profiler : : ON ) )
return ;
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
# if EASY_ENABLE_BLOCK_STATUS != 0
2016-12-12 22:26:32 +03:00
if ( ! THREAD_STORAGE - > allowChildren & & ! ( _desc - > m_status & FORCE_ON_FLAG ) )
2016-09-28 00:37:20 +03:00
return ;
# endif
profiler : : Block b ( _desc , _runtimeName ) ;
b . start ( ) ;
b . m_end = b . m_begin ;
_timestamp = b . m_begin ;
THREAD_STORAGE - > storeBlock ( b ) ;
}
void ProfileManager : : storeBlockForce2 ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName , : : profiler : : timestamp_t _timestamp )
{
if ( ! ( _desc - > m_status & profiler : : ON ) )
return ;
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
# if EASY_ENABLE_BLOCK_STATUS != 0
2016-12-12 22:26:32 +03:00
if ( ! THREAD_STORAGE - > allowChildren & & ! ( _desc - > m_status & FORCE_ON_FLAG ) )
2016-09-28 00:37:20 +03:00
return ;
# endif
profiler : : Block b ( _desc , _runtimeName ) ;
b . m_end = b . m_begin = _timestamp ;
THREAD_STORAGE - > storeBlock ( b ) ;
}
2016-12-12 22:26:32 +03:00
void ProfileManager : : storeBlockForce2 ( ThreadStorage & _registeredThread , const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName , : : profiler : : timestamp_t _timestamp )
{
profiler : : Block b ( _desc , _runtimeName ) ;
b . m_end = b . m_begin = _timestamp ;
_registeredThread . storeBlock ( b ) ;
}
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
void ProfileManager : : beginBlock ( Block & _block )
{
2016-12-21 21:59:40 +03:00
if ( + + THREAD_STACK_SIZE > 1 )
2016-09-18 19:02:12 +03:00
return ;
2016-12-21 21:59:40 +03:00
const auto state = m_profilerStatus . load ( std : : memory_order_acquire ) ;
if ( state = = EASY_PROF_DISABLED )
return ;
THREAD_STACK_SIZE = 0 ;
bool empty = true ;
if ( state = = EASY_PROF_DUMP )
{
if ( THREAD_STORAGE = = nullptr | | THREAD_STORAGE - > blocks . openedList . empty ( ) )
return ;
empty = false ;
}
else if ( THREAD_STORAGE = = nullptr )
{
2016-09-18 19:02:12 +03:00
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-12-21 21:59:40 +03:00
}
else
{
empty = THREAD_STORAGE - > blocks . openedList . empty ( ) ;
}
2016-09-18 19:02:12 +03:00
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
if ( THREAD_STORAGE - > allowChildren )
{
# endif
if ( _block . m_status & profiler : : ON )
_block . start ( ) ;
# if EASY_ENABLE_BLOCK_STATUS != 0
THREAD_STORAGE - > allowChildren = ! ( _block . m_status & profiler : : OFF_RECURSIVE ) ;
}
else if ( _block . m_status & FORCE_ON_FLAG )
{
_block . start ( ) ;
_block . m_status = profiler : : FORCE_ON_WITHOUT_CHILDREN ;
}
else
{
_block . m_status = profiler : : OFF_RECURSIVE ;
}
# endif
2016-12-21 21:59:40 +03:00
if ( empty )
THREAD_STORAGE - > frame . store ( true , std : : memory_order_release ) ;
2016-09-18 19:02:12 +03:00
THREAD_STORAGE - > blocks . openedList . emplace ( _block ) ;
}
void ProfileManager : : beginContextSwitch ( profiler : : thread_id_t _thread_id , profiler : : timestamp_t _time , profiler : : thread_id_t _target_thread_id , const char * _target_process , bool _lockSpin )
{
auto ts = _lockSpin ? findThreadStorage ( _thread_id ) : _findThreadStorage ( _thread_id ) ;
if ( ts ! = nullptr )
// Dirty hack: _target_thread_id will be written to the field "block_id_t m_id"
// and will be available calling method id().
ts - > sync . openedList . emplace ( _time , _target_thread_id , _target_process ) ;
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
void ProfileManager : : endBlock ( )
{
2016-12-21 21:59:40 +03:00
if ( - - THREAD_STACK_SIZE > 0 | | m_profilerStatus . load ( std : : memory_order_acquire ) = = EASY_PROF_DISABLED )
2016-09-18 19:02:12 +03:00
return ;
2016-12-21 21:59:40 +03:00
THREAD_STACK_SIZE = 0 ;
2016-11-20 14:37:42 +03:00
if ( THREAD_STORAGE = = nullptr | | THREAD_STORAGE - > blocks . openedList . empty ( ) )
2016-09-18 19:02:12 +03:00
return ;
Block & lastBlock = THREAD_STORAGE - > blocks . openedList . top ( ) ;
2016-09-20 22:57:34 +03:00
if ( lastBlock . m_status & profiler : : ON )
2016-09-18 19:02:12 +03:00
{
if ( ! lastBlock . finished ( ) )
lastBlock . finish ( ) ;
THREAD_STORAGE - > storeBlock ( lastBlock ) ;
}
2016-09-20 22:57:34 +03:00
else
{
lastBlock . m_end = lastBlock . m_begin ; // this is to restrict endBlock() call inside ~Block()
}
2016-09-18 19:02:12 +03:00
THREAD_STORAGE - > blocks . openedList . pop ( ) ;
2016-12-21 21:59:40 +03:00
const bool empty = THREAD_STORAGE - > blocks . openedList . empty ( ) ;
if ( empty )
THREAD_STORAGE - > frame . store ( false , std : : memory_order_release ) ;
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2016-12-21 21:59:40 +03:00
THREAD_STORAGE - > allowChildren = empty | | ! ( THREAD_STORAGE - > blocks . openedList . top ( ) . get ( ) . m_status & profiler : : OFF_RECURSIVE ) ;
2016-09-20 22:57:34 +03:00
# endif
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
void ProfileManager : : endContextSwitch ( profiler : : thread_id_t _thread_id , processid_t _process_id , profiler : : timestamp_t _endtime , bool _lockSpin )
2016-09-18 19:02:12 +03:00
{
2016-12-12 22:26:32 +03:00
ThreadStorage * ts = nullptr ;
if ( _process_id = = m_processId )
// If thread owned by current process then create new ThreadStorage if there is no one
ts = _lockSpin ? & threadStorage ( _thread_id ) : & _threadStorage ( _thread_id ) ;
else
// If thread owned by another process OR _process_id IS UNKNOWN then do not create ThreadStorage for this
ts = _lockSpin ? findThreadStorage ( _thread_id ) : _findThreadStorage ( _thread_id ) ;
2016-09-18 19:02:12 +03:00
if ( ts = = nullptr | | ts - > sync . openedList . empty ( ) )
return ;
Block & lastBlock = ts - > sync . openedList . top ( ) ;
lastBlock . finish ( _endtime ) ;
ts - > storeCSwitch ( lastBlock ) ;
ts - > sync . openedList . pop ( ) ;
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-12-21 21:59:40 +03:00
void ProfileManager : : enableEventTracer ( )
{
# ifdef _WIN32
if ( m_isEventTracingEnabled . load ( std : : memory_order_acquire ) )
EasyEventTracer : : instance ( ) . enable ( true ) ;
# endif
}
void ProfileManager : : disableEventTracer ( )
{
# ifdef _WIN32
EasyEventTracer : : instance ( ) . disable ( ) ;
# endif
}
void ProfileManager : : setEnabled ( bool isEnable )
2016-09-18 19:02:12 +03:00
{
2016-12-21 21:59:40 +03:00
guard_lock_t lock ( m_dumpSpin ) ;
2016-09-22 23:06:43 +03:00
auto time = getCurrentTime ( ) ;
2016-12-21 21:59:40 +03:00
const auto status = isEnable ? EASY_PROF_ENABLED : EASY_PROF_DISABLED ;
const auto prev = m_profilerStatus . exchange ( status , std : : memory_order_release ) ;
if ( prev = = status )
2016-09-22 23:06:43 +03:00
return ;
2016-09-18 19:02:12 +03:00
2016-09-22 23:06:43 +03:00
if ( isEnable )
{
2016-12-21 21:59:40 +03:00
enableEventTracer ( ) ;
m_beginTime = time ;
2016-09-22 23:06:43 +03:00
}
else
{
2016-12-21 21:59:40 +03:00
disableEventTracer ( ) ;
m_endTime = time ;
2016-09-24 00:15:33 +03:00
}
2016-09-18 19:02:12 +03:00
}
void ProfileManager : : setEventTracingEnabled ( bool _isEnable )
{
m_isEventTracingEnabled . store ( _isEnable , std : : memory_order_release ) ;
}
//////////////////////////////////////////////////////////////////////////
2016-12-21 21:59:40 +03:00
char ProfileManager : : checkThreadExpired ( ThreadStorage & _registeredThread )
2016-11-20 17:09:50 +03:00
{
2016-12-21 21:59:40 +03:00
const char val = _registeredThread . expired . load ( std : : memory_order_acquire ) ;
2016-12-12 22:26:32 +03:00
if ( val ! = 0 )
return val ;
if ( _registeredThread . guarded )
return 0 ;
2016-11-20 17:09:50 +03:00
# ifdef _WIN32
// Check thread for Windows
DWORD exitCode = 0 ;
auto hThread = OpenThread ( THREAD_QUERY_LIMITED_INFORMATION , FALSE , _registeredThread . id ) ;
2016-11-27 14:26:00 +03:00
if ( hThread = = nullptr | | GetExitCodeThread ( hThread , & exitCode ) = = FALSE | | exitCode ! = STILL_ACTIVE )
2016-11-20 17:09:50 +03:00
{
// Thread has been expired
2016-12-21 21:59:40 +03:00
_registeredThread . expired . store ( 1 , std : : memory_order_release ) ;
2016-11-20 17:09:50 +03:00
if ( hThread ! = nullptr )
CloseHandle ( hThread ) ;
2016-12-12 22:26:32 +03:00
return 1 ;
2016-11-20 17:09:50 +03:00
}
if ( hThread ! = nullptr )
CloseHandle ( hThread ) ;
2016-12-12 22:26:32 +03:00
return 0 ;
2016-11-20 17:09:50 +03:00
# else
2016-12-12 22:26:32 +03:00
return 0 ; //pthread_kill(_registeredThread.pthread_id, 0) != 0;
2016-11-20 17:09:50 +03:00
# endif
}
//////////////////////////////////////////////////////////////////////////
2016-12-21 21:59:40 +03:00
uint32_t ProfileManager : : dumpBlocksToStream ( profiler : : OStream & _outputStream , bool _lockSpin )
2016-09-18 19:02:12 +03:00
{
2016-12-21 21:59:40 +03:00
if ( _lockSpin )
m_dumpSpin . lock ( ) ;
const auto state = m_profilerStatus . load ( std : : memory_order_acquire ) ;
2016-09-18 19:02:12 +03:00
# ifndef _WIN32
const bool eventTracingEnabled = m_isEventTracingEnabled . load ( std : : memory_order_acquire ) ;
# endif
2016-12-21 21:59:40 +03:00
if ( state = = EASY_PROF_ENABLED ) {
m_profilerStatus . store ( EASY_PROF_DUMP , std : : memory_order_release ) ;
disableEventTracer ( ) ;
m_endTime = getCurrentTime ( ) ;
}
2016-09-18 19:02:12 +03:00
2016-09-20 22:57:34 +03:00
2016-09-18 19:02:12 +03:00
// This is to make sure that no new descriptors or new threads will be
// added until we finish sending data.
2016-12-21 21:59:40 +03:00
//m_spin.lock();
2016-09-18 19:02:12 +03:00
// This is the only place using both spins, so no dead-lock will occur
2016-09-20 22:57:34 +03:00
// Wait for some time to be sure that all operations which began before setEnabled(false) will be finished.
// This is much better than inserting spin-lock or atomic variable check into each store operation.
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 20 ) ) ;
2016-12-21 21:59:40 +03:00
// wait for all threads finish opened frames
for ( auto it = m_threads . begin ( ) , end = m_threads . end ( ) ; it ! = end ; )
{
if ( ! it - > second . frame . load ( std : : memory_order_acquire ) )
+ + it ;
else
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
}
m_profilerStatus . store ( EASY_PROF_DISABLED , std : : memory_order_release ) ;
m_spin . lock ( ) ;
m_storedSpin . lock ( ) ;
2016-09-20 22:57:34 +03:00
// TODO: think about better solution because this one is not 100% safe...
2016-12-12 22:26:32 +03:00
const profiler : : timestamp_t now = getCurrentTime ( ) ;
const profiler : : timestamp_t endtime = m_endTime = = 0 ? now : std : : min ( now , m_endTime ) ;
2016-09-20 22:57:34 +03:00
2016-09-18 19:02:12 +03:00
# ifndef _WIN32
if ( eventTracingEnabled )
{
// Read thread context switch events from temporary file
uint64_t timestamp = 0 ;
uint32_t thread_from = 0 , thread_to = 0 ;
std : : ifstream infile ( m_csInfoFilename . c_str ( ) ) ;
if ( infile . is_open ( ) ) {
2016-12-01 23:25:54 +03:00
std : : string next_task_name ;
2016-12-12 22:26:32 +03:00
pid_t process_to = 0 ;
while ( infile > > timestamp > > thread_from > > thread_to > > next_task_name > > process_to ) {
2016-12-01 23:25:54 +03:00
beginContextSwitch ( thread_from , timestamp , thread_to , next_task_name . c_str ( ) , false ) ;
2016-12-12 22:26:32 +03:00
endContextSwitch ( thread_to , ( processid_t ) process_to , timestamp , false ) ;
2016-09-18 19:02:12 +03:00
}
}
}
# endif
// Calculate used memory total size and total blocks number
uint64_t usedMemorySize = 0 ;
uint32_t blocks_number = 0 ;
2016-09-20 22:57:34 +03:00
for ( auto it = m_threads . begin ( ) , end = m_threads . end ( ) ; it ! = end ; )
2016-09-18 19:02:12 +03:00
{
2016-11-20 17:09:50 +03:00
auto & t = it - > second ;
2016-12-12 22:26:32 +03:00
uint32_t num = static_cast < uint32_t > ( t . blocks . closedList . size ( ) ) + static_cast < uint32_t > ( t . sync . closedList . size ( ) ) ;
2016-09-20 22:57:34 +03:00
2016-12-21 21:59:40 +03:00
const char expired = checkThreadExpired ( t ) ;
2016-12-12 22:26:32 +03:00
if ( num = = 0 & & ( expired ! = 0 | | ! t . guarded ) ) {
// Remove thread if it contains no profiled information and has been finished or is not guarded.
2016-09-20 22:57:34 +03:00
m_threads . erase ( it + + ) ;
continue ;
}
2016-12-12 22:26:32 +03:00
if ( expired = = 1 ) {
2017-02-08 22:35:46 +03:00
EASY_FORCE_EVENT3 ( t , endtime , " ThreadExpired " , EASY_COLOR_THREAD_END ) ;
2016-12-12 22:26:32 +03:00
+ + num ;
}
2016-09-18 19:02:12 +03:00
usedMemorySize + = t . blocks . usedMemorySize + t . sync . usedMemorySize ;
2016-09-20 22:57:34 +03:00
blocks_number + = num ;
+ + it ;
2016-09-18 19:02:12 +03:00
}
2016-09-27 22:28:04 +03:00
// Write profiler signature and version
_outputStream . write ( PROFILER_SIGNATURE ) ;
2016-11-16 22:17:39 +03:00
_outputStream . write ( EASY_CURRENT_VERSION ) ;
2016-12-12 22:26:32 +03:00
_outputStream . write ( m_processId ) ;
2016-09-27 22:28:04 +03:00
2016-09-18 19:02:12 +03:00
// Write CPU frequency to let GUI calculate real time value from CPU clocks
# ifdef _WIN32
_outputStream . write ( CPU_FREQUENCY ) ;
# else
2016-09-26 23:11:25 +03:00
# if !defined(USE_STD_CHRONO)
double g_TicksPerNanoSec ;
struct timespec begints , endts ;
uint64_t begin = 0 , end = 0 ;
clock_gettime ( CLOCK_MONOTONIC , & begints ) ;
begin = getCurrentTime ( ) ;
volatile uint64_t i ;
for ( i = 0 ; i < 100000000 ; i + + ) ; /* must be CPU intensive */
end = getCurrentTime ( ) ;
clock_gettime ( CLOCK_MONOTONIC , & endts ) ;
struct timespec tmpts ;
const int NANO_SECONDS_IN_SEC = 1000000000 ;
tmpts . tv_sec = endts . tv_sec - begints . tv_sec ;
tmpts . tv_nsec = endts . tv_nsec - begints . tv_nsec ;
if ( tmpts . tv_nsec < 0 ) {
tmpts . tv_sec - - ;
tmpts . tv_nsec + = NANO_SECONDS_IN_SEC ;
}
uint64_t nsecElapsed = tmpts . tv_sec * 1000000000LL + tmpts . tv_nsec ;
g_TicksPerNanoSec = ( double ) ( end - begin ) / ( double ) nsecElapsed ;
int64_t cpu_frequency = int ( g_TicksPerNanoSec * 1000000 ) ;
_outputStream . write ( cpu_frequency * 1000LL ) ;
# else
2016-09-18 19:02:12 +03:00
_outputStream . write ( 0LL ) ;
2016-09-26 23:11:25 +03:00
# endif
2016-09-18 19:02:12 +03:00
# endif
2016-09-22 23:06:43 +03:00
// Write begin and end time
_outputStream . write ( m_beginTime ) ;
_outputStream . write ( m_endTime ) ;
2016-09-18 19:02:12 +03:00
// Write blocks number and used memory size
_outputStream . write ( blocks_number ) ;
_outputStream . write ( usedMemorySize ) ;
_outputStream . write ( static_cast < uint32_t > ( m_descriptors . size ( ) ) ) ;
_outputStream . write ( m_usedMemorySize ) ;
// Write block descriptors
for ( const auto descriptor : m_descriptors )
{
2016-09-22 23:06:43 +03:00
const auto name_size = descriptor - > nameSize ( ) ;
const auto filename_size = descriptor - > filenameSize ( ) ;
2016-09-18 19:02:12 +03:00
const auto size = static_cast < uint16_t > ( sizeof ( profiler : : SerializedBlockDescriptor ) + name_size + filename_size ) ;
_outputStream . write ( size ) ;
_outputStream . write < profiler : : BaseBlockDescriptor > ( * descriptor ) ;
_outputStream . write ( name_size ) ;
_outputStream . write ( descriptor - > name ( ) , name_size ) ;
2016-09-22 23:06:43 +03:00
_outputStream . write ( descriptor - > filename ( ) , filename_size ) ;
2016-09-18 19:02:12 +03:00
}
// Write blocks and context switch events for each thread
2016-09-20 22:57:34 +03:00
for ( auto it = m_threads . begin ( ) , end = m_threads . end ( ) ; it ! = end ; )
2016-09-18 19:02:12 +03:00
{
2016-09-20 22:57:34 +03:00
auto & t = it - > second ;
2016-09-18 19:02:12 +03:00
2016-09-20 22:57:34 +03:00
_outputStream . write ( it - > first ) ;
2016-09-18 19:02:12 +03:00
const auto name_size = static_cast < uint16_t > ( t . name . size ( ) + 1 ) ;
_outputStream . write ( name_size ) ;
_outputStream . write ( name_size > 1 ? t . name . c_str ( ) : " " , name_size ) ;
_outputStream . write ( t . sync . closedList . size ( ) ) ;
if ( ! t . sync . closedList . empty ( ) )
t . sync . closedList . serialize ( _outputStream ) ;
_outputStream . write ( t . blocks . closedList . size ( ) ) ;
if ( ! t . blocks . closedList . empty ( ) )
t . blocks . closedList . serialize ( _outputStream ) ;
t . clearClosed ( ) ;
t . blocks . openedList . clear ( ) ;
t . sync . openedList . clear ( ) ;
2016-09-20 22:57:34 +03:00
2016-12-12 22:26:32 +03:00
if ( t . expired . load ( std : : memory_order_acquire ) ! = 0 )
2016-09-20 22:57:34 +03:00
m_threads . erase ( it + + ) ; // Remove expired thread after writing all profiled information
else
+ + it ;
2016-09-18 19:02:12 +03:00
}
2016-12-21 21:59:40 +03:00
m_storedSpin . unlock ( ) ;
m_spin . unlock ( ) ;
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
2016-09-18 19:02:12 +03:00
return blocks_number ;
}
uint32_t ProfileManager : : dumpBlocksToFile ( const char * _filename )
{
2017-02-08 22:06:38 +03:00
std : : ofstream outputFile ( _filename , std : : fstream : : binary ) ;
if ( ! outputFile . is_open ( ) )
return 0 ;
2016-09-18 19:02:12 +03:00
profiler : : OStream outputStream ;
2017-02-08 22:06:38 +03:00
// Replace outputStream buffer to outputFile buffer to avoid redundant copying
typedef : : std : : basic_iostream < std : : stringstream : : char_type , std : : stringstream : : traits_type > stringstream_parent ;
stringstream_parent & s = outputStream . stream ( ) ;
auto oldbuf = s . rdbuf ( outputFile . rdbuf ( ) ) ;
// Write data directly to file
2016-12-21 21:59:40 +03:00
const auto blocksNumber = dumpBlocksToStream ( outputStream , true ) ;
2016-09-18 19:02:12 +03:00
2017-02-08 22:06:38 +03:00
// Restore old outputStream buffer to avoid possible second memory free on stringstream destructor
s . rdbuf ( oldbuf ) ;
2016-09-18 19:02:12 +03:00
return blocksNumber ;
}
2016-09-20 22:57:34 +03:00
const char * ProfileManager : : registerThread ( const char * name , ThreadGuard & threadGuard )
2016-09-18 19:02:12 +03:00
{
2016-11-20 17:09:50 +03:00
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-12-12 22:26:32 +03:00
THREAD_STORAGE - > guarded = true ;
2016-11-20 17:09:50 +03:00
if ( ! THREAD_STORAGE - > named ) {
THREAD_STORAGE - > named = true ;
THREAD_STORAGE - > name = name ;
2016-09-18 19:02:12 +03:00
}
2016-11-20 17:09:50 +03:00
threadGuard . m_id = THREAD_STORAGE - > id ;
return THREAD_STORAGE - > name . c_str ( ) ;
}
const char * ProfileManager : : registerThread ( const char * name )
{
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-09-20 22:57:34 +03:00
2016-11-20 17:09:50 +03:00
if ( ! THREAD_STORAGE - > named ) {
2016-09-18 19:02:12 +03:00
THREAD_STORAGE - > named = true ;
THREAD_STORAGE - > name = name ;
}
return THREAD_STORAGE - > name . c_str ( ) ;
}
2016-09-22 23:06:43 +03:00
void ProfileManager : : setBlockStatus ( block_id_t _id , EasyBlockStatus _status )
2016-09-18 19:02:12 +03:00
{
2016-12-21 21:59:40 +03:00
if ( m_profilerStatus . load ( std : : memory_order_acquire ) ! = EASY_PROF_ENABLED )
2016-09-22 23:06:43 +03:00
return ; // Changing blocks statuses is restricted while profile session is active
2016-09-18 19:02:12 +03:00
2016-09-22 23:06:43 +03:00
guard_lock_t lock ( m_storedSpin ) ;
if ( _id < m_descriptors . size ( ) )
2016-09-18 19:02:12 +03:00
{
2016-09-22 23:06:43 +03:00
auto desc = m_descriptors [ _id ] ;
2016-09-18 19:02:12 +03:00
lock . unlock ( ) ;
2016-09-22 23:06:43 +03:00
desc - > m_status = _status ;
2016-09-18 19:02:12 +03:00
}
}
2016-12-01 23:30:43 +03:00
void ProfileManager : : startListen ( uint16_t _port )
2016-09-18 19:02:12 +03:00
{
2016-12-01 23:30:43 +03:00
if ( ! m_isAlreadyListening . exchange ( true , std : : memory_order_release ) )
2016-09-18 19:02:12 +03:00
{
2016-09-25 11:49:49 +03:00
m_stopListen . store ( false , std : : memory_order_release ) ;
2017-02-07 17:07:25 +01:00
m_listenThread = std : : thread ( & ProfileManager : : listen , this , _port ) ;
2016-09-18 19:02:12 +03:00
}
}
2016-12-01 23:30:43 +03:00
void ProfileManager : : stopListen ( )
2016-09-18 19:02:12 +03:00
{
2016-09-25 11:49:49 +03:00
m_stopListen . store ( true , std : : memory_order_release ) ;
2016-09-28 00:37:20 +03:00
if ( m_listenThread . joinable ( ) )
m_listenThread . join ( ) ;
2016-12-01 23:30:43 +03:00
m_isAlreadyListening . store ( false , std : : memory_order_release ) ;
2016-09-18 19:02:12 +03:00
}
//////////////////////////////////////////////////////////////////////////
2016-09-25 11:49:49 +03:00
//#define EASY_DEBUG_NET_PRINT
2016-12-01 23:25:54 +03:00
void ProfileManager : : listen ( uint16_t _port )
2016-09-18 19:02:12 +03:00
{
2016-11-20 17:09:50 +03:00
EASY_THREAD_SCOPE ( " EasyProfiler.Listen " ) ;
2016-09-18 19:02:12 +03:00
EasySocket socket ;
profiler : : net : : Message replyMessage ( profiler : : net : : MESSAGE_TYPE_REPLY_START_CAPTURING ) ;
2016-12-01 23:25:54 +03:00
socket . bind ( _port ) ;
2016-09-18 19:02:12 +03:00
int bytes = 0 ;
2016-09-25 11:49:49 +03:00
while ( ! m_stopListen . load ( std : : memory_order_acquire ) )
2016-09-18 19:02:12 +03:00
{
bool hasConnect = false ;
socket . listen ( ) ;
socket . accept ( ) ;
2017-02-08 22:35:46 +03:00
EASY_EVENT ( " ClientConnected " , EASY_COLOR_INTERNAL_EVENT , profiler : : OFF ) ;
2016-09-18 19:02:12 +03:00
hasConnect = true ;
2016-09-25 11:49:49 +03:00
# ifdef EASY_DEBUG_NET_PRINT
2016-09-28 00:37:20 +03:00
printf ( " GUI-client connected \n " ) ;
2016-09-25 11:49:49 +03:00
# endif
2016-09-18 19:02:12 +03:00
2016-09-28 00:37:20 +03:00
// Send reply
{
const bool wasLowPriorityET =
# ifdef _WIN32
EasyEventTracer : : instance ( ) . isLowPriority ( ) ;
# else
false ;
# endif
2016-12-21 21:59:40 +03:00
profiler : : net : : EasyProfilerStatus connectionReply ( m_profilerStatus . load ( std : : memory_order_acquire ) = = EASY_PROF_ENABLED , m_isEventTracingEnabled . load ( std : : memory_order_acquire ) , wasLowPriorityET ) ;
2016-09-28 00:37:20 +03:00
bytes = socket . send ( & connectionReply , sizeof ( connectionReply ) ) ;
hasConnect = bytes > 0 ;
}
2016-09-18 19:02:12 +03:00
2016-09-25 11:49:49 +03:00
while ( hasConnect & & ! m_stopListen . load ( std : : memory_order_acquire ) )
2016-09-18 19:02:12 +03:00
{
char buffer [ 256 ] = { } ;
bytes = socket . receive ( buffer , 255 ) ;
hasConnect = bytes > 0 ;
char * buf = & buffer [ 0 ] ;
if ( bytes > 0 )
{
profiler : : net : : Message * message = ( profiler : : net : : Message * ) buf ;
if ( ! message - > isEasyNetMessage ( ) ) {
continue ;
}
2016-09-25 11:49:49 +03:00
switch ( message - > type )
2016-09-18 19:02:12 +03:00
{
2016-11-27 14:26:00 +03:00
case profiler : : net : : MESSAGE_TYPE_CHECK_CONNECTION :
{
# ifdef EASY_DEBUG_NET_PRINT
printf ( " receive MESSAGE_TYPE_CHECK_CONNECTION \n " ) ;
# endif
break ;
}
2016-09-25 11:49:49 +03:00
case profiler : : net : : MESSAGE_TYPE_REQUEST_START_CAPTURE :
{
# ifdef EASY_DEBUG_NET_PRINT
2016-09-28 00:37:20 +03:00
printf ( " receive REQUEST_START_CAPTURE \n " ) ;
2016-09-25 11:49:49 +03:00
# endif
2016-09-28 00:37:20 +03:00
: : profiler : : timestamp_t t = 0 ;
2017-02-08 22:35:46 +03:00
EASY_FORCE_EVENT ( t , " StartCapture " , EASY_COLOR_START , profiler : : OFF ) ;
2016-09-18 19:02:12 +03:00
2016-12-21 21:59:40 +03:00
m_dumpSpin . lock ( ) ;
const auto prev = m_profilerStatus . exchange ( EASY_PROF_ENABLED , std : : memory_order_release ) ;
if ( prev ! = EASY_PROF_ENABLED ) {
enableEventTracer ( ) ;
m_beginTime = t ;
}
m_dumpSpin . unlock ( ) ;
2016-09-25 11:49:49 +03:00
replyMessage . type = profiler : : net : : MESSAGE_TYPE_REPLY_START_CAPTURING ;
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
break ;
}
case profiler : : net : : MESSAGE_TYPE_REQUEST_STOP_CAPTURE :
{
# ifdef EASY_DEBUG_NET_PRINT
2016-09-28 00:37:20 +03:00
printf ( " receive REQUEST_STOP_CAPTURE \n " ) ;
2016-09-25 11:49:49 +03:00
# endif
2016-12-21 21:59:40 +03:00
m_dumpSpin . lock ( ) ;
auto time = getCurrentTime ( ) ;
const auto prev = m_profilerStatus . exchange ( EASY_PROF_DUMP , std : : memory_order_release ) ;
if ( prev = = EASY_PROF_ENABLED ) {
disableEventTracer ( ) ;
m_endTime = time ;
}
2017-02-08 22:35:46 +03:00
EASY_FORCE_EVENT2 ( m_endTime , " StopCapture " , EASY_COLOR_END , profiler : : OFF ) ;
2016-09-28 00:37:20 +03:00
2016-09-25 11:49:49 +03:00
//TODO
//if connection aborted - ignore this part
profiler : : OStream os ;
2016-12-21 21:59:40 +03:00
dumpBlocksToStream ( os , false ) ;
m_dumpSpin . unlock ( ) ;
profiler : : net : : DataMessage dm ;
2016-09-25 11:49:49 +03:00
dm . size = ( uint32_t ) os . stream ( ) . str ( ) . length ( ) ;
int packet_size = int ( sizeof ( dm ) ) + int ( dm . size ) ;
char * sendbuf = new char [ packet_size ] ;
memset ( sendbuf , 0 , packet_size ) ;
memcpy ( sendbuf , & dm , sizeof ( dm ) ) ;
memcpy ( sendbuf + sizeof ( dm ) , os . stream ( ) . str ( ) . c_str ( ) , dm . size ) ;
bytes = socket . send ( sendbuf , packet_size ) ;
hasConnect = bytes > 0 ;
/*std::string tempfilename = "test_snd.prof";
std : : ofstream of ( tempfilename , std : : fstream : : binary ) ;
of . write ( ( const char * ) os . stream ( ) . str ( ) . c_str ( ) , dm . size ) ;
of . close ( ) ; */
2016-09-18 19:02:12 +03:00
2016-09-25 11:49:49 +03:00
delete [ ] sendbuf ;
replyMessage . type = profiler : : net : : MESSAGE_TYPE_REPLY_BLOCKS_END ;
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
break ;
}
case profiler : : net : : MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION :
{
# ifdef EASY_DEBUG_NET_PRINT
2016-09-28 00:37:20 +03:00
printf ( " receive REQUEST_BLOCKS_DESCRIPTION \n " ) ;
2016-09-25 11:49:49 +03:00
# endif
profiler : : OStream os ;
2016-09-27 22:28:04 +03:00
// Write profiler signature and version
os . write ( PROFILER_SIGNATURE ) ;
2016-11-16 22:17:39 +03:00
os . write ( EASY_CURRENT_VERSION ) ;
2016-09-27 22:28:04 +03:00
2016-09-25 11:49:49 +03:00
// Write block descriptors
m_storedSpin . lock ( ) ;
os . write ( static_cast < uint32_t > ( m_descriptors . size ( ) ) ) ;
os . write ( m_usedMemorySize ) ;
for ( const auto descriptor : m_descriptors )
{
const auto name_size = descriptor - > nameSize ( ) ;
const auto filename_size = descriptor - > filenameSize ( ) ;
const auto size = static_cast < uint16_t > ( sizeof ( profiler : : SerializedBlockDescriptor ) + name_size + filename_size ) ;
os . write ( size ) ;
os . write < profiler : : BaseBlockDescriptor > ( * descriptor ) ;
os . write ( name_size ) ;
os . write ( descriptor - > name ( ) , name_size ) ;
os . write ( descriptor - > filename ( ) , filename_size ) ;
}
m_storedSpin . unlock ( ) ;
// END of Write block descriptors.
profiler : : net : : DataMessage dm ( ( uint32_t ) os . stream ( ) . str ( ) . length ( ) , profiler : : net : : MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION ) ;
int packet_size = int ( sizeof ( dm ) ) + int ( dm . size ) ;
char * sendbuf = new char [ packet_size ] ;
memset ( sendbuf , 0 , packet_size ) ;
memcpy ( sendbuf , & dm , sizeof ( dm ) ) ;
memcpy ( sendbuf + sizeof ( dm ) , os . stream ( ) . str ( ) . c_str ( ) , dm . size ) ;
bytes = socket . send ( sendbuf , packet_size ) ;
hasConnect = bytes > 0 ;
delete [ ] sendbuf ;
replyMessage . type = profiler : : net : : MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION_END ;
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
break ;
}
case profiler : : net : : MESSAGE_TYPE_EDIT_BLOCK_STATUS :
{
2016-09-28 00:37:20 +03:00
auto data = reinterpret_cast < const profiler : : net : : BlockStatusMessage * > ( message ) ;
2016-09-25 11:49:49 +03:00
# ifdef EASY_DEBUG_NET_PRINT
2016-09-28 00:37:20 +03:00
printf ( " receive EDIT_BLOCK_STATUS id=%u status=%u \n " , data - > id , data - > status ) ;
2016-09-25 11:49:49 +03:00
# endif
setBlockStatus ( data - > id , static_cast < : : profiler : : EasyBlockStatus > ( data - > status ) ) ;
break ;
}
2016-09-28 00:37:20 +03:00
case profiler : : net : : MESSAGE_TYPE_EVENT_TRACING_STATUS :
{
auto data = reinterpret_cast < const profiler : : net : : BoolMessage * > ( message ) ;
# ifdef EASY_DEBUG_NET_PRINT
printf ( " receive EVENT_TRACING_STATUS on=%d \n " , data - > flag ? 1 : 0 ) ;
# endif
m_isEventTracingEnabled . store ( data - > flag , std : : memory_order_release ) ;
break ;
}
case profiler : : net : : MESSAGE_TYPE_EVENT_TRACING_PRIORITY :
{
2016-11-13 15:20:25 +03:00
# if defined(_WIN32) || defined(EASY_DEBUG_NET_PRINT)
2016-09-28 00:37:20 +03:00
auto data = reinterpret_cast < const profiler : : net : : BoolMessage * > ( message ) ;
2016-11-13 15:20:25 +03:00
# endif
2016-09-28 00:37:20 +03:00
# ifdef EASY_DEBUG_NET_PRINT
printf ( " receive EVENT_TRACING_PRIORITY low=%d \n " , data - > flag ? 1 : 0 ) ;
# endif
# ifdef _WIN32
EasyEventTracer : : instance ( ) . setLowPriority ( data - > flag ) ;
# endif
break ;
}
2016-09-25 11:49:49 +03:00
default :
break ;
}
2016-09-18 19:02:12 +03:00
//nn_freemsg (buf);
}
}
}
}
//////////////////////////////////////////////////////////////////////////