/ externals / microprofile / microprofile.h
microprofile.h
   1  #pragma once
   2  // This is free and unencumbered software released into the public domain.
   3  // Anyone is free to copy, modify, publish, use, compile, sell, or
   4  // distribute this software, either in source code form or as a compiled
   5  // binary, for any purpose, commercial or non-commercial, and by any
   6  // means.
   7  // In jurisdictions that recognize copyright laws, the author or authors
   8  // of this software dedicate any and all copyright interest in the
   9  // software to the public domain. We make this dedication for the benefit
  10  // of the public at large and to the detriment of our heirs and
  11  // successors. We intend this dedication to be an overt act of
  12  // relinquishment in perpetuity of all present and future rights to this
  13  // software under copyright law.
  14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  17  // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  // OTHER DEALINGS IN THE SOFTWARE.
  21  // For more information, please refer to <http://unlicense.org/>
  22  //
  23  // ***********************************************************************
  24  //
  25  //
  26  //
  27  //
  28  // Howto:
  29  // Call these functions from your code:
  30  //  MicroProfileOnThreadCreate
  31  //  MicroProfileMouseButton
  32  //  MicroProfileMousePosition
  33  //  MicroProfileModKey
  34  //  MicroProfileFlip                <-- Call this once per frame
  35  //  MicroProfileDraw                <-- Call this once per frame
  36  //  MicroProfileToggleDisplayMode   <-- Bind to a key to toggle profiling
  37  //  MicroProfileTogglePause         <-- Bind to a key to toggle pause
  38  //
  39  // Use these macros in your code in blocks you want to time:
  40  //
  41  //  MICROPROFILE_DECLARE
  42  //  MICROPROFILE_DEFINE
  43  //  MICROPROFILE_DECLARE_GPU
  44  //  MICROPROFILE_DEFINE_GPU
  45  //  MICROPROFILE_SCOPE
  46  //  MICROPROFILE_SCOPEI
  47  //  MICROPROFILE_SCOPEGPU
  48  //  MICROPROFILE_SCOPEGPUI
  49  //  MICROPROFILE_META
  50  //
  51  //
  52  //  Usage:
  53  //
  54  //  {
  55  //      MICROPROFILE_SCOPEI("GroupName", "TimerName", nColorRgb):
  56  //      ..Code to be timed..
  57  //  }
  58  //
  59  //  MICROPROFILE_DECLARE / MICROPROFILE_DEFINE allows defining groups in a shared place, to ensure sorting of the timers
  60  //
  61  //  (in global scope)
  62  //  MICROPROFILE_DEFINE(g_ProfileFisk, "Fisk", "Skalle", nSomeColorRgb);
  63  //
  64  //  (in some other file)
  65  //  MICROPROFILE_DECLARE(g_ProfileFisk);
  66  //
  67  //  void foo(){
  68  //      MICROPROFILE_SCOPE(g_ProfileFisk);
  69  //  }
  70  //
  71  //  Once code is instrumented the gui is activeted by calling MicroProfileToggleDisplayMode or by clicking in the upper left corner of
  72  //  the screen
  73  //
  74  // The following functions must be implemented before the profiler is usable
  75  //  debug render:
  76  //      void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
  77  //      void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType = MicroProfileBoxTypeFlat);
  78  //      void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor);
  79  //  Gpu time stamps: (See below for d3d/opengl helper)
  80  //      uint32_t MicroProfileGpuInsertTimeStamp();
  81  //      uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey);
  82  //      uint64_t MicroProfileTicksPerSecondGpu();
  83  //  threading:
  84  //      const char* MicroProfileGetThreadName(); Threadnames in detailed view
  85  //
  86  // Default implementations of Gpu timestamp functions:
  87  //      Opengl:
  88  //          in .c file where MICROPROFILE_IMPL is defined:
  89  //          #define MICROPROFILE_GPU_TIMERS_GL
  90  //          call MicroProfileGpuInitGL() on startup
  91  //      D3D11:
  92  //          in .c file where MICROPROFILE_IMPL is defined:
  93  //          #define MICROPROFILE_GPU_TIMERS_D3D11
  94  //          call MICROPROFILE_GPU_TIMERS_D3D11(). Pass Device & ImmediateContext
  95  //
  96  // Limitations:
  97  //  GPU timestamps can only be inserted from one thread.
  98  
  99  
 100  
 101  #ifndef MICROPROFILE_ENABLED
 102  #define MICROPROFILE_ENABLED 1
 103  #endif
 104  
 105  #include <stdint.h>
 106  typedef uint64_t MicroProfileToken;
 107  typedef uint16_t MicroProfileGroupId;
 108  
 109  #if 0 == MICROPROFILE_ENABLED
 110  
 111  #define MICROPROFILE_DECLARE(var)
 112  #define MICROPROFILE_DEFINE(var, group, name, color)
 113  #define MICROPROFILE_REGISTER_GROUP(group, color, category)
 114  #define MICROPROFILE_DECLARE_GPU(var)
 115  #define MICROPROFILE_DEFINE_GPU(var, name, color)
 116  #define MICROPROFILE_SCOPE(var) do{}while(0)
 117  #define MICROPROFILE_SCOPEI(group, name, color) do{}while(0)
 118  #define MICROPROFILE_SCOPEGPU(var) do{}while(0)
 119  #define MICROPROFILE_SCOPEGPUI( name, color) do{}while(0)
 120  #define MICROPROFILE_META_CPU(name, count)
 121  #define MICROPROFILE_META_GPU(name, count)
 122  #define MICROPROFILE_FORCEENABLECPUGROUP(s) do{} while(0)
 123  #define MICROPROFILE_FORCEDISABLECPUGROUP(s) do{} while(0)
 124  #define MICROPROFILE_FORCEENABLEGPUGROUP(s) do{} while(0)
 125  #define MICROPROFILE_FORCEDISABLEGPUGROUP(s) do{} while(0)
 126  #define MICROPROFILE_SCOPE_TOKEN(token)
 127  
 128  #define MicroProfileGetTime(group, name) 0.f
 129  #define MicroProfileOnThreadCreate(foo) do{}while(0)
 130  #define MicroProfileFlip() do{}while(0)
 131  #define MicroProfileSetAggregateFrames(a) do{}while(0)
 132  #define MicroProfileGetAggregateFrames() 0
 133  #define MicroProfileGetCurrentAggregateFrames() 0
 134  #define MicroProfileTogglePause() do{}while(0)
 135  #define MicroProfileToggleAllGroups() do{} while(0)
 136  #define MicroProfileDumpTimers() do{}while(0)
 137  #define MicroProfileShutdown() do{}while(0)
 138  #define MicroProfileSetForceEnable(a) do{} while(0)
 139  #define MicroProfileGetForceEnable() false
 140  #define MicroProfileSetEnableAllGroups(a) do{} while(0)
 141  #define MicroProfileEnableCategory(a) do{} while(0)
 142  #define MicroProfileDisableCategory(a) do{} while(0)
 143  #define MicroProfileGetEnableAllGroups() false
 144  #define MicroProfileSetForceMetaCounters(a)
 145  #define MicroProfileGetForceMetaCounters() 0
 146  #define MicroProfileEnableMetaCounter(c) do{}while(0)
 147  #define MicroProfileDisableMetaCounter(c) do{}while(0)
 148  #define MicroProfileDumpFile(html,csv) do{} while(0)
 149  #define MicroProfileWebServerPort() ((uint32_t)-1)
 150  
 151  #else
 152  
 153  #include <stdint.h>
 154  #include <string.h>
 155  #include <algorithm>
 156  #include <array>
 157  #include <atomic>
 158  #include <mutex>
 159  #include <thread>
 160  
 161  #ifndef MICROPROFILE_API
 162  #define MICROPROFILE_API
 163  #endif
 164  
 165  MICROPROFILE_API int64_t MicroProfileTicksPerSecondCpu();
 166  
 167  
 168  #if defined(__APPLE__)
 169  #include <mach/mach.h>
 170  #include <mach/mach_time.h>
 171  #include <unistd.h>
 172  #include <libkern/OSAtomic.h>
 173  #include <TargetConditionals.h>
 174  #if TARGET_OS_IPHONE
 175  #define MICROPROFILE_IOS
 176  #endif
 177  
 178  #define MP_TICK() mach_absolute_time()
 179  inline int64_t MicroProfileTicksPerSecondCpu()
 180  {
 181      static int64_t nTicksPerSecond = 0;
 182      if(nTicksPerSecond == 0)
 183      {
 184          mach_timebase_info_data_t sTimebaseInfo;
 185          mach_timebase_info(&sTimebaseInfo);
 186          nTicksPerSecond = 1000000000ll * sTimebaseInfo.denom / sTimebaseInfo.numer;
 187      }
 188      return nTicksPerSecond;
 189  }
 190  inline uint64_t MicroProfileGetCurrentThreadId()
 191  {
 192      uint64_t tid;
 193      pthread_threadid_np(pthread_self(), &tid);
 194      return tid;
 195  }
 196  
 197  #define MP_BREAK() __builtin_trap()
 198  #define MP_THREAD_LOCAL __thread
 199  #define MP_STRCASECMP strcasecmp
 200  #define MP_GETCURRENTTHREADID() MicroProfileGetCurrentThreadId()
 201  typedef uint64_t ThreadIdType;
 202  #elif defined(_WIN32)
 203  int64_t MicroProfileGetTick();
 204  #define MP_TICK() MicroProfileGetTick()
 205  #define MP_BREAK() __debugbreak()
 206  #define MP_THREAD_LOCAL thread_local
 207  #define MP_STRCASECMP _stricmp
 208  #define MP_GETCURRENTTHREADID() GetCurrentThreadId()
 209  typedef uint32_t ThreadIdType;
 210  
 211  #elif !defined(_WIN32)
 212  #include <unistd.h>
 213  #include <time.h>
 214  inline int64_t MicroProfileTicksPerSecondCpu()
 215  {
 216      return 1000000000ll;
 217  }
 218  
 219  inline int64_t MicroProfileGetTick()
 220  {
 221      timespec ts;
 222      clock_gettime(CLOCK_REALTIME, &ts);
 223      return 1000000000ll * ts.tv_sec + ts.tv_nsec;
 224  }
 225  #define MP_TICK() MicroProfileGetTick()
 226  #define MP_BREAK() __builtin_trap()
 227  #define MP_THREAD_LOCAL __thread
 228  #define MP_STRCASECMP strcasecmp
 229  #define MP_GETCURRENTTHREADID() (uint64_t)pthread_self()
 230  typedef uint64_t ThreadIdType;
 231  #endif
 232  
 233  
 234  #ifndef MP_GETCURRENTTHREADID
 235  #define MP_GETCURRENTTHREADID() 0
 236  typedef uint32_t ThreadIdType;
 237  #endif
 238  
 239  
 240  #define MP_ASSERT(a) do{if(!(a)){MP_BREAK();} }while(0)
 241  #define MICROPROFILE_DECLARE(var) extern MicroProfileToken g_mp_##var
 242  #define MICROPROFILE_DEFINE(var, group, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu)
 243  #define MICROPROFILE_REGISTER_GROUP(group, category, color) MicroProfileRegisterGroup(group, category, color)
 244  #define MICROPROFILE_DECLARE_GPU(var) extern MicroProfileToken g_mp_##var
 245  #define MICROPROFILE_DEFINE_GPU(var, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu)
 246  #define MICROPROFILE_TOKEN_PASTE0(a, b) a ## b
 247  #define MICROPROFILE_TOKEN_PASTE(a, b)  MICROPROFILE_TOKEN_PASTE0(a,b)
 248  #define MICROPROFILE_TOKEN(var) g_mp_##var
 249  #define MICROPROFILE_SCOPE(var) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var)
 250  #define MICROPROFILE_SCOPE_TOKEN(token) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(token)
 251  #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__))
 252  #define MICROPROFILE_SCOPEGPU(var) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var)
 253  #define MICROPROFILE_SCOPEGPUI(name, color) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__) = MicroProfileGetToken("GPU", name, color,  MicroProfileTokenTypeGpu); MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(foo,__LINE__)( MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__))
 254  #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)
 255  #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)
 256  
 257  
 258  #ifndef MICROPROFILE_USE_THREAD_NAME_CALLBACK
 259  #define MICROPROFILE_USE_THREAD_NAME_CALLBACK 0
 260  #endif
 261  
 262  #ifndef MICROPROFILE_PER_THREAD_BUFFER_SIZE
 263  #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<10)
 264  #endif
 265  
 266  #ifndef MICROPROFILE_MAX_FRAME_HISTORY
 267  #define MICROPROFILE_MAX_FRAME_HISTORY 512
 268  #endif
 269  
 270  #ifndef MICROPROFILE_PRINTF
 271  #define MICROPROFILE_PRINTF printf
 272  #endif
 273  
 274  #ifndef MICROPROFILE_META_MAX
 275  #define MICROPROFILE_META_MAX 8
 276  #endif
 277  
 278  #ifndef MICROPROFILE_WEBSERVER_PORT
 279  #define MICROPROFILE_WEBSERVER_PORT 1338
 280  #endif
 281  
 282  #ifndef MICROPROFILE_WEBSERVER
 283  #define MICROPROFILE_WEBSERVER 1
 284  #endif
 285  
 286  #ifndef MICROPROFILE_WEBSERVER_MAXFRAMES
 287  #define MICROPROFILE_WEBSERVER_MAXFRAMES 30
 288  #endif
 289  
 290  #ifndef MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE
 291  #define MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE (16<<10)
 292  #endif
 293  
 294  #ifndef MICROPROFILE_GPU_TIMERS
 295  #define MICROPROFILE_GPU_TIMERS 1
 296  #endif
 297  
 298  #ifndef MICROPROFILE_GPU_FRAME_DELAY
 299  #define MICROPROFILE_GPU_FRAME_DELAY 3 //must be > 0
 300  #endif
 301  
 302  
 303  #ifndef MICROPROFILE_NAME_MAX_LEN
 304  #define MICROPROFILE_NAME_MAX_LEN 64
 305  #endif
 306  
 307  #define MICROPROFILE_FORCEENABLECPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeCpu)
 308  #define MICROPROFILE_FORCEDISABLECPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeCpu)
 309  #define MICROPROFILE_FORCEENABLEGPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeGpu)
 310  #define MICROPROFILE_FORCEDISABLEGPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeGpu)
 311  
 312  #define MICROPROFILE_INVALID_TICK ((uint64_t)-1)
 313  #define MICROPROFILE_GROUP_MASK_ALL 0xffffffffffff
 314  
 315  
 316  #define MICROPROFILE_INVALID_TOKEN (uint64_t)-1
 317  
 318  enum MicroProfileTokenType
 319  {
 320      MicroProfileTokenTypeCpu,
 321      MicroProfileTokenTypeGpu,
 322  };
 323  
 324  enum MicroProfileBoxType
 325  {
 326      MicroProfileBoxTypeBar,
 327      MicroProfileBoxTypeFlat,
 328  };
 329  
 330  
 331  
 332  struct MicroProfile;
 333  
 334  MICROPROFILE_API void MicroProfileInit();
 335  MICROPROFILE_API void MicroProfileShutdown();
 336  MICROPROFILE_API MicroProfileToken MicroProfileFindToken(const char* sGroup, const char* sName);
 337  MICROPROFILE_API MicroProfileToken MicroProfileGetToken(const char* sGroup, const char* sName, uint32_t nColor, MicroProfileTokenType Token = MicroProfileTokenTypeCpu);
 338  MICROPROFILE_API MicroProfileToken MicroProfileGetMetaToken(const char* pName);
 339  MICROPROFILE_API void MicroProfileMetaUpdate(MicroProfileToken, int nCount, MicroProfileTokenType eTokenType);
 340  MICROPROFILE_API uint64_t MicroProfileEnter(MicroProfileToken nToken);
 341  MICROPROFILE_API void MicroProfileLeave(MicroProfileToken nToken, uint64_t nTick);
 342  MICROPROFILE_API uint64_t MicroProfileGpuEnter(MicroProfileToken nToken);
 343  MICROPROFILE_API void MicroProfileGpuLeave(MicroProfileToken nToken, uint64_t nTick);
 344  inline uint16_t MicroProfileGetTimerIndex(MicroProfileToken t){ return (t&0xffff); }
 345  inline uint64_t MicroProfileGetGroupMask(MicroProfileToken t){ return ((t>>16)&MICROPROFILE_GROUP_MASK_ALL);}
 346  inline MicroProfileToken MicroProfileMakeToken(uint64_t nGroupMask, uint16_t nTimer){ return (nGroupMask<<16) | nTimer;}
 347  
 348  MICROPROFILE_API void MicroProfileFlip(); //! call once per frame.
 349  MICROPROFILE_API void MicroProfileTogglePause();
 350  MICROPROFILE_API void MicroProfileForceEnableGroup(const char* pGroup, MicroProfileTokenType Type);
 351  MICROPROFILE_API void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Type);
 352  MICROPROFILE_API float MicroProfileGetTime(const char* pGroup, const char* pName);
 353  MICROPROFILE_API void MicroProfileContextSwitchSearch(uint32_t* pContextSwitchStart, uint32_t* pContextSwitchEnd, uint64_t nBaseTicksCpu, uint64_t nBaseTicksEndCpu);
 354  MICROPROFILE_API void MicroProfileOnThreadCreate(const char* pThreadName); //should be called from newly created threads
 355  MICROPROFILE_API void MicroProfileOnThreadExit(); //call on exit to reuse log
 356  MICROPROFILE_API void MicroProfileInitThreadLog();
 357  MICROPROFILE_API void MicroProfileSetForceEnable(bool bForceEnable);
 358  MICROPROFILE_API bool MicroProfileGetForceEnable();
 359  MICROPROFILE_API void MicroProfileSetEnableAllGroups(bool bEnable);
 360  MICROPROFILE_API void MicroProfileEnableCategory(const char* pCategory);
 361  MICROPROFILE_API void MicroProfileDisableCategory(const char* pCategory);
 362  MICROPROFILE_API bool MicroProfileGetEnableAllGroups();
 363  MICROPROFILE_API void MicroProfileSetForceMetaCounters(bool bEnable);
 364  MICROPROFILE_API bool MicroProfileGetForceMetaCounters();
 365  MICROPROFILE_API void MicroProfileEnableMetaCounter(const char* pMet);
 366  MICROPROFILE_API void MicroProfileDisableMetaCounter(const char* pMet);
 367  MICROPROFILE_API void MicroProfileSetAggregateFrames(int frames);
 368  MICROPROFILE_API int MicroProfileGetAggregateFrames();
 369  MICROPROFILE_API int MicroProfileGetCurrentAggregateFrames();
 370  MICROPROFILE_API MicroProfile* MicroProfileGet();
 371  MICROPROFILE_API void MicroProfileGetRange(uint32_t nPut, uint32_t nGet, uint32_t nRange[2][2]);
 372  MICROPROFILE_API std::recursive_mutex& MicroProfileGetMutex();
 373  MICROPROFILE_API void MicroProfileStartContextSwitchTrace();
 374  MICROPROFILE_API void MicroProfileStopContextSwitchTrace();
 375  MICROPROFILE_API bool MicroProfileIsLocalThread(uint32_t nThreadId);
 376  
 377  
 378  #if MICROPROFILE_WEBSERVER
 379  MICROPROFILE_API void MicroProfileDumpFile(const char* pHtml, const char* pCsv);
 380  MICROPROFILE_API uint32_t MicroProfileWebServerPort();
 381  #else
 382  #define MicroProfileDumpFile(c) do{} while(0)
 383  #define MicroProfileWebServerPort() ((uint32_t)-1)
 384  #endif
 385  
 386  
 387  
 388  
 389  #if MICROPROFILE_GPU_TIMERS
 390  MICROPROFILE_API uint32_t MicroProfileGpuInsertTimeStamp();
 391  MICROPROFILE_API uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey);
 392  MICROPROFILE_API uint64_t MicroProfileTicksPerSecondGpu();
 393  MICROPROFILE_API int MicroProfileGetGpuTickReference(int64_t* pOutCPU, int64_t* pOutGpu);
 394  #else
 395  #define MicroProfileGpuInsertTimeStamp() 1
 396  #define MicroProfileGpuGetTimeStamp(a) 0
 397  #define MicroProfileTicksPerSecondGpu() 1
 398  #define MicroProfileGetGpuTickReference(a,b) 0
 399  #endif
 400  
 401  #if MICROPROFILE_GPU_TIMERS_D3D11
 402  #define MICROPROFILE_D3D_MAX_QUERIES (8<<10)
 403  MICROPROFILE_API void MicroProfileGpuInitD3D11(void* pDevice, void* pDeviceContext);
 404  #endif
 405  
 406  #if MICROPROFILE_GPU_TIMERS_GL
 407  #define MICROPROFILE_GL_MAX_QUERIES (8<<10)
 408  MICROPROFILE_API void MicroProfileGpuInitGL();
 409  #endif
 410  
 411  
 412  
 413  #if MICROPROFILE_USE_THREAD_NAME_CALLBACK
 414  MICROPROFILE_API const char* MicroProfileGetThreadName();
 415  #else
 416  #define MicroProfileGetThreadName() "<implement MicroProfileGetThreadName to get threadnames>"
 417  #endif
 418  
 419  #if !defined(MICROPROFILE_THREAD_NAME_FROM_ID)
 420  #define MICROPROFILE_THREAD_NAME_FROM_ID(a) ""
 421  #endif
 422  
 423  
 424  struct MicroProfileScopeHandler
 425  {
 426      MicroProfileToken nToken;
 427      uint64_t nTick;
 428      MicroProfileScopeHandler(MicroProfileToken Token):nToken(Token)
 429      {
 430          nTick = MicroProfileEnter(nToken);
 431      }
 432      ~MicroProfileScopeHandler()
 433      {
 434          MicroProfileLeave(nToken, nTick);
 435      }
 436  };
 437  
 438  struct MicroProfileScopeGpuHandler
 439  {
 440      MicroProfileToken nToken;
 441      uint64_t nTick;
 442      MicroProfileScopeGpuHandler(MicroProfileToken Token):nToken(Token)
 443      {
 444          nTick = MicroProfileGpuEnter(nToken);
 445      }
 446      ~MicroProfileScopeGpuHandler()
 447      {
 448          MicroProfileGpuLeave(nToken, nTick);
 449      }
 450  };
 451  
 452  
 453  
 454  #define MICROPROFILE_MAX_TIMERS 1024
 455  #define MICROPROFILE_MAX_GROUPS 48 //dont bump! no. of bits used it bitmask
 456  #define MICROPROFILE_MAX_CATEGORIES 16
 457  #define MICROPROFILE_MAX_GRAPHS 5
 458  #define MICROPROFILE_GRAPH_HISTORY 128
 459  #define MICROPROFILE_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_BUFFER_SIZE)/sizeof(MicroProfileLogEntry))
 460  #define MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS 256
 461  #define MICROPROFILE_STACK_MAX 32
 462  //#define MICROPROFILE_MAX_PRESETS 5
 463  #define MICROPROFILE_ANIM_DELAY_PRC 0.5f
 464  #define MICROPROFILE_GAP_TIME 50 //extra ms to fetch to close timers from earlier frames
 465  
 466  
 467  #ifndef MICROPROFILE_MAX_THREADS
 468  #define MICROPROFILE_MAX_THREADS 32
 469  #endif
 470  
 471  #ifndef MICROPROFILE_UNPACK_RED
 472  #define MICROPROFILE_UNPACK_RED(c) ((c)>>16)
 473  #endif
 474  
 475  #ifndef MICROPROFILE_UNPACK_GREEN
 476  #define MICROPROFILE_UNPACK_GREEN(c) ((c)>>8)
 477  #endif
 478  
 479  #ifndef MICROPROFILE_UNPACK_BLUE
 480  #define MICROPROFILE_UNPACK_BLUE(c) ((c))
 481  #endif
 482  
 483  #ifndef MICROPROFILE_DEFAULT_PRESET
 484  #define MICROPROFILE_DEFAULT_PRESET "Default"
 485  #endif
 486  
 487  
 488  #ifndef MICROPROFILE_CONTEXT_SWITCH_TRACE
 489  #if defined(_WIN32)
 490  #define MICROPROFILE_CONTEXT_SWITCH_TRACE 1
 491  #elif defined(__APPLE__)
 492  #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 //disabled until dtrace script is working.
 493  #else
 494  #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
 495  #endif
 496  #endif
 497  
 498  #if MICROPROFILE_CONTEXT_SWITCH_TRACE
 499  #define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (128*1024) //2mb with 16 byte entry size
 500  #else
 501  #define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (1)
 502  #endif
 503  
 504  #ifndef MICROPROFILE_MINIZ
 505  #define MICROPROFILE_MINIZ 0
 506  #endif
 507  
 508  #ifdef _WIN32
 509  #include <basetsd.h>
 510  typedef UINT_PTR MpSocket;
 511  #else
 512  typedef int MpSocket;
 513  #endif
 514  
 515  
 516  #ifndef _WIN32
 517  typedef pthread_t MicroProfileThread;
 518  #elif defined(_MSC_VER)
 519  typedef HANDLE MicroProfileThread;
 520  #else
 521  typedef std::thread* MicroProfileThread;
 522  #endif
 523  
 524  
 525  
 526  enum MicroProfileDrawMask
 527  {
 528      MP_DRAW_OFF         = 0x0,
 529      MP_DRAW_BARS        = 0x1,
 530      MP_DRAW_DETAILED    = 0x2,
 531      MP_DRAW_HIDDEN      = 0x3,
 532  };
 533  
 534  enum MicroProfileDrawBarsMask
 535  {
 536      MP_DRAW_TIMERS              = 0x1,
 537      MP_DRAW_AVERAGE             = 0x2,
 538      MP_DRAW_MAX                 = 0x4,
 539      MP_DRAW_CALL_COUNT          = 0x8,
 540      MP_DRAW_TIMERS_EXCLUSIVE    = 0x10,
 541      MP_DRAW_AVERAGE_EXCLUSIVE   = 0x20,
 542      MP_DRAW_MAX_EXCLUSIVE       = 0x40,
 543      MP_DRAW_META_FIRST          = 0x80,
 544      MP_DRAW_ALL                 = 0xffffffff,
 545  
 546  };
 547  
 548  typedef uint64_t MicroProfileLogEntry;
 549  
 550  struct MicroProfileTimer
 551  {
 552      uint64_t nTicks;
 553      uint32_t nCount;
 554  };
 555  
 556  struct MicroProfileCategory
 557  {
 558      char pName[MICROPROFILE_NAME_MAX_LEN];
 559      uint64_t nGroupMask;
 560  };
 561  
 562  struct MicroProfileGroupInfo
 563  {
 564      char pName[MICROPROFILE_NAME_MAX_LEN];
 565      uint32_t nNameLen;
 566      uint32_t nGroupIndex;
 567      uint32_t nNumTimers;
 568      uint32_t nMaxTimerNameLen;
 569      uint32_t nColor;
 570      uint32_t nCategory;
 571      MicroProfileTokenType Type;
 572  };
 573  
 574  struct MicroProfileTimerInfo
 575  {
 576      MicroProfileToken nToken;
 577      uint32_t nTimerIndex;
 578      uint32_t nGroupIndex;
 579      char pName[MICROPROFILE_NAME_MAX_LEN];
 580      uint32_t nNameLen;
 581      uint32_t nColor;
 582      bool bGraph;
 583  };
 584  
 585  struct MicroProfileGraphState
 586  {
 587      int64_t nHistory[MICROPROFILE_GRAPH_HISTORY];
 588      MicroProfileToken nToken;
 589      int32_t nKey;
 590  };
 591  
 592  struct MicroProfileContextSwitch
 593  {
 594      ThreadIdType nThreadOut;
 595      ThreadIdType nThreadIn;
 596      int64_t nCpu : 8;
 597      int64_t nTicks : 56;
 598  };
 599  
 600  
 601  struct MicroProfileFrameState
 602  {
 603      int64_t nFrameStartCpu;
 604      int64_t nFrameStartGpu;
 605      uint32_t nLogStart[MICROPROFILE_MAX_THREADS];
 606  };
 607  
 608  struct MicroProfileThreadLog
 609  {
 610      std::array<MicroProfileLogEntry, MICROPROFILE_BUFFER_SIZE> Log{};
 611  
 612      std::atomic<uint32_t>   nPut{0};
 613      std::atomic<uint32_t>   nGet{0};
 614      uint32_t                nActive = 0;
 615      uint32_t                nGpu = 0;
 616      ThreadIdType            nThreadId{};
 617  
 618      std::array<uint32_t, MICROPROFILE_STACK_MAX> nStack{};
 619      std::array<int64_t, MICROPROFILE_STACK_MAX>  nChildTickStack{};
 620      uint32_t                                     nStackPos = 0;
 621  
 622  
 623      std::array<uint8_t, MICROPROFILE_MAX_GROUPS> nGroupStackPos{};
 624      std::array<int64_t, MICROPROFILE_MAX_GROUPS> nGroupTicks{};
 625      std::array<int64_t, MICROPROFILE_MAX_GROUPS> nAggregateGroupTicks{};
 626      enum
 627      {
 628          THREAD_MAX_LEN = 64,
 629      };
 630      char                    ThreadName[64]{};
 631      int                     nFreeListNext = 0;
 632  
 633      void Reset() {
 634          Log.fill({});
 635          nPut = 0;
 636          nGet = 0;
 637          nActive = 0;
 638          nGpu = 0;
 639          nThreadId = {};
 640          nStack.fill(0);
 641          nChildTickStack.fill(0);
 642          nStackPos = 0;
 643          nGroupStackPos.fill(0);
 644          nGroupTicks.fill(0);
 645          nAggregateGroupTicks.fill(0);
 646          std::fill(std::begin(ThreadName), std::end(ThreadName), '\0');
 647          nFreeListNext = 0;
 648      }
 649  };
 650  
 651  #if MICROPROFILE_GPU_TIMERS_D3D11
 652  struct MicroProfileD3D11Frame
 653  {
 654      uint32_t m_nQueryStart;
 655      uint32_t m_nQueryCount;
 656      uint32_t m_nRateQueryStarted;
 657      void* m_pRateQuery;
 658  };
 659  
 660  struct MicroProfileGpuTimerState
 661  {
 662      uint32_t bInitialized;
 663      void* m_pDevice;
 664      void* m_pDeviceContext;
 665      void* m_pQueries[MICROPROFILE_D3D_MAX_QUERIES];
 666      int64_t m_nQueryResults[MICROPROFILE_D3D_MAX_QUERIES];
 667      uint32_t m_nQueryPut;
 668      uint32_t m_nQueryGet;
 669      uint32_t m_nQueryFrame;
 670      int64_t m_nQueryFrequency;
 671      MicroProfileD3D11Frame m_QueryFrames[MICROPROFILE_GPU_FRAME_DELAY];
 672  };
 673  #elif MICROPROFILE_GPU_TIMERS_GL
 674  struct MicroProfileGpuTimerState
 675  {
 676      uint32_t GLTimers[MICROPROFILE_GL_MAX_QUERIES];
 677      uint32_t GLTimerPos;
 678  };
 679  #else
 680  struct MicroProfileGpuTimerState{};
 681  #endif
 682  
 683  struct MicroProfile
 684  {
 685      uint32_t nTotalTimers;
 686      uint32_t nGroupCount;
 687      uint32_t nCategoryCount;
 688      uint32_t nAggregateClear;
 689      uint32_t nAggregateFlip;
 690      uint32_t nAggregateFlipCount;
 691      uint32_t nAggregateFrames;
 692  
 693      uint64_t nAggregateFlipTick;
 694  
 695      uint32_t nDisplay;
 696      uint32_t nBars;
 697      uint64_t nActiveGroup;
 698      uint32_t nActiveBars;
 699  
 700      uint64_t nForceGroup;
 701      uint32_t nForceEnable;
 702      uint32_t nForceMetaCounters;
 703  
 704      uint64_t nForceGroupUI;
 705      uint64_t nActiveGroupWanted;
 706      uint32_t nAllGroupsWanted;
 707      uint32_t nAllThreadsWanted;
 708  
 709      uint32_t nOverflow;
 710  
 711      uint64_t nGroupMask;
 712      uint32_t nRunning;
 713      uint32_t nToggleRunning;
 714      uint32_t nMaxGroupSize;
 715      uint32_t nDumpFileNextFrame;
 716      uint32_t nAutoClearFrames;
 717      char HtmlDumpPath[512];
 718      char CsvDumpPath[512];
 719  
 720      int64_t nPauseTicks;
 721  
 722      float fReferenceTime;
 723      float fRcpReferenceTime;
 724  
 725      MicroProfileCategory    CategoryInfo[MICROPROFILE_MAX_CATEGORIES];
 726      MicroProfileGroupInfo   GroupInfo[MICROPROFILE_MAX_GROUPS];
 727      MicroProfileTimerInfo   TimerInfo[MICROPROFILE_MAX_TIMERS];
 728      uint8_t                 TimerToGroup[MICROPROFILE_MAX_TIMERS];
 729  
 730      MicroProfileTimer       AccumTimers[MICROPROFILE_MAX_TIMERS];
 731      uint64_t                AccumMaxTimers[MICROPROFILE_MAX_TIMERS];
 732      uint64_t                AccumTimersExclusive[MICROPROFILE_MAX_TIMERS];
 733      uint64_t                AccumMaxTimersExclusive[MICROPROFILE_MAX_TIMERS];
 734  
 735      MicroProfileTimer       Frame[MICROPROFILE_MAX_TIMERS];
 736      uint64_t                FrameExclusive[MICROPROFILE_MAX_TIMERS];
 737  
 738      MicroProfileTimer       Aggregate[MICROPROFILE_MAX_TIMERS];
 739      uint64_t                AggregateMax[MICROPROFILE_MAX_TIMERS];
 740      uint64_t                AggregateExclusive[MICROPROFILE_MAX_TIMERS];
 741      uint64_t                AggregateMaxExclusive[MICROPROFILE_MAX_TIMERS];
 742  
 743  
 744      uint64_t                FrameGroup[MICROPROFILE_MAX_GROUPS];
 745      uint64_t                AccumGroup[MICROPROFILE_MAX_GROUPS];
 746      uint64_t                AccumGroupMax[MICROPROFILE_MAX_GROUPS];
 747  
 748      uint64_t                AggregateGroup[MICROPROFILE_MAX_GROUPS];
 749      uint64_t                AggregateGroupMax[MICROPROFILE_MAX_GROUPS];
 750  
 751  
 752      struct
 753      {
 754          uint64_t nCounters[MICROPROFILE_MAX_TIMERS];
 755  
 756          uint64_t nAccum[MICROPROFILE_MAX_TIMERS];
 757          uint64_t nAccumMax[MICROPROFILE_MAX_TIMERS];
 758  
 759          uint64_t nAggregate[MICROPROFILE_MAX_TIMERS];
 760          uint64_t nAggregateMax[MICROPROFILE_MAX_TIMERS];
 761  
 762          uint64_t nSum;
 763          uint64_t nSumAccum;
 764          uint64_t nSumAccumMax;
 765          uint64_t nSumAggregate;
 766          uint64_t nSumAggregateMax;
 767  
 768          const char* pName;
 769      } MetaCounters[MICROPROFILE_META_MAX];
 770  
 771      MicroProfileGraphState  Graph[MICROPROFILE_MAX_GRAPHS];
 772      uint32_t                nGraphPut;
 773  
 774      uint32_t                nThreadActive[MICROPROFILE_MAX_THREADS];
 775      MicroProfileThreadLog*  Pool[MICROPROFILE_MAX_THREADS];
 776      uint32_t                nNumLogs;
 777      uint32_t                nMemUsage;
 778      int                     nFreeListHead;
 779  
 780      uint32_t                nFrameCurrent;
 781      uint32_t                nFrameCurrentIndex;
 782      uint32_t                nFramePut;
 783      uint64_t                nFramePutIndex;
 784  
 785      MicroProfileFrameState Frames[MICROPROFILE_MAX_FRAME_HISTORY];
 786  
 787      uint64_t                nFlipTicks;
 788      uint64_t                nFlipAggregate;
 789      uint64_t                nFlipMax;
 790      uint64_t                nFlipAggregateDisplay;
 791      uint64_t                nFlipMaxDisplay;
 792  
 793      MicroProfileThread          ContextSwitchThread;
 794      bool                        bContextSwitchRunning;
 795      bool                        bContextSwitchStop;
 796      bool                        bContextSwitchAllThreads;
 797      bool                        bContextSwitchNoBars;
 798      uint32_t                    nContextSwitchUsage;
 799      uint32_t                    nContextSwitchLastPut;
 800  
 801      int64_t                     nContextSwitchHoverTickIn;
 802      int64_t                     nContextSwitchHoverTickOut;
 803      uint32_t                    nContextSwitchHoverThread;
 804      uint32_t                    nContextSwitchHoverThreadBefore;
 805      uint32_t                    nContextSwitchHoverThreadAfter;
 806      uint8_t                     nContextSwitchHoverCpu;
 807      uint8_t                     nContextSwitchHoverCpuNext;
 808  
 809      uint32_t                    nContextSwitchPut;
 810      MicroProfileContextSwitch   ContextSwitch[MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE];
 811  
 812  
 813      MpSocket                    ListenerSocket;
 814      uint32_t                    nWebServerPort;
 815  
 816      char                        WebServerBuffer[MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE];
 817      uint32_t                    WebServerPut;
 818  
 819      uint64_t                    nWebServerDataSent;
 820  
 821      MicroProfileGpuTimerState   GPU;
 822  
 823  
 824  };
 825  
 826  #define MP_LOG_TICK_MASK  0x0000ffffffffffff
 827  #define MP_LOG_INDEX_MASK 0x3fff000000000000
 828  #define MP_LOG_BEGIN_MASK 0xc000000000000000
 829  #define MP_LOG_GPU_EXTRA 0x3
 830  #define MP_LOG_META 0x2
 831  #define MP_LOG_ENTER 0x1
 832  #define MP_LOG_LEAVE 0x0
 833  
 834  
 835  inline int MicroProfileLogType(MicroProfileLogEntry Index)
 836  {
 837      return (int)(((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3ULL);
 838  }
 839  
 840  inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
 841  {
 842      return (0x3fff&(Index>>48));
 843  }
 844  
 845  inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick)
 846  {
 847      MicroProfileLogEntry Entry =  (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
 848      int t = MicroProfileLogType(Entry);
 849      uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
 850      MP_ASSERT(static_cast<uint64_t>(t) == nBegin);
 851      MP_ASSERT(nTimerIndex == (nToken&0x3fff));
 852      return Entry;
 853  
 854  }
 855  
 856  inline int64_t MicroProfileLogTickDifference(MicroProfileLogEntry Start, MicroProfileLogEntry End)
 857  {
 858      uint64_t nStart = Start;
 859      uint64_t nEnd = End;
 860      int64_t nDifference = ((nEnd<<16) - (nStart<<16));
 861      return nDifference >> 16;
 862  }
 863  
 864  inline int64_t MicroProfileLogGetTick(MicroProfileLogEntry e)
 865  {
 866      return MP_LOG_TICK_MASK & e;
 867  }
 868  
 869  inline int64_t MicroProfileLogSetTick(MicroProfileLogEntry e, int64_t nTick)
 870  {
 871      return (MP_LOG_TICK_MASK & nTick) | (e & ~MP_LOG_TICK_MASK);
 872  }
 873  
 874  template<typename T>
 875  T MicroProfileMin(T a, T b)
 876  { return a < b ? a : b; }
 877  
 878  template<typename T>
 879  T MicroProfileMax(T a, T b)
 880  { return a > b ? a : b; }
 881  
 882  inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond)
 883  {
 884      return (int64_t)(fMs*0.001f*(float)nTicksPerSecond);
 885  }
 886  
 887  inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond)
 888  {
 889      return 1000.f / (float)nTicksPerSecond;
 890  }
 891  
 892  inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
 893  {
 894      return (uint16_t)MicroProfileGet()->TimerToGroup[MicroProfileGetTimerIndex(t)];
 895  }
 896  
 897  
 898  
 899  #ifdef MICROPROFILE_IMPL
 900  
 901  #ifdef _WIN32
 902  #include <windows.h>
 903  #define snprintf _snprintf
 904  
 905  #ifdef _MSC_VER
 906  #pragma warning(push)
 907  #pragma warning(disable: 4244)
 908  #endif
 909  int64_t MicroProfileTicksPerSecondCpu()
 910  {
 911      static int64_t nTicksPerSecond = 0;
 912      if(nTicksPerSecond == 0)
 913      {
 914          QueryPerformanceFrequency((LARGE_INTEGER*)&nTicksPerSecond);
 915      }
 916      return nTicksPerSecond;
 917  }
 918  int64_t MicroProfileGetTick()
 919  {
 920      int64_t ticks;
 921      QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
 922      return ticks;
 923  }
 924  
 925  #endif
 926  
 927  #if defined(MICROPROFILE_WEBSERVER) || defined(MICROPROFILE_CONTEXT_SWITCH_TRACE)
 928  
 929  
 930  typedef void* (*MicroProfileThreadFunc)(void*);
 931  
 932  #ifndef _WIN32
 933  typedef pthread_t MicroProfileThread;
 934  inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
 935  {
 936      pthread_attr_t Attr;
 937      int r  = pthread_attr_init(&Attr);
 938      MP_ASSERT(r == 0);
 939      pthread_create(pThread, &Attr, Func, 0);
 940  }
 941  inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
 942  {
 943      int r = pthread_join(*pThread, 0);
 944      MP_ASSERT(r == 0);
 945  }
 946  #elif defined(_MSC_VER)
 947  typedef HANDLE MicroProfileThread;
 948  DWORD _stdcall ThreadTrampoline(void* pFunc)
 949  {
 950      MicroProfileThreadFunc F = (MicroProfileThreadFunc)pFunc;
 951  
 952      // The return value of F will always return a void*, however, this is for
 953      // compatibility with pthreads. The underlying "address" of the pointer
 954      // is always a 32-bit value, so this cast is safe to perform.
 955      return static_cast<DWORD>(reinterpret_cast<uint64_t>(F(0)));
 956  }
 957  
 958  inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
 959  {
 960      *pThread = CreateThread(0, 0, ThreadTrampoline, Func, 0, 0);
 961  }
 962  inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
 963  {
 964      WaitForSingleObject(*pThread, INFINITE);
 965      CloseHandle(*pThread);
 966  }
 967  #else
 968  #include <thread>
 969  typedef std::thread* MicroProfileThread;
 970  inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
 971  {
 972      *pThread = new std::thread(Func, nullptr);
 973  }
 974  inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
 975  {
 976      (*pThread)->join();
 977      delete *pThread;
 978  }
 979  #endif
 980  #endif
 981  
 982  #if MICROPROFILE_WEBSERVER
 983  
 984  #ifdef _WIN32
 985  #define MP_INVALID_SOCKET(f) (f == INVALID_SOCKET)
 986  #endif
 987  
 988  #ifndef _WIN32
 989  #include <sys/socket.h>
 990  #include <netinet/in.h>
 991  #include <fcntl.h>
 992  #define MP_INVALID_SOCKET(f) (f < 0)
 993  #endif
 994  
 995  
 996  void MicroProfileWebServerStart();
 997  void MicroProfileWebServerStop();
 998  bool MicroProfileWebServerUpdate();
 999  void MicroProfileDumpToFile();
