2014-05-28 02:38:47 +00:00
# pragma once
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// 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 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.
// For more information, please refer to <http://unlicense.org/>
//
// ***********************************************************************
//
//
//
//
// Howto:
// Call these functions from your code:
// MicroProfileOnThreadCreate
// MicroProfileMouseButton
2015-01-02 18:37:58 +00:00
// MicroProfileMousePosition
2014-05-28 02:38:47 +00:00
// MicroProfileModKey
// MicroProfileFlip <-- Call this once per frame
// MicroProfileDraw <-- Call this once per frame
// MicroProfileToggleDisplayMode <-- Bind to a key to toggle profiling
// MicroProfileTogglePause <-- Bind to a key to toggle pause
//
// Use these macros in your code in blocks you want to time:
//
// MICROPROFILE_DECLARE
// MICROPROFILE_DEFINE
// MICROPROFILE_DECLARE_GPU
// MICROPROFILE_DEFINE_GPU
// MICROPROFILE_SCOPE
// MICROPROFILE_SCOPEI
// MICROPROFILE_SCOPEGPU
// MICROPROFILE_SCOPEGPUI
// MICROPROFILE_META
//
//
// Usage:
//
// {
// MICROPROFILE_SCOPEI("GroupName", "TimerName", nColorRgb):
// ..Code to be timed..
// }
//
// MICROPROFILE_DECLARE / MICROPROFILE_DEFINE allows defining groups in a shared place, to ensure sorting of the timers
//
// (in global scope)
// MICROPROFILE_DEFINE(g_ProfileFisk, "Fisk", "Skalle", nSomeColorRgb);
//
// (in some other file)
// MICROPROFILE_DECLARE(g_ProfileFisk);
//
// void foo(){
// MICROPROFILE_SCOPE(g_ProfileFisk);
// }
//
// Once code is instrumented the gui is activeted by calling MicroProfileToggleDisplayMode or by clicking in the upper left corner of
// the screen
//
// The following functions must be implemented before the profiler is usable
// debug render:
// void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
// void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType = MicroProfileBoxTypeFlat);
// void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor);
// Gpu time stamps:
// uint32_t MicroProfileGpuInsertTimeStamp();
// uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey);
// uint64_t MicroProfileTicksPerSecondGpu();
// threading:
// const char* MicroProfileGetThreadName(); Threadnames in detailed view
# ifndef MICROPROFILE_ENABLED
# define MICROPROFILE_ENABLED 1
# endif
2015-01-02 18:37:58 +00:00
# include <stdint.h>
typedef uint64_t MicroProfileToken ;
typedef uint16_t MicroProfileGroupId ;
2014-05-28 02:38:47 +00:00
#if 0 == MICROPROFILE_ENABLED
# define MICROPROFILE_DECLARE(var)
# define MICROPROFILE_DEFINE(var, group, name, color)
# define MICROPROFILE_DECLARE_GPU(var)
# define MICROPROFILE_DEFINE_GPU(var, group, name, color)
# define MICROPROFILE_SCOPE(var) do{}while(0)
# define MICROPROFILE_SCOPEI(group, name, color) do{}while(0)
# define MICROPROFILE_SCOPEGPU(var) do{}while(0)
# define MICROPROFILE_SCOPEGPUI(group, name, color) do{}while(0)
2015-01-02 18:37:58 +00:00
# define MICROPROFILE_META_CPU(name, count)
# define MICROPROFILE_META_GPU(name, count)
2014-05-28 02:38:47 +00:00
# define MICROPROFILE_FORCEENABLECPUGROUP(s) do{} while(0)
# define MICROPROFILE_FORCEDISABLECPUGROUP(s) do{} while(0)
# define MICROPROFILE_FORCEENABLEGPUGROUP(s) do{} while(0)
# define MICROPROFILE_FORCEDISABLEGPUGROUP(s) do{} while(0)
2015-01-02 18:37:58 +00:00
# define MICROPROFILE_SCOPE_TOKEN(token)
2014-05-28 02:38:47 +00:00
# define MicroProfileGetTime(group, name) 0.f
# define MicroProfileOnThreadCreate(foo) do{}while(0)
# define MicroProfileFlip() do{}while(0)
2015-01-02 18:37:58 +00:00
# define MicroProfileSetAggregateFrames(a) do{}while(0)
# define MicroProfileGetAggregateFrames() 0
# define MicroProfileGetCurrentAggregateFrames() 0
2014-05-28 02:38:47 +00:00
# define MicroProfileTogglePause() do{}while(0)
2015-01-02 18:37:58 +00:00
# define MicroProfileToggleAllGroups() do{} while(0)
2014-05-28 02:38:47 +00:00
# define MicroProfileDumpTimers() do{}while(0)
2015-01-02 18:37:58 +00:00
# define MicroProfileShutdown() do{}while(0)
# define MicroProfileSetForceEnable(a) do{} while(0)
# define MicroProfileGetForceEnable() false
# define MicroProfileSetEnableAllGroups(a) do{} while(0)
# define MicroProfileGetEnableAllGroups() false
# define MicroProfileSetForceMetaCounters(a)
# define MicroProfileGetForceMetaCounters() 0
# define MicroProfileDumpHtml(c) do{} while(0)
# define MicroProfileWebServerPort() ((uint32_t)-1)
2014-05-28 02:38:47 +00:00
# else
# include <stdint.h>
# include <string.h>
2015-01-02 18:37:58 +00:00
# include <thread>
# include <mutex>
# include <atomic>
# ifndef MICROPROFILE_API
# define MICROPROFILE_API
# endif
MICROPROFILE_API int64_t MicroProfileTicksPerSecondCpu ( ) ;
2014-05-28 02:38:47 +00:00
# if defined(__APPLE__)
# include <mach/mach.h>
# include <mach/mach_time.h>
# include <unistd.h>
# include <libkern/OSAtomic.h>
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# define MICROPROFILE_IOS
# endif
# define MP_TICK() mach_absolute_time()
inline int64_t MicroProfileTicksPerSecondCpu ( )
{
2015-01-02 18:37:58 +00:00
static int64_t nTicksPerSecond = 0 ;
if ( nTicksPerSecond = = 0 )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
mach_timebase_info_data_t sTimebaseInfo ;
2014-05-28 02:38:47 +00:00
mach_timebase_info ( & sTimebaseInfo ) ;
nTicksPerSecond = 1000000000ll * sTimebaseInfo . denom / sTimebaseInfo . numer ;
}
return nTicksPerSecond ;
}
# define MP_BREAK() __builtin_trap()
# define MP_THREAD_LOCAL __thread
# define MP_STRCASECMP strcasecmp
# define MP_GETCURRENTTHREADID() (uint64_t)pthread_self()
typedef uint64_t ThreadIdType ;
# elif defined(_WIN32)
int64_t MicroProfileGetTick ( ) ;
# define MP_TICK() MicroProfileGetTick()
# define MP_BREAK() __debugbreak()
# define MP_THREAD_LOCAL __declspec(thread)
# define MP_STRCASECMP _stricmp
# define MP_GETCURRENTTHREADID() GetCurrentThreadId()
typedef uint32_t ThreadIdType ;
# elif defined(__linux__)
# include <unistd.h>
# include <time.h>
inline int64_t MicroProfileTicksPerSecondCpu ( )
{
return 1000000000ll ;
}
inline int64_t MicroProfileGetTick ( )
{
timespec ts ;
clock_gettime ( CLOCK_REALTIME , & ts ) ;
return 1000000000ll * ts . tv_sec + ts . tv_nsec ;
}
# define MP_TICK() MicroProfileGetTick()
# define MP_BREAK() __builtin_trap()
# define MP_THREAD_LOCAL __thread
# define MP_STRCASECMP strcasecmp
# define MP_GETCURRENTTHREADID() (uint64_t)pthread_self()
typedef uint64_t ThreadIdType ;
# endif
2015-01-02 18:37:58 +00:00
# ifndef MP_GETCURRENTTHREADID
2014-05-28 02:38:47 +00:00
# define MP_GETCURRENTTHREADID() 0
typedef uint32_t ThreadIdType ;
# endif
# define MP_ASSERT(a) do{if(!(a)){MP_BREAK();} }while(0)
# define MICROPROFILE_DECLARE(var) extern MicroProfileToken g_mp_##var
# define MICROPROFILE_DEFINE(var, group, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu)
# define MICROPROFILE_DECLARE_GPU(var) extern MicroProfileToken g_mp_##var
# define MICROPROFILE_DEFINE_GPU(var, group, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeGpu)
# define MICROPROFILE_TOKEN_PASTE0(a, b) a ## b
# define MICROPROFILE_TOKEN_PASTE(a, b) MICROPROFILE_TOKEN_PASTE0(a,b)
# define MICROPROFILE_SCOPE(var) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var)
2015-01-02 18:37:58 +00:00
# define MICROPROFILE_SCOPE_TOKEN(token) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(token)
2014-05-28 02:38:47 +00:00
# define MICROPROFILE_SCOPEI(group, name, color) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__) = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu); MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo,__LINE__)( MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__))
# define MICROPROFILE_SCOPEGPU(var) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var)
# define MICROPROFILE_SCOPEGPUI(group, name, color) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__) = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeGpu); MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(foo,__LINE__)( MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__))
# define MICROPROFILE_META_CPU(name, count) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__) = MicroProfileGetMetaToken(name); MicroProfileMetaUpdate(MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__), count, MicroProfileTokenTypeCpu)
# define MICROPROFILE_META_GPU(name, count) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__) = MicroProfileGetMetaToken(name); MicroProfileMetaUpdate(MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__), count, MicroProfileTokenTypeGpu)
# ifndef MICROPROFILE_USE_THREAD_NAME_CALLBACK
# define MICROPROFILE_USE_THREAD_NAME_CALLBACK 0
# endif
# ifndef MICROPROFILE_GPU_FRAME_DELAY
# define MICROPROFILE_GPU_FRAME_DELAY 3 //must be > 0
# endif
# ifndef MICROPROFILE_PER_THREAD_BUFFER_SIZE
# define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<10)
# endif
2015-01-02 18:37:58 +00:00
# ifndef MICROPROFILE_MAX_FRAME_HISTORY
# define MICROPROFILE_MAX_FRAME_HISTORY 512
2014-05-28 02:38:47 +00:00
# endif
# ifndef MICROPROFILE_PRINTF
# define MICROPROFILE_PRINTF printf
# endif
# ifndef MICROPROFILE_META_MAX
# define MICROPROFILE_META_MAX 8
# endif
2015-01-02 18:37:58 +00:00
# ifndef MICROPROFILE_WEBSERVER_PORT
# define MICROPROFILE_WEBSERVER_PORT 1338
# endif
# ifndef MICROPROFILE_WEBSERVER
# define MICROPROFILE_WEBSERVER 1
# endif
# ifndef MICROPROFILE_WEBSERVER_MAXFRAMES
# define MICROPROFILE_WEBSERVER_MAXFRAMES 30
# endif
# ifndef MICROPROFILE_GPU_TIMERS
# define MICROPROFILE_GPU_TIMERS 1
# endif
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# ifndef MICROPROFILE_NAME_MAX_LEN
# define MICROPROFILE_NAME_MAX_LEN 64
# endif
2014-05-28 02:38:47 +00:00
# define MICROPROFILE_FORCEENABLECPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeCpu)
# define MICROPROFILE_FORCEDISABLECPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeCpu)
# define MICROPROFILE_FORCEENABLEGPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeGpu)
# define MICROPROFILE_FORCEDISABLEGPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeGpu)
# define MICROPROFILE_INVALID_TICK ((uint64_t)-1)
# define MICROPROFILE_GROUP_MASK_ALL 0xffffffffffff
# define MICROPROFILE_INVALID_TOKEN (uint64_t)-1
enum MicroProfileTokenType
{
MicroProfileTokenTypeCpu ,
MicroProfileTokenTypeGpu ,
} ;
2015-01-02 18:37:58 +00:00
2014-05-28 02:38:47 +00:00
enum MicroProfileBoxType
{
MicroProfileBoxTypeBar ,
MicroProfileBoxTypeFlat ,
} ;
2015-01-02 18:37:58 +00:00
// struct MicroProfileState
// {
// uint32_t nDisplay;
// uint32_t nAllGroupsWanted;
// uint64_t nActiveGroupWanted;
// uint32_t nAllThreadsWanted;
// uint32_t nAggregateFlip;
// uint32_t nBars;
// float fReferenceTime;
// };
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
struct MicroProfile ;
2014-05-28 02:38:47 +00:00
MICROPROFILE_API void MicroProfileInit ( ) ;
MICROPROFILE_API void MicroProfileShutdown ( ) ;
MICROPROFILE_API MicroProfileToken MicroProfileFindToken ( const char * sGroup , const char * sName ) ;
MICROPROFILE_API MicroProfileToken MicroProfileGetToken ( const char * sGroup , const char * sName , uint32_t nColor , MicroProfileTokenType Token = MicroProfileTokenTypeCpu ) ;
MICROPROFILE_API MicroProfileToken MicroProfileGetMetaToken ( const char * pName ) ;
MICROPROFILE_API void MicroProfileMetaUpdate ( MicroProfileToken , int nCount , MicroProfileTokenType eTokenType ) ;
MICROPROFILE_API uint64_t MicroProfileEnter ( MicroProfileToken nToken ) ;
MICROPROFILE_API void MicroProfileLeave ( MicroProfileToken nToken , uint64_t nTick ) ;
MICROPROFILE_API uint64_t MicroProfileGpuEnter ( MicroProfileToken nToken ) ;
MICROPROFILE_API void MicroProfileGpuLeave ( MicroProfileToken nToken , uint64_t nTick ) ;
inline uint16_t MicroProfileGetTimerIndex ( MicroProfileToken t ) { return ( t & 0xffff ) ; }
inline uint64_t MicroProfileGetGroupMask ( MicroProfileToken t ) { return ( ( t > > 16 ) & MICROPROFILE_GROUP_MASK_ALL ) ; }
inline MicroProfileToken MicroProfileMakeToken ( uint64_t nGroupMask , uint16_t nTimer ) { return ( nGroupMask < < 16 ) | nTimer ; }
MICROPROFILE_API void MicroProfileFlip ( ) ; //! called once per frame.
MICROPROFILE_API void MicroProfileTogglePause ( ) ;
2015-01-02 18:37:58 +00:00
// MICROPROFILE_API void MicroProfileGetState(MicroProfileState* pStateOut);
// MICROPROFILE_API void MicroProfileSetState(MicroProfileState* pStateIn);
2014-05-28 02:38:47 +00:00
MICROPROFILE_API void MicroProfileForceEnableGroup ( const char * pGroup , MicroProfileTokenType Type ) ;
MICROPROFILE_API void MicroProfileForceDisableGroup ( const char * pGroup , MicroProfileTokenType Type ) ;
MICROPROFILE_API float MicroProfileGetTime ( const char * pGroup , const char * pName ) ;
MICROPROFILE_API void MicroProfileOnThreadCreate ( const char * pThreadName ) ; //should be called from newly created threads
MICROPROFILE_API void MicroProfileOnThreadExit ( ) ; //call on exit to reuse log
MICROPROFILE_API void MicroProfileInitThreadLog ( ) ;
2015-01-02 18:37:58 +00:00
MICROPROFILE_API void MicroProfileSetForceEnable ( bool bForceEnable ) ;
MICROPROFILE_API bool MicroProfileGetForceEnable ( ) ;
MICROPROFILE_API void MicroProfileSetEnableAllGroups ( bool bEnable ) ;
MICROPROFILE_API bool MicroProfileGetEnableAllGroups ( ) ;
MICROPROFILE_API void MicroProfileSetForceMetaCounters ( bool bEnable ) ;
MICROPROFILE_API bool MicroProfileGetForceMetaCounters ( ) ;
MICROPROFILE_API void MicroProfileSetAggregateFrames ( int frames ) ;
MICROPROFILE_API int MicroProfileGetAggregateFrames ( ) ;
MICROPROFILE_API int MicroProfileGetCurrentAggregateFrames ( ) ;
MICROPROFILE_API MicroProfile * MicroProfileGet ( ) ;
MICROPROFILE_API void MicroProfileGetRange ( uint32_t nPut , uint32_t nGet , uint32_t nRange [ 2 ] [ 2 ] ) ;
MICROPROFILE_API std : : recursive_mutex & MicroProfileGetMutex ( ) ;
MICROPROFILE_API void MicroProfileStartContextSwitchTrace ( ) ;
MICROPROFILE_API void MicroProfileStopContextSwitchTrace ( ) ;
MICROPROFILE_API bool MicroProfileIsLocalThread ( uint32_t nThreadId ) ;
# if MICROPROFILE_WEBSERVER
MICROPROFILE_API void MicroProfileDumpHtml ( const char * pFile ) ;
MICROPROFILE_API uint32_t MicroProfileWebServerPort ( ) ;
# else
# define MicroProfileDumpHtml(c) do{} while(0)
# define MicroProfileWebServerPort() ((uint32_t)-1)
# endif
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# if MICROPROFILE_GPU_TIMERS
2014-05-28 02:38:47 +00:00
MICROPROFILE_API uint32_t MicroProfileGpuInsertTimeStamp ( ) ;
MICROPROFILE_API uint64_t MicroProfileGpuGetTimeStamp ( uint32_t nKey ) ;
MICROPROFILE_API uint64_t MicroProfileTicksPerSecondGpu ( ) ;
2015-01-02 18:37:58 +00:00
# else
# define MicroProfileGpuInsertTimeStamp() 1
# define MicroProfileGpuGetTimeStamp(a) 0
# define MicroProfileTicksPerSecondGpu() 1
# endif
2014-05-28 02:38:47 +00:00
# if MICROPROFILE_USE_THREAD_NAME_CALLBACK
MICROPROFILE_API const char * MicroProfileGetThreadName ( ) ;
# else
# define MicroProfileGetThreadName() "<implement MicroProfileGetThreadName to get threadnames>"
# endif
struct MicroProfileScopeHandler
{
MicroProfileToken nToken ;
uint64_t nTick ;
MicroProfileScopeHandler ( MicroProfileToken Token ) : nToken ( Token )
{
nTick = MicroProfileEnter ( nToken ) ;
}
~ MicroProfileScopeHandler ( )
{
MicroProfileLeave ( nToken , nTick ) ;
}
} ;
struct MicroProfileScopeGpuHandler
{
MicroProfileToken nToken ;
uint64_t nTick ;
MicroProfileScopeGpuHandler ( MicroProfileToken Token ) : nToken ( Token )
{
nTick = MicroProfileGpuEnter ( nToken ) ;
}
~ MicroProfileScopeGpuHandler ( )
{
MicroProfileGpuLeave ( nToken , nTick ) ;
}
} ;
# define MICROPROFILE_MAX_TIMERS 1024
# define MICROPROFILE_MAX_GROUPS 48 //dont bump! no. of bits used it bitmask
# define MICROPROFILE_MAX_GRAPHS 5
# define MICROPROFILE_GRAPH_HISTORY 128
# define MICROPROFILE_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_BUFFER_SIZE) / sizeof(MicroProfileLogEntry))
# define MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS 256
2015-01-02 18:37:58 +00:00
# define MICROPROFILE_STACK_MAX 32
//#define MICROPROFILE_MAX_PRESETS 5
2014-05-28 02:38:47 +00:00
# define MICROPROFILE_ANIM_DELAY_PRC 0.5f
# define MICROPROFILE_GAP_TIME 50 //extra ms to fetch to close timers from earlier frames
2015-01-02 18:37:58 +00:00
# ifndef MICROPROFILE_MAX_THREADS
2015-03-26 02:17:06 +00:00
# define MICROPROFILE_MAX_THREADS 64
2015-01-02 18:37:58 +00:00
# endif
# ifndef MICROPROFILE_UNPACK_RED
# define MICROPROFILE_UNPACK_RED(c) ((c)>>16)
# endif
# ifndef MICROPROFILE_UNPACK_GREEN
# define MICROPROFILE_UNPACK_GREEN(c) ((c)>>8)
# endif
# ifndef MICROPROFILE_UNPACK_BLUE
# define MICROPROFILE_UNPACK_BLUE(c) ((c))
# endif
# ifndef MICROPROFILE_DEFAULT_PRESET
# define MICROPROFILE_DEFAULT_PRESET "Default"
# endif
# ifndef MICROPROFILE_CONTEXT_SWITCH_TRACE
2014-05-28 02:38:47 +00:00
# ifdef _WIN32
# define MICROPROFILE_CONTEXT_SWITCH_TRACE 1
# else
# define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
# endif
# endif
# if MICROPROFILE_CONTEXT_SWITCH_TRACE
# define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (128*1024) //2mb with 16 byte entry size
# else
# define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (1)
# endif
2015-01-02 18:37:58 +00:00
# ifdef _WIN32
# include <basetsd.h>
typedef UINT_PTR MpSocket ;
# else
typedef int MpSocket ;
# endif
2014-05-28 02:38:47 +00:00
enum MicroProfileDrawMask
{
MP_DRAW_OFF = 0x0 ,
MP_DRAW_BARS = 0x1 ,
MP_DRAW_DETAILED = 0x2 ,
MP_DRAW_HIDDEN = 0x3 ,
} ;
enum MicroProfileDrawBarsMask
{
2015-01-02 18:37:58 +00:00
MP_DRAW_TIMERS = 0x1 ,
MP_DRAW_AVERAGE = 0x2 ,
MP_DRAW_MAX = 0x4 ,
2014-05-28 02:38:47 +00:00
MP_DRAW_CALL_COUNT = 0x8 ,
MP_DRAW_TIMERS_EXCLUSIVE = 0x10 ,
2015-01-02 18:37:58 +00:00
MP_DRAW_AVERAGE_EXCLUSIVE = 0x20 ,
2014-05-28 02:38:47 +00:00
MP_DRAW_MAX_EXCLUSIVE = 0x40 ,
MP_DRAW_META_FIRST = 0x80 ,
MP_DRAW_ALL = 0xffffffff ,
} ;
2015-01-02 18:37:58 +00:00
typedef uint64_t MicroProfileLogEntry ;
2014-05-28 02:38:47 +00:00
struct MicroProfileTimer
{
uint64_t nTicks ;
uint32_t nCount ;
} ;
struct MicroProfileGroupInfo
{
2015-01-02 18:37:58 +00:00
char pName [ MICROPROFILE_NAME_MAX_LEN ] ;
2014-05-28 02:38:47 +00:00
uint32_t nNameLen ;
uint32_t nGroupIndex ;
uint32_t nNumTimers ;
uint32_t nMaxTimerNameLen ;
MicroProfileTokenType Type ;
} ;
struct MicroProfileTimerInfo
{
MicroProfileToken nToken ;
uint32_t nTimerIndex ;
uint32_t nGroupIndex ;
2015-01-02 18:37:58 +00:00
char pName [ MICROPROFILE_NAME_MAX_LEN ] ;
2014-05-28 02:38:47 +00:00
uint32_t nNameLen ;
uint32_t nColor ;
2015-01-02 18:37:58 +00:00
bool bGraph ;
2014-05-28 02:38:47 +00:00
} ;
struct MicroProfileGraphState
{
int64_t nHistory [ MICROPROFILE_GRAPH_HISTORY ] ;
MicroProfileToken nToken ;
int32_t nKey ;
} ;
struct MicroProfileContextSwitch
{
ThreadIdType nThreadOut ;
ThreadIdType nThreadIn ;
int64_t nCpu : 8 ;
int64_t nTicks : 56 ;
} ;
struct MicroProfileFrameState
{
int64_t nFrameStartCpu ;
int64_t nFrameStartGpu ;
2015-01-02 18:37:58 +00:00
uint32_t nLogStart [ MICROPROFILE_MAX_THREADS ] ;
2014-05-28 02:38:47 +00:00
} ;
struct MicroProfileThreadLog
{
MicroProfileLogEntry Log [ MICROPROFILE_BUFFER_SIZE ] ;
std : : atomic < uint32_t > nPut ;
std : : atomic < uint32_t > nGet ;
uint32_t nActive ;
uint32_t nGpu ;
ThreadIdType nThreadId ;
2015-01-02 18:37:58 +00:00
uint32_t nStack [ MICROPROFILE_STACK_MAX ] ;
int64_t nChildTickStack [ MICROPROFILE_STACK_MAX ] ;
uint32_t nStackPos ;
2014-05-28 02:38:47 +00:00
enum
{
THREAD_MAX_LEN = 64 ,
} ;
char ThreadName [ 64 ] ;
int nFreeListNext ;
} ;
2015-01-02 18:37:58 +00:00
struct MicroProfile
2014-05-28 02:38:47 +00:00
{
uint32_t nTotalTimers ;
uint32_t nGroupCount ;
2015-01-02 18:37:58 +00:00
uint32_t nAggregateClear ;
2014-05-28 02:38:47 +00:00
uint32_t nAggregateFlip ;
uint32_t nAggregateFlipCount ;
uint32_t nAggregateFrames ;
2015-01-02 18:37:58 +00:00
uint64_t nAggregateFlipTick ;
2014-05-28 02:38:47 +00:00
uint32_t nDisplay ;
uint32_t nBars ;
uint64_t nActiveGroup ;
uint32_t nActiveBars ;
uint64_t nForceGroup ;
2015-01-02 18:37:58 +00:00
uint32_t nForceEnable ;
uint32_t nForceMetaCounters ;
uint64_t nActiveGroupWanted ;
uint32_t nAllGroupsWanted ;
uint32_t nAllThreadsWanted ;
2014-05-28 02:38:47 +00:00
uint32_t nOverflow ;
uint64_t nGroupMask ;
uint32_t nRunning ;
2015-01-02 18:37:58 +00:00
uint32_t nToggleRunning ;
2014-05-28 02:38:47 +00:00
uint32_t nMaxGroupSize ;
2015-01-02 18:37:58 +00:00
uint32_t nDumpHtmlNextFrame ;
char HtmlDumpPath [ 512 ] ;
int64_t nPauseTicks ;
2014-05-28 02:38:47 +00:00
float fReferenceTime ;
float fRcpReferenceTime ;
MicroProfileGroupInfo GroupInfo [ MICROPROFILE_MAX_GROUPS ] ;
MicroProfileTimerInfo TimerInfo [ MICROPROFILE_MAX_TIMERS ] ;
2015-01-02 18:37:58 +00:00
2014-05-28 02:38:47 +00:00
MicroProfileTimer AggregateTimers [ MICROPROFILE_MAX_TIMERS ] ;
uint64_t MaxTimers [ MICROPROFILE_MAX_TIMERS ] ;
uint64_t AggregateTimersExclusive [ MICROPROFILE_MAX_TIMERS ] ;
uint64_t MaxTimersExclusive [ MICROPROFILE_MAX_TIMERS ] ;
MicroProfileTimer Frame [ MICROPROFILE_MAX_TIMERS ] ;
uint64_t FrameExclusive [ MICROPROFILE_MAX_TIMERS ] ;
MicroProfileTimer Aggregate [ MICROPROFILE_MAX_TIMERS ] ;
2015-01-02 18:37:58 +00:00
uint64_t AggregateMax [ MICROPROFILE_MAX_TIMERS ] ;
2014-05-28 02:38:47 +00:00
uint64_t AggregateExclusive [ MICROPROFILE_MAX_TIMERS ] ;
uint64_t AggregateMaxExclusive [ MICROPROFILE_MAX_TIMERS ] ;
2015-01-02 18:37:58 +00:00
struct
2014-05-28 02:38:47 +00:00
{
uint64_t nCounters [ MICROPROFILE_MAX_TIMERS ] ;
const char * pName ;
} MetaCounters [ MICROPROFILE_META_MAX ] ;
MicroProfileGraphState Graph [ MICROPROFILE_MAX_GRAPHS ] ;
uint32_t nGraphPut ;
uint32_t nThreadActive [ MICROPROFILE_MAX_THREADS ] ;
MicroProfileThreadLog * Pool [ MICROPROFILE_MAX_THREADS ] ;
uint32_t nNumLogs ;
uint32_t nMemUsage ;
int nFreeListHead ;
uint32_t nFrameCurrent ;
2015-01-02 18:37:58 +00:00
uint32_t nFrameCurrentIndex ;
2014-05-28 02:38:47 +00:00
uint32_t nFramePut ;
2015-01-02 18:37:58 +00:00
uint64_t nFramePutIndex ;
2014-05-28 02:38:47 +00:00
MicroProfileFrameState Frames [ MICROPROFILE_MAX_FRAME_HISTORY ] ;
uint64_t nFlipTicks ;
uint64_t nFlipAggregate ;
uint64_t nFlipMax ;
uint64_t nFlipAggregateDisplay ;
uint64_t nFlipMaxDisplay ;
std : : thread * pContextSwitchThread ;
bool bContextSwitchRunning ;
bool bContextSwitchStop ;
bool bContextSwitchAllThreads ;
bool bContextSwitchNoBars ;
uint32_t nContextSwitchUsage ;
uint32_t nContextSwitchLastPut ;
int64_t nContextSwitchHoverTickIn ;
int64_t nContextSwitchHoverTickOut ;
uint32_t nContextSwitchHoverThread ;
uint32_t nContextSwitchHoverThreadBefore ;
uint32_t nContextSwitchHoverThreadAfter ;
uint8_t nContextSwitchHoverCpu ;
uint8_t nContextSwitchHoverCpuNext ;
2015-01-02 18:37:58 +00:00
uint32_t nContextSwitchPut ;
2014-05-28 02:38:47 +00:00
MicroProfileContextSwitch ContextSwitch [ MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE ] ;
2015-01-02 18:37:58 +00:00
MpSocket ListenerSocket ;
uint32_t nWebServerPort ;
} ;
# define MP_LOG_TICK_MASK 0x0000ffffffffffff
# define MP_LOG_INDEX_MASK 0x3fff000000000000
# define MP_LOG_BEGIN_MASK 0xc000000000000000
# define MP_LOG_META 0x2
# define MP_LOG_ENTER 0x1
# define MP_LOG_LEAVE 0x0
inline int MicroProfileLogType ( MicroProfileLogEntry Index )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return ( ( MP_LOG_BEGIN_MASK & Index ) > > 62 ) & 0x3 ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
inline uint64_t MicroProfileLogTimerIndex ( MicroProfileLogEntry Index )
{
return ( 0x3fff & ( Index > > 48 ) ) ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
inline MicroProfileLogEntry MicroProfileMakeLogIndex ( uint64_t nBegin , MicroProfileToken nToken , int64_t nTick )
{
MicroProfileLogEntry Entry = ( nBegin < < 62 ) | ( ( 0x3fff & nToken ) < < 48 ) | ( MP_LOG_TICK_MASK & nTick ) ;
int t = MicroProfileLogType ( Entry ) ;
uint64_t nTimerIndex = MicroProfileLogTimerIndex ( Entry ) ;
MP_ASSERT ( t = = nBegin ) ;
MP_ASSERT ( nTimerIndex = = ( nToken & 0x3fff ) ) ;
return Entry ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
inline int64_t MicroProfileLogTickDifference ( MicroProfileLogEntry Start , MicroProfileLogEntry End )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint64_t nStart = Start ;
uint64_t nEnd = End ;
int64_t nDifference = ( ( nEnd < < 16 ) - ( nStart < < 16 ) ) ;
return nDifference > > 16 ;
}
inline int64_t MicroProfileLogGetTick ( MicroProfileLogEntry e )
{
return MP_LOG_TICK_MASK & e ;
}
inline int64_t MicroProfileLogSetTick ( MicroProfileLogEntry e , int64_t nTick )
{
return ( MP_LOG_TICK_MASK & nTick ) | ( e & ~ MP_LOG_TICK_MASK ) ;
2014-05-28 02:38:47 +00:00
}
template < typename T >
T MicroProfileMin ( T a , T b )
{ return a < b ? a : b ; }
template < typename T >
T MicroProfileMax ( T a , T b )
{ return a > b ? a : b ; }
2015-01-02 18:37:58 +00:00
inline int64_t MicroProfileMsToTick ( float fMs , int64_t nTicksPerSecond )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return ( int64_t ) ( fMs * 0.001f * nTicksPerSecond ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
inline float MicroProfileTickToMsMultiplier ( int64_t nTicksPerSecond )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return 1000.f / nTicksPerSecond ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
inline uint16_t MicroProfileGetGroupIndex ( MicroProfileToken t )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return ( uint16_t ) MicroProfileGet ( ) - > TimerInfo [ MicroProfileGetTimerIndex ( t ) ] . nGroupIndex ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# ifdef MICROPROFILE_IMPL
# ifdef _WIN32
# include <windows.h>
# define snprintf _snprintf
# pragma warning(push)
# pragma warning(disable: 4244)
int64_t MicroProfileTicksPerSecondCpu ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
static int64_t nTicksPerSecond = 0 ;
if ( nTicksPerSecond = = 0 )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & nTicksPerSecond ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
return nTicksPerSecond ;
}
int64_t MicroProfileGetTick ( )
{
int64_t ticks ;
QueryPerformanceCounter ( ( LARGE_INTEGER * ) & ticks ) ;
return ticks ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# endif
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# if MICROPROFILE_WEBSERVER
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# ifdef _WIN32
# define MP_INVALID_SOCKET(f) (f == INVALID_SOCKET)
# endif
# if defined(__APPLE__)
# include <sys/socket.h>
# include <netinet/in.h>
# include <fcntl.h>
# define MP_INVALID_SOCKET(f) (f < 0)
# endif
void MicroProfileWebServerStart ( ) ;
void MicroProfileWebServerStop ( ) ;
bool MicroProfileWebServerUpdate ( ) ;
void MicroProfileDumpHtmlToFile ( ) ;
# else
# define MicroProfileWebServerStart() do{}while(0)
# define MicroProfileWebServerStop() do{}while(0)
# define MicroProfileWebServerUpdate() false
# define MicroProfileDumpHtmlToFile() do{} while(0)
# endif
# include <stdlib.h>
# include <stdio.h>
# include <math.h>
# include <algorithm>
# ifndef MICROPROFILE_DEBUG
# define MICROPROFILE_DEBUG 0
# endif
# define S g_MicroProfile
MicroProfile g_MicroProfile ;
MicroProfileThreadLog * g_MicroProfileGpuLog = 0 ;
# ifdef MICROPROFILE_IOS
// iOS doesn't support __thread
static pthread_key_t g_MicroProfileThreadLogKey ;
static pthread_once_t g_MicroProfileThreadLogKeyOnce = PTHREAD_ONCE_INIT ;
static void MicroProfileCreateThreadLogKey ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
pthread_key_create ( & g_MicroProfileThreadLogKey , NULL ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# else
MP_THREAD_LOCAL MicroProfileThreadLog * g_MicroProfileThreadLog = 0 ;
# endif
static bool g_bUseLock = false ; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MICROPROFILE_DEFINE ( g_MicroProfileFlip , " MicroProfile " , " MicroProfileFlip " , 0x3355ee ) ;
MICROPROFILE_DEFINE ( g_MicroProfileThreadLoop , " MicroProfile " , " ThreadLoop " , 0x3355ee ) ;
MICROPROFILE_DEFINE ( g_MicroProfileClear , " MicroProfile " , " Clear " , 0x3355ee ) ;
MICROPROFILE_DEFINE ( g_MicroProfileAccumulate , " MicroProfile " , " Accumulate " , 0x3355ee ) ;
inline std : : recursive_mutex & MicroProfileMutex ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
static std : : recursive_mutex Mutex ;
return Mutex ;
}
std : : recursive_mutex & MicroProfileGetMutex ( )
{
return MicroProfileMutex ( ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
MICROPROFILE_API MicroProfile * MicroProfileGet ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return & g_MicroProfile ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
MicroProfileThreadLog * MicroProfileCreateThreadLog ( const char * pName ) ;
2014-05-28 02:38:47 +00:00
void MicroProfileInit ( )
{
std : : recursive_mutex & mutex = MicroProfileMutex ( ) ;
bool bUseLock = g_bUseLock ;
if ( bUseLock )
mutex . lock ( ) ;
static bool bOnce = true ;
if ( bOnce )
{
S . nMemUsage + = sizeof ( S ) ;
bOnce = false ;
memset ( & S , 0 , sizeof ( S ) ) ;
2015-01-02 18:37:58 +00:00
for ( int i = 0 ; i < MICROPROFILE_MAX_GROUPS ; + + i )
{
S . GroupInfo [ i ] . pName [ 0 ] = ' \0 ' ;
}
for ( int i = 0 ; i < MICROPROFILE_MAX_TIMERS ; + + i )
{
S . TimerInfo [ i ] . pName [ 0 ] = ' \0 ' ;
}
2014-05-28 02:38:47 +00:00
S . nGroupCount = 0 ;
2015-01-02 18:37:58 +00:00
S . nAggregateFlipTick = MP_TICK ( ) ;
2014-05-28 02:38:47 +00:00
S . nActiveGroup = 0 ;
S . nActiveBars = 0 ;
S . nForceGroup = 0 ;
2015-01-02 18:37:58 +00:00
S . nAllGroupsWanted = 0 ;
S . nActiveGroupWanted = 0 ;
S . nAllThreadsWanted = 1 ;
S . nAggregateFlip = 0 ;
2014-05-28 02:38:47 +00:00
S . nTotalTimers = 0 ;
for ( uint32_t i = 0 ; i < MICROPROFILE_MAX_GRAPHS ; + + i )
{
S . Graph [ i ] . nToken = MICROPROFILE_INVALID_TOKEN ;
}
S . nRunning = 1 ;
S . fReferenceTime = 33.33f ;
S . fRcpReferenceTime = 1.f / S . fReferenceTime ;
S . nFreeListHead = - 1 ;
int64_t nTick = MP_TICK ( ) ;
for ( int i = 0 ; i < MICROPROFILE_MAX_FRAME_HISTORY ; + + i )
{
S . Frames [ i ] . nFrameStartCpu = nTick ;
S . Frames [ i ] . nFrameStartGpu = - 1 ;
}
MicroProfileThreadLog * pGpu = MicroProfileCreateThreadLog ( " GPU " ) ;
g_MicroProfileGpuLog = pGpu ;
MP_ASSERT ( S . Pool [ 0 ] = = pGpu ) ;
pGpu - > nGpu = 1 ;
pGpu - > nThreadId = 0 ;
2015-01-02 18:37:58 +00:00
MicroProfileWebServerStart ( ) ;
2014-05-28 02:38:47 +00:00
}
if ( bUseLock )
mutex . unlock ( ) ;
}
void MicroProfileShutdown ( )
{
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
2015-01-02 18:37:58 +00:00
MicroProfileWebServerStop ( ) ;
# if MICROPROFILE_CONTEXT_SWITCH_TRACE
2014-05-28 02:38:47 +00:00
if ( S . pContextSwitchThread )
{
if ( S . pContextSwitchThread - > joinable ( ) )
{
S . bContextSwitchStop = true ;
S . pContextSwitchThread - > join ( ) ;
}
delete S . pContextSwitchThread ;
}
# endif
}
# ifdef MICROPROFILE_IOS
inline MicroProfileThreadLog * MicroProfileGetThreadLog ( )
{
pthread_once ( & g_MicroProfileThreadLogKeyOnce , MicroProfileCreateThreadLogKey ) ;
return ( MicroProfileThreadLog * ) pthread_getspecific ( g_MicroProfileThreadLogKey ) ;
}
inline void MicroProfileSetThreadLog ( MicroProfileThreadLog * pLog )
{
pthread_once ( & g_MicroProfileThreadLogKeyOnce , MicroProfileCreateThreadLogKey ) ;
pthread_setspecific ( g_MicroProfileThreadLogKey , pLog ) ;
}
# else
MicroProfileThreadLog * MicroProfileGetThreadLog ( )
{
return g_MicroProfileThreadLog ;
}
inline void MicroProfileSetThreadLog ( MicroProfileThreadLog * pLog )
{
g_MicroProfileThreadLog = pLog ;
}
# endif
MicroProfileThreadLog * MicroProfileCreateThreadLog ( const char * pName )
{
MicroProfileThreadLog * pLog = 0 ;
if ( S . nFreeListHead ! = - 1 )
{
pLog = S . Pool [ S . nFreeListHead ] ;
2015-01-02 18:37:58 +00:00
MP_ASSERT ( pLog - > nPut . load ( ) = = 0 ) ;
MP_ASSERT ( pLog - > nGet . load ( ) = = 0 ) ;
2014-05-28 02:38:47 +00:00
S . nFreeListHead = S . Pool [ S . nFreeListHead ] - > nFreeListNext ;
}
else
{
pLog = new MicroProfileThreadLog ;
S . nMemUsage + = sizeof ( MicroProfileThreadLog ) ;
2015-01-02 18:37:58 +00:00
S . Pool [ S . nNumLogs + + ] = pLog ;
2014-05-28 02:38:47 +00:00
}
memset ( pLog , 0 , sizeof ( * pLog ) ) ;
int len = ( int ) strlen ( pName ) ;
int maxlen = sizeof ( pLog - > ThreadName ) - 1 ;
len = len < maxlen ? len : maxlen ;
memcpy ( & pLog - > ThreadName [ 0 ] , pName , len ) ;
pLog - > ThreadName [ len ] = ' \0 ' ;
pLog - > nThreadId = MP_GETCURRENTTHREADID ( ) ;
pLog - > nFreeListNext = - 1 ;
2015-01-02 18:37:58 +00:00
pLog - > nActive = 1 ;
2014-05-28 02:38:47 +00:00
return pLog ;
}
void MicroProfileOnThreadCreate ( const char * pThreadName )
{
g_bUseLock = true ;
MicroProfileInit ( ) ;
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
MP_ASSERT ( MicroProfileGetThreadLog ( ) = = 0 ) ;
MicroProfileThreadLog * pLog = MicroProfileCreateThreadLog ( pThreadName ? pThreadName : MicroProfileGetThreadName ( ) ) ;
MP_ASSERT ( pLog ) ;
MicroProfileSetThreadLog ( pLog ) ;
}
void MicroProfileOnThreadExit ( )
{
2015-01-02 18:37:58 +00:00
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
2014-05-28 02:38:47 +00:00
MicroProfileThreadLog * pLog = MicroProfileGetThreadLog ( ) ;
if ( pLog )
{
int32_t nLogIndex = - 1 ;
for ( int i = 0 ; i < MICROPROFILE_MAX_THREADS ; + + i )
{
if ( pLog = = S . Pool [ i ] )
{
nLogIndex = i ;
break ;
}
}
MP_ASSERT ( nLogIndex < MICROPROFILE_MAX_THREADS & & nLogIndex > 0 ) ;
pLog - > nFreeListNext = S . nFreeListHead ;
2015-01-02 18:37:58 +00:00
pLog - > nActive = 0 ;
pLog - > nPut . store ( 0 ) ;
pLog - > nGet . store ( 0 ) ;
2014-05-28 02:38:47 +00:00
S . nFreeListHead = nLogIndex ;
2015-01-02 18:37:58 +00:00
for ( int i = 0 ; i < MICROPROFILE_MAX_FRAME_HISTORY ; + + i )
{
S . Frames [ i ] . nLogStart [ nLogIndex ] = 0 ;
}
2014-05-28 02:38:47 +00:00
}
}
void MicroProfileInitThreadLog ( )
{
MicroProfileOnThreadCreate ( nullptr ) ;
}
struct MicroProfileScopeLock
{
bool bUseLock ;
std : : recursive_mutex & m ;
MicroProfileScopeLock ( std : : recursive_mutex & m ) : bUseLock ( g_bUseLock ) , m ( m )
{
if ( bUseLock )
m . lock ( ) ;
}
~ MicroProfileScopeLock ( )
{
if ( bUseLock )
m . unlock ( ) ;
}
} ;
MicroProfileToken MicroProfileFindToken ( const char * pGroup , const char * pName )
{
MicroProfileInit ( ) ;
MicroProfileScopeLock L ( MicroProfileMutex ( ) ) ;
for ( uint32_t i = 0 ; i < S . nTotalTimers ; + + i )
{
if ( ! MP_STRCASECMP ( pName , S . TimerInfo [ i ] . pName ) & & ! MP_STRCASECMP ( pGroup , S . GroupInfo [ S . TimerInfo [ i ] . nGroupIndex ] . pName ) )
{
return S . TimerInfo [ i ] . nToken ;
}
}
return MICROPROFILE_INVALID_TOKEN ;
}
uint16_t MicroProfileGetGroup ( const char * pGroup , MicroProfileTokenType Type )
{
for ( uint32_t i = 0 ; i < S . nGroupCount ; + + i )
{
if ( ! MP_STRCASECMP ( pGroup , S . GroupInfo [ i ] . pName ) )
{
return i ;
}
}
uint16_t nGroupIndex = 0xffff ;
2015-01-02 18:37:58 +00:00
uint32_t nLen = ( uint32_t ) strlen ( pGroup ) ;
if ( nLen > MICROPROFILE_NAME_MAX_LEN - 1 )
nLen = MICROPROFILE_NAME_MAX_LEN - 1 ;
memcpy ( & S . GroupInfo [ S . nGroupCount ] . pName [ 0 ] , pGroup , nLen ) ;
S . GroupInfo [ S . nGroupCount ] . pName [ nLen ] = ' \0 ' ;
S . GroupInfo [ S . nGroupCount ] . nNameLen = nLen ;
2014-05-28 02:38:47 +00:00
S . GroupInfo [ S . nGroupCount ] . nGroupIndex = S . nGroupCount ;
S . GroupInfo [ S . nGroupCount ] . nNumTimers = 0 ;
S . GroupInfo [ S . nGroupCount ] . Type = Type ;
S . GroupInfo [ S . nGroupCount ] . nMaxTimerNameLen = 0 ;
nGroupIndex = S . nGroupCount + + ;
S . nGroupMask = ( S . nGroupMask < < 1 ) | 1 ;
MP_ASSERT ( nGroupIndex < MICROPROFILE_MAX_GROUPS ) ;
return nGroupIndex ;
}
MicroProfileToken MicroProfileGetToken ( const char * pGroup , const char * pName , uint32_t nColor , MicroProfileTokenType Type )
{
MicroProfileInit ( ) ;
MicroProfileScopeLock L ( MicroProfileMutex ( ) ) ;
MicroProfileToken ret = MicroProfileFindToken ( pGroup , pName ) ;
if ( ret ! = MICROPROFILE_INVALID_TOKEN )
return ret ;
uint16_t nGroupIndex = MicroProfileGetGroup ( pGroup , Type ) ;
uint16_t nTimerIndex = ( uint16_t ) ( S . nTotalTimers + + ) ;
uint64_t nGroupMask = 1ll < < nGroupIndex ;
MicroProfileToken nToken = MicroProfileMakeToken ( nGroupMask , nTimerIndex ) ;
S . GroupInfo [ nGroupIndex ] . nNumTimers + + ;
S . GroupInfo [ nGroupIndex ] . nMaxTimerNameLen = MicroProfileMax ( S . GroupInfo [ nGroupIndex ] . nMaxTimerNameLen , ( uint32_t ) strlen ( pName ) ) ;
MP_ASSERT ( S . GroupInfo [ nGroupIndex ] . Type = = Type ) ; //dont mix cpu & gpu timers in the same group
S . nMaxGroupSize = MicroProfileMax ( S . nMaxGroupSize , S . GroupInfo [ nGroupIndex ] . nNumTimers ) ;
S . TimerInfo [ nTimerIndex ] . nToken = nToken ;
2015-01-02 18:37:58 +00:00
uint32_t nLen = ( uint32_t ) strlen ( pName ) ;
if ( nLen > MICROPROFILE_NAME_MAX_LEN - 1 )
nLen = MICROPROFILE_NAME_MAX_LEN - 1 ;
memcpy ( & S . TimerInfo [ nTimerIndex ] . pName , pName , nLen ) ;
S . TimerInfo [ nTimerIndex ] . pName [ nLen ] = ' \0 ' ;
S . TimerInfo [ nTimerIndex ] . nNameLen = nLen ;
2014-05-28 02:38:47 +00:00
S . TimerInfo [ nTimerIndex ] . nColor = nColor & 0xffffff ;
S . TimerInfo [ nTimerIndex ] . nGroupIndex = nGroupIndex ;
2015-01-02 18:37:58 +00:00
S . TimerInfo [ nTimerIndex ] . nTimerIndex = nTimerIndex ;
2014-05-28 02:38:47 +00:00
return nToken ;
}
MicroProfileToken MicroProfileGetMetaToken ( const char * pName )
{
MicroProfileInit ( ) ;
MicroProfileScopeLock L ( MicroProfileMutex ( ) ) ;
for ( uint32_t i = 0 ; i < MICROPROFILE_META_MAX ; + + i )
{
if ( ! S . MetaCounters [ i ] . pName )
{
S . MetaCounters [ i ] . pName = pName ;
return i ;
}
else if ( ! MP_STRCASECMP ( pName , S . MetaCounters [ i ] . pName ) )
{
return i ;
}
}
MP_ASSERT ( 0 ) ; //out of slots, increase MICROPROFILE_META_MAX
return ( MicroProfileToken ) - 1 ;
}
inline void MicroProfileLogPut ( MicroProfileToken nToken_ , uint64_t nTick , uint64_t nBegin , MicroProfileThreadLog * pLog )
{
MP_ASSERT ( pLog ! = 0 ) ; //this assert is hit if MicroProfileOnCreateThread is not called
2015-01-02 18:37:58 +00:00
MP_ASSERT ( pLog - > nActive ) ;
2014-05-28 02:38:47 +00:00
uint32_t nPos = pLog - > nPut . load ( std : : memory_order_relaxed ) ;
uint32_t nNextPos = ( nPos + 1 ) % MICROPROFILE_BUFFER_SIZE ;
if ( nNextPos = = pLog - > nGet . load ( std : : memory_order_relaxed ) )
{
S . nOverflow = 100 ;
}
else
{
int64_t test = MicroProfileMakeLogIndex ( nBegin , nToken_ , nTick ) ; ;
MP_ASSERT ( MicroProfileLogType ( test ) = = nBegin ) ;
MP_ASSERT ( MicroProfileLogTimerIndex ( test ) = = MicroProfileGetTimerIndex ( nToken_ ) ) ;
pLog - > Log [ nPos ] = MicroProfileMakeLogIndex ( nBegin , nToken_ , nTick ) ;
pLog - > nPut . store ( nNextPos , std : : memory_order_release ) ;
}
}
uint64_t MicroProfileEnter ( MicroProfileToken nToken_ )
{
if ( MicroProfileGetGroupMask ( nToken_ ) & S . nActiveGroup )
{
if ( ! MicroProfileGetThreadLog ( ) )
{
MicroProfileInitThreadLog ( ) ;
}
uint64_t nTick = MP_TICK ( ) ;
MicroProfileLogPut ( nToken_ , nTick , MP_LOG_ENTER , MicroProfileGetThreadLog ( ) ) ;
return nTick ;
}
return MICROPROFILE_INVALID_TICK ;
}
void MicroProfileMetaUpdate ( MicroProfileToken nToken , int nCount , MicroProfileTokenType eTokenType )
{
if ( ( MP_DRAW_META_FIRST < < nToken ) & S . nActiveBars )
{
2015-01-02 18:37:58 +00:00
MicroProfileThreadLog * pLog = MicroProfileTokenTypeCpu = = eTokenType ? MicroProfileGetThreadLog ( ) : g_MicroProfileGpuLog ;
2014-05-28 02:38:47 +00:00
if ( pLog )
{
MP_ASSERT ( nToken < MICROPROFILE_META_MAX ) ;
MicroProfileLogPut ( nToken , nCount , MP_LOG_META , pLog ) ;
}
}
}
void MicroProfileLeave ( MicroProfileToken nToken_ , uint64_t nTickStart )
{
if ( MICROPROFILE_INVALID_TICK ! = nTickStart )
{
if ( ! MicroProfileGetThreadLog ( ) )
{
MicroProfileInitThreadLog ( ) ;
}
uint64_t nTick = MP_TICK ( ) ;
MicroProfileThreadLog * pLog = MicroProfileGetThreadLog ( ) ;
MicroProfileLogPut ( nToken_ , nTick , MP_LOG_LEAVE , pLog ) ;
}
}
uint64_t MicroProfileGpuEnter ( MicroProfileToken nToken_ )
{
if ( MicroProfileGetGroupMask ( nToken_ ) & S . nActiveGroup )
{
uint64_t nTimer = MicroProfileGpuInsertTimeStamp ( ) ;
MicroProfileLogPut ( nToken_ , nTimer , MP_LOG_ENTER , g_MicroProfileGpuLog ) ;
return 1 ;
}
return 0 ;
}
void MicroProfileGpuLeave ( MicroProfileToken nToken_ , uint64_t nTickStart )
{
if ( nTickStart )
{
uint64_t nTimer = MicroProfileGpuInsertTimeStamp ( ) ;
MicroProfileLogPut ( nToken_ , nTimer , MP_LOG_LEAVE , g_MicroProfileGpuLog ) ;
}
}
void MicroProfileContextSwitchPut ( MicroProfileContextSwitch * pContextSwitch )
{
2015-01-02 18:37:58 +00:00
if ( S . nRunning | | pContextSwitch - > nTicks < = S . nPauseTicks )
2014-05-28 02:38:47 +00:00
{
uint32_t nPut = S . nContextSwitchPut ;
S . ContextSwitch [ nPut ] = * pContextSwitch ;
S . nContextSwitchPut = ( S . nContextSwitchPut + 1 ) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE ;
}
}
void MicroProfileGetRange ( uint32_t nPut , uint32_t nGet , uint32_t nRange [ 2 ] [ 2 ] )
{
if ( nPut > nGet )
{
nRange [ 0 ] [ 0 ] = nGet ;
nRange [ 0 ] [ 1 ] = nPut ;
nRange [ 1 ] [ 0 ] = nRange [ 1 ] [ 1 ] = 0 ;
}
else if ( nPut ! = nGet )
{
MP_ASSERT ( nGet ! = MICROPROFILE_BUFFER_SIZE ) ;
uint32_t nCountEnd = MICROPROFILE_BUFFER_SIZE - nGet ;
nRange [ 0 ] [ 0 ] = nGet ;
nRange [ 0 ] [ 1 ] = nGet + nCountEnd ;
nRange [ 1 ] [ 0 ] = 0 ;
nRange [ 1 ] [ 1 ] = nPut ;
}
}
void MicroProfileFlip ( )
{
#if 0
//verify LogEntry wraps correctly
MicroProfileLogEntry c = MP_LOG_TICK_MASK - 5000 ;
for ( int i = 0 ; i < 10000 ; + + i , c + = 1 )
{
MicroProfileLogEntry l2 = ( c + 2500 ) & MP_LOG_TICK_MASK ;
MP_ASSERT ( 2500 = = MicroProfileLogTickDifference ( c , l2 ) ) ;
}
# endif
MICROPROFILE_SCOPE ( g_MicroProfileFlip ) ;
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
2015-01-02 18:37:58 +00:00
if ( S . nToggleRunning )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nRunning = ! S . nRunning ;
if ( ! S . nRunning )
S . nPauseTicks = MP_TICK ( ) ;
S . nToggleRunning = 0 ;
for ( uint32_t i = 0 ; i < MICROPROFILE_MAX_THREADS ; + + i )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfileThreadLog * pLog = S . Pool [ i ] ;
if ( pLog )
{
pLog - > nStackPos = 0 ;
}
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
uint32_t nAggregateClear = S . nAggregateClear , nAggregateFlip = 0 ;
if ( S . nDumpHtmlNextFrame )
{
S . nDumpHtmlNextFrame = 0 ;
MicroProfileDumpHtmlToFile ( ) ;
}
if ( MicroProfileWebServerUpdate ( ) )
{
nAggregateClear = 1 ;
nAggregateFlip = 1 ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
if ( S . nRunning | | S . nForceEnable )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nFramePutIndex + + ;
2014-05-28 02:38:47 +00:00
S . nFramePut = ( S . nFramePut + 1 ) % MICROPROFILE_MAX_FRAME_HISTORY ;
2015-01-02 18:37:58 +00:00
MP_ASSERT ( ( S . nFramePutIndex % MICROPROFILE_MAX_FRAME_HISTORY ) = = S . nFramePut ) ;
2014-05-28 02:38:47 +00:00
S . nFrameCurrent = ( S . nFramePut + MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 1 ) % MICROPROFILE_MAX_FRAME_HISTORY ;
2015-01-02 18:37:58 +00:00
S . nFrameCurrentIndex + + ;
2014-05-28 02:38:47 +00:00
uint32_t nFrameNext = ( S . nFrameCurrent + 1 ) % MICROPROFILE_MAX_FRAME_HISTORY ;
uint32_t nContextSwitchPut = S . nContextSwitchPut ;
if ( S . nContextSwitchLastPut < nContextSwitchPut )
{
S . nContextSwitchUsage = ( nContextSwitchPut - S . nContextSwitchLastPut ) ;
}
else
{
S . nContextSwitchUsage = MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - S . nContextSwitchLastPut + nContextSwitchPut ;
}
S . nContextSwitchLastPut = nContextSwitchPut ;
MicroProfileFrameState * pFramePut = & S . Frames [ S . nFramePut ] ;
MicroProfileFrameState * pFrameCurrent = & S . Frames [ S . nFrameCurrent ] ;
MicroProfileFrameState * pFrameNext = & S . Frames [ nFrameNext ] ;
2015-01-02 18:37:58 +00:00
2014-05-28 02:38:47 +00:00
pFramePut - > nFrameStartCpu = MP_TICK ( ) ;
pFramePut - > nFrameStartGpu = ( uint32_t ) MicroProfileGpuInsertTimeStamp ( ) ;
if ( pFrameNext - > nFrameStartGpu ! = ( uint64_t ) - 1 )
pFrameNext - > nFrameStartGpu = MicroProfileGpuGetTimeStamp ( ( uint32_t ) pFrameNext - > nFrameStartGpu ) ;
if ( pFrameCurrent - > nFrameStartGpu = = ( uint64_t ) - 1 )
2015-01-02 18:37:58 +00:00
pFrameCurrent - > nFrameStartGpu = pFrameNext - > nFrameStartGpu + 1 ;
2014-05-28 02:38:47 +00:00
uint64_t nFrameStartCpu = pFrameCurrent - > nFrameStartCpu ;
uint64_t nFrameEndCpu = pFrameNext - > nFrameStartCpu ;
{
uint64_t nTick = nFrameEndCpu - nFrameStartCpu ;
S . nFlipTicks = nTick ;
S . nFlipAggregate + = nTick ;
S . nFlipMax = MicroProfileMax ( S . nFlipMax , nTick ) ;
}
for ( uint32_t i = 0 ; i < MICROPROFILE_MAX_THREADS ; + + i )
{
MicroProfileThreadLog * pLog = S . Pool [ i ] ;
if ( ! pLog )
{
pFramePut - > nLogStart [ i ] = 0 ;
}
else
{
2015-01-02 18:37:58 +00:00
uint32_t nPut = pLog - > nPut . load ( std : : memory_order_acquire ) ;
pFramePut - > nLogStart [ i ] = nPut ;
MP_ASSERT ( nPut < MICROPROFILE_BUFFER_SIZE ) ;
2014-05-28 02:38:47 +00:00
//need to keep last frame around to close timers. timers more than 1 frame old is ditched.
2015-01-02 18:37:58 +00:00
pLog - > nGet . store ( nPut , std : : memory_order_relaxed ) ;
2014-05-28 02:38:47 +00:00
}
}
if ( S . nRunning )
{
{
MICROPROFILE_SCOPE ( g_MicroProfileClear ) ;
for ( uint32_t i = 0 ; i < S . nTotalTimers ; + + i )
{
S . Frame [ i ] . nTicks = 0 ;
S . Frame [ i ] . nCount = 0 ;
S . FrameExclusive [ i ] = 0 ;
}
for ( uint32_t j = 0 ; j < MICROPROFILE_META_MAX ; + + j )
{
if ( S . MetaCounters [ j ] . pName )
{
for ( uint32_t i = 0 ; i < S . nTotalTimers ; + + i )
{
S . MetaCounters [ j ] . nCounters [ i ] = 0 ;
}
}
}
}
{
MICROPROFILE_SCOPE ( g_MicroProfileThreadLoop ) ;
for ( uint32_t i = 0 ; i < MICROPROFILE_MAX_THREADS ; + + i )
{
MicroProfileThreadLog * pLog = S . Pool [ i ] ;
2015-01-02 18:37:58 +00:00
if ( ! pLog )
2014-05-28 02:38:47 +00:00
continue ;
uint32_t nPut = pFrameNext - > nLogStart [ i ] ;
uint32_t nGet = pFrameCurrent - > nLogStart [ i ] ;
uint32_t nRange [ 2 ] [ 2 ] = { { 0 , 0 } , { 0 , 0 } , } ;
MicroProfileGetRange ( nPut , nGet , nRange ) ;
//fetch gpu results.
if ( pLog - > nGpu )
{
for ( uint32_t j = 0 ; j < 2 ; + + j )
{
uint32_t nStart = nRange [ j ] [ 0 ] ;
uint32_t nEnd = nRange [ j ] [ 1 ] ;
for ( uint32_t k = nStart ; k < nEnd ; + + k )
{
MicroProfileLogEntry L = pLog - > Log [ k ] ;
pLog - > Log [ k ] = MicroProfileLogSetTick ( L , MicroProfileGpuGetTimeStamp ( ( uint32_t ) MicroProfileLogGetTick ( L ) ) ) ;
}
}
}
2015-01-02 18:37:58 +00:00
uint32_t * pStack = & pLog - > nStack [ 0 ] ;
int64_t * pChildTickStack = & pLog - > nChildTickStack [ 0 ] ;
uint32_t nStackPos = pLog - > nStackPos ;
2014-05-28 02:38:47 +00:00
for ( uint32_t j = 0 ; j < 2 ; + + j )
{
uint32_t nStart = nRange [ j ] [ 0 ] ;
uint32_t nEnd = nRange [ j ] [ 1 ] ;
for ( uint32_t k = nStart ; k < nEnd ; + + k )
{
MicroProfileLogEntry LE = pLog - > Log [ k ] ;
int nType = MicroProfileLogType ( LE ) ;
if ( MP_LOG_ENTER = = nType )
{
2015-01-02 18:37:58 +00:00
MP_ASSERT ( nStackPos < MICROPROFILE_STACK_MAX ) ;
pStack [ nStackPos + + ] = k ;
pChildTickStack [ nStackPos ] = 0 ;
2014-05-28 02:38:47 +00:00
}
else if ( MP_LOG_META = = nType )
{
if ( nStackPos )
{
int64_t nMetaIndex = MicroProfileLogTimerIndex ( LE ) ;
int64_t nMetaCount = MicroProfileLogGetTick ( LE ) ;
MP_ASSERT ( nMetaIndex < MICROPROFILE_META_MAX ) ;
2015-01-02 18:37:58 +00:00
int64_t nCounter = MicroProfileLogTimerIndex ( pLog - > Log [ pStack [ nStackPos - 1 ] ] ) ;
2014-05-28 02:38:47 +00:00
S . MetaCounters [ nMetaIndex ] . nCounters [ nCounter ] + = nMetaCount ;
}
}
else
{
MP_ASSERT ( nType = = MP_LOG_LEAVE ) ;
2015-01-02 18:37:58 +00:00
if ( nStackPos )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
int64_t nTickStart = pLog - > Log [ pStack [ nStackPos - 1 ] ] ;
int64_t nTicks = MicroProfileLogTickDifference ( nTickStart , LE ) ;
int64_t nChildTicks = pChildTickStack [ nStackPos ] ;
2014-05-28 02:38:47 +00:00
nStackPos - - ;
2015-01-02 18:37:58 +00:00
pChildTickStack [ nStackPos ] + = nTicks ;
uint32_t nTimerIndex = MicroProfileLogTimerIndex ( LE ) ;
S . Frame [ nTimerIndex ] . nTicks + = nTicks ;
S . FrameExclusive [ nTimerIndex ] + = ( nTicks - nChildTicks ) ;
S . Frame [ nTimerIndex ] . nCount + = 1 ;
2014-05-28 02:38:47 +00:00
}
}
}
}
2015-01-02 18:37:58 +00:00
pLog - > nStackPos = nStackPos ;
2014-05-28 02:38:47 +00:00
}
}
{
MICROPROFILE_SCOPE ( g_MicroProfileAccumulate ) ;
for ( uint32_t i = 0 ; i < S . nTotalTimers ; + + i )
{
2015-01-02 18:37:58 +00:00
S . AggregateTimers [ i ] . nTicks + = S . Frame [ i ] . nTicks ;
2014-05-28 02:38:47 +00:00
S . AggregateTimers [ i ] . nCount + = S . Frame [ i ] . nCount ;
S . MaxTimers [ i ] = MicroProfileMax ( S . MaxTimers [ i ] , S . Frame [ i ] . nTicks ) ;
2015-01-02 18:37:58 +00:00
S . AggregateTimersExclusive [ i ] + = S . FrameExclusive [ i ] ;
2014-05-28 02:38:47 +00:00
S . MaxTimersExclusive [ i ] = MicroProfileMax ( S . MaxTimersExclusive [ i ] , S . FrameExclusive [ i ] ) ;
}
}
for ( uint32_t i = 0 ; i < MICROPROFILE_MAX_GRAPHS ; + + i )
{
if ( S . Graph [ i ] . nToken ! = MICROPROFILE_INVALID_TOKEN )
{
MicroProfileToken nToken = S . Graph [ i ] . nToken ;
S . Graph [ i ] . nHistory [ S . nGraphPut ] = S . Frame [ MicroProfileGetTimerIndex ( nToken ) ] . nTicks ;
}
}
S . nGraphPut = ( S . nGraphPut + 1 ) % MICROPROFILE_GRAPH_HISTORY ;
}
if ( S . nRunning & & S . nAggregateFlip < = + + S . nAggregateFlipCount )
{
2015-01-02 18:37:58 +00:00
nAggregateFlip = 1 ;
2014-05-28 02:38:47 +00:00
if ( S . nAggregateFlip ) // if 0 accumulate indefinitely
{
2015-01-02 18:37:58 +00:00
nAggregateClear = 1 ;
2014-05-28 02:38:47 +00:00
}
}
}
2015-01-02 18:37:58 +00:00
if ( nAggregateFlip )
{
memcpy ( & S . Aggregate [ 0 ] , & S . AggregateTimers [ 0 ] , sizeof ( S . Aggregate [ 0 ] ) * S . nTotalTimers ) ;
memcpy ( & S . AggregateMax [ 0 ] , & S . MaxTimers [ 0 ] , sizeof ( S . AggregateMax [ 0 ] ) * S . nTotalTimers ) ;
memcpy ( & S . AggregateExclusive [ 0 ] , & S . AggregateTimersExclusive [ 0 ] , sizeof ( S . AggregateExclusive [ 0 ] ) * S . nTotalTimers ) ;
memcpy ( & S . AggregateMaxExclusive [ 0 ] , & S . MaxTimersExclusive [ 0 ] , sizeof ( S . AggregateMaxExclusive [ 0 ] ) * S . nTotalTimers ) ;
S . nAggregateFrames = S . nAggregateFlipCount ;
S . nFlipAggregateDisplay = S . nFlipAggregate ;
S . nFlipMaxDisplay = S . nFlipMax ;
if ( nAggregateClear )
{
memset ( & S . AggregateTimers [ 0 ] , 0 , sizeof ( S . Aggregate [ 0 ] ) * S . nTotalTimers ) ;
memset ( & S . MaxTimers [ 0 ] , 0 , sizeof ( S . MaxTimers [ 0 ] ) * S . nTotalTimers ) ;
memset ( & S . AggregateTimersExclusive [ 0 ] , 0 , sizeof ( S . AggregateExclusive [ 0 ] ) * S . nTotalTimers ) ;
memset ( & S . MaxTimersExclusive [ 0 ] , 0 , sizeof ( S . MaxTimersExclusive [ 0 ] ) * S . nTotalTimers ) ;
S . nAggregateFlipCount = 0 ;
S . nFlipAggregate = 0 ;
S . nFlipMax = 0 ;
S . nAggregateFlipTick = MP_TICK ( ) ;
}
}
S . nAggregateClear = 0 ;
2014-05-28 02:38:47 +00:00
uint64_t nNewActiveGroup = 0 ;
2015-01-02 18:37:58 +00:00
if ( S . nForceEnable | | ( S . nDisplay & & S . nRunning ) )
nNewActiveGroup = S . nAllGroupsWanted ? S . nGroupMask : S . nActiveGroupWanted ;
2014-05-28 02:38:47 +00:00
nNewActiveGroup | = S . nForceGroup ;
if ( S . nActiveGroup ! = nNewActiveGroup )
S . nActiveGroup = nNewActiveGroup ;
uint32_t nNewActiveBars = 0 ;
if ( S . nDisplay & & S . nRunning )
nNewActiveBars = S . nBars ;
2015-01-02 18:37:58 +00:00
if ( S . nForceMetaCounters )
{
for ( int i = 0 ; i < MICROPROFILE_META_MAX ; + + i )
{
if ( S . MetaCounters [ i ] . pName )
{
nNewActiveBars | = ( MP_DRAW_META_FIRST < < i ) ;
}
}
}
2014-05-28 02:38:47 +00:00
if ( nNewActiveBars ! = S . nActiveBars )
S . nActiveBars = nNewActiveBars ;
2015-01-02 18:37:58 +00:00
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileSetForceEnable ( bool bEnable )
{
S . nForceEnable = bEnable ? 1 : 0 ;
}
bool MicroProfileGetForceEnable ( )
{
return S . nForceEnable ! = 0 ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
void MicroProfileSetEnableAllGroups ( bool bEnableAllGroups )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nAllGroupsWanted = bEnableAllGroups ? 1 : 0 ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
bool MicroProfileGetEnableAllGroups ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return 0 ! = S . nAllGroupsWanted ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileSetForceMetaCounters ( bool bForce )
{
S . nForceMetaCounters = bForce ? 1 : 0 ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
bool MicroProfileGetForceMetaCounters ( )
{
return 0 ! = S . nForceMetaCounters ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileSetAggregateFrames ( int nFrames )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nAggregateFlip = ( uint32_t ) nFrames ;
if ( 0 = = nFrames )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nAggregateClear = 1 ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
int MicroProfileGetAggregateFrames ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return S . nAggregateFlip ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
int MicroProfileGetCurrentAggregateFrames ( )
{
return int ( S . nAggregateFlip ? S . nAggregateFlip : S . nAggregateFlipCount ) ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileForceEnableGroup ( const char * pGroup , MicroProfileTokenType Type )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfileInit ( ) ;
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
uint16_t nGroup = MicroProfileGetGroup ( pGroup , Type ) ;
S . nForceGroup | = ( 1ll < < nGroup ) ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileForceDisableGroup ( const char * pGroup , MicroProfileTokenType Type )
{
MicroProfileInit ( ) ;
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
uint16_t nGroup = MicroProfileGetGroup ( pGroup , Type ) ;
S . nForceGroup & = ~ ( 1ll < < nGroup ) ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileCalcAllTimers ( float * pTimers , float * pAverage , float * pMax , float * pCallAverage , float * pExclusive , float * pAverageExclusive , float * pMaxExclusive , uint32_t nSize )
{
for ( uint32_t i = 0 ; i < S . nTotalTimers & & i < nSize ; + + i )
{
const uint32_t nGroupId = S . TimerInfo [ i ] . nGroupIndex ;
const float fToMs = MicroProfileTickToMsMultiplier ( S . GroupInfo [ nGroupId ] . Type = = MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu ( ) : MicroProfileTicksPerSecondCpu ( ) ) ;
uint32_t nTimer = i ;
uint32_t nIdx = i * 2 ;
uint32_t nAggregateFrames = S . nAggregateFrames ? S . nAggregateFrames : 1 ;
uint32_t nAggregateCount = S . Aggregate [ nTimer ] . nCount ? S . Aggregate [ nTimer ] . nCount : 1 ;
float fToPrc = S . fRcpReferenceTime ;
float fMs = fToMs * ( S . Frame [ nTimer ] . nTicks ) ;
float fPrc = MicroProfileMin ( fMs * fToPrc , 1.f ) ;
float fAverageMs = fToMs * ( S . Aggregate [ nTimer ] . nTicks / nAggregateFrames ) ;
float fAveragePrc = MicroProfileMin ( fAverageMs * fToPrc , 1.f ) ;
float fMaxMs = fToMs * ( S . AggregateMax [ nTimer ] ) ;
float fMaxPrc = MicroProfileMin ( fMaxMs * fToPrc , 1.f ) ;
float fCallAverageMs = fToMs * ( S . Aggregate [ nTimer ] . nTicks / nAggregateCount ) ;
float fCallAveragePrc = MicroProfileMin ( fCallAverageMs * fToPrc , 1.f ) ;
float fMsExclusive = fToMs * ( S . FrameExclusive [ nTimer ] ) ;
float fPrcExclusive = MicroProfileMin ( fMsExclusive * fToPrc , 1.f ) ;
float fAverageMsExclusive = fToMs * ( S . AggregateExclusive [ nTimer ] / nAggregateFrames ) ;
float fAveragePrcExclusive = MicroProfileMin ( fAverageMsExclusive * fToPrc , 1.f ) ;
float fMaxMsExclusive = fToMs * ( S . AggregateMaxExclusive [ nTimer ] ) ;
float fMaxPrcExclusive = MicroProfileMin ( fMaxMsExclusive * fToPrc , 1.f ) ;
pTimers [ nIdx ] = fMs ;
pTimers [ nIdx + 1 ] = fPrc ;
pAverage [ nIdx ] = fAverageMs ;
pAverage [ nIdx + 1 ] = fAveragePrc ;
pMax [ nIdx ] = fMaxMs ;
pMax [ nIdx + 1 ] = fMaxPrc ;
pCallAverage [ nIdx ] = fCallAverageMs ;
pCallAverage [ nIdx + 1 ] = fCallAveragePrc ;
pExclusive [ nIdx ] = fMsExclusive ;
pExclusive [ nIdx + 1 ] = fPrcExclusive ;
pAverageExclusive [ nIdx ] = fAverageMsExclusive ;
pAverageExclusive [ nIdx + 1 ] = fAveragePrcExclusive ;
pMaxExclusive [ nIdx ] = fMaxMsExclusive ;
pMaxExclusive [ nIdx + 1 ] = fMaxPrcExclusive ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
void MicroProfileTogglePause ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nToggleRunning = 1 ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
float MicroProfileGetTime ( const char * pGroup , const char * pName )
{
MicroProfileToken nToken = MicroProfileFindToken ( pGroup , pName ) ;
if ( nToken = = MICROPROFILE_INVALID_TOKEN )
{
return 0.f ;
}
uint32_t nTimerIndex = MicroProfileGetTimerIndex ( nToken ) ;
uint32_t nGroupIndex = MicroProfileGetGroupIndex ( nToken ) ;
float fToMs = MicroProfileTickToMsMultiplier ( S . GroupInfo [ nGroupIndex ] . Type = = MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu ( ) : MicroProfileTicksPerSecondCpu ( ) ) ;
return S . Frame [ nTimerIndex ] . nTicks * fToMs ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# if MICROPROFILE_WEBSERVER
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
# define MICROPROFILE_EMBED_HTML
extern const char g_MicroProfileHtml_begin [ ] ;
extern const char g_MicroProfileHtml_end [ ] ;
extern const size_t g_MicroProfileHtml_begin_size ;
extern const size_t g_MicroProfileHtml_end_size ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
typedef void MicroProfileWriteCallback ( void * Handle , size_t size , const char * pData ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
uint32_t MicroProfileWebServerPort ( )
{
return S . nWebServerPort ;
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileDumpHtml ( const char * pFile )
{
uint32_t nLen = strlen ( pFile ) ;
if ( nLen > sizeof ( S . HtmlDumpPath ) - 1 )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
return ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
memcpy ( S . HtmlDumpPath , pFile , nLen + 1 ) ;
S . nDumpHtmlNextFrame = 1 ;
}
void MicroProfilePrintf ( MicroProfileWriteCallback CB , void * Handle , const char * pFmt , . . . )
{
char buffer [ 32 * 1024 ] ;
va_list args ;
va_start ( args , pFmt ) ;
# ifdef _WIN32
size_t size = vsprintf_s ( buffer , pFmt , args ) ;
# else
size_t size = vsnprintf ( buffer , sizeof ( buffer ) - 1 , pFmt , args ) ;
# endif
CB ( Handle , size , & buffer [ 0 ] ) ;
va_end ( args ) ;
}
void MicroProfileDumpHtml ( MicroProfileWriteCallback CB , void * Handle , int nMaxFrames )
{
CB ( Handle , g_MicroProfileHtml_begin_size - 1 , & g_MicroProfileHtml_begin [ 0 ] ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
//dump info
uint64_t nTicks = MP_TICK ( ) ;
float fAggregateMs = MicroProfileTickToMsMultiplier ( MicroProfileTicksPerSecondCpu ( ) ) * ( nTicks - S . nAggregateFlipTick ) ;
MicroProfilePrintf ( CB , Handle , " var AggregateInfo = {'Frames':%d, 'Time':%f}; \n " , S . nAggregateFrames , fAggregateMs ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
//groups
MicroProfilePrintf ( CB , Handle , " var GroupInfo = Array(%d); \n \n " , S . nGroupCount ) ;
for ( uint32_t i = 0 ; i < S . nGroupCount ; + + i )
{
MP_ASSERT ( i = = S . GroupInfo [ i ] . nGroupIndex ) ;
MicroProfilePrintf ( CB , Handle , " GroupInfo[%d] = MakeGroup(%d, \" %s \" , %d, %d); \n " , S . GroupInfo [ i ] . nGroupIndex , S . GroupInfo [ i ] . nGroupIndex , S . GroupInfo [ i ] . pName , S . GroupInfo [ i ] . nNumTimers , S . GroupInfo [ i ] . Type = = MicroProfileTokenTypeGpu ? 1 : 0 ) ;
}
//timers
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
uint32_t nNumTimers = S . nTotalTimers ;
uint32_t nBlockSize = 2 * nNumTimers ;
float * pTimers = ( float * ) alloca ( nBlockSize * 7 * sizeof ( float ) ) ;
float * pAverage = pTimers + nBlockSize ;
float * pMax = pTimers + 2 * nBlockSize ;
float * pCallAverage = pTimers + 3 * nBlockSize ;
float * pTimersExclusive = pTimers + 4 * nBlockSize ;
float * pAverageExclusive = pTimers + 5 * nBlockSize ;
float * pMaxExclusive = pTimers + 6 * nBlockSize ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfileCalcAllTimers ( pTimers , pAverage , pMax , pCallAverage , pTimersExclusive , pAverageExclusive , pMaxExclusive , nNumTimers ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " \n var TimerInfo = Array(%d); \n \n " , S . nTotalTimers ) ;
for ( uint32_t i = 0 ; i < S . nTotalTimers ; + + i )
{
uint32_t nIdx = i * 2 ;
MP_ASSERT ( i = = S . TimerInfo [ i ] . nTimerIndex ) ;
MicroProfilePrintf ( CB , Handle , " var Meta%d = [ " , i ) ;
bool bOnce = true ;
for ( int j = 0 ; j < MICROPROFILE_META_MAX ; + + j )
{
if ( S . MetaCounters [ j ] . pName )
{
uint32_t lala = S . MetaCounters [ j ] . nCounters [ i ] ;
MicroProfilePrintf ( CB , Handle , bOnce ? " %d " : " ,%d " , lala ) ;
bOnce = false ;
}
}
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
MicroProfilePrintf ( CB , Handle , " TimerInfo[%d] = MakeTimer(%d, \" %s \" , %d, '#%02x%02x%02x', %f, %f, %f, %f, %f, %d, Meta%d); \n " , S . TimerInfo [ i ] . nTimerIndex , S . TimerInfo [ i ] . nTimerIndex , S . TimerInfo [ i ] . pName , S . TimerInfo [ i ] . nGroupIndex ,
MICROPROFILE_UNPACK_RED ( S . TimerInfo [ i ] . nColor ) & 0xff ,
MICROPROFILE_UNPACK_GREEN ( S . TimerInfo [ i ] . nColor ) & 0xff ,
MICROPROFILE_UNPACK_BLUE ( S . TimerInfo [ i ] . nColor ) & 0xff ,
pAverage [ nIdx ] ,
pMax [ nIdx ] ,
pAverageExclusive [ nIdx ] ,
pMaxExclusive [ nIdx ] ,
pCallAverage [ nIdx ] ,
S . Aggregate [ i ] . nCount ,
i
) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " \n var ThreadNames = [ " ) ;
for ( uint32_t i = 0 ; i < S . nNumLogs ; + + i )
{
if ( S . Pool [ i ] )
{
MicroProfilePrintf ( CB , Handle , " '%s', " , S . Pool [ i ] - > ThreadName ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
}
else
{
MicroProfilePrintf ( CB , Handle , " 'Thread %d', " , i ) ;
}
}
MicroProfilePrintf ( CB , Handle , " ]; \n \n " ) ;
MicroProfilePrintf ( CB , Handle , " \n var MetaNames = [ " ) ;
for ( int i = 0 ; i < MICROPROFILE_META_MAX ; + + i )
{
if ( S . MetaCounters [ i ] . pName )
{
MicroProfilePrintf ( CB , Handle , " '%s', " , S . MetaCounters [ i ] . pName ) ;
}
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ]; \n \n " ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
uint32_t nNumFrames = ( MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 1 ) ;
if ( S . nFrameCurrentIndex < nNumFrames )
nNumFrames = S . nFrameCurrentIndex ;
if ( ( int ) nNumFrames > nMaxFrames )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
nNumFrames = nMaxFrames ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# if MICROPROFILE_DEBUG
printf ( " dumping %d frames \n " , nNumFrames ) ;
# endif
uint32_t nFirstFrame = ( S . nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames ) % MICROPROFILE_MAX_FRAME_HISTORY ;
uint32_t nFirstFrameIndex = S . nFrameCurrentIndex - nNumFrames ;
int64_t nTickStart = S . Frames [ nFirstFrame ] . nFrameStartCpu ;
int64_t nTickStartGpu = S . Frames [ nFirstFrame ] . nFrameStartGpu ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " var Frames = Array(%d); \n " , nNumFrames ) ;
for ( uint32_t i = 0 ; i < nNumFrames ; + + i )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t nFrameIndex = ( nFirstFrame + i ) % MICROPROFILE_MAX_FRAME_HISTORY ;
uint32_t nFrameIndexNext = ( nFrameIndex + 1 ) % MICROPROFILE_MAX_FRAME_HISTORY ;
for ( uint32_t j = 0 ; j < S . nNumLogs ; + + j )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfileThreadLog * pLog = S . Pool [ j ] ;
int64_t nStartTick = pLog - > nGpu ? nTickStartGpu : nTickStart ;
uint32_t nLogStart = S . Frames [ nFrameIndex ] . nLogStart [ j ] ;
uint32_t nLogEnd = S . Frames [ nFrameIndexNext ] . nLogStart [ j ] ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
float fToMs = MicroProfileTickToMsMultiplier ( pLog - > nGpu ? MicroProfileTicksPerSecondGpu ( ) : MicroProfileTicksPerSecondCpu ( ) ) ;
MicroProfilePrintf ( CB , Handle , " var ts_%d_%d = [ " , i , j ) ;
if ( nLogStart ! = nLogEnd )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t k = nLogStart ;
uint32_t nLogType = MicroProfileLogType ( pLog - > Log [ k ] ) ;
float fTime = nLogType = = MP_LOG_META ? 0.f : MicroProfileLogTickDifference ( nStartTick , pLog - > Log [ k ] ) * fToMs ;
MicroProfilePrintf ( CB , Handle , " %f " , fTime ) ;
for ( k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE ; k ! = nLogEnd ; k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t nLogType = MicroProfileLogType ( pLog - > Log [ k ] ) ;
float fTime = nLogType = = MP_LOG_META ? 0.f : MicroProfileLogTickDifference ( nStartTick , pLog - > Log [ k ] ) * fToMs ;
MicroProfilePrintf ( CB , Handle , " ,%f " , fTime ) ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
MicroProfilePrintf ( CB , Handle , " var tt_%d_%d = [ " , i , j ) ;
if ( nLogStart ! = nLogEnd )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t k = nLogStart ;
MicroProfilePrintf ( CB , Handle , " %d " , MicroProfileLogType ( pLog - > Log [ k ] ) ) ;
for ( k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE ; k ! = nLogEnd ; k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t nLogType = MicroProfileLogType ( pLog - > Log [ k ] ) ;
if ( nLogType = = MP_LOG_META )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
//for meta, store the count + 2, which is the tick part
nLogType = 2 + MicroProfileLogGetTick ( pLog - > Log [ k ] ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ,%d " , nLogType ) ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " var ti_%d_%d = [ " , i , j ) ;
if ( nLogStart ! = nLogEnd )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
uint32_t k = nLogStart ;
MicroProfilePrintf ( CB , Handle , " %d " , ( uint32_t ) MicroProfileLogTimerIndex ( pLog - > Log [ k ] ) ) ;
for ( k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE ; k ! = nLogEnd ; k = ( k + 1 ) % MICROPROFILE_BUFFER_SIZE )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ,%d " , ( uint32_t ) MicroProfileLogTimerIndex ( pLog - > Log [ k ] ) ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
}
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
}
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " var ts%d = [ " , i ) ;
for ( uint32_t j = 0 ; j < S . nNumLogs ; + + j )
{
MicroProfilePrintf ( CB , Handle , " ts_%d_%d, " , i , j ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
MicroProfilePrintf ( CB , Handle , " var tt%d = [ " , i ) ;
for ( uint32_t j = 0 ; j < S . nNumLogs ; + + j )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " tt_%d_%d, " , i , j ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
MicroProfilePrintf ( CB , Handle , " var ti%d = [ " , i ) ;
for ( uint32_t j = 0 ; j < S . nNumLogs ; + + j )
{
MicroProfilePrintf ( CB , Handle , " ti_%d_%d, " , i , j ) ;
}
MicroProfilePrintf ( CB , Handle , " ]; \n " ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
int64_t nFrameStart = S . Frames [ nFrameIndex ] . nFrameStartCpu ;
int64_t nFrameEnd = S . Frames [ nFrameIndexNext ] . nFrameStartCpu ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
float fToMs = MicroProfileTickToMsMultiplier ( MicroProfileTicksPerSecondCpu ( ) ) ;
float fFrameMs = MicroProfileLogTickDifference ( nTickStart , nFrameStart ) * fToMs ;
float fFrameEndMs = MicroProfileLogTickDifference ( nTickStart , nFrameEnd ) * fToMs ;
MicroProfilePrintf ( CB , Handle , " Frames[%d] = MakeFrame(%d, %f, %f, ts%d, tt%d, ti%d); \n " , i , nFirstFrameIndex , fFrameMs , fFrameEndMs , i , i , i ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
CB ( Handle , g_MicroProfileHtml_end_size - 1 , & g_MicroProfileHtml_end [ 0 ] ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
void MicroProfileWriteFile ( void * Handle , size_t nSize , const char * pData )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
fwrite ( pData , nSize , 1 , ( FILE * ) Handle ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
void MicroProfileDumpHtmlToFile ( )
{
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
FILE * F = fopen ( S . HtmlDumpPath , " w " ) ;
if ( F )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
MicroProfileDumpHtml ( MicroProfileWriteFile , F , MICROPROFILE_WEBSERVER_MAXFRAMES ) ;
fclose ( F ) ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
static uint64_t g_nMicroProfileDataSent = 0 ;
void MicroProfileWriteSocket ( void * Handle , size_t nSize , const char * pData )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
g_nMicroProfileDataSent + = nSize ;
send ( * ( MpSocket * ) Handle , pData , nSize , 0 ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# ifndef MicroProfileSetNonBlocking //fcntl doesnt work on a some unix like platforms..
void MicroProfileSetNonBlocking ( MpSocket Socket , int NonBlocking )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
# ifdef _WIN32
u_long nonBlocking = NonBlocking ? 1 : 0 ;
ioctlsocket ( Socket , FIONBIO , & nonBlocking ) ;
# else
int Options = fcntl ( Socket , F_GETFL ) ;
if ( NonBlocking )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
fcntl ( Socket , F_SETFL , Options | O_NONBLOCK ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
else
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
fcntl ( Socket , F_SETFL , Options & ( ~ O_NONBLOCK ) ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# endif
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# endif
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
void MicroProfileWebServerStart ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
# ifdef _WIN32
WSADATA wsa ;
if ( WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsa ) )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . ListenerSocket = - 1 ;
2014-05-28 02:38:47 +00:00
return ;
}
2015-01-02 18:37:58 +00:00
# endif
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
S . ListenerSocket = socket ( PF_INET , SOCK_STREAM , 6 ) ;
MP_ASSERT ( ! MP_INVALID_SOCKET ( S . ListenerSocket ) ) ;
MicroProfileSetNonBlocking ( S . ListenerSocket , 1 ) ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
S . nWebServerPort = ( uint32_t ) - 1 ;
struct sockaddr_in Addr ;
Addr . sin_family = AF_INET ;
Addr . sin_addr . s_addr = INADDR_ANY ;
for ( int i = 0 ; i < 20 ; + + i )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
Addr . sin_port = htons ( MICROPROFILE_WEBSERVER_PORT + i ) ;
if ( 0 = = bind ( S . ListenerSocket , ( sockaddr * ) & Addr , sizeof ( Addr ) ) )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
S . nWebServerPort = MICROPROFILE_WEBSERVER_PORT + i ;
break ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
listen ( S . ListenerSocket , 8 ) ;
}
void MicroProfileWebServerStop ( )
{
# ifdef _WIN32
closesocket ( S . ListenerSocket ) ;
WSACleanup ( ) ;
# else
close ( S . ListenerSocket ) ;
# endif
}
bool MicroProfileWebServerUpdate ( )
{
MICROPROFILE_SCOPEI ( " MicroProfile " , " Webserver-update " , - 1 ) ;
MpSocket Connection = accept ( S . ListenerSocket , 0 , 0 ) ;
bool bServed = false ;
if ( ! MP_INVALID_SOCKET ( Connection ) )
2014-05-28 02:38:47 +00:00
{
2015-01-03 09:06:19 +00:00
int timeout = 100 ;
setsockopt ( Connection , SOL_SOCKET , SO_RCVTIMEO ,
reinterpret_cast < char * > ( & timeout ) , sizeof ( timeout ) ) ;
std : : lock_guard < std : : recursive_mutex > Lock ( MicroProfileMutex ( ) ) ;
2015-01-02 18:37:58 +00:00
char Req [ 8192 ] ;
MicroProfileSetNonBlocking ( Connection , 0 ) ;
int nReceived = recv ( Connection , Req , sizeof ( Req ) - 1 , 0 ) ;
if ( nReceived > 0 )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
Req [ nReceived ] = ' \0 ' ;
# if MICROPROFILE_DEBUG
printf ( " got request \n %s \n " , Req ) ;
# endif
# define MICROPROFILE_HTML_HEADER "HTTP / 1.0 200 OK\r\nContent-Type: text / html\r\n\r\n"
char * pHttp = strstr ( Req , " HTTP/ " ) ;
char * pGet = strstr ( Req , " GET / " ) ;
char * pGetParam = strstr ( Req , " GET /? " ) ;
if ( pHttp & & ( pGet | | pGetParam ) )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
int nMaxFrames = MICROPROFILE_WEBSERVER_MAXFRAMES ;
if ( pGetParam )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
* pHttp = ' \0 ' ;
pGetParam + = sizeof ( " GET /? " ) - 1 ;
while ( pGetParam ) //split url pairs foo=bar&lala=lele etc
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
char * pSplit = strstr ( pGetParam , " & " ) ;
if ( pSplit )
{
* pSplit + + = ' \0 ' ;
}
char * pKey = pGetParam ;
char * pValue = strstr ( pGetParam , " = " ) ;
if ( pValue )
{
* pValue + + = ' \0 ' ;
}
if ( 0 = = MP_STRCASECMP ( pKey , " frames " ) )
{
if ( pValue )
{
nMaxFrames = atoi ( pValue ) ;
}
}
pGetParam = pSplit ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
uint64_t nTickStart = MP_TICK ( ) ;
send ( Connection , MICROPROFILE_HTML_HEADER , sizeof ( MICROPROFILE_HTML_HEADER ) - 1 , 0 ) ;
uint64_t nDataStart = g_nMicroProfileDataSent ;
MicroProfileDumpHtml ( MicroProfileWriteSocket , & Connection , nMaxFrames ) ;
uint64_t nDataEnd = g_nMicroProfileDataSent ;
uint64_t nTickEnd = MP_TICK ( ) ;
float fMs = MicroProfileTickToMsMultiplier ( MicroProfileTicksPerSecondCpu ( ) ) * ( nTickEnd - nTickStart ) ;
MicroProfilePrintf ( MicroProfileWriteSocket , & Connection , " \n <!-- Sent %dkb in %6.2fms--> \n \n " , ( ( nDataEnd - nDataStart ) > > 10 ) + 1 , fMs ) ;
# if MICROPROFILE_DEBUG
printf ( " \n Sent %lldkb, in %6.3fms \n \n " , ( ( nDataEnd - nDataStart ) > > 10 ) + 1 , fMs ) ;
# endif
bServed = true ;
2014-05-28 02:38:47 +00:00
}
}
2015-01-02 18:37:58 +00:00
# ifdef _WIN32
closesocket ( Connection ) ;
# else
close ( Connection ) ;
# endif
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
return bServed ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
# endif
2014-05-28 02:38:47 +00:00
# if MICROPROFILE_CONTEXT_SWITCH_TRACE
# ifdef _WIN32
# define INITGUID
# include <evntrace.h>
# include <evntcons.h>
# include <strsafe.h>
static GUID g_MicroProfileThreadClassGuid = { 0x3d6fa8d1 , 0xfe05 , 0x11d0 , 0x9d , 0xda , 0x00 , 0xc0 , 0x4f , 0xd7 , 0xba , 0x7c } ;
struct MicroProfileSCSwitch
{
uint32_t NewThreadId ;
uint32_t OldThreadId ;
int8_t NewThreadPriority ;
int8_t OldThreadPriority ;
uint8_t PreviousCState ;
int8_t SpareByte ;
int8_t OldThreadWaitReason ;
int8_t OldThreadWaitMode ;
int8_t OldThreadState ;
int8_t OldThreadWaitIdealProcessor ;
uint32_t NewThreadWaitTime ;
uint32_t Reserved ;
} ;
VOID WINAPI MicroProfileContextSwitchCallback ( PEVENT_TRACE pEvent )
{
if ( pEvent - > Header . Guid = = g_MicroProfileThreadClassGuid )
{
if ( pEvent - > Header . Class . Type = = 36 )
{
MicroProfileSCSwitch * pCSwitch = ( MicroProfileSCSwitch * ) pEvent - > MofData ;
if ( ( pCSwitch - > NewThreadId ! = 0 ) | | ( pCSwitch - > OldThreadId ! = 0 ) )
{
MicroProfileContextSwitch Switch ;
Switch . nThreadOut = pCSwitch - > OldThreadId ;
Switch . nThreadIn = pCSwitch - > NewThreadId ;
Switch . nCpu = pEvent - > BufferContext . ProcessorNumber ;
Switch . nTicks = pEvent - > Header . TimeStamp . QuadPart ;
MicroProfileContextSwitchPut ( & Switch ) ;
}
}
}
}
ULONG WINAPI MicroProfileBufferCallback ( PEVENT_TRACE_LOGFILE Buffer )
{
return ( S . bContextSwitchStop | | ! S . bContextSwitchRunning ) ? FALSE : TRUE ;
}
struct MicroProfileKernelTraceProperties : public EVENT_TRACE_PROPERTIES
{
char dummy [ sizeof ( KERNEL_LOGGER_NAME ) ] ;
} ;
2015-01-02 18:37:58 +00:00
void MicroProfileContextSwitchStopTrace ( )
2014-05-28 02:38:47 +00:00
{
2015-01-02 18:37:58 +00:00
TRACEHANDLE SessionHandle = 0 ;
MicroProfileKernelTraceProperties sessionProperties ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
ZeroMemory ( & sessionProperties , sizeof ( sessionProperties ) ) ;
sessionProperties . Wnode . BufferSize = sizeof ( sessionProperties ) ;
sessionProperties . Wnode . Flags = WNODE_FLAG_TRACED_GUID ;
sessionProperties . Wnode . ClientContext = 1 ; //QPC clock resolution
sessionProperties . Wnode . Guid = SystemTraceControlGuid ;
sessionProperties . BufferSize = 1 ;
sessionProperties . NumberOfBuffers = 128 ;
sessionProperties . EnableFlags = EVENT_TRACE_FLAG_CSWITCH ;
sessionProperties . LogFileMode = EVENT_TRACE_REAL_TIME_MODE ;
sessionProperties . MaximumFileSize = 0 ;
sessionProperties . LoggerNameOffset = sizeof ( EVENT_TRACE_PROPERTIES ) ;
sessionProperties . LogFileNameOffset = 0 ;
2014-05-28 02:38:47 +00:00
2015-01-02 18:37:58 +00:00
EVENT_TRACE_LOGFILE log ;
ZeroMemory ( & log , sizeof ( log ) ) ;
log . LoggerName = KERNEL_LOGGER_NAME ;
log . ProcessTraceMode = 0 ;
TRACEHANDLE hLog = OpenTrace ( & log ) ;
if ( hLog )
{
ControlTrace ( SessionHandle , KERNEL_LOGGER_NAME , & sessionProperties , EVENT_TRACE_CONTROL_STOP ) ;
2014-05-28 02:38:47 +00:00
}
2015-01-02 18:37:58 +00:00
CloseTrace ( hLog ) ;
}
void MicroProfileTraceThread ( int unused )
{
MicroProfileContextSwitchStopTrace ( ) ;
2014-05-28 02:38:47 +00:00
ULONG status = ERROR_SUCCESS ;
TRACEHANDLE SessionHandle = 0 ;
MicroProfileKernelTraceProperties sessionProperties ;
ZeroMemory ( & sessionProperties , sizeof ( sessionProperties ) ) ;
sessionProperties . Wnode . BufferSize = sizeof ( sessionProperties ) ;
sessionProperties . Wnode . Flags = WNODE_FLAG_TRACED_GUID ;
2015-01-02 18:37:58 +00:00
sessionProperties . Wnode . ClientContext = 1 ; //QPC clock resolution
2014-05-28 02:38:47 +00:00
sessionProperties . Wnode . Guid = SystemTraceControlGuid ;
sessionProperties . BufferSize = 1 ;
sessionProperties . NumberOfBuffers = 128 ;
sessionProperties . EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_PROCESS ;
sessionProperties . LogFileMode = EVENT_TRACE_REAL_TIME_MODE ;
2015-01-02 18:37:58 +00:00
sessionProperties . MaximumFileSize = 0 ;
2014-05-28 02:38:47 +00:00
sessionProperties . LoggerNameOffset = sizeof ( EVENT_TRACE_PROPERTIES ) ;
sessionProperties . LogFileNameOffset = 0 ;
status = StartTrace ( ( PTRACEHANDLE ) & SessionHandle , KERNEL_LOGGER_NAME , & sessionProperties ) ;
if ( ERROR_SUCCESS ! = status )
{
S . bContextSwitchRunning = false ;
return ;
}
EVENT_TRACE_LOGFILE log ;
ZeroMemory ( & log , sizeof ( log ) ) ;
log . LoggerName = KERNEL_LOGGER_NAME ;
log . ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP ;
log . EventCallback = MicroProfileContextSwitchCallback ;
log . BufferCallback = MicroProfileBufferCallback ;
TRACEHANDLE hLog = OpenTrace ( & log ) ;
ProcessTrace ( & hLog , 1 , 0 , 0 ) ;
CloseTrace ( hLog ) ;
2015-01-02 18:37:58 +00:00
MicroProfileContextSwitchStopTrace ( ) ;
2014-05-28 02:38:47 +00:00
S . bContextSwitchRunning = false ;
}
void MicroProfileStartContextSwitchTrace ( )
{
if ( ! S . bContextSwitchRunning )
{
if ( ! S . pContextSwitchThread )
S . pContextSwitchThread = new std : : thread ( ) ;
if ( S . pContextSwitchThread - > joinable ( ) )
{
S . bContextSwitchStop = true ;
S . pContextSwitchThread - > join ( ) ;
}
S . bContextSwitchRunning = true ;
S . bContextSwitchStop = false ;
* S . pContextSwitchThread = std : : thread ( & MicroProfileTraceThread , 0 ) ;
}
}
void MicroProfileStopContextSwitchTrace ( )
{
if ( S . bContextSwitchRunning & & S . pContextSwitchThread )
{
S . bContextSwitchStop = true ;
S . pContextSwitchThread - > join ( ) ;
}
}
2015-01-02 18:37:58 +00:00
bool MicroProfileIsLocalThread ( uint32_t nThreadId )
2014-05-28 02:38:47 +00:00
{
HANDLE h = OpenThread ( THREAD_QUERY_LIMITED_INFORMATION , FALSE , nThreadId ) ;
if ( h = = NULL )
return false ;
DWORD hProcess = GetProcessIdOfThread ( h ) ;
CloseHandle ( h ) ;
return GetCurrentProcessId ( ) = = hProcess ;
}
# else
# error "context switch trace not supported / implemented on platform"
# endif
# else
bool MicroProfileIsLocalThread ( uint32_t nThreadId ) { return false ; }
void MicroProfileStopContextSwitchTrace ( ) { }
void MicroProfileStartContextSwitchTrace ( ) { }
# endif
# undef S
# ifdef _WIN32
# pragma warning(pop)
# endif
# endif
# endif
2015-01-02 18:37:58 +00:00
///start embedded file from microprofile.html
# ifdef MICROPROFILE_EMBED_HTML
const char g_MicroProfileHtml_begin [ ] =
" <!DOCTYPE HTML> \n "
" <html> \n "
" <head> \n "
" <title>MicroProfile Capture</title> \n "
" <style> \n "
" /* about css: http://bit.ly/1eMQ42U */ \n "
" body {margin: 0px;padding: 0px; font: 12px Courier New;background-color:#474747; color:white;overflow:hidden;} \n "
" ul {list-style-type: none;margin: 0;padding: 0;} \n "
" li{display: inline; float:left;border:5px; position:relative;text-align:center;} \n "
" a { \n "
" float:left; \n "
" text-decoration:none; \n "
" display: inline; \n "
" text-align: center; \n "
" padding:5px; \n "
" padding-bottom:0px; \n "
" padding-top:0px; \n "
" color: #FFFFFF; \n "
" background-color: #474747; \n "
" } \n "
" a:hover, a:active{ \n "
" background-color: #000000; \n "
" } \n "
" \n "
" ul ul { \n "
" position:absolute; \n "
" left:0; \n "
" top:100%; \n "
" margin-left:-999em; \n "
" } \n "
" li:hover ul { \n "
" margin-left:0; \n "
" margin-right:0; \n "
" } \n "
" ul li ul{ display:block;float:none;width:100%;} \n "
" ul li ul li{ display:block;float:none;width:100%;} \n "
" li li a{ display:block;float:none;width:100%;text-align:left;} \n "
" #nav li:hover div {margin-left:0;} \n "
" .help {position:absolute;z-index:5;text-align:left;padding:2px;margin-left:-999em;background-color: #313131;} \n "
" .root {z-index:1;position:absolute;top:0px;left:0px;} \n "
" </style> \n "
" </head> \n "
" <body style= \" \" > \n "
" <canvas id= \" History \" height= \" 70 \" style= \" background-color:#474747;margin:0px;padding:0px; \" ></canvas><canvas id= \" DetailedView \" height= \" 200 \" style= \" background-color:#474747;margin:0px;padding:0px; \" ></canvas> \n "
" <div id= \" root \" class= \" root \" > \n "
" <ul id= \" nav \" > \n "
" <li><a href= \" # \" >?</a> \n "
" <div class= \" help \" style= \" left:20px;top:20px;width:220px; \" > \n "
" Use Cursor to Inspect<br> \n "
" Shift-Drag to Pan view<br> \n "
" Ctrl-Drag to Zoom view<br> \n "
" Click to Zoom to selected range<br> \n "
" </div> \n "
" \n "
" <div class= \" help \" id= \" divFrameInfo \" style= \" left:20px;top:300px;width:auto; \" > \n "
" </div> \n "
" \n "
" </li> \n "
" <li><a href= \" # \" onclick= \" SetMode( \' timers \' ); \" id= \" buttonTimers \" >Timers</a> \n "
" <li><a href= \" # \" onclick= \" SetMode( \' detailed \' ); \" id= \" buttonDetailed \" >Detailed</a> \n "
" </li> \n "
" <li><a href= \" # \" >Reference</a> \n "
" <ul id= \' ReferenceSubMenu \' > \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 5ms \' ); \" >5ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 10ms \' ); \" >10ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 15ms \' ); \" >15ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 20ms \' ); \" >20ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 33ms \' ); \" >33ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 50ms \' ); \" >50ms</a></li> \n "
" <li><a href= \" # \" onclick= \" SetReferenceTime( \' 100ms \' ); \" >100ms</a></li> \n "
" </ul> \n "
" </li> \n "
" <li id= \" ilThreads \" ><a href= \" # \" >Threads</a> \n "
" <ul id= \" ThreadSubMenu \" > \n "
" <li><a href= \" # \" onclick= \" ToggleThread(); \" >All</a></li> \n "
" <li><a href= \" # \" >---</a></li> \n "
" </ul> \n "
" </li> \n "
" <li id= \" ilGroups \" ><a href= \" # \" >Groups</a> \n "
" <ul id= \" GroupSubMenu \" > \n "
" <li><a href= \" # \" onclick= \" ToggleGroup(); \" >All</a></li> \n "
" <li><a href= \" # \" >---</a></li> \n "
" </ul> \n "
" </li> \n "
" <li id= \" ilWidth \" ><a href= \" # \" >Width</a> \n "
" <ul id= \' WidthMenu \' > \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 1 \' ); \" >1</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.5 \' ); \" >0.5</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.25 \' ); \" >0.25</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.1 \' ); \" >0.1</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.05 \' ); \" >0.05</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.025 \' ); \" >0.025</a></li> \n "
" <li><a href= \" # \" onclick= \" SetMinWidth( \' 0.01 \' ); \" >0.01</a></li> \n "
" </ul> \n "
" </li> \n "
" </ul> \n "
" \n "
" </div> \n "
" \n "
" <script> \n "
" function InvertColor(hexTripletColor) { \n "
" var color = hexTripletColor; \n "
" color = color.substring(1); // remove # \n "
" color = parseInt(color, 16); // convert to integer \n "
" var R = ((color >> 16) % 256)/255.0; \n "
" var G = ((color >> 8) % 256)/255.0; \n "
" var B = ((color >> 0) % 256)/255.0; \n "
" var lum = (0.2126*R + 0.7152*G + 0.0722*B); \n "
" if(lum < 0.7) \n "
" { \n "
" return \' #ffffff \' ; \n "
" } \n "
" else \n "
" { \n "
" return \' #333333 \' ; \n "
" } \n "
" } \n "
" function MakeGroup(id, name, numtimers, isgpu) \n "
" { \n "
" var group = { \" id \" :id, \" name \" :name, \" numtimers \" :numtimers, \" isgpu \" :isgpu}; \n "
" return group; \n "
" } \n "
" \n "
" function MakeTimer(id, name, group, color, average, max, exclaverage, exclmax, callaverage, callcount, meta) \n "
" { \n "
" var timer = { \" id \" :id, \" name \" :name, \" len \" :name.length, \" color \" :color, \" textcolor \" :InvertColor(color), \" group \" :group, \" average \" :average, \" max \" :max, \" exclaverage \" :exclaverage, \" exclmax \" :exclmax, \" callaverage \" :callaverage, \" callcount \" :callcount, \" meta \" :meta}; \n "
" return timer; \n "
" } \n "
" function MakeFrame(id, framestart, frameend, ts, tt, ti) \n "
" { \n "
" var frame = { \" id \" :id, \" framestart \" :framestart, \" frameend \" :frameend, \" ts \" :ts, \" tt \" :tt, \" ti \" :ti}; \n "
" return frame; \n "
" } \n "
" \n "
" " ;
const size_t g_MicroProfileHtml_begin_size = sizeof ( g_MicroProfileHtml_begin ) ;
const char g_MicroProfileHtml_end [ ] =
" \n "
" \n "
" \n "
" var CanvasDetailedView = document.getElementById( \' DetailedView \' ); \n "
" var CanvasHistory = document.getElementById( \' History \' ); \n "
" \n "
" var fDetailedOffset = Frames[0].framestart; \n "
" var fDetailedRange = Frames[0].frameend - fDetailedOffset; \n "
" var nWidth = CanvasDetailedView.width; \n "
" var nHeight = CanvasDetailedView.height; \n "
" var ReferenceTime = 33; \n "
" var nHistoryHeight = 70; \n "
" var nOffsetY = 0; \n "
" var nOffsetBarsY = 0; \n "
" var nBarsWidth = 80; \n "
" var MouseButtonState = [0,0,0,0,0,0,0,0]; \n "
" var MouseDrag = 0; \n "
" var MouseZoom = 0; \n "
" var DetailedViewMouseX = 0; \n "
" var DetailedViewMouseY = 0; \n "
" var HistoryViewMouseX = -1; \n "
" var HistoryViewMouseY = -1; \n "
" var MouseHistory = 0; \n "
" var MouseDetailed = 0; \n "
" var FontHeight = 10; \n "
" var FontWidth = 1; \n "
" var FontAscent = 3; //Set manually \n "
" var Font = \' Bold \' + FontHeight + \' px Courier New \' ; \n "
" var BoxHeight = FontHeight + 2; \n "
" var ThreadsActive = new Object(); \n "
" var ThreadsAllActive = 1; \n "
" var GroupsActive = new Object(); \n "
" var GroupsAllActive = 1; \n "
" var nMinWidth = 0.5; \n "
" \n "
" var nModDown = 0; \n "
" var g_MSG = \' no \' ; \n "
" var nDrawCount = 0; \n "
" var nBackColors = [ \' #474747 \' , \' #313131 \' ]; \n "
" var nBackColorOffset = \' #606060 \' ; \n "
" var FRAME_HISTORY_COLOR_CPU = \' #ff7f27 \' ; \n "
" var FRAME_HISTORY_COLOR_GPU = \' #ffffff \' ; \n "
" var ZOOM_TIME = 0.5; \n "
" var AnimationActive = false; \n "
" var nHoverToken = -1; \n "
" var nHoverFrame = -1; \n "
" var nHoverTokenIndex = -1; \n "
" var nHoverTokenLogIndex = -1; \n "
" var nHoverCounter = 0; \n "
" var nHoverCounterDelta = 8; \n "
" \n "
" var fFrameScale = 33.33; \n "
" var fRangeBegin = 0; \n "
" var fRangeEnd = -1; \n "
" \n "
" var ModeDetailed = 0; \n "
" var ModeTimers = 1; \n "
" var Mode = ModeDetailed; \n "
" \n "
" var DebugDrawQuadCount = 0; \n "
" var DebugDrawTextCount = 0; \n "
" \n "
" \n "
" function InitFrameInfo() \n "
" { \n "
" var DetailedTotal = 0; \n "
" for(var i = 0; i < Frames.length; i++) \n "
" { \n "
" var frfr = Frames[i]; \n "
" DetailedTotal += frfr.frameend - frfr.framestart; \n "
" } \n "
" \n "
" var div = document.getElementById( \' divFrameInfo \' ); \n "
" var txt = \' \' ; \n "
" txt = txt + \' Timers View \' + \' <br> \' ; \n "
" txt = txt + \' Frames: \' + AggregateInfo.Frames + \' <br> \' ; \n "
" txt = txt + \' Time: \' + AggregateInfo.Time.toFixed(2) + \' ms<br> \' ; \n "
" txt = txt + \' <hr> \' ; \n "
" txt = txt + \' Detailed View \' + \' <br> \' ; \n "
" txt = txt + \' Frames: \' + Frames.length + \' <br> \' ; \n "
" txt = txt + \' Time: \' + DetailedTotal.toFixed(2) + \' ms<br> \' ; \n "
" div.innerHTML = txt; \n "
" } \n "
" function InitGroups() \n "
" { \n "
" for(groupid in GroupInfo) \n "
" { \n "
" var TimerArray = Array(); \n "
" for(timerid in TimerInfo) \n "
" { \n "
" if(TimerInfo[timerid].group == groupid) \n "
" { \n "
" TimerArray.push(timerid); \n "
" } \n "
" } \n "
" GroupInfo[groupid].TimerArray = TimerArray; \n "
" } \n "
" } \n "
" \n "
" function InitThreadMenu() \n "
" { \n "
" var ulThreadMenu = document.getElementById( \' ThreadSubMenu \' ); \n "
" var MaxLen = 7; \n "
" for(var idx in ThreadNames) \n "
" { \n "
" var name = ThreadNames[idx]; \n "
" var li = document.createElement( \' li \' ); \n "
" if(name.length > MaxLen) \n "
" { \n "
" MaxLen = name.length; \n "
" } \n "
" li.innerText = name; \n "
" var asText = li.innerHTML; \n "
" var html = \' <a href= \" # \" onclick= \" ToggleThread( \\ ' \' + name + \' \\ '); \" > \' + asText + \' </a> \' ; \n "
" li.innerHTML = html; \n "
" ulThreadMenu.appendChild(li); \n "
" } \n "
" var LenStr = (5+(1+MaxLen) * FontWidth) + \' px \' ; \n "
" var Lis = ulThreadMenu.getElementsByTagName( \' li \' ); \n "
" for(var i = 0; i < Lis.length; ++i) \n "
" { \n "
" Lis[i].style[ \' width \' ] = LenStr; \n "
" } \n "
" } \n "
" \n "
" function UpdateThreadMenu() \n "
" { \n "
" var ulThreadMenu = document.getElementById( \' ThreadSubMenu \' ); \n "
" var as = ulThreadMenu.getElementsByTagName( \' a \' ); \n "
" for(var i = 0; i < as.length; ++i) \n "
" { \n "
" var elem = as[i]; \n "
" var inner = elem.innerText; \n "
" var bActive = false; \n "
" if(i < 2) \n "
" { \n "
" if(inner == \' All \' ) \n "
" { \n "
" bActive = ThreadsAllActive; \n "
" } \n "
" } \n "
" else \n "
" { \n "
" bActive = ThreadsActive[inner]; \n "
" } \n "
" if(bActive) \n "
" { \n "
" elem.style[ \' text-decoration \' ] = \' underline \' ; \n "
" } \n "
" else \n "
" { \n "
" elem.style[ \' text-decoration \' ] = \' none \' ; \n "
" } \n "
" } \n "
" } \n "
" \n "
" function ToggleThread(ThreadName) \n "
" { \n "
" if(ThreadName) \n "
" { \n "
" if(ThreadsActive[ThreadName]) \n "
" { \n "
" ThreadsActive[ThreadName] = false; \n "
" } \n "
" else \n "
" { \n "
" ThreadsActive[ThreadName] = true; \n "
" } \n "
" } \n "
" else \n "
" { \n "
" if(ThreadsAllActive) \n "
" { \n "
" ThreadsAllActive = 0; \n "
" } \n "
" else \n "
" { \n "
" ThreadsAllActive = 1; \n "
" } \n "
" } \n "
" UpdateThreadMenu(); \n "
" WriteCookie(); \n "
" Draw(); \n "
" } \n "
" \n "
" \n "
" function InitGroupMenu() \n "
" { \n "
" var ulGroupMenu = document.getElementById( \' GroupSubMenu \' ); \n "
" var MaxLen = 7; \n "
" for(var idx in GroupInfo) \n "
" { \n "
" var name = GroupInfo[idx].name; \n "
" var li = document.createElement( \' li \' ); \n "
" if(name.length > MaxLen) \n "
" { \n "
" MaxLen = name.length; \n "
" } \n "
" li.innerText = name; \n "
" var asText = li.innerHTML; \n "
" var html = \' <a href= \" # \" onclick= \" ToggleGroup( \\ ' \' + name + \' \\ '); \" > \' + asText + \' </a> \' ; \n "
" li.innerHTML = html; \n "
" ulGroupMenu.appendChild(li); \n "
" } \n "
" var LenStr = (5+(1+MaxLen) * FontWidth) + \' px \' ; \n "
" var Lis = ulGroupMenu.getElementsByTagName( \' li \' ); \n "
" for(var i = 0; i < Lis.length; ++i) \n "
" { \n "
" Lis[i].style[ \' width \' ] = LenStr; \n "
" } \n "
" UpdateGroupMenu(); \n "
" } \n "
" \n "
" function UpdateGroupMenu() \n "
" { \n "
" var ulThreadMenu = document.getElementById( \' GroupSubMenu \' ); \n "
" var as = ulThreadMenu.getElementsByTagName( \' a \' ); \n "
" for(var i = 0; i < as.length; ++i) \n "
" { \n "
" var elem = as[i]; \n "
" var inner = elem.innerText; \n "
" var bActive = false; \n "
" if(i < 2) \n "
" { \n "
" if(inner == \' All \' ) \n "
" { \n "
" bActive = GroupsAllActive; \n "
" } \n "
" } \n "
" else \n "
" { \n "
" bActive = GroupsActive[inner]; \n "
" } \n "
" if(bActive) \n "
" { \n "
" elem.style[ \' text-decoration \' ] = \' underline \' ; \n "
" } \n "
" else \n "
" { \n "
" elem.style[ \' text-decoration \' ] = \' none \' ; \n "
" } \n "
" } \n "
" } \n "
" \n "
" \n "
" function ToggleGroup(GroupName) \n "
" { \n "
" if(GroupName) \n "
" { \n "
" if(GroupsActive[GroupName]) \n "
" { \n "
" GroupsActive[GroupName] = false; \n "
" } \n "
" else \n "
" { \n "
" GroupsActive[GroupName] = true; \n "
" } \n "
" } \n "
" else \n "
" { \n "
" if(GroupsAllActive) \n "
" { \n "
" GroupsAllActive = 0; \n "
" } \n "
" else \n "
" { \n "
" GroupsAllActive = 1; \n "
" } \n "
" } \n "
" UpdateGroupMenu(); \n "
" WriteCookie(); \n "
" Draw(); \n "
" } \n "
" \n "
" \n "
" \n "
" function SetMode(NewMode) \n "
" { \n "
" console.log( \' setmodemodemode \' + NewMode); \n "
" console.log( \' !!!mode is \' + NewMode); \n "
" var buttonTimers = document.getElementById( \' buttonTimers \' ); \n "
" var buttonDetailed = document.getElementById( \' buttonDetailed \' ); \n "
" var ilWidth = document.getElementById( \' ilWidth \' ); \n "
" var ilThreads = document.getElementById( \' ilThreads \' ); \n "
" var ilGroups = document.getElementById( \' ilGroups \' ); \n "
" if(NewMode == \' timers \' || NewMode == ModeTimers) \n "
" { \n "
" buttonTimers.style[ \' text-decoration \' ] = \' underline \' ; \n "
" buttonDetailed.style[ \' text-decoration \' ] = \' none \' ; \n "
" ilWidth.style[ \' display \' ] = \' none \' ; \n "
" ilThreads.style[ \' display \' ] = \' none \' ; \n "
" ilGroups.style[ \' display \' ] = \' block \' ; \n "
" Mode = ModeTimers; \n "
" } \n "
" else if(NewMode == \' detailed \' || NewMode == ModeDetailed) \n "
" { \n "
" buttonTimers.style[ \' text-decoration \' ] = \' none \' ; \n "
" buttonDetailed.style[ \' text-decoration \' ] = \' underline \' ; \n "
" ilWidth.style[ \' display \' ] = \' block \' ; \n "
" ilThreads.style[ \' display \' ] = \' block \' ; \n "
" ilGroups.style[ \' display \' ] = \' none \' ; \n "
" Mode = ModeDetailed; \n "
" } \n "
" WriteCookie(); \n "
" Draw(); \n "
" } \n "
" \n "
" function SetReferenceTime(TimeString) \n "
" { \n "
" ReferenceTime = parseInt(TimeString); \n "
" var ReferenceMenu = document.getElementById( \' ReferenceSubMenu \' ); \n "
" var Links = ReferenceMenu.getElementsByTagName( \' a \' ); \n "
" for(var i = 0; i < Links.length; ++i) \n "
" { \n "
" if(Links[i].innerHTML.match( \' ^ \' + TimeString)) \n "
" { \n "
" Links[i].style[ \' text-decoration \' ] = \' underline \' ; \n "
" } \n "
" else \n "
" { \n "
" Links[i].style[ \' text-decoration \' ] = \' none \' ; \n "
" } \n "
" } \n "
" WriteCookie(); \n "
" Draw(); \n "
" } \n "
" \n "
" function SetMinWidth(TimeString) \n "
" { \n "
" nMinWidth = parseFloat(TimeString); \n "
" var ReferenceMenu = document.getElementById( \' WidthMenu \' ); \n "
" var Links = ReferenceMenu.getElementsByTagName( \' a \' ); \n "
" for(var i = 0; i < Links.length; ++i) \n "
" { \n "
" if(Links[i].innerHTML.match( \' ^ \' + TimeString)) \n "
" { \n "
" Links[i].style[ \' text-decoration \' ] = \' underline \' ; \n "
" } \n "
" else \n "
" { \n "
" Links[i].style[ \' text-decoration \' ] = \' none \' ; \n "
" } \n "
" } \n "
" WriteCookie(); \n "
" Draw(); \n "
" } \n "
" \n "
" function GatherHoverMetaCounters(TimerIndex, StartIndex, nLog, nFrameLast) \n "
" { \n "
" var HoverInfo = new Object(); \n "
" var StackPos = 1; \n "
" //search backwards, count meta counters \n "
" for(var i = nFrameLast; i >= 0; i--) \n "
" { \n "
" var fr = Frames[i]; \n "
" var ts = fr.ts[nLog]; \n "
" var ti = fr.ti[nLog]; \n "
" var tt = fr.tt[nLog]; \n "
" var start = i == nFrameLast ? StartIndex-1 : ts.length-1; \n "
" \n "
" for(var j = start; j >= 0; j--) \n "
" { \n "
" var type = tt[j]; \n "
" var index = ti[j]; \n "
" var time = ts[j]; \n "
" if(type == 1) \n "
" { \n "
" StackPos--; \n "
" if(StackPos == 0 && index == TimerIndex) \n "
" { \n "
" return HoverInfo; \n "
" } \n "
" } \n "
" else if(type == 0) \n "
" { \n "
" StackPos++; \n "
" } \n "
" else \n "
" { \n "
" var nMetaCount = type - 2; \n "
" var nMetaIndex = MetaNames[index]; \n "
" if(nMetaIndex in HoverInfo) \n "
" { \n "
" HoverInfo[nMetaIndex] += nMetaCount; \n "
" } \n "
" else \n "
" { \n "
" HoverInfo[nMetaIndex] = nMetaCount; \n "
" } \n "
" } \n "
" } \n "
" } \n "
" \n "
" } \n "
" function CalculateTimers(Result, TimerIndex, nFrameFirst, nFrameLast) \n "
" { \n "
" //var Result = new Object(); \n "
" if(!nFrameFirst || nFrameFirst < 0) \n "
" nFrameFirst = 0; \n "
" if(!nFrameLast || nFrameLast > Frames.length) \n "
" nFrameLast = Frames.length; \n "
" var FrameCount = nFrameLast - nFrameFirst; \n "
" if(0 == FrameCount) \n "
" return; \n "
" var CallCount = 0; \n "
" var Sum = 0; \n "
" var Max = 0; \n "
" var FrameMax = 0; \n "
" \n "
" var nNumLogs = Frames[0].ts.length; \n "
" var StackPosArray = Array(nNumLogs); \n "
" var StackArray = Array(nNumLogs); \n "
" for(var i = 0; i < nNumLogs; ++i) \n "
" { \n "
" StackPosArray[i] = 0; \n "
" StackArray[i] = Array(20); \n "
" } \n "
" \n "
" for(var i = nFrameFirst; i < nFrameLast; i++) \n "
" { \n "
" var FrameSum = 0; \n "
" var fr = Frames[i]; \n "
" for(nLog = 0; nLog < nNumLogs; nLog++) \n "
" { \n "
" var StackPos = StackPosArray[nLog]; \n "
" var Stack = StackArray[nLog]; \n "
" var ts = fr.ts[nLog]; \n "
" var ti = fr.ti[nLog]; \n "
" var tt = fr.tt[nLog]; \n "
" var count = ts.length; \n "
" for(j = 0; j < count; j++) \n "
" { \n "
" var type = tt[j]; \n "
" var index = ti[j]; \n "
" var time = ts[j]; \n "
" if(type == 1) //enter \n "
" { \n "
" //push \n "
" Stack[StackPos] = time; \n "
" if(StackArray[nLog][StackPos] != time) \n "
" { \n "
" console.log( \' fail fail fail \' ); \n "
" } \n "
" StackPos++; \n "
" } \n "
" else if(type == 0) // leave \n "
" { \n "
" var timestart; \n "
" var timeend = time; \n "
" if(StackPos>0) \n "
" { \n "
" StackPos--; \n "
" timestart = Stack[StackPos]; \n "
" } \n "
" else \n "
" { \n "
" timestart = Frames[nFrameFirst].framestart; \n "
" } \n "
" if(index == TimerIndex) \n "
" { \n "
" var TimeDelta = timeend - timestart; \n "
" CallCount++; \n "
" FrameSum += TimeDelta; \n "
" Sum += TimeDelta; \n "
" if(TimeDelta > Max) \n "
" Max = TimeDelta; \n "
" } \n "
" } \n "
" else \n "
" { \n "
" //meta \n "
" } \n "
" } \n "
" if(FrameSum > FrameMax) \n "
" { \n "
" FrameMax = FrameSum; \n "
" } \n "
" StackPosArray[nLog] = StackPos; \n "
" } \n "
" } \n "
" \n "
" Result.CallCount = CallCount; \n "
" Result.Sum = Sum.toFixed(3); \n "
" Result.Max = Max.toFixed(3); \n "
" Result.Average = (Sum / CallCount).toFixed(3); \n "
" Result.FrameAverage = (Sum / FrameCount).toFixed(3); \n "
" Result.FrameCallAverage = (CallCount / FrameCount).toFixed(3); \n "
" Result.FrameMax = FrameMax.toFixed(3); \n "
" return Result; \n "
" \n "
" } \n "
" \n "
" function DrawDetailedFrameHistory() \n "
" { \n "
" var x = HistoryViewMouseX; \n "
" \n "
" var context = CanvasHistory.getContext( \' 2d \' ); \n "
" context.clearRect(0, 0, CanvasHistory.width, CanvasHistory.height); \n "
" \n "
" var fHeight = nHistoryHeight; \n "
" var fWidth = nWidth / Frames.length; \n "
" var fHeightScale = fHeight / ReferenceTime; \n "
" var fX = 0; \n "
" var FrameIndex = -1; \n "
" \n "
" for(i = 0; i < Frames.length; i++) \n "
" { \n "
" var fMs = Frames[i].frameend - Frames[i].framestart; \n "
" var fH = fHeightScale * fMs; \n "
" var bMouse = x > fX && x < fX + fWidth; \n "
" if(bMouse) \n "
" { \n "
" context.fillStyle = FRAME_HISTORY_COLOR_GPU; \n "
" fRangeBegin = Frames[i].framestart; \n "
" fRangeEnd = Frames[i].frameend; \n "
" FrameIndex = i; \n "
" } \n "
" else \n "
" { \n "
" context.fillStyle = FRAME_HISTORY_COLOR_CPU; \n "
" } \n "
" context.fillRect(fX, fHeight - fH, fWidth-1, fH); \n "
" fX += fWidth; \n "
" } \n "
" \n "
" if(FrameIndex>=0) \n "
" { \n "
" var StringArray = []; \n "
" StringArray.push( \" Frame \" ); \n "
" StringArray.push( \" \" + FrameIndex); \n "
" StringArray.push( \" Time \" ); \n "
" StringArray.push( \" \" + (Frames[FrameIndex].frameend - Frames[FrameIndex].framestart).toFixed(3)); \n "
" \n "
" DrawToolTip(StringArray, CanvasHistory, HistoryViewMouseX, HistoryViewMouseY+20); \n "
" \n "
" } \n "
" \n "
" } \n "
" \n "
" function DrawDetailedBackground() \n "
" { \n "
" var context = CanvasDetailedView.getContext( \' 2d \' ); \n "
" var fMs = fDetailedRange; \n "
" var fMsEnd = fMs + fDetailedOffset; \n "
" var fMsToScreen = nWidth / fMs; \n "
" var fRate = Math.floor(2*((Math.log(fMs)/Math.log(10))-1))/2; \n "
" var fStep = Math.pow(10, fRate); \n "
" var fRcpStep = 1.0 / fStep; \n "
" var nColorIndex = Math.floor(fDetailedOffset * fRcpStep) % 2; \n "
" if(nColorIndex < 0) \n "
" nColorIndex = -nColorIndex; \n "
" var fStart = Math.floor(fDetailedOffset * fRcpStep) * fStep; \n "
" var fHeight = CanvasDetailedView.height; \n "
" var fScaleX = nWidth / fDetailedRange; \n "
" for(f = fStart; f < fMsEnd; ) \n "
" { \n "
" var fNext = f + fStep; \n "
" var X = (f - fDetailedOffset) * fScaleX; \n "
" var W = (fNext-f)*fScaleX; \n "
" context.fillStyle = nBackColors[nColorIndex]; \n "
" context.fillRect(X, 0, W+2, fHeight); \n "
" nColorIndex = 1 - nColorIndex; \n "
" f = fNext; \n "
" } \n "
" var fScaleX = nWidth / fDetailedRange; \n "
" context.globalAlpha = 0.5; \n "
" context.strokeStyle = \' #bbbbbb \' ; \n "
" context.beginPath(); \n "
" for(var i = 0; i < Frames.length; i++) \n "
" { \n "
" var frfr = Frames[i]; \n "
" if(frfr.frameend < fDetailedOffset || frfr.framestart > fDetailedOffset + fDetailedRange) \n "
" { \n "
" continue; \n "
" } \n "
" var X = (frfr.framestart - fDetailedOffset) * fScaleX; \n "
" if(X >= 0 && X < nWidth) \n "
" { \n "
" context.moveTo(X, 0); \n "
" context.lineTo(X, nHeight); \n "
" } \n "
" } \n "
" context.stroke(); \n "
" context.globalAlpha = 1; \n "
" \n "
" } \n "
" function DrawToolTip(StringArray, Canvas, x, y) \n "
" { \n "
" var context = Canvas.getContext( \' 2d \' ); \n "
" context.font = Font; \n "
" var WidthArray = Array(StringArray.length); \n "
" var nMaxWidth = 0; \n "
" var nHeight = 0; \n "
" for(i = 0; i < StringArray.length; i += 2) \n "
" { \n "
" var nWidth0 = context.measureText(StringArray[i]).width; \n "
" var nWidth1 = context.measureText(StringArray[i+1]).width; \n "
" var nSum = nWidth0 + nWidth1; \n "
" WidthArray[i] = nWidth0; \n "
" WidthArray[i+1] = nWidth1; \n "
" if(nSum > nMaxWidth) \n "
" { \n "
" nMaxWidth = nSum; \n "
" } \n "
" nHeight += BoxHeight; \n "
" } \n "
" nMaxWidth += 15; \n "
" //bounds check. \n "
" var CanvasRect = Canvas.getBoundingClientRect(); \n "
" if(y + nHeight > CanvasRect.height) \n "
" { \n "
" y = CanvasRect.height - nHeight; \n "
" x += 20; \n "
" } \n "
" if(x + nMaxWidth > CanvasRect.width) \n "
" { \n "
" x = CanvasRect.width - nMaxWidth; \n "
" } \n "
" \n "
" context.fillStyle = \' black \' ; \n "
" context.fillRect(x-1, y, nMaxWidth+2, nHeight); \n "
" context.fillStyle = \' white \' ; \n "
" \n "
" var XPos = x; \n "
" var XPosRight = x + nMaxWidth; \n "
" var YPos = y + BoxHeight-2; \n "
" for(i = 0; i < StringArray.length; i += 2) \n "
" { \n "
" context.fillText(StringArray[i], XPos, YPos); \n "
" context.fillText(StringArray[i+1], XPosRight - WidthArray[i+1], YPos); \n "
" YPos += BoxHeight; \n "
" } \n "
" } \n "
" function DrawHoverToolTip() \n "
" { \n "
" if(nHoverToken != -1) \n "
" { \n "
" var StringArray = []; \n "
" var groupid = TimerInfo[nHoverToken].group; \n "
" StringArray.push(GroupInfo[groupid].name); \n "
" StringArray.push(TimerInfo[nHoverToken].name); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" Time \" ); \n "
" StringArray.push((fRangeEnd-fRangeBegin).toFixed(3)); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" Total \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].Sum); \n "
" StringArray.push( \" Max \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].Max); \n "
" StringArray.push( \" Average \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].Average); \n "
" StringArray.push( \" Count \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].CallCount); \n "
" \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" \" ); \n "
" \n "
" StringArray.push( \" Max/Frame \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].FrameMax); \n "
" \n "
" StringArray.push( \" Average Time/Frame \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].FrameAverage); \n "
" \n "
" StringArray.push( \" Average Count/Frame \" ); \n "
" StringArray.push( \" \" + TimerInfo[nHoverToken].FrameCallAverage); \n "
" \n "
" \n "
" if(nHoverFrame != -1) \n "
" { \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" Frame \" + nHoverFrame); \n "
" StringArray.push( \" \" ); \n "
" \n "
" var FrameTime = new Object(); \n "
" CalculateTimers(FrameTime, nHoverToken, nHoverFrame, nHoverFrame+1); \n "
" StringArray.push( \" Total \" ); \n "
" StringArray.push( \" \" + FrameTime.Sum); \n "
" StringArray.push( \" Count \" ); \n "
" StringArray.push( \" \" + FrameTime.CallCount); \n "
" StringArray.push( \" Average \" ); \n "
" StringArray.push( \" \" + FrameTime.Average); \n "
" StringArray.push( \" Max \" ); \n "
" StringArray.push( \" \" + FrameTime.Max); \n "
" } \n "
" \n "
" var HoverInfo = GatherHoverMetaCounters(nHoverToken, nHoverTokenIndex, nHoverTokenLogIndex, nHoverFrame); \n "
" var Header = 0; \n "
" for(index in HoverInfo) \n "
" { \n "
" if(0 == Header) \n "
" { \n "
" Header = 1; \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" \" ); \n "
" StringArray.push( \" Meta \" ); \n "
" StringArray.push( \" \" ); \n "
" \n "
" } \n "
" StringArray.push( \" \" +index); \n "
" StringArray.push( \" \" +HoverInfo[index]); \n "
" } \n "
" DrawToolTip(StringArray, CanvasDetailedView, DetailedViewMouseX, DetailedViewMouseY+20); \n "
" \n "
" } \n "
" } \n "
" \n "
" \n "
" function DrawBarView() \n "
" { \n "
" console.log( \' bar view view \' ); \n "
" nHoverToken = -1; \n "
" nHoverFrame = -1; \n "
" var context = CanvasDetailedView.getContext( \' 2d \' ); \n "
" context.clearRect(0, 0, nWidth, nHeight); \n "
" \n "
" var Height = BoxHeight; \n "
" var Width = nWidth; \n "
" \n "
" //clamp offset to prevent scrolling into the void \n "
" var nTotalRows = 0; \n "
" for(var groupid in GroupInfo) \n "
" { \n "
" if(GroupsAllActive || GroupsActive[GroupInfo[groupid].name]) \n "
" { \n "
" nTotalRows += GroupInfo[groupid].TimerArray.length + 1; \n "
" } \n "
" } \n "
" var nTotalRowPixels = nTotalRows * Height; \n "
" var nFrameRows = nHeight - BoxHeight; \n "
" if(nOffsetBarsY + nFrameRows > nTotalRowPixels && nTotalRowPixels > nFrameRows) \n "
" { \n "
" nOffsetBarsY = nTotalRowPixels - nFrameRows; \n "
" } \n "
" \n "
" \n "
" var Y = -nOffsetBarsY + BoxHeight; \n "
" var nColorIndex = 0; \n "
" \n "
" context.fillStyle = \' white \' ; \n "
" context.font = Font; \n "
" var bMouseIn = 0; \n "
" var RcpReferenceTime = 1.0 / ReferenceTime; \n "
" var CountWidth = 8 * FontWidth; \n "
" var nMetaLen = TimerInfo[0].meta.length; \n "
" var nMetaCharacters = 10; \n "
" for(var i = 0; i < nMetaLen; ++i) \n "
" { \n "
" if(nMetaCharacters < MetaNames[i].length) \n "
" nMetaCharacters = MetaNames[i].length; \n "
" } \n "
" var nWidthMeta = nMetaCharacters * FontWidth + 6; \n "
" \n "
" \n "
" \n "
" for(var groupid in GroupInfo) \n "
" { \n "
" var Group = GroupInfo[groupid]; \n "
" if(GroupsAllActive || GroupsActive[Group.name]) \n "
" { \n "
" //write header \n "
" nColorIndex = 1-nColorIndex; \n "
" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight; \n "
" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex]; \n "
" context.fillRect(0, Y, Width, Height); \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(Group.name, 1, Y+Height-FontAscent); \n "
" \n "
" \n "
" Y += Height; \n "
" var TimerArray = Group.TimerArray; \n "
" var InnerBoxHeight = BoxHeight-2; \n "
" var TimerLen = 6; \n "
" var TimerWidth = TimerLen * FontWidth; \n "
" var nWidthBars = nBarsWidth+2; \n "
" var nWidthMs = TimerWidth + 2 + 10; \n "
" \n "
" \n "
" for(var timerindex in TimerArray) \n "
" { \n "
" var timerid = TimerArray[timerindex]; \n "
" var X = 0; \n "
" nColorIndex = 1-nColorIndex; \n "
" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight; \n "
" if(bMouseIn) \n "
" { \n "
" nHoverToken = timerid; \n "
" } \n "
" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex]; \n "
" context.fillRect(X, Y, Width, Height); \n "
" \n "
" var Timer = TimerInfo[timerid]; \n "
" \n "
" var Average = Timer.average; \n "
" var Max = Timer.max; \n "
" var ExclusiveMax = Timer.exclmax; \n "
" var ExclusiveAverage = Timer.exclaverage; \n "
" var CallAverage = Timer.callaverage; \n "
" var CallCount = Timer.callcount; \n "
" var YText = Y+Height-FontAscent; \n "
" function DrawTimer(Value) \n "
" { \n "
" var Prc = Value * RcpReferenceTime; \n "
" if(Prc > 1) \n "
" { \n "
" Prc = 1; \n "
" } \n "
" context.fillStyle = Timer.color; \n "
" context.fillRect(X+1, Y+1, Prc * nBarsWidth, InnerBoxHeight); \n "
" X += nWidthBars; \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(( \" \" + Value.toFixed(2)).slice(-TimerLen), X, YText); \n "
" X += nWidthMs; \n "
" } \n "
" function DrawMeta(Value) \n "
" { \n "
" if(!Value) \n "
" { \n "
" Value = \" 0 \" ; \n "
" } \n "
" else \n "
" { \n "
" Value = \' \' + Value; \n "
" } \n "
" context.fillText(Value, X + nWidthMeta - 6 - Value.length * FontWidth, YText); \n "
" X += nWidthMeta; \n "
" } \n "
" \n "
" DrawTimer(Average); \n "
" DrawTimer(Max); \n "
" DrawTimer(CallAverage); \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(CallCount, X, YText); \n "
" X += CountWidth; \n "
" DrawTimer(ExclusiveAverage); \n "
" DrawTimer(ExclusiveMax); \n "
" \n "
" context.fillStyle = \' white \' ; \n "
" for(var j = 0; j < nMetaLen; ++j) \n "
" { \n "
" DrawMeta(Timer.meta[j]); \n "
" } \n "
" \n "
" \n "
" context.fillStyle = Timer.color; \n "
" context.fillText(Timer.name, X+1, YText); \n "
" Y += Height; \n "
" \n "
" } \n "
" } \n "
" } \n "
" X = 0; \n "
" context.fillStyle = nBackColorOffset; \n "
" context.fillRect(0, 0, Width, Height); \n "
" context.fillStyle = \' white \' ; \n "
" \n "
" \n "
" function DrawHeaderSplit(Header) \n "
" { \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(Header, X, Height-FontAscent); \n "
" X += nWidthBars; \n "
" context.fillStyle = nBackColorOffset; \n "
" X += nWidthMs; \n "
" context.fillRect(X-3, 0, 1, nHeight); \n "
" } \n "
" function DrawHeaderSplitSingle(Header, Width) \n "
" { \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(Header, X, Height-FontAscent); \n "
" X += Width; \n "
" context.fillStyle = nBackColorOffset; \n "
" context.fillRect(X-3, 0, 1, nHeight); \n "
" } \n "
" \n "
" \n "
" DrawHeaderSplit( \' Average \' ); \n "
" DrawHeaderSplit( \' Max \' ); \n "
" DrawHeaderSplit( \' Call Average \' ); \n "
" DrawHeaderSplitSingle( \' Count \' , CountWidth); \n "
" DrawHeaderSplit( \' Excl Average \' ); \n "
" DrawHeaderSplit( \' Excl Max \' ); \n "
" for(var i = 0; i < nMetaLen; ++i) \n "
" { \n "
" DrawHeaderSplitSingle(MetaNames[i], nWidthMeta); \n "
" } \n "
" DrawHeaderSplit( \' Name \' ); \n "
" \n "
" } \n "
" \n "
" function DrawDetailed(Animation) \n "
" { \n "
" if(AnimationActive != Animation) \n "
" { \n "
" return; \n "
" } \n "
" DebugDrawQuadCount = 0; \n "
" DebugDrawTextCount = 0; \n "
" \n "
" \n "
" var start = new Date(); \n "
" nDrawCount++; \n "
" \n "
" var context = CanvasDetailedView.getContext( \' 2d \' ); \n "
" context.clearRect(0, 0, CanvasDetailedView.width, CanvasDetailedView.height); \n "
" \n "
" DrawDetailedBackground(); \n "
" \n "
" var colors = [ \' #ff0000 \' , \' #ff00ff \' , \' #ffff00 \' ]; \n "
" \n "
" var fScaleX = nWidth / fDetailedRange; \n "
" var fOffsetY = -nOffsetY + BoxHeight; \n "
" var nHoverTokenNext = -1; \n "
" var nHoverTokenLogIndexNext = -1; \n "
" var nHoverTokenIndexNext = -1; \n "
" nHoverCounter += nHoverCounterDelta; \n "
" if(nHoverCounter >= 255) \n "
" { \n "
" nHoverCounter = 255; \n "
" nHoverCounterDelta = -nHoverCounterDelta; \n "
" } \n "
" if(nHoverCounter < 128) \n "
" { \n "
" nHoverCounter = 128; \n "
" nHoverCounterDelta = -nHoverCounterDelta; \n "
" } \n "
" var nHoverHigh = nHoverCounter.toString(16); \n "
" var nHoverLow = (127+255-nHoverCounter).toString(16); \n "
" var nHoverColor = \' # \' + nHoverHigh + nHoverHigh + nHoverHigh; \n "
" \n "
" context.fillStyle = \' black \' ; \n "
" context.font = Font; \n "
" var nNumLogs = Frames[0].ts.length; \n "
" for(nLog = 0; nLog < nNumLogs; nLog++) \n "
" { \n "
" var ThreadName = ThreadNames[nLog]; \n "
" if(ThreadsAllActive || ThreadsActive[ThreadName]) \n "
" { \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText(ThreadName, 0, fOffsetY); \n "
" fOffsetY += BoxHeight; \n "
" \n "
" var MaxDepth = 1; \n "
" var StackPos = 0; \n "
" var Stack = Array(20); \n "
" \n "
" for(var i = 0; i < Frames.length; i++) \n "
" { \n "
" var frfr = Frames[i]; \n "
" if(0 == StackPos && frfr.framestart > fDetailedOffset + fDetailedRange) \n "
" { \n "
" continue; \n "
" } \n "
" var ts = frfr.ts[nLog]; \n "
" var ti = frfr.ti[nLog]; \n "
" var tt = frfr.tt[nLog]; \n "
" var count = ts.length; \n "
" \n "
" for(j = 0; j < count; j++) \n "
" { \n "
" var type = tt[j]; \n "
" var index = ti[j]; \n "
" var time = ts[j]; \n "
" if(type == 1) \n "
" { \n "
" //push \n "
" Stack[StackPos] = time; \n "
" StackPos++; \n "
" if(StackPos > MaxDepth) \n "
" { \n "
" MaxDepth = StackPos; \n "
" } \n "
" } \n "
" else if(type == 0) \n "
" { \n "
" if(StackPos>0) \n "
" { \n "
" StackPos--; \n "
" var timestart = Stack[StackPos]; \n "
" var timeend = time; \n "
" var X = (timestart - fDetailedOffset) * fScaleX; \n "
" var Y = fOffsetY + StackPos * BoxHeight; \n "
" var W = (timeend-timestart)*fScaleX; \n "
" \n "
" if(W > nMinWidth && X < nWidth && X+W > 0) \n "
" { \n "
" if(index == nHoverToken) \n "
" { \n "
" context.fillStyle = nHoverColor; \n "
" context.fillRect(X, Y, W, BoxHeight-1); \n "
" } \n "
" else \n "
" { \n "
" context.fillStyle = TimerInfo[index].color; \n "
" context.fillRect(X, Y, W, BoxHeight-1); \n "
" } \n "
" DebugDrawQuadCount++; \n "
" \n "
" var XText = X < 0 ? 0 : X; \n "
" var WText = W - (XText-X); \n "
" var name = TimerInfo[index].name; \n "
" var len = TimerInfo[index].len; \n "
" var sublen = Math.floor((WText-2)/FontWidth); \n "
" if(sublen >= 2) \n "
" { \n "
" if(sublen < len) \n "
" name = name.substr(0, sublen); \n "
" context.fillStyle = InvertColor(TimerInfo[index].color); \n "
" context.fillText(name, XText+1, Y+BoxHeight-FontAscent); \n "
" DebugDrawTextCount++; \n "
" } \n "
" if(DetailedViewMouseX >= X && DetailedViewMouseX <= X+W && DetailedViewMouseY < Y+BoxHeight && DetailedViewMouseY >= Y) \n "
" { \n "
" fRangeBegin = timestart; \n "
" fRangeEnd = timeend; \n "
" nHoverTokenNext = index; \n "
" nHoverTokenIndexNext = j; \n "
" nHoverTokenLogIndexNext = nLog; \n "
" nHoverFrame = i; \n "
" } \n "
" } \n "
" } \n "
" } \n "
" } \n "
" } \n "
" fOffsetY += (1+MaxDepth) * BoxHeight; \n "
" } \n "
" } \n "
" if(MouseDrag || MouseZoom) \n "
" { \n "
" nHoverToken = -1; \n "
" nHoverTokenIndex = -1; \n "
" nHoverTokenLogIndex = -1; \n "
" \n "
" fRangeBegin = fRangeEnd = -1; \n "
" } \n "
" else \n "
" { \n "
" nHoverToken = nHoverTokenNext; \n "
" nHoverTokenIndex = nHoverTokenIndexNext; \n "
" nHoverTokenLogIndex = nHoverTokenLogIndexNext; \n "
" \n "
" } \n "
" \n "
" \n "
" \n "
" if(fRangeBegin < fRangeEnd) \n "
" { \n "
" var X = (fRangeBegin - fDetailedOffset) * fScaleX; \n "
" var Y = 0; \n "
" var W = (fRangeEnd - fRangeBegin) * fScaleX; \n "
" context.globalAlpha = 0.1; \n "
" context.fillStyle = \' #009900 \' ; \n "
" context.fillRect(X, Y, W, nHeight); \n "
" context.globalAlpha = 1; \n "
" context.strokeStyle = \' #00ff00 \' ; \n "
" context.beginPath(); \n "
" context.moveTo(X, Y); \n "
" context.lineTo(X, Y+nHeight); \n "
" context.moveTo(X+W, Y); \n "
" context.lineTo(X+W, Y+nHeight); \n "
" context.stroke(); \n "
" var tRangeBeginWidth = context.measureText( \' \' + fRangeBegin).width; \n "
" \n "
" context.fillStyle = \' white \' ; \n "
" context.fillText( \' \' + fRangeBegin, X - tRangeBeginWidth-2, 9); \n "
" context.fillText( \' \' + fRangeEnd, X + W, 9); \n "
" } \n "
" \n "
" \n "
" \n "
" \n "
" \n "
" var end = new Date(); \n "
" var time = end - start; \n "
" var timeTaken = \' TIME \' + time + \' ms \' ; \n "
" if(false) \n "
" { \n "
" context.fillStyle = \' white \' ; \n "
" context.font = \' italic 12pt Calibri \' ; \n "
" context.fillText(timeTaken+ \" \" + nDrawCount + \" ... \" + g_MSG + \" Q: \" + DebugDrawQuadCount + \" T: \" + DebugDrawTextCount, 20, 20); \n "
" g_MSG = \' \' ; \n "
" } \n "
" } \n "
" \n "
" function ZoomTo(fZoomBegin, fZoomEnd) \n "
" { \n "
" if(fZoomBegin < fZoomEnd) \n "
" { \n "
" AnimationActive = true; \n "
" var fDetailedOffsetOriginal = fDetailedOffset; \n "
" var fDetailedRangeOriginal = fDetailedRange; \n "
" var fDetailedOffsetTarget = fZoomBegin; \n "
" var fDetailedRangeTarget = fZoomEnd - fZoomBegin; \n "
" var TimestampStart = new Date(); \n "
" var count = 0; \n "
" function ZoomFunc(Timestamp) \n "
" { \n "
" var fPrc = (new Date() - TimestampStart) / (ZOOM_TIME * 1000.0); \n "
" if(fPrc > 1.0) \n "
" { \n "
" fPrc = 1.0; \n "
" } \n "
" fPrc = Math.pow(fPrc, 0.3); \n "
" fDetailedOffset = fDetailedOffsetOriginal + (fDetailedOffsetTarget - fDetailedOffsetOriginal) * fPrc; \n "
" fDetailedRange = fDetailedRangeOriginal + (fDetailedRangeTarget - fDetailedRangeOriginal) * fPrc; \n "
" DrawDetailed(true); \n "
" if(fPrc >= 1.0) \n "
" { \n "
" AnimationActive = false; \n "
" fDetailedOffset = fDetailedOffsetTarget; \n "
" fDetailedRange = fDetailedRangeTarget; \n "
" } \n "
" else \n "
" { \n "
" requestAnimationFrame(ZoomFunc); \n "
" } \n "
" } \n "
" requestAnimationFrame(ZoomFunc); \n "
" } \n "
" } \n "
" function Draw() \n "
" { \n "
" \n "
" console.log( \' drawing \' + Mode); \n "
" if(Mode == ModeTimers) \n "
" { \n "
" DrawBarView(); \n "
" } \n "
" else if(Mode == ModeDetailed) \n "
" { \n "
" DrawDetailed(false); \n "
" DrawHoverToolTip(); \n "
" } \n "
" DrawDetailedFrameHistory(); \n "
" } \n "
" function AutoRedraw(Timestamp) \n "
" { \n "
" if(Mode == ModeDetailed) \n "
" { \n "
" if(nHoverToken != -1 && !MouseZoom && !MouseDrag) \n "
" { \n "
" DrawDetailed(false); \n "
" DrawHoverToolTip(); \n "
" } \n "
" } \n "
" requestAnimationFrame(AutoRedraw); \n "
" } \n "
" \n "
" \n "
" function ZoomGraph(nZoom) \n "
" { \n "
" var fOldRange = fDetailedRange; \n "
" if(nZoom>0) \n "
" { \n "
" fDetailedRange *= Math.pow(nModDown ? 1.40 : 1.03, nZoom); \n "
" } \n "
" else \n "
" { \n "
" var fNewDetailedRange = fDetailedRange / Math.pow((nModDown ? 1.40 : 1.03), -nZoom); \n "
" if(fNewDetailedRange < 0.0001) //100ns \n "
" fNewDetailedRange = 0.0001; \n "
" fDetailedRange = fNewDetailedRange; \n "
" } \n "
" \n "
" var fDiff = fOldRange - fDetailedRange; \n "
" var fMousePrc = DetailedViewMouseX / nWidth; \n "
" if(fMousePrc < 0) \n "
" { \n "
" fMousePrc = 0; \n "
" } \n "
" fDetailedOffset += fDiff * fMousePrc; \n "
" \n "
" } \n "
" \n "
" function MeasureFont() \n "
" { \n "
" var context = CanvasDetailedView.getContext( \' 2d \' ); \n "
" context.font = Font; \n "
" FontWidth = context.measureText( \' W \' ).width; \n "
" \n "
" } \n "
" function ResizeCanvas() \n "
" { \n "
" nWidth = window.innerWidth; \n "
" nHeight = window.innerHeight - CanvasHistory.height-2; \n "
" var DPR = window.devicePixelRatio; \n "
" if(DPR) \n "
" { \n "
" CanvasDetailedView.style.width = nWidth + \' px \' ; \n "
" CanvasDetailedView.style.height = nHeight + \' px \' ; \n "
" CanvasDetailedView.width = nWidth * DPR; \n "
" CanvasDetailedView.height = nHeight * DPR; \n "
" CanvasHistory.style.width = window.innerWidth + \' px \' ; \n "
" CanvasHistory.style.height = 70 + \' px \' ; \n "
" CanvasHistory.width = window.innerWidth * DPR; \n "
" CanvasHistory.height = 70 * DPR; \n "
" CanvasHistory.getContext( \' 2d \' ).scale(DPR,DPR); \n "
" CanvasDetailedView.getContext( \' 2d \' ).scale(DPR,DPR); \n "
" \n "
" \n "
" } \n "
" else \n "
" { \n "
" CanvasDetailedView.width = nWidth; \n "
" CanvasDetailedView.height = nHeight; \n "
" CanvasHistory.width = window.innerWidth; \n "
" } \n "
" Draw(); \n "
" } \n "
" \n "
" function MouseMove(evt) \n "
" { \n "
" MouseHistory = 0; \n "
" MouseDetailed = 0; \n "
" HistoryViewMouseX = HistoryViewMouseY = -1; \n "
" if(evt.target == CanvasDetailedView) \n "
" { \n "
" fRangeBegin = fRangeEnd = -1; \n "
" var rect = CanvasDetailedView.getBoundingClientRect(); \n "
" var x = evt.clientX - rect.left; \n "
" var y = evt.clientY - rect.top; \n "
" if(Mode == ModeDetailed) \n "
" { \n "
" if(MouseDrag) \n "
" { \n "
" var X = x - DetailedViewMouseX; \n "
" var Y = y - DetailedViewMouseY; \n "
" if(X) \n "
" { \n "
" fDetailedOffset += -X * fDetailedRange / nWidth; \n "
" } \n "
" nOffsetY -= Y; \n "
" if(nOffsetY < 0) \n "
" { \n "
" nOffsetY = 0; \n "
" } \n "
" } \n "
" if(MouseZoom) \n "
" { \n "
" if(y != DetailedViewMouseY) \n "
" { \n "
" ZoomGraph(y - DetailedViewMouseY); \n "
" } \n "
" } \n "
" } \n "
" else if(Mode == ModeTimers) \n "
" { \n "
" if(MouseDrag) \n "
" { \n "
" var X = x - DetailedViewMouseX; \n "
" var Y = y - DetailedViewMouseY; \n "
" nOffsetBarsY -= Y; \n "
" if(nOffsetBarsY < 0) \n "
" { \n "
" nOffsetBarsY = 0; \n "
" } \n "
" } \n "
" } \n "
" DetailedViewMouseX = x; \n "
" DetailedViewMouseY = y; \n "
" } \n "
" else if(evt.target = CanvasHistory) \n "
" { \n "
" var Rect = CanvasHistory.getBoundingClientRect(); \n "
" HistoryViewMouseX = evt.clientX - Rect.left; \n "
" HistoryViewMouseY = evt.clientY - Rect.top; \n "
" } \n "
" Draw(); \n "
" } \n "
" function MouseButton(bPressed, evt) \n "
" { \n "
" if(evt.target == CanvasHistory) \n "
" { \n "
" if(!bPressed) \n "
" { \n "
" if(evt.button == 0) \n "
" { \n "
" ZoomTo(fRangeBegin, fRangeEnd); \n "
" } \n "
" } \n "
" } \n "
" else if(evt.target == CanvasDetailedView) \n "
" { \n "
" var rect = CanvasDetailedView.getBoundingClientRect(); \n "
" var x = evt.clientX - rect.left; \n "
" var y = evt.clientY - rect.top; \n "
" if(bPressed) \n "
" { \n "
" MouseButtonState[evt.button]=1; \n "
" if(evt.button == 0) \n "
" { \n "
" } \n "
" } \n "
" else \n "
" { \n "
" MouseButtonState[evt.button]=1; \n "
" if(evt.button == 0) \n "
" { \n "
" ZoomTo(fRangeBegin, fRangeEnd); \n "
" } \n "
" } \n "
" } \n "
" } \n "
" function MouseOut(evt) \n "
" { \n "
" MouseZoom = 0; \n "
" MouseDrag = 0; \n "
" nHoverToken = -1; \n "
" fRangeBegin = fRangeEnd = -1; \n "
" } \n "
" \n "
" function KeyUp(evt) \n "
" { \n "
" if(evt.keyCode == 17) \n "
" { \n "
" MouseZoom = 0; \n "
" } \n "
" else if(evt.keyCode == 16) \n "
" { \n "
" MouseDrag = 0; \n "
" } \n "
" } \n "
" \n "
" function KeyDown(evt) \n "
" { \n "
" g_MSG = \' keycode \' + evt.keyCode; \n "
" if(evt.keyCode == 17) \n "
" { \n "
" MouseDrag = 0; \n "
" MouseZoom = 1; \n "
" } \n "
" else if(evt.keyCode == 16) \n "
" { \n "
" MouseDrag = 1; \n "
" } \n "
" } \n "
" \n "
" function ReadCookie() \n "
" { \n "
" var result = document.cookie.match(/fisk=([^;]+)/); \n "
" var NewMode = ModeDetailed; \n "
" var ReferenceTimeString = \' 33ms \' ; \n "
" var nMinWidth = 0.1; \n "
" if(result && result.length > 0) \n "
" { \n "
" var Obj = JSON.parse(result[1]); \n "
" if(Obj.Mode) \n "
" { \n "
" NewMode = Obj.Mode; \n "
" } \n "
" if(Obj.ReferenceTime) \n "
" { \n "
" ReferenceTimeString = Obj.ReferenceTime; \n "
" } \n "
" if(Obj.ThreadsAllActive || Obj.ThreadsAllActive == 0 || Obj.ThreadsAllActive == false) \n "
" { \n "
" ThreadsAllActive = Obj.ThreadsAllActive; \n "
" } \n "
" else \n "
" { \n "
" ThreadsAllActive = 1; \n "
" } \n "
" if(Obj.ThreadsActive) \n "
" { \n "
" ThreadsActive = Obj.ThreadsActive; \n "
" } \n "
" if(Obj.nMinWidth) \n "
" { \n "
" nMinWidth = Obj.nMinWidth; \n "
" } \n "
" if(Obj.GroupsAllActive || Obj.GroupsAllActive == 0 || Obj.GroupsAllActive) \n "
" { \n "
" GroupsAllActive = Obj.GroupsAllActive; \n "
" } \n "
" else \n "
" { \n "
" GroupsAllActive = 1; \n "
" } \n "
" if(Obj.GroupsActive) \n "
" { \n "
" GroupsActive = Obj.GroupsActive; \n "
" } \n "
" } \n "
" SetMode(NewMode); \n "
" SetReferenceTime(ReferenceTimeString); \n "
" SetMinWidth( \' \' + nMinWidth); \n "
" \n "
" } \n "
" function WriteCookie() \n "
" { \n "
" var Obj = new Object(); \n "
" Obj.Mode = Mode; \n "
" Obj.ReferenceTime = ReferenceTime + \' ms \' ; \n "
" Obj.ThreadsActive = ThreadsActive; \n "
" Obj.ThreadsAllActive = ThreadsAllActive; \n "
" Obj.GroupsActive = GroupsActive; \n "
" Obj.GroupsAllActive = GroupsAllActive; \n "
" Obj.nMinWidth = nMinWidth; \n "
" var date = new Date(); \n "
" date.setFullYear(2099); \n "
" var cookie = \' fisk= \' + JSON.stringify(Obj) + \' ;expires= \' + date; \n "
" document.cookie = cookie; \n "
" } \n "
" \n "
" CanvasDetailedView.addEventListener( \' mousemove \' , MouseMove, false); \n "
" CanvasDetailedView.addEventListener( \' mousedown \' , function(evt) { MouseButton(true, evt); }); \n "
" CanvasDetailedView.addEventListener( \' mouseup \' , function(evt) { MouseButton(false, evt); } ); \n "
" CanvasDetailedView.addEventListener( \' mouseout \' , MouseOut); \n "
" CanvasHistory.addEventListener( \' mousemove \' , MouseMove); \n "
" CanvasHistory.addEventListener( \' mousedown \' , function(evt) { MouseButton(true, evt); }); \n "
" CanvasHistory.addEventListener( \' mouseup \' , function(evt) { MouseButton(false, evt); } ); \n "
" CanvasHistory.addEventListener( \' mouseout \' , MouseOut); \n "
" window.addEventListener( \' keydown \' , KeyDown); \n "
" window.addEventListener( \' keyup \' , KeyUp); \n "
" window.addEventListener( \' resize \' , ResizeCanvas, false); \n "
" \n "
" \n "
" var start = new Date(); \n "
" for(var i = 0; i < TimerInfo.length; i++) \n "
" { \n "
" var v = CalculateTimers(TimerInfo[i], i); \n "
" \n "
" } \n "
" var end = new Date(); \n "
" var time = end - start; \n "
" console.log( \' setup :: \' + time + \' ms \' ); \n "
" \n "
" InitGroups(); \n "
" ReadCookie(); \n "
" MeasureFont() \n "
" InitThreadMenu(); \n "
" InitGroupMenu(); \n "
" InitFrameInfo(); \n "
" UpdateThreadMenu(); \n "
" ResizeCanvas(); \n "
" Draw(); \n "
" AutoRedraw(); \n "
" \n "
" </script> \n "
" </body> \n "
" </html> " ;
const size_t g_MicroProfileHtml_end_size = sizeof ( g_MicroProfileHtml_end ) ;
# endif //MICROPROFILE_EMBED_HTML
///end embedded file from microprofile.html