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
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
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-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
//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
//////////////////////////////////////////////////////////////////////////
2016-11-20 13:42:05 +03:00
EASY_THREAD_LOCAL static : : ThreadStorage * THREAD_STORAGE = nullptr ;
//////////////////////////////////////////////////////////////////////////
# ifdef BUILD_WITH_EASY_PROFILER
# 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__ ) ) ) ; \
storeBlockForce ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) , timestamp ) ;
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__ ) ) ) ; \
storeBlockForce2 ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) , timestamp ) ;
2016-11-20 13:42:05 +03:00
# else
# define EASY_FORCE_EVENT(timestamp, name, ...)
# define EASY_FORCE_EVENT2(timestamp, name, ...)
# 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-09-20 22:57:34 +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 )
2016-09-18 19:02:12 +03:00
{
2016-09-20 22:57:34 +03:00
return MANAGER . addBlockDescriptor ( _status , _autogenUniqueId , _name , _filename , _line , _block_type , _color ) ;
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 ( ) ;
}
PROFILER_API void startListenSignalToCapture ( )
{
return MANAGER . startListenSignalToCapture ( ) ;
}
PROFILER_API void stopListenSignalToCapture ( )
{
return MANAGER . stopListenSignalToCapture ( ) ;
}
2016-11-20 13:42:05 +03:00
# else
PROFILER_API const BaseBlockDescriptor * registerDescription ( EasyBlockStatus , const char * , const char * , const char * , int , block_type_t , color_t ) { return reinterpret_cast < const BaseBlockDescriptor * > ( 0xbad ) ; }
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 " " ; }
PROFILER_API void startListenSignalToCapture ( ) { }
PROFILER_API void stopListenSignalToCapture ( ) { }
# 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_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
EASY_BLOCK_DESC_STRING m_filename ; ///< Source file name where this block is declared
uint16_t m_size ; ///< Used memory size
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_name ( _name )
, m_filename ( _filename )
, m_size ( static_cast < uint16_t > ( sizeof ( profiler : : SerializedBlockDescriptor ) + strlen ( _name ) + strlen ( _filename ) + 2 ) )
{
}
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-11-20 17:09:50 +03:00
ThreadStorage : : ThreadStorage ( ) : id ( getCurrentThreadId ( ) ) , allowChildren ( true ) , named ( false )
{
expired = ATOMIC_VAR_INIT ( false ) ;
}
2016-09-18 19:02:12 +03:00
void ThreadStorage : : storeBlock ( const profiler : : Block & block )
{
# if EASY_MEASURE_STORAGE_EXPAND != 0
2016-09-22 23:06:43 +03:00
EASY_LOCAL_STATIC_PTR ( const BaseBlockDescriptor * , desc , \
MANAGER . addBlockDescriptor ( EASY_STORAGE_EXPAND_ENABLED ? profiler : : ON : profiler : : OFF , EASY_UNIQUE_LINE_ID , " EasyProfiler.ExpandStorage " , \
__FILE__ , __LINE__ , profiler : : BLOCK_TYPE_BLOCK , profiler : : colors : : White ) ) ;
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 ) ;
# if EASY_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 ) ;
# if EASY_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 ;
# if EASY_MEASURE_STORAGE_EXPAND != 0
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-09-23 23:51:49 +03:00
EASY_EVENT ( " ThreadFinished " , profiler : : colors : : Dark ) ;
2016-09-20 22:57:34 +03:00
THREAD_STORAGE - > expired . store ( true , std : : memory_order_release ) ;
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
ProfileManager : : ProfileManager ( )
2016-09-17 11:10:25 +03:00
{
2016-09-18 19:02:12 +03:00
m_isEnabled = ATOMIC_VAR_INIT ( false ) ;
m_isEventTracingEnabled = ATOMIC_VAR_INIT ( EASY_EVENT_TRACING_ENABLED ) ;
m_stopListen = ATOMIC_VAR_INIT ( false ) ;
}
ProfileManager : : ~ ProfileManager ( )
{
2016-11-20 13:42:05 +03:00
# ifndef EASY_PROFILER_API_DISABLED
2016-09-20 22:57:34 +03:00
stopListenSignalToCapture ( ) ;
2016-11-20 13:42:05 +03:00
# endif
2016-09-20 22:57:34 +03:00
for ( auto desc : m_descriptors )
{
if ( desc ! = nullptr )
delete desc ;
}
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-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-09-11 16:57:35 +03:00
ThreadStorage & ProfileManager : : threadStorage ( profiler : : thread_id_t _thread_id )
{
guard_lock_t lock ( m_spin ) ;
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-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 ,
color_t _color )
{
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 ] ;
auto desc = new BlockDescriptor ( static_cast < block_id_t > ( m_descriptors . size ( ) ) , _defaultStatus , _name , _filename , _line , _block_type , _color ) ;
m_usedMemorySize + = desc - > m_size ;
m_descriptors . emplace_back ( desc ) ;
m_descriptorsMap . emplace ( key , desc - > id ( ) ) ;
return desc ;
}
void ProfileManager : : storeBlock ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName )
2016-09-18 19:02:12 +03:00
{
2016-09-22 23:06:43 +03:00
if ( ! m_isEnabled . load ( std : : memory_order_acquire ) | | ! ( _desc - > m_status & profiler : : ON ) )
2016-09-18 19:02:12 +03:00
return ;
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
if ( ! THREAD_STORAGE - > allowChildren )
return ;
# 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-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
if ( ! THREAD_STORAGE - > allowChildren )
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
if ( ! THREAD_STORAGE - > allowChildren )
return ;
# endif
profiler : : Block b ( _desc , _runtimeName ) ;
b . m_end = b . m_begin = _timestamp ;
THREAD_STORAGE - > storeBlock ( b ) ;
}
2016-09-18 19:02:12 +03:00
void ProfileManager : : beginBlock ( Block & _block )
{
if ( ! m_isEnabled . load ( std : : memory_order_acquire ) )
return ;
if ( THREAD_STORAGE = = nullptr )
THREAD_STORAGE = & threadStorage ( getCurrentThreadId ( ) ) ;
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-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 ) ;
}
void ProfileManager : : storeContextSwitch ( profiler : : thread_id_t _thread_id , profiler : : timestamp_t _time , profiler : : thread_id_t _target_thread_id , bool _lockSpin )
{
auto ts = _lockSpin ? findThreadStorage ( _thread_id ) : _findThreadStorage ( _thread_id ) ;
if ( ts ! = nullptr )
{
profiler : : Block b ( _time , _target_thread_id , " " ) ;
b . finish ( _time ) ;
ts - > storeCSwitch ( b ) ;
}
}
void ProfileManager : : endBlock ( )
{
if ( ! m_isEnabled . load ( std : : memory_order_acquire ) )
return ;
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-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2016-11-20 15:18:51 +03:00
THREAD_STORAGE - > allowChildren = THREAD_STORAGE - > blocks . openedList . 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
}
void ProfileManager : : endContextSwitch ( profiler : : thread_id_t _thread_id , profiler : : timestamp_t _endtime , bool _lockSpin )
{
auto ts = _lockSpin ? findThreadStorage ( _thread_id ) : _findThreadStorage ( _thread_id ) ;
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-09-28 00:37:20 +03:00
void ProfileManager : : setEnabled ( bool isEnable , bool _setTime )
2016-09-18 19:02:12 +03:00
{
2016-09-22 23:06:43 +03:00
auto time = getCurrentTime ( ) ;
const bool prev = m_isEnabled . exchange ( isEnable , std : : memory_order_release ) ;
if ( prev = = isEnable )
return ;
2016-09-18 19:02:12 +03:00
2016-09-22 23:06:43 +03:00
if ( isEnable )
{
2016-09-24 00:15:33 +03:00
# ifdef _WIN32
2016-09-18 19:02:12 +03:00
if ( m_isEventTracingEnabled . load ( std : : memory_order_acquire ) )
EasyEventTracer : : instance ( ) . enable ( true ) ;
2016-09-24 00:15:33 +03:00
# endif
2016-09-28 00:37:20 +03:00
if ( _setTime )
{
guard_lock_t lk ( m_spin ) ;
m_beginTime = time ;
}
2016-09-22 23:06:43 +03:00
}
else
{
2016-09-24 00:15:33 +03:00
# ifdef _WIN32
2016-09-18 19:02:12 +03:00
EasyEventTracer : : instance ( ) . disable ( ) ;
# endif
2016-09-28 00:37:20 +03:00
if ( _setTime )
{
guard_lock_t lk ( m_spin ) ;
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-11-20 17:09:50 +03:00
bool ProfileManager : : checkThreadExpired ( ThreadStorage & _registeredThread )
{
if ( _registeredThread . expired . load ( std : : memory_order_acquire ) )
return true ;
# ifdef _WIN32
// Check thread for Windows
DWORD exitCode = 0 ;
auto hThread = OpenThread ( THREAD_QUERY_LIMITED_INFORMATION , FALSE , _registeredThread . id ) ;
if ( hThread = = nullptr | | GetExitCodeThread ( hThread , & exitCode ) = = FALSE | | exitCode ! = STILL_ACTIVE )
{
// Thread has been expired
_registeredThread . expired . store ( true , std : : memory_order_release ) ;
if ( hThread ! = nullptr )
CloseHandle ( hThread ) ;
return true ;
}
if ( hThread ! = nullptr )
CloseHandle ( hThread ) ;
# else
// TODO: Check thread for Linux
# endif
return false ;
}
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
uint32_t ProfileManager : : dumpBlocksToStream ( profiler : : OStream & _outputStream )
{
const bool wasEnabled = m_isEnabled . load ( std : : memory_order_acquire ) ;
# ifndef _WIN32
const bool eventTracingEnabled = m_isEventTracingEnabled . load ( std : : memory_order_acquire ) ;
# endif
if ( wasEnabled )
: : profiler : : setEnabled ( false ) ;
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.
guard_lock_t lock1 ( m_storedSpin ) ;
guard_lock_t lock2 ( m_spin ) ;
// 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 ) ) ;
// TODO: think about better solution because this one is not 100% safe...
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 ( ) ) {
while ( infile > > timestamp > > thread_from > > thread_to ) {
beginContextSwitch ( thread_from , timestamp , thread_to , " " , false ) ;
endContextSwitch ( thread_to , timestamp , false ) ;
}
}
}
# 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-09-20 22:57:34 +03:00
const uint32_t num = static_cast < uint32_t > ( t . blocks . closedList . size ( ) ) + static_cast < uint32_t > ( t . sync . closedList . size ( ) ) ;
2016-11-20 17:09:50 +03:00
const bool expired = checkThreadExpired ( t ) | | t . expired . load ( std : : memory_order_acquire ) ;
if ( expired & & num = = 0 ) {
2016-09-20 22:57:34 +03:00
// Thread has been finished and contains no profiled information.
// Remove it now.
m_threads . erase ( it + + ) ;
continue ;
}
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-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
if ( t . expired . load ( std : : memory_order_acquire ) )
m_threads . erase ( it + + ) ; // Remove expired thread after writing all profiled information
else
+ + it ;
2016-09-18 19:02:12 +03:00
}
//if (wasEnabled)
// ::profiler::setEnabled(true);
return blocks_number ;
}
uint32_t ProfileManager : : dumpBlocksToFile ( const char * _filename )
{
profiler : : OStream outputStream ;
const auto blocksNumber = dumpBlocksToStream ( outputStream ) ;
std : : ofstream of ( _filename , std : : fstream : : binary ) ;
of < < outputStream . stream ( ) . str ( ) ;
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 ( ) ) ;
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-09-22 23:06:43 +03:00
if ( m_isEnabled . load ( std : : memory_order_acquire ) )
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
}
}
void ProfileManager : : startListenSignalToCapture ( )
{
if ( ! m_isAlreadyListened )
{
2016-09-25 11:49:49 +03:00
m_stopListen . store ( false , std : : memory_order_release ) ;
2016-09-28 00:37:20 +03:00
m_listenThread = std : : move ( std : : thread ( & ProfileManager : : listen , this ) ) ;
2016-09-18 19:02:12 +03:00
m_isAlreadyListened = true ;
}
}
void ProfileManager : : stopListenSignalToCapture ( )
{
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-09-18 19:02:12 +03:00
m_isAlreadyListened = false ;
}
//////////////////////////////////////////////////////////////////////////
2016-09-25 11:49:49 +03:00
//#define EASY_DEBUG_NET_PRINT
void ProfileManager : : listen ( )
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 ) ;
socket . bind ( profiler : : DEFAULT_PORT ) ;
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 ( ) ;
2016-09-20 22:57:34 +03:00
EASY_EVENT ( " ClientConnected " , profiler : : colors : : White , 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
profiler : : net : : EasyProfilerStatus connectionReply ( m_isEnabled . load ( std : : memory_order_acquire ) , m_isEventTracingEnabled . load ( std : : memory_order_acquire ) , wasLowPriorityET ) ;
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-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 ;
EASY_FORCE_EVENT ( t , " StartCapture " , profiler : : colors : : Green , profiler : : OFF ) ;
ProfileManager : : setEnabled ( true , false ) ;
2016-09-18 19:02:12 +03:00
2016-09-28 00:37:20 +03:00
m_spin . lock ( ) ;
m_beginTime = t ;
m_spin . 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
ProfileManager : : setEnabled ( false ) ;
2016-09-28 00:37:20 +03:00
m_spin . lock ( ) ;
: : profiler : : timestamp_t t = m_endTime ;
m_spin . unlock ( ) ;
EASY_FORCE_EVENT2 ( t , " StopCapture " , profiler : : colors : : Red , profiler : : OFF ) ;
2016-09-25 11:49:49 +03:00
//TODO
//if connection aborted - ignore this part
profiler : : net : : DataMessage dm ;
profiler : : OStream os ;
dumpBlocksToStream ( os ) ;
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);
}
}
}
}
//////////////////////////////////////////////////////////////////////////