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