1000  
1001  #else
1002  
1003  #define MicroProfileWebServerStart() do{}while(0)
1004  #define MicroProfileWebServerStop() do{}while(0)
1005  #define MicroProfileWebServerUpdate() false
1006  #define MicroProfileDumpToFile() do{} while(0)
1007  #endif
1008  
1009  
1010  #if MICROPROFILE_GPU_TIMERS_D3D11
1011  void MicroProfileGpuFlip();
1012  void MicroProfileGpuShutdown();
1013  #else
1014  #define MicroProfileGpuFlip() do{}while(0)
1015  #define MicroProfileGpuShutdown() do{}while(0)
1016  #endif
1017  
1018  
1019  
1020  #include <stdlib.h>
1021  #include <stdio.h>
1022  #include <math.h>
1023  #include <algorithm>
1024  
1025  
1026  #ifndef MICROPROFILE_DEBUG
1027  #define MICROPROFILE_DEBUG 0
1028  #endif
1029  
1030  
1031  #define S g_MicroProfile
1032  
1033  MicroProfile g_MicroProfile;
1034  MicroProfileThreadLog*          g_MicroProfileGpuLog = 0;
1035  #ifdef MICROPROFILE_IOS
1036  // iOS doesn't support __thread
1037  static pthread_key_t g_MicroProfileThreadLogKey;
1038  static pthread_once_t g_MicroProfileThreadLogKeyOnce = PTHREAD_ONCE_INIT;
1039  static void MicroProfileCreateThreadLogKey()
1040  {
1041      pthread_key_create(&g_MicroProfileThreadLogKey, NULL);
1042  }
1043  #else
1044  MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLog = 0;
1045  #endif
1046  static std::atomic<bool> g_bUseLock{false}; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)
1047  
1048  
1049  MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", 0x3355ee);
1050  MICROPROFILE_DEFINE(g_MicroProfileThreadLoop, "MicroProfile", "ThreadLoop", 0x3355ee);
1051  MICROPROFILE_DEFINE(g_MicroProfileClear, "MicroProfile", "Clear", 0x3355ee);
1052  MICROPROFILE_DEFINE(g_MicroProfileAccumulate, "MicroProfile", "Accumulate", 0x3355ee);
1053  MICROPROFILE_DEFINE(g_MicroProfileContextSwitchSearch,"MicroProfile", "ContextSwitchSearch", 0xDD7300);
1054  
1055  inline std::recursive_mutex& MicroProfileMutex()
1056  {
1057      static std::recursive_mutex Mutex;
1058      return Mutex;
1059  }
1060  std::recursive_mutex& MicroProfileGetMutex()
1061  {
1062      return MicroProfileMutex();
1063  }
1064  
1065  MICROPROFILE_API MicroProfile* MicroProfileGet()
1066  {
1067      return &g_MicroProfile;
1068  }
1069  
1070  
1071  MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName);
1072  
1073  
1074  void MicroProfileInit()
1075  {
1076      std::recursive_mutex& mutex = MicroProfileMutex();
1077      bool bUseLock = g_bUseLock;
1078      if(bUseLock)
1079          mutex.lock();
1080      static bool bOnce = true;
1081      if(bOnce)
1082      {
1083          S.nMemUsage += sizeof(S);
1084          bOnce = false;
1085          memset(&S, 0, sizeof(S));
1086          for(int i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
1087          {
1088              S.GroupInfo[i].pName[0] = '\0';
1089          }
1090          for(int i = 0; i < MICROPROFILE_MAX_CATEGORIES; ++i)
1091          {
1092              S.CategoryInfo[i].pName[0] = '\0';
1093              S.CategoryInfo[i].nGroupMask = 0;
1094          }
1095          strcpy(&S.CategoryInfo[0].pName[0], "default");
1096          S.nCategoryCount = 1;
1097          for(int i = 0; i < MICROPROFILE_MAX_TIMERS; ++i)
1098          {
1099              S.TimerInfo[i].pName[0] = '\0';
1100          }
1101          S.nGroupCount = 0;
1102          S.nAggregateFlipTick = MP_TICK();
1103          S.nActiveGroup = 0;
1104          S.nActiveBars = 0;
1105          S.nForceGroup = 0;
1106          S.nAllGroupsWanted = 0;
1107          S.nActiveGroupWanted = 0;
1108          S.nAllThreadsWanted = 1;
1109          S.nAggregateFlip = 0;
1110          S.nTotalTimers = 0;
1111          for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1112          {
1113              S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
1114          }
1115          S.nRunning = 1;
1116          S.fReferenceTime = 33.33f;
1117          S.fRcpReferenceTime = 1.f / S.fReferenceTime;
1118          S.nFreeListHead = -1;
1119          int64_t nTick = MP_TICK();
1120          for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)
1121          {
1122              S.Frames[i].nFrameStartCpu = nTick;
1123              S.Frames[i].nFrameStartGpu = -1;
1124          }
1125  
1126          MicroProfileThreadLog* pGpu = MicroProfileCreateThreadLog("GPU");
1127          g_MicroProfileGpuLog = pGpu;
1128          MP_ASSERT(S.Pool[0] == pGpu);
1129          pGpu->nGpu = 1;
1130          pGpu->nThreadId = 0;
1131  
1132          S.nWebServerDataSent = (uint64_t)-1;
1133      }
1134      if(bUseLock)
1135          mutex.unlock();
1136  }
1137  
1138  void MicroProfileShutdown()
1139  {
1140      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
1141      MicroProfileWebServerStop();
1142      MicroProfileStopContextSwitchTrace();
1143      MicroProfileGpuShutdown();
1144  }
1145  
1146  #ifdef MICROPROFILE_IOS
1147  inline MicroProfileThreadLog* MicroProfileGetThreadLog()
1148  {
1149      pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey);
1150      return (MicroProfileThreadLog*)pthread_getspecific(g_MicroProfileThreadLogKey);
1151  }
1152  
1153  inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)
1154  {
1155      pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey);
1156      pthread_setspecific(g_MicroProfileThreadLogKey, pLog);
1157  }
1158  #else
1159  inline MicroProfileThreadLog* MicroProfileGetThreadLog()
1160  {
1161      return g_MicroProfileThreadLog;
1162  }
1163  inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)
1164  {
1165      g_MicroProfileThreadLog = pLog;
1166  }
1167  #endif
1168  
1169  
1170  MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)
1171  {
1172      MicroProfileThreadLog* pLog = 0;
1173      if(S.nFreeListHead != -1)
1174      {
1175          pLog = S.Pool[S.nFreeListHead];
1176          MP_ASSERT(pLog->nPut.load() == 0);
1177          MP_ASSERT(pLog->nGet.load() == 0);
1178          S.nFreeListHead = S.Pool[S.nFreeListHead]->nFreeListNext;
1179          pLog->Reset();
1180      }
1181      else
1182      {
1183          pLog = new MicroProfileThreadLog;
1184          S.nMemUsage += sizeof(MicroProfileThreadLog);
1185          S.Pool[S.nNumLogs++] = pLog;
1186      }
1187      int len = (int)strlen(pName);
1188      int maxlen = sizeof(pLog->ThreadName)-1;
1189      len = len < maxlen ? len : maxlen;
1190      memcpy(&pLog->ThreadName[0], pName, len);
1191      pLog->ThreadName[len] = '\0';
1192      pLog->nThreadId = MP_GETCURRENTTHREADID();
1193      pLog->nFreeListNext = -1;
1194      pLog->nActive = 1;
1195      return pLog;
1196  }
1197  
1198  void MicroProfileOnThreadCreate(const char* pThreadName)
1199  {
1200      g_bUseLock = true;
1201      MicroProfileInit();
1202      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
1203      MP_ASSERT(MicroProfileGetThreadLog() == 0);
1204      MicroProfileThreadLog* pLog = MicroProfileCreateThreadLog(pThreadName ? pThreadName : MicroProfileGetThreadName());
1205      MP_ASSERT(pLog);
1206      MicroProfileSetThreadLog(pLog);
1207  }
1208  
1209  void MicroProfileOnThreadExit()
1210  {
1211      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
1212      MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();
1213      if(pLog)
1214      {
1215          int32_t nLogIndex = -1;
1216          for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
1217          {
1218              if(pLog == S.Pool[i])
1219              {
1220                  nLogIndex = i;
1221                  break;
1222              }
1223          }
1224          MP_ASSERT(nLogIndex < MICROPROFILE_MAX_THREADS && nLogIndex > 0);
1225          pLog->nFreeListNext = S.nFreeListHead;
1226          pLog->nActive = 0;
1227          pLog->nPut.store(0);
1228          pLog->nGet.store(0);
1229          S.nFreeListHead = nLogIndex;
1230          for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)
1231          {
1232              S.Frames[i].nLogStart[nLogIndex] = 0;
1233          }
1234          pLog->nGroupStackPos.fill(0);
1235          pLog->nGroupTicks.fill(0);
1236      }
1237  }
1238  
1239  void MicroProfileInitThreadLog()
1240  {
1241      MicroProfileOnThreadCreate(nullptr);
1242  }
1243  
1244  
1245  struct MicroProfileScopeLock
1246  {
1247      bool bUseLock;
1248      std::recursive_mutex& m;
1249      MicroProfileScopeLock(std::recursive_mutex& m) : bUseLock(g_bUseLock), m(m)
1250      {
1251          if(bUseLock)
1252              m.lock();
1253      }
1254      ~MicroProfileScopeLock()
1255      {
1256          if(bUseLock)
1257              m.unlock();
1258      }
1259  };
1260  
1261  MicroProfileToken MicroProfileFindToken(const char* pGroup, const char* pName)
1262  {
1263      MicroProfileInit();
1264      MicroProfileScopeLock L(MicroProfileMutex());
1265      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
1266      {
1267          if(!MP_STRCASECMP(pName, S.TimerInfo[i].pName) && !MP_STRCASECMP(pGroup, S.GroupInfo[S.TimerToGroup[i]].pName))
1268          {
1269              return S.TimerInfo[i].nToken;
1270          }
1271      }
1272      return MICROPROFILE_INVALID_TOKEN;
1273  }
1274  
1275  inline uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
1276  {
1277      for(uint32_t i = 0; i < S.nGroupCount; ++i)
1278      {
1279          if(!MP_STRCASECMP(pGroup, S.GroupInfo[i].pName))
1280          {
1281              return i;
1282          }
1283      }
1284      uint16_t nGroupIndex = 0xffff;
1285      uint32_t nLen = (uint32_t)strlen(pGroup);
1286      if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
1287          nLen = MICROPROFILE_NAME_MAX_LEN-1;
1288      memcpy(&S.GroupInfo[S.nGroupCount].pName[0], pGroup, nLen);
1289      S.GroupInfo[S.nGroupCount].pName[nLen] = '\0';
1290      S.GroupInfo[S.nGroupCount].nNameLen = nLen;
1291      S.GroupInfo[S.nGroupCount].nNumTimers = 0;
1292      S.GroupInfo[S.nGroupCount].nGroupIndex = S.nGroupCount;
1293      S.GroupInfo[S.nGroupCount].Type = Type;
1294      S.GroupInfo[S.nGroupCount].nMaxTimerNameLen = 0;
1295      S.GroupInfo[S.nGroupCount].nColor = 0x88888888;
1296      S.GroupInfo[S.nGroupCount].nCategory = 0;
1297      S.CategoryInfo[0].nGroupMask |= (1ll << (uint64_t)S.nGroupCount);
1298      nGroupIndex = S.nGroupCount++;
1299      S.nGroupMask = (S.nGroupMask<<1)|1;
1300      MP_ASSERT(nGroupIndex < MICROPROFILE_MAX_GROUPS);
1301      return nGroupIndex;
1302  }
1303  
1304  inline void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)
1305  {
1306      int nCategoryIndex = -1;
1307      for(uint32_t i = 0; i < S.nCategoryCount; ++i)
1308      {
1309          if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName))
1310          {
1311              nCategoryIndex = (int)i;
1312              break;
1313          }
1314      }
1315      if(-1 == nCategoryIndex && S.nCategoryCount < MICROPROFILE_MAX_CATEGORIES)
1316      {
1317          MP_ASSERT(S.CategoryInfo[S.nCategoryCount].pName[0] == '\0');
1318          nCategoryIndex = (int)S.nCategoryCount++;
1319          uint32_t nLen = (uint32_t)strlen(pCategory);
1320          if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
1321              nLen = MICROPROFILE_NAME_MAX_LEN-1;
1322          memcpy(&S.CategoryInfo[nCategoryIndex].pName[0], pCategory, nLen);
1323          S.CategoryInfo[nCategoryIndex].pName[nLen] = '\0';
1324      }
1325      uint16_t nGroup = MicroProfileGetGroup(pGroup, 0 != MP_STRCASECMP(pGroup, "gpu")?MicroProfileTokenTypeCpu : MicroProfileTokenTypeGpu);
1326      S.GroupInfo[nGroup].nColor = nColor;
1327      if(nCategoryIndex >= 0)
1328      {
1329          uint64_t nBit = 1ll << nGroup;
1330          uint32_t nOldCategory = S.GroupInfo[nGroup].nCategory;
1331          S.CategoryInfo[nOldCategory].nGroupMask &= ~nBit;
1332          S.CategoryInfo[nCategoryIndex].nGroupMask |= nBit;
1333          S.GroupInfo[nGroup].nCategory = nCategoryIndex;
1334      }
1335  }
1336  
1337  MicroProfileToken MicroProfileGetToken(const char* pGroup, const char* pName, uint32_t nColor, MicroProfileTokenType Type)
1338  {
1339      MicroProfileInit();
1340      MicroProfileScopeLock L(MicroProfileMutex());
1341      MicroProfileToken ret = MicroProfileFindToken(pGroup, pName);
1342      if(ret != MICROPROFILE_INVALID_TOKEN)
1343          return ret;
1344      uint16_t nGroupIndex = MicroProfileGetGroup(pGroup, Type);
1345      uint16_t nTimerIndex = (uint16_t)(S.nTotalTimers++);
1346      uint64_t nGroupMask = 1ll << nGroupIndex;
1347      MicroProfileToken nToken = MicroProfileMakeToken(nGroupMask, nTimerIndex);
1348      S.GroupInfo[nGroupIndex].nNumTimers++;
1349      S.GroupInfo[nGroupIndex].nMaxTimerNameLen = MicroProfileMax(S.GroupInfo[nGroupIndex].nMaxTimerNameLen, (uint32_t)strlen(pName));
1350      MP_ASSERT(S.GroupInfo[nGroupIndex].Type == Type); //dont mix cpu & gpu timers in the same group
1351      S.nMaxGroupSize = MicroProfileMax(S.nMaxGroupSize, S.GroupInfo[nGroupIndex].nNumTimers);
1352      S.TimerInfo[nTimerIndex].nToken = nToken;
1353      uint32_t nLen = (uint32_t)strlen(pName);
1354      if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
1355          nLen = MICROPROFILE_NAME_MAX_LEN-1;
1356      memcpy(&S.TimerInfo[nTimerIndex].pName, pName, nLen);
1357      S.TimerInfo[nTimerIndex].pName[nLen] = '\0';
1358      S.TimerInfo[nTimerIndex].nNameLen = nLen;
1359      S.TimerInfo[nTimerIndex].nColor = nColor&0xffffff;
1360      S.TimerInfo[nTimerIndex].nGroupIndex = nGroupIndex;
1361      S.TimerInfo[nTimerIndex].nTimerIndex = nTimerIndex;
1362      S.TimerToGroup[nTimerIndex] = nGroupIndex;
1363      return nToken;
1364  }
1365  
1366  MicroProfileToken MicroProfileGetMetaToken(const char* pName)
1367  {
1368      MicroProfileInit();
1369      MicroProfileScopeLock L(MicroProfileMutex());
1370      for(uint32_t i = 0; i < MICROPROFILE_META_MAX; ++i)
1371      {
1372          if(!S.MetaCounters[i].pName)
1373          {
1374              S.MetaCounters[i].pName = pName;
1375              return i;
1376          }
1377          else if(!MP_STRCASECMP(pName, S.MetaCounters[i].pName))
1378          {
1379              return i;
1380          }
1381      }
1382      MP_ASSERT(0);//out of slots, increase MICROPROFILE_META_MAX
1383      return (MicroProfileToken)-1;
1384  }
1385  
1386  
1387  inline void MicroProfileLogPut(MicroProfileToken nToken_, uint64_t nTick, uint64_t nBegin, MicroProfileThreadLog* pLog)
1388  {
1389      MP_ASSERT(pLog != 0); //this assert is hit if MicroProfileOnCreateThread is not called
1390      MP_ASSERT(pLog->nActive);
1391      uint32_t nPos = pLog->nPut.load(std::memory_order_relaxed);
1392      uint32_t nNextPos = (nPos+1) % MICROPROFILE_BUFFER_SIZE;
1393      if(nNextPos == pLog->nGet.load(std::memory_order_relaxed))
1394      {
1395          S.nOverflow = 100;
1396      }
1397      else
1398      {
1399          pLog->Log[nPos] = MicroProfileMakeLogIndex(nBegin, nToken_, nTick);
1400          pLog->nPut.store(nNextPos, std::memory_order_release);
1401      }
1402  }
1403  
1404  uint64_t MicroProfileEnter(MicroProfileToken nToken_)
1405  {
1406      if(MicroProfileGetGroupMask(nToken_) & S.nActiveGroup)
1407      {
1408          if(!MicroProfileGetThreadLog())
1409          {
1410              MicroProfileInitThreadLog();
1411          }
1412          uint64_t nTick = MP_TICK();
1413          MicroProfileLogPut(nToken_, nTick, MP_LOG_ENTER, MicroProfileGetThreadLog());
1414          return nTick;
1415      }
1416      return MICROPROFILE_INVALID_TICK;
1417  }
1418  
1419  void MicroProfileMetaUpdate(MicroProfileToken nToken, int nCount, MicroProfileTokenType eTokenType)
1420  {
1421      if((MP_DRAW_META_FIRST<<nToken) & S.nActiveBars)
1422      {
1423          MicroProfileThreadLog* pLog = MicroProfileTokenTypeCpu == eTokenType ? MicroProfileGetThreadLog() : g_MicroProfileGpuLog;
1424          if(pLog)
1425          {
1426              MP_ASSERT(nToken < MICROPROFILE_META_MAX);
1427              MicroProfileLogPut(nToken, nCount, MP_LOG_META, pLog);
1428          }
1429      }
1430  }
1431  
1432  
1433  void MicroProfileLeave(MicroProfileToken nToken_, uint64_t nTickStart)
1434  {
1435      if(MICROPROFILE_INVALID_TICK != nTickStart)
1436      {
1437          if(!MicroProfileGetThreadLog())
1438          {
1439              MicroProfileInitThreadLog();
1440          }
1441          uint64_t nTick = MP_TICK();
1442          MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();
1443          MicroProfileLogPut(nToken_, nTick, MP_LOG_LEAVE, pLog);
1444      }
1445  }
1446  
1447  
1448  uint64_t MicroProfileGpuEnter(MicroProfileToken nToken_)
1449  {
1450      if(MicroProfileGetGroupMask(nToken_) & S.nActiveGroup)
1451      {
1452          uint64_t nTimer = MicroProfileGpuInsertTimeStamp();
1453          MicroProfileLogPut(nToken_, nTimer, MP_LOG_ENTER, g_MicroProfileGpuLog);
1454          MicroProfileLogPut(nToken_, MP_TICK(), MP_LOG_GPU_EXTRA, g_MicroProfileGpuLog);
1455          return 1;
1456      }
1457      return 0;
1458  }
1459  
1460  void MicroProfileGpuLeave(MicroProfileToken nToken_, uint64_t nTickStart)
1461  {
1462      if(nTickStart)
1463      {
1464          uint64_t nTimer = MicroProfileGpuInsertTimeStamp();
1465          MicroProfileLogPut(nToken_, nTimer, MP_LOG_LEAVE, g_MicroProfileGpuLog);
1466          MicroProfileLogPut(nToken_, MP_TICK(), MP_LOG_GPU_EXTRA, g_MicroProfileGpuLog);
1467      }
1468  }
1469  
1470  inline void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)
1471  {
1472      if(S.nRunning || pContextSwitch->nTicks <= S.nPauseTicks)
1473      {
1474          uint32_t nPut = S.nContextSwitchPut;
1475          S.ContextSwitch[nPut] = *pContextSwitch;
1476          S.nContextSwitchPut = (S.nContextSwitchPut+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;
1477      }
1478  }
1479  
1480  
1481  void MicroProfileGetRange(uint32_t nPut, uint32_t nGet, uint32_t nRange[2][2])
1482  {
1483      if(nPut > nGet)
1484      {
1485          nRange[0][0] = nGet;
1486          nRange[0][1] = nPut;
1487          nRange[1][0] = nRange[1][1] = 0;
1488      }
1489      else if(nPut != nGet)
1490      {
1491          MP_ASSERT(nGet != MICROPROFILE_BUFFER_SIZE);
1492          uint32_t nCountEnd = MICROPROFILE_BUFFER_SIZE - nGet;
1493          nRange[0][0] = nGet;
1494          nRange[0][1] = nGet + nCountEnd;
1495          nRange[1][0] = 0;
1496          nRange[1][1] = nPut;
1497      }
1498  }
1499  
1500  void MicroProfileFlip()
1501  {
1502      #if 0
1503      //verify LogEntry wraps correctly
1504      MicroProfileLogEntry c = MP_LOG_TICK_MASK-5000;
1505      for(int i = 0; i < 10000; ++i, c += 1)
1506      {
1507          MicroProfileLogEntry l2 = (c+2500) & MP_LOG_TICK_MASK;
1508          MP_ASSERT(2500 == MicroProfileLogTickDifference(c, l2));
1509      }
1510      #endif
1511      MICROPROFILE_SCOPE(g_MicroProfileFlip);
1512      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
1513  
1514  
1515      MicroProfileGpuFlip();
1516  
1517      if(S.nToggleRunning)
1518      {
1519          S.nRunning = !S.nRunning;
1520          if(!S.nRunning)
1521              S.nPauseTicks = MP_TICK();
1522          S.nToggleRunning = 0;
1523          for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
1524          {
1525              MicroProfileThreadLog* pLog = S.Pool[i];
1526              if(pLog)
1527              {
1528                  pLog->nStackPos = 0;
1529              }
1530          }
1531      }
1532      uint32_t nAggregateClear = S.nAggregateClear || S.nAutoClearFrames, nAggregateFlip = 0;
1533      if(S.nDumpFileNextFrame)
1534      {
1535          MicroProfileDumpToFile();
1536          S.nDumpFileNextFrame = 0;
1537          S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; //hide spike from dumping webpage
1538      }
1539      if(S.nWebServerDataSent == (uint64_t)-1)
1540      {
1541          MicroProfileWebServerStart();
1542          S.nWebServerDataSent = 0;
1543      }
1544  
1545      if(MicroProfileWebServerUpdate())
1546      {
1547          S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; //hide spike from dumping webpage
1548      }
1549  
1550      if(S.nAutoClearFrames)
1551      {
1552          nAggregateClear = 1;
1553          nAggregateFlip = 1;
1554          S.nAutoClearFrames -= 1;
1555      }
1556  
1557  
1558      if(S.nRunning || S.nForceEnable)
1559      {
1560          S.nFramePutIndex++;
1561          S.nFramePut = (S.nFramePut+1) % MICROPROFILE_MAX_FRAME_HISTORY;
1562          MP_ASSERT((S.nFramePutIndex % MICROPROFILE_MAX_FRAME_HISTORY) == S.nFramePut);
1563          S.nFrameCurrent = (S.nFramePut + MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 1) % MICROPROFILE_MAX_FRAME_HISTORY;
1564          S.nFrameCurrentIndex++;
1565          uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
1566  
1567          uint32_t nContextSwitchPut = S.nContextSwitchPut;
1568          if(S.nContextSwitchLastPut < nContextSwitchPut)
1569          {
1570              S.nContextSwitchUsage = (nContextSwitchPut - S.nContextSwitchLastPut);
1571          }
1572          else
1573          {
1574              S.nContextSwitchUsage = MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - S.nContextSwitchLastPut + nContextSwitchPut;
1575          }
1576          S.nContextSwitchLastPut = nContextSwitchPut;
1577  
1578          MicroProfileFrameState* pFramePut = &S.Frames[S.nFramePut];
1579          MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
1580          MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
1581  
1582          pFramePut->nFrameStartCpu = MP_TICK();
1583          pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp();
1584          if(static_cast<uint64_t>(pFrameNext->nFrameStartGpu) != (uint64_t)-1)
1585              pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);
1586  
1587          if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1)
1588              pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1;
1589  
1590          uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
1591          uint64_t nFrameEndCpu = pFrameNext->nFrameStartCpu;
1592  
1593          {
1594              uint64_t nTick = nFrameEndCpu - nFrameStartCpu;
1595              S.nFlipTicks = nTick;
1596              S.nFlipAggregate += nTick;
1597              S.nFlipMax = MicroProfileMax(S.nFlipMax, nTick);
1598          }
1599  
1600          uint8_t* pTimerToGroup = &S.TimerToGroup[0];
1601          for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
1602          {
1603              MicroProfileThreadLog* pLog = S.Pool[i];
1604              if(!pLog)
1605              {
1606                  pFramePut->nLogStart[i] = 0;
1607              }
1608              else
1609              {
1610                  uint32_t nPut = pLog->nPut.load(std::memory_order_acquire);
1611                  pFramePut->nLogStart[i] = nPut;
1612                  MP_ASSERT(nPut< MICROPROFILE_BUFFER_SIZE);
1613                  //need to keep last frame around to close timers. timers more than 1 frame old is ditched.
1614                  pLog->nGet.store(nPut, std::memory_order_relaxed);
1615              }
1616          }
1617  
1618          if(S.nRunning)
1619          {
1620              uint64_t* pFrameGroup = &S.FrameGroup[0];
1621              {
1622                  MICROPROFILE_SCOPE(g_MicroProfileClear);
1623                  for(uint32_t i = 0; i < S.nTotalTimers; ++i)
1624                  {
1625                      S.Frame[i].nTicks = 0;
1626                      S.Frame[i].nCount = 0;
1627                      S.FrameExclusive[i] = 0;
1628                  }
1629                  for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
1630                  {
1631                      pFrameGroup[i] = 0;
1632                  }
1633                  for(uint32_t j = 0; j < MICROPROFILE_META_MAX; ++j)
1634                  {
1635                      if(S.MetaCounters[j].pName && 0 != (S.nActiveBars & (MP_DRAW_META_FIRST<<j)))
1636                      {
1637                          auto& Meta = S.MetaCounters[j];
1638                          for(uint32_t i = 0; i < S.nTotalTimers; ++i)
1639                          {
1640                              Meta.nCounters[i] = 0;
1641                          }
1642                      }
1643                  }
1644  
1645              }
1646              {
1647                  MICROPROFILE_SCOPE(g_MicroProfileThreadLoop);
1648                  for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
1649                  {
1650                      MicroProfileThreadLog* pLog = S.Pool[i];
1651                      if(!pLog)
1652                          continue;
1653  
1654                      uint8_t* pGroupStackPos = &pLog->nGroupStackPos[0];
1655                      int64_t nGroupTicks[MICROPROFILE_MAX_GROUPS] = {0};
1656  
1657  
1658                      uint32_t nPut = pFrameNext->nLogStart[i];
1659                      uint32_t nGet = pFrameCurrent->nLogStart[i];
1660                      uint32_t nRange[2][2] = { {0, 0}, {0, 0}, };
1661                      MicroProfileGetRange(nPut, nGet, nRange);
1662  
1663  
1664                      //fetch gpu results.
1665                      if(pLog->nGpu)
1666                      {
1667                          for(uint32_t j = 0; j < 2; ++j)
1668                          {
1669                              uint32_t nStart = nRange[j][0];
1670                              uint32_t nEnd = nRange[j][1];
1671                              for(uint32_t k = nStart; k < nEnd; ++k)
1672                              {
1673                                  MicroProfileLogEntry L = pLog->Log[k];
1674                                  if(MicroProfileLogType(L) < MP_LOG_META)
1675                                  {
1676                                      pLog->Log[k] = MicroProfileLogSetTick(L, MicroProfileGpuGetTimeStamp((uint32_t)MicroProfileLogGetTick(L)));
1677                                  }
1678                              }
1679                          }
1680                      }
1681  
1682  
1683                      uint32_t* pStack = &pLog->nStack[0];
1684                      int64_t* pChildTickStack = &pLog->nChildTickStack[0];
1685                      uint32_t nStackPos = pLog->nStackPos;
1686  
1687                      for(uint32_t j = 0; j < 2; ++j)
1688                      {
1689                          uint32_t nStart = nRange[j][0];
1690                          uint32_t nEnd = nRange[j][1];
1691                          for(uint32_t k = nStart; k < nEnd; ++k)
1692                          {
1693                              MicroProfileLogEntry LE = pLog->Log[k];
1694                              int nType = MicroProfileLogType(LE);
1695  
1696                              if(MP_LOG_ENTER == nType)
1697                              {
1698                                  int nTimer = MicroProfileLogTimerIndex(LE);
1699                                  uint8_t nGroup = pTimerToGroup[nTimer];
1700                                  MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
1701                                  MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);
1702                                  pGroupStackPos[nGroup]++;
1703                                  pStack[nStackPos++] = k;
1704                                  pChildTickStack[nStackPos] = 0;
1705  
1706                              }
1707                              else if(MP_LOG_META == nType)
1708                              {
1709                                  if(nStackPos)
1710                                  {
1711                                      int64_t nMetaIndex = MicroProfileLogTimerIndex(LE);
1712                                      int64_t nMetaCount = MicroProfileLogGetTick(LE);
1713                                      MP_ASSERT(nMetaIndex < MICROPROFILE_META_MAX);
1714                                      int64_t nCounter = MicroProfileLogTimerIndex(pLog->Log[pStack[nStackPos-1]]);
1715                                      S.MetaCounters[nMetaIndex].nCounters[nCounter] += nMetaCount;
1716                                  }
1717                              }
1718                              else if(MP_LOG_LEAVE == nType)
1719                              {
1720                                  int nTimer = MicroProfileLogTimerIndex(LE);
1721                                  uint8_t nGroup = pTimerToGroup[nTimer];
1722                                  MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);
1723                                  if(nStackPos)
1724                                  {
1725                                      int64_t nTickStart = pLog->Log[pStack[nStackPos-1]];
1726                                      int64_t nTicks = MicroProfileLogTickDifference(nTickStart, LE);
1727                                      int64_t nChildTicks = pChildTickStack[nStackPos];
1728                                      nStackPos--;
1729                                      pChildTickStack[nStackPos] += nTicks;
1730  
1731                                      uint32_t nTimerIndex = MicroProfileLogTimerIndex(LE);
1732                                      S.Frame[nTimerIndex].nTicks += nTicks;
1733                                      S.FrameExclusive[nTimerIndex] += (nTicks-nChildTicks);
1734                                      S.Frame[nTimerIndex].nCount += 1;
1735  
1736                                      MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);
1737                                      uint8_t nGroupStackPos = pGroupStackPos[nGroup];
1738                                      if(nGroupStackPos)
1739                                      {
1740                                          nGroupStackPos--;
1741                                          if(0 == nGroupStackPos)
1742                                          {
1743                                              nGroupTicks[nGroup] += nTicks;
1744                                          }
1745                                          pGroupStackPos[nGroup] = nGroupStackPos;
1746                                      }
1747                                  }
1748                              }
1749                          }
1750                      }
1751                      for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1752                      {
1753                          pLog->nGroupTicks[j] += nGroupTicks[j];
1754                          pFrameGroup[j] += nGroupTicks[j];
1755                      }
1756                      pLog->nStackPos = nStackPos;
1757                  }
1758              }
1759              {
1760                  MICROPROFILE_SCOPE(g_MicroProfileAccumulate);
1761                  for(uint32_t i = 0; i < S.nTotalTimers; ++i)
1762                  {
1763                      S.AccumTimers[i].nTicks += S.Frame[i].nTicks;
1764                      S.AccumTimers[i].nCount += S.Frame[i].nCount;
1765                      S.AccumMaxTimers[i] = MicroProfileMax(S.AccumMaxTimers[i], S.Frame[i].nTicks);
1766                      S.AccumTimersExclusive[i] += S.FrameExclusive[i];
1767                      S.AccumMaxTimersExclusive[i] = MicroProfileMax(S.AccumMaxTimersExclusive[i], S.FrameExclusive[i]);
1768                  }
1769  
1770                  for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
1771                  {
1772                      S.AccumGroup[i] += pFrameGroup[i];
1773                      S.AccumGroupMax[i] = MicroProfileMax(S.AccumGroupMax[i], pFrameGroup[i]);
1774                  }
1775  
1776                  for(uint32_t j = 0; j < MICROPROFILE_META_MAX; ++j)
1777                  {
1778                      if(S.MetaCounters[j].pName && 0 != (S.nActiveBars & (MP_DRAW_META_FIRST<<j)))
1779                      {
1780                          auto& Meta = S.MetaCounters[j];
1781                          uint64_t nSum = 0;;
1782                          for(uint32_t i = 0; i < S.nTotalTimers; ++i)
1783                          {
1784                              uint64_t nCounter = Meta.nCounters[i];
1785                              Meta.nAccumMax[i] = MicroProfileMax(Meta.nAccumMax[i], nCounter);
1786                              Meta.nAccum[i] += nCounter;
1787                              nSum += nCounter;
1788                          }
1789                          Meta.nSumAccum += nSum;
1790                          Meta.nSumAccumMax = MicroProfileMax(Meta.nSumAccumMax, nSum);
1791                      }
1792                  }
1793              }
1794              for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1795              {
1796                  if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1797                  {
1798                      MicroProfileToken nToken = S.Graph[i].nToken;
1799                      S.Graph[i].nHistory[S.nGraphPut] = S.Frame[MicroProfileGetTimerIndex(nToken)].nTicks;
1800                  }
1801              }
1802              S.nGraphPut = (S.nGraphPut+1) % MICROPROFILE_GRAPH_HISTORY;
1803  
1804          }
1805  
1806  
1807          if(S.nRunning && S.nAggregateFlip <= ++S.nAggregateFlipCount)
1808          {
1809              nAggregateFlip = 1;
1810              if(S.nAggregateFlip) // if 0 accumulate indefinitely
1811              {
1812                  nAggregateClear = 1;
1813              }
1814          }
1815      }
1816      if(nAggregateFlip)
1817      {
1818          memcpy(&S.Aggregate[0], &S.AccumTimers[0], sizeof(S.Aggregate[0]) * S.nTotalTimers);
1819          memcpy(&S.AggregateMax[0], &S.AccumMaxTimers[0], sizeof(S.AggregateMax[0]) * S.nTotalTimers);
1820          memcpy(&S.AggregateExclusive[0], &S.AccumTimersExclusive[0], sizeof(S.AggregateExclusive[0]) * S.nTotalTimers);
1821          memcpy(&S.AggregateMaxExclusive[0], &S.AccumMaxTimersExclusive[0], sizeof(S.AggregateMaxExclusive[0]) * S.nTotalTimers);
1822  
1823          memcpy(&S.AggregateGroup[0], &S.AccumGroup[0], sizeof(S.AggregateGroup));
1824          memcpy(&S.AggregateGroupMax[0], &S.AccumGroupMax[0], sizeof(S.AggregateGroup));
1825  
1826          for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
1827          {
1828              MicroProfileThreadLog* pLog = S.Pool[i];
1829              if(!pLog)
1830                  continue;
1831  
1832              memcpy(&pLog->nAggregateGroupTicks[0], &pLog->nGroupTicks[0], sizeof(pLog->nAggregateGroupTicks));
1833  
1834              if(nAggregateClear)
1835              {
1836                  memset(&pLog->nGroupTicks[0], 0, sizeof(pLog->nGroupTicks));
1837              }
1838          }
1839  
1840          for(uint32_t j = 0; j < MICROPROFILE_META_MAX; ++j)
1841          {
1842              if(S.MetaCounters[j].pName && 0 != (S.nActiveBars & (MP_DRAW_META_FIRST<<j)))
1843              {
1844                  auto& Meta = S.MetaCounters[j];
1845                  memcpy(&Meta.nAggregateMax[0], &Meta.nAccumMax[0], sizeof(Meta.nAggregateMax[0]) * S.nTotalTimers);
1846                  memcpy(&Meta.nAggregate[0], &Meta.nAccum[0], sizeof(Meta.nAggregate[0]) * S.nTotalTimers);
1847                  Meta.nSumAggregate = Meta.nSumAccum;
1848                  Meta.nSumAggregateMax = Meta.nSumAccumMax;
1849                  if(nAggregateClear)
1850                  {
1851                      memset(&Meta.nAccumMax[0], 0, sizeof(Meta.nAccumMax[0]) * S.nTotalTimers);
1852                      memset(&Meta.nAccum[0], 0, sizeof(Meta.nAccum[0]) * S.nTotalTimers);
1853                      Meta.nSumAccum = 0;
1854                      Meta.nSumAccumMax = 0;
1855                  }
1856              }
1857          }
1858  
1859  
1860  
1861  
1862  
1863          S.nAggregateFrames = S.nAggregateFlipCount;
1864          S.nFlipAggregateDisplay = S.nFlipAggregate;
1865          S.nFlipMaxDisplay = S.nFlipMax;
1866          if(nAggregateClear)
1867          {
1868              memset(&S.AccumTimers[0], 0, sizeof(S.Aggregate[0]) * S.nTotalTimers);
1869              memset(&S.AccumMaxTimers[0], 0, sizeof(S.AccumMaxTimers[0]) * S.nTotalTimers);
1870              memset(&S.AccumTimersExclusive[0], 0, sizeof(S.AggregateExclusive[0]) * S.nTotalTimers);
1871              memset(&S.AccumMaxTimersExclusive[0], 0, sizeof(S.AccumMaxTimersExclusive[0]) * S.nTotalTimers);
1872              memset(&S.AccumGroup[0], 0, sizeof(S.AggregateGroup));
1873              memset(&S.AccumGroupMax[0], 0, sizeof(S.AggregateGroup));
1874  
1875              S.nAggregateFlipCount = 0;
1876              S.nFlipAggregate = 0;
1877              S.nFlipMax = 0;
1878  
1879              S.nAggregateFlipTick = MP_TICK();
1880          }
1881      }
1882      S.nAggregateClear = 0;
1883  
1884      uint64_t nNewActiveGroup = 0;
1885      if(S.nForceEnable || (S.nDisplay && S.nRunning))
1886          nNewActiveGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1887      nNewActiveGroup |= S.nForceGroup;
1888      nNewActiveGroup |= S.nForceGroupUI;
1889      if(S.nActiveGroup != nNewActiveGroup)
1890          S.nActiveGroup = nNewActiveGroup;
1891      uint32_t nNewActiveBars = 0;
1892      if(S.nDisplay && S.nRunning)
1893          nNewActiveBars = S.nBars;
1894      if(S.nForceMetaCounters)
1895      {
1896          for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
1897          {
1898              if(S.MetaCounters[i].pName)
1899              {
1900                  nNewActiveBars |= (MP_DRAW_META_FIRST<<i);
1901              }
1902          }
1903      }
1904      if(nNewActiveBars != S.nActiveBars)
1905          S.nActiveBars = nNewActiveBars;
1906  }
1907  
1908  void MicroProfileSetForceEnable(bool bEnable)
1909  {
1910      S.nForceEnable = bEnable ? 1 : 0;
1911  }
1912  bool MicroProfileGetForceEnable()
1913  {
1914      return S.nForceEnable != 0;
1915  }
1916  
1917  void MicroProfileSetEnableAllGroups(bool bEnableAllGroups)
1918  {
1919      S.nAllGroupsWanted = bEnableAllGroups ? 1 : 0;
1920  }
1921  
1922  inline void MicroProfileEnableCategory(const char* pCategory, bool bEnabled)
1923  {
1924      int nCategoryIndex = -1;
1925      for(uint32_t i = 0; i < S.nCategoryCount; ++i)
1926      {
1927          if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName))
1928          {
1929              nCategoryIndex = (int)i;
1930              break;
1931          }
1932      }
1933      if(nCategoryIndex >= 0)
1934      {
1935          if(bEnabled)
1936          {
1937              S.nActiveGroupWanted |= S.CategoryInfo[nCategoryIndex].nGroupMask;
1938          }
1939          else
1940          {
1941              S.nActiveGroupWanted &= ~S.CategoryInfo[nCategoryIndex].nGroupMask;
1942          }
1943      }
1944  }
1945  
1946  
1947  void MicroProfileEnableCategory(const char* pCategory)
1948  {
1949      MicroProfileEnableCategory(pCategory, true);
1950  }
1951  void MicroProfileDisableCategory(const char* pCategory)
1952  {
1953      MicroProfileEnableCategory(pCategory, false);
1954  }
1955  
1956  bool MicroProfileGetEnableAllGroups()
1957  {
1958      return 0 != S.nAllGroupsWanted;
1959  }
1960  
1961  void MicroProfileSetForceMetaCounters(bool bForce)
1962  {
1963      S.nForceMetaCounters = bForce ? 1 : 0;
1964  }
1965  
1966  bool MicroProfileGetForceMetaCounters()
1967  {
1968      return 0 != S.nForceMetaCounters;
1969  }
1970  
1971  void MicroProfileEnableMetaCounter(const char* pMeta)
1972  {
1973      for(uint32_t i = 0; i < MICROPROFILE_META_MAX; ++i)
1974      {
1975          if(S.MetaCounters[i].pName && 0 == MP_STRCASECMP(S.MetaCounters[i].pName, pMeta))
1976          {
1977              S.nBars |= (MP_DRAW_META_FIRST<<i);
1978              return;
1979          }
1980      }
1981  }
1982  void MicroProfileDisableMetaCounter(const char* pMeta)
1983  {
1984      for(uint32_t i = 0; i < MICROPROFILE_META_MAX; ++i)
1985      {
1986          if(S.MetaCounters[i].pName && 0 == MP_STRCASECMP(S.MetaCounters[i].pName, pMeta))
1987          {
1988              S.nBars &= ~(MP_DRAW_META_FIRST<<i);
1989              return;
1990          }
1991      }
1992  }
1993  
1994  
1995  void MicroProfileSetAggregateFrames(int nFrames)
1996  {
1997      S.nAggregateFlip = (uint32_t)nFrames;
1998      if(0 == nFrames)
1999      {
2000          S.nAggregateClear = 1;
2001      }
2002  }
2003  
2004  int MicroProfileGetAggregateFrames()
2005  {
2006      return S.nAggregateFlip;
2007  }
2008  
2009  int MicroProfileGetCurrentAggregateFrames()
2010  {
2011      return int(S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount);
2012  }
2013  
2014  
2015  void MicroProfileForceEnableGroup(const char* pGroup, MicroProfileTokenType Type)
2016  {
2017      MicroProfileInit();
2018      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
2019      uint16_t nGroup = MicroProfileGetGroup(pGroup, Type);
2020      S.nForceGroup |= (1ll << nGroup);
2021  }
2022  
2023  void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Type)
2024  {
2025      MicroProfileInit();
2026      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
2027      uint16_t nGroup = MicroProfileGetGroup(pGroup, Type);
2028      S.nForceGroup &= ~(1ll << nGroup);
2029  }
2030  
2031  
2032  inline void MicroProfileCalcAllTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)
2033  {
2034      for(uint32_t i = 0; i < S.nTotalTimers && i < nSize; ++i)
2035      {
2036          const uint32_t nGroupId = S.TimerInfo[i].nGroupIndex;
2037          const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
2038          uint32_t nTimer = i;
2039          uint32_t nIdx = i * 2;
2040          uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2041          uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;
2042          float fToPrc = S.fRcpReferenceTime;
2043          float fMs = fToMs * (S.Frame[nTimer].nTicks);
2044          float fPrc = MicroProfileMin(fMs * fToPrc, 1.f);
2045          float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);
2046          float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f);
2047          float fMaxMs = fToMs * (S.AggregateMax[nTimer]);
2048          float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f);
2049          float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);
2050          float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f);
2051          float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);
2052          float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f);
2053          float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);
2054          float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f);
2055          float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);
2056          float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f);
2057          float fTotalMs = fToMs * S.Aggregate[nTimer].nTicks;
2058          pTimers[nIdx] = fMs;
2059          pTimers[nIdx+1] = fPrc;
2060          pAverage[nIdx] = fAverageMs;
2061          pAverage[nIdx+1] = fAveragePrc;
2062          pMax[nIdx] = fMaxMs;
2063          pMax[nIdx+1] = fMaxPrc;
2064          pCallAverage[nIdx] = fCallAverageMs;
2065          pCallAverage[nIdx+1] = fCallAveragePrc;
2066          pExclusive[nIdx] = fMsExclusive;
2067          pExclusive[nIdx+1] = fPrcExclusive;
2068          pAverageExclusive[nIdx] = fAverageMsExclusive;
2069          pAverageExclusive[nIdx+1] = fAveragePrcExclusive;
2070          pMaxExclusive[nIdx] = fMaxMsExclusive;
2071          pMaxExclusive[nIdx+1] = fMaxPrcExclusive;
2072          pTotal[nIdx] = fTotalMs;
2073          pTotal[nIdx+1] = 0.f;
2074      }
2075  }
2076  
2077  void MicroProfileTogglePause()
2078  {
2079      S.nToggleRunning = 1;
2080  }
2081  
2082  float MicroProfileGetTime(const char* pGroup, const char* pName)
2083  {
2084      MicroProfileToken nToken = MicroProfileFindToken(pGroup, pName);
2085      if(nToken == MICROPROFILE_INVALID_TOKEN)
2086      {
2087          return 0.f;
2088      }
2089      uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken);
2090      uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken);
2091      float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
2092      return S.Frame[nTimerIndex].nTicks * fToMs;
2093  }
2094  
2095  
2096  void MicroProfileContextSwitchSearch(uint32_t* pContextSwitchStart, uint32_t* pContextSwitchEnd, uint64_t nBaseTicksCpu, uint64_t nBaseTicksEndCpu)
2097  {
2098      MICROPROFILE_SCOPE(g_MicroProfileContextSwitchSearch);
2099      uint32_t nContextSwitchPut = S.nContextSwitchPut;
2100      uint64_t nContextSwitchStart, nContextSwitchEnd;
2101      nContextSwitchStart = nContextSwitchEnd = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;
2102      int64_t nSearchEnd = nBaseTicksEndCpu + MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu());
2103      int64_t nSearchBegin = nBaseTicksCpu - MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu());
2104      for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; ++i)
2105      {
2106          uint32_t nIndex = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - (i+1)) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;
2107          MicroProfileContextSwitch& CS = S.ContextSwitch[nIndex];
2108          if(CS.nTicks > nSearchEnd)
2109          {
2110              nContextSwitchEnd = nIndex;
2111          }
2112          if(CS.nTicks > nSearchBegin)
2113          {
2114              nContextSwitchStart = nIndex;
2115          }
2116      }
2117      *pContextSwitchStart = nContextSwitchStart;
2118      *pContextSwitchEnd = nContextSwitchEnd;
2119  }
2120  
2121  
2122  
2123  #if MICROPROFILE_WEBSERVER
2124  
2125  #define MICROPROFILE_EMBED_HTML
2126  
2127  extern const char* g_MicroProfileHtml_begin[];
2128  extern size_t g_MicroProfileHtml_begin_sizes[];
2129  extern size_t g_MicroProfileHtml_begin_count;
2130  extern const char* g_MicroProfileHtml_end[];
2131  extern size_t g_MicroProfileHtml_end_sizes[];
2132  extern size_t g_MicroProfileHtml_end_count;
2133  
2134  typedef void MicroProfileWriteCallback(void* Handle, size_t size, const char* pData);
2135  
2136  uint32_t MicroProfileWebServerPort()
2137  {
2138      return S.nWebServerPort;
2139  }
2140  
2141  void MicroProfileDumpFile(const char* pHtml, const char* pCsv)
2142  {
2143      S.nDumpFileNextFrame = 0;
2144      if(pHtml)
2145      {
2146          uint32_t nLen = strlen(pHtml);
2147          if(nLen > sizeof(S.HtmlDumpPath)-1)
2148          {
2149              return;
2150          }
2151          memcpy(S.HtmlDumpPath, pHtml, nLen+1);
2152          S.nDumpFileNextFrame |= 1;
2153      }
2154      if(pCsv)
2155      {
2156          uint32_t nLen = strlen(pCsv);
2157          if(nLen > sizeof(S.CsvDumpPath)-1)
2158          {
2159              return;
2160          }
2161          memcpy(S.CsvDumpPath, pCsv, nLen+1);
2162          S.nDumpFileNextFrame |= 2;
2163      }
2164  }
2165  
2166  void MicroProfilePrintf(MicroProfileWriteCallback CB, void* Handle, const char* pFmt, ...)
2167  {
2168      char buffer[32*1024];
2169      va_list args;
2170      va_start (args, pFmt);
2171  #ifdef _WIN32
2172      size_t size = vsprintf_s(buffer, pFmt, args);
2173  #else
2174      size_t size = vsnprintf(buffer, sizeof(buffer)-1,  pFmt, args);
2175  #endif
2176      CB(Handle, size, &buffer[0]);
2177      va_end (args);
2178  }
2179  
2180  #define printf(...) MicroProfilePrintf(CB, Handle, __VA_ARGS__)
2181  void MicroProfileDumpCsv(MicroProfileWriteCallback CB, void* Handle, int nMaxFrames)
2182  {
2183      uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2184      float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2185      float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());
2186  
2187      printf("frames,%d\n", nAggregateFrames);
2188      printf("group,name,average,max,callaverage\n");
2189  
2190      uint32_t nNumTimers = S.nTotalTimers;
2191      uint32_t nBlockSize = 2 * nNumTimers;
2192      float* pTimers = (float*)alloca(nBlockSize * 8 * sizeof(float));
2193      float* pAverage = pTimers + nBlockSize;
2194      float* pMax = pTimers + 2 * nBlockSize;
2195      float* pCallAverage = pTimers + 3 * nBlockSize;
2196      float* pTimersExclusive = pTimers + 4 * nBlockSize;
2197      float* pAverageExclusive = pTimers + 5 * nBlockSize;
2198      float* pMaxExclusive = pTimers + 6 * nBlockSize;
2199      float* pTotal = pTimers + 7 * nBlockSize;
2200  
2201      MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers);
2202  
2203      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
2204      {
2205          uint32_t nIdx = i * 2;
2206          printf("\"%s\",\"%s\",%f,%f,%f\n", S.TimerInfo[i].pName, S.GroupInfo[S.TimerInfo[i].nGroupIndex].pName, pAverage[nIdx], pMax[nIdx], pCallAverage[nIdx]);
2207      }
2208  
2209      printf("\n\n");
2210  
2211      printf("group,average,max,total\n");
2212      for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
2213      {
2214          const char* pGroupName = S.GroupInfo[j].pName;
2215          float fToMs =  S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;
2216          if(pGroupName[0] != '\0')
2217          {
2218              printf("\"%s\",%.3f,%.3f,%.3f\n", pGroupName, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j]);
2219          }
2220      }
2221  
2222      printf("\n\n");
2223      printf("group,thread,average,total\n");
2224      for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
2225      {
2226          for(uint32_t i = 0; i < S.nNumLogs; ++i)
2227          {
2228              if(S.Pool[i])
2229              {
2230                  const char* pThreadName = &S.Pool[i]->ThreadName[0];
2231                  // MicroProfilePrintf(CB, Handle, "var ThreadGroupTime%d = [", i);
2232                  float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;
2233                  {
2234                      uint64_t nTicks = S.Pool[i]->nAggregateGroupTicks[j];
2235                      float fTime = nTicks / nAggregateFrames * fToMs;
2236                      float fTimeTotal = nTicks * fToMs;
2237                      if(fTimeTotal > 0.01f)
2238                      {
2239                          const char* pGroupName = S.GroupInfo[j].pName;
2240                          printf("\"%s\",\"%s\",%.3f,%.3f\n", pGroupName, pThreadName, fTime, fTimeTotal);
2241                      }
2242                  }
2243              }
2244          }
2245      }
2246  
2247      printf("\n\n");
2248      printf("frametimecpu\n");
2249  
2250      const uint32_t nCount = MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3;
2251      const uint32_t nStart = S.nFrameCurrent;
2252      for(uint32_t i = nCount; i > 0; i--)
2253      {
2254          uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
2255          uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY;
2256          uint64_t nTicks = S.Frames[nFrameNext].nFrameStartCpu - S.Frames[nFrame].nFrameStartCpu;
2257          printf("%f,", nTicks * fToMsCPU);
2258      }
2259      printf("\n");
2260  
2261      printf("\n\n");
2262      printf("frametimegpu\n");
2263  
2264      for(uint32_t i = nCount; i > 0; i--)
2265      {
2266          uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
2267          uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY;
2268          uint64_t nTicks = S.Frames[nFrameNext].nFrameStartGpu - S.Frames[nFrame].nFrameStartGpu;
2269          printf("%f,", nTicks * fToMsGPU);
2270      }
2271      printf("\n\n");
2272      printf("Meta\n");//only single frame snapshot
2273      printf("name,average,max,total\n");
2274      for(int j = 0; j < MICROPROFILE_META_MAX; ++j)
2275      {
2276          if(S.MetaCounters[j].pName)
2277          {
2278              printf("\"%s\",%f,%lld,%lld\n",S.MetaCounters[j].pName, S.MetaCounters[j].nSumAggregate / (float)nAggregateFrames, S.MetaCounters[j].nSumAggregateMax,S.MetaCounters[j].nSumAggregate);
2279          }
2280      }
2281  }
2282  #undef printf
2283  
2284  void MicroProfileDumpHtml(MicroProfileWriteCallback CB, void* Handle, int nMaxFrames, const char* pHost)
2285  {
2286      uint32_t nRunning = S.nRunning;
2287      S.nRunning = 0;
2288      //stall pushing of timers
2289      uint64_t nActiveGroup = S.nActiveGroup;
2290      S.nActiveGroup = 0;
2291      S.nPauseTicks = MP_TICK();
2292  
2293  
2294      for(size_t i = 0; i < g_MicroProfileHtml_begin_count; ++i)
2295      {
2296          CB(Handle, g_MicroProfileHtml_begin_sizes[i]-1, g_MicroProfileHtml_begin[i]);
2297      }
2298      //dump info
2299      uint64_t nTicks = MP_TICK();
2300  
2301      float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2302      float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());
2303      float fAggregateMs = fToMsCPU * (nTicks - S.nAggregateFlipTick);
2304      MicroProfilePrintf(CB, Handle, "var DumpHost = '%s';\n", pHost ? pHost : "");
2305      time_t CaptureTime;
2306      time(&CaptureTime);
2307      MicroProfilePrintf(CB, Handle, "var DumpUtcCaptureTime = %ld;\n", CaptureTime);
2308      MicroProfilePrintf(CB, Handle, "var AggregateInfo = {'Frames':%d, 'Time':%f};\n", S.nAggregateFrames, fAggregateMs);
2309  
2310      //categories
2311      MicroProfilePrintf(CB, Handle, "var CategoryInfo = Array(%d);\n",S.nCategoryCount);
2312      for(uint32_t i = 0; i < S.nCategoryCount; ++i)
2313      {
2314          MicroProfilePrintf(CB, Handle, "CategoryInfo[%d] = \"%s\";\n", i, S.CategoryInfo[i].pName);
2315      }
2316  
2317      //groups
2318      MicroProfilePrintf(CB, Handle, "var GroupInfo = Array(%d);\n\n",S.nGroupCount);
2319      uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2320      float fRcpAggregateFrames = 1.f / nAggregateFrames;
2321      for(uint32_t i = 0; i < S.nGroupCount; ++i)
2322      {
2323          MP_ASSERT(i == S.GroupInfo[i].nGroupIndex);
2324          float fToMs = S.GroupInfo[i].Type == MicroProfileTokenTypeCpu ? fToMsCPU : fToMsGPU;
2325          MicroProfilePrintf(CB, Handle, "GroupInfo[%d] = MakeGroup(%d, \"%s\", %d, %d, %d, %f, %f, %f, '#%02x%02x%02x');\n",
2326              S.GroupInfo[i].nGroupIndex,
2327              S.GroupInfo[i].nGroupIndex,
2328              S.GroupInfo[i].pName,
2329              S.GroupInfo[i].nCategory,
2330              S.GroupInfo[i].nNumTimers,
2331              S.GroupInfo[i].Type == MicroProfileTokenTypeGpu?1:0,
2332              fToMs * S.AggregateGroup[i],
2333              fToMs * S.AggregateGroup[i] / nAggregateFrames,
2334              fToMs * S.AggregateGroupMax[i],
2335              MICROPROFILE_UNPACK_RED(S.GroupInfo[i].nColor) & 0xff,
2336              MICROPROFILE_UNPACK_GREEN(S.GroupInfo[i].nColor) & 0xff,
2337              MICROPROFILE_UNPACK_BLUE(S.GroupInfo[i].nColor) & 0xff);
2338      }
2339      //timers
2340  
2341      uint32_t nNumTimers = S.nTotalTimers;
2342      uint32_t nBlockSize = 2 * nNumTimers;
2343      float* pTimers = (float*)alloca(nBlockSize * 8 * sizeof(float));
2344      float* pAverage = pTimers + nBlockSize;
2345      float* pMax = pTimers + 2 * nBlockSize;
2346      float* pCallAverage = pTimers + 3 * nBlockSize;
2347      float* pTimersExclusive = pTimers + 4 * nBlockSize;
2348      float* pAverageExclusive = pTimers + 5 * nBlockSize;
2349      float* pMaxExclusive = pTimers + 6 * nBlockSize;
2350      float* pTotal = pTimers + 7 * nBlockSize;
2351  
2352      MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers);
2353  
2354      MicroProfilePrintf(CB, Handle, "\nvar TimerInfo = Array(%d);\n\n", S.nTotalTimers);
2355      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
2356      {
2357          uint32_t nIdx = i * 2;
2358          MP_ASSERT(i == S.TimerInfo[i].nTimerIndex);
2359          MicroProfilePrintf(CB, Handle, "var Meta%d = [", i);
2360          bool bOnce = true;
2361          for(int j = 0; j < MICROPROFILE_META_MAX; ++j)
2362          {
2363              if(S.MetaCounters[j].pName)
2364              {
2365                  uint32_t lala = S.MetaCounters[j].nCounters[i];
2366                  MicroProfilePrintf(CB, Handle, bOnce ? "%d" : ",%d", lala);
2367                  bOnce = false;
2368              }
2369          }
2370          MicroProfilePrintf(CB, Handle, "];\n");
2371          MicroProfilePrintf(CB, Handle, "var MetaAvg%d = [", i);
2372          bOnce = true;
2373          for(int j = 0; j < MICROPROFILE_META_MAX; ++j)
2374          {
2375              if(S.MetaCounters[j].pName)
2376              {
2377                  MicroProfilePrintf(CB, Handle, bOnce ? "%f" : ",%f", fRcpAggregateFrames * S.MetaCounters[j].nAggregate[i]);
2378                  bOnce = false;
2379              }
2380          }
2381          MicroProfilePrintf(CB, Handle, "];\n");
2382          MicroProfilePrintf(CB, Handle, "var MetaMax%d = [", i);
2383          bOnce = true;
2384          for(int j = 0; j < MICROPROFILE_META_MAX; ++j)
2385          {
2386              if(S.MetaCounters[j].pName)
2387              {
2388                  MicroProfilePrintf(CB, Handle, bOnce ? "%d" : ",%d", S.MetaCounters[j].nAggregateMax[i]);
2389                  bOnce = false;
2390              }
2391          }
2392          MicroProfilePrintf(CB, Handle, "];\n");
2393  
2394  
2395          uint32_t nColor = S.TimerInfo[i].nColor;
2396          uint32_t nColorDark = (nColor >> 1) & ~0x80808080;
2397          MicroProfilePrintf(CB, Handle, "TimerInfo[%d] = MakeTimer(%d, \"%s\", %d, '#%02x%02x%02x','#%02x%02x%02x', %f, %f, %f, %f, %f, %d, %f, Meta%d, MetaAvg%d, MetaMax%d);\n", S.TimerInfo[i].nTimerIndex, S.TimerInfo[i].nTimerIndex, S.TimerInfo[i].pName, S.TimerInfo[i].nGroupIndex,
2398              MICROPROFILE_UNPACK_RED(nColor) & 0xff,
2399              MICROPROFILE_UNPACK_GREEN(nColor) & 0xff,
2400              MICROPROFILE_UNPACK_BLUE(nColor) & 0xff,
2401              MICROPROFILE_UNPACK_RED(nColorDark) & 0xff,
2402              MICROPROFILE_UNPACK_GREEN(nColorDark) & 0xff,
2403              MICROPROFILE_UNPACK_BLUE(nColorDark) & 0xff,
2404              pAverage[nIdx],
2405              pMax[nIdx],
2406              pAverageExclusive[nIdx],
2407              pMaxExclusive[nIdx],
2408              pCallAverage[nIdx],
2409              S.Aggregate[i].nCount,
2410              pTotal[nIdx],
2411              i,i,i);
2412  
2413      }
2414  
2415      MicroProfilePrintf(CB, Handle, "\nvar ThreadNames = [");
2416      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2417      {
2418          if(S.Pool[i])
2419          {
2420              MicroProfilePrintf(CB, Handle, "'%s',", S.Pool[i]->ThreadName);
2421          }
2422          else
2423          {
2424              MicroProfilePrintf(CB, Handle, "'Thread %d',", i);
2425          }
2426      }
2427      MicroProfilePrintf(CB, Handle, "];\n\n");
2428  
2429  
2430      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2431      {
2432          if(S.Pool[i])
2433          {
2434              MicroProfilePrintf(CB, Handle, "var ThreadGroupTime%d = [", i);
2435              float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;
2436              for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
2437              {
2438                  MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j]/nAggregateFrames * fToMs);
2439              }
2440              MicroProfilePrintf(CB, Handle, "];\n");
2441          }
2442      }
2443      MicroProfilePrintf(CB, Handle, "\nvar ThreadGroupTimeArray = [");
2444      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2445      {
2446          if(S.Pool[i])
2447          {
2448              MicroProfilePrintf(CB, Handle, "ThreadGroupTime%d,", i);
2449          }
2450      }
2451      MicroProfilePrintf(CB, Handle, "];\n");
2452  
2453  
2454      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2455      {
2456          if(S.Pool[i])
2457          {
2458              MicroProfilePrintf(CB, Handle, "var ThreadGroupTimeTotal%d = [", i);
2459              float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;
2460              for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
2461              {
2462                  MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j] * fToMs);
2463              }
2464              MicroProfilePrintf(CB, Handle, "];\n");
2465          }
2466      }
2467      MicroProfilePrintf(CB, Handle, "\nvar ThreadGroupTimeTotalArray = [");
2468      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2469      {
2470          if(S.Pool[i])
2471          {
2472              MicroProfilePrintf(CB, Handle, "ThreadGroupTimeTotal%d,", i);
2473          }
2474      }
2475      MicroProfilePrintf(CB, Handle, "];");
2476  
2477  
2478  
2479  
2480      MicroProfilePrintf(CB, Handle, "\nvar ThreadIds = [");
2481      for(uint32_t i = 0; i < S.nNumLogs; ++i)
2482      {
2483          if(S.Pool[i])
2484          {
2485              ThreadIdType ThreadId = S.Pool[i]->nThreadId;
2486              if(!ThreadId)
2487              {
2488                  ThreadId = (ThreadIdType)-1;
2489              }
2490              MicroProfilePrintf(CB, Handle, "%d,", ThreadId);
2491          }
2492          else
2493          {
2494              MicroProfilePrintf(CB, Handle, "-1,", i);
2495          }
2496      }
2497      MicroProfilePrintf(CB, Handle, "];\n\n");
2498  
2499      MicroProfilePrintf(CB, Handle, "\nvar MetaNames = [");
2500      for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
2501      {
2502          if(S.MetaCounters[i].pName)
2503          {
2504              MicroProfilePrintf(CB, Handle, "'%s',", S.MetaCounters[i].pName);
2505          }
2506      }
2507  
2508  
2509      MicroProfilePrintf(CB, Handle, "];\n\n");
2510  
2511  
2512  
2513      uint32_t nNumFrames = (MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3); //leave a few to not overwrite
2514      nNumFrames = MicroProfileMin(nNumFrames, (uint32_t)nMaxFrames);
2515  
2516  
2517      uint32_t nFirstFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;
2518      uint32_t nLastFrame = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;
2519      MP_ASSERT(nLastFrame == (S.nFrameCurrent % MICROPROFILE_MAX_FRAME_HISTORY));
2520      MP_ASSERT(nFirstFrame < MICROPROFILE_MAX_FRAME_HISTORY);
2521      MP_ASSERT(nLastFrame  < MICROPROFILE_MAX_FRAME_HISTORY);
2522      const int64_t nTickStart = S.Frames[nFirstFrame].nFrameStartCpu;
2523      const int64_t nTickEnd = S.Frames[nLastFrame].nFrameStartCpu;
2524      int64_t nTickStartGpu = S.Frames[nFirstFrame].nFrameStartGpu;
2525  
2526      int64_t nTickReferenceCpu, nTickReferenceGpu;
2527      int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();
2528      int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();
2529      int nTickReference = 0;
2530      if(MicroProfileGetGpuTickReference(&nTickReferenceCpu, &nTickReferenceGpu))
2531      {
2532          nTickStartGpu = (nTickStart - nTickReferenceCpu) * nTicksPerSecondGpu / nTicksPerSecondCpu + nTickReferenceGpu;
2533          nTickReference = 1;
2534      }
2535  
2536  
2537  #if MICROPROFILE_DEBUG
2538      printf("dumping %d frames\n", nNumFrames);
2539      printf("dumping frame %d to %d\n", nFirstFrame, nLastFrame);
2540  #endif
2541  
2542  
2543      uint32_t* nTimerCounter = (uint32_t*)alloca(sizeof(uint32_t)* S.nTotalTimers);
2544      memset(nTimerCounter, 0, sizeof(uint32_t) * S.nTotalTimers);
2545  
2546      MicroProfilePrintf(CB, Handle, "var Frames = Array(%d);\n", nNumFrames);
2547      for(uint32_t i = 0; i < nNumFrames; ++i)
2548      {
2549          uint32_t nFrameIndex = (nFirstFrame + i) % MICROPROFILE_MAX_FRAME_HISTORY;
2550          uint32_t nFrameIndexNext = (nFrameIndex + 1) % MICROPROFILE_MAX_FRAME_HISTORY;
2551  
2552          for(uint32_t j = 0; j < S.nNumLogs; ++j)
2553          {
2554              MicroProfileThreadLog* pLog = S.Pool[j];
2555              int64_t nStartTickBase = pLog->nGpu ? nTickStartGpu : nTickStart;
2556              uint32_t nLogStart = S.Frames[nFrameIndex].nLogStart[j];
2557              uint32_t nLogEnd = S.Frames[nFrameIndexNext].nLogStart[j];
2558  
2559              float fToMsCpu = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);
2560              float fToMsBase = MicroProfileTickToMsMultiplier(pLog->nGpu ? nTicksPerSecondGpu : nTicksPerSecondCpu);
2561              MicroProfilePrintf(CB, Handle, "var ts_%d_%d = [", i, j);
2562              if(nLogStart != nLogEnd)
2563              {
2564                  uint32_t k = nLogStart;
2565                  uint32_t nLogType = MicroProfileLogType(pLog->Log[k]);
2566                  float fToMs = nLogType == MP_LOG_GPU_EXTRA ? fToMsCpu : fToMsBase;
2567                  int64_t nStartTick = nLogType == MP_LOG_GPU_EXTRA ? nTickStart : nStartTickBase;
2568                  float fTime = nLogType == MP_LOG_META ? 0.f : MicroProfileLogTickDifference(nStartTick, pLog->Log[k]) * fToMs;
2569                  MicroProfilePrintf(CB, Handle, "%f", fTime);
2570                  for(k = (k+1) % MICROPROFILE_BUFFER_SIZE; k != nLogEnd; k = (k+1) % MICROPROFILE_BUFFER_SIZE)
2571                  {
2572                      uint32_t nLogType = MicroProfileLogType(pLog->Log[k]);
2573                      float fToMs = nLogType == MP_LOG_GPU_EXTRA ? fToMsCpu : fToMsBase;
2574                      nStartTick = nLogType == MP_LOG_GPU_EXTRA ? nTickStart : nStartTickBase;
2575                      float fTime = nLogType == MP_LOG_META ? 0.f : MicroProfileLogTickDifference(nStartTick, pLog->Log[k]) * fToMs;
2576                      MicroProfilePrintf(CB, Handle, ",%f", fTime);
2577                  }
2578              }
2579              MicroProfilePrintf(CB, Handle, "];\n");
2580              MicroProfilePrintf(CB, Handle, "var tt_%d_%d = [", i, j);
2581              if(nLogStart != nLogEnd)
2582              {
2583                  uint32_t k = nLogStart;
2584                  MicroProfilePrintf(CB, Handle, "%d", MicroProfileLogType(pLog->Log[k]));
2585                  for(k = (k+1) % MICROPROFILE_BUFFER_SIZE; k != nLogEnd; k = (k+1) % MICROPROFILE_BUFFER_SIZE)
2586                  {
2587                      uint32_t nLogType = MicroProfileLogType(pLog->Log[k]);
2588                      if(nLogType == MP_LOG_META)
2589                      {
2590                          //for meta, store the count + 3, which is the tick part
2591                          nLogType = 3 + MicroProfileLogGetTick(pLog->Log[k]);
2592                      }
2593                      MicroProfilePrintf(CB, Handle, ",%d", nLogType);
2594                  }
2595              }
2596              MicroProfilePrintf(CB, Handle, "];\n");
2597  
2598              MicroProfilePrintf(CB, Handle, "var ti_%d_%d = [", i, j);
2599              if(nLogStart != nLogEnd)
2600              {
2601                  uint32_t k = nLogStart;
2602                  MicroProfilePrintf(CB, Handle, "%d", (uint32_t)MicroProfileLogTimerIndex(pLog->Log[k]));
2603                  for(k = (k+1) % MICROPROFILE_BUFFER_SIZE; k != nLogEnd; k = (k+1) % MICROPROFILE_BUFFER_SIZE)
2604                  {
2605                      uint32_t nTimerIndex = (uint32_t)MicroProfileLogTimerIndex(pLog->Log[k]);
2606                      MicroProfilePrintf(CB, Handle, ",%d", nTimerIndex);
2607                      nTimerCounter[nTimerIndex]++;
2608                  }
2609              }
2610              MicroProfilePrintf(CB, Handle, "];\n");
2611  
2612          }
2613  
2614          MicroProfilePrintf(CB, Handle, "var ts%d = [", i);
2615          for(uint32_t j = 0; j < S.nNumLogs; ++j)
2616          {
2617              MicroProfilePrintf(CB, Handle, "ts_%d_%d,", i, j);
2618          }
2619          MicroProfilePrintf(CB, Handle, "];\n");
2620          MicroProfilePrintf(CB, Handle, "var tt%d = [", i);
2621          for(uint32_t j = 0; j < S.nNumLogs; ++j)
2622          {
2623              MicroProfilePrintf(CB, Handle, "tt_%d_%d,", i, j);
2624          }
2625          MicroProfilePrintf(CB, Handle, "];\n");
2626  
2627          MicroProfilePrintf(CB, Handle, "var ti%d = [", i);
2628          for(uint32_t j = 0; j < S.nNumLogs; ++j)
2629          {
2630              MicroProfilePrintf(CB, Handle, "ti_%d_%d,", i, j);
2631          }
2632          MicroProfilePrintf(CB, Handle, "];\n");
2633  
2634  
2635          int64_t nFrameStart = S.Frames[nFrameIndex].nFrameStartCpu;
2636          int64_t nFrameEnd = S.Frames[nFrameIndexNext].nFrameStartCpu;
2637  
2638          float fToMs = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);
2639          float fFrameMs = MicroProfileLogTickDifference(nTickStart, nFrameStart) * fToMs;
2640          float fFrameEndMs = MicroProfileLogTickDifference(nTickStart, nFrameEnd) * fToMs;
2641          float fFrameGpuMs = 0;
2642          float fFrameGpuEndMs = 0;
2643          if(nTickReference)
2644          {
2645              fFrameGpuMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndex].nFrameStartGpu) * fToMsGPU;
2646              fFrameGpuEndMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndexNext].nFrameStartGpu) * fToMsGPU;
2647          }
2648          MicroProfilePrintf(CB, Handle, "Frames[%d] = MakeFrame(%d, %f, %f, %f, %f, ts%d, tt%d, ti%d);\n", i, 0, fFrameMs, fFrameEndMs, fFrameGpuMs, fFrameGpuEndMs, i, i, i);
2649      }
2650  
2651      uint32_t nContextSwitchStart = 0;
2652      uint32_t nContextSwitchEnd = 0;
2653      MicroProfileContextSwitchSearch(&nContextSwitchStart, &nContextSwitchEnd, nTickStart, nTickEnd);
2654  
2655      uint32_t nWrittenBefore = S.nWebServerDataSent;
2656      MicroProfilePrintf(CB, Handle, "var CSwitchThreadInOutCpu = [");
2657      for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
2658      {
2659          MicroProfileContextSwitch CS = S.ContextSwitch[j];
2660          int nCpu = CS.nCpu;
2661          MicroProfilePrintf(CB, Handle, "%d,%d,%d,", CS.nThreadIn, CS.nThreadOut, nCpu);
2662      }
2663      MicroProfilePrintf(CB, Handle, "];\n");
2664      MicroProfilePrintf(CB, Handle, "var CSwitchTime = [");
2665      float fToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2666      for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
2667      {
2668          MicroProfileContextSwitch CS = S.ContextSwitch[j];
2669          float fTime = MicroProfileLogTickDifference(nTickStart, CS.nTicks) * fToMsCpu;
2670          MicroProfilePrintf(CB, Handle, "%f,", fTime);
2671      }
2672      MicroProfilePrintf(CB, Handle, "];\n");
2673      uint32_t nWrittenAfter = S.nWebServerDataSent;
2674      MicroProfilePrintf(CB, Handle, "//CSwitch Size %d\n", nWrittenAfter - nWrittenBefore);
2675  
2676  
2677      for(size_t i = 0; i < g_MicroProfileHtml_end_count; ++i)
2678      {
2679          CB(Handle, g_MicroProfileHtml_end_sizes[i]-1, g_MicroProfileHtml_end[i]);
2680      }
2681  
2682      uint32_t* nGroupCounter = (uint32_t*)alloca(sizeof(uint32_t)* S.nGroupCount);
2683  
2684      memset(nGroupCounter, 0, sizeof(uint32_t) * S.nGroupCount);
2685      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
2686      {
2687          uint32_t nGroupIndex = S.TimerInfo[i].nGroupIndex;
2688          nGroupCounter[nGroupIndex] += nTimerCounter[i];
2689      }
2690  
2691      uint32_t* nGroupCounterSort = (uint32_t*)alloca(sizeof(uint32_t)* S.nGroupCount);
2692      uint32_t* nTimerCounterSort = (uint32_t*)alloca(sizeof(uint32_t)* S.nTotalTimers);
2693      for(uint32_t i = 0; i < S.nGroupCount; ++i)
2694      {
2695          nGroupCounterSort[i] = i;
2696      }
2697      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
2698      {
2699          nTimerCounterSort[i] = i;
2700      }
2701      std::sort(nGroupCounterSort, nGroupCounterSort + S.nGroupCount,
2702          [nGroupCounter](const uint32_t l, const uint32_t r)
2703          {
2704              return nGroupCounter[l] > nGroupCounter[r];
2705          }
2706      );
2707  
2708      std::sort(nTimerCounterSort, nTimerCounterSort + S.nTotalTimers,
2709          [nTimerCounter](const uint32_t l, const uint32_t r)
2710          {
2711              return nTimerCounter[l] > nTimerCounter[r];
2712          }
2713      );
2714  
2715      MicroProfilePrintf(CB, Handle, "\n<!--\nMarker Per Group\n");
2716      for(uint32_t i = 0; i < S.nGroupCount; ++i)
2717      {
2718          uint32_t idx = nGroupCounterSort[i];
2719          MicroProfilePrintf(CB, Handle, "%8d:%s\n", nGroupCounter[idx], S.GroupInfo[idx].pName);
2720      }
2721      MicroProfilePrintf(CB, Handle, "Marker Per Timer\n");
2722      for(uint32_t i = 0; i < S.nTotalTimers; ++i)
2723      {
2724          uint32_t idx = nTimerCounterSort[i];
2725          MicroProfilePrintf(CB, Handle, "%8d:%s(%s)\n", nTimerCounter[idx], S.TimerInfo[idx].pName, S.GroupInfo[S.TimerInfo[idx].nGroupIndex].pName);
2726      }
2727      MicroProfilePrintf(CB, Handle, "\n-->\n");
2728  
2729      S.nActiveGroup = nActiveGroup;
2730      S.nRunning = nRunning;
2731  
2732  #if MICROPROFILE_DEBUG
2733      int64_t nTicksEnd = MP_TICK();
2734      float fMs = fToMsCpu * (nTicksEnd - S.nPauseTicks);
2735      printf("html dump took %6.2fms\n", fMs);
2736  #endif
2737  
2738  
2739  }
2740  
2741  void MicroProfileWriteFile(void* Handle, size_t nSize, const char* pData)
2742  {
2743      fwrite(pData, nSize, 1, (FILE*)Handle);
2744  }
2745  
2746  void MicroProfileDumpToFile()
2747  {
2748      std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
2749      if(S.nDumpFileNextFrame&1)
2750      {
2751          FILE* F = fopen(S.HtmlDumpPath, "w");
2752          if(F)
2753          {
2754              MicroProfileDumpHtml(MicroProfileWriteFile, F, MICROPROFILE_WEBSERVER_MAXFRAMES, S.HtmlDumpPath);
2755              fclose(F);
2756          }
2757      }
2758      if(S.nDumpFileNextFrame&2)
2759      {
2760          FILE* F = fopen(S.CsvDumpPath, "w");
2761          if(F)
2762          {
2763              MicroProfileDumpCsv(MicroProfileWriteFile, F, MICROPROFILE_WEBSERVER_MAXFRAMES);
2764              fclose(F);
2765          }
2766      }
2767  }
2768  
2769  void MicroProfileFlushSocket(MpSocket Socket)
2770  {
2771      send(Socket, &S.WebServerBuffer[0], S.WebServerPut, 0);
2772      S.WebServerPut = 0;
2773  
2774  }
2775  
2776  void MicroProfileWriteSocket(void* Handle, size_t nSize, const char* pData)
2777  {
2778      S.nWebServerDataSent += nSize;
2779      MpSocket Socket = *(MpSocket*)Handle;
2780      if(nSize > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE / 2)
2781      {
2782          MicroProfileFlushSocket(Socket);
2783          send(Socket, pData, nSize, 0);
2784  
2785      }
2786      else
2787      {
2788          memcpy(&S.WebServerBuffer[S.WebServerPut], pData, nSize);
2789          S.WebServerPut += nSize;
2790          if(S.WebServerPut > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE/2)
2791          {
2792              MicroProfileFlushSocket(Socket);
2793          }
2794      }
2795  }
2796  
2797  #if MICROPROFILE_MINIZ
2798  #ifndef MICROPROFILE_COMPRESS_BUFFER_SIZE
2799  #define MICROPROFILE_COMPRESS_BUFFER_SIZE (256<<10)
2800  #endif
2801  
2802  #define MICROPROFILE_COMPRESS_CHUNK (MICROPROFILE_COMPRESS_BUFFER_SIZE/2)
2803  struct MicroProfileCompressedSocketState
2804  {
2805      unsigned char DeflateOut[MICROPROFILE_COMPRESS_CHUNK];
2806      unsigned char DeflateIn[MICROPROFILE_COMPRESS_CHUNK];
2807      mz_stream Stream;
2808      MpSocket Socket;
2809      uint32_t nSize;
2810      uint32_t nCompressedSize;
2811      uint32_t nFlushes;
2812      uint32_t nMemmoveBytes;
2813  };
2814  
2815  void MicroProfileCompressedSocketFlush(MicroProfileCompressedSocketState* pState)
2816  {
2817      mz_stream& Stream = pState->Stream;
2818      unsigned char* pSendStart = &pState->DeflateOut[0];
2819      unsigned char* pSendEnd = &pState->DeflateOut[MICROPROFILE_COMPRESS_CHUNK - Stream.avail_out];
2820      if(pSendStart != pSendEnd)
2821      {
2822          send(pState->Socket, (const char*)pSendStart, pSendEnd - pSendStart, 0);
2823          pState->nCompressedSize += pSendEnd - pSendStart;
2824      }
2825      Stream.next_out = &pState->DeflateOut[0];
2826      Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK;
2827  
2828  }
2829  void MicroProfileCompressedSocketStart(MicroProfileCompressedSocketState* pState, MpSocket Socket)
2830  {
2831      mz_stream& Stream = pState->Stream;
2832      memset(&Stream, 0, sizeof(Stream));
2833      Stream.next_out = &pState->DeflateOut[0];
2834      Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK;
2835      Stream.next_in = &pState->DeflateIn[0];
2836      Stream.avail_in = 0;
2837      mz_deflateInit(&Stream, Z_DEFAULT_COMPRESSION);
2838      pState->Socket = Socket;
2839      pState->nSize = 0;
2840      pState->nCompressedSize = 0;
2841      pState->nFlushes = 0;
2842      pState->nMemmoveBytes = 0;
2843  
2844  }
2845  void MicroProfileCompressedSocketFinish(MicroProfileCompressedSocketState* pState)
2846  {
2847      mz_stream& Stream = pState->Stream;
2848      MicroProfileCompressedSocketFlush(pState);
2849      int r = mz_deflate(&Stream, MZ_FINISH);
2850      MP_ASSERT(r == MZ_STREAM_END);
2851      MicroProfileCompressedSocketFlush(pState);
2852      r = mz_deflateEnd(&Stream);
2853      MP_ASSERT(r == MZ_OK);
2854  }
2855  
2856  void MicroProfileCompressedWriteSocket(void* Handle, size_t nSize, const char* pData)
2857  {
2858      MicroProfileCompressedSocketState* pState = (MicroProfileCompressedSocketState*)Handle;
2859      mz_stream& Stream = pState->Stream;
2860      const unsigned char* pDeflateInEnd = Stream.next_in + Stream.avail_in;
2861      const unsigned char* pDeflateInStart = &pState->DeflateIn[0];
2862      const unsigned char* pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK];
2863      pState->nSize += nSize;
2864      if(nSize <= pDeflateInRealEnd - pDeflateInEnd)
2865      {
2866          memcpy((void*)pDeflateInEnd, pData, nSize);
2867          Stream.avail_in += nSize;
2868          MP_ASSERT(Stream.next_in + Stream.avail_in <= pDeflateInRealEnd);
2869          return;
2870      }
2871      int Flush = 0;
2872      while(nSize)
2873      {
2874          pDeflateInEnd = Stream.next_in + Stream.avail_in;
2875          if(Flush)
2876          {
2877              pState->nFlushes++;
2878              MicroProfileCompressedSocketFlush(pState);
2879              pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK];
2880              if(pDeflateInEnd == pDeflateInRealEnd)
2881              {
2882                  if(Stream.avail_in)
2883                  {
2884                      MP_ASSERT(pDeflateInStart != Stream.next_in);
2885                      memmove((void*)pDeflateInStart, Stream.next_in, Stream.avail_in);
2886                      pState->nMemmoveBytes += Stream.avail_in;
2887                  }
2888                  Stream.next_in = pDeflateInStart;
2889                  pDeflateInEnd = Stream.next_in + Stream.avail_in;
2890              }
2891          }
2892          size_t nSpace = pDeflateInRealEnd - pDeflateInEnd;
2893          size_t nBytes = MicroProfileMin(nSpace, nSize);
2894          MP_ASSERT(nBytes + pDeflateInEnd <= pDeflateInRealEnd);
2895          memcpy((void*)pDeflateInEnd, pData, nBytes);
2896          Stream.avail_in += nBytes;
2897          nSize -= nBytes;
2898          pData += nBytes;
2899          int r = mz_deflate(&Stream, MZ_NO_FLUSH);
2900          Flush = r == MZ_BUF_ERROR || nBytes == 0 || Stream.avail_out == 0 ? 1 : 0;
2901          MP_ASSERT(r == MZ_BUF_ERROR || r == MZ_OK);
2902          if(r == MZ_BUF_ERROR)
2903          {
2904              r = mz_deflate(&Stream, MZ_SYNC_FLUSH);
2905          }
2906      }
2907  }
2908  #endif
2909  
2910  
2911  #ifndef MicroProfileSetNonBlocking //fcntl doesnt work on a some unix like platforms..
2912  void MicroProfileSetNonBlocking(MpSocket Socket, int NonBlocking)
2913  {
2914  #ifdef _WIN32
2915      u_long nonBlocking = NonBlocking ? 1 : 0;
2916      ioctlsocket(Socket, FIONBIO, &nonBlocking);
2917  #else
2918      int Options = fcntl(Socket, F_GETFL);
2919      if(NonBlocking)
2920      {
2921          fcntl(Socket, F_SETFL, Options|O_NONBLOCK);
2922      }
2923      else
2924      {
2925          fcntl(Socket, F_SETFL, Options&(~O_NONBLOCK));
2926      }
2927  #endif
2928  }
2929  #endif
2930  
2931  void MicroProfileWebServerStart()
2932  {
2933  #ifdef _WIN32
2934      WSADATA wsa;
2935      if(WSAStartup(MAKEWORD(2, 2), &wsa))
2936      {
2937          S.ListenerSocket = -1;
2938          return;
2939      }
2940  #endif
2941  
2942      S.ListenerSocket = socket(PF_INET, SOCK_STREAM, 6);
2943      MP_ASSERT(!MP_INVALID_SOCKET(S.ListenerSocket));
2944      MicroProfileSetNonBlocking(S.ListenerSocket, 1);
2945  
2946      S.nWebServerPort = (uint32_t)-1;
2947      struct sockaddr_in Addr;
2948      Addr.sin_family = AF_INET;
2949      Addr.sin_addr.s_addr = INADDR_ANY;
2950      for(int i = 0; i < 20; ++i)
2951      {
2952          Addr.sin_port = htons(MICROPROFILE_WEBSERVER_PORT+i);
2953          if(0 == bind(S.ListenerSocket, (sockaddr*)&Addr, sizeof(Addr)))
2954          {
2955              S.nWebServerPort = MICROPROFILE_WEBSERVER_PORT+i;
2956              break;
2957          }
2958      }
2959      listen(S.ListenerSocket, 8);
2960  }
2961  
2962  void MicroProfileWebServerStop()
2963  {
2964  #ifdef _WIN32
2965      closesocket(S.ListenerSocket);
2966      WSACleanup();
2967  #else
2968      close(S.ListenerSocket);
2969  #endif
2970  }
2971  
2972  int MicroProfileParseGet(const char* pGet)
2973  {
2974      const char* pStart = pGet;
2975      while(*pGet != '\0')
2976      {
2977          if(*pGet < '0' || *pGet > '9')
2978              return 0;
2979          pGet++;
2980      }
2981      int nFrames = atoi(pStart);
2982      if(nFrames)
2983      {
2984          return nFrames;
2985      }
2986      else
2987      {
2988          return MICROPROFILE_WEBSERVER_MAXFRAMES;
2989      }
2990  }
2991  bool MicroProfileWebServerUpdate()
2992  {
2993      MICROPROFILE_SCOPEI("MicroProfile", "Webserver-update", -1);
2994      MpSocket Connection = accept(S.ListenerSocket, 0, 0);
2995      bool bServed = false;
2996      if(!MP_INVALID_SOCKET(Connection))
2997      {
2998          std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());
2999          char Req[8192];
3000          MicroProfileSetNonBlocking(Connection, 0);
3001          int nReceived = recv(Connection, Req, sizeof(Req)-1, 0);
3002          if(nReceived > 0)
3003          {
3004              Req[nReceived] = '\0';
3005  #if MICROPROFILE_MINIZ
3006  #define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Encoding: deflate\r\nExpires: Tue, 01 Jan 2199 16:00:00 GMT\r\n\r\n"
3007  #else
3008  #define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nExpires: Tue, 01 Jan 2199 16:00:00 GMT\r\n\r\n"
3009  #endif
3010              char* pHttp = strstr(Req, "HTTP/");
3011              char* pGet = strstr(Req, "GET /");
3012              char* pHost = strstr(Req, "Host: ");
3013              auto Terminate = [](char* pString)
3014              {
3015                  char* pEnd = pString;
3016                  while(*pEnd != '\0')
3017                  {
3018                      if(*pEnd == '\r' || *pEnd == '\n' || *pEnd == ' ')
3019                      {
3020                          *pEnd = '\0';
3021                          return;
3022                      }
3023                      pEnd++;
3024                  }
3025              };
3026              if(pHost)
3027              {
3028                  pHost += sizeof("Host: ")-1;
3029                  Terminate(pHost);
3030              }
3031  
3032              if(pHttp && pGet)
3033              {
3034                  *pHttp = '\0';
3035                  pGet += sizeof("GET /")-1;
3036                  Terminate(pGet);
3037                  int nFrames = MicroProfileParseGet(pGet);
3038                  if(nFrames)
3039                  {
3040                      uint64_t nTickStart = MP_TICK();
3041                      send(Connection, MICROPROFILE_HTML_HEADER, sizeof(MICROPROFILE_HTML_HEADER)-1, 0);
3042                      uint64_t nDataStart = S.nWebServerDataSent;
3043                      S.WebServerPut = 0;
3044      #if 0 == MICROPROFILE_MINIZ
3045                      MicroProfileDumpHtml(MicroProfileWriteSocket, &Connection, nFrames, pHost);
3046                      uint64_t nDataEnd = S.nWebServerDataSent;
3047                      uint64_t nTickEnd = MP_TICK();
3048                      uint64_t nDiff = (nTickEnd - nTickStart);
3049                      float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;
3050                      int nKb = ((nDataEnd-nDataStart)>>10) + 1;
3051                      int nCompressedKb = nKb;
3052                      MicroProfilePrintf(MicroProfileWriteSocket, &Connection, "\n<!-- Sent %dkb in %.2fms-->\n\n",nKb, fMs);
3053                      MicroProfileFlushSocket(Connection);
3054      #else
3055                      MicroProfileCompressedSocketState CompressState;
3056                      MicroProfileCompressedSocketStart(&CompressState, Connection);
3057                      MicroProfileDumpHtml(MicroProfileCompressedWriteSocket, &CompressState, nFrames, pHost);
3058                      S.nWebServerDataSent += CompressState.nSize;
3059                      uint64_t nDataEnd = S.nWebServerDataSent;
3060                      uint64_t nTickEnd = MP_TICK();
3061                      uint64_t nDiff = (nTickEnd - nTickStart);
3062                      float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;
3063                      int nKb = ((nDataEnd-nDataStart)>>10) + 1;
3064                      int nCompressedKb = ((CompressState.nCompressedSize)>>10) + 1;
3065                      MicroProfilePrintf(MicroProfileCompressedWriteSocket, &CompressState, "\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);
3066                      MicroProfileCompressedSocketFinish(&CompressState);
3067                      MicroProfileFlushSocket(Connection);
3068      #endif
3069  
3070      #if MICROPROFILE_DEBUG
3071                      printf("\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);
3072      #endif
3073                  }
3074              }
3075          }
3076  #ifdef _WIN32
3077          closesocket(Connection);
3078  #else
3079          close(Connection);
3080  #endif
3081      }
3082      return bServed;
3083  }
3084  #endif
3085  
3086  
3087  
3088  
3089  #if MICROPROFILE_CONTEXT_SWITCH_TRACE
3090  //functions that need to be implemented per platform.
3091  void* MicroProfileTraceThread(void* unused);
3092  bool MicroProfileIsLocalThread(uint32_t nThreadId);
3093  
3094  
3095  void MicroProfileStartContextSwitchTrace()
3096  {
3097      if(!S.bContextSwitchRunning)
3098      {
3099          S.bContextSwitchRunning    = true;
3100          S.bContextSwitchStop = false;
3101          MicroProfileThreadStart(&S.ContextSwitchThread, MicroProfileTraceThread);
3102      }
3103  }
3104  
3105  void MicroProfileStopContextSwitchTrace()
3106  {
3107      if(S.bContextSwitchRunning)
3108      {
3109          S.bContextSwitchStop = true;
3110          MicroProfileThreadJoin(&S.ContextSwitchThread);
3111      }
3112  }
3113  
3114  
3115  #ifdef _WIN32
3116  #define INITGUID
3117  #include <evntrace.h>
3118  #include <evntcons.h>
3119  #include <strsafe.h>
3120  
3121  
3122  static GUID g_MicroProfileThreadClassGuid = { 0x3d6fa8d1, 0xfe05, 0x11d0, 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c };
3123  
3124  struct MicroProfileSCSwitch
3125  {
3126      uint32_t NewThreadId;
3127      uint32_t OldThreadId;
3128      int8_t   NewThreadPriority;
3129      int8_t   OldThreadPriority;
3130      uint8_t  PreviousCState;
3131      int8_t   SpareByte;
3132      int8_t   OldThreadWaitReason;
3133      int8_t   OldThreadWaitMode;
3134      int8_t   OldThreadState;
3135      int8_t   OldThreadWaitIdealProcessor;
3136      uint32_t NewThreadWaitTime;
3137      uint32_t Reserved;
3138  };
3139  
3140  
3141  VOID WINAPI MicroProfileContextSwitchCallback(PEVENT_TRACE pEvent)
3142  {
3143      if (pEvent->Header.Guid == g_MicroProfileThreadClassGuid)
3144      {
3145          if (pEvent->Header.Class.Type == 36)
3146          {
3147              MicroProfileSCSwitch* pCSwitch = (MicroProfileSCSwitch*) pEvent->MofData;
3148              if ((pCSwitch->NewThreadId != 0) || (pCSwitch->OldThreadId != 0))
3149              {
3150                  MicroProfileContextSwitch Switch;
3151                  Switch.nThreadOut = pCSwitch->OldThreadId;
3152                  Switch.nThreadIn = pCSwitch->NewThreadId;
3153                  Switch.nCpu = pEvent->BufferContext.ProcessorNumber;
3154                  Switch.nTicks = pEvent->Header.TimeStamp.QuadPart;
3155                  MicroProfileContextSwitchPut(&Switch);
3156              }
3157          }
3158      }
3159  }
3160  
3161  ULONG WINAPI MicroProfileBufferCallback(PEVENT_TRACE_LOGFILE Buffer)
3162  {
3163      return (S.bContextSwitchStop || !S.bContextSwitchRunning) ? FALSE : TRUE;
3164  }
3165  
3166  
3167  struct MicroProfileKernelTraceProperties : public EVENT_TRACE_PROPERTIES
3168  {
3169      char dummy[sizeof(KERNEL_LOGGER_NAME)];
3170  };
3171  
3172  void MicroProfileContextSwitchShutdownTrace()
3173  {
3174      TRACEHANDLE SessionHandle = 0;
3175      MicroProfileKernelTraceProperties sessionProperties;
3176  
3177      ZeroMemory(&sessionProperties, sizeof(sessionProperties));
3178      sessionProperties.Wnode.BufferSize = sizeof(sessionProperties);
3179      sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
3180      sessionProperties.Wnode.ClientContext = 1; //QPC clock resolution
3181      sessionProperties.Wnode.Guid = SystemTraceControlGuid;
3182      sessionProperties.BufferSize = 1;
3183      sessionProperties.NumberOfBuffers = 128;
3184      sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
3185      sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
3186      sessionProperties.MaximumFileSize = 0;
3187      sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
3188      sessionProperties.LogFileNameOffset = 0;
3189  
3190      EVENT_TRACE_LOGFILE log;
3191      ZeroMemory(&log, sizeof(log));
3192      log.LoggerName = KERNEL_LOGGER_NAME;
3193      log.ProcessTraceMode = 0;
3194      TRACEHANDLE hLog = OpenTrace(&log);
3195      if (hLog)
3196      {
3197          ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties, EVENT_TRACE_CONTROL_STOP);
3198      }
3199      CloseTrace(hLog);
3200  
3201  
3202  }
3203  
3204  void* MicroProfileTraceThread(void* unused)
3205  {
3206  
3207      MicroProfileContextSwitchShutdownTrace();
3208      ULONG status = ERROR_SUCCESS;
3209      TRACEHANDLE SessionHandle = 0;
3210      MicroProfileKernelTraceProperties sessionProperties;
3211  
3212      ZeroMemory(&sessionProperties, sizeof(sessionProperties));
3213      sessionProperties.Wnode.BufferSize = sizeof(sessionProperties);
3214      sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
3215      sessionProperties.Wnode.ClientContext = 1; //QPC clock resolution
3216      sessionProperties.Wnode.Guid = SystemTraceControlGuid;
3217      sessionProperties.BufferSize = 1;
3218      sessionProperties.NumberOfBuffers = 128;
3219      sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH|EVENT_TRACE_FLAG_PROCESS;
3220      sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
3221      sessionProperties.MaximumFileSize = 0;
3222      sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
3223      sessionProperties.LogFileNameOffset = 0;
3224  
3225  
3226      status = StartTrace((PTRACEHANDLE) &SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties);
3227  
3228      if (ERROR_SUCCESS != status)
3229      {
3230          S.bContextSwitchRunning = false;
3231          return 0;
3232      }
3233  
3234      EVENT_TRACE_LOGFILE log;
3235      ZeroMemory(&log, sizeof(log));
3236  
3237      log.LoggerName = KERNEL_LOGGER_NAME;
3238      log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
3239      log.EventCallback = MicroProfileContextSwitchCallback;
3240      log.BufferCallback = MicroProfileBufferCallback;
3241  
3242      TRACEHANDLE hLog = OpenTrace(&log);
3243      ProcessTrace(&hLog, 1, 0, 0);
3244      CloseTrace(hLog);
3245      MicroProfileContextSwitchShutdownTrace();
3246  
3247      S.bContextSwitchRunning = false;
3248      return 0;
3249  }
3250  
3251  bool MicroProfileIsLocalThread(uint32_t nThreadId)
3252  {
3253      HANDLE h = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, nThreadId);
3254      if(h == NULL)
3255          return false;
3256      DWORD hProcess = GetProcessIdOfThread(h);
3257      CloseHandle(h);
3258      return GetCurrentProcessId() == hProcess;
3259  }
3260  
3261  #elif defined(__APPLE__)
3262  #include <sys/time.h>
3263  void* MicroProfileTraceThread(void* unused)
3264  {
3265      FILE* pFile = fopen("mypipe", "r");
3266      if(!pFile)
3267      {
3268          printf("CONTEXT SWITCH FAILED TO OPEN FILE: make sure to run dtrace script\n");
3269          S.bContextSwitchRunning = false;
3270          return 0;
3271      }
3272      printf("STARTING TRACE THREAD\n");
3273      char* pLine = 0;
3274      size_t cap = 0;
3275      size_t len = 0;
3276      struct timeval tv;
3277  
3278      gettimeofday(&tv, NULL);
3279  
3280      uint64_t nsSinceEpoch = ((uint64_t)(tv.tv_sec) * 1000000 + (uint64_t)(tv.tv_usec)) * 1000;
3281      uint64_t nTickEpoch = MP_TICK();
3282      uint32_t nLastThread[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS] = {0};
3283      mach_timebase_info_data_t sTimebaseInfo;
3284      mach_timebase_info(&sTimebaseInfo);
3285      S.bContextSwitchRunning = true;
3286  
3287      uint64_t nProcessed = 0;
3288      uint64_t nProcessedLast = 0;
3289      while((len = getline(&pLine, &cap, pFile))>0 && !S.bContextSwitchStop)
3290      {
3291          nProcessed += len;
3292          if(nProcessed - nProcessedLast > 10<<10)
3293          {
3294              nProcessedLast = nProcessed;
3295              printf("processed %llukb %llukb\n", (nProcessed-nProcessedLast)>>10,nProcessed >>10);
3296          }
3297  
3298          char* pX = strchr(pLine, 'X');
3299          if(pX)
3300          {
3301              int cpu = atoi(pX+1);
3302              char* pX2 = strchr(pX + 1, 'X');
3303              char* pX3 = strchr(pX2 + 1, 'X');
3304              int thread = atoi(pX2+1);
3305              char* lala;
3306              int64_t timestamp = strtoll(pX3 + 1, &lala, 10);
3307              MicroProfileContextSwitch Switch;
3308  
3309              //convert to ticks.
3310              uint64_t nDeltaNsSinceEpoch = timestamp - nsSinceEpoch;
3311              uint64_t nDeltaTickSinceEpoch = sTimebaseInfo.numer * nDeltaNsSinceEpoch / sTimebaseInfo.denom;
3312              uint64_t nTicks = nDeltaTickSinceEpoch + nTickEpoch;
3313              if(cpu < MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS)
3314              {
3315                  Switch.nThreadOut = nLastThread[cpu];
3316                  Switch.nThreadIn = thread;
3317                  nLastThread[cpu] = thread;
3318                  Switch.nCpu = cpu;
3319                  Switch.nTicks = nTicks;
3320                  MicroProfileContextSwitchPut(&Switch);
3321              }
3322          }
3323      }
3324      printf("EXITING TRACE THREAD\n");
3325      S.bContextSwitchRunning = false;
3326      return 0;
3327  }
3328  
3329  bool MicroProfileIsLocalThread(uint32_t nThreadId)
3330  {
3331      return false;
3332  }
3333  
3334  #endif
3335  #else
3336  
3337  bool MicroProfileIsLocalThread([[maybe_unused]] uint32_t nThreadId) { return false; }
3338  void MicroProfileStopContextSwitchTrace(){}
3339  void MicroProfileStartContextSwitchTrace(){}
3340  
3341  #endif
3342  
3343  
3344  
3345  
3346  #if MICROPROFILE_GPU_TIMERS_D3D11
3347  uint32_t MicroProfileGpuInsertTimeStamp()
3348  {
3349      MicroProfileD3D11Frame& Frame = S.GPU.m_QueryFrames[S.GPU.m_nQueryFrame];
3350      if(Frame.m_nRateQueryStarted)
3351      {
3352          uint32_t nCurrent = (Frame.m_nQueryStart + Frame.m_nQueryCount) % MICROPROFILE_D3D_MAX_QUERIES;
3353          uint32_t nNext = (nCurrent + 1) % MICROPROFILE_D3D_MAX_QUERIES;
3354          if(nNext != S.GPU.m_nQueryGet)
3355          {
3356              Frame.m_nQueryCount++;
3357              ID3D11Query* pQuery = (ID3D11Query*)S.GPU.m_pQueries[nCurrent];
3358              ID3D11DeviceContext* pContext = (ID3D11DeviceContext*)S.GPU.m_pDeviceContext;
3359              pContext->End(pQuery);
3360              S.GPU.m_nQueryPut = nNext;
3361              return nCurrent;
3362          }
3363      }
3364      return (uint32_t)-1;
3365  }
3366  
3367  uint64_t MicroProfileGpuGetTimeStamp(uint32_t nIndex)
3368  {
3369      if(nIndex == (uint32_t)-1)
3370      {
3371          return (uint64_t)-1;
3372      }
3373      int64_t nResult = S.GPU.m_nQueryResults[nIndex];
3374      MP_ASSERT(nResult != -1);
3375      return nResult;
3376  }
3377  
3378  bool MicroProfileGpuGetData(void* pQuery, void* pData, uint32_t nDataSize)
3379  {
3380      HRESULT hr;
3381      do
3382      {
3383          hr = ((ID3D11DeviceContext*)S.GPU.m_pDeviceContext)->GetData((ID3D11Query*)pQuery, pData, nDataSize, 0);
3384      }while(hr == S_FALSE);
3385      switch(hr)
3386      {
3387          case DXGI_ERROR_DEVICE_REMOVED:
3388          case DXGI_ERROR_INVALID_CALL:
3389          case E_INVALIDARG:
3390              MP_BREAK();
3391              return false;
3392  
3393      }
3394      return true;
3395  }
3396  
3397  uint64_t MicroProfileTicksPerSecondGpu()
3398  {
3399      return S.GPU.m_nQueryFrequency;
3400  }
3401  
3402  void MicroProfileGpuFlip()
3403  {
3404      MicroProfileD3D11Frame& CurrentFrame = S.GPU.m_QueryFrames[S.GPU.m_nQueryFrame];
3405      ID3D11DeviceContext* pContext = (ID3D11DeviceContext*)S.GPU.m_pDeviceContext;
3406      if(CurrentFrame.m_nRateQueryStarted)
3407      {
3408          pContext->End((ID3D11Query*)CurrentFrame.m_pRateQuery);
3409      }
3410      uint32_t nNextFrame = (S.GPU.m_nQueryFrame + 1) % MICROPROFILE_GPU_FRAME_DELAY;
3411      MicroProfileD3D11Frame& OldFrame = S.GPU.m_QueryFrames[nNextFrame];
3412      if(OldFrame.m_nRateQueryStarted)
3413      {
3414          struct RateQueryResult
3415          {
3416              uint64_t nFrequency;
3417              BOOL bDisjoint;
3418          };
3419          RateQueryResult Result;
3420          if(MicroProfileGpuGetData(OldFrame.m_pRateQuery, &Result, sizeof(Result)))
3421          {
3422              if(S.GPU.m_nQueryFrequency != (int64_t)Result.nFrequency)
3423              {
3424                  if(S.GPU.m_nQueryFrequency)
3425                  {
3426                      OutputDebugString("Query freq changing");
3427                  }
3428                  S.GPU.m_nQueryFrequency = Result.nFrequency;
3429              }
3430              uint32_t nStart = OldFrame.m_nQueryStart;
3431              uint32_t nCount = OldFrame.m_nQueryCount;
3432              for(uint32_t i = 0; i < nCount; ++i)
3433              {
3434                  uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D_MAX_QUERIES;
3435  
3436  
3437  
3438                  if(!MicroProfileGpuGetData(S.GPU.m_pQueries[nIndex], &S.GPU.m_nQueryResults[nIndex], sizeof(uint64_t)))
3439                  {
3440                      S.GPU.m_nQueryResults[nIndex] = -1;
3441                  }
3442              }
3443          }
3444          else
3445          {
3446              uint32_t nStart = OldFrame.m_nQueryStart;
3447              uint32_t nCount = OldFrame.m_nQueryCount;
3448              for(uint32_t i = 0; i < nCount; ++i)
3449              {
3450                  uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D_MAX_QUERIES;
3451                  S.GPU.m_nQueryResults[nIndex] = -1;
3452              }
3453          }
3454          S.GPU.m_nQueryGet = (OldFrame.m_nQueryStart + OldFrame.m_nQueryCount) % MICROPROFILE_D3D_MAX_QUERIES;
3455      }
3456  
3457      S.GPU.m_nQueryFrame = nNextFrame;
3458      MicroProfileD3D11Frame& NextFrame = S.GPU.m_QueryFrames[nNextFrame];
3459      pContext->Begin((ID3D11Query*)NextFrame.m_pRateQuery);
3460      NextFrame.m_nQueryStart = S.GPU.m_nQueryPut;
3461      NextFrame.m_nQueryCount = 0;
3462  
3463      NextFrame.m_nRateQueryStarted = 1;
3464  }
3465  
3466  void MicroProfileGpuInitD3D11(void* pDevice_, void* pDeviceContext_)
3467  {
3468      ID3D11Device* pDevice = (ID3D11Device*)pDevice_;
3469      ID3D11DeviceContext* pDeviceContext = (ID3D11DeviceContext*)pDeviceContext_;
3470      S.GPU.m_pDeviceContext = pDeviceContext_;
3471  
3472      D3D11_QUERY_DESC Desc;
3473      Desc.MiscFlags = 0;
3474      Desc.Query = D3D11_QUERY_TIMESTAMP;
3475      for(uint32_t i = 0; i < MICROPROFILE_D3D_MAX_QUERIES; ++i)
3476      {
3477          HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&S.GPU.m_pQueries[i]);
3478          MP_ASSERT(hr == S_OK);
3479          S.GPU.m_nQueryResults[i] = -1;
3480      }
3481      S.GPU.m_nQueryPut = 0;
3482      S.GPU.m_nQueryGet = 0;
3483      S.GPU.m_nQueryFrame = 0;
3484      S.GPU.m_nQueryFrequency = 0;
3485      Desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
3486      for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i)
3487      {
3488          S.GPU.m_QueryFrames[i].m_nQueryStart = 0;
3489          S.GPU.m_QueryFrames[i].m_nQueryCount = 0;
3490          S.GPU.m_QueryFrames[i].m_nRateQueryStarted = 0;
3491          HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&S.GPU.m_QueryFrames[i].m_pRateQuery);
3492          MP_ASSERT(hr == S_OK);
3493      }
3494  }
3495  
3496  
3497  void MicroProfileGpuShutdown()
3498  {
3499      for(uint32_t i = 0; i < MICROPROFILE_D3D_MAX_QUERIES; ++i)
3500      {
3501          ((ID3D11Query*)&S.GPU.m_pQueries[i])->Release();
3502          S.GPU.m_pQueries[i] = 0;
3503      }
3504      for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i)
3505      {
3506          ((ID3D11Query*)S.GPU.m_QueryFrames[i].m_pRateQuery)->Release();
3507          S.GPU.m_QueryFrames[i].m_pRateQuery = 0;
3508      }
3509  }
3510  
3511  int MicroProfileGetGpuTickReference(int64_t* pOutCPU, int64_t* pOutGpu)
3512  {
3513      return 0;
3514  }
3515  
3516  
3517  #elif MICROPROFILE_GPU_TIMERS_GL
3518  void MicroProfileGpuInitGL()
3519  {
3520      S.GPU.GLTimerPos = 0;
3521      glGenQueries(MICROPROFILE_GL_MAX_QUERIES, &S.GPU.GLTimers[0]);
3522  }
3523  
3524  uint32_t MicroProfileGpuInsertTimeStamp()
3525  {
3526      uint32_t nIndex = (S.GPU.GLTimerPos+1)%MICROPROFILE_GL_MAX_QUERIES;
3527      glQueryCounter(S.GPU.GLTimers[nIndex], GL_TIMESTAMP);
3528      S.GPU.GLTimerPos = nIndex;
3529      return nIndex;
3530  }
3531  uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey)
3532  {
3533      uint64_t result;
3534      glGetQueryObjectui64v(S.GPU.GLTimers[nKey], GL_QUERY_RESULT, &result);
3535      return result;
3536  }
3537  
3538  uint64_t MicroProfileTicksPerSecondGpu()
3539  {
3540      return 1000000000ll;
3541  }
3542  
3543  int MicroProfileGetGpuTickReference(int64_t* pOutCpu, int64_t* pOutGpu)
3544  {
3545      int64_t nGpuTimeStamp;
3546      glGetInteger64v(GL_TIMESTAMP, &nGpuTimeStamp);
3547      if(nGpuTimeStamp)
3548      {
3549          *pOutCpu = MP_TICK();
3550          *pOutGpu = nGpuTimeStamp;
3551          #if 0 //debug test if timestamp diverges
3552          static int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();
3553          static int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();
3554          static int64_t nGpuStart = 0;
3555          static int64_t nCpuStart = 0;
3556          if(!nCpuStart)
3557          {
3558              nCpuStart = *pOutCpu;
3559              nGpuStart = *pOutGpu;
3560          }
3561          static int nCountDown = 100;
3562          if(0 == nCountDown--)
3563          {
3564              int64_t nCurCpu = *pOutCpu;
3565              int64_t nCurGpu = *pOutGpu;
3566              double fDistanceCpu = (nCurCpu - nCpuStart) / (double)nTicksPerSecondCpu;
3567              double fDistanceGpu = (nCurGpu - nGpuStart) / (double)nTicksPerSecondGpu;
3568  
3569              char buf[254];
3570              snprintf(buf, sizeof(buf)-1,"Distance %f %f diff %f\n", fDistanceCpu, fDistanceGpu, fDistanceCpu-fDistanceGpu);
3571              OutputDebugString(buf);
3572              nCountDown = 100;
3573          }
3574          #endif
3575          return 1;
3576      }
3577      return 0;
3578  }
3579  
3580  
3581  #endif
3582  
3583  #undef S
3584  
3585  #ifdef _MSC_VER
3586  #pragma warning(pop)
3587  #endif
3588  
3589  
3590  
3591  
3592  
3593  #endif
3594  #endif
3595  #ifdef MICROPROFILE_EMBED_HTML
3596  #include "microprofile_html.h"
3597  #endif