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