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 + +
2018-01-29 23:29:43 +03:00
* : Copyright ( C ) 2016 - 2018 Sergey Yagovtsev , Victor Zarubkin
2016-09-18 19:02:12 +03:00
* :
2017-03-30 06:55:15 +03:00
* : Licensed under either of
* : * MIT license ( LICENSE . MIT or http : //opensource.org/licenses/MIT)
* : * Apache License , Version 2.0 , ( LICENSE . APACHE or http : //www.apache.org/licenses/LICENSE-2.0)
* : at your option .
2016-11-13 16:39:59 +03:00
* :
2017-03-30 06:55:15 +03:00
* : The MIT License
* :
* : Permission is hereby granted , free of charge , to any person obtaining a copy
* : of this software and associated documentation files ( the " Software " ) , to deal
* : in the Software without restriction , including without limitation the rights
* : to use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
* : of the Software , and to permit persons to whom the Software is furnished
* : to do so , subject to the following conditions :
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software .
* :
* : THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT ,
* : TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE .
* :
* : The Apache License , Version 2.0 ( the " License " )
* :
* : You may not use this file except in compliance with the License .
2016-11-13 16:39:59 +03:00
* : 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 .
2016-09-18 19:02:12 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <algorithm>
2017-11-02 22:43:37 +03:00
# include <future>
2018-05-07 21:42:17 +03:00
# include <fstream>
# include <ostream>
# include <sstream>
2016-09-18 19:02:12 +03:00
# include "profile_manager.h"
2017-03-05 23:50:38 +03:00
2017-11-09 23:34:17 +03:00
# include <easy/profiler.h>
# include <easy/arbitrary_value.h>
2017-03-05 23:50:38 +03:00
# include <easy/easy_net.h>
2017-11-09 23:56:46 +03:00
# ifndef _WIN32
# include <easy / easy_socket.h>
2018-05-07 21:42:17 +03:00
# else
# include "event_trace_win.h"
2017-11-09 23:56:46 +03:00
# endif
2017-03-05 23:50:38 +03:00
2018-05-07 21:42:17 +03:00
# include "block_descriptor.h"
2018-05-08 01:30:10 +03:00
# include "current_time.h"
2017-09-30 19:51:33 +03:00
# include "current_thread.h"
2016-09-18 19:02:12 +03:00
2017-06-12 11:30:01 -04:00
# ifdef __APPLE__
2018-05-07 21:42:17 +03:00
# include <mach / clock.h>
# include <mach / mach.h>
2017-06-12 11:30:01 -04:00
# endif
2017-02-08 23:20:09 +03:00
# if EASY_OPTION_LOG_ENABLED != 0
# include <iostream>
# ifndef EASY_ERRORLOG
2018-01-29 23:29:43 +03:00
# define EASY_ERRORLOG std::cerr
2017-02-08 23:20:09 +03:00
# endif
# ifndef EASY_LOG
2018-01-29 23:29:43 +03:00
# define EASY_LOG std::cerr
2017-02-08 23:20:09 +03:00
# endif
# ifndef EASY_ERROR
# define EASY_ERROR(LOG_MSG) EASY_ERRORLOG << "EasyProfiler ERROR: " << LOG_MSG
# endif
# ifndef EASY_WARNING
# define EASY_WARNING(LOG_MSG) EASY_ERRORLOG << "EasyProfiler WARNING: " << LOG_MSG
# endif
# ifndef EASY_LOGMSG
# define EASY_LOGMSG(LOG_MSG) EASY_LOG << "EasyProfiler INFO: " << LOG_MSG
# endif
# ifndef EASY_LOG_ONLY
# define EASY_LOG_ONLY(CODE) CODE
# endif
2018-05-07 21:42:17 +03:00
# else // EASY_OPTION_LOG_ENABLED == 0
2017-02-08 23:20:09 +03:00
# ifndef EASY_ERROR
2017-06-12 11:30:01 -04:00
# define EASY_ERROR(LOG_MSG)
2017-02-08 23:20:09 +03:00
# endif
# ifndef EASY_WARNING
2017-06-12 11:30:01 -04:00
# define EASY_WARNING(LOG_MSG)
2017-02-08 23:20:09 +03:00
# endif
# ifndef EASY_LOGMSG
2017-06-12 11:30:01 -04:00
# define EASY_LOGMSG(LOG_MSG)
2017-02-08 23:20:09 +03:00
# endif
# ifndef EASY_LOG_ONLY
2017-06-12 11:30:01 -04:00
# define EASY_LOG_ONLY(CODE)
2017-02-08 23:20:09 +03:00
# endif
2018-05-07 21:42:17 +03:00
# endif // EASY_OPTION_LOG_ENABLED
2017-02-08 23:20:09 +03:00
2016-12-12 22:26:32 +03:00
# ifdef min
2017-09-30 19:02:24 +03:00
# undef min
# endif
2017-09-30 19:51:33 +03:00
# ifndef EASY_ENABLE_BLOCK_STATUS
# define EASY_ENABLE_BLOCK_STATUS 1
# endif
2017-09-30 19:02:24 +03:00
# if !defined(_WIN32) && !defined(EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS)
# define EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS 0
# endif
# ifndef EASY_OPTION_IMPLICIT_THREAD_REGISTRATION
# define EASY_OPTION_IMPLICIT_THREAD_REGISTRATION 0
2016-11-27 14:26:00 +03:00
# endif
2016-09-18 19:02:12 +03:00
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
extern const uint32_t EASY_PROFILER_SIGNATURE ;
extern const uint32_t EASY_PROFILER_VERSION ;
2016-09-18 19:02:12 +03:00
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
2017-02-08 22:35:46 +03:00
extern const profiler : : color_t EASY_COLOR_INTERNAL_EVENT = 0xffffffff ; // profiler::colors::White
2017-11-09 23:12:54 +03:00
EASY_CONSTEXPR profiler : : color_t EASY_COLOR_THREAD_END = 0xff212121 ; // profiler::colors::Dark
EASY_CONSTEXPR profiler : : color_t EASY_COLOR_START = 0xff4caf50 ; // profiler::colors::Green
EASY_CONSTEXPR profiler : : color_t EASY_COLOR_END = 0xfff44336 ; // profiler::colors::Red
2017-02-08 22:35:46 +03:00
2016-09-20 22:57:34 +03:00
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
EASY_CONSTEXPR uint8_t FORCE_ON_FLAG = profiler : : FORCE_ON & ~ profiler : : ON ;
//////////////////////////////////////////////////////////////////////////
2018-09-18 22:50:51 +03:00
static EASY_THREAD_LOCAL : : ThreadStorage * THIS_THREAD = nullptr ;
static EASY_THREAD_LOCAL bool THIS_THREAD_IS_MAIN = false ;
static EASY_THREAD_LOCAL profiler : : timestamp_t THIS_THREAD_FRAME_T_MAX = 0ULL ;
static EASY_THREAD_LOCAL profiler : : timestamp_t THIS_THREAD_FRAME_T_CUR = 0ULL ;
static EASY_THREAD_LOCAL profiler : : timestamp_t THIS_THREAD_FRAME_T_ACC = 0ULL ;
static EASY_THREAD_LOCAL uint32_t THIS_THREAD_N_FRAMES = 0 ;
static EASY_THREAD_LOCAL bool THIS_THREAD_FRAME_T_RESET_MAX = false ;
static EASY_THREAD_LOCAL bool THIS_THREAD_FRAME_T_RESET_AVG = false ;
2017-04-02 14:23:11 +03:00
2017-11-09 23:12:54 +03:00
# ifdef EASY_CXX11_TLS_AVAILABLE
2017-09-28 21:04:28 +03:00
thread_local static profiler : : ThreadGuard THIS_THREAD_GUARD ; // thread guard for monitoring thread life time
# endif
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, ...)\
2018-05-07 21:42:17 +03:00
EASY_LOCAL_STATIC_PTR ( const profiler : : BaseBlockDescriptor * , EASY_UNIQUE_DESC ( __LINE__ ) , \
ProfileManager : : instance ( ) . addBlockDescriptor ( profiler : : extract_enable_flag ( __VA_ARGS__ ) , \
EASY_UNIQUE_LINE_ID , EASY_COMPILETIME_NAME ( name ) , \
2018-01-29 23:29:43 +03:00
__FILE__ , __LINE__ , profiler : : BlockType : : Event , profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
2018-05-07 21:42:17 +03:00
res = ProfileManager : : instance ( ) . storeBlock ( EASY_UNIQUE_DESC ( __LINE__ ) , EASY_RUNTIME_NAME ( name ) )
2016-12-12 22:26:32 +03:00
2016-11-20 13:42:05 +03:00
# define EASY_FORCE_EVENT(timestamp, name, ...)\
2018-01-29 23:29:43 +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 : : BlockType : : 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, ...)\
2018-01-29 23:29:43 +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 : : BlockType : : 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, ...)\
2018-01-29 23:29:43 +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 : : BlockType : : Event , profiler : : extract_color ( __VA_ARGS__ ) ) ) ; \
2018-01-08 02:56:51 +03:00
ts . storeBlockForce ( profiler : : Block ( timestamp , timestamp , EASY_UNIQUE_DESC ( __LINE__ ) - > id ( ) , EASY_RUNTIME_NAME ( name ) ) )
2016-11-20 13:42:05 +03:00
# else
2017-03-31 21:17:08 +03:00
# ifndef EASY_PROFILER_API_DISABLED
# define EASY_PROFILER_API_DISABLED
# endif
2017-06-12 11:30:01 -04:00
# define EASY_EVENT_RES(res, name, ...)
# define EASY_FORCE_EVENT(timestamp, name, ...)
# define EASY_FORCE_EVENT2(timestamp, name, ...)
# define EASY_FORCE_EVENT3(ts, timestamp, name, ...)
2016-11-20 13:42:05 +03:00
# endif
2016-09-28 00:37:20 +03:00
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
template < typename T >
static void write ( std : : ostream & _outstream , const char * _data , T _size )
{
_outstream . write ( _data , _size ) ;
}
2017-04-03 23:08:52 +03:00
2018-05-07 21:42:17 +03:00
template < class T >
static void write ( std : : ostream & _outstream , const T & _data )
{
_outstream . write ( ( const char * ) & _data , sizeof ( T ) ) ;
}
2017-04-03 23:08:52 +03:00
2018-05-07 21:42:17 +03:00
static void clear_sstream ( std : : stringstream & _outstream )
{
# if defined(__GNUC__) && __GNUC__ < 5
// gcc 4 has a known bug which has been solved in gcc 5:
// std::stringstream has no swap() method :(
_outstream . str ( std : : string ( ) ) ;
2016-11-20 13:42:05 +03:00
# else
2018-05-07 21:42:17 +03:00
std : : stringstream ( ) . swap ( _outstream ) ;
2016-11-20 13:42:05 +03:00
# endif
2018-05-07 21:42:17 +03:00
}
2016-09-18 19:02:12 +03:00
2018-05-07 21:42:17 +03:00
//////////////////////////////////////////////////////////////////////////
2016-11-16 22:17:39 +03:00
2018-05-07 21:42:17 +03:00
profiler : : ThreadGuard : : ~ ThreadGuard ( )
{
# ifndef EASY_PROFILER_API_DISABLED
if ( m_id ! = 0 & & THIS_THREAD ! = nullptr & & THIS_THREAD - > id = = m_id )
2016-11-16 22:17:39 +03:00
{
2018-05-07 21:42:17 +03:00
bool isMarked = false ;
EASY_EVENT_RES ( isMarked , " ThreadFinished " , EASY_COLOR_THREAD_END , profiler : : FORCE_ON ) ;
//THIS_THREAD->markProfilingFrameEnded();
THIS_THREAD - > putMark ( ) ;
THIS_THREAD - > expired . store ( isMarked ? 2 : 1 , std : : memory_order_release ) ;
THIS_THREAD = nullptr ;
2016-11-16 22:17:39 +03:00
}
2016-11-20 13:42:05 +03:00
# endif
2016-09-18 19:02:12 +03:00
}
2016-11-20 13:42:05 +03:00
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
# if defined(EASY_CHRONO_CLOCK)
2018-05-15 23:56:29 +03:00
static EASY_CONSTEXPR_FCN int64_t calculate_cpu_frequency ( )
2017-06-06 20:46:06 +03:00
{
2018-09-18 14:19:38 -04:00
return EASY_CHRONO_CLOCK : : period : : den / EASY_CHRONO_CLOCK : : period : : num ;
2017-06-06 20:46:06 +03:00
}
2018-05-07 21:42:17 +03:00
# elif defined(_WIN32)
static int64_t calculate_cpu_frequency ( )
2016-09-18 19:02:12 +03:00
{
2018-05-07 21:42:17 +03:00
LARGE_INTEGER freq ;
QueryPerformanceFrequency ( & freq ) ;
return static_cast < int64_t > ( freq . QuadPart ) ;
2016-09-18 19:02:12 +03:00
}
2016-09-22 23:06:43 +03:00
# else
2018-05-07 21:42:17 +03:00
# ifndef __APPLE__
# include <time.h>
# endif
static int64_t calculate_cpu_frequency ( )
2016-09-18 19:02:12 +03:00
{
2018-05-07 21:42:17 +03:00
EASY_CONSTEXPR int NANO_SECONDS_IN_SEC = 1000000000 ;
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
uint64_t begin = 0 ;
uint64_t end = 0 ;
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
# ifdef __APPLE__
clock_serv_t cclock ;
mach_timespec_t begints , endts ;
host_get_clock_service ( mach_host_self ( ) , SYSTEM_CLOCK , & cclock ) ;
clock_get_time ( cclock , & begints ) ;
# else
struct timespec begints , endts ;
clock_gettime ( CLOCK_MONOTONIC , & begints ) ;
# endif
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
begin = profiler : : clock : : now ( ) ;
volatile uint64_t i ;
for ( i = 0 ; i < 100000000 ; i + + ) ; /* must be CPU intensive */
end = profiler : : clock : : now ( ) ;
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
# ifdef __APPLE__
clock_get_time ( cclock , & endts ) ;
mach_port_deallocate ( mach_task_self ( ) , cclock ) ;
# else
clock_gettime ( CLOCK_MONOTONIC , & endts ) ;
# endif
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
struct timespec tmpts ;
tmpts . tv_sec = endts . tv_sec - begints . tv_sec ;
tmpts . tv_nsec = endts . tv_nsec - begints . tv_nsec ;
2016-09-22 23:06:43 +03:00
2018-05-07 21:42:17 +03:00
if ( tmpts . tv_nsec < 0 )
{
tmpts . tv_sec - - ;
tmpts . tv_nsec + = NANO_SECONDS_IN_SEC ;
2016-09-22 23:06:43 +03:00
}
2018-05-07 21:42:17 +03:00
const uint64_t nsecElapsed = tmpts . tv_sec * 1000000000LL + tmpts . tv_nsec ;
const double ticksPerNanoSec = static_cast < double > ( end - begin ) / static_cast < double > ( nsecElapsed ) ;
2016-09-18 19:02:12 +03:00
2018-05-07 21:42:17 +03:00
return int64_t ( ticksPerNanoSec * 1000000 ) ;
2017-03-31 21:17:08 +03:00
}
2018-05-07 21:42:17 +03:00
# endif
2017-03-31 21:17:08 +03:00
//////////////////////////////////////////////////////////////////////////
2016-12-12 22:26:32 +03:00
ProfileManager : : ProfileManager ( ) :
2018-05-07 21:42:17 +03:00
2016-12-12 22:26:32 +03:00
# ifdef _WIN32
m_processId ( GetProcessId ( GetCurrentProcess ( ) ) )
# else
m_processId ( ( processid_t ) getpid ( ) )
# endif
2018-05-07 21:42:17 +03:00
# if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
, m_cpuFrequency ( calculate_cpu_frequency ( ) )
# endif
2018-04-02 01:53:29 +03:00
, m_descriptorsMemorySize ( 0 )
2016-12-12 22:26:32 +03:00
, m_beginTime ( 0 )
, m_endTime ( 0 )
2016-09-17 11:10:25 +03:00
{
2018-09-18 22:41:58 +03:00
m_profilerStatus = false ;
m_isEventTracingEnabled = EASY_OPTION_EVENT_TRACING_ENABLED ;
m_isAlreadyListening = false ;
m_stopDumping = false ;
m_stopListen = false ;
m_mainThreadId = 0 ;
m_frameMax = 0 ;
m_frameAvg = 0 ;
m_frameCur = 0 ;
m_frameMaxReset = false ;
m_frameAvgReset = false ;
2017-04-03 23:08:52 +03:00
2018-05-07 21:42:17 +03:00
# if !defined(EASY_CHRONO_CLOCK) && !defined(_WIN32)
2018-09-18 22:41:58 +03:00
m_cpuFrequency = 1 ;
2018-05-07 21:42:17 +03:00
# if !defined(EASY_PROFILER_API_DISABLED)
const auto cpu_frequency = calculate_cpu_frequency ( ) ;
m_cpuFrequency . store ( cpu_frequency , std : : memory_order_release ) ;
# endif
2016-12-13 21:53:29 +03:00
# endif
2017-03-31 21:17:08 +03:00
2018-05-07 21:42:17 +03:00
# if !defined(EASY_PROFILER_API_DISABLED) && EASY_OPTION_START_LISTEN_ON_STARTUP != 0
startListen ( profiler : : DEFAULT_PORT ) ;
2017-03-31 21:17:08 +03:00
# 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
2018-05-07 21:42:17 +03:00
for ( auto desc : m_descriptors )
BlockDescriptor : : destroy ( desc ) ;
2016-09-18 19:02:12 +03:00
}
2017-11-09 23:12:54 +03:00
# ifndef EASY_MAGIC_STATIC_AVAILABLE
2016-09-22 23:06:43 +03:00
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 ( )
{
2017-11-09 23:12:54 +03:00
# ifndef EASY_MAGIC_STATIC_AVAILABLE
2016-09-22 23:06:43 +03:00
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
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
const profiler : : BaseBlockDescriptor * ProfileManager : : addBlockDescriptor ( profiler : : EasyBlockStatus _defaultStatus
, const char * _autogenUniqueId , const char * _name , const char * _filename , int _line
, profiler : : block_type_t _block_type , profiler : : color_t _color , bool _copyName )
2016-09-22 23:06:43 +03:00
{
guard_lock_t lock ( m_storedSpin ) ;
2018-05-07 21:42:17 +03:00
const descriptors_map_t : : key_type key ( _autogenUniqueId ) ;
2016-09-22 23:06:43 +03:00
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 ) ;
2018-04-02 01:53:29 +03:00
m_descriptorsMemorySize + = sizeof ( profiler : : SerializedBlockDescriptor ) + nameLen + strlen ( _filename ) + 2 ;
2016-12-21 21:59:40 +03:00
# 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 ) ;
2018-05-07 21:42:17 +03:00
desc = : : new ( data ) BlockDescriptor ( static_cast < profiler : : block_id_t > ( m_descriptors . size ( ) ) ,
_defaultStatus , name , _filename , _line , _block_type , _color ) ;
2016-12-21 21:59:40 +03:00
}
else
{
void * data = malloc ( sizeof ( BlockDescriptor ) ) ;
2018-05-07 21:42:17 +03:00
desc = : : new ( data ) BlockDescriptor ( static_cast < profiler : : block_id_t > ( m_descriptors . size ( ) ) ,
_defaultStatus , _name , _filename , _line , _block_type , _color ) ;
2016-12-21 21:59:40 +03:00
}
# else
2018-05-07 21:42:17 +03:00
auto desc = new BlockDescriptor ( static_cast < profiler : : block_id_t > ( m_descriptors . size ( ) ) ,
_defaultStatus , _name , _filename , _line , _block_type , _color ) ;
2018-01-04 15:15:02 +01:00
( void ) _copyName ; // unused
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
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
void ProfileManager : : storeValue ( const profiler : : BaseBlockDescriptor * _desc , profiler : : DataType _type , const void * _data ,
uint16_t _size , bool _isArray , profiler : : ValueId _vin )
2017-10-20 22:18:32 +03:00
{
2018-01-08 02:56:51 +03:00
if ( ! isEnabled ( ) | | ( _desc - > m_status & profiler : : ON ) = = 0 )
2017-10-20 22:18:32 +03:00
return ;
2017-12-14 23:12:27 +03:00
if ( THIS_THREAD = = nullptr )
2017-10-20 22:18:32 +03:00
registerThread ( ) ;
# if EASY_ENABLE_BLOCK_STATUS != 0
2018-01-08 02:56:51 +03:00
if ( THIS_THREAD - > stackSize > 0 | | ( ! THIS_THREAD - > allowChildren & & ( _desc - > m_status & FORCE_ON_FLAG ) = = 0 ) )
return ;
# else
if ( THIS_THREAD - > stackSize > 0 )
// Prevent from store values until frame, which has been opened when profiler was disabled, finish
2017-10-20 22:18:32 +03:00
return ;
# endif
2018-01-29 23:29:43 +03:00
THIS_THREAD - > storeValue ( profiler : : clock : : now ( ) , _desc - > id ( ) , _type , _data , _size , _isArray , _vin ) ;
2017-10-20 22:18:32 +03:00
}
//////////////////////////////////////////////////////////////////////////
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
{
2018-01-08 02:56:51 +03:00
if ( ! isEnabled ( ) | | ( _desc - > m_status & profiler : : ON ) = = 0 )
2016-12-12 22:26:32 +03:00
return false ;
2016-09-18 19:02:12 +03:00
2017-12-28 22:21:54 +03:00
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2016-09-18 19:02:12 +03:00
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2018-01-08 02:56:51 +03:00
if ( THIS_THREAD - > stackSize > 0 | | ( ! THIS_THREAD - > allowChildren & & ( _desc - > m_status & FORCE_ON_FLAG ) = = 0 ) )
return false ;
# else
if ( THIS_THREAD - > stackSize > 0 )
// Prevent from store block until frame, which has been opened when profiler was disabled, finish
2016-12-12 22:26:32 +03:00
return false ;
2016-09-20 22:57:34 +03:00
# endif
2018-01-29 23:29:43 +03:00
const auto time = profiler : : clock : : now ( ) ;
2017-11-15 21:43:52 +03:00
THIS_THREAD - > storeBlock ( profiler : : Block ( time , time , _desc - > id ( ) , _runtimeName ) ) ;
2018-01-08 02:56:51 +03:00
THIS_THREAD - > putMarkIfEmpty ( ) ;
2016-12-12 22:26:32 +03:00
return true ;
2016-09-18 19:02:12 +03:00
}
2018-05-07 21:42:17 +03:00
bool ProfileManager : : storeBlock ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName ,
profiler : : timestamp_t _beginTime , profiler : : timestamp_t _endTime )
2017-04-17 22:27:10 +03:00
{
2018-01-08 02:56:51 +03:00
if ( ! isEnabled ( ) | | ( _desc - > m_status & profiler : : ON ) = = 0 )
2017-04-17 22:27:10 +03:00
return false ;
2017-12-28 22:21:54 +03:00
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2017-04-17 22:27:10 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2018-01-08 02:56:51 +03:00
if ( THIS_THREAD - > stackSize > 0 | | ( ! THIS_THREAD - > allowChildren & & ( _desc - > m_status & FORCE_ON_FLAG ) = = 0 ) )
return false ;
# else
if ( THIS_THREAD - > stackSize > 0 )
// Prevent from store block until frame, which has been opened when profiler was disabled, finish
2017-04-17 22:27:10 +03:00
return false ;
# endif
profiler : : Block b ( _beginTime , _endTime , _desc - > id ( ) , _runtimeName ) ;
THIS_THREAD - > storeBlock ( b ) ;
b . m_end = b . m_begin ;
2018-01-08 02:56:51 +03:00
THIS_THREAD - > putMarkIfEmpty ( ) ;
2017-04-17 22:27:10 +03:00
return true ;
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
void ProfileManager : : storeBlockForce ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName ,
profiler : : timestamp_t & _timestamp )
2016-09-28 00:37:20 +03:00
{
2017-11-09 23:12:54 +03:00
if ( ( _desc - > m_status & profiler : : ON ) = = 0 )
2016-09-28 00:37:20 +03:00
return ;
2017-03-31 21:17:08 +03:00
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2016-09-28 00:37:20 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2017-11-09 23:12:54 +03:00
if ( ! THIS_THREAD - > allowChildren & & ( _desc - > m_status & FORCE_ON_FLAG ) = = 0 )
2016-09-28 00:37:20 +03:00
return ;
# endif
2018-01-29 23:29:43 +03:00
_timestamp = profiler : : clock : : now ( ) ;
2017-11-15 21:43:52 +03:00
THIS_THREAD - > storeBlock ( profiler : : Block ( _timestamp , _timestamp , _desc - > id ( ) , _runtimeName ) ) ;
2018-01-08 02:56:51 +03:00
THIS_THREAD - > putMark ( ) ;
2016-09-28 00:37:20 +03:00
}
2018-05-07 21:42:17 +03:00
void ProfileManager : : storeBlockForce2 ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName ,
profiler : : timestamp_t _timestamp )
2016-09-28 00:37:20 +03:00
{
2017-11-09 23:12:54 +03:00
if ( ( _desc - > m_status & profiler : : ON ) = = 0 )
2016-09-28 00:37:20 +03:00
return ;
2017-03-31 21:17:08 +03:00
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2016-09-28 00:37:20 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2017-11-09 23:12:54 +03:00
if ( ! THIS_THREAD - > allowChildren & & ( _desc - > m_status & FORCE_ON_FLAG ) = = 0 )
2016-09-28 00:37:20 +03:00
return ;
# endif
2017-11-15 21:43:52 +03:00
THIS_THREAD - > storeBlock ( profiler : : Block ( _timestamp , _timestamp , _desc - > id ( ) , _runtimeName ) ) ;
2018-01-08 02:56:51 +03:00
THIS_THREAD - > putMark ( ) ;
2016-12-12 22:26:32 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
void ProfileManager : : beginBlock ( profiler : : Block & _block )
2016-09-18 19:02:12 +03:00
{
2017-04-05 22:36:06 +03:00
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2017-04-05 22:36:06 +03:00
2017-09-30 20:45:06 +03:00
if ( + + THIS_THREAD - > stackSize > 1 )
2017-04-05 22:36:06 +03:00
{
2018-01-08 02:56:51 +03:00
// _block is a sibling of current opened frame and this frame has been opened
// before profiler was enabled. This _block should be ignored.
2017-04-06 22:59:33 +03:00
_block . m_status = profiler : : OFF ;
2017-04-17 22:27:10 +03:00
THIS_THREAD - > blocks . openedList . emplace_back ( _block ) ;
2016-09-18 19:02:12 +03:00
return ;
2017-04-05 22:36:06 +03:00
}
2016-09-18 19:02:12 +03:00
2018-01-08 02:56:51 +03:00
if ( ! isEnabled ( ) )
{
// _block is a top-level block (a.k.a. frame).
// It should be ignored because profiler is disabled.
_block . m_status = profiler : : OFF ;
THIS_THREAD - > blocks . openedList . emplace_back ( _block ) ;
beginFrame ( ) ; // FPS counter
return ;
}
2017-04-05 22:36:06 +03:00
2018-01-08 02:56:51 +03:00
// Profiler is enabled. Begin block.
2016-09-18 19:02:12 +03:00
2017-09-30 20:45:06 +03:00
THIS_THREAD - > stackSize = 0 ;
2017-04-02 14:23:11 +03:00
2018-01-08 02:56:51 +03:00
const auto blockStatus = _block . m_status ;
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2017-03-31 21:17:08 +03:00
if ( THIS_THREAD - > allowChildren )
2016-09-20 22:57:34 +03:00
{
# endif
2017-11-15 21:43:52 +03:00
if ( blockStatus & profiler : : ON )
2016-09-20 22:57:34 +03:00
_block . start ( ) ;
# if EASY_ENABLE_BLOCK_STATUS != 0
2017-11-15 21:43:52 +03:00
THIS_THREAD - > allowChildren = ( ( blockStatus & profiler : : OFF_RECURSIVE ) = = 0 ) ;
2017-06-12 11:30:01 -04:00
}
2017-11-15 21:43:52 +03:00
else if ( blockStatus & FORCE_ON_FLAG )
2016-09-20 22:57:34 +03:00
{
_block . start ( ) ;
_block . m_status = profiler : : FORCE_ON_WITHOUT_CHILDREN ;
}
else
{
_block . m_status = profiler : : OFF_RECURSIVE ;
}
# endif
2018-01-08 02:56:51 +03:00
if ( THIS_THREAD - > blocks . openedList . empty ( ) )
beginFrame ( ) ; // FPS counter
2017-04-02 14:23:11 +03:00
2017-04-17 22:27:10 +03:00
THIS_THREAD - > blocks . openedList . emplace_back ( _block ) ;
}
void ProfileManager : : beginNonScopedBlock ( const profiler : : BaseBlockDescriptor * _desc , const char * _runtimeName )
{
if ( THIS_THREAD = = nullptr )
2017-09-28 21:04:28 +03:00
registerThread ( ) ;
2017-04-17 22:27:10 +03:00
NonscopedBlock & b = THIS_THREAD - > nonscopedBlocks . push ( _desc , _runtimeName , false ) ;
beginBlock ( b ) ;
b . copyname ( ) ;
2016-09-18 19:02:12 +03:00
}
2018-05-07 21:42:17 +03:00
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 )
2016-09-18 19:02:12 +03:00
{
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().
2017-06-06 20:46:06 +03:00
ts - > sync . openedList . emplace_back ( _time , _target_thread_id , _target_process ) ;
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2016-09-18 19:02:12 +03:00
void ProfileManager : : endBlock ( )
{
2017-09-30 20:45:06 +03:00
if ( - - THIS_THREAD - > stackSize > 0 )
2017-04-05 22:36:06 +03:00
{
2018-01-08 02:56:51 +03:00
// Just pop child blocks from stack until frame, which
// has been opened before profiler was enabled, finish.
2017-04-05 22:36:06 +03:00
THIS_THREAD - > popSilent ( ) ;
2017-04-02 14:23:11 +03:00
return ;
2017-04-05 22:36:06 +03:00
}
2017-04-02 14:23:11 +03:00
2017-09-30 20:45:06 +03:00
THIS_THREAD - > stackSize = 0 ;
2018-01-08 02:56:51 +03:00
if ( ! isEnabled ( ) )
2017-04-02 14:23:11 +03:00
{
2017-04-05 22:36:06 +03:00
THIS_THREAD - > popSilent ( ) ;
2018-01-08 02:56:51 +03:00
endFrame ( ) ; // FPS counter
2016-09-18 19:02:12 +03:00
return ;
2017-04-02 14:23:11 +03:00
}
2016-09-18 19:02:12 +03:00
2018-01-08 02:56:51 +03:00
auto & currentThreadStack = THIS_THREAD - > blocks . openedList ;
if ( currentThreadStack . empty ( ) )
2016-09-18 19:02:12 +03:00
return ;
2018-05-07 21:42:17 +03:00
profiler : : Block & top = currentThreadStack . back ( ) ;
2017-04-05 22:36:06 +03:00
if ( top . m_status & profiler : : ON )
2016-09-18 19:02:12 +03:00
{
2017-04-05 22:36:06 +03:00
if ( ! top . finished ( ) )
top . finish ( ) ;
THIS_THREAD - > storeBlock ( top ) ;
2016-09-18 19:02:12 +03:00
}
2016-09-20 22:57:34 +03:00
else
{
2018-01-08 02:56:51 +03:00
// This is to restrict endBlock() call inside ~Block()
top . m_end = top . m_begin ;
2016-09-20 22:57:34 +03:00
}
2016-09-18 19:02:12 +03:00
2017-04-17 22:27:10 +03:00
if ( ! top . m_isScoped )
THIS_THREAD - > nonscopedBlocks . pop ( ) ;
2018-01-08 02:56:51 +03:00
currentThreadStack . pop_back ( ) ;
if ( currentThreadStack . empty ( ) )
2017-04-02 14:23:11 +03:00
{
2018-01-08 02:56:51 +03:00
THIS_THREAD - > putMark ( ) ;
endFrame ( ) ; // FPS counter
2016-09-20 22:57:34 +03:00
# if EASY_ENABLE_BLOCK_STATUS != 0
2017-04-02 14:23:11 +03:00
THIS_THREAD - > allowChildren = true ;
}
else
{
2018-05-07 21:42:17 +03:00
THIS_THREAD - > allowChildren = ( ( currentThreadStack . back ( ) . get ( ) . m_status & profiler : : OFF_RECURSIVE ) = = 0 ) ;
2016-09-20 22:57:34 +03:00
# endif
2018-01-08 02:56:51 +03:00
}
2016-09-18 19:02:12 +03:00
}
2018-05-07 21:42:17 +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 )
2017-09-28 21:04:28 +03:00
{
// Implicit thread registration.
2016-12-12 22:26:32 +03:00
// If thread owned by current process then create new ThreadStorage if there is no one
2017-09-30 19:02:24 +03:00
# if EASY_OPTION_IMPLICIT_THREAD_REGISTRATION != 0
2016-12-12 22:26:32 +03:00
ts = _lockSpin ? & threadStorage ( _thread_id ) : & _threadStorage ( _thread_id ) ;
2017-11-09 23:12:54 +03:00
# if !defined(_WIN32) && !defined(EASY_CXX11_TLS_AVAILABLE)
2017-09-30 19:02:24 +03:00
# if EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS != 0
# pragma message "Warning: Implicit thread registration together with removing empty unguarded threads may cause application crash because there is no possibility to check thread state (dead or alive) for pthreads and removed ThreadStorage may be reused if thread is still alive."
2017-09-28 21:04:28 +03:00
# else
2017-09-30 19:02:24 +03:00
# pragma message "Warning: Implicit thread registration without removing empty unguarded threads may lead to memory leak because there is no possibility to check thread state (dead or alive) for pthreads."
2017-09-28 21:04:28 +03:00
# endif
# endif
# endif
}
2016-12-12 22:26:32 +03:00
else
2017-09-28 21:04:28 +03:00
{
2016-12-12 22:26:32 +03:00
// 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 ) ;
2017-09-28 21:04:28 +03:00
}
2016-12-12 22:26:32 +03:00
2016-09-18 19:02:12 +03:00
if ( ts = = nullptr | | ts - > sync . openedList . empty ( ) )
return ;
2017-06-06 20:46:06 +03:00
CSwitchBlock & lastBlock = ts - > sync . openedList . back ( ) ;
2017-04-06 23:10:14 +03:00
lastBlock . m_end = _endtime ;
2016-09-18 19:02:12 +03:00
ts - > storeCSwitch ( lastBlock ) ;
2017-04-17 22:27:10 +03:00
ts - > sync . openedList . pop_back ( ) ;
2016-09-18 19:02:12 +03:00
}
2016-12-12 22:26:32 +03:00
//////////////////////////////////////////////////////////////////////////
2017-04-02 14:23:11 +03:00
void ProfileManager : : beginFrame ( )
2017-03-31 21:17:08 +03:00
{
2017-09-30 20:45:06 +03:00
THIS_THREAD - > beginFrame ( ) ;
2017-03-31 21:17:08 +03:00
}
void ProfileManager : : endFrame ( )
{
2017-09-30 20:45:06 +03:00
if ( ! THIS_THREAD - > frameOpened )
2017-04-02 14:23:11 +03:00
return ;
2017-03-31 21:17:08 +03:00
2017-09-30 20:45:06 +03:00
const profiler : : timestamp_t duration = THIS_THREAD - > endFrame ( ) ;
2017-03-31 21:17:08 +03:00
2018-01-08 02:56:51 +03:00
if ( THIS_THREAD_FRAME_T_RESET_MAX )
THIS_THREAD_FRAME_T_MAX = 0 ;
2017-11-15 21:43:52 +03:00
THIS_THREAD_FRAME_T_RESET_MAX = false ;
2017-03-31 21:17:08 +03:00
2017-04-02 14:23:11 +03:00
THIS_THREAD_FRAME_T_CUR = duration ;
if ( duration > THIS_THREAD_FRAME_T_MAX )
THIS_THREAD_FRAME_T_MAX = duration ;
2017-03-31 21:17:08 +03:00
2017-11-15 21:43:52 +03:00
THIS_THREAD_FRAME_T_RESET_AVG = THIS_THREAD_FRAME_T_RESET_AVG | | THIS_THREAD_N_FRAMES > 10000 ;
2017-04-03 23:08:52 +03:00
2017-04-02 14:23:11 +03:00
if ( THIS_THREAD_IS_MAIN )
{
2018-01-08 02:56:51 +03:00
if ( m_frameAvgReset . exchange ( false , std : : memory_order_acq_rel ) | | THIS_THREAD_FRAME_T_RESET_AVG )
2017-04-03 23:08:52 +03:00
{
if ( THIS_THREAD_N_FRAMES > 0 )
m_frameAvg . store ( THIS_THREAD_FRAME_T_ACC / THIS_THREAD_N_FRAMES , std : : memory_order_release ) ;
THIS_THREAD_FRAME_T_RESET_AVG = false ;
THIS_THREAD_FRAME_T_ACC = duration ;
THIS_THREAD_N_FRAMES = 1 ;
}
else
{
THIS_THREAD_FRAME_T_ACC + = duration ;
+ + THIS_THREAD_N_FRAMES ;
m_frameAvg . store ( THIS_THREAD_FRAME_T_ACC / THIS_THREAD_N_FRAMES , std : : memory_order_release ) ;
}
2017-11-15 21:43:52 +03:00
const auto maxDuration = m_frameMax . load ( std : : memory_order_acquire ) ;
2018-01-08 02:56:51 +03:00
if ( m_frameMaxReset . exchange ( false , std : : memory_order_acq_rel ) | | duration > maxDuration )
2017-04-02 14:23:11 +03:00
m_frameMax . store ( duration , std : : memory_order_release ) ;
2017-04-03 23:08:52 +03:00
m_frameCur . store ( duration , std : : memory_order_release ) ;
2017-11-15 21:43:52 +03:00
return ;
2017-04-03 23:08:52 +03:00
}
2017-11-15 21:43:52 +03:00
const auto reset = ( uint32_t ) ! THIS_THREAD_FRAME_T_RESET_AVG ;
THIS_THREAD_FRAME_T_RESET_AVG = false ;
THIS_THREAD_N_FRAMES = 1 + reset * THIS_THREAD_N_FRAMES ;
THIS_THREAD_FRAME_T_ACC = duration + reset * THIS_THREAD_FRAME_T_ACC ;
2017-03-31 21:17:08 +03:00
}
profiler : : timestamp_t ProfileManager : : maxFrameDuration ( )
{
auto duration = m_frameMax . load ( std : : memory_order_acquire ) ;
2017-04-03 23:08:52 +03:00
m_frameMaxReset . store ( true , std : : memory_order_release ) ;
return duration ;
}
profiler : : timestamp_t ProfileManager : : avgFrameDuration ( )
{
auto duration = m_frameAvg . load ( std : : memory_order_acquire ) ;
m_frameAvgReset . store ( true , std : : memory_order_release ) ;
2017-03-31 21:17:08 +03:00
return duration ;
}
2017-04-03 23:08:52 +03:00
profiler : : timestamp_t ProfileManager : : curFrameDuration ( ) const
2017-03-31 21:17:08 +03:00
{
2017-04-03 23:08:52 +03:00
return m_frameCur . load ( std : : memory_order_acquire ) ;
2017-03-31 21:17:08 +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 ) ;
2018-01-29 23:29:43 +03:00
auto time = profiler : : clock : : now ( ) ;
2018-01-08 02:56:51 +03:00
if ( m_profilerStatus . exchange ( isEnable , std : : memory_order_acq_rel ) = = isEnable )
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 )
{
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Enabled profiling \n " ) ;
2016-12-21 21:59:40 +03:00
enableEventTracer ( ) ;
m_beginTime = time ;
2016-09-22 23:06:43 +03:00
}
else
{
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Disabled profiling \n " ) ;
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 )
{
2017-03-02 10:28:43 +02:00
m_isEventTracingEnabled . store ( _isEnable , std : : memory_order_release ) ;
2017-03-01 11:14:02 +02:00
}
bool ProfileManager : : isEventTracingEnabled ( ) const
{
return m_isEventTracingEnabled . load ( std : : memory_order_acquire ) ;
2016-09-18 19:02:12 +03:00
}
//////////////////////////////////////////////////////////////////////////
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
2017-09-28 21:04:28 +03:00
// Check thread state for Windows
2016-11-20 17:09:50 +03:00
DWORD exitCode = 0 ;
2017-06-05 21:24:01 +03:00
auto hThread = OpenThread ( THREAD_QUERY_LIMITED_INFORMATION , FALSE , ( DWORD ) _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
2017-09-28 21:04:28 +03:00
// Check thread state for Linux and MacOS/iOS
// This would drop the application if pthread already died
//return pthread_kill(_registeredThread.pthread_id, 0) != 0 ? 1 : 0;
2016-11-20 17:09:50 +03:00
2017-09-28 21:04:28 +03:00
// There is no function to check external pthread state in Linux! :((
2016-11-20 17:09:50 +03:00
2017-11-09 23:12:54 +03:00
# ifndef EASY_CXX11_TLS_AVAILABLE
2018-05-07 21:42:17 +03:00
# pragma message "Warning: Your compiler does not support thread_local C++11 feature. Please use EASY_THREAD_SCOPE as much as possible. Otherwise, there is a possibility of memory leak if there are a lot of rapidly created and destroyed threads."
2016-11-20 17:09:50 +03:00
# endif
2017-09-28 21:04:28 +03:00
return 0 ;
# endif
2016-11-20 17:09:50 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
uint32_t ProfileManager : : dumpBlocksToStream ( std : : ostream & _outputStream , bool _lockSpin , bool _async )
2016-09-18 19:02:12 +03:00
{
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " dumpBlocksToStream(_lockSpin = " < < _lockSpin < < " )... \n " ) ;
2016-12-21 21:59:40 +03:00
if ( _lockSpin )
m_dumpSpin . lock ( ) ;
2016-09-18 19:02:12 +03:00
# ifndef _WIN32
const bool eventTracingEnabled = m_isEventTracingEnabled . load ( std : : memory_order_acquire ) ;
# endif
2018-01-08 02:56:51 +03:00
if ( isEnabled ( ) )
{
m_profilerStatus . store ( false , std : : memory_order_release ) ;
2016-12-21 21:59:40 +03:00
disableEventTracer ( ) ;
2018-01-29 23:29:43 +03:00
m_endTime = profiler : : clock : : now ( ) ;
2016-12-21 21:59:40 +03:00
}
2016-09-18 19:02:12 +03:00
2017-11-02 22:43:37 +03:00
if ( _async & & m_stopDumping . load ( std : : memory_order_acquire ) )
{
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
return 0 ;
}
2018-01-08 02:56:51 +03:00
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.
2018-01-08 02:56:51 +03:00
// This is much better than inserting spin-lock or atomic variable store/load into each storeBlock operation.
//
// Note: this means - wait for all ThreadStorage::storeBlock() to finish.
2016-09-20 22:57:34 +03:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 20 ) ) ;
2016-12-21 21:59:40 +03:00
2017-12-28 22:21:54 +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 ( ) ;
m_storedSpin . lock ( ) ;
2017-12-28 22:21:54 +03:00
// This is the only place using both spins, so no dead-lock will occur
2016-09-20 22:57:34 +03:00
// TODO: think about better solution because this one is not 100% safe...
2018-01-29 23:29:43 +03:00
const auto time = profiler : : clock : : now ( ) ;
const auto endtime = m_endTime = = 0 ? time : std : : min ( time , 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
2017-11-02 22:43:37 +03:00
if ( _async & & m_stopDumping . load ( std : : memory_order_acquire ) )
{
m_spin . unlock ( ) ;
m_storedSpin . unlock ( ) ;
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
return 0 ;
}
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Writing context switch events... \n " ) ;
2016-09-18 19:02:12 +03:00
uint64_t timestamp = 0 ;
2017-06-06 20:46:06 +03:00
profiler : : thread_id_t thread_from = 0 , thread_to = 0 ;
2016-09-18 19:02:12 +03:00
std : : ifstream infile ( m_csInfoFilename . c_str ( ) ) ;
2017-02-08 23:20:09 +03:00
if ( infile . is_open ( ) )
{
EASY_LOG_ONLY ( uint32_t num = 0 ) ;
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 ;
2017-02-08 23:20:09 +03:00
while ( infile > > timestamp > > thread_from > > thread_to > > next_task_name > > process_to )
{
2017-11-02 22:43:37 +03:00
if ( _async & & m_stopDumping . load ( std : : memory_order_acquire ) )
{
m_spin . unlock ( ) ;
m_storedSpin . unlock ( ) ;
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
return 0 ;
}
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 ) ;
2017-02-08 23:20:09 +03:00
EASY_LOG_ONLY ( + + num ) ;
2016-09-18 19:02:12 +03:00
}
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Done, " < < num < < " context switch events wrote \n " ) ;
2016-09-18 19:02:12 +03:00
}
2017-02-08 23:20:09 +03:00
EASY_LOG_ONLY (
else {
EASY_ERROR ( " Can not open context switch log-file \" " < < m_csInfoFilename < < " \" \n " ) ;
}
)
2016-09-18 19:02:12 +03:00
}
# endif
2017-04-09 10:23:59 +03:00
bool mainThreadExpired = false ;
2016-09-18 19:02:12 +03:00
// Calculate used memory total size and total blocks number
uint64_t usedMemorySize = 0 ;
uint32_t blocks_number = 0 ;
2017-12-28 00:00:20 +03:00
for ( auto thread_it = m_threads . begin ( ) , end = m_threads . end ( ) ; thread_it ! = end ; )
2016-09-18 19:02:12 +03:00
{
2017-11-02 22:43:37 +03:00
if ( _async & & m_stopDumping . load ( std : : memory_order_acquire ) )
{
m_spin . unlock ( ) ;
m_storedSpin . unlock ( ) ;
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
return 0 ;
}
2017-12-28 00:00:20 +03:00
auto & thread = thread_it - > second ;
2017-12-28 22:21:54 +03:00
uint32_t num = thread . blocks . closedList . markedSize ( ) + thread . sync . closedList . size ( ) ;
2017-12-28 00:00:20 +03:00
const char expired = ProfileManager : : checkThreadExpired ( thread ) ;
2016-09-20 22:57:34 +03:00
2017-09-30 19:02:24 +03:00
# ifdef _WIN32
if ( num = = 0 & & expired ! = 0 )
2017-11-09 23:12:54 +03:00
# elif defined(EASY_CXX11_TLS_AVAILABLE)
2017-09-30 19:02:24 +03:00
// Removing !guarded thread when thread_local feature is supported is safe.
2017-12-28 00:00:20 +03:00
if ( num = = 0 & & ( expired ! = 0 | | ! thread . guarded ) )
2017-09-30 19:02:24 +03:00
# elif EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS != 0
# pragma message "Warning: Removing !guarded thread without thread_local support may cause an application crash, but fixes potential memory leak when using pthreads."
// Removing !guarded thread may cause an application crash if a thread would start to write blocks after ThreadStorage remove.
// TODO: Find solution to check thread state for pthread or to nullify THIS_THREAD pointer for removed ThreadStorage
if ( num = = 0 & & ( expired ! = 0 | | ! t . guarded ) )
2017-09-28 21:04:28 +03:00
# else
2017-09-30 19:02:24 +03:00
# pragma message "Warning: Can not check pthread state (dead or alive). This may cause memory leak because ThreadStorage-s would not be removed ever during an application launched."
2017-09-28 21:04:28 +03:00
if ( num = = 0 & & expired ! = 0 )
# endif
{
// Remove thread if it contains no profiled information and has been finished (or is not guarded --deprecated).
2017-12-28 00:00:20 +03:00
profiler : : thread_id_t id = thread_it - > first ;
2017-04-09 10:23:59 +03:00
if ( ! mainThreadExpired & & m_mainThreadId . compare_exchange_weak ( id , 0 , std : : memory_order_release , std : : memory_order_acquire ) )
mainThreadExpired = true ;
2017-12-28 00:00:20 +03:00
m_threads . erase ( thread_it + + ) ;
2016-09-20 22:57:34 +03:00
continue ;
}
2017-09-28 21:04:28 +03:00
if ( expired = = 1 )
{
2017-12-28 00:00:20 +03:00
EASY_FORCE_EVENT3 ( thread , endtime , " ThreadExpired " , EASY_COLOR_THREAD_END ) ;
2016-12-12 22:26:32 +03:00
+ + num ;
}
2017-12-28 00:00:20 +03:00
usedMemorySize + = thread . blocks . usedMemorySize + thread . sync . usedMemorySize ;
2016-09-20 22:57:34 +03:00
blocks_number + = num ;
2017-12-28 00:00:20 +03:00
+ + thread_it ;
2016-09-18 19:02:12 +03:00
}
2016-09-27 22:28:04 +03:00
// Write profiler signature and version
2018-05-07 21:42:17 +03:00
write ( _outputStream , EASY_PROFILER_SIGNATURE ) ;
write ( _outputStream , EASY_PROFILER_VERSION ) ;
write ( _outputStream , 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
2017-05-04 21:40:48 +03:00
# if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
2018-05-08 01:30:10 +03:00
write ( _outputStream , m_cpuFrequency ) ;
2016-09-18 19:02:12 +03:00
# else
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Calculating CPU frequency \n " ) ;
2017-03-31 21:17:08 +03:00
const int64_t cpu_frequency = calculate_cpu_frequency ( ) ;
2018-05-07 21:42:17 +03:00
write ( _outputStream , cpu_frequency * 1000LL ) ;
2017-03-31 21:17:08 +03:00
EASY_LOGMSG ( " Done calculating CPU frequency \n " ) ;
2016-09-26 23:11:25 +03:00
2018-05-07 21:42:17 +03:00
m_cpuFrequency . store ( cpu_frequency , std : : memory_order_release ) ;
2016-09-18 19:02:12 +03:00
# endif
2016-09-22 23:06:43 +03:00
// Write begin and end time
2018-05-07 21:42:17 +03:00
write ( _outputStream , m_beginTime ) ;
write ( _outputStream , m_endTime ) ;
2016-09-22 23:06:43 +03:00
2016-09-18 19:02:12 +03:00
// Write blocks number and used memory size
2018-05-07 21:42:17 +03:00
write ( _outputStream , usedMemorySize ) ;
write ( _outputStream , m_descriptorsMemorySize ) ;
write ( _outputStream , blocks_number ) ;
write ( _outputStream , static_cast < uint32_t > ( m_descriptors . size ( ) ) ) ;
2018-06-09 02:18:39 +03:00
write ( _outputStream , static_cast < uint32_t > ( m_threads . size ( ) ) ) ;
write ( _outputStream , static_cast < uint16_t > ( 0 ) ) ; // Bookmarks count (they can be created by user in the UI)
write ( _outputStream , static_cast < uint16_t > ( 0 ) ) ; // padding
2016-09-18 19:02:12 +03:00
// 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 ) ;
2018-05-07 21:42:17 +03:00
write ( _outputStream , size ) ;
write < profiler : : BaseBlockDescriptor > ( _outputStream , * descriptor ) ;
write ( _outputStream , name_size ) ;
write ( _outputStream , descriptor - > name ( ) , name_size ) ;
write ( _outputStream , descriptor - > filename ( ) , filename_size ) ;
2016-09-18 19:02:12 +03:00
}
// Write blocks and context switch events for each thread
2017-12-28 00:00:20 +03:00
for ( auto thread_it = m_threads . begin ( ) , end = m_threads . end ( ) ; thread_it ! = end ; )
2016-09-18 19:02:12 +03:00
{
2017-11-02 22:43:37 +03:00
if ( _async & & m_stopDumping . load ( std : : memory_order_acquire ) )
{
m_spin . unlock ( ) ;
m_storedSpin . unlock ( ) ;
if ( _lockSpin )
m_dumpSpin . unlock ( ) ;
return 0 ;
}
2017-12-28 00:00:20 +03:00
auto & thread = thread_it - > second ;
2016-09-18 19:02:12 +03:00
2018-05-07 21:42:17 +03:00
write ( _outputStream , thread_it - > first ) ;
2016-09-18 19:02:12 +03:00
2017-12-28 00:00:20 +03:00
const auto name_size = static_cast < uint16_t > ( thread . name . size ( ) + 1 ) ;
2018-05-07 21:42:17 +03:00
write ( _outputStream , name_size ) ;
write ( _outputStream , name_size > 1 ? thread . name . c_str ( ) : " " , name_size ) ;
2016-09-18 19:02:12 +03:00
2018-05-07 21:42:17 +03:00
write ( _outputStream , thread . sync . closedList . size ( ) ) ;
2017-12-28 00:00:20 +03:00
if ( ! thread . sync . closedList . empty ( ) )
thread . sync . closedList . serialize ( _outputStream ) ;
2016-09-18 19:02:12 +03:00
2018-05-07 21:42:17 +03:00
write ( _outputStream , thread . blocks . closedList . markedSize ( ) ) ;
2017-12-28 22:21:54 +03:00
if ( ! thread . blocks . closedList . markedEmpty ( ) )
2017-12-28 00:00:20 +03:00
thread . blocks . closedList . serialize ( _outputStream ) ;
2016-09-18 19:02:12 +03:00
2017-12-28 00:00:20 +03:00
thread . clearClosed ( ) ;
2017-04-06 23:10:14 +03:00
//t.blocks.openedList.clear();
2017-12-28 00:00:20 +03:00
thread . sync . openedList . clear ( ) ;
2016-09-20 22:57:34 +03:00
2017-12-28 00:00:20 +03:00
if ( thread . expired . load ( std : : memory_order_acquire ) ! = 0 )
2017-04-09 10:23:59 +03:00
{
// Remove expired thread after writing all profiled information
2017-12-28 00:00:20 +03:00
profiler : : thread_id_t id = thread_it - > first ;
2017-04-09 10:23:59 +03:00
if ( ! mainThreadExpired & & m_mainThreadId . compare_exchange_weak ( id , 0 , std : : memory_order_release , std : : memory_order_acquire ) )
mainThreadExpired = true ;
2017-12-28 00:00:20 +03:00
m_threads . erase ( thread_it + + ) ;
2017-04-09 10:23:59 +03:00
}
2016-09-20 22:57:34 +03:00
else
2017-04-09 10:23:59 +03:00
{
2017-12-28 00:00:20 +03:00
+ + thread_it ;
2017-04-09 10:23:59 +03:00
}
2016-09-18 19:02:12 +03:00
}
2018-06-09 02:18:39 +03:00
// End of threads section
write ( _outputStream , EASY_PROFILER_SIGNATURE ) ;
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
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Done dumpBlocksToStream(). Dumped " < < blocks_number < < " blocks \n " ) ;
2016-09-18 19:02:12 +03:00
return blocks_number ;
}
uint32_t ProfileManager : : dumpBlocksToFile ( const char * _filename )
{
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " dumpBlocksToFile( \" " < < _filename < < " \" )... \n " ) ;
2017-02-08 22:06:38 +03:00
std : : ofstream outputFile ( _filename , std : : fstream : : binary ) ;
if ( ! outputFile . is_open ( ) )
2017-02-08 23:20:09 +03:00
{
EASY_ERROR ( " Can not open \" " < < _filename < < " \" for writing \n " ) ;
2017-02-08 22:06:38 +03:00
return 0 ;
2017-02-08 23:20:09 +03:00
}
2017-02-08 22:06:38 +03:00
// Write data directly to file
2018-05-07 21:42:17 +03:00
const auto blocksNumber = dumpBlocksToStream ( outputFile , true , false ) ;
2016-09-18 19:02:12 +03:00
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Done dumpBlocksToFile() \n " ) ;
2016-09-18 19:02:12 +03:00
return blocksNumber ;
}
2017-09-28 21:04:28 +03:00
void ProfileManager : : registerThread ( )
{
THIS_THREAD = & threadStorage ( getCurrentThreadId ( ) ) ;
2017-11-09 23:12:54 +03:00
# ifdef EASY_CXX11_TLS_AVAILABLE
2017-09-28 21:04:28 +03:00
THIS_THREAD - > guarded = true ;
THIS_THREAD_GUARD . m_id = THIS_THREAD - > id ;
# endif
}
2018-05-07 21:42:17 +03:00
const char * ProfileManager : : registerThread ( const char * name , profiler : : ThreadGuard & threadGuard )
2016-09-18 19:02:12 +03:00
{
2017-03-31 21:17:08 +03:00
if ( THIS_THREAD = = nullptr )
THIS_THREAD = & threadStorage ( getCurrentThreadId ( ) ) ;
THIS_THREAD - > guarded = true ;
2017-04-09 10:23:59 +03:00
if ( ! THIS_THREAD - > named )
{
2017-03-31 21:17:08 +03:00
THIS_THREAD - > named = true ;
THIS_THREAD - > name = name ;
2017-04-09 10:23:59 +03:00
2017-04-09 09:12:27 +03:00
if ( THIS_THREAD - > name = = " Main " )
2017-04-09 10:23:59 +03:00
{
profiler : : thread_id_t id = 0 ;
THIS_THREAD_IS_MAIN = m_mainThreadId . compare_exchange_weak ( id , THIS_THREAD - > id , std : : memory_order_release , std : : memory_order_acquire ) ;
}
2017-09-28 21:04:28 +03:00
2017-11-09 23:12:54 +03:00
# ifdef EASY_CXX11_TLS_AVAILABLE
2017-09-28 21:04:28 +03:00
THIS_THREAD_GUARD . m_id = THIS_THREAD - > id ;
}
2017-10-04 22:46:13 +03:00
( void ) threadGuard ; // this is just to prevent from warning about unused variable
2017-09-28 21:04:28 +03:00
# else
2016-09-18 19:02:12 +03:00
}
2017-03-31 21:17:08 +03:00
threadGuard . m_id = THIS_THREAD - > id ;
2017-09-28 21:04:28 +03:00
# endif
2016-11-20 17:09:50 +03:00
2017-03-31 21:17:08 +03:00
return THIS_THREAD - > name . c_str ( ) ;
2016-11-20 17:09:50 +03:00
}
const char * ProfileManager : : registerThread ( const char * name )
{
2017-03-31 21:17:08 +03:00
if ( THIS_THREAD = = nullptr )
THIS_THREAD = & threadStorage ( getCurrentThreadId ( ) ) ;
2016-09-20 22:57:34 +03:00
2017-04-09 10:23:59 +03:00
if ( ! THIS_THREAD - > named )
{
2017-03-31 21:17:08 +03:00
THIS_THREAD - > named = true ;
THIS_THREAD - > name = name ;
2017-04-09 10:23:59 +03:00
2017-04-09 09:12:27 +03:00
if ( THIS_THREAD - > name = = " Main " )
2017-04-09 10:23:59 +03:00
{
profiler : : thread_id_t id = 0 ;
THIS_THREAD_IS_MAIN = m_mainThreadId . compare_exchange_weak ( id , THIS_THREAD - > id , std : : memory_order_release , std : : memory_order_acquire ) ;
}
2017-09-28 21:04:28 +03:00
2017-11-09 23:12:54 +03:00
# ifdef EASY_CXX11_TLS_AVAILABLE
2017-09-28 21:04:28 +03:00
THIS_THREAD - > guarded = true ;
THIS_THREAD_GUARD . m_id = THIS_THREAD - > id ;
# endif
2016-09-18 19:02:12 +03:00
}
2017-03-31 21:17:08 +03:00
return THIS_THREAD - > name . c_str ( ) ;
2016-09-18 19:02:12 +03:00
}
2018-05-07 21:42:17 +03:00
void ProfileManager : : setBlockStatus ( profiler : : block_id_t _id , profiler : : EasyBlockStatus _status )
2016-09-18 19:02:12 +03:00
{
2018-01-08 02:56:51 +03:00
if ( isEnabled ( ) )
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
{
2018-01-08 02:56:51 +03:00
if ( ! m_isAlreadyListening . exchange ( true , std : : memory_order_acq_rel ) )
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
}
2017-03-01 11:14:02 +02:00
bool ProfileManager : : isListening ( ) const
{
return m_isAlreadyListening . load ( std : : memory_order_acquire ) ;
}
2016-09-18 19:02:12 +03:00
//////////////////////////////////////////////////////////////////////////
2018-05-07 21:42:17 +03:00
void ProfileManager : : setContextSwitchLogFilename ( const char * name )
{
m_csInfoFilename = name ;
}
const char * ProfileManager : : getContextSwitchLogFilename ( ) const
{
return m_csInfoFilename . c_str ( ) ;
}
//////////////////////////////////////////////////////////////////////////
# if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
profiler : : timestamp_t ProfileManager : : ticks2ns ( profiler : : timestamp_t ticks ) const
{
return static_cast < profiler : : timestamp_t > ( ticks * 1000000000LL / m_cpuFrequency ) ;
}
profiler : : timestamp_t ProfileManager : : ticks2us ( profiler : : timestamp_t ticks ) const
{
return static_cast < profiler : : timestamp_t > ( ticks * 1000000LL / m_cpuFrequency ) ;
}
# else
profiler : : timestamp_t ProfileManager : : ticks2ns ( profiler : : timestamp_t ticks ) const
{
return static_cast < profiler : : timestamp_t > ( ticks / m_cpuFrequency . load ( std : : memory_order_acquire ) ) ;
}
profiler : : timestamp_t ProfileManager : : ticks2us ( profiler : : timestamp_t ticks ) const
{
return static_cast < profiler : : timestamp_t > ( ticks * 1000 / m_cpuFrequency . load ( std : : memory_order_acquire ) ) ;
}
# endif
//////////////////////////////////////////////////////////////////////////
bool ProfileManager : : isMainThread ( )
{
return THIS_THREAD_IS_MAIN ;
}
profiler : : timestamp_t ProfileManager : : this_thread_frameTime ( profiler : : Duration _durationCast )
{
if ( _durationCast = = profiler : : TICKS )
return THIS_THREAD_FRAME_T_CUR ;
return ProfileManager : : instance ( ) . ticks2us ( THIS_THREAD_FRAME_T_CUR ) ;
}
profiler : : timestamp_t ProfileManager : : this_thread_frameTimeLocalMax ( profiler : : Duration _durationCast )
{
THIS_THREAD_FRAME_T_RESET_MAX = true ;
if ( _durationCast = = profiler : : TICKS )
return THIS_THREAD_FRAME_T_MAX ;
return ProfileManager : : instance ( ) . ticks2us ( THIS_THREAD_FRAME_T_MAX ) ;
}
profiler : : timestamp_t ProfileManager : : this_thread_frameTimeLocalAvg ( profiler : : Duration _durationCast )
{
THIS_THREAD_FRAME_T_RESET_AVG = true ;
auto avgDuration = THIS_THREAD_N_FRAMES > 0 ? THIS_THREAD_FRAME_T_ACC / THIS_THREAD_N_FRAMES : 0 ;
if ( _durationCast = = profiler : : TICKS )
return avgDuration ;
return ProfileManager : : instance ( ) . ticks2us ( avgDuration ) ;
}
profiler : : timestamp_t ProfileManager : : main_thread_frameTime ( profiler : : Duration _durationCast )
{
const auto ticks = THIS_THREAD_IS_MAIN ? THIS_THREAD_FRAME_T_CUR : ProfileManager : : instance ( ) . curFrameDuration ( ) ;
if ( _durationCast = = profiler : : TICKS )
return ticks ;
return ProfileManager : : instance ( ) . ticks2us ( ticks ) ;
}
profiler : : timestamp_t ProfileManager : : main_thread_frameTimeLocalMax ( profiler : : Duration _durationCast )
{
if ( THIS_THREAD_IS_MAIN )
{
THIS_THREAD_FRAME_T_RESET_MAX = true ;
if ( _durationCast = = profiler : : TICKS )
return THIS_THREAD_FRAME_T_MAX ;
return ProfileManager : : instance ( ) . ticks2us ( THIS_THREAD_FRAME_T_MAX ) ;
}
if ( _durationCast = = profiler : : TICKS )
return ProfileManager : : instance ( ) . maxFrameDuration ( ) ;
return ProfileManager : : instance ( ) . ticks2us ( ProfileManager : : instance ( ) . maxFrameDuration ( ) ) ;
}
profiler : : timestamp_t ProfileManager : : main_thread_frameTimeLocalAvg ( profiler : : Duration _durationCast )
{
if ( THIS_THREAD_IS_MAIN )
{
THIS_THREAD_FRAME_T_RESET_AVG = true ;
auto avgDuration = THIS_THREAD_N_FRAMES > 0 ? THIS_THREAD_FRAME_T_ACC / THIS_THREAD_N_FRAMES : 0 ;
if ( _durationCast = = profiler : : TICKS )
return avgDuration ;
return ProfileManager : : instance ( ) . ticks2us ( avgDuration ) ;
}
if ( _durationCast = = profiler : : TICKS )
return ProfileManager : : instance ( ) . avgFrameDuration ( ) ;
return ProfileManager : : instance ( ) . ticks2us ( ProfileManager : : instance ( ) . avgFrameDuration ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-11-02 22:43:37 +03:00
template < class T >
2018-05-07 21:42:17 +03:00
static void join ( std : : future < T > & futureResult )
2017-11-02 22:43:37 +03:00
{
if ( futureResult . valid ( ) )
futureResult . get ( ) ;
}
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
2017-02-08 23:20:09 +03:00
EASY_LOGMSG ( " Listening started \n " ) ;
2018-05-07 21:42:17 +03:00
std : : stringstream os ( std : : ios_base : : out | std : : ios_base : : binary ) ;
2017-11-02 22:43:37 +03:00
std : : future < uint32_t > dumpingResult ;
bool dumping = false ;
2018-01-29 23:42:18 +03:00
const auto stopDumping = [ & ] {
2017-11-02 22:43:37 +03:00
dumping = false ;
m_stopDumping . store ( true , std : : memory_order_release ) ;
join ( dumpingResult ) ;
2018-05-07 21:42:17 +03:00
clear_sstream ( os ) ;
2017-11-02 22:43:37 +03:00
} ;
2016-09-18 19:02:12 +03:00
EasySocket socket ;
2017-11-09 23:12:54 +03:00
profiler : : net : : Message replyMessage ( profiler : : net : : MessageType : : Reply_Capturing_Started ) ;
2016-09-18 19:02:12 +03:00
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
{
2017-11-02 22:43:37 +03:00
if ( dumping )
stopDumping ( ) ;
2016-09-18 19:02:12 +03:00
socket . listen ( ) ;
socket . accept ( ) ;
2017-11-02 22:43:37 +03:00
bool hasConnect = true ;
2016-09-25 11:49:49 +03:00
2016-09-28 00:37:20 +03:00
// Send reply
{
const bool wasLowPriorityET =
# ifdef _WIN32
EasyEventTracer : : instance ( ) . isLowPriority ( ) ;
# else
false ;
# endif
2018-01-08 02:56:51 +03:00
const profiler : : net : : EasyProfilerStatus connectionReply ( isEnabled ( ) , isEventTracingEnabled ( ) , wasLowPriorityET ) ;
2017-11-09 23:12:54 +03:00
2017-03-31 21:17:08 +03:00
bytes = socket . send ( & connectionReply , sizeof ( profiler : : net : : EasyProfilerStatus ) ) ;
2016-09-28 00:37:20 +03:00
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
{
2017-11-02 22:43:37 +03:00
if ( dumping )
{
if ( ! dumpingResult . valid ( ) )
{
dumping = false ;
socket . setReceiveTimeout ( 0 ) ;
2018-05-07 21:42:17 +03:00
clear_sstream ( os ) ;
2017-11-02 22:43:37 +03:00
}
else if ( dumpingResult . wait_for ( std : : chrono : : milliseconds ( 0 ) ) = = std : : future_status : : ready )
{
dumping = false ;
dumpingResult . get ( ) ;
2018-05-07 21:42:17 +03:00
const auto size = os . tellp ( ) ;
2017-11-02 22:43:37 +03:00
static const decltype ( size ) badSize = - 1 ;
if ( size ! = badSize )
{
const profiler : : net : : DataMessage dm ( static_cast < uint32_t > ( size ) ,
2017-11-09 23:12:54 +03:00
profiler : : net : : MessageType : : Reply_Blocks ) ;
2017-11-02 22:43:37 +03:00
const size_t packet_size = sizeof ( dm ) + dm . size ;
std : : string sendbuf ;
sendbuf . reserve ( packet_size + 1 ) ;
if ( sendbuf . capacity ( ) > = packet_size ) // check if there is enough memory
{
sendbuf . append ( ( const char * ) & dm , sizeof ( dm ) ) ;
2018-05-07 21:42:17 +03:00
sendbuf + = os . str ( ) ; // TODO: Avoid double-coping data from stringstream!
clear_sstream ( os ) ;
2017-11-02 22:43:37 +03:00
bytes = socket . send ( sendbuf . c_str ( ) , packet_size ) ;
hasConnect = bytes > 0 ;
if ( ! hasConnect )
break ;
}
else
{
EASY_ERROR ( " Can not send blocks. Not enough memory for allocating " < < packet_size
< < " bytes " ) ;
2018-05-07 21:42:17 +03:00
clear_sstream ( os ) ;
2017-11-02 22:43:37 +03:00
}
}
else
{
EASY_ERROR ( " Can not send blocks. Bad std::stringstream.tellp() == -1 " ) ;
2018-05-07 21:42:17 +03:00
clear_sstream ( os ) ;
2017-11-02 22:43:37 +03:00
}
2017-11-09 23:12:54 +03:00
replyMessage . type = profiler : : net : : MessageType : : Reply_Blocks_End ;
2017-11-02 22:43:37 +03:00
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
if ( ! hasConnect )
break ;
2016-09-18 19:02:12 +03:00
2017-11-02 22:43:37 +03:00
socket . setReceiveTimeout ( 0 ) ;
}
}
char buffer [ 256 ] = { } ;
2016-09-18 19:02:12 +03:00
bytes = socket . receive ( buffer , 255 ) ;
2017-11-02 22:43:37 +03:00
hasConnect = socket . isConnected ( ) ;
if ( ! hasConnect | | bytes < static_cast < int > ( sizeof ( profiler : : net : : Message ) ) )
continue ;
2016-09-18 19:02:12 +03:00
2017-11-02 22:43:37 +03:00
auto message = ( const profiler : : net : : Message * ) buffer ;
if ( ! message - > isEasyNetMessage ( ) )
continue ;
2016-09-18 19:02:12 +03:00
2017-11-02 22:43:37 +03:00
switch ( message - > type )
2016-09-18 19:02:12 +03:00
{
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Ping :
2017-11-02 22:43:37 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Ping \n " ) ;
2017-11-02 22:43:37 +03:00
break ;
2016-09-18 19:02:12 +03:00
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Request_MainThread_FPS :
2016-09-18 19:02:12 +03:00
{
2017-11-02 22:43:37 +03:00
profiler : : timestamp_t maxDuration = maxFrameDuration ( ) , avgDuration = avgFrameDuration ( ) ;
2017-11-09 23:12:54 +03:00
2018-05-07 21:42:17 +03:00
maxDuration = ticks2us ( maxDuration ) ;
avgDuration = ticks2us ( avgDuration ) ;
2017-11-09 23:12:54 +03:00
const profiler : : net : : TimestampMessage reply ( profiler : : net : : MessageType : : Reply_MainThread_FPS ,
( uint32_t ) maxDuration , ( uint32_t ) avgDuration ) ;
2017-11-02 22:43:37 +03:00
bytes = socket . send ( & reply , sizeof ( profiler : : net : : TimestampMessage ) ) ;
hasConnect = bytes > 0 ;
2017-11-09 23:12:54 +03:00
2017-11-02 22:43:37 +03:00
break ;
}
2017-03-30 06:47:00 +03:00
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Request_Start_Capture :
2017-11-02 22:43:37 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Request_Start_Capture \n " ) ;
2017-03-31 21:17:08 +03:00
2018-01-29 23:29:43 +03:00
profiler : : timestamp_t t = 0 ;
2017-11-02 22:43:37 +03:00
EASY_FORCE_EVENT ( t , " StartCapture " , EASY_COLOR_START , profiler : : OFF ) ;
2017-02-08 23:20:09 +03:00
2017-11-02 22:43:37 +03:00
m_dumpSpin . lock ( ) ;
2018-01-08 02:56:51 +03:00
if ( ! m_profilerStatus . exchange ( true , std : : memory_order_acq_rel ) )
{
2017-11-02 22:43:37 +03:00
enableEventTracer ( ) ;
m_beginTime = t ;
}
m_dumpSpin . unlock ( ) ;
2016-09-18 19:02:12 +03:00
2017-11-09 23:12:54 +03:00
replyMessage . type = profiler : : net : : MessageType : : Reply_Capturing_Started ;
2017-11-02 22:43:37 +03:00
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Request_Stop_Capture :
2017-11-02 22:43:37 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Request_Stop_Capture \n " ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
if ( dumping )
2016-09-25 11:49:49 +03:00
break ;
2017-11-02 22:43:37 +03:00
m_dumpSpin . lock ( ) ;
2018-01-29 23:29:43 +03:00
auto time = profiler : : clock : : now ( ) ;
2018-01-08 02:56:51 +03:00
if ( m_profilerStatus . exchange ( false , std : : memory_order_acq_rel ) )
{
2017-11-02 22:43:37 +03:00
disableEventTracer ( ) ;
m_endTime = time ;
2016-09-25 11:49:49 +03:00
}
2017-11-02 22:43:37 +03:00
EASY_FORCE_EVENT2 ( m_endTime , " StopCapture " , EASY_COLOR_END , profiler : : OFF ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
dumping = true ;
socket . setReceiveTimeout ( 500 ) ; // We have to check if dumping ready or not
m_stopDumping . store ( false , std : : memory_order_release ) ;
dumpingResult = std : : async ( std : : launch : : async , [ this , & os ]
2016-09-25 11:49:49 +03:00
{
2017-11-02 22:43:37 +03:00
auto result = dumpBlocksToStream ( os , false , true ) ;
m_dumpSpin . unlock ( ) ;
return result ;
} ) ;
2016-09-28 00:37:20 +03:00
2017-11-02 22:43:37 +03:00
break ;
}
2016-09-25 11:49:49 +03:00
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Request_Blocks_Description :
2017-11-02 22:43:37 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Request_Blocks_Description \n " ) ;
2016-12-21 21:59:40 +03:00
2017-11-02 22:43:37 +03:00
if ( dumping )
stopDumping ( ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
// Write profiler signature and version
2018-05-07 21:42:17 +03:00
write ( os , EASY_PROFILER_SIGNATURE ) ;
write ( os , EASY_PROFILER_VERSION ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
// Write block descriptors
m_storedSpin . lock ( ) ;
2018-05-07 21:42:17 +03:00
write ( os , static_cast < uint32_t > ( m_descriptors . size ( ) ) ) ;
write ( os , m_descriptorsMemorySize ) ;
2017-11-02 22:43:37 +03:00
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 ) ;
2018-05-07 21:42:17 +03:00
write ( os , size ) ;
write < profiler : : BaseBlockDescriptor > ( os , * descriptor ) ;
write ( os , name_size ) ;
write ( os , descriptor - > name ( ) , name_size ) ;
write ( os , descriptor - > filename ( ) , filename_size ) ;
2016-09-25 11:49:49 +03:00
}
2017-11-02 22:43:37 +03:00
m_storedSpin . unlock ( ) ;
// END of Write block descriptors.
2016-09-25 11:49:49 +03:00
2018-05-07 21:42:17 +03:00
const auto size = os . tellp ( ) ;
2017-11-02 22:43:37 +03:00
static const decltype ( size ) badSize = - 1 ;
if ( size ! = badSize )
2016-09-25 11:49:49 +03:00
{
2017-11-02 22:43:37 +03:00
const profiler : : net : : DataMessage dm ( static_cast < uint32_t > ( size ) ,
2017-11-09 23:12:54 +03:00
profiler : : net : : MessageType : : Reply_Blocks_Description ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
const size_t packet_size = sizeof ( dm ) + dm . size ;
std : : string sendbuf ;
sendbuf . reserve ( packet_size + 1 ) ;
2016-09-27 22:28:04 +03:00
2017-11-02 22:43:37 +03:00
if ( sendbuf . capacity ( ) > = packet_size ) // check if there is enough memory
2016-09-25 11:49:49 +03:00
{
2017-11-02 22:43:37 +03:00
sendbuf . append ( ( const char * ) & dm , sizeof ( dm ) ) ;
2018-05-07 21:42:17 +03:00
sendbuf + = os . str ( ) ; // TODO: Avoid double-coping data from stringstream!
clear_sstream ( os ) ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
bytes = socket . send ( sendbuf . c_str ( ) , packet_size ) ;
//hasConnect = bytes > 0;
2017-03-30 06:47:00 +03:00
}
else
{
2017-11-02 22:43:37 +03:00
EASY_ERROR ( " Can not send block descriptions. Not enough memory for allocating " < < packet_size < < " bytes " ) ;
2017-03-30 06:47:00 +03:00
}
2017-11-02 22:43:37 +03:00
}
else
{
EASY_ERROR ( " Can not send block descriptions. Bad std::stringstream.tellp() == -1 " ) ;
}
2016-09-25 11:49:49 +03:00
2018-01-08 02:56:51 +03:00
replyMessage . type = profiler : : net : : MessageType : : Reply_Blocks_Description_End ;
2017-11-02 22:43:37 +03:00
bytes = socket . send ( & replyMessage , sizeof ( replyMessage ) ) ;
hasConnect = bytes > 0 ;
2016-09-25 11:49:49 +03:00
2017-11-02 22:43:37 +03:00
break ;
}
2016-09-25 11:49:49 +03:00
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Change_Block_Status :
2017-11-02 22:43:37 +03:00
{
auto data = reinterpret_cast < const profiler : : net : : BlockStatusMessage * > ( message ) ;
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::ChangeBLock_Status id= " < < data - > id < < " status= " < < data - > status < < std : : endl ) ;
2018-01-29 23:29:43 +03:00
setBlockStatus ( data - > id , static_cast < profiler : : EasyBlockStatus > ( data - > status ) ) ;
2017-11-02 22:43:37 +03:00
break ;
}
2016-09-25 11:49:49 +03:00
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Change_Event_Tracing_Status :
2017-11-02 22:43:37 +03:00
{
auto data = reinterpret_cast < const profiler : : net : : BoolMessage * > ( message ) ;
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Change_Event_Tracing_Status on= " < < data - > flag < < std : : endl ) ;
2018-01-08 02:56:51 +03:00
setEventTracingEnabled ( data - > flag ) ;
2017-11-02 22:43:37 +03:00
break ;
}
2016-09-28 00:37:20 +03:00
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Change_Event_Tracing_Priority :
2017-11-02 22:43:37 +03:00
{
2017-02-08 23:20:09 +03:00
# if defined(_WIN32) || EASY_OPTION_LOG_ENABLED != 0
2017-11-02 22:43:37 +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
2017-11-09 23:12:54 +03:00
EASY_LOGMSG ( " receive MessageType::Change_Event_Tracing_Priority low= " < < data - > flag < < std : : endl ) ;
2016-09-28 00:37:20 +03:00
2017-11-02 22:43:37 +03:00
# if defined(_WIN32)
EasyEventTracer : : instance ( ) . setLowPriority ( data - > flag ) ;
2016-09-28 00:37:20 +03:00
# endif
2017-11-02 22:43:37 +03:00
break ;
2016-09-25 11:49:49 +03:00
}
2016-09-18 19:02:12 +03:00
2017-11-02 22:43:37 +03:00
default :
break ;
2016-09-18 19:02:12 +03:00
}
}
}
2017-11-02 22:43:37 +03:00
if ( dumping )
{
m_stopDumping . store ( true , std : : memory_order_release ) ;
join ( dumpingResult ) ;
}
2017-12-28 22:21:54 +03:00
EASY_LOGMSG ( " Listening stopped \n " ) ;
2016-09-18 19:02:12 +03:00
}
2017-03-01 11:14:02 +02:00
2016-09-18 19:02:12 +03:00
//////////////////////////////////////////////////////////////////////////