summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--externals/microprofile/README.md7
-rw-r--r--externals/microprofile/microprofile.h3571
-rw-r--r--externals/microprofile/microprofile_html.h3868
-rw-r--r--externals/microprofile/microprofileui.h3348
-rw-r--r--src/citra/citra.cpp7
-rw-r--r--src/citra_qt/bootmanager.cpp5
-rw-r--r--src/citra_qt/debugger/profiler.cpp202
-rw-r--r--src/citra_qt/debugger/profiler.h17
-rw-r--r--src/citra_qt/main.cpp14
-rw-r--r--src/citra_qt/main.h2
-rw-r--r--src/common/CMakeLists.txt3
-rw-r--r--src/common/microprofile.cpp7
-rw-r--r--src/common/microprofile.h25
-rw-r--r--src/common/microprofileui.h16
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp7
-rw-r--r--src/core/hle/service/gsp_gpu.cpp5
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/hw/gpu.cpp8
-rw-r--r--src/video_core/command_processor.cpp4
-rw-r--r--src/video_core/rasterizer.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp5
-rw-r--r--src/video_core/shader/shader.cpp3
24 files changed, 11142 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6cdac1177..2ac94bc9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -213,6 +213,7 @@ set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
213include_directories(${INI_PREFIX}) 213include_directories(${INI_PREFIX})
214add_subdirectory(${INI_PREFIX}) 214add_subdirectory(${INI_PREFIX})
215 215
216include_directories(externals/microprofile)
216include_directories(externals/nihstro/include) 217include_directories(externals/nihstro/include)
217 218
218if (MSVC) 219if (MSVC)
diff --git a/externals/microprofile/README.md b/externals/microprofile/README.md
new file mode 100644
index 000000000..0a58d1c5a
--- /dev/null
+++ b/externals/microprofile/README.md
@@ -0,0 +1,7 @@
1# microprofile
2
3MicroProfile is a embeddable profiler in a single file, written in C++
4
5It can display profile information in the application, or by generating captures via a minimal built in webserver.
6
7For more information see the project webpage at https://bitbucket.org/jonasmeyer/microprofile
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
diff --git a/externals/microprofile/microprofile_html.h b/externals/microprofile/microprofile_html.h
new file mode 100644
index 000000000..01b624b60
--- /dev/null
+++ b/externals/microprofile/microprofile_html.h
@@ -0,0 +1,3868 @@
1///start file generated from microprofile.html
2#ifdef MICROPROFILE_EMBED_HTML
3const char g_MicroProfileHtml_begin_0[] =
4"<!DOCTYPE HTML>\n"
5"<html>\n"
6"<head>\n"
7"<title>MicroProfile Capture</title>\n"
8"<style>\n"
9"/* about css: http://bit.ly/1eMQ42U */\n"
10"body {margin: 0px;padding: 0px; font: 12px Courier New;background-color:#474747; color:white;overflow:hidden;}\n"
11"ul {list-style-type: none;margin: 0;padding: 0;}\n"
12"li{display: inline; float:left;border:5px; position:relative;text-align:center;}\n"
13"a {\n"
14" float:left;\n"
15" text-decoration:none;\n"
16" display: inline;\n"
17" text-align: center;\n"
18" padding:5px;\n"
19" padding-bottom:0px;\n"
20" padding-top:0px;\n"
21" color: #FFFFFF;\n"
22" background-color: #474747;\n"
23"}\n"
24"a:hover, a:active{\n"
25" background-color: #000000;\n"
26"}\n"
27"\n"
28"ul ul {\n"
29" position:absolute;\n"
30" left:0;\n"
31" top:100%;\n"
32" margin-left:-999em;\n"
33"}\n"
34"li:hover ul {\n"
35" margin-left:0;\n"
36" margin-right:0;\n"
37"}\n"
38"ul li ul{ display:block;float:none;width:100%;}\n"
39"ul li ul li{ display:block;float:none;width:100%;}\n"
40"li li a{ display:block;float:none;width:100%;text-align:left;}\n"
41"#nav li:hover div {margin-left:0;}\n"
42".help {position:absolute;z-index:5;text-align:left;padding:2px;margin-left:-999em;background-color: #313131;width:300px;}\n"
43".helpstart {position:absolute;z-index:5;text-align:left;padding:2px;background-color: #313131;width:300px;display:none}\n"
44".root {z-index:1;position:absolute;top:0px;left:0px;}\n"
45"</style>\n"
46"</head>\n"
47"<body style=\"\">\n"
48"<canvas id=\"History\" height=\"70\" style=\"background-color:#474747;margin:0px;padding:0px;\"></canvas><canvas id=\"DetailedView\" height=\"200\" style=\"background-color:#474747;margin:0px;padding:0px;\"></canvas>\n"
49"<div id=\"root\" class=\"root\">\n"
50"<ul id=\"nav\">\n"
51"<li><a href=\"javascript:void(0)\" onclick=\"ToggleDebugMode();\">?</a>\n"
52"<div class=\"helpstart\" id=\"helpwindow\" style=\"left:20px;top:20px\">\n"
53"History View:<br>\n"
54"Click + Drag: Pan View<br>\n"
55"Right Click + Drag : Zoom on region<br>\n"
56"Click Frame : Center on frame<br>\n"
57"<hr>\n"
58"Main View:<br>\n"
59"Ctrl + Mouse up/down: Zoom<br>\n"
60"Mousewheel : Zoom<br>\n"
61"Right Click + Drag: Zoom to region<br>\n"
62"Ctrl + Drag: Pan<br>\n"
63"Click + Drag: Pan<br>\n"
64"<hr>\n"
65"<table style=\"width:100%\">\n"
66"<tr>\n"
67"<td width=\"50%\" align=\"left\"><a href=\'javascript:void(0)\' onclick=\"ShowHelp(0, 0);\">Close</a></td>\n"
68"<td width=\"50%\" align=\"right\"><a href=\'javascript:void(0)\' onclick=\"ShowHelp(0, 1);\">Close, Never Show</a></td>\n"
69"</tr>\n"
70"</table>\n"
71"</div>\n"
72"<div class=\"help\" id=\"divFrameInfo\" style=\"left:20px;top:300px;width:auto;\">\n"
73"</div>\n"
74"</li>\n"
75"<li><a id=\'ModeSubMenuText\'>Mode</a>\n"
76" <ul id=\'ModeSubMenu\'>\n"
77" <li><a href=\"javascript:void(0)\" onclick=\"SetMode(\'timers\', 0);\" id=\"buttonTimers\">Timers</a></li>\n"
78" <li><a href=\"javascript:void(0)\" onclick=\"SetMode(\'timers\', 1);\" id=\"buttonGroups\">Groups</a></li> \n"
79" <li><a href=\"javascript:void(0)\" onclick=\"SetMode(\'timers\', 2);\" id=\"buttonThreads\">Threads</a></li>\n"
80" <li><a href=\"javascript:void(0)\" onclick=\"SetMode(\'detailed\', 0);\" id=\"buttonDetailed\">Detailed</a></li>\n"
81" </ul>\n"
82"</li>\n"
83"<li><a>Reference</a>\n"
84" <ul id=\'ReferenceSubMenu\'>\n"
85" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'5ms\');\">5ms</a></li>\n"
86" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'10ms\');\">10ms</a></li>\n"
87" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'15ms\');\">15ms</a></li>\n"
88" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'20ms\');\">20ms</a></li>\n"
89" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'33ms\');\">33ms</a></li>\n"
90" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'50ms\');\">50ms</a></li>\n"
91" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'100ms\');\">100ms</a></li>\n"
92" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'250ms\');\">250ms</a></li>\n"
93" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'500ms\');\">500ms</a></li>\n"
94" <li><a href=\"javascript:void(0)\" onclick=\"SetReferenceTime(\'1000ms\');\">1000ms</a></li>\n"
95" </ul>\n"
96"</li>\n"
97"<li id=\"ilThreads\"><a>Threads</a>\n"
98" <ul id=\"ThreadSubMenu\">\n"
99" <li><a href=\"javascript:void(0)\" onclick=\"ToggleThread();\">All</a></li>\n"
100" <li><a>---</a></li>\n"
101" </ul>\n"
102"</li>\n"
103"<li id=\"ilGroups\"><a>Groups</a>\n"
104" <ul id=\"GroupSubMenu\">\n"
105" <li><a href=\"javascript:void(0)\" onclick=\"ToggleGroup();\">All</a></li>\n"
106" <li><a>---</a></li>\n"
107" </ul>\n"
108"</li>\n"
109"<li id=\"ilOptions\"><a>Options&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</a>\n"
110" <ul id=\'OptionsMenu\'>\n"
111" <li><a href=\"javascript:void(0)\" onclick=\"ToggleContextSwitch();\">Context Switch</a></li>\n"
112" <li><a href=\"javascript:void(0)\" onclick=\"ToggleDisableMerge();\">MergeDisable</a></li>\n"
113" <li><a href=\"javascript:void(0)\" onclick=\"ToggleDisableLod();\">LodDisable</a></li>\n"
114" <li id=\'GroupColors\'><a href=\"javascript:void(0)\" onclick=\"ToggleGroupColors();\">Group Colors</a></li>\n"
115" <li id=\'TimersMeta\'><a href=\"javascript:void(0)\" onclick=\"ToggleTimersMeta();\">Meta</a></li>\n"
116" <li id=\'ShowHelp\'><a href=\"javascript:void(0)\" onclick=\"ShowHelp(1,1);\">Help</a></li>\n"
117"<!-- <li><a href=\"javascript:void(0)\" onclick=\"ToggleDebug();\">DEBUG</a></li> -->\n"
118" </ul>\n"
119"</li>\n"
120"</ul>\n"
121"</div>\n"
122"<script>\n"
123"function InvertColor(hexTripletColor) {\n"
124" var color = hexTripletColor;\n"
125" color = color.substring(1); // remove #\n"
126" color = parseInt(color, 16); // convert to integer\n"
127" var R = ((color >> 16) % 256)/255.0;\n"
128" var G = ((color >> 8) % 256)/255.0;\n"
129" var B = ((color >> 0) % 256)/255.0;\n"
130" var lum = (0.2126*R + 0.7152*G + 0.0722*B);\n"
131" if(lum < 0.7)\n"
132" {\n"
133" return \'#ffffff\';\n"
134" }\n"
135" else\n"
136" {\n"
137" return \'#333333\';\n"
138" }\n"
139"}\n"
140"function InvertColorIndex(hexTripletColor) {\n"
141" var color = hexTripletColor;\n"
142" color = color.substring(1); // remove #\n"
143" color = parseInt(color, 16); // convert to integer\n"
144" var R = ((color >> 16) % 256)/255.0;\n"
145" var G = ((color >> 8) % 256)/255.0;\n"
146" var B = ((color >> 0) % 256)/255.0;\n"
147" var lum = (0.2126*R + 0.7152*G + 0.0722*B);\n"
148" if(lum < 0.7)\n"
149" {\n"
150" return 0;\n"
151" }\n"
152" else\n"
153" {\n"
154" return 1;\n"
155" }\n"
156"}\n"
157"function MakeGroup(id, name, category, numtimers, isgpu, total, average, max, color)\n"
158"{\n"
159" var group = {\"id\":id, \"name\":name, \"category\":category, \"numtimers\":numtimers, \"isgpu\":isgpu, \"total\": total, \"average\" : average, \"max\" : max, \"color\":color};\n"
160" return group;\n"
161"}\n"
162"\n"
163"function MakeTimer(id, name, group, color, colordark, average, max, exclaverage, exclmax, callaverage, callcount, total, meta, metaavg, metamax)\n"
164"{\n"
165" var timer = {\"id\":id, \"name\":name, \"len\":name.length, \"color\":color, \"colordark\":colordark,\"timercolor\":color, \"textcolor\":InvertColor(color), \"group\":group, \"average\":average, \"max\":max, \"exclaverage\":exclaverage, \"exclmax\":exclmax, \"callaverage\":callaverage, \"callcount\":callcount, \"total\":total, \"meta\":meta, \"textcolorindex\":InvertColorIndex(color), \"metaavg\":metaavg, \"metamax\":metamax};\n"
166" return timer;\n"
167"}\n"
168"function MakeFrame(id, framestart, frameend, framestartgpu, frameendgpu, ts, tt, ti)\n"
169"{\n"
170" var frame = {\"id\":id, \"framestart\":framestart, \"frameend\":frameend, \"framestartgpu\":framestartgpu, \"frameendgpu\":frameendgpu, \"ts\":ts, \"tt\":tt, \"ti\":ti};\n"
171" return frame;\n"
172"}\n"
173"\n"
174"";
175
176const size_t g_MicroProfileHtml_begin_0_size = sizeof(g_MicroProfileHtml_begin_0);
177const char* g_MicroProfileHtml_begin[] = {
178&g_MicroProfileHtml_begin_0[0],
179};
180size_t g_MicroProfileHtml_begin_sizes[] = {
181sizeof(g_MicroProfileHtml_begin_0),
182};
183size_t g_MicroProfileHtml_begin_count = 1;
184const char g_MicroProfileHtml_end_0[] =
185"\n"
186"\n"
187"\n"
188"var CanvasDetailedView = document.getElementById(\'DetailedView\');\n"
189"var CanvasHistory = document.getElementById(\'History\');\n"
190"var CanvasDetailedOffscreen = document.createElement(\'canvas\');\n"
191"var g_Msg = \'0\';\n"
192"\n"
193"var Initialized = 0;\n"
194"var fDetailedOffset = Frames[0].framestart;\n"
195"var fDetailedRange = Frames[0].frameend - fDetailedOffset;\n"
196"var nWidth = CanvasDetailedView.width;\n"
197"var nHeight = CanvasDetailedView.height;\n"
198"var ReferenceTime = 33;\n"
199"var nHistoryHeight = 70;\n"
200"var nOffsetY = 0;\n"
201"var nOffsetBarsX = 0;\n"
202"var nOffsetBarsY = 0;\n"
203"var nBarsWidth = 80;\n"
204"var NameWidth = 200;\n"
205"var MouseButtonState = [0,0,0,0,0,0,0,0];\n"
206"var KeyShiftDown = 0;\n"
207"var MouseDragButton = 0;\n"
208"var KeyCtrlDown = 0;\n"
209"var FlipToolTip = 0;\n"
210"var DetailedViewMouseX = 0;\n"
211"var DetailedViewMouseY = 0;\n"
212"var HistoryViewMouseX = -1;\n"
213"var HistoryViewMouseY = -1;\n"
214"var MouseHistory = 0;\n"
215"var MouseDetailed = 0;\n"
216"var FontHeight = 10;\n"
217"var FontWidth = 1;\n"
218"var FontAscent = 3; //Set manually\n"
219"var Font = \'Bold \' + FontHeight + \'px Courier New\';\n"
220"var FontFlash = \'Bold \' + 35 + \'px Courier New\';\n"
221"var BoxHeight = FontHeight + 2;\n"
222"var ThreadsActive = new Object();\n"
223"var ThreadsAllActive = 1;\n"
224"var GroupsActive = new Object();\n"
225"var GroupsAllActive = 1;\n"
226"var nMinWidth = 0.01;//subpixel width\n"
227"var nMinWidthPan = 1.0;//subpixel width when panning\n"
228"var nContextSwitchEnabled = 1;\n"
229"var DisableLod = 0;\n"
230"var DisableMerge = 0;\n"
231"var GroupColors = 0;\n"
232"var nModDown = 0;\n"
233"var g_MSG = \'no\';\n"
234"var nDrawCount = 0;\n"
235"var nBackColors = [\'#474747\', \'#313131\' ];\n"
236"var nBackColorOffset = \'#606060\';\n"
237"var CSwitchColors =[\"#9DD8AF\",\"#D7B6DA\",\"#EAAC76\",\"#DBDA61\",\"#8AD5E1\",\"#8CE48B\",\"#C4D688\",\"#57E5C4\"];//generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php\n"
238"var CSwitchHeight = 5;\n"
239"var FRAME_HISTORY_COLOR_CPU = \'#ff7f27\';\n"
240"var FRAME_HISTORY_COLOR_GPU = \'#ffffff\';\n"
241"var ZOOM_TIME = 0.5;\n"
242"var AnimationActive = false;\n"
243"var nHoverCSCpu = -1;\n"
244"var nHoverCSCpuNext = -1;\n"
245"var nHoverCSToolTip = null;\n"
246"var nHoverToken = -1;\n"
247"var nHoverFrame = -1;\n"
248"var nHoverTokenIndex = -1;\n"
249"var nHoverTokenLogIndex = -1;\n"
250"var nHoverCounter = 0;\n"
251"var nHoverCounterDelta = 8;\n"
252"var nHoverTokenNext = -1;\n"
253"var nHoverTokenLogIndexNext = -1;\n"
254"var nHoverTokenIndexNext = -1;\n"
255"var nHideHelp = 0;\n"
256"\n"
257"\n"
258"var fFrameScale = 33.33;\n"
259"var fRangeBegin = 0;\n"
260"var fRangeEnd = -1;\n"
261"var fRangeBeginNext = 0;\n"
262"var fRangeEndNext = 0;\n"
263"var fRangeBeginGpuNext = 0;\n"
264"var fRangeEndGpuNext = 0;\n"
265"var fRangeBeginHistory = -1;\n"
266"var fRangeEndHistory = -1;\n"
267"var fRangeBeginHistoryGpu = -1;\n"
268"var fRangeEndHistoryGpu = -1;\n"
269"var fRangeBeginSelect = 0;\n"
270"var fRangeEndSelect = -1;\n"
271"\n"
272"var ModeDetailed = 0;\n"
273"var ModeTimers = 1;\n"
274"var Mode = ModeDetailed;\n"
275"\n"
276"var DebugDrawQuadCount = 0;\n"
277"var DebugDrawTextCount = 0;\n"
278"var ProfileMode = 0;\n"
279"var ProfileFps = 0;\n"
280"var ProfileFpsAggr = 0;\n"
281"var ProfileFpsCount = 0;\n"
282"var ProfileLastTimeStamp = new Date();\n"
283"\n"
284"var CSwitchCache = {};\n"
285"var CSwitchOnlyThreads = [];\n"
286"var ProfileData = {};\n"
287"var ProfileStackTime = {};\n"
288"var ProfileStackName = {};\n"
289"var Debug = 1;\n"
290"\n"
291"var g_MaxStack = Array();\n"
292"var g_TypeArray;\n"
293"var g_TimeArray;\n"
294"var g_IndexArray;\n"
295"var LodData = new Array();\n"
296"var NumLodSplits = 10;\n"
297"var SplitMin = 100;\n"
298"var SPLIT_LIMIT = 1e20;\n"
299"var DPR = 1;\n"
300"var DetailedRedrawState = {};\n"
301"var OffscreenData;\n"
302"var DetailedFrameCounter = 0;\n"
303"var Invalidate = 0;\n"
304"var GroupOrder = Array();\n"
305"var ThreadOrder = Array();\n"
306"var TimersGroups = 0;\n"
307"var TimersMeta = 1;\n"
308"var MetaLengths = Array();\n"
309"var MetaLengthsAvg = Array();\n"
310"var MetaLengthsMax = Array();\n"
311"\n"
312"\n"
313"function ProfileModeClear()\n"
314"{\n"
315" if(ProfileMode)\n"
316" {\n"
317" ProfileData = new Object();\n"
318" ProfileStackTime = new Array();\n"
319" ProfileStackName = new Array();\n"
320" }\n"
321"}\n"
322"function ProfileEnter(Name)\n"
323"{\n"
324" if(ProfileMode)\n"
325" {\n"
326" ProfileStackTime.push(new Date());\n"
327" ProfileStackName.push(Name);\n"
328" }\n"
329"}\n"
330"function ProfileLeave()\n"
331"{\n"
332" if(ProfileMode)\n"
333" {\n"
334" var Time = new Date();\n"
335" var Delta = Time - ProfileStackTime.pop();\n"
336" var Name = ProfileStackName.pop();\n"
337" var Obj = ProfileData[Name];\n"
338" if(!Obj)\n"
339" {\n"
340" Obj = new Object();\n"
341" Obj.Count = 0;\n"
342" Obj.Name = Name;\n"
343" Obj.Time = 0;\n"
344" ProfileData[Name] = Obj;\n"
345" }\n"
346" Obj.Time += Delta;\n"
347" Obj.Count += 1;\n"
348" }\n"
349"}\n"
350"\n"
351"function ProfilePlot(s)\n"
352"{\n"
353" if(ProfileMode)\n"
354" {\n"
355" var A = ProfileData.Plot;\n"
356" if(!A)\n"
357" {\n"
358" ProfileData.Plot = Array();\n"
359" A = ProfileData.Plot;\n"
360" }\n"
361" if(A.length<10)\n"
362" {\n"
363" A.push(s);\n"
364" }\n"
365" }\n"
366"}\n"
367"function ProfileModeDump()\n"
368"{\n"
369" for(var idx in ProfileData)\n"
370" {\n"
371" var Timer = ProfileData[idx];\n"
372" console.log(Timer.Name + \" \" + Timer.Time + \"ms \" + Timer.Count);\n"
373" }\n"
374"\n"
375"}\n"
376"function ProfileModeDraw(Canvas)\n"
377"{\n"
378" if(ProfileMode)\n"
379" {\n"
380" var StringArray = [];\n"
381" for(var idx in ProfileData)\n"
382" {\n"
383" if(idx == \"Plot\")\n"
384" continue;\n"
385" var Timer = ProfileData[idx];\n"
386" StringArray.push(Timer.Name);\n"
387" StringArray.push(Timer.Time + \"ms\");\n"
388" StringArray.push(\"#\");\n"
389" StringArray.push(\"\" + Timer.Count);\n"
390" }\n"
391" StringArray.push(\"debug\");\n"
392" StringArray.push(Debug);\n"
393" var Time = new Date();\n"
394" var Delta = Time - ProfileLastTimeStamp;\n"
395" ProfileLastTimeStamp = Time;\n"
396" StringArray.push(\"Frame Delta\");\n"
397" StringArray.push(Delta + \"ms\");\n"
398" if(ProfileMode == 2)\n"
399" {\n"
400" ProfileFpsAggr += Delta;\n"
401" ProfileFpsCount ++ ;\n"
402" var AggrFrames = 10;\n"
403" if(ProfileFpsCount == AggrFrames)\n"
404" {\n"
405" ProfileFps = 1000 / (ProfileFpsAggr / AggrFrames);\n"
406" ProfileFpsAggr = 0;\n"
407" ProfileFpsCount = 0;\n"
408" }\n"
409" StringArray.push(\"FPS\");\n"
410" StringArray.push(\"\" + ProfileFps.toFixed(2));\n"
411" }\n"
412"\n"
413"\n"
414" for(var i = 0; i < ProfileData.Plot; ++i)\n"
415" {\n"
416" StringArray.push(\"\");\n"
417" StringArray.push(ProfileData.Plot[i]);\n"
418" }\n"
419" ProfileData.Plot = Array();\n"
420" DrawToolTip(StringArray, Canvas, 0, 200);\n"
421" }\n"
422"}\n"
423"\n"
424"function ToggleDebugMode()\n"
425"{\n"
426" ProfileMode = (ProfileMode+1)%4;\n"
427" console.log(\'Toggle Debug Mode \' + ProfileMode);\n"
428"}\n"
429"\n"
430"function DetailedTotal()\n"
431"{\n"
432" var Total = 0;\n"
433" for(var i = 0; i < Frames.length; i++)\n"
434" {\n"
435" var frfr = Frames[i];\n"
436" Total += frfr.frameend - frfr.framestart;\n"
437" }\n"
438" return Total;\n"
439"}\n"
440"\n"
441"function InitFrameInfo()\n"
442"{\n"
443"\n"
444" var div = document.getElementById(\'divFrameInfo\');\n"
445" var txt = \'\';\n"
446" txt = txt + \'Timers View\' + \'<br>\';\n"
447" txt = txt + \'Frames:\' + AggregateInfo.Frames +\'<br>\';\n"
448" txt = txt + \'Time:\' + AggregateInfo.Time.toFixed(2) +\'ms<br>\';\n"
449" txt = txt + \'<hr>\';\n"
450" txt = txt + \'Detailed View\' + \'<br>\';\n"
451" txt = txt + \'Frames:\' + Frames.length +\'<br>\';\n"
452" txt = txt + \'Time:\' + DetailedTotal().toFixed(2) +\'ms<br>\';\n"
453" div.innerHTML = txt;\n"
454"}\n"
455"function InitGroups()\n"
456"{\n"
457" for(groupid in GroupInfo)\n"
458" {\n"
459" var TimerArray = Array();\n"
460" for(timerid in TimerInfo)\n"
461" {\n"
462" if(TimerInfo[timerid].group == groupid)\n"
463" {\n"
464" TimerArray.push(timerid);\n"
465" }\n"
466" }\n"
467" GroupInfo[groupid].TimerArray = TimerArray;\n"
468" }\n"
469"}\n"
470"\n"
471"function InitThreadMenu()\n"
472"{\n"
473" var ulThreadMenu = document.getElementById(\'ThreadSubMenu\');\n"
474" var MaxLen = 7;\n"
475" ThreadOrder = CreateOrderArray(ThreadNames, function(a){return a;});\n"
476" for(var idx in ThreadOrder)\n"
477" {\n"
478" var name = ThreadNames[ThreadOrder[idx]];\n"
479" var li = document.createElement(\'li\');\n"
480" if(name.length > MaxLen)\n"
481" {\n"
482" MaxLen = name.length;\n"
483" }\n"
484" li.innerText = name;\n"
485" var asText = li.innerHTML;\n"
486" var html = \'<a href=\"javascript:void(0)\" onclick=\"ToggleThread(\\'\' + name + \'\\');\">\' + asText + \'</a>\';\n"
487" li.innerHTML = html;\n"
488" ulThreadMenu.appendChild(li);\n"
489" }\n"
490" var LenStr = (5+(1+MaxLen) * (1+FontWidth)) + \'px\';\n"
491" var Lis = ulThreadMenu.getElementsByTagName(\'li\');\n"
492" for(var i = 0; i < Lis.length; ++i)\n"
493" {\n"
494" Lis[i].style[\'width\'] = LenStr;\n"
495" }\n"
496"}\n"
497"\n"
498"function UpdateThreadMenu()\n"
499"{\n"
500" var ulThreadMenu = document.getElementById(\'ThreadSubMenu\');\n"
501" var as = ulThreadMenu.getElementsByTagName(\'a\');\n"
502" for(var i = 0; i < as.length; ++i)\n"
503" {\n"
504" var elem = as[i];\n"
505" var inner = elem.innerText;\n"
506" var bActive = false;\n"
507" if(i < 2)\n"
508" {\n"
509" if(inner == \'All\')\n"
510" {\n"
511" bActive = ThreadsAllActive;\n"
512" }\n"
513" }\n"
514" else\n"
515" {\n"
516" bActive = ThreadsActive[inner];\n"
517" }\n"
518" if(bActive)\n"
519" {\n"
520" elem.style[\'text-decoration\'] = \'underline\';\n"
521" }\n"
522" else\n"
523" {\n"
524" elem.style[\'text-decoration\'] = \'none\';\n"
525" }\n"
526" }\n"
527"}\n"
528"\n"
529"function ToggleThread(ThreadName)\n"
530"{\n"
531" if(ThreadName)\n"
532" {\n"
533" if(ThreadsActive[ThreadName])\n"
534" {\n"
535" ThreadsActive[ThreadName] = false;\n"
536" }\n"
537" else\n"
538" {\n"
539" ThreadsActive[ThreadName] = true;\n"
540" }\n"
541" }\n"
542" else\n"
543" {\n"
544" if(ThreadsAllActive)\n"
545" {\n"
546" ThreadsAllActive = 0;\n"
547" }\n"
548" else\n"
549" {\n"
550" ThreadsAllActive = 1;\n"
551" }\n"
552" }\n"
553" Invalidate = 0;\n"
554" UpdateThreadMenu();\n"
555" WriteCookie();\n"
556" Draw(1);\n"
557"\n"
558"}\n"
559"\n"
560"function CreateOrderArray(Source, NameFunc)\n"
561"{\n"
562" var Temp = Array(Source.length);\n"
563" for(var i = 0; i < Source.length; ++i)\n"
564" {\n"
565" Temp[i] = {};\n"
566" Temp[i].index = i;\n"
567" Temp[i].namezz = NameFunc(Source[i]).toLowerCase();\n"
568" }\n"
569" Temp.sort(function(l, r)\n"
570" { \n"
571" if(r.namezz<l.namezz)\n"
572" {return 1;}\n"
573" if(l.namezz<r.namezz)\n"
574" {return -1;} \n"
575" return 0;\n"
576" } );\n"
577" var OrderArray = Array(Source.length);\n"
578" for(var i = 0; i < Source.length; ++i)\n"
579" {\n"
580" OrderArray[i] = Temp[i].index;\n"
581" }\n"
582" return OrderArray;\n"
583"}\n"
584"\n"
585"\n"
586"function InitGroupMenu()\n"
587"{\n"
588" var ulGroupMenu = document.getElementById(\'GroupSubMenu\');\n"
589" var MaxLen = 7;\n"
590" var MenuArray = Array();\n"
591" for(var i = 0; i < GroupInfo.length; ++i)\n"
592" {\n"
593" var x = {};\n"
594" x.IsCategory = 0;\n"
595" x.category = GroupInfo[i].category;\n"
596" x.name = GroupInfo[i].name;\n"
597" x.index = i;\n"
598" MenuArray.push(x);\n"
599" }\n"
600" for(var i = 0; i < CategoryInfo.length; ++i)\n"
601" {\n"
602" var x = {};\n"
603" x.IsCategory = 1;\n"
604" x.category = i;\n"
605" x.name = CategoryInfo[i];\n"
606" x.index = i;\n"
607" MenuArray.push(x);\n"
608" }\n"
609" var OrderFunction = function(a){ return a.category + \"__\" + a.name; };\n"
610" var OrderFunctionMenu = function(a){ return a.IsCategory ? (a.category + \'\') : (a.category + \"__\" + a.name); };\n"
611" GroupOrder = CreateOrderArray(GroupInfo, OrderFunction);\n"
612" var MenuOrder = CreateOrderArray(MenuArray, OrderFunctionMenu);\n"
613"\n"
614" for(var idx in MenuOrder)\n"
615" {\n"
616" var MenuItem = MenuArray[MenuOrder[idx]];\n"
617" var name = MenuItem.name;\n"
618" var li = document.createElement(\'li\');\n"
619" if(name.length > MaxLen)\n"
620" {\n"
621" MaxLen = name.length;\n"
622" }\n"
623" var jsfunc = \'\';\n"
624" if(MenuItem.IsCategory)\n"
625" { \n"
626" li.innerText = \'[\' + name + \']\';\n"
627" jsfunc = \"ToggleCategory\";\n"
628" }\n"
629" else\n"
630" {\n"
631" li.innerText = name;\n"
632" jsfunc = \"ToggleGroup\";\n"
633" }\n"
634" var asText = li.innerHTML;\n"
635" var html = \'<a href=\"javascript:void(0)\" onclick=\"\' + jsfunc + \'(\\'\' + name + \'\\');\">\' + asText + \'</a>\';\n"
636" li.innerHTML = html;\n"
637" ulGroupMenu.appendChild(li);\n"
638" }\n"
639" var LenStr = (5+(1+MaxLen) * FontWidth) + \'px\';\n"
640" var Lis = ulGroupMenu.getElementsByTagName(\'li\');\n"
641" for(var i = 0; i < Lis.length; ++i)\n"
642" {\n"
643" Lis[i].style[\'width\'] = LenStr;\n"
644" }\n"
645" UpdateGroupMenu();\n"
646"}\n"
647"\n"
648"function UpdateGroupMenu()\n"
649"{\n"
650" var ulThreadMenu = document.getElementById(\'GroupSubMenu\');\n"
651" var as = ulThreadMenu.getElementsByTagName(\'a\');\n"
652" for(var i = 0; i < as.length; ++i)\n"
653" {\n"
654" var elem = as[i];\n"
655" var inner = elem.innerText;\n"
656" var bActive = false;\n"
657" if(i < 2)\n"
658" {\n"
659" if(inner == \'All\')\n"
660" {\n"
661" bActive = GroupsAllActive;\n"
662" }\n"
663" }\n"
664" else\n"
665" {\n"
666" var CategoryString = inner.length>2 ? inner.substring(1, inner.length-2) : \"\";\n"
667" var CategoryIdx = CategoryIndex(CategoryString);\n"
668" if(inner[0] == \'[\' && inner[inner.length-1] == \']\' && CategoryIdx >= 0)\n"
669" {\n"
670" bActive = IsCategoryActive(CategoryIdx);\n"
671" }\n"
672" else\n"
673" {\n"
674" bActive = GroupsActive[inner];\n"
675" }\n"
676" }\n"
677" if(bActive)\n"
678" {\n"
679" elem.style[\'text-decoration\'] = \'underline\';\n"
680" }\n"
681" else\n"
682" {\n"
683" elem.style[\'text-decoration\'] = \'none\';\n"
684" }\n"
685" }\n"
686"}\n"
687"function CategoryIndex(CategoryName)\n"
688"{\n"
689" for(var i = 0; i < CategoryInfo.length; ++i)\n"
690" {\n"
691" if(CategoryInfo[i] == CategoryName)\n"
692" {\n"
693" return i;\n"
694" }\n"
695" }\n"
696" return -1;\n"
697"}\n"
698"function IsCategoryActive(CategoryIdx)\n"
699"{\n"
700" for(var i = 0; i < GroupInfo.length; ++i)\n"
701" {\n"
702" if(GroupInfo[i].category == CategoryIdx)\n"
703" {\n"
704" var Name = GroupInfo[i].name;\n"
705" if(!GroupsActive[Name])\n"
706" {\n"
707" return false;\n"
708" }\n"
709" }\n"
710" }\n"
711" return true;\n"
712"\n"
713"}\n"
714"function ToggleCategory(CategoryName)\n"
715"{\n"
716" var CategoryIdx = CategoryIndex(CategoryName);\n"
717" if(CategoryIdx < 0)\n"
718" return;\n"
719" var CategoryActive = IsCategoryActive(CategoryIdx);\n"
720" for(var i = 0; i < GroupInfo.length; ++i)\n"
721" {\n"
722" if(GroupInfo[i].category == CategoryIdx)\n"
723" {\n"
724" var Name = GroupInfo[i].name;\n"
725" if(CategoryActive)\n"
726" {\n"
727" GroupsActive[Name] = false;\n"
728" }\n"
729" else\n"
730" {\n"
731" GroupsActive[Name] = true;\n"
732" }\n"
733" }\n"
734" }\n"
735" UpdateGroupMenu();\n"
736" WriteCookie();\n"
737" RequestRedraw();\n"
738"}\n"
739"\n"
740"function ToggleGroup(GroupName)\n"
741"{\n"
742" if(GroupName)\n"
743" {\n"
744" if(GroupsActive[GroupName])\n"
745" {\n"
746" GroupsActive[GroupName] = false;\n"
747" }\n"
748" else\n"
749" {\n"
750" GroupsActive[GroupName] = true;\n"
751" }\n"
752" }\n"
753" else\n"
754" {\n"
755" if(GroupsAllActive)\n"
756" {\n"
757" GroupsAllActive = 0;\n"
758" }\n"
759" else\n"
760" {\n"
761" GroupsAllActive = 1;\n"
762" }\n"
763" }\n"
764" UpdateGroupMenu();\n"
765" WriteCookie();\n"
766" RequestRedraw();\n"
767"}\n"
768"function UpdateGroupColors()\n"
769"{\n"
770" for(var i = 0; i < TimerInfo.length; ++i)\n"
771" {\n"
772" if(GroupColors)\n"
773" {\n"
774" TimerInfo[i].color = GroupInfo[TimerInfo[i].group].color;\n"
775" }\n"
776" else\n"
777" {\n"
778" TimerInfo[i].color = TimerInfo[i].timercolor;\n"
779" }\n"
780" TimerInfo[i].textcolorindex = InvertColorIndex(TimerInfo[i].color);\n"
781" }\n"
782"}\n"
783"\n"
784"function ToggleGroupColors()\n"
785"{\n"
786" GroupColors = !GroupColors;\n"
787" UpdateGroupColors();\n"
788" UpdateOptionsMenu();\n"
789" WriteCookie();\n"
790" RequestRedraw();\n"
791"}\n"
792"\n"
793"function UpdateOptionsMenu()\n"
794"{\n"
795" var ulTimersMeta = document.getElementById(\'TimersMeta\');\n"
796" ulTimersMeta.style[\'text-decoration\'] = TimersMeta ? \'underline\' : \'none\';\n"
797" var ulGroupColors = document.getElementById(\'GroupColors\');\n"
798" ulGroupColors.style[\'text-decoration\'] = GroupColors ? \'underline\' : \'none\';\n"
799"}\n"
800"\n"
801"function ToggleTimersMeta()\n"
802"{\n"
803" TimersMeta = TimersMeta ? 0 : 1;\n"
804" WriteCookie();\n"
805" UpdateOptionsMenu();\n"
806" RequestRedraw();\n"
807"}\n"
808"\n"
809"function ShowHelp(Show, Forever)\n"
810"{\n"
811" var HelpWindow = document.getElementById(\'helpwindow\');\n"
812" if(Show)\n"
813" {\n"
814" HelpWindow.style[\'display\'] = \'block\';\n"
815" }\n"
816" else\n"
817" {\n"
818" HelpWindow.style[\'display\'] = \'none\';\n"
819" }\n"
820" if(Forever)\n"
821" {\n"
822" nHideHelp = Show ? 0 : 1;\n"
823" WriteCookie();\n"
824" }\n"
825"}\n"
826"function SetMode(NewMode, Groups)\n"
827"{\n"
828" var buttonTimers = document.getElementById(\'buttonTimers\');\n"
829" var buttonDetailed = document.getElementById(\'buttonDetailed\');\n"
830" var buttonGroups = document.getElementById(\'buttonGroups\');\n"
831" var buttonThreads = document.getElementById(\'buttonThreads\');\n"
832" var ilThreads = document.getElementById(\'ilThreads\');\n"
833" var ilGroups = document.getElementById(\'ilGroups\');\n"
834" var ModeElement = null;\n"
835" if(NewMode == \'timers\' || NewMode == ModeTimers)\n"
836" {\n"
837" TimersGroups = Groups;\n"
838" buttonTimers.style[\'text-decoration\'] = TimersGroups ? \'none\' : \'underline\';\n"
839" buttonGroups.style[\'text-decoration\'] = TimersGroups == 1 ? \'underline\' : \'none\';\n"
840" buttonThreads.style[\'text-decoration\'] = TimersGroups == 2 ? \'underline\' : \'none\';\n"
841" buttonDetailed.style[\'text-decoration\'] = \'none\';\n"
842" if(TimersGroups == 0)\n"
843" {\n"
844" ilThreads.style[\'display\'] = \'none\';\n"
845" }\n"
846" else\n"
847" {\n"
848" ilThreads.style[\'display\'] = \'block\';\n"
849" }\n"
850" ilGroups.style[\'display\'] = \'block\';\n"
851" Mode = ModeTimers;\n"
852" ModeElement = TimersGroups == 2 ? buttonThreads : TimersGroups == 1 ? buttonGroups : buttonTimers;\n"
853" }\n"
854" else if(NewMode == \'detailed\' || NewMode == ModeDetailed)\n"
855" {\n"
856" buttonTimers.style[\'text-decoration\'] = \'none\';\n"
857" buttonGroups.style[\'text-decoration\'] = \'none\';\n"
858" buttonThreads.style[\'text-decoration\'] = \'none\';\n"
859" buttonDetailed.style[\'text-decoration\'] = \'underline\';\n"
860" ilThreads.style[\'display\'] = \'block\';\n"
861" ilGroups.style[\'display\'] = \'none\';\n"
862" Mode = ModeDetailed;\n"
863" ModeElement = buttonDetailed;\n"
864" }\n"
865" var ModeSubMenuText = document.getElementById(\'ModeSubMenuText\');\n"
866" ModeSubMenuText.innerText = \'Mode[\' + ModeElement.innerText + \']\';\n"
867"\n"
868" WriteCookie();\n"
869" RequestRedraw();\n"
870"\n"
871"}\n"
872"\n"
873"function SetReferenceTime(TimeString)\n"
874"{\n"
875" ReferenceTime = parseInt(TimeString);\n"
876" var ReferenceMenu = document.getElementById(\'ReferenceSubMenu\');\n"
877" var Links = ReferenceMenu.getElementsByTagName(\'a\');\n"
878" for(var i = 0; i < Links.length; ++i)\n"
879" {\n"
880" if(Links[i].innerHTML.match(\'^\' + TimeString))\n"
881" {\n"
882" Links[i].style[\'text-decoration\'] = \'underline\';\n"
883" }\n"
884" else\n"
885" {\n"
886" Links[i].style[\'text-decoration\'] = \'none\';\n"
887" }\n"
888" }\n"
889" WriteCookie();\n"
890" RequestRedraw();\n"
891"\n"
892"}\n"
893"\n"
894"function ToggleContextSwitch()\n"
895"{\n"
896" SetContextSwitch(nContextSwitchEnabled ? 0 : 1);\n"
897"}\n"
898"function SetContextSwitch(Enabled)\n"
899"{\n"
900" nContextSwitchEnabled = Enabled ? 1 : 0;\n"
901" var ReferenceMenu = document.getElementById(\'OptionsMenu\');\n"
902" var Links = ReferenceMenu.getElementsByTagName(\'a\');\n"
903" Links[0].style[\'text-decoration\'] = nContextSwitchEnabled ? \'underline\' : \'none\';\n"
904" WriteCookie();\n"
905" RequestRedraw();\n"
906"}\n"
907"\n"
908"function ToggleDebug()\n"
909"{\n"
910" Debug = (Debug + 1) % 2;\n"
911"}\n"
912"\n"
913"function ToggleDisableMerge()\n"
914"{\n"
915" DisableMerge = DisableMerge ? 0 : 1;\n"
916" var ReferenceMenu = document.getElementById(\'OptionsMenu\');\n"
917" var Links = ReferenceMenu.getElementsByTagName(\'a\');\n"
918" if(DisableMerge)\n"
919" {\n"
920" Links[1].style[\'text-decoration\'] = \'underline\';\n"
921" }\n"
922" else\n"
923" {\n"
924" Links[1].style[\'text-decoration\'] = \'none\';\n"
925" }\n"
926"\n"
927"}\n"
928"\n"
929"function ToggleDisableLod()\n"
930"{\n"
931" DisableLod = DisableLod ? 0 : 1;\n"
932" var ReferenceMenu = document.getElementById(\'OptionsMenu\');\n"
933" var Links = ReferenceMenu.getElementsByTagName(\'a\');\n"
934" if(DisableLod)\n"
935" {\n"
936" Links[2].style[\'text-decoration\'] = \'underline\';\n"
937" }\n"
938" else\n"
939" {\n"
940" Links[2].style[\'text-decoration\'] = \'none\';\n"
941" }\n"
942"\n"
943"}\n"
944"\n"
945"function GatherHoverMetaCounters(TimerIndex, StartIndex, nLog, nFrameLast)\n"
946"{\n"
947" var HoverInfo = new Object();\n"
948" var StackPos = 1;\n"
949" //search backwards, count meta counters \n"
950" for(var i = nFrameLast; i >= 0; i--)\n"
951" {\n"
952" var fr = Frames[i];\n"
953" var ts = fr.ts[nLog];\n"
954" var ti = fr.ti[nLog];\n"
955" var tt = fr.tt[nLog];\n"
956" var start = i == nFrameLast ? StartIndex-1 : ts.length-1;\n"
957"\n"
958" for(var j = start; j >= 0; j--)\n"
959" {\n"
960" var type = tt[j];\n"
961" var index = ti[j];\n"
962" var time = ts[j];\n"
963" if(type == 1)\n"
964" {\n"
965" StackPos--;\n"
966" if(StackPos == 0 && index == TimerIndex)\n"
967" {\n"
968" return HoverInfo;\n"
969" }\n"
970" }\n"
971" else if(type == 0)\n"
972" {\n"
973" StackPos++;\n"
974" }\n"
975" else if(type > 3)\n"
976" {\n"
977" var nMetaCount = type - 3;\n"
978" var nMetaIndex = MetaNames[index];\n"
979" if(nMetaIndex in HoverInfo)\n"
980" {\n"
981" HoverInfo[nMetaIndex] += nMetaCount;\n"
982" }\n"
983" else\n"
984" {\n"
985" HoverInfo[nMetaIndex] = nMetaCount;\n"
986" }\n"
987" }\n"
988" }\n"
989" }\n"
990"}\n"
991"function CalculateAllTimers(fBegin, fEnd)\n"
992"{\n"
993" var Sum = [];\n"
994" var Count = [];\n"
995" var Sorted = [];\n"
996" for(var i = 0; i < TimerInfo.length; ++i)\n"
997" {\n"
998" Sum.push(0.0);\n"
999" Count.push(0);\n"
1000" Sorted.push(i);\n"
1001" }\n"
1002" var nFrameFirst = 0;\n"
1003" var nFrameLast = Frames.length;\n"
1004"\n"
1005" var nNumLogs = Frames[0].ts.length;\n"
1006" var StackPosArray = Array(nNumLogs);\n"
1007" var StackArray = Array(nNumLogs);\n"
1008" for(var i = 0; i < nNumLogs; ++i)\n"
1009" {\n"
1010" StackPosArray[i] = 0;\n"
1011" StackArray[i] = Array(20);\n"
1012" }\n"
1013"\n"
1014" for(var i = nFrameFirst; i < nFrameLast; i++)\n"
1015" {\n"
1016" var fr = Frames[i];\n"
1017" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
1018" {\n"
1019" var StackPos = StackPosArray[nLog];\n"
1020" var Stack = StackArray[nLog];\n"
1021" var ts = fr.ts[nLog];\n"
1022" var ti = fr.ti[nLog];\n"
1023" var tt = fr.tt[nLog];\n"
1024" var count = ts.length;\n"
1025" for(j = 0; j < count; j++)\n"
1026" {\n"
1027" var type = tt[j];\n"
1028" var index = ti[j];\n"
1029" var time = ts[j];\n"
1030" if(type == 1 && time < fEnd) //enter\n"
1031" {\n"
1032" Stack[StackPos] = time < fBegin ? fBegin : time;\n"
1033" if(StackArray[nLog][StackPos] != time)\n"
1034" {\n"
1035" console.log(\'fail fail fail\');\n"
1036" }\n"
1037" StackPos++;\n"
1038" }\n"
1039" else if(type == 0) // leave\n"
1040" {\n"
1041" if(StackPos>0)\n"
1042" {\n"
1043" var timeend = time;\n"
1044" StackPos--;\n"
1045" timestart = Stack[StackPos];\n"
1046" var TimeDelta = timeend - timestart;\n"
1047" Sum[index] += TimeDelta;\n"
1048" Count[index]++;\n"
1049" }\n"
1050" }\n"
1051" }\n"
1052" StackPosArray[nLog] = StackPos;\n"
1053" }\n"
1054" }\n"
1055" Sorted.sort(function(a,b){ return Sum[b] - Sum[a]; } );\n"
1056" var Result = {\"Sorted\" : Sorted, \"Sum\" : Sum, \"Count\" : Count};\n"
1057" return Result;\n"
1058"}\n"
1059"function CalculateTimers(Result, TimerIndex, nFrameFirst, nFrameLast)\n"
1060"{\n"
1061" if(!nFrameFirst || nFrameFirst < 0)\n"
1062" nFrameFirst = 0;\n"
1063" if(!nFrameLast || nFrameLast > Frames.length)\n"
1064" nFrameLast = Frames.length;\n"
1065" var FrameCount = nFrameLast - nFrameFirst;\n"
1066" if(0 == FrameCount)\n"
1067" return;\n"
1068" var CallCount = 0;\n"
1069" var Sum = 0;\n"
1070" var Max = 0;\n"
1071" var FrameMax = 0;\n"
1072"\n"
1073" var nNumLogs = Frames[0].ts.length;\n"
1074" var StackPosArray = Array(nNumLogs);\n"
1075" var StackArray = Array(nNumLogs);\n"
1076" for(var i = 0; i < nNumLogs; ++i)\n"
1077" {\n"
1078" StackPosArray[i] = 0;\n"
1079" StackArray[i] = Array(20);\n"
1080" }\n"
1081"\n"
1082" for(var i = nFrameFirst; i < nFrameLast; i++)\n"
1083" {\n"
1084" var FrameSum = 0;\n"
1085" var fr = Frames[i];\n"
1086" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
1087" {\n"
1088" var StackPos = StackPosArray[nLog];\n"
1089" var Stack = StackArray[nLog];\n"
1090" var ts = fr.ts[nLog];\n"
1091" var ti = fr.ti[nLog];\n"
1092" var tt = fr.tt[nLog];\n"
1093" var count = ts.length;\n"
1094" for(j = 0; j < count; j++)\n"
1095" {\n"
1096" var type = tt[j];\n"
1097" var index = ti[j];\n"
1098" var time = ts[j];\n"
1099" if(type == 1) //enter\n"
1100" {\n"
1101" //push\n"
1102" Stack[StackPos] = time;\n"
1103" if(StackArray[nLog][StackPos] != time)\n"
1104" {\n"
1105" console.log(\'fail fail fail\');\n"
1106" }\n"
1107" StackPos++;\n"
1108" }\n"
1109" else if(type == 0) // leave\n"
1110" {\n"
1111" var timestart;\n"
1112" var timeend = time;\n"
1113" if(StackPos>0)\n"
1114" {\n"
1115" StackPos--;\n"
1116" timestart = Stack[StackPos];\n"
1117" }\n"
1118" else\n"
1119" {\n"
1120" timestart = Frames[nFrameFirst].framestart;\n"
1121" }\n"
1122" if(index == TimerIndex)\n"
1123" {\n"
1124" var TimeDelta = timeend - timestart;\n"
1125" CallCount++;\n"
1126" FrameSum += TimeDelta;\n"
1127" Sum += TimeDelta;\n"
1128" if(TimeDelta > Max)\n"
1129" Max = TimeDelta;\n"
1130" }\n"
1131" }\n"
1132" else\n"
1133" {\n"
1134" //meta\n"
1135" }\n"
1136" }\n"
1137" if(FrameSum > FrameMax)\n"
1138" {\n"
1139" FrameMax = FrameSum;\n"
1140" }\n"
1141" StackPosArray[nLog] = StackPos;\n"
1142" }\n"
1143" }\n"
1144"\n"
1145" Result.CallCount = CallCount;\n"
1146" Result.Sum = Sum.toFixed(3);\n"
1147" Result.Max = Max.toFixed(3);\n"
1148" Result.Average = (Sum / CallCount).toFixed(3);\n"
1149" Result.FrameAverage = (Sum / FrameCount).toFixed(3);\n"
1150" Result.FrameCallAverage = (CallCount / FrameCount).toFixed(3);\n"
1151" Result.FrameMax = FrameMax.toFixed(3);\n"
1152" return Result;\n"
1153"}\n"
1154"\n"
1155"function PreprocessCalculateAllTimers()\n"
1156"{\n"
1157" ProfileEnter(\"CalculateAllTimers\");\n"
1158" var nFrameFirst = 0;\n"
1159" var nFrameLast = Frames.length;\n"
1160" var FrameCount = nFrameLast - nFrameFirst;\n"
1161" if(0 == FrameCount)\n"
1162" return;\n"
1163" for(var j = 0; j < TimerInfo.length; j++)\n"
1164" {\n"
1165" TimerInfo[j].CallCount = 0;\n"
1166" TimerInfo[j].Sum = 0;\n"
1167" TimerInfo[j].Max = 0;\n"
1168" TimerInfo[j].FrameMax = 0;\n"
1169" }\n"
1170"\n"
1171"\n"
1172" var nNumLogs = Frames[0].ts.length;\n"
1173" var StackPosArray = Array(nNumLogs);\n"
1174" var StackArray = Array(nNumLogs);\n"
1175" for(var i = 0; i < nNumLogs; ++i)\n"
1176" {\n"
1177" StackPosArray[i] = 0;\n"
1178" StackArray[i] = Array(20);\n"
1179" }\n"
1180"\n"
1181" for(var i = nFrameFirst; i < nFrameLast; i++)\n"
1182" {\n"
1183" for(var j = 0; j < TimerInfo.length; j++)\n"
1184" {\n"
1185" TimerInfo[j].FrameSum = 0;\n"
1186" }\n"
1187"\n"
1188" var fr = Frames[i];\n"
1189" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
1190" {\n"
1191" var StackPos = StackPosArray[nLog];\n"
1192" var Stack = StackArray[nLog];\n"
1193" var ts = fr.ts[nLog];\n"
1194" var ti = fr.ti[nLog];\n"
1195" var tt = fr.tt[nLog];\n"
1196" var count = ts.length;\n"
1197" for(j = 0; j < count; j++)\n"
1198" {\n"
1199" var type = tt[j];\n"
1200" var index = ti[j];\n"
1201" var time = ts[j];\n"
1202" if(type == 1) //enter\n"
1203" {\n"
1204" //push\n"
1205" Stack[StackPos] = time;\n"
1206" if(StackArray[nLog][StackPos] != time)\n"
1207" {\n"
1208" console.log(\'fail fail fail\');\n"
1209" }\n"
1210" StackPos++;\n"
1211" }\n"
1212" else if(type == 0) // leave\n"
1213" {\n"
1214" var timestart;\n"
1215" var timeend = time;\n"
1216" if(StackPos>0)\n"
1217" {\n"
1218" StackPos--;\n"
1219" timestart = Stack[StackPos];\n"
1220" }\n"
1221" else\n"
1222" {\n"
1223" timestart = Frames[nFrameFirst].framestart;\n"
1224" }\n"
1225" // if(index == TimerIndex)\n"
1226" {\n"
1227" var TimeDelta = timeend - timestart;\n"
1228" TimerInfo[index].CallCount++;\n"
1229" TimerInfo[index].FrameSum += TimeDelta;\n"
1230" TimerInfo[index].Sum += TimeDelta;\n"
1231" if(TimeDelta > TimerInfo[index].Max)\n"
1232" TimerInfo[index].Max = TimeDelta;\n"
1233" }\n"
1234" }\n"
1235" else\n"
1236" {\n"
1237" //meta\n"
1238" }\n"
1239" }\n"
1240" for(var j = 0; j < TimerInfo.length; j++)\n"
1241" {\n"
1242" if(TimerInfo[j].FrameSum > TimerInfo[j].FrameMax)\n"
1243" {\n"
1244" TimerInfo[j].FrameMax = TimerInfo[j].FrameSum;\n"
1245" }\n"
1246" }\n"
1247" StackPosArray[nLog] = StackPos;\n"
1248" }\n"
1249"\n"
1250"\n"
1251" }\n"
1252"\n"
1253" for(var j = 0; j < TimerInfo.length; j++)\n"
1254" {\n"
1255" var CallCount = TimerInfo[j].CallCount;\n"
1256" var Sum = TimerInfo[j].Sum.toFixed(3);\n"
1257" var Max = TimerInfo[j].Max.toFixed(3);\n"
1258" var Average = (TimerInfo[j].Sum / TimerInfo[j].CallCount).toFixed(3);\n"
1259" var FrameAverage = (TimerInfo[j].Sum / FrameCount).toFixed(3);\n"
1260" var FrameCallAverage = (TimerInfo[j].CallCount / FrameCount).toFixed(3);\n"
1261" var FrameMax = TimerInfo[j].FrameMax.toFixed(3);\n"
1262" TimerInfo[j].CallCount = CallCount;\n"
1263" TimerInfo[j].Sum = Sum;\n"
1264" TimerInfo[j].Max = Max ;\n"
1265" TimerInfo[j].Average = Average;\n"
1266" TimerInfo[j].FrameAverage = FrameAverage;\n"
1267" TimerInfo[j].FrameCallAverage = FrameCallAverage;\n"
1268" TimerInfo[j].FrameMax = FrameMax;\n"
1269" }\n"
1270" ProfileLeave();\n"
1271"}\n"
1272"\n"
1273"var FlashFrames = 10;\n"
1274"var FlashFrameCounter = 0;\n"
1275"var FlashMessage = \'\';\n"
1276"function TimeString(Diff)\n"
1277"{\n"
1278" var DiffString = \"0 sec\";\n"
1279" var DiffTable = [1,60,60*60,60*60*24];\n"
1280" var DiffNameTable = [\"sec\", \"min\", \"hr\", \"day\"];\n"
1281" for(var i = 0; i < DiffTable.length; ++i)\n"
1282" {\n"
1283" if(Diff >= DiffTable[i])\n"
1284" {\n"
1285" DiffString = Math.floor(Diff / DiffTable[i]) + \" \" + DiffNameTable[i];\n"
1286" }\n"
1287" }\n"
1288" return DiffString;\n"
1289"\n"
1290"}\n"
1291"function ShowFlashMessage(Message, FrameCount)\n"
1292"{\n"
1293" FlashMessage = Message;\n"
1294" FlashFrameCounter = FrameCount;\n"
1295"}\n"
1296"function OnPageReady()\n"
1297"{\n"
1298" var DumpDate = DumpUtcCaptureTime;\n"
1299" var CurrentDate = Date.now() / 1000;\n"
1300" var Diff = CurrentDate - DumpDate;\n"
1301" var Limit = 10*60;//flash old message when loading captures older than 10 minutes \n"
1302" if(Diff > Limit)\n"
1303" {\n"
1304" ShowFlashMessage(\"Captured \" + TimeString(Diff) + \" ago\", 100);\n"
1305" }\n"
1306" if(!nHideHelp)\n"
1307" {\n"
1308" ShowHelp(1,0);\n"
1309" }\n"
1310"}\n"
1311"\n"
1312"function DrawFlashMessage(context)\n"
1313"{\n"
1314" if(FlashFrameCounter > 0)\n"
1315" {\n"
1316" if(FlashFrameCounter>1)\n"
1317" {\n"
1318" var FlashPrc = Math.sin(FlashFrameCounter / FlashFrames);\n"
1319" context.font = FontFlash;\n"
1320" context.globalAlpha = FlashPrc * 0.35 + 0.5;\n"
1321" context.textAlign = \'center\';\n"
1322" context.fillStyle = \'red\';\n"
1323" context.fillText(FlashMessage, nWidth * 0.5, 50);\n"
1324" context.globalAlpha = 1;\n"
1325" context.textAlign = \'left\';\n"
1326" context.font = Font;\n"
1327" }\n"
1328" FlashFrameCounter -= 1;\n"
1329"\n"
1330" }\n"
1331"}\n"
1332"\n"
1333"function DrawCaptureInfo(context)\n"
1334"{\n"
1335" context.fillStyle = \'white\';\n"
1336" context.textAlign = \'right\';\n"
1337" context.font = Font;\n"
1338" var DumpDate = DumpUtcCaptureTime;\n"
1339" var CurrentDate = Date.now() / 1000;\n"
1340" var Diff = CurrentDate - DumpDate;\n"
1341" var DiffString = TimeString(Diff) + \" ago\";\n"
1342" context.fillText(new Date(DumpDate*1000).toLocaleString(), nWidth, FontHeight);\n"
1343" if(Mode == ModeTimers)\n"
1344" {\n"
1345" context.fillText(\"Timer Frames: \" + AggregateInfo.Frames, nWidth, FontHeight*2);\n"
1346" }\n"
1347" else\n"
1348" {\n"
1349" context.fillText(\"Detailed Frames \"+ Frames.length, nWidth, FontHeight*2);\n"
1350" }\n"
1351" context.fillText(DumpHost, nWidth, FontHeight*3);\n"
1352" context.fillText(DiffString, nWidth, FontHeight*4);\n"
1353" context.textAlign = \'left\';\n"
1354" DrawFlashMessage(context);\n"
1355"}\n"
1356"\n"
1357"function DrawDetailedFrameHistory()\n"
1358"{\n"
1359" ProfileEnter(\"DrawDetailedFrameHistory\");\n"
1360" var x = HistoryViewMouseX;\n"
1361"\n"
1362" var context = CanvasHistory.getContext(\'2d\');\n"
1363" context.clearRect(0, 0, CanvasHistory.width, CanvasHistory.height);\n"
1364"\n"
1365" var fHeight = nHistoryHeight;\n"
1366" var fWidth = nWidth / Frames.length;\n"
1367" var fHeightScale = fHeight / ReferenceTime;\n"
1368" var fX = 0;\n"
1369" var FrameIndex = -1;\n"
1370" var MouseDragging = MouseDragState != MouseDragOff;\n"
1371" fRangeBeginHistory = fRangeEndHistory = -1;\n"
1372" fRangeBeginHistoryGpu = fRangeEndHistoryGpu = -1;\n"
1373"\n"
1374" var FrameFirst = -1;\n"
1375" var FrameLast = nWidth;\n"
1376" var fDetailedOffsetEnd = fDetailedOffset + fDetailedRange;\n"
1377" for(i = 0; i < Frames.length; i++)\n"
1378" {\n"
1379" var fMs = Frames[i].frameend - Frames[i].framestart;\n"
1380" if(fDetailedOffset <= Frames[i].frameend && fDetailedOffset >= Frames[i].framestart)\n"
1381" {\n"
1382" var lerp = (fDetailedOffset - Frames[i].framestart) / (Frames[i].frameend - Frames[i].framestart);\n"
1383" FrameFirst = fX + fWidth * lerp;\n"
1384" }\n"
1385" if(fDetailedOffsetEnd <= Frames[i].frameend && fDetailedOffsetEnd >= Frames[i].framestart)\n"
1386" {\n"
1387" var lerp = (fDetailedOffsetEnd - Frames[i].framestart) / (Frames[i].frameend - Frames[i].framestart);\n"
1388" FrameLast = fX + fWidth * lerp;\n"
1389" }\n"
1390" var fH = fHeightScale * fMs;\n"
1391" var bMouse = x > fX && x < fX + fWidth;\n"
1392" if(bMouse && !MouseDragging)\n"
1393" {\n"
1394" context.fillStyle = FRAME_HISTORY_COLOR_GPU;\n"
1395" fRangeBeginHistory = Frames[i].framestart;\n"
1396" fRangeEndHistory = Frames[i].frameend;\n"
1397" if(Frames[i].framestartgpu)\n"
1398" {\n"
1399" fRangeBeginHistoryGpu = Frames[i].framestartgpu;\n"
1400" fRangeEndHistoryGpu = Frames[i].frameendgpu;\n"
1401" }\n"
1402" FrameIndex = i;\n"
1403" }\n"
1404" else\n"
1405" {\n"
1406" context.fillStyle = FRAME_HISTORY_COLOR_CPU;\n"
1407" }\n"
1408" context.fillRect(fX, fHeight - fH, fWidth-1, fH);\n"
1409" fX += fWidth;\n"
1410" }\n"
1411"\n"
1412" var fRangeHistoryBegin = FrameFirst;\n"
1413" var fRangeHistoryEnd = FrameLast;\n"
1414" var X = fRangeHistoryBegin;\n"
1415" var Y = 0;\n"
1416" var W = fRangeHistoryEnd - fRangeHistoryBegin;\n"
1417" context.globalAlpha = 0.35;\n"
1418" context.fillStyle = \'#009900\';\n"
1419" context.fillRect(X, Y, W, fHeight);\n"
1420" context.globalAlpha = 1;\n"
1421" context.strokeStyle = \'#00ff00\';\n"
1422" context.beginPath();\n"
1423" context.moveTo(X, Y);\n"
1424" context.lineTo(X, Y+fHeight);\n"
1425" context.moveTo(X+W, Y);\n"
1426" context.lineTo(X+W, Y+fHeight);\n"
1427" context.stroke();\n"
1428"\n"
1429"\n"
1430"\n"
1431"\n"
1432" DrawCaptureInfo(context);\n"
1433"\n"
1434" if(FrameIndex>=0 && !MouseDragging)\n"
1435" {\n"
1436" var StringArray = [];\n"
1437" StringArray.push(\"Frame\");\n"
1438" StringArray.push(\"\" + FrameIndex);\n"
1439" StringArray.push(\"Time\");\n"
1440" StringArray.push(\"\" + (Frames[FrameIndex].frameend - Frames[FrameIndex].framestart).toFixed(3));\n"
1441"\n"
1442" DrawToolTip(StringArray, CanvasHistory, HistoryViewMouseX, HistoryViewMouseY+20);\n"
1443"\n"
1444" }\n"
1445" ProfileLeave();\n"
1446"}\n"
1447"function TimeToMsString(Time)\n"
1448"{\n"
1449" return Time.toFixed(3) + \"ms\";\n"
1450"}\n"
1451"function TimeToString(Time)\n"
1452"{\n"
1453" if(Time > 1000)\n"
1454" {\n"
1455" return (Time/1000.0).toFixed(0) +\"s\";\n"
1456" }\n"
1457" else if(Time > 0.9)\n"
1458" {\n"
1459" return Time.toFixed(0) + \"ms\";\n"
1460" }\n"
1461" else if(Time > 0.0009)\n"
1462" {\n"
1463" return (Time*1000).toFixed(0) + \"us\";\n"
1464" }\n"
1465" else\n"
1466" {\n"
1467" return (Time*1000000).toFixed(0) + \"ns\";\n"
1468" }\n"
1469"}\n"
1470"\n"
1471"function DrawDetailedBackground(context)\n"
1472"{\n"
1473" var fMs = fDetailedRange;\n"
1474" var fMsEnd = fMs + fDetailedOffset;\n"
1475" var fMsToScreen = nWidth / fMs;\n"
1476" var fRate = Math.floor(2*((Math.log(fMs)/Math.log(10))-1))/2;\n"
1477" var fStep = Math.pow(10, fRate);\n"
1478" var fRcpStep = 1.0 / fStep;\n"
1479" var nColorIndex = Math.floor(fDetailedOffset * fRcpStep) % 2;\n"
1480" if(nColorIndex < 0)\n"
1481" nColorIndex = -nColorIndex;\n"
1482" var fStart = Math.floor(fDetailedOffset * fRcpStep) * fStep;\n"
1483" var fHeight = CanvasDetailedView.height;\n"
1484" var fScaleX = nWidth / fDetailedRange; \n"
1485" var HeaderString = TimeToString(fStep);\n"
1486" context.textAlign = \'center\';\n"
1487" for(f = fStart; f < fMsEnd; )\n"
1488" {\n"
1489" var fNext = f + fStep;\n"
1490" var X = (f - fDetailedOffset) * fScaleX;\n"
1491" var W = (fNext-f)*fScaleX;\n"
1492" context.fillStyle = nBackColors[nColorIndex];\n"
1493" context.fillRect(X, 0, W+2, fHeight);\n"
1494" nColorIndex = 1 - nColorIndex;\n"
1495" context.fillStyle = \'#777777\'\n"
1496" context.fillText(HeaderString, X + W * 0.5, 10);\n"
1497" context.fillText(HeaderString, X + W * 0.5, nHeight - 10);\n"
1498" f = fNext;\n"
1499" }\n"
1500" context.textAlign = \'left\';\n"
1501" var fScaleX = nWidth / fDetailedRange; \n"
1502" context.globalAlpha = 0.5;\n"
1503" context.strokeStyle = \'#bbbbbb\';\n"
1504" context.beginPath();\n"
1505" for(var i = 0; i < Frames.length; i++)\n"
1506" {\n"
1507" var frfr = Frames[i];\n"
1508" if(frfr.frameend < fDetailedOffset || frfr.framestart > fDetailedOffset + fDetailedRange)\n"
1509" {\n"
1510" continue;\n"
1511" }\n"
1512" var X = (frfr.framestart - fDetailedOffset) * fScaleX;\n"
1513" if(X >= 0 && X < nWidth)\n"
1514" {\n"
1515" context.moveTo(X, 0);\n"
1516" context.lineTo(X, nHeight);\n"
1517" }\n"
1518" }\n"
1519" context.stroke();\n"
1520" context.globalAlpha = 1;\n"
1521"\n"
1522"}\n"
1523"function DrawToolTip(StringArray, Canvas, x, y)\n"
1524"{\n"
1525" var context = Canvas.getContext(\'2d\');\n"
1526" context.font = Font;\n"
1527" var WidthArray = Array(StringArray.length);\n"
1528" var nMaxWidth = 0;\n"
1529" var nHeight = 0;\n"
1530" for(i = 0; i < StringArray.length; i += 2)\n"
1531" {\n"
1532" var nWidth0 = context.measureText(StringArray[i]).width;\n"
1533" var nWidth1 = context.measureText(StringArray[i+1]).width;\n"
1534" var nSum = nWidth0 + nWidth1;\n"
1535" WidthArray[i] = nWidth0;\n"
1536" WidthArray[i+1] = nWidth1;\n"
1537" if(nSum > nMaxWidth)\n"
1538" {\n"
1539" nMaxWidth = nSum;\n"
1540" }\n"
1541" nHeight += BoxHeight;\n"
1542" }\n"
1543" nMaxWidth += 15;\n"
1544" //bounds check.\n"
1545" var CanvasRect = Canvas.getBoundingClientRect();\n"
1546" if(y + nHeight > CanvasRect.height)\n"
1547" {\n"
1548" y = CanvasRect.height - nHeight;\n"
1549" x += 20;\n"
1550" }\n"
1551" if(x + nMaxWidth > CanvasRect.width)\n"
1552" {\n"
1553" x = CanvasRect.width - nMaxWidth;\n"
1554" }\n"
1555"\n"
1556" context.fillStyle = \'black\';\n"
1557" context.fillRect(x-1, y, nMaxWidth+2, nHeight);\n"
1558" context.fillStyle = \'white\';\n"
1559"\n"
1560" var XPos = x;\n"
1561" var XPosRight = x + nMaxWidth;\n"
1562" var YPos = y + BoxHeight-2;\n"
1563" for(i = 0; i < StringArray.length; i += 2)\n"
1564" {\n"
1565" context.fillText(StringArray[i], XPos, YPos);\n"
1566" context.fillText(StringArray[i+1], XPosRight - WidthArray[i+1], YPos);\n"
1567" YPos += BoxHeight;\n"
1568" }\n"
1569"}\n"
1570"function DrawHoverToolTip()\n"
1571"{\n"
1572" ProfileEnter(\"DrawHoverToolTip\");\n"
1573" if(nHoverToken != -1)\n"
1574" {\n"
1575" var StringArray = [];\n"
1576" var groupid = TimerInfo[nHoverToken].group;\n"
1577" StringArray.push(\"Timer\");\n"
1578" StringArray.push(TimerInfo[nHoverToken].name);\n"
1579" StringArray.push(\"Group\");\n"
1580" StringArray.push(GroupInfo[groupid].name);\n"
1581"\n"
1582" var bShowTimers = Mode == ModeTimers;\n"
1583" if(FlipToolTip)\n"
1584" {\n"
1585" bShowTimers = !bShowTimers;\n"
1586" }\n"
1587" if(bShowTimers)\n"
1588" {\n"
1589"\n"
1590" StringArray.push(\"\");\n"
1591" StringArray.push(\"\");\n"
1592" var Timer = TimerInfo[nHoverToken];\n"
1593" StringArray.push(\"Average\");\n"
1594" StringArray.push(Timer.average);\n"
1595" StringArray.push(\"Max\");\n"
1596" StringArray.push(Timer.max);\n"
1597" StringArray.push(\"Excl Max\");\n"
1598" StringArray.push(Timer.exclmax);\n"
1599" StringArray.push(\"Excl Average\");\n"
1600" StringArray.push(Timer.exclaverage);\n"
1601" StringArray.push(\"Call Average\");\n"
1602" StringArray.push(Timer.callaverage);\n"
1603" StringArray.push(\"Call Count\");\n"
1604" StringArray.push(Timer.callcount);\n"
1605"\n"
1606" StringArray.push(\"\");\n"
1607" StringArray.push(\"\");\n"
1608"\n"
1609"\n"
1610" StringArray.push(\"Group\");\n"
1611" StringArray.push(GroupInfo[groupid].name);\n"
1612" StringArray.push(\"Average\");\n"
1613" StringArray.push(GroupInfo[groupid].average);\n"
1614" StringArray.push(\"Max\");\n"
1615" StringArray.push(GroupInfo[groupid].max);\n"
1616"\n"
1617" StringArray.push(\"\");\n"
1618" StringArray.push(\"\");\n"
1619"\n"
1620" StringArray.push(\"";
1621
1622const size_t g_MicroProfileHtml_end_0_size = sizeof(g_MicroProfileHtml_end_0);
1623const char g_MicroProfileHtml_end_1[] =
1624"Timer Capture\");\n"
1625" StringArray.push(\"\");\n"
1626" StringArray.push(\"Frames\");\n"
1627" StringArray.push(AggregateInfo.Frames);\n"
1628" StringArray.push(\"Time\");\n"
1629" StringArray.push(AggregateInfo.Time.toFixed(2) + \"ms\");\n"
1630"\n"
1631"\n"
1632"\n"
1633"\n"
1634" }\n"
1635" else\n"
1636" {\n"
1637" StringArray.push(\"\");\n"
1638" StringArray.push(\"\");\n"
1639"\n"
1640"\n"
1641"\n"
1642" StringArray.push(\"Time\");\n"
1643" StringArray.push((fRangeEnd-fRangeBegin).toFixed(3));\n"
1644" StringArray.push(\"\");\n"
1645" StringArray.push(\"\");\n"
1646" StringArray.push(\"Total\");\n"
1647" StringArray.push(\"\" + TimerInfo[nHoverToken].Sum);\n"
1648" StringArray.push(\"Max\");\n"
1649" StringArray.push(\"\" + TimerInfo[nHoverToken].Max);\n"
1650" StringArray.push(\"Average\");\n"
1651" StringArray.push(\"\" + TimerInfo[nHoverToken].Average);\n"
1652" StringArray.push(\"Count\");\n"
1653" StringArray.push(\"\" + TimerInfo[nHoverToken].CallCount);\n"
1654"\n"
1655" StringArray.push(\"\");\n"
1656" StringArray.push(\"\");\n"
1657"\n"
1658" StringArray.push(\"Max/Frame\");\n"
1659" StringArray.push(\"\" + TimerInfo[nHoverToken].FrameMax);\n"
1660"\n"
1661" StringArray.push(\"Average Time/Frame\");\n"
1662" StringArray.push(\"\" + TimerInfo[nHoverToken].FrameAverage);\n"
1663"\n"
1664" StringArray.push(\"Average Count/Frame\");\n"
1665" StringArray.push(\"\" + TimerInfo[nHoverToken].FrameCallAverage);\n"
1666"\n"
1667"\n"
1668"\n"
1669"\n"
1670"\n"
1671" \n"
1672" if(nHoverFrame != -1)\n"
1673" {\n"
1674" StringArray.push(\"\");\n"
1675" StringArray.push(\"\");\n"
1676" StringArray.push(\"Frame \" + nHoverFrame);\n"
1677" StringArray.push(\"\");\n"
1678"\n"
1679" var FrameTime = new Object();\n"
1680" CalculateTimers(FrameTime, nHoverToken, nHoverFrame, nHoverFrame+1);\n"
1681" StringArray.push(\"Total\");\n"
1682" StringArray.push(\"\" + FrameTime.Sum);\n"
1683" StringArray.push(\"Count\");\n"
1684" StringArray.push(\"\" + FrameTime.CallCount);\n"
1685" StringArray.push(\"Average\");\n"
1686" StringArray.push(\"\" + FrameTime.Average);\n"
1687" StringArray.push(\"Max\");\n"
1688" StringArray.push(\"\" + FrameTime.Max);\n"
1689" }\n"
1690"\n"
1691" var HoverInfo = GatherHoverMetaCounters(nHoverToken, nHoverTokenIndex, nHoverTokenLogIndex, nHoverFrame);\n"
1692" var Header = 0;\n"
1693" for(index in HoverInfo)\n"
1694" {\n"
1695" if(0 == Header)\n"
1696" {\n"
1697" Header = 1;\n"
1698" StringArray.push(\"\");\n"
1699" StringArray.push(\"\");\n"
1700" StringArray.push(\"Meta\");\n"
1701" StringArray.push(\"\");\n"
1702"\n"
1703" }\n"
1704" StringArray.push(\"\"+index);\n"
1705" StringArray.push(\"\"+HoverInfo[index]);\n"
1706" }\n"
1707"\n"
1708" StringArray.push(\"\");\n"
1709" StringArray.push(\"\");\n"
1710"\n"
1711" StringArray.push(\"Detailed Capture\");\n"
1712" StringArray.push(\"\");\n"
1713" StringArray.push(\"Frames\");\n"
1714" StringArray.push(Frames.length);\n"
1715" StringArray.push(\"Time\");\n"
1716" StringArray.push(DetailedTotal().toFixed(2) + \"ms\");\n"
1717"\n"
1718"\n"
1719" }\n"
1720" DrawToolTip(StringArray, CanvasDetailedView, DetailedViewMouseX, DetailedViewMouseY+20);\n"
1721" }\n"
1722" else if(nHoverCSCpu >= 0)\n"
1723" {\n"
1724" var StringArray = [];\n"
1725" StringArray.push(\"Context Switch\");\n"
1726" StringArray.push(\"\");\n"
1727" StringArray.push(\"\");\n"
1728" StringArray.push(\"\");\n"
1729" StringArray.push(\"Cpu\");\n"
1730" StringArray.push(\"\" + nHoverCSCpu);\n"
1731" StringArray.push(\"Begin\");\n"
1732" StringArray.push(\"\" + fRangeBegin);\n"
1733" StringArray.push(\"End\");\n"
1734" StringArray.push(\"\" + fRangeEnd);\n"
1735" DrawToolTip(StringArray, CanvasDetailedView, DetailedViewMouseX, DetailedViewMouseY+20);\n"
1736" }\n"
1737" ProfileLeave();\n"
1738"}\n"
1739"\n"
1740"function FormatMeta(Value, Dec)\n"
1741"{\n"
1742" if(!Value)\n"
1743" {\n"
1744" Value = \"0\";\n"
1745" }\n"
1746" else\n"
1747" {\n"
1748" Value = \'\' + Value.toFixed(Dec);\n"
1749" }\n"
1750" return Value;\n"
1751"}\n"
1752"\n"
1753"function DrawBarView()\n"
1754"{\n"
1755" ProfileEnter(\"DrawBarView\");\n"
1756" Invalidate++;\n"
1757" nHoverToken = -1;\n"
1758" nHoverFrame = -1;\n"
1759" var context = CanvasDetailedView.getContext(\'2d\');\n"
1760" context.clearRect(0, 0, nWidth, nHeight);\n"
1761"\n"
1762" var Height = BoxHeight;\n"
1763" var Width = nWidth;\n"
1764"\n"
1765" //clamp offset to prevent scrolling into the void\n"
1766" var nTotalRows = 0;\n"
1767" for(var groupid in GroupInfo)\n"
1768" {\n"
1769" if(GroupsAllActive || GroupsActive[GroupInfo[groupid].name])\n"
1770" {\n"
1771" nTotalRows += GroupInfo[groupid].TimerArray.length + 1;\n"
1772" }\n"
1773" }\n"
1774" var nTotalRowPixels = nTotalRows * Height;\n"
1775" var nFrameRows = nHeight - BoxHeight;\n"
1776" if(nOffsetBarsY + nFrameRows > nTotalRowPixels && nTotalRowPixels > nFrameRows)\n"
1777" {\n"
1778" nOffsetBarsY = nTotalRowPixels - nFrameRows;\n"
1779" }\n"
1780"\n"
1781"\n"
1782" var Y = -nOffsetBarsY + BoxHeight;\n"
1783" if(TimersGroups)\n"
1784" {\n"
1785" nOffsetBarsX = 0;\n"
1786" }\n"
1787" var XBase = -nOffsetBarsX;\n"
1788" var nColorIndex = 0;\n"
1789"\n"
1790" context.fillStyle = \'white\';\n"
1791" context.font = Font;\n"
1792" var bMouseIn = 0;\n"
1793" var RcpReferenceTime = 1.0 / ReferenceTime;\n"
1794" var CountWidth = 8 * FontWidth;\n"
1795" var nMetaLen = TimerInfo[0].meta.length;\n"
1796" var nMetaCharacters = 10;\n"
1797" for(var i = 0; i < nMetaLen; ++i)\n"
1798" {\n"
1799" if(nMetaCharacters < MetaNames[i].length)\n"
1800" nMetaCharacters = MetaNames[i].length;\n"
1801" }\n"
1802" var nWidthMeta = nMetaCharacters * FontWidth + 6;\n"
1803" function DrawHeaderSplit(Header)\n"
1804" {\n"
1805" context.fillStyle = \'white\';\n"
1806" context.fillText(Header, X, Height-FontAscent);\n"
1807" X += nWidthBars;\n"
1808" context.fillStyle = nBackColorOffset;\n"
1809" X += nWidthMs;\n"
1810" if(X >= NameWidth)\n"
1811" {\n"
1812" context.fillRect(X-3, 0, 1, nHeight);\n"
1813" }\n"
1814" }\n"
1815" function DrawHeaderSplitSingle(Header, Width)\n"
1816" {\n"
1817" context.fillStyle = \'white\';\n"
1818" context.fillText(Header, X, Height-FontAscent);\n"
1819" X += Width;\n"
1820" context.fillStyle = nBackColorOffset;\n"
1821" if(X >= NameWidth)\n"
1822" {\n"
1823" context.fillRect(X-3, 0, 1, nHeight);\n"
1824" }\n"
1825" }\n"
1826" function DrawHeaderSplitLeftRight(HeaderLeft, HeaderRight, Width)\n"
1827" {\n"
1828" context.textAlign = \'left\';\n"
1829" context.fillStyle = \'white\';\n"
1830" context.fillText(HeaderLeft, X, Height-FontAscent);\n"
1831" X += Width;\n"
1832" context.textAlign = \'right\';\n"
1833" context.fillText(HeaderRight, X-5, Height-FontAscent);\n"
1834" context.textAlign = \'left\';\n"
1835" context.fillStyle = nBackColorOffset;\n"
1836" if(X >= NameWidth)\n"
1837" {\n"
1838" context.fillRect(X-3, 0, 1, nHeight);\n"
1839" }\n"
1840" }\n"
1841" function DrawTimer(Value, Color)\n"
1842" {\n"
1843" var Prc = Value * RcpReferenceTime;\n"
1844" var YText = Y+Height-FontAscent;\n"
1845" if(Prc > 1)\n"
1846" {\n"
1847" Prc = 1;\n"
1848" }\n"
1849" context.fillStyle = Color;\n"
1850" context.fillRect(X+1, Y+1, Prc * nBarsWidth, InnerBoxHeight);\n"
1851" X += nWidthBars;\n"
1852" context.fillStyle = \'white\';\n"
1853" context.fillText((\" \" + Value.toFixed(2)).slice(-TimerLen), X, YText);\n"
1854" X += nWidthMs;\n"
1855" }\n"
1856" function DrawMeta(Value, Width, Dec)\n"
1857" {\n"
1858" Value = FormatMeta(Value, Dec);\n"
1859" X += (FontWidth*Width);\n"
1860" context.textAlign = \'right\';\n"
1861" context.fillText(Value, X-FontWidth, YText);\n"
1862" context.textAlign = \'left\';\n"
1863" }\n"
1864" var InnerBoxHeight = BoxHeight-2;\n"
1865" var TimerLen = 6;\n"
1866" var TimerWidth = TimerLen * FontWidth;\n"
1867" var nWidthBars = nBarsWidth+2;\n"
1868" var nWidthMs = TimerWidth+2+10;\n"
1869"\n"
1870"\n"
1871" if(2 == TimersGroups)\n"
1872" {\n"
1873" for(var i = 0; i < ThreadNames.length; ++i)\n"
1874" {\n"
1875" if(ThreadsActive[ThreadNames[i]] || ThreadsAllActive)\n"
1876" {\n"
1877" var X = 0;\n"
1878" var YText = Y+Height-FontAscent;\n"
1879" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight;\n"
1880" nColorIndex = 1-nColorIndex;\n"
1881" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1882" context.fillRect(0, Y, Width, Height);\n"
1883" var ThreadColor = CSwitchColors[i % CSwitchColors.length];\n"
1884" context.fillStyle = ThreadColor;\n"
1885" context.fillText(ThreadNames[i], 1, YText);\n"
1886" context.textAlign = \'left\';\n"
1887" Y += Height;\n"
1888" for(var idx in GroupOrder)\n"
1889" {\n"
1890" var groupid = GroupOrder[idx];\n"
1891" var Group = GroupInfo[groupid];\n"
1892" var PerThreadTimer = ThreadGroupTimeArray[i][groupid];\n"
1893" var PerThreadTimerTotal = ThreadGroupTimeTotalArray[i][groupid];\n"
1894" if((PerThreadTimer > 0.0001|| PerThreadTimerTotal>0.1) && (GroupsAllActive || GroupsActive[Group.name]))\n"
1895" {\n"
1896" var GColor = GroupColors ? GroupInfo[groupid].color : \'white\';\n"
1897" var X = 0;\n"
1898" nColorIndex = 1-nColorIndex;\n"
1899" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight;\n"
1900" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1901" context.fillRect(0, Y, Width, nHeight);\n"
1902" context.fillStyle = GColor;\n"
1903" context.textAlign = \'right\';\n"
1904" context.fillText(Group.name, NameWidth - 5, Y+Height-FontAscent);\n"
1905" context.textAlign = \'left\';\n"
1906" X += NameWidth;\n"
1907" DrawTimer(PerThreadTimer, GColor);\n"
1908" X += nWidthBars + nWidthMs; \n"
1909" DrawTimer(PerThreadTimerTotal, GColor);\n"
1910"\n"
1911" Y += Height;\n"
1912" }\n"
1913" }\n"
1914" }\n"
1915" }\n"
1916" }\n"
1917" else\n"
1918" {\n"
1919" for(var idx in GroupOrder)\n"
1920" {\n"
1921" var groupid = GroupOrder[idx];\n"
1922" var Group = GroupInfo[groupid];\n"
1923" var GColor = GroupColors ? GroupInfo[groupid].color : \'white\';\n"
1924" if(GroupsAllActive || GroupsActive[Group.name])\n"
1925" {\n"
1926" var TimerArray = Group.TimerArray;\n"
1927" var X = XBase;\n"
1928" nColorIndex = 1-nColorIndex;\n"
1929" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight;\n"
1930" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1931" context.fillRect(0, Y, Width, nHeight);\n"
1932" context.fillStyle = GColor;\n"
1933" context.fillText(Group.name, 1, Y+Height-FontAscent);\n"
1934" X += NameWidth;\n"
1935" DrawTimer(Group.average, GColor);\n"
1936" DrawTimer(Group.max, GColor);\n"
1937" DrawTimer(Group.total, GColor);\n"
1938"\n"
1939" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1940" context.fillRect(0, Y, NameWidth, nHeight);\n"
1941" context.fillStyle = GColor;\n"
1942" context.fillText(Group.name, 1, Y+Height-FontAscent);\n"
1943"\n"
1944"\n"
1945"\n"
1946" Y += Height;\n"
1947" if(TimersGroups)\n"
1948" {\n"
1949" for(var i = 0; i < ThreadNames.length; ++i)\n"
1950" {\n"
1951" var PerThreadTimer = ThreadGroupTimeArray[i][groupid];\n"
1952" var PerThreadTimerTotal = ThreadGroupTimeTotalArray[i][groupid];\n"
1953" if((PerThreadTimer > 0.0001|| PerThreadTimerTotal>0.1) && (ThreadsActive[ThreadNames[i]] || ThreadsAllActive))\n"
1954" {\n"
1955" var YText = Y+Height-FontAscent;\n"
1956" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight;\n"
1957" nColorIndex = 1-nColorIndex;\n"
1958" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1959" context.fillRect(0, Y, Width, Height);\n"
1960" var ThreadColor = CSwitchColors[i % CSwitchColors.length];\n"
1961" context.fillStyle = ThreadColor;\n"
1962" context.textAlign = \'right\';\n"
1963" context.fillText(ThreadNames[i], NameWidth - 5, YText);\n"
1964" context.textAlign = \'left\';\n"
1965" X = NameWidth;\n"
1966" DrawTimer(PerThreadTimer, ThreadColor);\n"
1967" X += nWidthBars + nWidthMs; \n"
1968" DrawTimer(PerThreadTimerTotal, ThreadColor);\n"
1969" Y += Height;\n"
1970" }\n"
1971" }\n"
1972" }\n"
1973" else\n"
1974" {\n"
1975" for(var timerindex in TimerArray)\n"
1976" {\n"
1977" var timerid = TimerArray[timerindex];\n"
1978" var Timer = TimerInfo[timerid];\n"
1979" var Average = Timer.average;\n"
1980" var Max = Timer.max;\n"
1981" var ExclusiveMax = Timer.exclmax;\n"
1982" var ExclusiveAverage = Timer.exclaverage;\n"
1983" var CallAverage = Timer.callaverage;\n"
1984" var CallCount = Timer.callcount;\n"
1985" var YText = Y+Height-FontAscent;\n"
1986" X = NameWidth + XBase;\n"
1987"\n"
1988" nColorIndex = 1-nColorIndex;\n"
1989" bMouseIn = DetailedViewMouseY >= Y && DetailedViewMouseY < Y + BoxHeight;\n"
1990" if(bMouseIn)\n"
1991" {\n"
1992" nHoverToken = timerid;\n"
1993" }\n"
1994" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
1995" context.fillRect(0, Y, Width, Height);\n"
1996"\n"
1997" DrawTimer(Average, Timer.color);\n"
1998" DrawTimer(Max,Timer.color);\n"
1999" DrawTimer(Timer.total,Timer.color);\n"
2000" DrawTimer(CallAverage,Timer.color);\n"
2001" context.fillStyle = \'white\';\n"
2002" context.fillText(CallCount, X, YText);\n"
2003" X += CountWidth;\n"
2004" DrawTimer(ExclusiveAverage,Timer.color);\n"
2005" DrawTimer(ExclusiveMax,Timer.color);\n"
2006"\n"
2007" if(TimersMeta)\n"
2008" {\n"
2009" context.fillStyle = \'white\';\n"
2010" for(var j = 0; j < nMetaLen; ++j)\n"
2011" {\n"
2012" // var Len = MetaNames[j].length + 1;\n"
2013" DrawMeta(Timer.meta[j], MetaLengths[j], 0);\n"
2014" DrawMeta(Timer.metaavg[j], MetaLengthsAvg[j], 2);\n"
2015" DrawMeta(Timer.metamax[j], MetaLengthsMax[j], 0);\n"
2016" }\n"
2017" }\n"
2018" context.fillStyle = bMouseIn ? nBackColorOffset : nBackColors[nColorIndex];\n"
2019" context.fillRect(0, Y, NameWidth, Height);\n"
2020" context.textAlign = \'right\';\n"
2021" context.fillStyle = Timer.color;\n"
2022" context.fillText(Timer.name, NameWidth - 5, YText);\n"
2023" context.textAlign = \'left\';\n"
2024"\n"
2025"\n"
2026" Y += Height;\n"
2027" } \n"
2028" }\n"
2029" }\n"
2030" }\n"
2031" }\n"
2032" X = 0;\n"
2033" context.fillStyle = nBackColorOffset;\n"
2034" context.fillRect(0, 0, Width, Height);\n"
2035" context.fillStyle = \'white\';\n"
2036" if(TimersGroups)\n"
2037" {\n"
2038" if(2 == TimersGroups)\n"
2039" {\n"
2040" DrawHeaderSplitLeftRight(\'Thread\', \'Group\', NameWidth);\n"
2041" DrawHeaderSplit(\'Average\');\n"
2042" }\n"
2043" else\n"
2044" {\n"
2045" DrawHeaderSplitLeftRight(\'Group\', \'Thread\', NameWidth);\n"
2046" DrawHeaderSplit(\'Average\');\n"
2047" DrawHeaderSplit(\'Max\');\n"
2048" DrawHeaderSplit(\'Total\');\n"
2049" }\n"
2050" }\n"
2051" else\n"
2052" {\n"
2053" X = NameWidth + XBase;\n"
2054" DrawHeaderSplit(\'Average\');\n"
2055" DrawHeaderSplit(\'Max\');\n"
2056" DrawHeaderSplit(\'Total\');\n"
2057" DrawHeaderSplit(\'Call Average\');\n"
2058" DrawHeaderSplitSingle(\'Count\', CountWidth);\n"
2059" DrawHeaderSplit(\'Excl Average\');\n"
2060" DrawHeaderSplit(\'Excl Max\');\n"
2061" if(TimersMeta)\n"
2062" {\n"
2063" for(var i = 0; i < nMetaLen; ++i)\n"
2064" {\n"
2065" DrawHeaderSplitSingle(MetaNames[i], MetaLengths[i] * FontWidth);\n"
2066" DrawHeaderSplitSingle(MetaNames[i] + \" Avg\", MetaLengthsAvg[i] * FontWidth);\n"
2067" DrawHeaderSplitSingle(MetaNames[i] + \" Max\", MetaLengthsMax[i] * FontWidth);\n"
2068" }\n"
2069" }\n"
2070" X = 0;\n"
2071" context.fillStyle = nBackColorOffset;\n"
2072" context.fillRect(0, 0, NameWidth, Height);\n"
2073" context.fillStyle = \'white\';\n"
2074" \n"
2075" DrawHeaderSplitLeftRight(\'Group\', \'Timer\', NameWidth);\n"
2076" \n"
2077" }\n"
2078"\n"
2079" ProfileLeave();\n"
2080"}\n"
2081"\n"
2082"\n"
2083"//preprocess context switch data to contain array per thread\n"
2084"function PreprocessContextSwitchCacheItem(ThreadId)\n"
2085"{\n"
2086" console.log(\'context switch preparing \' + ThreadId);\n"
2087" var CSObject = CSwitchCache[ThreadId];\n"
2088" if(ThreadId > 0 && !CSObject)\n"
2089" {\n"
2090" CSArrayIn = new Array();\n"
2091" CSArrayOut = new Array();\n"
2092" CSArrayCpu = new Array();\n"
2093" var nCount = CSwitchTime.length;\n"
2094" var j = 0;\n"
2095" var TimeIn = -1.0;\n"
2096" for(var i = 0; i < nCount; ++i)\n"
2097" { \n"
2098" var ThreadIn = CSwitchThreadInOutCpu[j];\n"
2099" var ThreadOut = CSwitchThreadInOutCpu[j+1];\n"
2100" var Cpu = CSwitchThreadInOutCpu[j+2];\n"
2101" if(TimeIn < 0)\n"
2102" {\n"
2103" if(ThreadIn == ThreadId)\n"
2104" {\n"
2105" TimeIn = CSwitchTime[i];\n"
2106" }\n"
2107" }\n"
2108" else\n"
2109" {\n"
2110" if(ThreadOut == ThreadId)\n"
2111" {\n"
2112" var TimeOut = CSwitchTime[i];\n"
2113" CSArrayIn.push(TimeIn);\n"
2114" CSArrayOut.push(TimeOut);\n"
2115" CSArrayCpu.push(Cpu);\n"
2116" TimeIn = -1;\n"
2117" }\n"
2118" }\n"
2119" j += 3;\n"
2120" }\n"
2121" CSObject = new Object();\n"
2122" CSObject.Size = CSArrayIn.length;\n"
2123" CSObject.In = CSArrayIn;\n"
2124" CSObject.Out = CSArrayOut;\n"
2125" CSObject.Cpu = CSArrayCpu;\n"
2126" CSwitchCache[ThreadId] = CSObject;\n"
2127" }\n"
2128"\n"
2129"}\n"
2130"function PreprocessContextSwitchCache()\n"
2131"{\n"
2132" ProfileEnter(\"PreprocessContextSwitchCache\");\n"
2133" var AllThreads = {};\n"
2134" var nCount = CSwitchTime.length;\n"
2135" for(var i = 0; i < nCount; ++i)\n"
2136" { \n"
2137" var nThreadIn = CSwitchThreadInOutCpu[i];\n"
2138" if(!AllThreads[nThreadIn])\n"
2139" {\n"
2140" AllThreads[nThreadIn] = \'\' + nThreadIn;\n"
2141" var FoundThread = false;\n"
2142" for(var i = 0; i < ThreadIds.length; ++i)\n"
2143" {\n"
2144" if(ThreadIds[i] == nThreadIn)\n"
2145" {\n"
2146" FoundThread = true;\n"
2147" }\n"
2148" }\n"
2149" if(!FoundThread)\n"
2150" {\n"
2151" CSwitchOnlyThreads.push(nThreadIn);\n"
2152" }\n"
2153" }\n"
2154" }\n"
2155" for(var i = 0; i < CSwitchOnlyThreads.length; ++i)\n"
2156" {\n"
2157" PreprocessContextSwitchCacheItem(CSwitchOnlyThreads[i]);\n"
2158" }\n"
2159" for(var i = 0; i < ThreadIds.length; ++i)\n"
2160" {\n"
2161" PreprocessContextSwitchCacheItem(ThreadIds[i]); \n"
2162" }\n"
2163" ProfileLeave();\n"
2164"}\n"
2165"\n"
2166"function DrawContextSwitchBars(context, ThreadId, fScaleX, fOffsetY, fDetailedOffset, nHoverColor, MinWidth, bDrawEnabled)\n"
2167"{\n"
2168" ProfileEnter(\"DrawContextSwitchBars\");\n"
2169" var CSObject = CSwitchCache[ThreadId];\n"
2170" if(CSObject)\n"
2171" {\n"
2172" var Size = CSObject.Size; \n"
2173" var In = CSObject.In;\n"
2174" var Out = CSObject.Out;\n"
2175" var Cpu = CSObject.Cpu;\n"
2176" var nNumColors = CSwitchColors.length;\n"
2177" for(var i = 0; i < Size; ++i)\n"
2178" {\n"
2179" var TimeIn = In[i];\n"
2180" var TimeOut = Out[i];\n"
2181" var ActiveCpu = Cpu[i];\n"
2182"\n"
2183" var X = (TimeIn - fDetailedOffset) * fScaleX;\n"
2184" if(X > nWidth)\n"
2185" {\n"
2186" break;\n"
2187" }\n"
2188" var W = (TimeOut - TimeIn) * fScaleX;\n"
2189" if(W > MinWidth && X+W > 0)\n"
2190" {\n"
2191" if(nHoverCSCpu == ActiveCpu || bDrawEnabled)\n"
2192" {\n"
2193" if(nHoverCSCpu == ActiveCpu)\n"
2194" {\n"
2195" context.fillStyle = nHoverColor;\n"
2196" }\n"
2197" else\n"
2198" {\n"
2199" context.fillStyle = CSwitchColors[ActiveCpu % nNumColors];\n"
2200" }\n"
2201" context.fillRect(X, fOffsetY, W, CSwitchHeight);\n"
2202" }\n"
2203" if(DetailedViewMouseX >= X && DetailedViewMouseX <= X+W && DetailedViewMouseY < fOffsetY+CSwitchHeight && DetailedViewMouseY >= fOffsetY)\n"
2204" {\n"
2205" nHoverCSCpuNext = ActiveCpu;\n"
2206" fRangeBeginNext = TimeIn;\n"
2207" fRangeEndNext = TimeOut;\n"
2208" fRangeBeginGpuNext = fRangeEndGpuNext = -1;\n"
2209" }\n"
2210" }\n"
2211" }\n"
2212" }\n"
2213" ProfileLeave();\n"
2214"}\n"
2215"\n"
2216"function DrawDetailedView(context, MinWidth, bDrawEnabled)\n"
2217"{\n"
2218" if(bDrawEnabled)\n"
2219" {\n"
2220" DrawDetailedBackground(context);\n"
2221" }\n"
2222"\n"
2223" var colors = [ \'#ff0000\', \'#ff00ff\', \'#ffff00\'];\n"
2224"\n"
2225" var fScaleX = nWidth / fDetailedRange; \n"
2226" var fOffsetY = -nOffsetY + BoxHeight;\n"
2227" nHoverTokenNext = -1;\n"
2228" nHoverTokenLogIndexNext = -1;\n"
2229" nHoverTokenIndexNext = -1;\n"
2230" nHoverCounter += nHoverCounterDelta;\n"
2231" if(nHoverCounter >= 255) \n"
2232" {\n"
2233" nHoverCounter = 255;\n"
2234" nHoverCounterDelta = -nHoverCounterDelta;\n"
2235" }\n"
2236" if(nHoverCounter < 128) \n"
2237" {\n"
2238" nHoverCounter = 128;\n"
2239" nHoverCounterDelta = -nHoverCounterDelta;\n"
2240" }\n"
2241" var nHoverHigh = nHoverCounter.toString(16);\n"
2242" var nHoverLow = (127+255-nHoverCounter).toString(16);\n"
2243" var nHoverColor = \'#\' + nHoverHigh + nHoverHigh + nHoverHigh;\n"
2244"\n"
2245" context.fillStyle = \'black\';\n"
2246" context.font = Font;\n"
2247" var nNumLogs = Frames[0].ts.length;\n"
2248" var fTimeEnd = fDetailedOffset + fDetailedRange;\n"
2249"\n"
2250" var FirstFrame = 0;\n"
2251" for(var i = 0; i < Frames.length ; i++)\n"
2252" {\n"
2253" if(Frames[i].frameend < fDetailedOffset)\n"
2254" {\n"
2255" FirstFrame = i;\n"
2256" }\n"
2257" }\n"
2258" var nMinTimeMs = MinWidth / fScaleX;\n"
2259" {\n"
2260"\n"
2261" var Batches = new Array(TimerInfo.length);\n"
2262" var BatchesTxt = Array();\n"
2263" var BatchesTxtPos = Array();\n"
2264" var BatchesTxtColor = [\'#ffffff\', \'#333333\'];\n"
2265"\n"
2266" for(var i = 0; i < 2; ++i)\n"
2267" {\n"
2268" BatchesTxt[i] = Array();\n"
2269" BatchesTxtPos[i] = Array();\n"
2270" }\n"
2271" for(var i = 0; i < Batches.length; ++i)\n"
2272" {\n"
2273" Batches[i] = Array();\n"
2274" }\n"
2275" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
2276" {\n"
2277" var ThreadName = ThreadNames[nLog];\n"
2278" if(ThreadsAllActive || ThreadsActive[ThreadName])\n"
2279" {\n"
2280"\n"
2281" var LodIndex = 0;\n"
2282" var MinDelta = 0;\n"
2283" var NextLod = 1;\n"
2284" while(NextLod < LodData.length && LodData[NextLod].MinDelta[nLog] < nMinTimeMs)\n"
2285" {\n"
2286" LodIndex = NextLod;\n"
2287" NextLod = NextLod + 1;\n"
2288" MinDelta = LodData[LodIndex].MinDelta[nLog];\n"
2289" }\n"
2290" if(LodIndex == LodData.length)\n"
2291" {\n"
2292" LodIndex = LodData.length-1;\n"
2293" }\n"
2294" if(DisableLod)\n"
2295" {\n"
2296" LodIndex = 0;\n"
2297" }\n"
2298"\n"
2299" context.fillStyle = \'white\';\n"
2300" fOffsetY += BoxHeight;\n"
2301" context.fillText(ThreadName, 0, fOffsetY);\n"
2302" if(nContextSwitchEnabled)\n"
2303" {\n"
2304" DrawContextSwitchBars(context, ThreadIds[nLog], fScaleX, fOffsetY, fDetailedOffset, nHoverColor, MinWidth, bDrawEnabled);\n"
2305" fOffsetY += CSwitchHeight+1;\n"
2306" }\n"
2307" var MaxDepth = 1;\n"
2308" var StackPos = 0;\n"
2309" var Stack = Array(20);\n"
2310" var Lod = LodData[LodIndex];\n"
2311"\n"
2312" var TypeArray = Lod.TypeArray[nLog];\n"
2313" var IndexArray = Lod.IndexArray[nLog];\n"
2314" var TimeArray = Lod.TimeArray[nLog];\n"
2315"\n"
2316" var LocalFirstFrame = Frames[FirstFrame].FirstFrameIndex[nLog];\n"
2317" var IndexStart = Lod.LogStart[LocalFirstFrame][nLog];\n"
2318" var IndexEnd = TimeArray.length;\n"
2319" IndexEnd = TimeArray.length;\n"
2320" var HasSetHover = 0;\n"
2321"\n"
2322"\n"
2323" for(var j = IndexStart; j < IndexEnd; ++j)\n"
2324" {\n"
2325" var type = TypeArray[j];\n"
2326" var index = IndexArray[j];\n"
2327" var time = TimeArray[j];\n"
2328" if(type == 1)\n"
2329" {\n"
2330" //push\n"
2331" Stack[StackPos] = j;\n"
2332" StackPos++;\n"
2333" if(StackPos > MaxDepth)\n"
2334" {\n"
2335" MaxDepth = StackPos;\n"
2336" }\n"
2337" }\n"
2338" else if(type == 0)\n"
2339" {\n"
2340" if(StackPos>0)\n"
2341" {\n"
2342" StackPos--;\n"
2343"\n"
2344" var StartIndex = Stack[StackPos];\n"
2345" var timestart = TimeArray[StartIndex];\n"
2346" var timeend = time;\n"
2347" var X = (timestart - fDetailedOffset) * fScaleX;\n"
2348" var Y = fOffsetY + StackPos * BoxHeight;\n"
2349" var W = (timeend-timestart)*fScaleX;\n"
2350"\n"
2351" if(W > MinWidth && X < nWidth && X+W > 0)\n"
2352" {\n"
2353" if(bDrawEnabled || index == nHoverToken)\n"
2354" {\n"
2355" Batches[index].push(X);\n"
2356" Batches[index].push(Y);\n"
2357" Batches[index].push(W);\n"
2358" DebugDrawQuadCount++;\n"
2359"\n"
2360" var XText = X < 0 ? 0 : X;\n"
2361" var WText = W - (XText-X);\n"
2362" if(XText + WText > nWidth)\n"
2363" {\n"
2364" WText = nWidth - XText;\n"
2365" }\n"
2366" var Name = TimerInfo[index].name;\n"
2367" var NameLen = TimerInfo[index].len;\n"
2368" var BarTextLen = Math.floor((WText-2)/FontWidth);\n"
2369" var TimeText = TimeToMsString(timeend-timestart);\n"
2370" var TimeTextLen = TimeText.length;\n"
2371"\n"
2372" if(BarTextLen >= 2)\n"
2373" {\n"
2374" if(BarTextLen < NameLen)\n"
2375" Name = Name.substr(0, BarTextLen);\n"
2376" var txtidx = TimerInfo[index].textcolorindex;\n"
2377" var YPos = Y+BoxHeight-FontAscent;\n"
2378" BatchesTxt[txtidx].push(Name);\n"
2379" BatchesTxtPos[txtidx].push(XText+2);\n"
2380"\n"
2381" BatchesTxtPos[txtidx].push(YPos);\n"
2382" DebugDrawTextCount++;\n"
2383" if(BarTextLen - NameLen > TimeTextLen)\n"
2384" {\n"
2385" BatchesTxt[txtidx].push(TimeText);\n"
2386" BatchesTxtPos[txtidx].push(XText+WText-2 - TimeTextLen * FontWidth);\n"
2387" BatchesTxtPos[txtidx].push(YPos);\n"
2388" DebugDrawTextCount++;\n"
2389" }\n"
2390"\n"
2391" }\n"
2392" }\n"
2393"\n"
2394" if(DetailedViewMouseX >= X && DetailedViewMouseX <= X+W && DetailedViewMouseY < Y+BoxHeight && DetailedViewMouseY >= Y)\n"
2395" {\n"
2396" fRangeBeginNext = timestart;\n"
2397" fRangeEndNext = timeend;\n"
2398" if(TypeArray[StartIndex+1] == 3 && TypeArray[j+1] == 3)\n"
2399" {\n"
2400" fRangeBeginGpuNext = fRangeBeginNext;\n"
2401" fRangeEndGpuNext = fRangeEndNext;\n"
2402" //cpu tick is stored following\n"
2403" fRangeBeginNext = TimeArray[StartIndex+1];\n"
2404" fRangeEndNext = TimeArray[j+1];\n"
2405" }\n"
2406" else\n"
2407" {\n"
2408" fRangeBeginGpuNext = -1;\n"
2409" fRangeEndGpuNext = -1;\n"
2410" }\n"
2411"\n"
2412" nHoverTokenNext = index;\n"
2413" nHoverTokenIndexNext = j;\n"
2414" nHoverTokenLogIndexNext = nLog;\n"
2415" bHasSetHover = 1;\n"
2416" }\n"
2417" }\n"
2418" if(StackPos == 0 && time > fTimeEnd)\n"
2419" break; \n"
2420" }\n"
2421" }\n"
2422" }\n"
2423" fOffsetY += (1+g_MaxStack[nLog]) * BoxHeight;\n"
2424"\n"
2425" if(HasSetHover)\n"
2426" {\n"
2427" for(var i = 0; i < Frames.length-1; ++i)\n"
2428" {\n"
2429" var IndexStart = Lod.LogStart[i][nLog];\n"
2430" if(nHoverTokenNext >= IndexStart)\n"
2431" {\n"
2432" nHoverFrame = i;\n"
2433" }\n"
2434" }\n"
2435" }\n"
2436" }\n"
2437" }\n"
2438"\n"
2439" if(nContextSwitchEnabled) //non instrumented threads.\n"
2440" {\n"
2441" var ContextSwitchThreads = CSwitchOnlyThreads;\n"
2442" for(var i = 0; i < ContextSwitchThreads.length; ++i)\n"
2443" {\n"
2444" var ThreadId = ContextSwitchThreads[i];\n"
2445" var ThreadName = \'\' + ThreadId;\n"
2446" DrawContextSwitchBars(context, ThreadId, fScaleX, fOffsetY, fDetailedOffset, nHoverColor, MinWidth, bDrawEnabled);\n"
2447" context.fillStyle = \'white\';\n"
2448" context.fillText(ThreadName, 0, fOffsetY+5);\n"
2449" fOffsetY += BoxHeight + 1;\n"
2450" }\n"
2451" }\n"
2452"\n"
2453"\n"
2454" {\n"
2455" for(var i = 0; i < Batches.length; ++i)\n"
2456" {\n"
2457" var a = Batches[i];\n"
2458" if(a.length)\n"
2459" {\n"
2460" context.fillStyle = TimerInfo[i].colordark;\n"
2461" if(!DisableMerge)\n"
2462" {\n"
2463" for(var j = 0; j < a.length; j += 3)\n"
2464" { \n"
2465" var X = a[j];\n"
2466" var Y = a[j+1];\n"
2467" var BaseWidth = j + 2;\n"
2468" var W = a[BaseWidth];\n"
2469" while(j+1 < a.length && W < 1)\n"
2470" {\n"
2471" var jnext = j+3;\n"
2472" var XNext = a[jnext];\n"
2473" var YNext = a[jnext+1];\n"
2474" var WNext = a[jnext+2];\n"
2475" var Delta = XNext - (X+W);\n"
2476" var YDelta = Math.abs(Y - YNext); \n"
2477" if(Delta < 0.3 && YDelta < 0.5 && WNext < 1)\n"
2478" {\n"
2479" W = (XNext+WNext) - X;\n"
2480" a[BaseWidth] = W;\n"
2481" a[jnext+2] = 0;\n"
2482" j += 3;\n"
2483" }\n"
2484" else\n"
2485" {\n"
2486" break;\n"
2487" }\n"
2488"\n"
2489" }\n"
2490" }\n"
2491" }\n"
2492" var off = 0.7;\n"
2493" var off2 = 2*off;\n"
2494" context.fillStyle = TimerInfo[i].colordark;\n"
2495" for(var j = 0; j < a.length; j += 3)\n"
2496" { \n"
2497" var X = a[j];\n"
2498" var Y = a[j+1];\n"
2499" var W = a[j+2];\n"
2500" if(W >= 1)\n"
2501" {\n"
2502" context.fillRect(X, Y, W, BoxHeight-1);\n"
2503" }\n"
2504" }\n"
2505" \n"
2506"\n"
2507" if(i == nHoverToken)\n"
2508" {\n"
2509" context.fillStyle = nHoverColor;\n"
2510" }\n"
2511" else\n"
2512" {\n"
2513" context.fillStyle = TimerInfo[i].color;\n"
2514" }\n"
2515" for(var j = 0; j < a.length; j += 3)\n"
2516" { \n"
2517" var X = a[j];\n"
2518" var Y = a[j+1];\n"
2519" var W = a[j+2];\n"
2520" if(W > 0)\n"
2521" {\n"
2522" context.fillRect(X+off, Y+off, W-off2, BoxHeight-1-off2);\n"
2523" }\n"
2524" }\n"
2525" }\n"
2526" } \n"
2527" }\n"
2528" for(var i = 0; i < BatchesTxt.length; ++i)\n"
2529" {\n"
2530" context.fillStyle = BatchesTxtColor[i];\n"
2531" var TxtArray = BatchesTxt[i];\n"
2532" var PosArray = BatchesTxtPos[i];\n"
2533" for(var j = 0; j < TxtArray.length; ++j)\n"
2534" {\n"
2535" var k = j * 2;\n"
2536" context.fillText(TxtArray[j], PosArray[k],PosArray[k+1]);\n"
2537" }\n"
2538" }\n"
2539"\n"
2540" }\n"
2541"}\n"
2542"function DrawTextBox(context, text, x, y, align)\n"
2543"{\n"
2544" var textsize = context.measureText(text).width;\n"
2545" var offsetx = 0;\n"
2546" var offsety = -FontHeight;\n"
2547" if(align == \'center\')\n"
2548" {\n"
2549" offsetx = -textsize / 2.0;\n"
2550" }\n"
2551" else if(align == \'right\')\n"
2552" {\n"
2553" offsetx = -textsize;\n"
2554" }\n"
2555" context.fillStyle = nBackColors[0];\n"
2556" context.fillRect(x + offsetx, y + offsety, textsize+2, FontHeight + 2);\n"
2557" context.fillStyle = \'white\';\n"
2558" context.fillText(text, x, y);\n"
2559"\n"
2560"}\n"
2561"function DrawRange(context, fBegin, fEnd, ColorBack, ColorFront, Offset, Name)\n"
2562"{\n"
2563" if(fBegin < fEnd)\n"
2564" {\n"
2565" var fScaleX = nWidth / fDetailedRange; \n"
2566" var X = (fBegin - fDetailedOffset) * fScaleX;\n"
2567" var YSpace = (FontHeight+2);\n"
2568" var Y = YSpace * (Offset);\n"
2569" var W = (fEnd - fBegin) * fScaleX;\n"
2570" context.globalAlpha = 0.1;\n"
2571" context.fillStyle = ColorBack;\n"
2572" context.fillRect(X, 0, W, nHeight);\n"
2573" context.globalAlpha = 1;\n"
2574" context.strokeStyle = ColorFront;\n"
2575" context.beginPath();\n"
2576" context.moveTo(X, 0);\n"
2577" context.lineTo(X, nHeight);\n"
2578" context.moveTo(X+W, 0);\n"
2579" context.lineTo(X+W, nHeight);\n"
2580" context.stroke();\n"
2581" var Duration = (fEnd - fBegin).toFixed(2) + \"ms\";\n"
2582" var Center = ((fBegin + fEnd) / 2.0) - fDetailedOffset;\n"
2583" var DurationWidth = context.measureText(Duration+ \" \").width;\n"
2584"\n"
2585" context.fillStyle = \'white\';\n"
2586" context.textAlign = \'right\';\n"
2587" var TextPosY = Y + YSpace;\n"
2588" DrawTextBox(context, \'\' + fBegin.toFixed(2), X-3, TextPosY, \'right\');\n"
2589" if(DurationWidth < W + 10)\n"
2590" {\n"
2591" context.textAlign = \'center\';\n"
2592" DrawTextBox(context,\'\' + Duration,Center * fScaleX, TextPosY, \'center\');\n"
2593"\n"
2594" var W0 = W - DurationWidth + FontWidth*1.5;\n"
2595" if(W0 > 6)\n"
2596" {\n"
2597" var Y0 = Y + FontHeight * 0.5;\n"
2598" W0 = W0 / 2.0;\n"
2599" var X0 = X + W0;\n"
2600" var X1 = X + W - W0;\n"
2601" context.strokeStyle = ColorFront;\n"
2602" context.beginPath();\n"
2603" context.moveTo(X, Y0);\n"
2604" context.lineTo(X0, Y0);\n"
2605" context.moveTo(X0, Y0-2);\n"
2606" context.lineTo(X0, Y0+2);\n"
2607" context.moveTo(X1, Y0-2);\n"
2608" context.lineTo(X1, Y0+2);\n"
2609" context.moveTo(X1, Y0);\n"
2610" context.lineTo(X + W, Y0);\n"
2611" context.stroke();\n"
2612" }\n"
2613" }\n"
2614" context.textAlign = \'left\';\n"
2615" DrawTextBox(context, \'\' + fEnd.toFixed(2), X + W + 2, TextPosY, \'left\');\n"
2616" DrawTextBox(context, Name, X + W + 2, nHeight - FontHeight - YSpace*Offset, \'left\');\n"
2617" Offset += 1;\n"
2618" }\n"
2619" return Offset;\n"
2620"}\n"
2621"\n"
2622"function DrawDetailed(Animation)\n"
2623"{\n"
2624" if(AnimationActive != Animation || !Initialized)\n"
2625" {\n"
2626" return;\n"
2627" }\n"
2628" ProfileEnter(\"DrawDetailed\");\n"
2629" DebugDrawQuadCount = 0;\n"
2630" DebugDrawTextCount = 0;\n"
2631" nHoverCSCpuNext = -1;\n"
2632"\n"
2633" fRangeBeginNext = fRangeEndNext = -1;\n"
2634" fRangeBeginGpuNext = fRangeEndGpuNext = -1;\n"
2635" var fRangeBeginGpu = -1;\n"
2636" var fRangeEndGpu = -1;\n"
2637"\n"
2638" var start = new Date();\n"
2639" nDrawCount++;\n"
2640"\n"
2641" var context = CanvasDetailedView.getContext(\'2d\');\n"
2642" var offscreen = CanvasDetailedOffscreen.getContext(\'2d\');\n"
2643" var fScaleX = nWidth / fDetailedRange; \n"
2644" var fOffsetY = -nOffsetY + BoxHeight;\n"
2645"\n"
2646" if(DetailedRedrawState.fOffsetY == fOffsetY && DetailedRedrawState.fDetailedOffset == fDetailedOffset && DetailedRedrawState.fDetailedRange == fDetailedRange && !KeyCtrlDown && !KeyShiftDown && !MouseDragButton)\n"
2647" {\n"
2648" Invalidate++;\n"
2649" }\n"
2650" else\n"
2651" {\n"
2652" Invalidate = 0;\n"
2653" DetailedRedrawState.fOffsetY = fOffsetY;\n"
2654" DetailedRedrawState.fDetailedOffset = fDetailedOffset;\n"
2655" DetailedRedrawState.fDetailedRange = fDetailedRange;\n"
2656" }\n"
2657" if(Invalidate == 0) //when panning, only draw bars that are a certain width to keep decent framerate\n"
2658" {\n"
2659" context.clearRect(0, 0, CanvasDetailedView.width, CanvasDetailedView.height);\n"
2660" DrawDetailedView(context, nMinWidthPan, true);\n"
2661" }\n"
2662" else if(Invalidate == 1) //draw full and store\n"
2663" {\n"
2664" offscreen.clearRect(0, 0, CanvasDetailedView.width, CanvasDetailedView.height);\n"
2665" DrawDetailedView(offscreen, nMinWidth, true);\n"
2666" OffscreenData = offscreen.getImageData(0, 0, CanvasDetailedOffscreen.width, CanvasDetailedOffscreen.height);\n"
2667" }\n"
2668" else//reuse stored result untill next time viewport is changed.\n"
2669" {\n"
2670" context.clearRect(0, 0, CanvasDetailedView.width, CanvasDetailedView.height);\n"
2671" context.putImageData(OffscreenData, 0, 0);\n"
2672" DrawDetailedView(context, nMinWidth, false);\n"
2673" }\n"
2674"\n"
2675" if(KeyShiftDown || KeyCtrlDown || MouseDragButton || MouseDragSelectRange())\n"
2676" {\n"
2677" nHoverToken = -1;\n"
2678" nHoverTokenIndex = -1;\n"
2679" nHoverTokenLogIndex = -1;\n"
2680" fRangeBegin = fRangeEnd = -1;\n"
2681" }\n"
2682" else\n"
2683" {\n"
2684" nHoverToken = nHoverTokenNext;\n"
2685" nHoverTokenIndex = nHoverTokenIndexNext;\n"
2686" nHoverTokenLogIndex = nHoverTokenLogIndexNext;\n"
2687" if(fRangeBeginHistory < fRangeEndHistory)\n"
2688" {\n"
2689" fRangeBegin = fRangeBeginHistory;\n"
2690" fRangeEnd = fRangeEndHistory;\n"
2691" fRangeBeginGpu = fRangeBeginHistoryGpu;\n"
2692" fRangeEndGpu = fRangeEndHistoryGpu;\n"
2693" }\n"
2694" else\n"
2695" {\n"
2696" fRangeBegin = fRangeBeginNext;\n"
2697" fRangeEnd = fRangeEndNext;\n"
2698" fRangeBeginGpu = fRangeBeginGpuNext;\n"
2699" fRangeEndGpu = fRangeEndGpuNext;\n"
2700" }\n"
2701" }\n"
2702"\n"
2703" DrawTextBox(context, TimeToMsString(fDetailedOffset), 0, FontHeight, \'left\');\n"
2704" context.textAlign = \'right\';\n"
2705" DrawTextBox(context, TimeToMsString(fDetailedOffset + fDetailedRange), nWidth, FontHeight, \'right\');\n"
2706" context.textAlign = \'left\';\n"
2707"\n"
2708" var Offset = 0;\n"
2709" Offset = DrawRange(context, fRangeBeginSelect, fRangeEndSelect, \'#59d0ff\', \'#00ddff\', Offset, \"Selection\");\n"
2710" Offset = DrawRange(context, fRangeBegin, fRangeEnd, \'#009900\', \'#00ff00\', Offset, \"Cpu\");\n"
2711" Offset = DrawRange(context, fRangeBeginGpu, fRangeEndGpu, \'#996600\', \'#775500\', Offset, \"Gpu\");\n"
2712"\n"
2713" nHoverCSCpu = nHoverCSCpuNext;\n"
2714" ProfileLeave();\n"
2715"}\n"
2716"\n"
2717"function ZoomTo(fZoomBegin, fZoomEnd)\n"
2718"{\n"
2719" if(fZoomBegin < fZoomEnd)\n"
2720" {\n"
2721" AnimationActive = true;\n"
2722" var fDetailedOffsetOriginal = fDetailedOffset;\n"
2723" var fDetailedRangeOriginal = fDetailedRange;\n"
2724" var fDetailedOffsetTarget = fZoomBegin;\n"
2725" var fDetailedRangeTarget = fZoomEnd - fZoomBegin;\n"
2726" var TimestampStart = new Date();\n"
2727" var count = 0;\n"
2728" function ZoomFunc(Timestamp)\n"
2729" {\n"
2730" var fPrc = (new Date() - TimestampStart) / (ZOOM_TIME * 1000.0);\n"
2731" if(fPrc > 1.0)\n"
2732" {\n"
2733" fPrc = 1.0;\n"
2734" }\n"
2735" fPrc = Math.pow(fPrc, 0.3);\n"
2736" fDetailedOffset = fDetailedOffsetOriginal + (fDetailedOffsetTarget - fDetailedOffsetOriginal) * fPrc;\n"
2737" fDetailedRange = fDetailedRangeOriginal + (fDetailedRangeTarget - fDetailedRangeOriginal) * fPrc;\n"
2738" DrawDetailed(true);\n"
2739" if(fPrc >= 1.0)\n"
2740" {\n"
2741" AnimationActive = false;\n"
2742" fDetailedOffset = fDetailedOffsetTarget;\n"
2743" fDetailedRange = fDetailedRangeTarget;\n"
2744" }\n"
2745" else\n"
2746" {\n"
2747" requestAnimationFrame(ZoomFunc);\n"
2748" }\n"
2749" }\n"
2750" requestAnimationFrame(ZoomFunc);\n"
2751" }\n"
2752"}\n"
2753"function RequestRedraw()\n"
2754"{\n"
2755" Invalidate = 0;\n"
2756" Draw(1);\n"
2757"}\n"
2758"function Draw(RedrawMode)\n"
2759"{\n"
2760" if(ProfileMode)\n"
2761" {\n"
2762" ProfileModeClear();\n"
2763" ProfileEnter(\"Total\");\n"
2764" }\n"
2765" if(RedrawMode == 1)\n"
2766" {\n"
2767" if(Mode == ModeTimers)\n"
2768" {\n"
2769" DrawBarView();\n"
2770" DrawHoverToolTip();\n"
2771" }\n"
2772" else if(Mode == ModeDetailed)\n"
2773" {\n"
2774" DrawDetailed(false);\n"
2775" DrawHoverToolTip();\n"
2776" }\n"
2777" }\n"
2778" DrawDetailedFrameHistory();\n"
2779"\n"
2780" if(ProfileMode)\n"
2781" {\n"
2782" ProfileLeave();\n"
2783" ProfileModeDraw(CanvasDetailedView);\n"
2784" }\n"
2785"}\n"
2786"\n"
2787"function AutoRedraw(Timestamp)\n"
2788"{\n"
2789" var RedrawMode = 0;\n"
2790" if(Mode == ModeDetailed)\n"
2791" {\n"
2792" if(ProfileMode == 2 || ((nHoverCSCpu >= 0 || nHoverToken != -1) && !KeyCtrlDown && !KeyShiftDown && !MouseDragButton)||(Invalidate<2 && !KeyCtrlDown && !KeyShiftDown && !MouseDragButton))\n"
2793" {\n"
2794" RedrawMode = 1;\n"
2795" }\n"
2796" }\n"
2797" else\n"
2798" {\n"
2799" if(Invalidate < 1)\n"
2800" {\n"
2801" RedrawMode = 1;\n"
2802" }\n"
2803" }\n"
2804" if(RedrawMode)\n"
2805" {\n"
2806" Draw(RedrawMode);\n"
2807" }\n"
2808" else if(FlashFrameCounter>0)\n"
2809" {\n"
2810" Draw(0);\n"
2811" }\n"
2812" requestAnimationFrame(AutoRedraw);\n"
2813"}\n"
2814"\n"
2815"\n"
2816"function ZoomGraph(nZoom)\n"
2817"{\n"
2818" var fOldRange = fDetailedRange;\n"
2819" if(nZoom>0)\n"
2820" {\n"
2821" fDetailedRange *= Math.pow(nModDown ? 1.40 : 1.03, nZoom);\n"
2822" }\n"
2823" else\n"
2824" {\n"
2825" var fNewDetailedRange = fDetailedRange / Math.pow((nModDown ? 1.40 : 1.03), -nZoom);\n"
2826" if(fNewDetailedRange < 0.0001) //100ns\n"
2827" fNewDetailedRange = 0.0001;\n"
2828" fDetailedRange = fNewDetailedRange;\n"
2829" }\n"
2830"\n"
2831" var fDiff = fOldRange - fDetailedRange;\n"
2832" var fMousePrc = DetailedViewMouseX / nWidth;\n"
2833" if(fMousePrc < 0)\n"
2834" {\n"
2835" fMousePrc = 0;\n"
2836" }\n"
2837" fDetailedOffset += fDiff * fMousePrc;\n"
2838"\n"
2839"}\n"
2840"\n"
2841"function MeasureFont()\n"
2842"{\n"
2843" var context = CanvasDetailedView.getContext(\'2d\');\n"
2844" context.font = Font;\n"
2845" FontWidth = context.measureText(\'W\').width;\n"
2846"\n"
2847"}\n"
2848"function ResizeCanvas() \n"
2849"{\n"
2850" nWidth = window.innerWidth;\n"
2851" nHeight = window.innerHeight - CanvasHistory.height-2;\n"
2852" DPR = window.devicePixelRatio;\n"
2853"\n"
2854" if(DPR)\n"
2855" {\n"
2856" CanvasDetailedView.style.width = nWidth + \'px\'; \n"
2857" CanvasDetailedView.style.height = nHeight + \'px\';\n"
2858" CanvasDetailedView.width = nWidth * DPR;\n"
2859" CanvasDetailedView.height = nHeight * DPR;\n"
2860" CanvasHistory.style.width = window.innerWidth + \'px\';\n"
2861" CanvasHistory.style.height = 70 + \'px\';\n"
2862" CanvasHistory.width = window.innerWidth * DPR;\n"
2863" CanvasHistory.height = 70 * DPR;\n"
2864" CanvasHistory.getContext(\'2d\').scale(DPR,DPR);\n"
2865" CanvasDetailedView.getContext(\'2d\').scale(DPR,DPR);\n"
2866"\n"
2867" CanvasDetailedOffscreen.style.width = nWidth + \'px\';\n"
2868" CanvasDetailedOffscreen.style.height = nHeight + \'px\';\n"
2869" CanvasDetailedOffscreen.wid";
2870
2871const size_t g_MicroProfileHtml_end_1_size = sizeof(g_MicroProfileHtml_end_1);
2872const char g_MicroProfileHtml_end_2[] =
2873"th = nWidth * DPR;\n"
2874" CanvasDetailedOffscreen.height = nHeight * DPR;\n"
2875" CanvasDetailedOffscreen.getContext(\'2d\').scale(DPR,DPR);\n"
2876"\n"
2877" }\n"
2878" else\n"
2879" {\n"
2880" DPR = 1;\n"
2881" CanvasDetailedView.width = nWidth;\n"
2882" CanvasDetailedView.height = nHeight;\n"
2883" CanvasDetailedOffscreen.width = nWidth;\n"
2884" CanvasDetailedOffscreen.height = nHeight;\n"
2885" CanvasHistory.width = window.innerWidth;\n"
2886" }\n"
2887" RequestRedraw();\n"
2888"}\n"
2889"\n"
2890"var MouseDragOff = 0;\n"
2891"var MouseDragDown = 1;\n"
2892"var MouseDragUp = 2;\n"
2893"var MouseDragMove = 3;\n"
2894"var MouseDragState = MouseDragOff;\n"
2895"var MouseDragTarget = 0;\n"
2896"var MouseDragButton = 0;\n"
2897"var MouseDragKeyShift = 0;\n"
2898"var MouseDragKeyCtrl = 0;\n"
2899"var MouseDragX = 0;\n"
2900"var MouseDragY = 0;\n"
2901"var MouseDragXLast = 0;\n"
2902"var MouseDragYLast = 0;\n"
2903"var MouseDragXStart = 0;\n"
2904"var MouseDragYStart = 0;\n"
2905"\n"
2906"function clamp(number, min, max)\n"
2907"{\n"
2908" return Math.max(min, Math.min(number, max));\n"
2909"}\n"
2910"\n"
2911"function MouseDragPan()\n"
2912"{\n"
2913" return MouseDragButton == 1 || MouseDragKeyShift;\n"
2914"}\n"
2915"function MouseDragSelectRange()\n"
2916"{\n"
2917" return MouseDragState == MouseDragMove && (MouseDragButton == 3 || (MouseDragKeyShift && MouseDragKeyCtrl));\n"
2918"}\n"
2919"function MouseHandleDrag()\n"
2920"{\n"
2921" if(MouseDragTarget == CanvasDetailedView)\n"
2922" {\n"
2923" if(Mode == ModeDetailed)\n"
2924" {\n"
2925" if(MouseDragSelectRange())\n"
2926" {\n"
2927" var xStart = MouseDragXStart;\n"
2928" var xEnd = MouseDragX;\n"
2929" if(xStart > xEnd)\n"
2930" {\n"
2931" var Temp = xStart;\n"
2932" xStart = xEnd;\n"
2933" xEnd = Temp;\n"
2934" }\n"
2935" if(xEnd - xStart > 1)\n"
2936" {\n"
2937" fRangeBegin = fDetailedOffset + fDetailedRange * (xStart / nWidth);\n"
2938" fRangeEnd = fDetailedOffset + fDetailedRange * (xEnd / nWidth);\n"
2939" fRangeBeginSelect = fDetailedOffset + fDetailedRange * (xStart / nWidth);\n"
2940" fRangeEndSelect = fDetailedOffset + fDetailedRange * (xEnd / nWidth);\n"
2941" }\n"
2942" }\n"
2943" else if(MouseDragPan())\n"
2944" {\n"
2945" var X = MouseDragX - MouseDragXLast;\n"
2946" var Y = MouseDragY - MouseDragYLast;\n"
2947" if(X)\n"
2948" {\n"
2949" fDetailedOffset += -X * fDetailedRange / nWidth;\n"
2950" }\n"
2951" nOffsetY -= Y;\n"
2952" if(nOffsetY < 0)\n"
2953" {\n"
2954" nOffsetY = 0;\n"
2955" }\n"
2956" }\n"
2957" else if(MouseDragKeyCtrl)\n"
2958" {\n"
2959" if(MouseDragY != MouseDragYLast)\n"
2960" {\n"
2961" ZoomGraph(MouseDragY - MouseDragYLast);\n"
2962" }\n"
2963" }\n"
2964" }\n"
2965" else if(Mode == ModeTimers)\n"
2966" {\n"
2967" if(MouseDragKeyShift || MouseDragButton == 1)\n"
2968" {\n"
2969" var X = MouseDragX - MouseDragXLast;\n"
2970" var Y = MouseDragY - MouseDragYLast;\n"
2971" nOffsetBarsY -= Y;\n"
2972" nOffsetBarsX -= X;\n"
2973" if(nOffsetBarsY < 0)\n"
2974" {\n"
2975" nOffsetBarsY = 0;\n"
2976" }\n"
2977" if(nOffsetBarsX < 0)\n"
2978" {\n"
2979" nOffsetBarsX = 0;\n"
2980" }\n"
2981" }\n"
2982"\n"
2983" }\n"
2984"\n"
2985" }\n"
2986" else if(MouseDragTarget == CanvasHistory)\n"
2987" {\n"
2988" function HistoryFrameTime(x)\n"
2989" {\n"
2990" var NumFrames = Frames.length;\n"
2991" var fBarWidth = nWidth / NumFrames;\n"
2992" var Index = clamp(Math.floor(NumFrames * x / nWidth), 0, NumFrames-1);\n"
2993" var Lerp = clamp((x/fBarWidth - Index) , 0, 1);\n"
2994" var time = Frames[Index].framestart + (Frames[Index].frameend - Frames[Index].framestart) * Lerp;\n"
2995" return time;\n"
2996" }\n"
2997" if(MouseDragSelectRange())\n"
2998" {\n"
2999" fRangeBegin = fRangeEnd = -1;\n"
3000"\n"
3001" var xStart = MouseDragXStart;\n"
3002" var xEnd = MouseDragX;\n"
3003" if(xStart > xEnd)\n"
3004" {\n"
3005" var Temp = xStart;\n"
3006" xStart = xEnd;\n"
3007" xEnd = Temp;\n"
3008" }\n"
3009" if(xEnd - xStart > 2)\n"
3010" {\n"
3011" var timestart = HistoryFrameTime(xStart);\n"
3012" var timeend = HistoryFrameTime(xEnd);\n"
3013" fDetailedOffset = timestart;\n"
3014" fDetailedRange = timeend-timestart;\n"
3015" }\n"
3016" }\n"
3017" else if(MouseDragPan())\n"
3018" {\n"
3019" var Time = HistoryFrameTime(MouseDragX);\n"
3020" fDetailedOffset = Time - fDetailedRange / 2.0;\n"
3021" }\n"
3022" }\n"
3023"}\n"
3024"function MouseHandleDragEnd()\n"
3025"{\n"
3026" if(MouseDragTarget == CanvasDetailedView)\n"
3027" {\n"
3028"\n"
3029" }\n"
3030" else if(MouseDragTarget == CanvasHistory)\n"
3031" {\n"
3032" if(!MouseDragSelectRange() && !MouseDragPan())\n"
3033" {\n"
3034" ZoomTo(fRangeBegin, fRangeEnd);\n"
3035" fRangeBegin = fRangeEnd = -1;\n"
3036" }\n"
3037"\n"
3038"\n"
3039" }\n"
3040"\n"
3041"}\n"
3042"\n"
3043"function MouseHandleDragClick()\n"
3044"{\n"
3045" if(MouseDragTarget == CanvasDetailedView)\n"
3046" {\n"
3047" ZoomTo(fRangeBegin, fRangeEnd);\n"
3048" }\n"
3049" else if(MouseDragTarget == CanvasHistory)\n"
3050" {\n"
3051" if(Mode == ModeDetailed)\n"
3052" {\n"
3053" ZoomTo(fRangeBegin, fRangeEnd);\n"
3054" }\n"
3055" }\n"
3056"}\n"
3057"\n"
3058"function MapMouseButton(Event)\n"
3059"{\n"
3060" if(event.button == 1 || event.which == 1)\n"
3061" {\n"
3062" return 1;\n"
3063" }\n"
3064" else if(event.button == 3 || event.which == 3)\n"
3065" {\n"
3066" return 3;\n"
3067" }\n"
3068" else\n"
3069" {\n"
3070" return 0;\n"
3071" }\n"
3072"}\n"
3073"\n"
3074"function MouseDragReset()\n"
3075"{\n"
3076" MouseDragState = MouseDragOff;\n"
3077" MouseDragTarget = 0;\n"
3078" MouseDragKeyShift = 0;\n"
3079" MouseDragKeyCtrl = 0;\n"
3080" MouseDragButton = 0;\n"
3081"}\n"
3082"function MouseDragKeyUp()\n"
3083"{\n"
3084" if((MouseDragKeyShift && !KeyShiftDown) || (MouseDragKeyCtrl && !KeyCtrlDown))\n"
3085" {\n"
3086" MouseHandleDragEnd();\n"
3087" MouseDragReset();\n"
3088" }\n"
3089"}\n"
3090"function MouseDrag(Source, Event)\n"
3091"{\n"
3092" if(Source == MouseDragOff || (MouseDragTarget && MouseDragTarget != Event.target))\n"
3093" {\n"
3094" MouseDragReset();\n"
3095" return;\n"
3096" }\n"
3097"\n"
3098" var LocalRect = Event.target.getBoundingClientRect();\n"
3099" MouseDragX = Event.clientX - LocalRect.left;\n"
3100" MouseDragY = Event.clientY - LocalRect.top;\n"
3101" // console.log(\'cur drag state \' + MouseDragState + \' Source \' + Source);\n"
3102" if(MouseDragState == MouseDragMove)\n"
3103" {\n"
3104" var dx = Math.abs(MouseDragX - MouseDragXStart);\n"
3105" var dy = Math.abs(MouseDragY - MouseDragYStart);\n"
3106" if((Source == MouseDragUp && MapMouseButton(Event) == MouseDragButton) ||\n"
3107" (MouseDragKeyCtrl && !KeyCtrlDown) ||\n"
3108" (MouseDragKeyShift && !KeyShiftDown))\n"
3109" {\n"
3110" MouseHandleDragEnd();\n"
3111" MouseDragReset();\n"
3112" return;\n"
3113" }\n"
3114" else\n"
3115" {\n"
3116" MouseHandleDrag();\n"
3117" }\n"
3118" }\n"
3119" else if(MouseDragState == MouseDragOff)\n"
3120" {\n"
3121" if(Source == MouseDragDown || KeyShiftDown || KeyCtrlDown)\n"
3122" {\n"
3123" MouseDragTarget = Event.target;\n"
3124" MouseDragButton = MapMouseButton(Event);\n"
3125" MouseDragState = MouseDragDown;\n"
3126" MouseDragXStart = MouseDragX;\n"
3127" MouseDragYStart = MouseDragY;\n"
3128" MouseDragKeyCtrl = 0;\n"
3129" MouseDragKeyShift = 0;\n"
3130"\n"
3131" if(KeyShiftDown || KeyCtrlDown)\n"
3132" {\n"
3133" MouseDragKeyShift = KeyShiftDown;\n"
3134" MouseDragKeyCtrl = KeyCtrlDown;\n"
3135" MouseDragState = MouseDragMove;\n"
3136" }\n"
3137" }\n"
3138" }\n"
3139" else if(MouseDragState == MouseDragDown)\n"
3140" {\n"
3141" if(Source == MouseDragUp)\n"
3142" {\n"
3143" MouseHandleDragClick();\n"
3144" MouseDragReset();\n"
3145" }\n"
3146" else if(Source == MouseDragMove)\n"
3147" {\n"
3148" var dx = Math.abs(MouseDragX - MouseDragXStart);\n"
3149" var dy = Math.abs(MouseDragY - MouseDragYStart);\n"
3150" if(dx+dy>1)\n"
3151" {\n"
3152" MouseDragState = MouseDragMove;\n"
3153" }\n"
3154" }\n"
3155" }\n"
3156" MouseDragXLast = MouseDragX;\n"
3157" MouseDragYLast = MouseDragY;\n"
3158"}\n"
3159"\n"
3160"function MouseMove(evt)\n"
3161"{\n"
3162" evt.preventDefault();\n"
3163" MouseDrag(MouseDragMove, evt);\n"
3164" MouseHistory = 0;\n"
3165" MouseDetailed = 0;\n"
3166" HistoryViewMouseX = HistoryViewMouseY = -1;\n"
3167" var rect = evt.target.getBoundingClientRect();\n"
3168" var x = evt.clientX - rect.left;\n"
3169" var y = evt.clientY - rect.top;\n"
3170" if(evt.target == CanvasDetailedView)\n"
3171" {\n"
3172" if(!MouseDragSelectRange())\n"
3173" {\n"
3174" fRangeBegin = fRangeEnd = -1;\n"
3175" }\n"
3176" DetailedViewMouseX = x;\n"
3177" DetailedViewMouseY = y;\n"
3178" }\n"
3179" else if(evt.target = CanvasHistory)\n"
3180" {\n"
3181" var Rect = CanvasHistory.getBoundingClientRect();\n"
3182" HistoryViewMouseX = x;\n"
3183" HistoryViewMouseY = y;\n"
3184" }\n"
3185" Draw(1);\n"
3186"}\n"
3187"\n"
3188"function MouseButton(bPressed, evt)\n"
3189"{\n"
3190" evt.preventDefault();\n"
3191" MouseDrag(bPressed ? MouseDragDown : MouseDragUp, evt);\n"
3192"}\n"
3193"\n"
3194"function MouseOut(evt)\n"
3195"{\n"
3196" MouseDrag(MouseDragOff, evt);\n"
3197" KeyCtrlDown = 0;\n"
3198" KeyShiftDown = 0;\n"
3199" MouseDragButton = 0;\n"
3200" nHoverToken = -1;\n"
3201" fRangeBegin = fRangeEnd = -1;\n"
3202"}\n"
3203"\n"
3204"function MouseWheel(e)\n"
3205"{\n"
3206" var e = window.event || e;\n"
3207" var delta = (e.wheelDelta || e.detail * (-120));\n"
3208" ZoomGraph((-4 * delta / 120.0) | 0);\n"
3209" Draw(1);\n"
3210"}\n"
3211"\n"
3212"\n"
3213"function KeyUp(evt)\n"
3214"{\n"
3215" if(evt.keyCode == 17)\n"
3216" {\n"
3217" KeyCtrlDown = 0;\n"
3218" MouseDragKeyUp();\n"
3219" }\n"
3220" else if(evt.keyCode == 16)\n"
3221" {\n"
3222" KeyShiftDown = 0;\n"
3223" MouseDragKeyUp();\n"
3224" }\n"
3225" if(evt.keyCode == 18)\n"
3226" {\n"
3227" FlipToolTip = 0;\n"
3228" }\n"
3229" if(evt.keyCode == 32)\n"
3230" {\n"
3231" if(fRangeBeginSelect < fRangeEndSelect)\n"
3232" {\n"
3233" ZoomTo(fRangeBeginSelect, fRangeEndSelect);\n"
3234" fRangeBeginSelect = fRangeEndSelect = -1;\n"
3235" MouseHandleDragEnd();\n"
3236" }\n"
3237" }\n"
3238" if(evt.keyCode == 27)\n"
3239" {\n"
3240" fRangeBeginSelect = fRangeEndSelect = -1; \n"
3241" }\n"
3242" Invalidate = 0;\n"
3243"}\n"
3244"\n"
3245"function KeyDown(evt)\n"
3246"{\n"
3247" if(evt.keyCode == 18)\n"
3248" {\n"
3249" FlipToolTip = 1;\n"
3250" }\n"
3251" if(evt.keyCode == 17)\n"
3252" {\n"
3253" KeyCtrlDown = 1;\n"
3254" }\n"
3255" else if(evt.keyCode == 16)\n"
3256" {\n"
3257" KeyShiftDown = 1;\n"
3258" }\n"
3259" Invalidate = 0;\n"
3260"}\n"
3261"\n"
3262"function ReadCookie()\n"
3263"{\n"
3264" var result = document.cookie.match(/fisk=([^;]+)/);\n"
3265" var NewMode = ModeDetailed;\n"
3266" var ReferenceTimeString = \'33ms\';\n"
3267" if(result && result.length > 0)\n"
3268" {\n"
3269" var Obj = JSON.parse(result[1]);\n"
3270" if(Obj.Mode)\n"
3271" {\n"
3272" NewMode = Obj.Mode;\n"
3273" }\n"
3274" if(Obj.ReferenceTime)\n"
3275" {\n"
3276" ReferenceTimeString = Obj.ReferenceTime;\n"
3277" }\n"
3278" if(Obj.ThreadsAllActive || Obj.ThreadsAllActive == 0 || Obj.ThreadsAllActive == false)\n"
3279" {\n"
3280" ThreadsAllActive = Obj.ThreadsAllActive;\n"
3281" }\n"
3282" else\n"
3283" {\n"
3284" ThreadsAllActive = 1;\n"
3285" }\n"
3286" if(Obj.ThreadsActive)\n"
3287" {\n"
3288" ThreadsActive = Obj.ThreadsActive;\n"
3289" }\n"
3290" if(Obj.GroupsAllActive || Obj.GroupsAllActive == 0 || Obj.GroupsAllActive)\n"
3291" {\n"
3292" GroupsAllActive = Obj.GroupsAllActive;\n"
3293" }\n"
3294" else\n"
3295" {\n"
3296" GroupsAllActive = 1;\n"
3297" }\n"
3298" if(Obj.GroupsActive)\n"
3299" {\n"
3300" GroupsActive = Obj.GroupsActive;\n"
3301" }\n"
3302" if(Obj.nContextSwitchEnabled)\n"
3303" {\n"
3304" nContextSwitchEnabled = Obj.nContextSwitchEnabled; \n"
3305" }\n"
3306" else\n"
3307" {\n"
3308" nContextSwitchEnabled = 1;\n"
3309" }\n"
3310" if(Obj.GroupColors)\n"
3311" {\n"
3312" GroupColors = Obj.GroupColors;\n"
3313" }\n"
3314" else\n"
3315" {\n"
3316" GroupColors = 0;\n"
3317" }\n"
3318" if(Obj.nHideHelp)\n"
3319" {\n"
3320" nHideHelp = 1;\n"
3321" }\n"
3322" TimersGroups = Obj.TimersGroups?Obj.TimersGroups:0;\n"
3323" TimersMeta = Obj.TimersMeta?0:1;\n"
3324" }\n"
3325" SetContextSwitch(nContextSwitchEnabled);\n"
3326" SetMode(NewMode, TimersGroups);\n"
3327" SetReferenceTime(ReferenceTimeString);\n"
3328" UpdateOptionsMenu();\n"
3329" UpdateGroupColors();\n"
3330"}\n"
3331"function WriteCookie()\n"
3332"{\n"
3333" var Obj = new Object();\n"
3334" Obj.Mode = Mode;\n"
3335" Obj.ReferenceTime = ReferenceTime + \'ms\';\n"
3336" Obj.ThreadsActive = ThreadsActive;\n"
3337" Obj.ThreadsAllActive = ThreadsAllActive;\n"
3338" Obj.GroupsActive = GroupsActive;\n"
3339" Obj.GroupsAllActive = GroupsAllActive;\n"
3340" Obj.nContextSwitchEnabled = nContextSwitchEnabled;\n"
3341" Obj.TimersGroups = TimersGroups?TimersGroups:0;\n"
3342" Obj.TimersMeta = TimersMeta?0:1;\n"
3343" Obj.GroupColors = GroupColors;\n"
3344" if(nHideHelp)\n"
3345" {\n"
3346" Obj.nHideHelp = 1;\n"
3347" }\n"
3348" var date = new Date();\n"
3349" date.setFullYear(2099);\n"
3350" var cookie = \'fisk=\' + JSON.stringify(Obj) + \';expires=\' + date;\n"
3351" document.cookie = cookie;\n"
3352"}\n"
3353"\n"
3354"var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? \"DOMMouseScroll\" : \"mousewheel\" //FF doesn\'t recognize mousewheel as of FF3.x\n"
3355"\n"
3356"CanvasDetailedView.addEventListener(\'mousemove\', MouseMove, false);\n"
3357"CanvasDetailedView.addEventListener(\'mousedown\', function(evt) { MouseButton(true, evt); });\n"
3358"CanvasDetailedView.addEventListener(\'mouseup\', function(evt) { MouseButton(false, evt); } );\n"
3359"CanvasDetailedView.addEventListener(\'mouseout\', MouseOut);\n"
3360"CanvasDetailedView.addEventListener(\"contextmenu\", function (e) { e.preventDefault(); }, false);\n"
3361"CanvasDetailedView.addEventListener(mousewheelevt, MouseWheel, false);\n"
3362"CanvasHistory.addEventListener(\'mousemove\', MouseMove);\n"
3363"CanvasHistory.addEventListener(\'mousedown\', function(evt) { MouseButton(true, evt); });\n"
3364"CanvasHistory.addEventListener(\'mouseup\', function(evt) { MouseButton(false, evt); } );\n"
3365"CanvasHistory.addEventListener(\'mouseout\', MouseOut);\n"
3366"CanvasHistory.addEventListener(\"contextmenu\", function (e) { e.preventDefault(); }, false);\n"
3367"CanvasHistory.addEventListener(mousewheelevt, MouseWheel, false);\n"
3368"window.addEventListener(\'keydown\', KeyDown);\n"
3369"window.addEventListener(\'keyup\', KeyUp);\n"
3370"window.addEventListener(\'resize\', ResizeCanvas, false);\n"
3371"\n"
3372"function CalcAverage()\n"
3373"{\n"
3374" var Sum = 0;\n"
3375" var Count = 0;\n"
3376" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
3377" {\n"
3378" StackPos = 0;\n"
3379" for(var i = 0; i < Frames.length; i++)\n"
3380" {\n"
3381" var Frame_ = Frames[i]; \n"
3382" var tt = Frame_.tt[nLog];\n"
3383" var ts = Frame_.ts[nLog];\n"
3384"\n"
3385" var count = tt.length;\n"
3386" for(var j = 0; j < count; j++)\n"
3387" {\n"
3388" var type = tt[j];\n"
3389" var time = ts[j];\n"
3390" if(type == 1)\n"
3391" {\n"
3392" Stack[StackPos] = time;//store the frame which it comes from\n"
3393" StackPos++;\n"
3394" }\n"
3395" else if(type == 0)\n"
3396" {\n"
3397" if(StackPos>0)\n"
3398" {\n"
3399"\n"
3400" StackPos--;\n"
3401" var localtime = time - Stack[StackPos];\n"
3402" Count++;\n"
3403" Sum += localtime;\n"
3404" }\n"
3405" }\n"
3406" }\n"
3407" }\n"
3408" }\n"
3409" return Sum / Count;\n"
3410"\n"
3411"}\n"
3412"\n"
3413"function MakeLod(index, MinDelta, TimeArray, TypeArray, IndexArray, LogStart)\n"
3414"{\n"
3415" if(LodData[index])\n"
3416" {\n"
3417" console.log(\"error!!\");\n"
3418" }\n"
3419" // debugger;\n"
3420" var o = new Object();\n"
3421" o.MinDelta = MinDelta;\n"
3422" o.TimeArray = TimeArray;\n"
3423" o.TypeArray = TypeArray;\n"
3424" o.IndexArray = IndexArray;\n"
3425" o.LogStart = LogStart;\n"
3426" LodData[index] = o;\n"
3427"}\n"
3428"\n"
3429"function PreprocessBuildSplitArray()\n"
3430"{\n"
3431" var nNumLogs = Frames[0].ts.length;\n"
3432"\n"
3433" ProfileEnter(\"PreprocessBuildSplitArray\");\n"
3434" var SplitArrays = new Array(nNumLogs);\n"
3435"\n"
3436" for(nLog = 0; nLog < nNumLogs; ++nLog)\n"
3437" {\n"
3438" console.log(\"source log \" + nLog + \" size \" + LodData[0].TypeArray[nLog].length);\n"
3439" }\n"
3440"\n"
3441"\n"
3442" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
3443" {\n"
3444" var MaxDepth = 1;\n"
3445" var StackPos = 0;\n"
3446" var Stack = Array(20);\n"
3447" var TypeArray = LodData[0].TypeArray[nLog];\n"
3448" var TimeArray = LodData[0].TimeArray[nLog];\n"
3449" var DeltaTimes = new Array(TypeArray.length);\n"
3450"\n"
3451" for(var j = 0; j < TypeArray.length; ++j)\n"
3452" {\n"
3453" var type = TypeArray[j];\n"
3454" var time = TimeArray[j];\n"
3455" if(type == 1)\n"
3456" {\n"
3457" //push\n"
3458" Stack[StackPos] = time;\n"
3459" StackPos++;\n"
3460" }\n"
3461" else if(type == 0)\n"
3462" {\n"
3463" if(StackPos>0)\n"
3464" {\n"
3465" StackPos--;\n"
3466" DeltaTimes[j] = time - Stack[StackPos];\n"
3467" }\n"
3468" else\n"
3469" {\n"
3470" DeltaTimes[j] = 0;\n"
3471" }\n"
3472" }\n"
3473" }\n"
3474" DeltaTimes.sort(function(a,b){return b-a;});\n"
3475" var SplitArray = Array(NumLodSplits);\n"
3476" var SplitIndex = DeltaTimes.length;\n"
3477"\n"
3478" var j = 0;\n"
3479" for(j = 0; j < NumLodSplits; ++j)\n"
3480" {\n"
3481" SplitIndex = Math.floor(SplitIndex / 2);\n"
3482" while(SplitIndex > 0 && !DeltaTimes[SplitIndex])\n"
3483" {\n"
3484" SplitIndex--;\n"
3485" }\n"
3486" if(SplitIndex < SplitMin)\n"
3487" {\n"
3488" break;\n"
3489" }\n"
3490" //search.. if 0\n"
3491" var SplitTime = DeltaTimes[SplitIndex];\n"
3492" if(SplitTime>=0)\n"
3493" {\n"
3494" SplitArray[j] = SplitTime;\n"
3495" }\n"
3496" else\n"
3497" {\n"
3498" SplitArray[j] = SPLIT_LIMIT;\n"
3499" }\n"
3500" if(j>0)\n"
3501" {\n"
3502" console.assert(SplitArray[j-1] <= SplitArray[j], \"must be less\");\n"
3503" }\n"
3504"\n"
3505" }\n"
3506" for(; j < NumLodSplits; ++j)\n"
3507" {\n"
3508" SplitArray[j] = SPLIT_LIMIT;\n"
3509" // console.log(\"split skipping \" + j + \" \" + SPLIT_LIMIT);\n"
3510" }\n"
3511"\n"
3512"\n"
3513" SplitArrays[nLog] = SplitArray;\n"
3514" }\n"
3515" ProfileLeave();\n"
3516" return SplitArrays;\n"
3517"}\n"
3518"\n"
3519"function PreprocessBuildDurationArray()\n"
3520"{\n"
3521" var nNumLogs = Frames[0].ts.length;\n"
3522" ProfileEnter(\"PreprocessBuildDurationArray\");\n"
3523" var DurationArrays = new Array(nNumLogs);\n"
3524" for(nLog = 0; nLog < nNumLogs; ++nLog)\n"
3525" {\n"
3526" var MaxDepth = 1;\n"
3527" var StackPos = 0;\n"
3528" var Stack = Array(20);\n"
3529" var StackIndex = Array(20);\n"
3530" var TypeArray = LodData[0].TypeArray[nLog];\n"
3531" var TimeArray = LodData[0].TimeArray[nLog];\n"
3532" var DurationArray = Array(LodData[0].TypeArray[nLog].length);\n"
3533" for(var j = 0; j < TypeArray.length; ++j)\n"
3534" {\n"
3535" var type = TypeArray[j];\n"
3536" var time = TimeArray[j];\n"
3537" if(type == 1)\n"
3538" {\n"
3539" //push\n"
3540" Stack[StackPos] = time;\n"
3541" StackIndex[StackPos] = j;\n"
3542" StackPos++;\n"
3543" }\n"
3544" else if(type == 0)\n"
3545" {\n"
3546" if(StackPos>0)\n"
3547" {\n"
3548" StackPos--;\n"
3549" var Duration = time - Stack[StackPos];\n"
3550" DurationArray[StackIndex[StackPos]] = Duration;\n"
3551" DurationArray[j] = Duration;\n"
3552" }\n"
3553" else\n"
3554" {\n"
3555" DurationArray[j] = 0;\n"
3556" }\n"
3557" }\n"
3558" }\n"
3559" for(var j = 0; j < StackPos; ++j)\n"
3560" {\n"
3561" DurationArray[j] = 0;\n"
3562" }\n"
3563" DurationArrays[nLog] = DurationArray;\n"
3564" }\n"
3565" ProfileLeave();\n"
3566" return DurationArrays;\n"
3567"\n"
3568"}\n"
3569"function PreprocessLods()\n"
3570"{\n"
3571" ProfileEnter(\"PreprocessLods\");\n"
3572" var nNumLogs = Frames[0].ts.length;\n"
3573" var SplitArrays = PreprocessBuildSplitArray();\n"
3574" var DurationArrays = PreprocessBuildDurationArray();\n"
3575" var Source = LodData[0];\n"
3576" var SourceLogStart = Source.LogStart;\n"
3577" var NumFrames = SourceLogStart.length;\n"
3578"\n"
3579" for(var i = 0; i < NumLodSplits-1; ++i)\n"
3580" {\n"
3581" var DestLogStart = Array(SourceLogStart.length);\n"
3582" for(var j = 0; j < DestLogStart.length; ++j)\n"
3583" {\n"
3584" DestLogStart[j] = Array(nNumLogs);\n"
3585" }\n"
3586" var MinDelta = Array(nNumLogs);\n"
3587" var TimeArray = Array(nNumLogs);\n"
3588" var IndexArray = Array(nNumLogs);\n"
3589" var TypeArray = Array(nNumLogs);\n"
3590"\n"
3591"\n"
3592"\n"
3593" for(nLog = 0; nLog < nNumLogs; ++nLog)\n"
3594" {\n"
3595" var SourceTypeArray = Source.TypeArray[nLog];\n"
3596" var SourceTimeArray = Source.TimeArray[nLog];\n"
3597" var SourceIndexArray = Source.IndexArray[nLog];\n"
3598" var Duration = DurationArrays[nLog];\n"
3599" console.assert(Duration.length == SourceTypeArray.length, \"must be equal!\");\n"
3600" var SplitTime = SplitArrays[nLog][i];\n"
3601"\n"
3602" MinDelta[nLog] = SplitTime;\n"
3603" if(SplitTime < SPLIT_LIMIT)\n"
3604" {\n"
3605" var SourceCount = SourceTypeArray.length;\n"
3606" var DestTypeArray = Array();\n"
3607" var DestTimeArray = Array();\n"
3608" var DestIndexArray = Array();\n"
3609" var RemapArray = Array(SourceCount);\n"
3610" var DiscardLast = 0;\n"
3611"\n"
3612" for(var j = 0; j < SourceCount; ++j)\n"
3613" {\n"
3614" RemapArray[j] = DestTypeArray.length;\n"
3615" if(Duration[j] >= SplitTime || (SourceTypeArray[j] == 3 && 0 == DiscardLast))\n"
3616" {\n"
3617" DiscardLast = 0;\n"
3618" DestTypeArray.push(SourceTypeArray[j]);\n"
3619" DestTimeArray.push(SourceTimeArray[j]);\n"
3620" DestIndexArray.push(SourceIndexArray[j]);\n"
3621" }\n"
3622" else\n"
3623" {\n"
3624" DiscardLast = 1;\n"
3625" }\n"
3626" }\n"
3627" TimeArray[nLog] = DestTimeArray;\n"
3628" IndexArray[nLog] = DestIndexArray;\n"
3629" TypeArray[nLog] = DestTypeArray;\n"
3630" for(var j = 0; j < NumFrames; ++j)\n"
3631" {\n"
3632" var OldStart = SourceLogStart[j][nLog];\n"
3633" var NewStart = RemapArray[OldStart];\n"
3634" var FrameArray = DestLogStart[j];\n"
3635" FrameArray[nLog] = NewStart;\n"
3636" }\n"
3637" }\n"
3638" else\n"
3639" {\n"
3640"\n"
3641" for(var j = 0; j < NumFrames; ++j)\n"
3642" {\n"
3643" var FrameArray = DestLogStart[j];\n"
3644" \n"
3645" FrameArray[nLog] = 0;\n"
3646" }\n"
3647"\n"
3648" }\n"
3649"\n"
3650" }\n"
3651" MakeLod(i+1, MinDelta, TimeArray, TypeArray, IndexArray, DestLogStart);\n"
3652" }\n"
3653" ProfileLeave();\n"
3654"}\n"
3655"function PreprocessGlobalArray()\n"
3656"{\n"
3657" ProfileEnter(\"PreprocessGlobalArray\");\n"
3658" var nNumLogs = Frames[0].ts.length;\n"
3659" var CaptureStart = Frames[0].framestart;\n"
3660" var CaptureEnd = Frames[Frames.length-1].frameend;\n"
3661" g_TypeArray = new Array(nNumLogs);\n"
3662" g_TimeArray = new Array(nNumLogs);\n"
3663" g_IndexArray = new Array(nNumLogs);\n"
3664" var StackPos = 0;\n"
3665" var Stack = Array(20);\n"
3666" var LogStartArray = new Array(Frames.length);\n"
3667" for(var i = 0; i < Frames.length; i++)\n"
3668" {\n"
3669" Frames[i].LogStart = new Array(nNumLogs); \n"
3670" LogStartArray[i] = Frames[i].LogStart;\n"
3671"\n"
3672" Frames[i].LogEnd = new Array(nNumLogs);\n"
3673" }\n"
3674" var MinDelta = Array(nNumLogs);\n"
3675" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
3676" {\n"
3677" MinDelta[nLog] = 0;\n"
3678" var Discard = 0;\n"
3679" var TypeArray = new Array();\n"
3680" var TimeArray = new Array();\n"
3681" var IndexArray = new Array();\n"
3682" for(var i = 0; i < Frames.length; i++)\n"
3683" {\n"
3684" var Frame_ = Frames[i]; \n"
3685" Frame_.LogStart[nLog] = TimeArray.length;\n"
3686" var FrameDiscard = Frame_.frameend + 33;//if timestamps are more than 33ms after current frame, we assume buffer has wrapped.\n"
3687" var tt = Frame_.tt[nLog];\n"
3688" var ts = Frame_.ts[nLog];\n"
3689" var ti = Frame_.ti[nLog];\n"
3690" var len = tt.length;\n"
3691" var DiscardLast = 0;\n"
3692" for(var xx = 0; xx < len; ++xx)\n"
3693" {\n"
3694" var Skip = (tt[i] == 3) ? DiscardLast : ts[xx] > FrameDiscard;\n"
3695" if(Skip)\n"
3696" {\n"
3697" Discard++;\n"
3698" DiscardLast = 1;\n"
3699" }\n"
3700" else\n"
3701" {\n"
3702" DiscardLast = 0;\n"
3703" TypeArray.push(tt[xx]);\n"
3704" TimeArray.push(ts[xx]);\n"
3705" IndexArray.push(ti[xx]);\n"
3706" }\n"
3707" }\n"
3708" Frame_.LogEnd[nLog] = TimeArray.length;\n"
3709" }\n"
3710" g_TypeArray[nLog] = TypeArray;\n"
3711" g_TimeArray[nLog] = TimeArray;\n"
3712" g_IndexArray[nLog] = IndexArray;\n"
3713" if(Discard)\n"
3714" {\n"
3715" console.log(\'discarded \' + Discard + \' markers from \' + ThreadNames[nLog]);\n"
3716" }\n"
3717" }\n"
3718" MakeLod(0, MinDelta, g_TimeArray, g_TypeArray, g_IndexArray, LogStartArray);\n"
3719" ProfileLeave();\n"
3720"}\n"
3721"\n"
3722"function PreprocessFindFirstFrames()\n"
3723"{\n"
3724" ProfileEnter(\"PreprocesFindFirstFrames\");\n"
3725" //create arrays that show how far back we need to start search in order to get all markers.\n"
3726" var nNumLogs = Frames[0].ts.length;\n"
3727" for(var i = 0; i < Frames.length; i++)\n"
3728" {\n"
3729" Frames[i].FirstFrameIndex = new Array(nNumLogs);\n"
3730" }\n"
3731"\n"
3732" var StackPos = 0;\n"
3733" var Stack = Array(20);\n"
3734" g_MaxStack = Array(nNumLogs);\n"
3735" \n"
3736" for(nLog = 0; nLog < nNumLogs; nLog++)\n"
3737" {\n"
3738" var MaxStack = 0;\n"
3739" StackPos = 0;\n"
3740" for(var i = 0; i < Frames.length; i++)\n"
3741" {\n"
3742" var Frame_ = Frames[i]; \n"
3743" var tt = Frame_.tt[nLog];\n"
3744" var count = tt.length;\n"
3745"\n"
3746" var FirstFrame = i;\n"
3747" if(StackPos>0)\n"
3748" {\n"
3749" FirstFrame = Stack[0];\n"
3750" }\n"
3751" Frames[i].FirstFrameIndex[nLog] = FirstFrame;\n"
3752"\n"
3753" for(var j = 0; j < count; j++)\n"
3754" {\n"
3755" var type = tt[j];\n"
3756" if(type == 1)\n"
3757" {\n"
3758" Stack[StackPos] = i;//store the frame which it comes from\n"
3759" StackPos++;\n"
3760" if(StackPos > MaxStack)\n"
3761" {\n"
3762" MaxStack = StackPos;\n"
3763" }\n"
3764" }\n"
3765" else if(type == 0)\n"
3766" {\n"
3767" if(StackPos>0)\n"
3768" {\n"
3769" StackPos--;\n"
3770" }\n"
3771" }\n"
3772" }\n"
3773" }\n"
3774" g_MaxStack[nLog] = MaxStack;\n"
3775" }\n"
3776" ProfileLeave();\n"
3777"}\n"
3778"function PreprocessMeta()\n"
3779"{\n"
3780" MetaLengths = Array(MetaNames.length);\n"
3781" MetaLengthsAvg = Array(MetaNames.length);\n"
3782" MetaLengthsMax = Array(MetaNames.length);\n"
3783" for(var i = 0; i < MetaNames.length; ++i)\n"
3784" {\n"
3785" MetaLengths[i] = MetaNames[i].length+1;\n"
3786" MetaLengthsAvg[i] = MetaNames[i].length+5;\n"
3787" MetaLengthsMax[i] = MetaNames[i].length+5;\n"
3788" if(MetaLengths[i]<12)\n"
3789" MetaLengths[i] = 12;\n"
3790" if(MetaLengthsAvg[i]<12)\n"
3791" MetaLengthsAvg[i] = 12;\n"
3792" if(MetaLengthsMax[i]<12)\n"
3793" MetaLengthsMax[i] = 12;\n"
3794" }\n"
3795" for(var i = 0; i < TimerInfo.length; ++i)\n"
3796" {\n"
3797" var Timer = TimerInfo[i];\n"
3798" for(var j = 0; j < MetaNames.length; ++j)\n"
3799" {\n"
3800" var Len = FormatMeta(Timer.meta[j],0).length + 2;\n"
3801" var LenAvg = FormatMeta(Timer.meta[j],2).length + 2;\n"
3802" var LenMax = FormatMeta(Timer.meta[j],0).length + 2;\n"
3803" if(Len > MetaLengths[j])\n"
3804" {\n"
3805" MetaLengths[j] = Len;\n"
3806" }\n"
3807" if(LenAvg > MetaLengthsAvg[j])\n"
3808" {\n"
3809" MetaLengthsAvg[j] = LenAvg;\n"
3810" }\n"
3811" if(LenMax > MetaLengthsMax[j])\n"
3812" {\n"
3813" MetaLengthsMax[j] = LenMax;\n"
3814" }\n"
3815" }\n"
3816" }\n"
3817"}\n"
3818"\n"
3819"function Preprocess()\n"
3820"{\n"
3821" var ProfileModeOld = ProfileMode;\n"
3822" ProfileMode = 1;\n"
3823" ProfileModeClear();\n"
3824" ProfileEnter(\"Preprocess\");\n"
3825" PreprocessCalculateAllTimers();\n"
3826" PreprocessFindFirstFrames();\n"
3827" PreprocessGlobalArray();\n"
3828" PreprocessLods();\n"
3829" PreprocessMeta();\n"
3830" PreprocessContextSwitchCache();\n"
3831" ProfileLeave();\n"
3832" ProfileModeDump();\n"
3833" ProfileMode = ProfileModeOld;\n"
3834" Initialized = 1;\n"
3835"}\n"
3836"\n"
3837"InitGroups();\n"
3838"ReadCookie();\n"
3839"MeasureFont()\n"
3840"InitThreadMenu();\n"
3841"InitGroupMenu();\n"
3842"InitFrameInfo();\n"
3843"UpdateThreadMenu();\n"
3844"ResizeCanvas();\n"
3845"Preprocess();\n"
3846"OnPageReady();\n"
3847"Draw(1);\n"
3848"AutoRedraw();\n"
3849"\n"
3850"</script>\n"
3851"</body>\n"
3852"</html> ";
3853
3854const size_t g_MicroProfileHtml_end_2_size = sizeof(g_MicroProfileHtml_end_2);
3855const char* g_MicroProfileHtml_end[] = {
3856&g_MicroProfileHtml_end_0[0],
3857&g_MicroProfileHtml_end_1[0],
3858&g_MicroProfileHtml_end_2[0],
3859};
3860size_t g_MicroProfileHtml_end_sizes[] = {
3861sizeof(g_MicroProfileHtml_end_0),
3862sizeof(g_MicroProfileHtml_end_1),
3863sizeof(g_MicroProfileHtml_end_2),
3864};
3865size_t g_MicroProfileHtml_end_count = 3;
3866#endif //MICROPROFILE_EMBED_HTML
3867
3868///end file generated from microprofile.html
diff --git a/externals/microprofile/microprofileui.h b/externals/microprofile/microprofileui.h
new file mode 100644
index 000000000..eac1119a4
--- /dev/null
+++ b/externals/microprofile/microprofileui.h
@@ -0,0 +1,3348 @@
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
29#ifndef MICROPROFILE_ENABLED
30#error "microprofile.h must be included before including microprofileui.h"
31#endif
32
33#ifndef MICROPROFILEUI_ENABLED
34#define MICROPROFILEUI_ENABLED MICROPROFILE_ENABLED
35#endif
36
37#ifndef MICROPROFILEUI_API
38#define MICROPROFILEUI_API
39#endif
40
41
42#if 0 == MICROPROFILEUI_ENABLED
43#define MicroProfileMouseButton(foo, bar) do{}while(0)
44#define MicroProfileMousePosition(foo, bar, z) do{}while(0)
45#define MicroProfileModKey(key) do{}while(0)
46#define MicroProfileDraw(foo, bar) do{}while(0)
47#define MicroProfileIsDrawing() 0
48#define MicroProfileToggleDisplayMode() do{}while(0)
49#define MicroProfileSetDisplayMode(f) do{}while(0)
50#else
51
52#ifndef MICROPROFILE_DRAWCURSOR
53#define MICROPROFILE_DRAWCURSOR 0
54#endif
55
56#ifndef MICROPROFILE_DETAILED_BAR_NAMES
57#define MICROPROFILE_DETAILED_BAR_NAMES 1
58#endif
59
60#ifndef MICROPROFILE_TEXT_WIDTH
61#define MICROPROFILE_TEXT_WIDTH 5
62#endif
63
64#ifndef MICROPROFILE_TEXT_HEIGHT
65#define MICROPROFILE_TEXT_HEIGHT 8
66#endif
67
68#ifndef MICROPROFILE_DETAILED_BAR_HEIGHT
69#define MICROPROFILE_DETAILED_BAR_HEIGHT 12
70#endif
71
72#ifndef MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT
73#define MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT 7
74#endif
75
76#ifndef MICROPROFILE_GRAPH_WIDTH
77#define MICROPROFILE_GRAPH_WIDTH 256
78#endif
79
80#ifndef MICROPROFILE_GRAPH_HEIGHT
81#define MICROPROFILE_GRAPH_HEIGHT 256
82#endif
83
84#ifndef MICROPROFILE_BORDER_SIZE
85#define MICROPROFILE_BORDER_SIZE 1
86#endif
87
88#ifndef MICROPROFILE_HELP_LEFT
89#define MICROPROFILE_HELP_LEFT "Left-Click"
90#endif
91
92#ifndef MICROPROFILE_HELP_ALT
93#define MICROPROFILE_HELP_ALT "Alt-Click"
94#endif
95
96#ifndef MICROPROFILE_HELP_MOD
97#define MICROPROFILE_HELP_MOD "Mod"
98#endif
99
100#ifndef MICROPROFILE_BAR_WIDTH
101#define MICROPROFILE_BAR_WIDTH 100
102#endif
103
104#ifndef MICROPROFILE_CUSTOM_MAX
105#define MICROPROFILE_CUSTOM_MAX 8
106#endif
107
108#ifndef MICROPROFILE_CUSTOM_MAX_TIMERS
109#define MICROPROFILE_CUSTOM_MAX_TIMERS 64
110#endif
111
112#ifndef MICROPROFILE_CUSTOM_PADDING
113#define MICROPROFILE_CUSTOM_PADDING 12
114#endif
115
116
117#define MICROPROFILE_FRAME_HISTORY_HEIGHT 50
118#define MICROPROFILE_FRAME_HISTORY_WIDTH 7
119#define MICROPROFILE_FRAME_HISTORY_COLOR_CPU 0xffff7f27 //255 127 39
120#define MICROPROFILE_FRAME_HISTORY_COLOR_GPU 0xff37a0ee //55 160 238
121#define MICROPROFILE_FRAME_HISTORY_COLOR_HIGHTLIGHT 0x7733bb44
122#define MICROPROFILE_FRAME_COLOR_HIGHTLIGHT 0x20009900
123#define MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU 0x20996600
124#define MICROPROFILE_NUM_FRAMES (MICROPROFILE_MAX_FRAME_HISTORY - (MICROPROFILE_GPU_FRAME_DELAY+1))
125
126#define MICROPROFILE_TOOLTIP_MAX_STRINGS (32 + MICROPROFILE_MAX_GROUPS*2)
127#define MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE (4*1024)
128#define MICROPROFILE_TOOLTIP_MAX_LOCKED 3
129
130
131enum
132{
133 MICROPROFILE_CUSTOM_BARS = 0x1,
134 MICROPROFILE_CUSTOM_BAR_SOURCE_MAX = 0x2,
135 MICROPROFILE_CUSTOM_BAR_SOURCE_AVG = 0,
136 MICROPROFILE_CUSTOM_STACK = 0x4,
137 MICROPROFILE_CUSTOM_STACK_SOURCE_MAX = 0x8,
138 MICROPROFILE_CUSTOM_STACK_SOURCE_AVG = 0,
139};
140
141
142MICROPROFILEUI_API void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight); //! call if drawing microprofilers
143MICROPROFILEUI_API bool MicroProfileIsDrawing();
144MICROPROFILEUI_API void MicroProfileToggleGraph(MicroProfileToken nToken);
145MICROPROFILEUI_API bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight);
146MICROPROFILEUI_API void MicroProfileToggleDisplayMode(); //switch between off, bars, detailed
147MICROPROFILEUI_API void MicroProfileSetDisplayMode(int); //switch between off, bars, detailed
148MICROPROFILEUI_API void MicroProfileClearGraph();
149MICROPROFILEUI_API void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta);
150MICROPROFILEUI_API void MicroProfileModKey(uint32_t nKeyState);
151MICROPROFILEUI_API void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight);
152MICROPROFILEUI_API void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor);
153MICROPROFILEUI_API void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor);
154MICROPROFILEUI_API void MicroProfileLoadPreset(const char* pSuffix);
155MICROPROFILEUI_API void MicroProfileSavePreset(const char* pSuffix);
156
157MICROPROFILEUI_API void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
158MICROPROFILEUI_API void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType = MicroProfileBoxTypeFlat);
159MICROPROFILEUI_API void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor);
160MICROPROFILEUI_API void MicroProfileDumpTimers();
161
162MICROPROFILEUI_API void MicroProfileInitUI();
163
164MICROPROFILEUI_API void MicroProfileCustomGroupToggle(const char* pCustomName);
165MICROPROFILEUI_API void MicroProfileCustomGroupEnable(const char* pCustomName);
166MICROPROFILEUI_API void MicroProfileCustomGroupEnable(uint32_t nIndex);
167MICROPROFILEUI_API void MicroProfileCustomGroupDisable();
168MICROPROFILEUI_API void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags);
169MICROPROFILEUI_API void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer);
170
171#ifdef MICROPROFILEUI_IMPL
172#ifdef _WIN32
173#define snprintf _snprintf
174#endif
175#include <stdlib.h>
176#include <stdarg.h>
177#include <math.h>
178#include <algorithm>
179
180MICROPROFILE_DEFINE(g_MicroProfileDetailed, "MicroProfile", "Detailed View", 0x8888000);
181MICROPROFILE_DEFINE(g_MicroProfileDrawGraph, "MicroProfile", "Draw Graph", 0xff44ee00);
182MICROPROFILE_DEFINE(g_MicroProfileDrawBarView, "MicroProfile", "DrawBarView", 0x00dd77);
183MICROPROFILE_DEFINE(g_MicroProfileDraw,"MicroProfile", "Draw", 0x737373);
184
185
186struct MicroProfileStringArray
187{
188 const char* ppStrings[MICROPROFILE_TOOLTIP_MAX_STRINGS];
189 char Buffer[MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE];
190 char* pBufferPos;
191 uint32_t nNumStrings;
192};
193
194struct MicroProfileGroupMenuItem
195{
196 uint32_t nIsCategory;
197 uint32_t nCategoryIndex;
198 uint32_t nIndex;
199 const char* pName;
200};
201
202struct MicroProfileCustom
203{
204 char pName[MICROPROFILE_NAME_MAX_LEN];
205 uint32_t nFlags;
206 uint32_t nAggregateFlip;
207 uint32_t nNumTimers;
208 uint32_t nMaxTimers;
209 uint64_t nGroupMask;
210 float fReference;
211 uint64_t* pTimers;
212};
213
214struct SOptionDesc
215{
216 SOptionDesc(){}
217 SOptionDesc(uint8_t nSubType, uint8_t nIndex, const char* fmt, ...):nSubType(nSubType), nIndex(nIndex)
218 {
219 va_list args;
220 va_start (args, fmt);
221 vsprintf(Text, fmt, args);
222 va_end(args);
223 }
224 char Text[32];
225 uint8_t nSubType;
226 uint8_t nIndex;
227 bool bSelected;
228};
229static uint32_t g_MicroProfileAggregatePresets[] = {0, 10, 20, 30, 60, 120};
230static float g_MicroProfileReferenceTimePresets[] = {5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
231static uint32_t g_MicroProfileOpacityPresets[] = {0x40, 0x80, 0xc0, 0xff};
232static const char* g_MicroProfilePresetNames[] =
233{
234 MICROPROFILE_DEFAULT_PRESET,
235 "Render",
236 "GPU",
237 "Lighting",
238 "AI",
239 "Visibility",
240 "Sound",
241};
242
243enum
244{
245 MICROPROFILE_NUM_REFERENCE_PRESETS = sizeof(g_MicroProfileReferenceTimePresets)/sizeof(g_MicroProfileReferenceTimePresets[0]),
246 MICROPROFILE_NUM_OPACITY_PRESETS = sizeof(g_MicroProfileOpacityPresets)/sizeof(g_MicroProfileOpacityPresets[0]),
247#if MICROPROFILE_CONTEXT_SWITCH_TRACE
248 MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 7,
249#else
250 MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 3,
251#endif
252};
253
254struct MicroProfileUI
255{
256 //menu/mouse over stuff
257 uint64_t nHoverToken;
258 int64_t nHoverTime;
259 int nHoverFrame;
260#if MICROPROFILE_DEBUG
261 uint64_t nHoverAddressEnter;
262 uint64_t nHoverAddressLeave;
263#endif
264
265 uint32_t nWidth;
266 uint32_t nHeight;
267
268
269 int nOffsetX;
270 int nOffsetY;
271 float fDetailedOffset; //display offset relative to start of latest displayable frame.
272 float fDetailedRange; //no. of ms to display
273 float fDetailedOffsetTarget;
274 float fDetailedRangeTarget;
275 uint32_t nOpacityBackground;
276 uint32_t nOpacityForeground;
277 bool bShowSpikes;
278
279
280
281 uint32_t nMouseX;
282 uint32_t nMouseY;
283 uint32_t nMouseDownX;
284 uint32_t nMouseDownY;
285 int nMouseWheelDelta;
286 uint32_t nMouseDownLeft;
287 uint32_t nMouseDownRight;
288 uint32_t nMouseLeft;
289 uint32_t nMouseRight;
290 uint32_t nMouseLeftMod;
291 uint32_t nMouseRightMod;
292 uint32_t nModDown;
293 uint32_t nActiveMenu;
294
295 MicroProfileLogEntry* pDisplayMouseOver;
296
297 int64_t nRangeBegin;
298 int64_t nRangeEnd;
299 int64_t nRangeBeginGpu;
300 int64_t nRangeEndGpu;
301 uint32_t nRangeBeginIndex;
302 uint32_t nRangeEndIndex;
303 MicroProfileThreadLog* pRangeLog;
304 uint32_t nHoverColor;
305 uint32_t nHoverColorShared;
306
307 MicroProfileStringArray LockedToolTips[MICROPROFILE_TOOLTIP_MAX_LOCKED];
308 uint32_t nLockedToolTipColor[MICROPROFILE_TOOLTIP_MAX_LOCKED];
309 int LockedToolTipFront;
310
311 MicroProfileGroupMenuItem GroupMenu[MICROPROFILE_MAX_GROUPS + MICROPROFILE_MAX_CATEGORIES];
312 uint32_t GroupMenuCount;
313
314
315 uint32_t nCustomActive;
316 uint32_t nCustomTimerCount;
317 uint32_t nCustomCount;
318 MicroProfileCustom Custom[MICROPROFILE_CUSTOM_MAX];
319 uint64_t CustomTimer[MICROPROFILE_CUSTOM_MAX_TIMERS];
320
321 SOptionDesc Options[MICROPROFILE_OPTION_SIZE];
322
323
324};
325
326MicroProfileUI g_MicroProfileUI;
327#define UI g_MicroProfileUI
328static uint32_t g_nMicroProfileBackColors[2] = { 0x474747, 0x313131 };
329#define MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS 16
330static uint32_t g_nMicroProfileContextSwitchThreadColors[MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS] = //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
331{
332 0x63607B,
333 0x755E2B,
334 0x326A55,
335 0x523135,
336 0x904F42,
337 0x87536B,
338 0x346875,
339 0x5E6046,
340 0x35404C,
341 0x224038,
342 0x413D1E,
343 0x5E3A26,
344 0x5D6161,
345 0x4C6234,
346 0x7D564F,
347 0x5C4352,
348};
349
350
351void MicroProfileInitUI()
352{
353 static bool bInitialized = false;
354 if(!bInitialized)
355 {
356 bInitialized = true;
357 memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
358 UI.nActiveMenu = (uint32_t)-1;
359 UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
360 UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
361
362 UI.nOpacityBackground = 0xff<<24;
363 UI.nOpacityForeground = 0xff<<24;
364
365 UI.bShowSpikes = false;
366
367 UI.nWidth = 100;
368 UI.nHeight = 100;
369
370 UI.nCustomActive = (uint32_t)-1;
371 UI.nCustomTimerCount = 0;
372 UI.nCustomCount = 0;
373
374 int nIndex = 0;
375 UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "Reference");
376 for(int i = 0; i < MICROPROFILE_NUM_REFERENCE_PRESETS; ++i)
377 {
378 UI.Options[nIndex++] = SOptionDesc(0, i, " %6.2fms", g_MicroProfileReferenceTimePresets[i]);
379 }
380 UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "BG Opacity");
381 for(int i = 0; i < MICROPROFILE_NUM_OPACITY_PRESETS; ++i)
382 {
383 UI.Options[nIndex++] = SOptionDesc(1, i, " %7d%%", (i+1)*25);
384 }
385 UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "FG Opacity");
386 for(int i = 0; i < MICROPROFILE_NUM_OPACITY_PRESETS; ++i)
387 {
388 UI.Options[nIndex++] = SOptionDesc(2, i, " %7d%%", (i+1)*25);
389 }
390 UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "Spike Display");
391 UI.Options[nIndex++] = SOptionDesc(3, 0, "%s", " Enable");
392
393#if MICROPROFILE_CONTEXT_SWITCH_TRACE
394 UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "CSwitch Trace");
395 UI.Options[nIndex++] = SOptionDesc(4, 0, "%s", " Enable");
396 UI.Options[nIndex++] = SOptionDesc(4, 1, "%s", " All Threads");
397 UI.Options[nIndex++] = SOptionDesc(4, 2, "%s", " No Bars");
398#endif
399 MP_ASSERT(nIndex == MICROPROFILE_OPTION_SIZE);
400 }
401}
402
403void MicroProfileSetDisplayMode(int nValue)
404{
405 MicroProfile& S = *MicroProfileGet();
406 nValue = nValue >= 0 && nValue < 4 ? nValue : S.nDisplay;
407 S.nDisplay = nValue;
408 UI.nOffsetY = 0;
409}
410
411void MicroProfileToggleDisplayMode()
412{
413 MicroProfile& S = *MicroProfileGet();
414 S.nDisplay = (S.nDisplay + 1) % 4;
415 UI.nOffsetY = 0;
416}
417
418
419void MicroProfileStringArrayClear(MicroProfileStringArray* pArray)
420{
421 pArray->nNumStrings = 0;
422 pArray->pBufferPos = &pArray->Buffer[0];
423}
424
425void MicroProfileStringArrayAddLiteral(MicroProfileStringArray* pArray, const char* pLiteral)
426{
427 MP_ASSERT(pArray->nNumStrings < MICROPROFILE_TOOLTIP_MAX_STRINGS);
428 pArray->ppStrings[pArray->nNumStrings++] = pLiteral;
429}
430
431void MicroProfileStringArrayFormat(MicroProfileStringArray* pArray, const char* fmt, ...)
432{
433 MP_ASSERT(pArray->nNumStrings < MICROPROFILE_TOOLTIP_MAX_STRINGS);
434 pArray->ppStrings[pArray->nNumStrings++] = pArray->pBufferPos;
435 va_list args;
436 va_start (args, fmt);
437 pArray->pBufferPos += 1 + vsprintf(pArray->pBufferPos, fmt, args);
438 va_end(args);
439 MP_ASSERT(pArray->pBufferPos < pArray->Buffer + MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE);
440}
441void MicroProfileStringArrayCopy(MicroProfileStringArray* pDest, MicroProfileStringArray* pSrc)
442{
443 memcpy(&pDest->ppStrings[0], &pSrc->ppStrings[0], sizeof(pDest->ppStrings));
444 memcpy(&pDest->Buffer[0], &pSrc->Buffer[0], sizeof(pDest->Buffer));
445 for(uint32_t i = 0; i < MICROPROFILE_TOOLTIP_MAX_STRINGS; ++i)
446 {
447 if(i < pSrc->nNumStrings)
448 {
449 if(pSrc->ppStrings[i] >= &pSrc->Buffer[0] && pSrc->ppStrings[i] < &pSrc->Buffer[0] + MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE)
450 {
451 pDest->ppStrings[i] += &pDest->Buffer[0] - &pSrc->Buffer[0];
452 }
453 }
454 }
455 pDest->nNumStrings = pSrc->nNumStrings;
456}
457
458void MicroProfileFloatWindowSize(const char** ppStrings, uint32_t nNumStrings, uint32_t* pColors, uint32_t& nWidth, uint32_t& nHeight, uint32_t* pStringLengths = 0)
459{
460 uint32_t* nStringLengths = pStringLengths ? pStringLengths : (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
461 uint32_t nTextCount = nNumStrings/2;
462 for(uint32_t i = 0; i < nTextCount; ++i)
463 {
464 uint32_t i0 = i * 2;
465 uint32_t s0, s1;
466 nStringLengths[i0] = s0 = (uint32_t)strlen(ppStrings[i0]);
467 nStringLengths[i0+1] = s1 = (uint32_t)strlen(ppStrings[i0+1]);
468 nWidth = MicroProfileMax(s0+s1, nWidth);
469 }
470 nWidth = (MICROPROFILE_TEXT_WIDTH+1) * (2+nWidth) + 2 * MICROPROFILE_BORDER_SIZE;
471 if(pColors)
472 nWidth += MICROPROFILE_TEXT_WIDTH + 1;
473 nHeight = (MICROPROFILE_TEXT_HEIGHT+1) * nTextCount + 2 * MICROPROFILE_BORDER_SIZE;
474}
475
476void MicroProfileDrawFloatWindow(uint32_t nX, uint32_t nY, const char** ppStrings, uint32_t nNumStrings, uint32_t nColor, uint32_t* pColors = 0)
477{
478 uint32_t nWidth = 0, nHeight = 0;
479 uint32_t* nStringLengths = (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
480 MicroProfileFloatWindowSize(ppStrings, nNumStrings, pColors, nWidth, nHeight, nStringLengths);
481 uint32_t nTextCount = nNumStrings/2;
482 if(nX + nWidth > UI.nWidth)
483 nX = UI.nWidth - nWidth;
484 if(nY + nHeight > UI.nHeight)
485 nY = UI.nHeight - nHeight;
486 MicroProfileDrawBox(nX-1, nY-1, nX + nWidth+1, nY + nHeight+1, 0xff000000|nColor);
487 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
488 if(pColors)
489 {
490 nX += MICROPROFILE_TEXT_WIDTH+1;
491 nWidth -= MICROPROFILE_TEXT_WIDTH+1;
492 }
493 for(uint32_t i = 0; i < nTextCount; ++i)
494 {
495 int i0 = i * 2;
496 if(pColors)
497 {
498 MicroProfileDrawBox(nX-MICROPROFILE_TEXT_WIDTH, nY, nX, nY + MICROPROFILE_TEXT_WIDTH, pColors[i]|0xff000000);
499 }
500 MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
501 MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, (uint32_t)-1, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
502 nY += (MICROPROFILE_TEXT_HEIGHT+1);
503 }
504}
505void MicroProfileDrawTextBox(uint32_t nX, uint32_t nY, const char** ppStrings, uint32_t nNumStrings, uint32_t nColor, uint32_t* pColors = 0)
506{
507 uint32_t nWidth = 0, nHeight = 0;
508 uint32_t* nStringLengths = (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
509 for(uint32_t i = 0; i < nNumStrings; ++i)
510 {
511 nStringLengths[i] = (uint32_t)strlen(ppStrings[i]);
512 nWidth = MicroProfileMax(nWidth, nStringLengths[i]);
513 nHeight++;
514 }
515 nWidth = (MICROPROFILE_TEXT_WIDTH+1) * (2+nWidth) + 2 * MICROPROFILE_BORDER_SIZE;
516 nHeight = (MICROPROFILE_TEXT_HEIGHT+1) * nHeight + 2 * MICROPROFILE_BORDER_SIZE;
517 if(nX + nWidth > UI.nWidth)
518 nX = UI.nWidth - nWidth;
519 if(nY + nHeight > UI.nHeight)
520 nY = UI.nHeight - nHeight;
521 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
522 for(uint32_t i = 0; i < nNumStrings; ++i)
523 {
524 MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
525 nY += (MICROPROFILE_TEXT_HEIGHT+1);
526 }
527}
528
529
530
531void MicroProfileToolTipMeta(MicroProfileStringArray* pToolTip)
532{
533 MicroProfile& S = *MicroProfileGet();
534 if(UI.nRangeBeginIndex != UI.nRangeEndIndex && UI.pRangeLog)
535 {
536 uint64_t nMetaSum[MICROPROFILE_META_MAX] = {0};
537 uint64_t nMetaSumInclusive[MICROPROFILE_META_MAX] = {0};
538 int nStackDepth = 0;
539 uint32_t nRange[2][2];
540 MicroProfileThreadLog* pLog = UI.pRangeLog;
541
542
543 MicroProfileGetRange(UI.nRangeEndIndex, UI.nRangeBeginIndex, nRange);
544 for(uint32_t i = 0; i < 2; ++i)
545 {
546 uint32_t nStart = nRange[i][0];
547 uint32_t nEnd = nRange[i][1];
548 for(uint32_t j = nStart; j < nEnd; ++j)
549 {
550 MicroProfileLogEntry LE = pLog->Log[j];
551 int nType = MicroProfileLogType(LE);
552 switch(nType)
553 {
554 case MP_LOG_META:
555 {
556 int64_t nMetaIndex = MicroProfileLogTimerIndex(LE);
557 int64_t nMetaCount = MicroProfileLogGetTick(LE);
558 MP_ASSERT(nMetaIndex < MICROPROFILE_META_MAX);
559 if(nStackDepth>1)
560 {
561 nMetaSumInclusive[nMetaIndex] += nMetaCount;
562 }
563 else
564 {
565 nMetaSum[nMetaIndex] += nMetaCount;
566 }
567 }
568 break;
569 case MP_LOG_LEAVE:
570 if(nStackDepth)
571 {
572 nStackDepth--;
573 }
574 else
575 {
576 for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
577 {
578 nMetaSumInclusive[i] += nMetaSum[i];
579 nMetaSum[i] = 0;
580 }
581 }
582 break;
583 case MP_LOG_ENTER:
584 nStackDepth++;
585 break;
586 }
587
588 }
589 }
590 bool bSpaced = false;
591 for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
592 {
593 if(S.MetaCounters[i].pName && (nMetaSum[i]||nMetaSumInclusive[i]))
594 {
595 if(!bSpaced)
596 {
597 bSpaced = true;
598 MicroProfileStringArrayAddLiteral(pToolTip, "");
599 MicroProfileStringArrayAddLiteral(pToolTip, "");
600 }
601 MicroProfileStringArrayFormat(pToolTip, "%s excl", S.MetaCounters[i].pName);
602 MicroProfileStringArrayFormat(pToolTip, "%5d", nMetaSum[i]);
603 MicroProfileStringArrayFormat(pToolTip, "%s incl", S.MetaCounters[i].pName);
604 MicroProfileStringArrayFormat(pToolTip, "%5d", nMetaSum[i] + nMetaSumInclusive[i]);
605 }
606 }
607 }
608}
609
610void MicroProfileDrawFloatTooltip(uint32_t nX, uint32_t nY, uint32_t nToken, uint64_t nTime)
611{
612 MicroProfile& S = *MicroProfileGet();
613
614 uint32_t nIndex = MicroProfileGetTimerIndex(nToken);
615 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
616 uint32_t nAggregateCount = S.Aggregate[nIndex].nCount ? S.Aggregate[nIndex].nCount : 1;
617
618 uint32_t nGroupId = MicroProfileGetGroupIndex(nToken);
619 uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
620 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
621
622 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
623
624 float fMs = fToMs * (nTime);
625 float fFrameMs = fToMs * (S.Frame[nIndex].nTicks);
626 float fAverage = fToMs * (S.Aggregate[nIndex].nTicks/nAggregateFrames);
627 float fCallAverage = fToMs * (S.Aggregate[nIndex].nTicks / nAggregateCount);
628 float fMax = fToMs * (S.AggregateMax[nIndex]);
629
630 float fFrameMsExclusive = fToMs * (S.FrameExclusive[nIndex]);
631 float fAverageExclusive = fToMs * (S.AggregateExclusive[nIndex]/nAggregateFrames);
632 float fMaxExclusive = fToMs * (S.AggregateMaxExclusive[nIndex]);
633
634 float fGroupAverage = fToMs * (S.AggregateGroup[nGroupId] / nAggregateFrames);
635 float fGroupMax = fToMs * (S.AggregateGroupMax[nGroupId]);
636 float fGroup = fToMs * (S.FrameGroup[nGroupId]);
637
638
639 MicroProfileStringArray ToolTip;
640 MicroProfileStringArrayClear(&ToolTip);
641 const char* pGroupName = S.GroupInfo[nGroupId].pName;
642 const char* pTimerName = S.TimerInfo[nTimerId].pName;
643 MicroProfileStringArrayAddLiteral(&ToolTip, "Timer:");
644 MicroProfileStringArrayFormat(&ToolTip, "%s", pTimerName);
645
646#if MICROPROFILE_DEBUG
647 MicroProfileStringArrayFormat(&ToolTip,"0x%p", UI.nHoverAddressEnter);
648 MicroProfileStringArrayFormat(&ToolTip,"0x%p", UI.nHoverAddressLeave);
649#endif
650
651 if(nTime != (uint64_t)0)
652 {
653 MicroProfileStringArrayAddLiteral(&ToolTip, "Time:");
654 MicroProfileStringArrayFormat(&ToolTip,"%6.3fms", fMs);
655 MicroProfileStringArrayAddLiteral(&ToolTip, "");
656 MicroProfileStringArrayAddLiteral(&ToolTip, "");
657 }
658
659 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Time:");
660 MicroProfileStringArrayFormat(&ToolTip,"%6.3fms", fFrameMs);
661
662 MicroProfileStringArrayAddLiteral(&ToolTip, "Average:");
663 MicroProfileStringArrayFormat(&ToolTip,"%6.3fms", fAverage);
664
665 MicroProfileStringArrayAddLiteral(&ToolTip, "Max:");
666 MicroProfileStringArrayFormat(&ToolTip,"%6.3fms", fMax);
667
668 MicroProfileStringArrayAddLiteral(&ToolTip, "");
669 MicroProfileStringArrayAddLiteral(&ToolTip, "");
670
671 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Call Average:");
672 MicroProfileStringArrayFormat(&ToolTip,"%6.3fms", fCallAverage);
673
674 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Call Count:");
675 MicroProfileStringArrayFormat(&ToolTip, "%6d", nAggregateCount / nAggregateFrames);
676
677 MicroProfileStringArrayAddLiteral(&ToolTip, "");
678 MicroProfileStringArrayAddLiteral(&ToolTip, "");
679
680 MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Frame Time:");
681 MicroProfileStringArrayFormat(&ToolTip, "%6.3fms", fFrameMsExclusive);
682
683 MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Average:");
684 MicroProfileStringArrayFormat(&ToolTip, "%6.3fms", fAverageExclusive);
685
686 MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Max:");
687 MicroProfileStringArrayFormat(&ToolTip, "%6.3fms", fMaxExclusive);
688
689 MicroProfileStringArrayAddLiteral(&ToolTip, "");
690 MicroProfileStringArrayAddLiteral(&ToolTip, "");
691
692 MicroProfileStringArrayAddLiteral(&ToolTip, "Group:");
693 MicroProfileStringArrayFormat(&ToolTip, "%s", pGroupName);
694 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Time:");
695 MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroup);
696 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Average:");
697 MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroupAverage);
698 MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Max:");
699 MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroupMax);
700
701
702
703
704 MicroProfileToolTipMeta(&ToolTip);
705
706
707 MicroProfileDrawFloatWindow(nX, nY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, S.TimerInfo[nTimerId].nColor);
708
709 if(UI.nMouseLeftMod)
710 {
711 int nIndex = (g_MicroProfileUI.LockedToolTipFront + MICROPROFILE_TOOLTIP_MAX_LOCKED - 1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
712 g_MicroProfileUI.nLockedToolTipColor[nIndex] = S.TimerInfo[nTimerId].nColor;
713 MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex], &ToolTip);
714 g_MicroProfileUI.LockedToolTipFront = nIndex;
715
716 }
717}
718
719
720void MicroProfileZoomTo(int64_t nTickStart, int64_t nTickEnd)
721{
722 MicroProfile& S = *MicroProfileGet();
723
724 int64_t nStart = S.Frames[S.nFrameCurrent].nFrameStartCpu;
725 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
726 UI.fDetailedOffsetTarget = MicroProfileLogTickDifference(nStart, nTickStart) * fToMs;
727 UI.fDetailedRangeTarget = MicroProfileLogTickDifference(nTickStart, nTickEnd) * fToMs;
728}
729
730void MicroProfileCenter(int64_t nTickCenter)
731{
732 MicroProfile& S = *MicroProfileGet();
733 int64_t nStart = S.Frames[S.nFrameCurrent].nFrameStartCpu;
734 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
735 float fCenter = MicroProfileLogTickDifference(nStart, nTickCenter) * fToMs;
736 UI.fDetailedOffsetTarget = UI.fDetailedOffset = fCenter - 0.5f * UI.fDetailedRange;
737}
738#ifdef MICROPROFILE_DEBUG
739uint64_t* g_pMicroProfileDumpStart = 0;
740uint64_t* g_pMicroProfileDumpEnd = 0;
741void MicroProfileDebugDumpRange()
742{
743 MicroProfile& S = *MicroProfileGet();
744 if(g_pMicroProfileDumpStart != g_pMicroProfileDumpEnd)
745 {
746 uint64_t* pStart = g_pMicroProfileDumpStart;
747 uint64_t* pEnd = g_pMicroProfileDumpEnd;
748 while(pStart != pEnd)
749 {
750 uint64_t nTick = MicroProfileLogGetTick(*pStart);
751 uint64_t nToken = MicroProfileLogTimerIndex(*pStart);
752 uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
753
754 const char* pTimerName = S.TimerInfo[nTimerId].pName;
755 char buffer[256];
756 int type = MicroProfileLogType(*pStart);
757
758 const char* pBegin = type == MP_LOG_LEAVE ? "END" :
759 (type == MP_LOG_ENTER ? "BEGIN" : "META");
760 snprintf(buffer, 255, "DUMP 0x%p: %s :: %llx: %s\n", pStart, pBegin, nTick, pTimerName);
761#ifdef _WIN32
762 OutputDebugString(buffer);
763#else
764 printf("%s", buffer);
765#endif
766 pStart++;
767 }
768
769 g_pMicroProfileDumpStart = g_pMicroProfileDumpEnd;
770 }
771}
772#define MP_DEBUG_DUMP_RANGE() MicroProfileDebugDumpRange();
773#else
774#define MP_DEBUG_DUMP_RANGE() do{} while(0)
775#endif
776
777#define MICROPROFILE_HOVER_DIST 0.5f
778
779void MicroProfileDrawDetailedContextSwitchBars(uint32_t nY, uint32_t nThreadId, uint32_t nContextSwitchStart, uint32_t nContextSwitchEnd, int64_t nBaseTicks, uint32_t nBaseY)
780{
781 MicroProfile& S = *MicroProfileGet();
782 int64_t nTickIn = -1;
783 uint32_t nThreadBefore = -1;
784 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
785 float fMsToScreen = UI.nWidth / UI.fDetailedRange;
786 float fMouseX = (float)UI.nMouseX;
787 float fMouseY = (float)UI.nMouseY;
788
789
790 for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
791 {
792 MP_ASSERT(j < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE);
793 MicroProfileContextSwitch CS = S.ContextSwitch[j];
794
795 if(nTickIn == -1)
796 {
797 if(CS.nThreadIn == nThreadId)
798 {
799 nTickIn = CS.nTicks;
800 nThreadBefore = CS.nThreadOut;
801 }
802 }
803 else
804 {
805 if(CS.nThreadOut == nThreadId)
806 {
807 int64_t nTickOut = CS.nTicks;
808 float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickIn);
809 float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickOut);
810 if(fMsStart <= fMsEnd)
811 {
812 float fXStart = fMsStart * fMsToScreen;
813 float fXEnd = fMsEnd * fMsToScreen;
814 float fYStart = (float)nY;
815 float fYEnd = fYStart + (MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT);
816 uint32_t nColor = g_nMicroProfileContextSwitchThreadColors[CS.nCpu%MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS];
817 float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
818 bool bHover = fXDist < MICROPROFILE_HOVER_DIST && fYStart <= fMouseY && fMouseY <= fYEnd && nBaseY < fMouseY;
819 if(bHover)
820 {
821 UI.nRangeBegin = nTickIn;
822 UI.nRangeEnd = nTickOut;
823 S.nContextSwitchHoverTickIn = nTickIn;
824 S.nContextSwitchHoverTickOut = nTickOut;
825 S.nContextSwitchHoverThread = CS.nThreadOut;
826 S.nContextSwitchHoverThreadBefore = nThreadBefore;
827 S.nContextSwitchHoverThreadAfter = CS.nThreadIn;
828 S.nContextSwitchHoverCpuNext = CS.nCpu;
829 nColor = UI.nHoverColor;
830 }
831 if(CS.nCpu == S.nContextSwitchHoverCpu)
832 {
833 nColor = UI.nHoverColorShared;
834 }
835 MicroProfileDrawBox(fXStart, fYStart, fXEnd, fYEnd, nColor|UI.nOpacityForeground, MicroProfileBoxTypeFlat);
836 }
837 nTickIn = -1;
838 }
839 }
840 }
841}
842
843void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY, int nSelectedFrame)
844{
845 MicroProfile& S = *MicroProfileGet();
846 MP_DEBUG_DUMP_RANGE();
847 int nY = nBaseY - UI.nOffsetY;
848 int64_t nNumBoxes = 0;
849 int64_t nNumLines = 0;
850
851 uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
852 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
853 MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
854
855 UI.nRangeBegin = 0;
856 UI.nRangeEnd = 0;
857 UI.nRangeBeginGpu = 0;
858 UI.nRangeEndGpu = 0;
859 UI.nRangeBeginIndex = UI.nRangeEndIndex = 0;
860 UI.pRangeLog = 0;
861 int64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
862 int64_t nFrameStartGpu = pFrameCurrent->nFrameStartGpu;
863 int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();
864 int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();
865 float fToMsCpu = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);
866 float fToMsGpu = MicroProfileTickToMsMultiplier(nTicksPerSecondGpu);
867
868 float fDetailedOffset = UI.fDetailedOffset;
869 float fDetailedRange = UI.fDetailedRange;
870
871
872 int64_t nDetailedOffsetTicksCpu = MicroProfileMsToTick(fDetailedOffset, MicroProfileTicksPerSecondCpu());
873 int64_t nDetailedOffsetTicksGpu = MicroProfileMsToTick(fDetailedOffset, MicroProfileTicksPerSecondGpu());
874 int64_t nBaseTicksCpu = nDetailedOffsetTicksCpu + nFrameStartCpu;
875 int64_t nBaseTicksGpu = nDetailedOffsetTicksGpu + nFrameStartGpu;
876 int64_t nBaseTicksEndCpu = nBaseTicksCpu + MicroProfileMsToTick(fDetailedRange, MicroProfileTicksPerSecondCpu());
877
878 int64_t nTickReferenceCpu = 0, nTickReferenceGpu = 0;
879 static int64_t nRefCpu = 0, nRefGpu = 0;
880 if(MicroProfileGetGpuTickReference(&nTickReferenceCpu, &nTickReferenceGpu))
881 {
882 if(0 == nRefCpu || abs(nRefCpu-nBaseTicksCpu) > abs(nTickReferenceCpu-nBaseTicksCpu))
883 {
884 nRefCpu = nTickReferenceCpu;
885 nRefGpu = nTickReferenceGpu;
886 }
887 else
888 {
889 nTickReferenceCpu = nRefCpu;
890 nTickReferenceGpu = nRefGpu;
891 }
892 nBaseTicksGpu = (nBaseTicksCpu - nTickReferenceCpu) * nTicksPerSecondGpu / nTicksPerSecondCpu + nTickReferenceGpu;
893 }
894 int64_t nBaseTicksEndGpu = nBaseTicksCpu + MicroProfileMsToTick(fDetailedRange, MicroProfileTicksPerSecondCpu());
895
896 MicroProfileFrameState* pFrameFirst = pFrameCurrent;
897 int64_t nGapTime = MicroProfileTicksPerSecondCpu() * MICROPROFILE_GAP_TIME / 1000;
898 for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY; ++i)
899 {
900 uint32_t nNextIndex = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
901 pFrameFirst = &S.Frames[nNextIndex];
902 if(pFrameFirst->nFrameStartCpu <= nBaseTicksCpu-nGapTime)
903 break;
904 }
905
906 float fMsBase = fToMsCpu * nDetailedOffsetTicksCpu;
907 float fMs = fDetailedRange;
908 float fMsEnd = fMs + fMsBase;
909 float fWidth = (float)nWidth;
910 float fMsToScreen = fWidth / fMs;
911
912 {
913 float fRate = floor(2*(log10(fMs)-1))/2;
914 float fStep = powf(10.f, fRate);
915 float fRcpStep = 1.f / fStep;
916 int nColorIndex = (int)(floor(fMsBase*fRcpStep));
917 float fStart = floor(fMsBase*fRcpStep) * fStep;
918 for(float f = fStart; f < fMsEnd; )
919 {
920 float fStart = f;
921 float fNext = f + fStep;
922 MicroProfileDrawBox(((fStart-fMsBase) * fMsToScreen), nBaseY, (fNext-fMsBase) * fMsToScreen+1, nBaseY + nHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[nColorIndex++ & 1]);
923 f = fNext;
924 }
925 }
926
927 nY += MICROPROFILE_TEXT_HEIGHT+1;
928 MicroProfileLogEntry* pMouseOver = UI.pDisplayMouseOver;
929 MicroProfileLogEntry* pMouseOverNext = 0;
930 uint64_t nMouseOverToken = pMouseOver ? MicroProfileLogTimerIndex(*pMouseOver) : MICROPROFILE_INVALID_TOKEN;
931 float fMouseX = (float)UI.nMouseX;
932 float fMouseY = (float)UI.nMouseY;
933 uint64_t nHoverToken = MICROPROFILE_INVALID_TOKEN;
934 int64_t nHoverTime = 0;
935
936 static int nHoverCounter = 155;
937 static int nHoverCounterDelta = 10;
938 nHoverCounter += nHoverCounterDelta;
939 if(nHoverCounter >= 245)
940 nHoverCounterDelta = -10;
941 else if(nHoverCounter < 100)
942 nHoverCounterDelta = 10;
943 UI.nHoverColor = (nHoverCounter<<24)|(nHoverCounter<<16)|(nHoverCounter<<8)|nHoverCounter;
944 uint32_t nHoverCounterShared = nHoverCounter>>2;
945 UI.nHoverColorShared = (nHoverCounterShared<<24)|(nHoverCounterShared<<16)|(nHoverCounterShared<<8)|nHoverCounterShared;
946
947 uint32_t nLinesDrawn[MICROPROFILE_STACK_MAX]={0};
948
949 uint32_t nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadAfter;
950 uint32_t nContextSwitchHoverThreadBefore = S.nContextSwitchHoverThreadBefore;
951 S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
952
953 uint32_t nContextSwitchStart = -1;
954 uint32_t nContextSwitchEnd = -1;
955 S.nContextSwitchHoverCpuNext = 0xff;
956 S.nContextSwitchHoverTickIn = -1;
957 S.nContextSwitchHoverTickOut = -1;
958 if(S.bContextSwitchRunning)
959 {
960 MicroProfileContextSwitchSearch(&nContextSwitchStart, &nContextSwitchEnd, nBaseTicksCpu, nBaseTicksEndCpu);
961 }
962
963 bool bSkipBarView = S.bContextSwitchRunning && S.bContextSwitchNoBars;
964
965 if(!bSkipBarView)
966 {
967 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
968 {
969 MicroProfileThreadLog* pLog = S.Pool[i];
970 if(!pLog)
971 continue;
972
973 uint32_t nPut = pFrameNext->nLogStart[i];
974 ///note: this may display new samples as old data, but this will only happen when
975 // unpaused, where the detailed view is hardly perceptible
976 uint32_t nFront = S.Pool[i]->nPut.load(std::memory_order_relaxed);
977 MicroProfileFrameState* pFrameLogFirst = pFrameCurrent;
978 MicroProfileFrameState* pFrameLogLast = pFrameNext;
979 uint32_t nGet = pFrameLogFirst->nLogStart[i];
980 do
981 {
982 MP_ASSERT(pFrameLogFirst >= &S.Frames[0] && pFrameLogFirst < &S.Frames[MICROPROFILE_MAX_FRAME_HISTORY]);
983 uint32_t nNewGet = pFrameLogFirst->nLogStart[i];
984 bool bIsValid = false;
985 if(nPut < nFront)
986 {
987 bIsValid = nNewGet <= nPut || nNewGet >= nFront;
988 }
989 else
990 {
991 bIsValid = nNewGet <= nPut && nNewGet >= nFront;
992 }
993 if(bIsValid)
994 {
995 nGet = nNewGet;
996 pFrameLogFirst--;
997 if(pFrameLogFirst < &S.Frames[0])
998 pFrameLogFirst = &S.Frames[MICROPROFILE_MAX_FRAME_HISTORY-1];
999 }
1000 else
1001 {
1002 break;
1003 }
1004 }while(pFrameLogFirst != pFrameFirst);
1005
1006
1007 if(nGet == (uint32_t)-1)
1008 continue;
1009 MP_ASSERT(nGet != (uint32_t)-1);
1010
1011 nPut = pFrameLogLast->nLogStart[i];
1012
1013 uint32_t nRange[2][2] = { {0, 0}, {0, 0}, };
1014
1015 MicroProfileGetRange(nPut, nGet, nRange);
1016 if(nPut == nGet)
1017 continue;
1018 uint32_t nMaxStackDepth = 0;
1019
1020 bool bGpu = pLog->nGpu != 0;
1021 float fToMs = bGpu ? fToMsGpu : fToMsCpu;
1022 int64_t nBaseTicks = bGpu ? nBaseTicksGpu : nBaseTicksCpu;
1023 char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1024 uint64_t nThreadId = pLog->nThreadId;
1025 snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s", nThreadId, &pLog->ThreadName[0] );
1026 nY += 3;
1027 uint32_t nThreadColor = -1;
1028 if(pLog->nThreadId == nContextSwitchHoverThreadAfter || pLog->nThreadId == nContextSwitchHoverThreadBefore)
1029 nThreadColor = UI.nHoverColorShared|0x906060;
1030 MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], (uint32_t)strlen(&ThreadName[0]));
1031 nY += 3;
1032 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1033
1034 if(S.bContextSwitchRunning)
1035 {
1036 MicroProfileDrawDetailedContextSwitchBars(nY, pLog->nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicks, nBaseY);
1037 nY -= MICROPROFILE_DETAILED_BAR_HEIGHT;
1038 nY += MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT+1;
1039 }
1040
1041 uint32_t nYDelta = MICROPROFILE_DETAILED_BAR_HEIGHT;
1042 uint32_t nStack[MICROPROFILE_STACK_MAX];
1043 uint32_t nStackPos = 0;
1044 for(uint32_t j = 0; j < 2; ++j)
1045 {
1046 uint32_t nStart = nRange[j][0];
1047 uint32_t nEnd = nRange[j][1];
1048 for(uint32_t k = nStart; k < nEnd; ++k)
1049 {
1050 MicroProfileLogEntry* pEntry = pLog->Log + k;
1051 int nType = MicroProfileLogType(*pEntry);
1052 if(MP_LOG_ENTER == nType)
1053 {
1054 MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
1055 nStack[nStackPos++] = k;
1056 }
1057 else if(MP_LOG_META == nType)
1058 {
1059
1060 }
1061 else if(MP_LOG_LEAVE == nType)
1062 {
1063 if(0 == nStackPos)
1064 {
1065 continue;
1066 }
1067
1068 MicroProfileLogEntry* pEntryEnter = pLog->Log + nStack[nStackPos-1];
1069 if(MicroProfileLogTimerIndex(*pEntryEnter) != MicroProfileLogTimerIndex(*pEntry))
1070 {
1071 //uprintf("mismatch %llx %llx\n", pEntryEnter->nToken, pEntry->nToken);
1072 continue;
1073 }
1074 int64_t nTickStart = MicroProfileLogGetTick(*pEntryEnter);
1075 int64_t nTickEnd = MicroProfileLogGetTick(*pEntry);
1076 uint64_t nTimerIndex = MicroProfileLogTimerIndex(*pEntry);
1077 uint32_t nColor = S.TimerInfo[nTimerIndex].nColor;
1078 if(nMouseOverToken == nTimerIndex)
1079 {
1080 if(pEntry == pMouseOver)
1081 {
1082 nColor = UI.nHoverColor;
1083 if(bGpu)
1084 {
1085 UI.nRangeBeginGpu = *pEntryEnter;
1086 UI.nRangeEndGpu = *pEntry;
1087 uint32_t nCpuBegin = (nStack[nStackPos-1] + 1) % MICROPROFILE_BUFFER_SIZE;
1088 uint32_t nCpuEnd = (k + 1) % MICROPROFILE_BUFFER_SIZE;
1089 MicroProfileLogEntry LogCpuBegin = pLog->Log[nCpuBegin];
1090 MicroProfileLogEntry LogCpuEnd = pLog->Log[nCpuEnd];
1091 if(MicroProfileLogType(LogCpuBegin)==3 && MicroProfileLogType(LogCpuEnd) == 3)
1092 {
1093 UI.nRangeBegin = LogCpuBegin;
1094 UI.nRangeEnd = LogCpuEnd;
1095 }
1096 UI.nRangeBeginIndex = nStack[nStackPos-1];
1097 UI.nRangeEndIndex = k;
1098 UI.pRangeLog = pLog;
1099 }
1100 else
1101 {
1102 UI.nRangeBegin = *pEntryEnter;
1103 UI.nRangeEnd = *pEntry;
1104 UI.nRangeBeginIndex = nStack[nStackPos-1];
1105 UI.nRangeEndIndex = k;
1106 UI.pRangeLog = pLog;
1107
1108 }
1109 }
1110 else
1111 {
1112 nColor = UI.nHoverColorShared;
1113 }
1114 }
1115
1116 nMaxStackDepth = MicroProfileMax(nMaxStackDepth, nStackPos);
1117 float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickStart);
1118 float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickEnd);
1119 float fXStart = fMsStart * fMsToScreen;
1120 float fXEnd = fMsEnd * fMsToScreen;
1121 float fYStart = (float)(nY + nStackPos * nYDelta);
1122 float fYEnd = fYStart + (MICROPROFILE_DETAILED_BAR_HEIGHT);
1123 float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
1124 bool bHover = fXDist < MICROPROFILE_HOVER_DIST && fYStart <= fMouseY && fMouseY <= fYEnd && nBaseY < fMouseY;
1125 uint32_t nIntegerWidth = (uint32_t)(fXEnd - fXStart);
1126 if(nIntegerWidth)
1127 {
1128 if(bHover && UI.nActiveMenu == -1)
1129 {
1130 nHoverToken = MicroProfileLogTimerIndex(*pEntry);
1131 #if MICROPROFILE_DEBUG
1132 UI.nHoverAddressEnter = (uint64_t)pEntryEnter;
1133 UI.nHoverAddressLeave = (uint64_t)pEntry;
1134 #endif
1135 nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1136 pMouseOverNext = pEntry;
1137 }
1138
1139 MicroProfileDrawBox(fXStart, fYStart, fXEnd, fYEnd, nColor|UI.nOpacityForeground, MicroProfileBoxTypeBar);
1140#if MICROPROFILE_DETAILED_BAR_NAMES
1141 if(nIntegerWidth>3*MICROPROFILE_TEXT_WIDTH)
1142 {
1143 float fXStartText = MicroProfileMax(fXStart, 0.f);
1144 int nTextWidth = (int)(fXEnd - fXStartText);
1145 int nCharacters = (nTextWidth - 2*MICROPROFILE_TEXT_WIDTH) / MICROPROFILE_TEXT_WIDTH;
1146 if(nCharacters>0)
1147 {
1148 MicroProfileDrawText(fXStartText+1, fYStart+1, -1, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
1149 }
1150 }
1151#endif
1152 ++nNumBoxes;
1153 }
1154 else
1155 {
1156 float fXAvg = 0.5f * (fXStart + fXEnd);
1157 int nLineX = (int)floor(fXAvg+0.5f);
1158 if(nLineX != (int)nLinesDrawn[nStackPos])
1159 {
1160 if(bHover && UI.nActiveMenu == -1)
1161 {
1162 nHoverToken = (uint32_t)MicroProfileLogTimerIndex(*pEntry);
1163 nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1164 pMouseOverNext = pEntry;
1165 }
1166 nLinesDrawn[nStackPos] = nLineX;
1167 MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground);
1168 ++nNumLines;
1169 }
1170 }
1171 nStackPos--;
1172 if(0 == nStackPos)
1173 {
1174 if(bGpu ? (nTickStart > nBaseTicksEndGpu) : (nTickStart > nBaseTicksEndCpu))
1175 {
1176 break;
1177 }
1178 }
1179 }
1180 }
1181 }
1182 nY += nMaxStackDepth * nYDelta + MICROPROFILE_DETAILED_BAR_HEIGHT+1;
1183 }
1184 }
1185 if(S.bContextSwitchRunning && (S.bContextSwitchAllThreads||S.bContextSwitchNoBars))
1186 {
1187 uint32_t nNumThreads = 0;
1188 uint32_t nThreads[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS];
1189 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS && S.Pool[i]; ++i)
1190 nThreads[nNumThreads++] = S.Pool[i]->nThreadId;
1191 uint32_t nNumThreadsBase = nNumThreads;
1192 if(S.bContextSwitchAllThreads)
1193 {
1194 for(uint32_t i = nContextSwitchStart; i != nContextSwitchEnd; i = (i+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
1195 {
1196 MicroProfileContextSwitch CS = S.ContextSwitch[i];
1197 ThreadIdType nThreadId = CS.nThreadIn;
1198 if(nThreadId)
1199 {
1200 bool bSeen = false;
1201 for(uint32_t j = 0; j < nNumThreads; ++j)
1202 {
1203 if(nThreads[j] == nThreadId)
1204 {
1205 bSeen = true;
1206 break;
1207 }
1208 }
1209 if(!bSeen)
1210 {
1211 nThreads[nNumThreads++] = nThreadId;
1212 }
1213 }
1214 if(nNumThreads == MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS)
1215 {
1216 S.nOverflow = 10;
1217 break;
1218 }
1219 }
1220 std::sort(&nThreads[nNumThreadsBase], &nThreads[nNumThreads]);
1221 }
1222 uint32_t nStart = nNumThreadsBase;
1223 if(S.bContextSwitchNoBars)
1224 nStart = 0;
1225 for(uint32_t i = nStart; i < nNumThreads; ++i)
1226 {
1227 ThreadIdType nThreadId = nThreads[i];
1228 if(nThreadId)
1229 {
1230 char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1231 const char* cLocal = MicroProfileIsLocalThread(nThreadId) ? "*": " ";
1232
1233 int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04x: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
1234 uint32_t nThreadColor = -1;
1235 if(nThreadId == nContextSwitchHoverThreadAfter || nThreadId == nContextSwitchHoverThreadBefore)
1236 nThreadColor = UI.nHoverColorShared|0x906060;
1237 MicroProfileDrawDetailedContextSwitchBars(nY+2, nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicksCpu, nBaseY);
1238 MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], nStrLen);
1239 nY += MICROPROFILE_TEXT_HEIGHT+1;
1240 }
1241 }
1242 }
1243
1244 S.nContextSwitchHoverCpu = S.nContextSwitchHoverCpuNext;
1245
1246
1247
1248
1249 UI.pDisplayMouseOver = pMouseOverNext;
1250
1251 if(!S.nRunning)
1252 {
1253 if(nHoverToken != MICROPROFILE_INVALID_TOKEN && nHoverTime)
1254 {
1255 UI.nHoverToken = nHoverToken;
1256 UI.nHoverTime = nHoverTime;
1257 }
1258
1259 if(nSelectedFrame != -1)
1260 {
1261 UI.nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1262 UI.nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1263 UI.nRangeBeginGpu = S.Frames[nSelectedFrame].nFrameStartGpu;
1264 UI.nRangeEndGpu = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartGpu;
1265 }
1266 if(UI.nRangeBegin != UI.nRangeEnd)
1267 {
1268 float fMsStart = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeBegin);
1269 float fMsEnd = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeEnd);
1270 float fXStart = fMsStart * fMsToScreen;
1271 float fXEnd = fMsEnd * fMsToScreen;
1272 MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1273 MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1274 MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1275
1276 fMsStart += fDetailedOffset;
1277 fMsEnd += fDetailedOffset;
1278 char sBuffer[32];
1279 uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1280 float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1281 float fStartTextX = fXStart - fStartTextWidth - 2;
1282 MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1283 MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
1284 uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1285 MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1286 MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
1287
1288 if(UI.nMouseRight)
1289 {
1290 MicroProfileZoomTo(UI.nRangeBegin, UI.nRangeEnd);
1291 }
1292 }
1293
1294 if(UI.nRangeBeginGpu != UI.nRangeEndGpu)
1295 {
1296 float fMsStart = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeBeginGpu);
1297 float fMsEnd = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeEndGpu);
1298 float fXStart = fMsStart * fMsToScreen;
1299 float fXEnd = fMsEnd * fMsToScreen;
1300 MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU, MicroProfileBoxTypeFlat);
1301 MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1302 MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1303
1304 nBaseY += MICROPROFILE_TEXT_HEIGHT+1;
1305
1306 fMsStart += fDetailedOffset;
1307 fMsEnd += fDetailedOffset;
1308 char sBuffer[32];
1309 uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1310 float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1311 float fStartTextX = fXStart - fStartTextWidth - 2;
1312 MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1313 MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
1314 uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1315 MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1316 MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
1317 }
1318 }
1319}
1320
1321
1322void MicroProfileDrawDetailedFrameHistory(uint32_t nWidth, uint32_t nHeight, uint32_t nBaseY, uint32_t nSelectedFrame)
1323{
1324 MicroProfile& S = *MicroProfileGet();
1325
1326 const uint32_t nBarHeight = MICROPROFILE_FRAME_HISTORY_HEIGHT;
1327 float fBaseX = (float)nWidth;
1328 float fDx = fBaseX / MICROPROFILE_NUM_FRAMES;
1329
1330 uint32_t nLastIndex = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
1331 MicroProfileDrawBox(0, nBaseY, nWidth, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, 0xff000000 | g_nMicroProfileBackColors[0], MicroProfileBoxTypeFlat);
1332 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * S.fRcpReferenceTime;
1333 float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()) * S.fRcpReferenceTime;
1334
1335
1336 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
1337 uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
1338 int64_t nDetailedOffsetTicksCpu = MicroProfileMsToTick(UI.fDetailedOffset, MicroProfileTicksPerSecondCpu());
1339 int64_t nCpuStart = nDetailedOffsetTicksCpu + nFrameStartCpu;
1340 int64_t nCpuEnd = nCpuStart + MicroProfileMsToTick(UI.fDetailedRange, MicroProfileTicksPerSecondCpu());;
1341
1342
1343 float fSelectionStart = (float)nWidth;
1344 float fSelectionEnd = 0.f;
1345 for(uint32_t i = 0; i < MICROPROFILE_NUM_FRAMES; ++i)
1346 {
1347 uint32_t nIndex = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
1348 MicroProfileFrameState* pCurrent = &S.Frames[nIndex];
1349 MicroProfileFrameState* pNext = &S.Frames[nLastIndex];
1350
1351 int64_t nTicks = pNext->nFrameStartCpu - pCurrent->nFrameStartCpu;
1352 int64_t nTicksGpu = pNext->nFrameStartGpu - pCurrent->nFrameStartGpu;
1353 float fScale = fToMs * nTicks;
1354 float fScaleGpu = fToMsGpu * nTicksGpu;
1355 fScale = fScale > 1.f ? 0.f : 1.f - fScale;
1356 fScaleGpu = fScaleGpu > 1.f ? 0.f : 1.f - fScaleGpu;
1357 float fXEnd = fBaseX;
1358 float fXStart = fBaseX - fDx;
1359 fBaseX = fXStart;
1360 uint32_t nColor = MICROPROFILE_FRAME_HISTORY_COLOR_CPU;
1361 if(nIndex == nSelectedFrame)
1362 nColor = (uint32_t)-1;
1363 MicroProfileDrawBox(fXStart, nBaseY + fScale * nBarHeight, fXEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, nColor, MicroProfileBoxTypeBar);
1364 if(pNext->nFrameStartCpu > nCpuStart)
1365 {
1366 fSelectionStart = fXStart;
1367 }
1368 if(pCurrent->nFrameStartCpu < nCpuEnd && fSelectionEnd == 0.f)
1369 {
1370 fSelectionEnd = fXEnd;
1371 }
1372 nLastIndex = nIndex;
1373 }
1374 MicroProfileDrawBox(fSelectionStart, nBaseY, fSelectionEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, MICROPROFILE_FRAME_HISTORY_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1375}
1376void MicroProfileDrawDetailedView(uint32_t nWidth, uint32_t nHeight)
1377{
1378 MicroProfile& S = *MicroProfileGet();
1379
1380 MICROPROFILE_SCOPE(g_MicroProfileDetailed);
1381 uint32_t nBaseY = MICROPROFILE_TEXT_HEIGHT + 1;
1382
1383 int nSelectedFrame = -1;
1384 if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == -1)
1385 {
1386
1387 nSelectedFrame = ((MICROPROFILE_NUM_FRAMES) * (UI.nWidth-UI.nMouseX) / UI.nWidth);
1388 nSelectedFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nSelectedFrame) % MICROPROFILE_MAX_FRAME_HISTORY;
1389 UI.nHoverFrame = nSelectedFrame;
1390 if(UI.nMouseRight)
1391 {
1392 int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1393 int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1394 MicroProfileZoomTo(nRangeBegin, nRangeEnd);
1395 }
1396 if(UI.nMouseDownLeft)
1397 {
1398 uint64_t nFrac = (1024 * (MICROPROFILE_NUM_FRAMES) * (UI.nMouseX) / UI.nWidth) % 1024;
1399 int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1400 int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1401 MicroProfileCenter(nRangeBegin + (nRangeEnd-nRangeBegin) * nFrac / 1024);
1402 }
1403 }
1404 else
1405 {
1406 UI.nHoverFrame = -1;
1407 }
1408
1409 MicroProfileDrawDetailedBars(nWidth, nHeight, nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT, nSelectedFrame);
1410 MicroProfileDrawDetailedFrameHistory(nWidth, nHeight, nBaseY, nSelectedFrame);
1411}
1412
1413void MicroProfileDrawTextRight(uint32_t nX, uint32_t nY, uint32_t nColor, const char* pStr, uint32_t nStrLen)
1414{
1415 MicroProfileDrawText(nX - nStrLen * (MICROPROFILE_TEXT_WIDTH+1), nY, nColor, pStr, nStrLen);
1416}
1417void MicroProfileDrawHeader(int32_t nX, uint32_t nWidth, const char* pName)
1418{
1419 if(pName)
1420 {
1421 MicroProfileDrawBox(nX-8, MICROPROFILE_TEXT_HEIGHT + 2, nX + nWidth+5, MICROPROFILE_TEXT_HEIGHT + 2 + (MICROPROFILE_TEXT_HEIGHT+1), 0xff000000|g_nMicroProfileBackColors[1]);
1422 MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, pName, (uint32_t)strlen(pName));
1423 }
1424}
1425
1426
1427typedef void (*MicroProfileLoopGroupCallback)(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pData);
1428
1429void MicroProfileLoopActiveGroupsDraw(int32_t nX, int32_t nY, const char* pName, MicroProfileLoopGroupCallback CB, void* pData)
1430{
1431 MicroProfile& S = *MicroProfileGet();
1432 nY += MICROPROFILE_TEXT_HEIGHT + 2;
1433 uint64_t nGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1434 uint32_t nCount = 0;
1435 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1436 {
1437 uint64_t nMask = 1ll << j;
1438 if(nMask & nGroup)
1439 {
1440 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1441 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1442 {
1443 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1444 if(nTokenMask & nMask)
1445 {
1446 if(nY >= 0)
1447 CB(i, nCount, nMask, nX, nY, pData);
1448
1449 nCount += 2;
1450 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1451
1452 if(nY > (int)UI.nHeight)
1453 return;
1454 }
1455 }
1456
1457 }
1458 }
1459}
1460
1461
1462void MicroProfileCalcTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, uint64_t nGroup, uint32_t nSize)
1463{
1464 MicroProfile& S = *MicroProfileGet();
1465
1466 uint32_t nCount = 0;
1467 uint64_t nMask = 1;
1468
1469 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1470 {
1471 if(nMask & nGroup)
1472 {
1473 const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1474 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1475 {
1476 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1477 if(nTokenMask & nMask)
1478 {
1479 {
1480 uint32_t nTimer = i;
1481 uint32_t nIdx = nCount;
1482 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
1483 uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;
1484 float fToPrc = S.fRcpReferenceTime;
1485 float fMs = fToMs * (S.Frame[nTimer].nTicks);
1486 float fPrc = MicroProfileMin(fMs * fToPrc, 1.f);
1487 float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);
1488 float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f);
1489 float fMaxMs = fToMs * (S.AggregateMax[nTimer]);
1490 float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f);
1491 float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);
1492 float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f);
1493 float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);
1494 float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f);
1495 float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);
1496 float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f);
1497 float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);
1498 float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f);
1499 pTimers[nIdx] = fMs;
1500 pTimers[nIdx+1] = fPrc;
1501 pAverage[nIdx] = fAverageMs;
1502 pAverage[nIdx+1] = fAveragePrc;
1503 pMax[nIdx] = fMaxMs;
1504 pMax[nIdx+1] = fMaxPrc;
1505 pCallAverage[nIdx] = fCallAverageMs;
1506 pCallAverage[nIdx+1] = fCallAveragePrc;
1507 pExclusive[nIdx] = fMsExclusive;
1508 pExclusive[nIdx+1] = fPrcExclusive;
1509 pAverageExclusive[nIdx] = fAverageMsExclusive;
1510 pAverageExclusive[nIdx+1] = fAveragePrcExclusive;
1511 pMaxExclusive[nIdx] = fMaxMsExclusive;
1512 pMaxExclusive[nIdx+1] = fMaxPrcExclusive;
1513 }
1514 nCount += 2;
1515 }
1516 }
1517 }
1518 nMask <<= 1ll;
1519 }
1520}
1521
1522#define SBUF_MAX 32
1523
1524void MicroProfileDrawBarArrayCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1525{
1526 const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1527 const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1528 const float fWidth = (float)MICROPROFILE_BAR_WIDTH;
1529
1530 float* pTimers = ((float**)pExtra)[0];
1531 float* pTimers2 = ((float**)pExtra)[1];
1532 MicroProfile& S = *MicroProfileGet();
1533 char sBuffer[SBUF_MAX];
1534 if (pTimers2 && pTimers2[nIdx] > 0.1f)
1535 snprintf(sBuffer, SBUF_MAX-1, "%5.2f %3.1fx", pTimers[nIdx], pTimers[nIdx] / pTimers2[nIdx]);
1536 else
1537 snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pTimers[nIdx]);
1538 if (!pTimers2)
1539 MicroProfileDrawBox(nX + nTextWidth, nY, nX + nTextWidth + fWidth * pTimers[nIdx+1], nY + nHeight, UI.nOpacityForeground|S.TimerInfo[nTimer].nColor, MicroProfileBoxTypeBar);
1540 MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, (uint32_t)strlen(sBuffer));
1541}
1542
1543
1544uint32_t MicroProfileDrawBarArray(int32_t nX, int32_t nY, float* pTimers, const char* pName, uint32_t nTotalHeight, float* pTimers2 = NULL)
1545{
1546 const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1547 const uint32_t nWidth = MICROPROFILE_BAR_WIDTH;
1548
1549 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1550 float* pTimersArray[2] = {pTimers, pTimers2};
1551 MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarArrayCallback, pTimersArray);
1552 MicroProfileDrawHeader(nX, nTextWidth + nWidth, pName);
1553 return nWidth + 5 + nTextWidth;
1554
1555}
1556void MicroProfileDrawBarCallCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1557{
1558 MicroProfile& S = *MicroProfileGet();
1559 char sBuffer[SBUF_MAX];
1560 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5d", S.Frame[nTimer].nCount);//fix
1561 MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, nLen);
1562}
1563
1564uint32_t MicroProfileDrawBarCallCount(int32_t nX, int32_t nY, const char* pName)
1565{
1566 MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarCallCountCallback, 0);
1567 const uint32_t nTextWidth = 6 * MICROPROFILE_TEXT_WIDTH;
1568 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1569 return 5 + nTextWidth;
1570}
1571
1572struct MicroProfileMetaAverageArgs
1573{
1574 uint64_t* pCounters;
1575 float fRcpFrames;
1576};
1577
1578void MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1579{
1580 MicroProfileMetaAverageArgs* pArgs = (MicroProfileMetaAverageArgs*)pExtra;
1581 uint64_t* pCounters = pArgs->pCounters;
1582 float fRcpFrames = pArgs->fRcpFrames;
1583 char sBuffer[SBUF_MAX];
1584 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pCounters[nTimer] * fRcpFrames);
1585 MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
1586}
1587
1588uint32_t MicroProfileDrawBarMetaAverage(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1589{
1590 if(!pName)
1591 return 0;
1592 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1593 uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1594 float fRcpFrames = 1.f / (MicroProfileGet()->nAggregateFrames ? MicroProfileGet()->nAggregateFrames : 1);
1595 MicroProfileMetaAverageArgs Args = {pCounters, fRcpFrames};
1596 MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaAverageCallback, &Args);
1597 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1598 return 5 + nTextWidth;
1599}
1600
1601
1602void MicroProfileDrawBarMetaCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1603{
1604 uint64_t* pCounters = (uint64_t*)pExtra;
1605 char sBuffer[SBUF_MAX];
1606 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5llu", pCounters[nTimer]);
1607 MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
1608}
1609
1610uint32_t MicroProfileDrawBarMetaCount(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1611{
1612 if(!pName)
1613 return 0;
1614
1615 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1616 uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1617 MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaCountCallback, pCounters);
1618 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1619 return 5 + nTextWidth;
1620}
1621
1622void MicroProfileDrawBarLegendCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1623{
1624 MicroProfile& S = *MicroProfileGet();
1625 if (S.TimerInfo[nTimer].bGraph)
1626 {
1627 MicroProfileDrawText(nX, nY, S.TimerInfo[nTimer].nColor, ">", 1);
1628 }
1629 MicroProfileDrawTextRight(nX, nY, S.TimerInfo[nTimer].nColor, S.TimerInfo[nTimer].pName, (uint32_t)strlen(S.TimerInfo[nTimer].pName));
1630 if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT+1)
1631 {
1632 UI.nHoverToken = nTimer;
1633 UI.nHoverTime = 0;
1634 }
1635}
1636
1637uint32_t MicroProfileDrawBarLegend(int32_t nX, int32_t nY, uint32_t nTotalHeight, uint32_t nMaxWidth)
1638{
1639 MicroProfileDrawLineVertical(nX-5, nY, nTotalHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1640 MicroProfileLoopActiveGroupsDraw(nMaxWidth, nY, 0, MicroProfileDrawBarLegendCallback, 0);
1641 return nX;
1642}
1643
1644bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
1645{
1646 MicroProfile& S = *MicroProfileGet();
1647
1648 MICROPROFILE_SCOPE(g_MicroProfileDrawGraph);
1649 bool bEnabled = false;
1650 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1651 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1652 bEnabled = true;
1653 if(!bEnabled)
1654 return false;
1655
1656 uint32_t nX = nScreenWidth - MICROPROFILE_GRAPH_WIDTH;
1657 uint32_t nY = nScreenHeight - MICROPROFILE_GRAPH_HEIGHT;
1658 MicroProfileDrawBox(nX, nY, nX + MICROPROFILE_GRAPH_WIDTH, nY + MICROPROFILE_GRAPH_HEIGHT, 0x88000000 | g_nMicroProfileBackColors[0]);
1659 bool bMouseOver = UI.nMouseX >= nX && UI.nMouseY >= nY;
1660 float fMouseXPrc =(float(UI.nMouseX - nX)) / MICROPROFILE_GRAPH_WIDTH;
1661 if(bMouseOver)
1662 {
1663 float fXAvg = fMouseXPrc * MICROPROFILE_GRAPH_WIDTH + nX;
1664 MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, (uint32_t)-1);
1665 }
1666
1667
1668 float fY = (float)nScreenHeight;
1669 float fDX = MICROPROFILE_GRAPH_WIDTH * 1.f / MICROPROFILE_GRAPH_HISTORY;
1670 float fDY = MICROPROFILE_GRAPH_HEIGHT;
1671 uint32_t nPut = S.nGraphPut;
1672 float* pGraphData = (float*)alloca(sizeof(float)* MICROPROFILE_GRAPH_HISTORY*2);
1673 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1674 {
1675 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1676 {
1677 uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1678 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1679 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1680 float fToPrc = fToMs * S.fRcpReferenceTime * 3 / 4;
1681
1682 float fX = (float)nX;
1683 for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j)
1684 {
1685 float fWeigth = MicroProfileMin(fToPrc * (S.Graph[i].nHistory[(j+nPut)%MICROPROFILE_GRAPH_HISTORY]), 1.f);
1686 pGraphData[(j*2)] = fX;
1687 pGraphData[(j*2)+1] = fY - fDY * fWeigth;
1688 fX += fDX;
1689 }
1690 MicroProfileDrawLine2D(MICROPROFILE_GRAPH_HISTORY, pGraphData, S.TimerInfo[MicroProfileGetTimerIndex(S.Graph[i].nToken)].nColor);
1691 }
1692 }
1693 {
1694 float fY1 = 0.25f * MICROPROFILE_GRAPH_HEIGHT + nY;
1695 float fY2 = 0.50f * MICROPROFILE_GRAPH_HEIGHT + nY;
1696 float fY3 = 0.75f * MICROPROFILE_GRAPH_HEIGHT + nY;
1697 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY1, 0xffdd4444);
1698 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY2, 0xff000000| g_nMicroProfileBackColors[0]);
1699 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY3, 0xff000000|g_nMicroProfileBackColors[0]);
1700
1701 char buf[32];
1702 int nLen = snprintf(buf, sizeof(buf)-1, "%5.2fms", S.fReferenceTime);
1703 MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), (uint32_t)-1, buf, nLen);
1704 }
1705
1706
1707
1708 if(bMouseOver)
1709 {
1710 uint32_t pColors[MICROPROFILE_MAX_GRAPHS];
1711 MicroProfileStringArray Strings;
1712 MicroProfileStringArrayClear(&Strings);
1713 uint32_t nTextCount = 0;
1714 uint32_t nGraphIndex = (S.nGraphPut + MICROPROFILE_GRAPH_HISTORY - int(MICROPROFILE_GRAPH_HISTORY*(1.f - fMouseXPrc))) % MICROPROFILE_GRAPH_HISTORY;
1715
1716 uint32_t nX = UI.nMouseX;
1717 uint32_t nY = UI.nMouseY + 20;
1718
1719 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1720 {
1721 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1722 {
1723 uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1724 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1725 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1726 uint32_t nIndex = MicroProfileGetTimerIndex(S.Graph[i].nToken);
1727 uint32_t nColor = S.TimerInfo[nIndex].nColor;
1728 const char* pName = S.TimerInfo[nIndex].pName;
1729 pColors[nTextCount++] = nColor;
1730 MicroProfileStringArrayAddLiteral(&Strings, pName);
1731 MicroProfileStringArrayFormat(&Strings, "%5.2fms", fToMs * (S.Graph[i].nHistory[nGraphIndex]));
1732 }
1733 }
1734 if(nTextCount)
1735 {
1736 MicroProfileDrawFloatWindow(nX, nY, Strings.ppStrings, Strings.nNumStrings, 0, pColors);
1737 }
1738
1739 if(UI.nMouseRight)
1740 {
1741 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1742 {
1743 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
1744 }
1745 }
1746 }
1747
1748 return bMouseOver;
1749}
1750
1751void MicroProfileDumpTimers()
1752{
1753 MicroProfile& S = *MicroProfileGet();
1754
1755 uint64_t nActiveGroup = S.nGroupMask;
1756
1757 uint32_t nNumTimers = S.nTotalTimers;
1758 uint32_t nBlockSize = 2 * nNumTimers;
1759 float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1760 float* pAverage = pTimers + nBlockSize;
1761 float* pMax = pTimers + 2 * nBlockSize;
1762 float* pCallAverage = pTimers + 3 * nBlockSize;
1763 float* pTimersExclusive = pTimers + 4 * nBlockSize;
1764 float* pAverageExclusive = pTimers + 5 * nBlockSize;
1765 float* pMaxExclusive = pTimers + 6 * nBlockSize;
1766 MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1767
1768 MICROPROFILE_PRINTF("%11s, ", "Time");
1769 MICROPROFILE_PRINTF("%11s, ", "Average");
1770 MICROPROFILE_PRINTF("%11s, ", "Max");
1771 MICROPROFILE_PRINTF("%11s, ", "Call Avg");
1772 MICROPROFILE_PRINTF("%9s, ", "Count");
1773 MICROPROFILE_PRINTF("%11s, ", "Excl");
1774 MICROPROFILE_PRINTF("%11s, ", "Avg Excl");
1775 MICROPROFILE_PRINTF("%11s, \n", "Max Excl");
1776
1777 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1778 {
1779 uint64_t nMask = 1ll << j;
1780 if(nMask & nActiveGroup)
1781 {
1782 MICROPROFILE_PRINTF("%s\n", S.GroupInfo[j].pName);
1783 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1784 {
1785 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1786 if(nTokenMask & nMask)
1787 {
1788 uint32_t nIdx = i * 2;
1789 MICROPROFILE_PRINTF("%9.2fms, ", pTimers[nIdx]);
1790 MICROPROFILE_PRINTF("%9.2fms, ", pAverage[nIdx]);
1791 MICROPROFILE_PRINTF("%9.2fms, ", pMax[nIdx]);
1792 MICROPROFILE_PRINTF("%9.2fms, ", pCallAverage[nIdx]);
1793 MICROPROFILE_PRINTF("%9d, ", S.Frame[i].nCount);
1794 MICROPROFILE_PRINTF("%9.2fms, ", pTimersExclusive[nIdx]);
1795 MICROPROFILE_PRINTF("%9.2fms, ", pAverageExclusive[nIdx]);
1796 MICROPROFILE_PRINTF("%9.2fms, ", pMaxExclusive[nIdx]);
1797 MICROPROFILE_PRINTF("%s\n", S.TimerInfo[i].pName);
1798 }
1799 }
1800 }
1801 }
1802}
1803
1804void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeight)
1805{
1806 MicroProfile& S = *MicroProfileGet();
1807
1808 uint64_t nActiveGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1809 if(!nActiveGroup)
1810 return;
1811 MICROPROFILE_SCOPE(g_MicroProfileDrawBarView);
1812
1813 const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1814 int nColorIndex = 0;
1815 uint32_t nMaxTimerNameLen = 1;
1816 uint32_t nNumTimers = 0;
1817 uint32_t nNumGroups = 0;
1818 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1819 {
1820 if(nActiveGroup & (1ll << j))
1821 {
1822 nNumTimers += S.GroupInfo[j].nNumTimers;
1823 nNumGroups += 1;
1824 nMaxTimerNameLen = MicroProfileMax(nMaxTimerNameLen, S.GroupInfo[j].nMaxTimerNameLen);
1825 }
1826 }
1827 uint32_t nTimerWidth = 2+(4+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1828 uint32_t nX = nTimerWidth + UI.nOffsetX;
1829 uint32_t nY = nHeight + 3 - UI.nOffsetY;
1830 uint32_t nBlockSize = 2 * nNumTimers;
1831 float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1832 float* pAverage = pTimers + nBlockSize;
1833 float* pMax = pTimers + 2 * nBlockSize;
1834 float* pCallAverage = pTimers + 3 * nBlockSize;
1835 float* pTimersExclusive = pTimers + 4 * nBlockSize;
1836 float* pAverageExclusive = pTimers + 5 * nBlockSize;
1837 float* pMaxExclusive = pTimers + 6 * nBlockSize;
1838 MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1839 uint32_t nWidth = 0;
1840 {
1841 uint32_t nMetaIndex = 0;
1842 for(uint32_t i = 1; i ; i <<= 1)
1843 {
1844 if(S.nBars & i)
1845 {
1846 if(i >= MP_DRAW_META_FIRST)
1847 {
1848 if(nMetaIndex < MICROPROFILE_META_MAX && S.MetaCounters[nMetaIndex].pName)
1849 {
1850 uint32_t nStrWidth = strlen(S.MetaCounters[nMetaIndex].pName);
1851 if(S.nBars & MP_DRAW_TIMERS)
1852 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth);
1853 if(S.nBars & MP_DRAW_AVERAGE)
1854 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1855 if(S.nBars & MP_DRAW_MAX)
1856 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1857 }
1858 }
1859 else
1860 {
1861 nWidth += MICROPROFILE_BAR_WIDTH + 6 + 6 * (1+MICROPROFILE_TEXT_WIDTH);
1862 if(i & MP_DRAW_CALL_COUNT)
1863 nWidth += 6 + 6 * MICROPROFILE_TEXT_WIDTH;
1864 }
1865 }
1866 if(i >= MP_DRAW_META_FIRST)
1867 {
1868 ++nMetaIndex;
1869 }
1870 }
1871 nWidth += (1+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1872 for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1873 {
1874 uint32_t nY0 = nY + i * (nHeight + 1);
1875 bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1876 MicroProfileDrawBox(nX, nY0, nWidth+nX, nY0 + (nHeight+1)+1, UI.nOpacityBackground | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1877 }
1878 nX += 10;
1879 }
1880 int nTotalHeight = (nNumTimers+nNumGroups+1) * (nHeight+1);
1881 uint32_t nLegendOffset = 1;
1882 if(S.nBars & MP_DRAW_TIMERS)
1883 nX += MicroProfileDrawBarArray(nX, nY, pTimers, "Time", nTotalHeight) + 1;
1884 if(S.nBars & MP_DRAW_AVERAGE)
1885 nX += MicroProfileDrawBarArray(nX, nY, pAverage, "Average", nTotalHeight) + 1;
1886 if(S.nBars & MP_DRAW_MAX)
1887 nX += MicroProfileDrawBarArray(nX, nY, pMax, (!UI.bShowSpikes) ? "Max Time" : "Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverage : NULL) + 1;
1888 if(S.nBars & MP_DRAW_CALL_COUNT)
1889 {
1890 nX += MicroProfileDrawBarArray(nX, nY, pCallAverage, "Call Average", nTotalHeight) + 1;
1891 nX += MicroProfileDrawBarCallCount(nX, nY, "Count") + 1;
1892 }
1893 if(S.nBars & MP_DRAW_TIMERS_EXCLUSIVE)
1894 nX += MicroProfileDrawBarArray(nX, nY, pTimersExclusive, "Exclusive Time", nTotalHeight) + 1;
1895 if(S.nBars & MP_DRAW_AVERAGE_EXCLUSIVE)
1896 nX += MicroProfileDrawBarArray(nX, nY, pAverageExclusive, "Exclusive Average", nTotalHeight) + 1;
1897 if(S.nBars & MP_DRAW_MAX_EXCLUSIVE)
1898 nX += MicroProfileDrawBarArray(nX, nY, pMaxExclusive, (!UI.bShowSpikes) ? "Exclusive Max Time" :"Excl Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverageExclusive : NULL) + 1;
1899
1900 for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
1901 {
1902 if(0 != (S.nBars & (MP_DRAW_META_FIRST<<i)) && S.MetaCounters[i].pName)
1903 {
1904 uint32_t nBufferSize = strlen(S.MetaCounters[i].pName) + 32;
1905 char* buffer = (char*)alloca(nBufferSize);
1906 if(S.nBars & MP_DRAW_TIMERS)
1907 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nCounters[0], S.MetaCounters[i].pName, nTotalHeight) + 1;
1908 if(S.nBars & MP_DRAW_AVERAGE)
1909 {
1910 snprintf(buffer, nBufferSize-1, "%s Avg", S.MetaCounters[i].pName);
1911 nX += MicroProfileDrawBarMetaAverage(nX, nY, &S.MetaCounters[i].nAggregate[0], buffer, nTotalHeight) + 1;
1912 }
1913 if(S.nBars & MP_DRAW_MAX)
1914 {
1915 snprintf(buffer, nBufferSize-1, "%s Max", S.MetaCounters[i].pName);
1916 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nAggregateMax[0], buffer, nTotalHeight) + 1;
1917 }
1918 }
1919 }
1920 nX = 0;
1921 nY = nHeight + 3 - UI.nOffsetY;
1922 for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1923 {
1924 uint32_t nY0 = nY + i * (nHeight + 1);
1925 bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1926 MicroProfileDrawBox(nX, nY0, nTimerWidth, nY0 + (nHeight+1)+1, 0xff0000000 | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1927 }
1928 nX += MicroProfileDrawBarLegend(nX, nY, nTotalHeight, nTimerWidth-5) + 1;
1929
1930 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1931 {
1932 if(nActiveGroup & (1ll << j))
1933 {
1934 MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, (uint32_t)-1, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
1935 nLegendOffset += S.GroupInfo[j].nNumTimers+1;
1936 }
1937 }
1938 MicroProfileDrawHeader(nX, nTimerWidth-5, "Group");
1939 MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, "Timer", 5);
1940 MicroProfileDrawLineVertical(nTimerWidth, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1941 MicroProfileDrawLineHorizontal(0, nWidth, 2*MICROPROFILE_TEXT_HEIGHT + 3, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1942}
1943
1944typedef const char* (*MicroProfileSubmenuCallback)(int, bool* bSelected);
1945typedef void (*MicroProfileClickCallback)(int);
1946
1947
1948const char* MicroProfileUIMenuMode(int nIndex, bool* bSelected)
1949{
1950 MicroProfile& S = *MicroProfileGet();
1951 switch(nIndex)
1952 {
1953 case 0:
1954 *bSelected = S.nDisplay == MP_DRAW_DETAILED;
1955 return "Detailed";
1956 case 1:
1957 *bSelected = S.nDisplay == MP_DRAW_BARS;
1958 return "Timers";
1959 case 2:
1960 *bSelected = S.nDisplay == MP_DRAW_HIDDEN;
1961 return "Hidden";
1962 case 3:
1963 *bSelected = true;
1964 return "Off";
1965 case 4:
1966 *bSelected = true;
1967 return "------";
1968 case 5:
1969 *bSelected = S.nForceEnable != 0;
1970 return "Force Enable";
1971
1972 default: return 0;
1973 }
1974}
1975
1976const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
1977{
1978 MicroProfile& S = *MicroProfileGet();
1979 *bSelected = false;
1980 if(nIndex == 0)
1981 {
1982 *bSelected = S.nAllGroupsWanted != 0;
1983 return "[ALL]";
1984 }
1985 else
1986 {
1987 nIndex = nIndex-1;
1988 if(nIndex < UI.GroupMenuCount)
1989 {
1990 MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
1991 static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
1992 if(Item.nIsCategory)
1993 {
1994 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
1995 *bSelected = nGroupMask == (nGroupMask & S.nActiveGroupWanted);
1996 snprintf(buffer, sizeof(buffer)-1, "[%s]", Item.pName);
1997 }
1998 else
1999 {
2000 *bSelected = 0 != (S.nActiveGroupWanted & (1ll << Item.nIndex));
2001 snprintf(buffer, sizeof(buffer)-1, " %s", Item.pName);
2002 }
2003 return buffer;
2004 }
2005 return 0;
2006 }
2007}
2008
2009const char* MicroProfileUIMenuAggregate(int nIndex, bool* bSelected)
2010{
2011 MicroProfile& S = *MicroProfileGet();
2012 if(nIndex < sizeof(g_MicroProfileAggregatePresets)/sizeof(g_MicroProfileAggregatePresets[0]))
2013 {
2014 int val = g_MicroProfileAggregatePresets[nIndex];
2015 *bSelected = (int)S.nAggregateFlip == val;
2016 if(0 == val)
2017 return "Infinite";
2018 else
2019 {
2020 static char buf[128];
2021 snprintf(buf, sizeof(buf)-1, "%7d", val);
2022 return buf;
2023 }
2024 }
2025 return 0;
2026
2027}
2028
2029const char* MicroProfileUIMenuTimers(int nIndex, bool* bSelected)
2030{
2031 MicroProfile& S = *MicroProfileGet();
2032 *bSelected = 0 != (S.nBars & (1 << nIndex));
2033 switch(nIndex)
2034 {
2035 case 0: return "Time";
2036 case 1: return "Average";
2037 case 2: return "Max";
2038 case 3: return "Call Count";
2039 case 4: return "Exclusive Timers";
2040 case 5: return "Exclusive Average";
2041 case 6: return "Exclusive Max";
2042 }
2043 int nMetaIndex = nIndex - 7;
2044 if(nMetaIndex < MICROPROFILE_META_MAX)
2045 {
2046 return S.MetaCounters[nMetaIndex].pName;
2047 }
2048 return 0;
2049}
2050
2051const char* MicroProfileUIMenuOptions(int nIndex, bool* bSelected)
2052{
2053 MicroProfile& S = *MicroProfileGet();
2054 if(nIndex >= MICROPROFILE_OPTION_SIZE) return 0;
2055 switch(UI.Options[nIndex].nSubType)
2056 {
2057 case 0:
2058 *bSelected = S.fReferenceTime == g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2059 break;
2060 case 1:
2061 *bSelected = UI.nOpacityBackground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2062 break;
2063 case 2:
2064 *bSelected = UI.nOpacityForeground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2065 break;
2066 case 3:
2067 *bSelected = UI.bShowSpikes;
2068 break;
2069#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2070 case 4:
2071 {
2072 switch(UI.Options[nIndex].nIndex)
2073 {
2074 case 0:
2075 *bSelected = S.bContextSwitchRunning;
2076 break;
2077 case 1:
2078 *bSelected = S.bContextSwitchAllThreads;
2079 break;
2080 case 2:
2081 *bSelected = S.bContextSwitchNoBars;
2082 break;
2083 }
2084 }
2085 break;
2086#endif
2087 }
2088 return UI.Options[nIndex].Text;
2089}
2090
2091const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
2092{
2093 static char buf[128];
2094 *bSelected = false;
2095 int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
2096 int nIndexSave = nIndex - nNumPresets - 1;
2097 if(nIndex == nNumPresets)
2098 return "--";
2099 else if(nIndexSave >=0 && nIndexSave <nNumPresets)
2100 {
2101 snprintf(buf, sizeof(buf)-1, "Save '%s'", g_MicroProfilePresetNames[nIndexSave]);
2102 return buf;
2103 }
2104 else if(nIndex < nNumPresets)
2105 {
2106 snprintf(buf, sizeof(buf)-1, "Load '%s'", g_MicroProfilePresetNames[nIndex]);
2107 return buf;
2108 }
2109 else
2110 {
2111 return 0;
2112 }
2113}
2114
2115const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
2116{
2117 if((uint32_t)-1 == UI.nCustomActive)
2118 {
2119 *bSelected = nIndex == 0;
2120 }
2121 else
2122 {
2123 *bSelected = nIndex-2 == UI.nCustomActive;
2124 }
2125 switch(nIndex)
2126 {
2127 case 0: return "Disable";
2128 case 1: return "--";
2129 default:
2130 nIndex -= 2;
2131 if(nIndex < UI.nCustomCount)
2132 {
2133 return UI.Custom[nIndex].pName;
2134 }
2135 else
2136 {
2137 return 0;
2138 }
2139 }
2140}
2141
2142const char* MicroProfileUIMenuEmpty(int nIndex, bool* bSelected)
2143{
2144 return 0;
2145}
2146
2147
2148void MicroProfileUIClickMode(int nIndex)
2149{
2150 MicroProfile& S = *MicroProfileGet();
2151 switch(nIndex)
2152 {
2153 case 0:
2154 S.nDisplay = MP_DRAW_DETAILED;
2155 break;
2156 case 1:
2157 S.nDisplay = MP_DRAW_BARS;
2158 break;
2159 case 2:
2160 S.nDisplay = MP_DRAW_HIDDEN;
2161 break;
2162 case 3:
2163 S.nDisplay = 0;
2164 break;
2165 case 4:
2166 break;
2167 case 5:
2168 S.nForceEnable = !S.nForceEnable;
2169 break;
2170 }
2171}
2172
2173void MicroProfileUIClickGroups(int nIndex)
2174{
2175 MicroProfile& S = *MicroProfileGet();
2176 if(nIndex == 0)
2177 S.nAllGroupsWanted = 1-S.nAllGroupsWanted;
2178 else
2179 {
2180 nIndex -= 1;
2181 if(nIndex < UI.GroupMenuCount)
2182 {
2183 MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
2184 if(Item.nIsCategory)
2185 {
2186 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
2187 if(nGroupMask != (nGroupMask & S.nActiveGroupWanted))
2188 {
2189 S.nActiveGroupWanted |= nGroupMask;
2190 }
2191 else
2192 {
2193 S.nActiveGroupWanted &= ~nGroupMask;
2194 }
2195 }
2196 else
2197 {
2198 MP_ASSERT(Item.nIndex < S.nGroupCount);
2199 S.nActiveGroupWanted ^= (1ll << Item.nIndex);
2200 }
2201 }
2202 }
2203}
2204
2205void MicroProfileUIClickAggregate(int nIndex)
2206{
2207 MicroProfile& S = *MicroProfileGet();
2208 S.nAggregateFlip = g_MicroProfileAggregatePresets[nIndex];
2209 if(0 == S.nAggregateFlip)
2210 {
2211 S.nAggregateClear = 1;
2212 }
2213}
2214
2215void MicroProfileUIClickTimers(int nIndex)
2216{
2217 MicroProfile& S = *MicroProfileGet();
2218 S.nBars ^= (1 << nIndex);
2219}
2220
2221void MicroProfileUIClickOptions(int nIndex)
2222{
2223 MicroProfile& S = *MicroProfileGet();
2224 switch(UI.Options[nIndex].nSubType)
2225 {
2226 case 0:
2227 S.fReferenceTime = g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2228 S.fRcpReferenceTime = 1.f / S.fReferenceTime;
2229 break;
2230 case 1:
2231 UI.nOpacityBackground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2232 break;
2233 case 2:
2234 UI.nOpacityForeground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2235 break;
2236 case 3:
2237 UI.bShowSpikes = !UI.bShowSpikes;
2238 break;
2239#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2240 case 4:
2241 {
2242 switch(UI.Options[nIndex].nIndex)
2243 {
2244 case 0:
2245 if(S.bContextSwitchRunning)
2246 {
2247 MicroProfileStopContextSwitchTrace();
2248 }
2249 else
2250 {
2251 MicroProfileStartContextSwitchTrace();
2252 }
2253 break;
2254 case 1:
2255 S.bContextSwitchAllThreads = !S.bContextSwitchAllThreads;
2256 break;
2257 case 2:
2258 S.bContextSwitchNoBars= !S.bContextSwitchNoBars;
2259 break;
2260
2261 }
2262 }
2263 break;
2264#endif
2265 }
2266}
2267
2268void MicroProfileUIClickPreset(int nIndex)
2269{
2270 int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
2271 int nIndexSave = nIndex - nNumPresets - 1;
2272 if(nIndexSave >= 0 && nIndexSave < nNumPresets)
2273 {
2274 MicroProfileSavePreset(g_MicroProfilePresetNames[nIndexSave]);
2275 }
2276 else if(nIndex >= 0 && nIndex < nNumPresets)
2277 {
2278 MicroProfileLoadPreset(g_MicroProfilePresetNames[nIndex]);
2279 }
2280}
2281
2282void MicroProfileUIClickCustom(int nIndex)
2283{
2284 if(nIndex == 0)
2285 {
2286 MicroProfileCustomGroupDisable();
2287 }
2288 else
2289 {
2290 MicroProfileCustomGroupEnable(nIndex-2);
2291 }
2292
2293}
2294
2295void MicroProfileUIClickEmpty(int nIndex)
2296{
2297
2298}
2299
2300
2301void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
2302{
2303 MicroProfile& S = *MicroProfileGet();
2304
2305 uint32_t nX = 0;
2306 uint32_t nY = 0;
2307 bool bMouseOver = UI.nMouseY < MICROPROFILE_TEXT_HEIGHT + 1;
2308#define SBUF_SIZE 256
2309 char buffer[256];
2310 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + (MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff000000|g_nMicroProfileBackColors[1]);
2311
2312#define MICROPROFILE_MENU_MAX 16
2313 const char* pMenuText[MICROPROFILE_MENU_MAX] = {0};
2314 uint32_t nMenuX[MICROPROFILE_MENU_MAX] = {0};
2315 uint32_t nNumMenuItems = 0;
2316
2317 int nLen = snprintf(buffer, 127, "MicroProfile");
2318 MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
2319 nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
2320 pMenuText[nNumMenuItems++] = "Mode";
2321 pMenuText[nNumMenuItems++] = "Groups";
2322 char AggregateText[64];
2323 snprintf(AggregateText, sizeof(AggregateText)-1, "Aggregate[%d]", S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount);
2324 pMenuText[nNumMenuItems++] = &AggregateText[0];
2325 pMenuText[nNumMenuItems++] = "Timers";
2326 pMenuText[nNumMenuItems++] = "Options";
2327 pMenuText[nNumMenuItems++] = "Preset";
2328 pMenuText[nNumMenuItems++] = "Custom";
2329 const int nPauseIndex = nNumMenuItems;
2330 pMenuText[nNumMenuItems++] = S.nRunning ? "Pause" : "Unpause";
2331 pMenuText[nNumMenuItems++] = "Help";
2332
2333 if(S.nOverflow)
2334 {
2335 pMenuText[nNumMenuItems++] = "!BUFFERSFULL!";
2336 }
2337
2338
2339 if(UI.GroupMenuCount != S.nGroupCount + S.nCategoryCount)
2340 {
2341 UI.GroupMenuCount = S.nGroupCount + S.nCategoryCount;
2342 for(uint32_t i = 0; i < S.nCategoryCount; ++i)
2343 {
2344 UI.GroupMenu[i].nIsCategory = 1;
2345 UI.GroupMenu[i].nCategoryIndex = i;
2346 UI.GroupMenu[i].nIndex = i;
2347 UI.GroupMenu[i].pName = S.CategoryInfo[i].pName;
2348 }
2349 for(uint32_t i = 0; i < S.nGroupCount; ++i)
2350 {
2351 uint32_t idx = i + S.nCategoryCount;
2352 UI.GroupMenu[idx].nIsCategory = 0;
2353 UI.GroupMenu[idx].nCategoryIndex = S.GroupInfo[i].nCategory;
2354 UI.GroupMenu[idx].nIndex = i;
2355 UI.GroupMenu[idx].pName = S.GroupInfo[i].pName;
2356 }
2357 std::sort(&UI.GroupMenu[0], &UI.GroupMenu[UI.GroupMenuCount],
2358 [] (const MicroProfileGroupMenuItem& l, const MicroProfileGroupMenuItem& r) -> bool
2359 {
2360 if(l.nCategoryIndex < r.nCategoryIndex)
2361 {
2362 return true;
2363 }
2364 else if(r.nCategoryIndex < l.nCategoryIndex)
2365 {
2366 return false;
2367 }
2368 if(r.nIsCategory || l.nIsCategory)
2369 {
2370 return l.nIsCategory > r.nIsCategory;
2371 }
2372 return MP_STRCASECMP(l.pName, r.pName)<0;
2373 }
2374 );
2375 }
2376
2377 MicroProfileSubmenuCallback GroupCallback[MICROPROFILE_MENU_MAX] =
2378 {
2379 MicroProfileUIMenuMode,
2380 MicroProfileUIMenuGroups,
2381 MicroProfileUIMenuAggregate,
2382 MicroProfileUIMenuTimers,
2383 MicroProfileUIMenuOptions,
2384 MicroProfileUIMenuPreset,
2385 MicroProfileUIMenuCustom,
2386 MicroProfileUIMenuEmpty,
2387 MicroProfileUIMenuEmpty,
2388 MicroProfileUIMenuEmpty,
2389 };
2390
2391 MicroProfileClickCallback CBClick[MICROPROFILE_MENU_MAX] =
2392 {
2393 MicroProfileUIClickMode,
2394 MicroProfileUIClickGroups,
2395 MicroProfileUIClickAggregate,
2396 MicroProfileUIClickTimers,
2397 MicroProfileUIClickOptions,
2398 MicroProfileUIClickPreset,
2399 MicroProfileUIClickCustom,
2400 MicroProfileUIClickEmpty,
2401 MicroProfileUIClickEmpty,
2402 MicroProfileUIClickEmpty,
2403 };
2404
2405
2406 uint32_t nSelectMenu = (uint32_t)-1;
2407 for(uint32_t i = 0; i < nNumMenuItems; ++i)
2408 {
2409 nMenuX[i] = nX;
2410 uint32_t nLen = (uint32_t)strlen(pMenuText[i]);
2411 uint32_t nEnd = nX + nLen * (MICROPROFILE_TEXT_WIDTH+1);
2412 if(UI.nMouseY <= MICROPROFILE_TEXT_HEIGHT && UI.nMouseX <= nEnd && UI.nMouseX >= nX)
2413 {
2414 MicroProfileDrawBox(nX-1, nY, nX + nLen * (MICROPROFILE_TEXT_WIDTH+1), nY +(MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff888888);
2415 nSelectMenu = i;
2416 if((UI.nMouseLeft || UI.nMouseRight) && i == (int)nPauseIndex)
2417 {
2418 S.nToggleRunning = 1;
2419 }
2420 }
2421 MicroProfileDrawText(nX, nY, (uint32_t)-1, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
2422 nX += (nLen+1) * (MICROPROFILE_TEXT_WIDTH+1);
2423 }
2424 uint32_t nMenu = nSelectMenu != (uint32_t)-1 ? nSelectMenu : UI.nActiveMenu;
2425 UI.nActiveMenu = nMenu;
2426 if((uint32_t)-1 != nMenu)
2427 {
2428 nX = nMenuX[nMenu];
2429 nY += MICROPROFILE_TEXT_HEIGHT+1;
2430 MicroProfileSubmenuCallback CB = GroupCallback[nMenu];
2431 int nNumLines = 0;
2432 bool bSelected = false;
2433 const char* pString = CB(nNumLines, &bSelected);
2434 uint32_t nWidth = 0, nHeight = 0;
2435 while(pString)
2436 {
2437 nWidth = MicroProfileMax<int>(nWidth, (int)strlen(pString));
2438 nNumLines++;
2439 pString = CB(nNumLines, &bSelected);
2440 }
2441 nWidth = (2+nWidth) * (MICROPROFILE_TEXT_WIDTH+1);
2442 nHeight = nNumLines * (MICROPROFILE_TEXT_HEIGHT+1);
2443 if(UI.nMouseY <= nY + nHeight+0 && UI.nMouseY >= nY-0 && UI.nMouseX <= nX + nWidth + 0 && UI.nMouseX >= nX - 0)
2444 {
2445 UI.nActiveMenu = nMenu;
2446 }
2447 else if(nSelectMenu == (uint32_t)-1)
2448 {
2449 UI.nActiveMenu = (uint32_t)-1;
2450 }
2451 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
2452 for(int i = 0; i < nNumLines; ++i)
2453 {
2454 bool bSelected = false;
2455 const char* pString = CB(i, &bSelected);
2456 if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
2457 {
2458 bMouseOver = true;
2459 if(UI.nMouseLeft || UI.nMouseRight)
2460 {
2461 CBClick[nMenu](i);
2462 }
2463 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
2464 }
2465 int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
2466 MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
2467 nY += MICROPROFILE_TEXT_HEIGHT+1;
2468 }
2469 }
2470
2471
2472 {
2473 static char FrameTimeMessage[64];
2474 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2475 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2476 float fMs = fToMs * (S.nFlipTicks);
2477 float fAverageMs = fToMs * (S.nFlipAggregateDisplay / nAggregateFrames);
2478 float fMaxMs = fToMs * S.nFlipMaxDisplay;
2479 int nLen = snprintf(FrameTimeMessage, sizeof(FrameTimeMessage)-1, "Time[%6.2f] Avg[%6.2f] Max[%6.2f]", fMs, fAverageMs, fMaxMs);
2480 pMenuText[nNumMenuItems++] = &FrameTimeMessage[0];
2481 MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, -1, FrameTimeMessage, nLen);
2482 }
2483}
2484
2485
2486void MicroProfileMoveGraph()
2487{
2488
2489 int nZoom = UI.nMouseWheelDelta;
2490 int nPanX = 0;
2491 int nPanY = 0;
2492 static int X = 0, Y = 0;
2493 if(UI.nMouseDownLeft && !UI.nModDown)
2494 {
2495 nPanX = UI.nMouseX - X;
2496 nPanY = UI.nMouseY - Y;
2497 }
2498 X = UI.nMouseX;
2499 Y = UI.nMouseY;
2500
2501 if(nZoom)
2502 {
2503 float fOldRange = UI.fDetailedRange;
2504 if(nZoom>0)
2505 {
2506 UI.fDetailedRangeTarget = UI.fDetailedRange *= UI.nModDown ? 1.40f : 1.05f;
2507 }
2508 else
2509 {
2510 float fNewDetailedRange = UI.fDetailedRange / (UI.nModDown ? 1.40f : 1.05f);
2511 if(fNewDetailedRange < 1e-4f) //100ns
2512 fNewDetailedRange = 1e-4f;
2513 UI.fDetailedRangeTarget = UI.fDetailedRange = fNewDetailedRange;
2514 }
2515
2516 float fDiff = fOldRange - UI.fDetailedRange;
2517 float fMousePrc = MicroProfileMax((float)UI.nMouseX / UI.nWidth ,0.f);
2518 UI.fDetailedOffsetTarget = UI.fDetailedOffset += fDiff * fMousePrc;
2519
2520 }
2521 if(nPanX)
2522 {
2523 UI.fDetailedOffsetTarget = UI.fDetailedOffset += -nPanX * UI.fDetailedRange / UI.nWidth;
2524 }
2525 UI.nOffsetY -= nPanY;
2526 UI.nOffsetX += nPanX;
2527 if(UI.nOffsetX > 0)
2528 UI.nOffsetX = 0;
2529 if(UI.nOffsetY<0)
2530 UI.nOffsetY = 0;
2531}
2532
2533void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
2534{
2535 if((uint32_t)-1 != UI.nCustomActive)
2536 {
2537 MicroProfile& S = *MicroProfileGet();
2538 MP_ASSERT(UI.nCustomActive < MICROPROFILE_CUSTOM_MAX);
2539 MicroProfileCustom* pCustom = &UI.Custom[UI.nCustomActive];
2540 uint32_t nCount = pCustom->nNumTimers;
2541 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2542 uint32_t nExtraOffset = 1 + ((pCustom->nFlags & MICROPROFILE_CUSTOM_STACK) != 0 ? 3 : 0);
2543 uint32_t nOffsetYBase = nHeight - (nExtraOffset+nCount)* (1+MICROPROFILE_TEXT_HEIGHT) - MICROPROFILE_CUSTOM_PADDING;
2544 uint32_t nOffsetY = nOffsetYBase;
2545 float fReference = pCustom->fReference;
2546 float fRcpReference = 1.f / fReference;
2547 uint32_t nReducedWidth = UI.nWidth - 2*MICROPROFILE_CUSTOM_PADDING - MICROPROFILE_GRAPH_WIDTH;
2548
2549 char Buffer[MICROPROFILE_NAME_MAX_LEN*2+1];
2550 float* pTime = (float*)alloca(sizeof(float)*nCount);
2551 float* pTimeAvg = (float*)alloca(sizeof(float)*nCount);
2552 float* pTimeMax = (float*)alloca(sizeof(float)*nCount);
2553 uint32_t* pColors = (uint32_t*)alloca(sizeof(uint32_t)*nCount);
2554 uint32_t nMaxOffsetX = 0;
2555 MicroProfileDrawBox(MICROPROFILE_CUSTOM_PADDING-1, nOffsetY-1, MICROPROFILE_CUSTOM_PADDING+nReducedWidth+1, UI.nHeight - MICROPROFILE_CUSTOM_PADDING+1, 0x88000000|g_nMicroProfileBackColors[0]);
2556
2557 for(uint32_t i = 0; i < nCount; ++i)
2558 {
2559 uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2560 uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2561 float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
2562 pTime[i] = S.Frame[nTimerIndex].nTicks * fToMs;
2563 pTimeAvg[i] = fToMs * (S.Aggregate[nTimerIndex].nTicks / nAggregateFrames);
2564 pTimeMax[i] = fToMs * (S.AggregateMax[nTimerIndex]);
2565 pColors[i] = S.TimerInfo[nTimerIndex].nColor;
2566 }
2567
2568 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Avg", sizeof("Avg")-1);
2569 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Max", sizeof("Max")-1);
2570 for(uint32_t i = 0; i < nCount; ++i)
2571 {
2572 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2573 uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2574 uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2575 MicroProfileTimerInfo* pTimerInfo = &S.TimerInfo[nTimerIndex];
2576 int nSize;
2577 uint32_t nOffsetX = MICROPROFILE_CUSTOM_PADDING;
2578 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeAvg[i]);
2579 MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
2580 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2581 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeMax[i]);
2582 MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
2583 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2584 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%s:%s", S.GroupInfo[nGroupIndex].pName, pTimerInfo->pName);
2585 MicroProfileDrawText(nOffsetX, nOffsetY, pTimerInfo->nColor, Buffer, nSize);
2586 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2587 nMaxOffsetX = MicroProfileMax(nMaxOffsetX, nOffsetX);
2588 }
2589 uint32_t nMaxWidth = nReducedWidth- nMaxOffsetX;
2590
2591 if(pCustom->nFlags & MICROPROFILE_CUSTOM_BARS)
2592 {
2593 nOffsetY = nOffsetYBase;
2594 float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? pTimeMax : pTimeAvg;
2595 const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? "Max" : "Avg";
2596 MicroProfileDrawText(nMaxOffsetX, nOffsetY, (uint32_t)-1, pString, strlen(pString));
2597 int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2598 MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
2599 for(uint32_t i = 0; i < nCount; ++i)
2600 {
2601 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2602 uint32_t nWidth = MicroProfileMin(nMaxWidth, (uint32_t)(nMaxWidth * pMs[i] * fRcpReference));
2603 MicroProfileDrawBox(nMaxOffsetX, nOffsetY, nMaxOffsetX+nWidth, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2604 }
2605 }
2606 if(pCustom->nFlags & MICROPROFILE_CUSTOM_STACK)
2607 {
2608 nOffsetY += 2*(1+MICROPROFILE_TEXT_HEIGHT);
2609 const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? "Max" : "Avg";
2610 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, (uint32_t)-1, pString, strlen(pString));
2611 int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2612 MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
2613 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2614 float fPosX = MICROPROFILE_CUSTOM_PADDING;
2615 float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? pTimeMax : pTimeAvg;
2616 for(uint32_t i = 0; i < nCount; ++i)
2617 {
2618 float fWidth = pMs[i] * fRcpReference * nReducedWidth;
2619 uint32_t nX = fPosX;
2620 fPosX += fWidth;
2621 uint32_t nXEnd = fPosX;
2622 if(nX < nXEnd)
2623 {
2624 MicroProfileDrawBox(nX, nOffsetY, nXEnd, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2625 }
2626 }
2627 }
2628 }
2629}
2630void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
2631{
2632 MICROPROFILE_SCOPE(g_MicroProfileDraw);
2633 MicroProfile& S = *MicroProfileGet();
2634
2635 {
2636 static int once = 0;
2637 if(0 == once)
2638 {
2639 std::recursive_mutex& m = MicroProfileGetMutex();
2640 m.lock();
2641 MicroProfileInitUI();
2642
2643
2644
2645 uint32_t nDisplay = S.nDisplay;
2646 MicroProfileLoadPreset(MICROPROFILE_DEFAULT_PRESET);
2647 once++;
2648 S.nDisplay = nDisplay;// dont load display, just state
2649 m.unlock();
2650
2651 }
2652 }
2653
2654
2655 if(S.nDisplay)
2656 {
2657 std::recursive_mutex& m = MicroProfileGetMutex();
2658 m.lock();
2659 UI.nWidth = nWidth;
2660 UI.nHeight = nHeight;
2661 UI.nHoverToken = MICROPROFILE_INVALID_TOKEN;
2662 UI.nHoverTime = 0;
2663 UI.nHoverFrame = -1;
2664 if(S.nDisplay != MP_DRAW_DETAILED)
2665 S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
2666 MicroProfileMoveGraph();
2667
2668
2669 if(S.nDisplay == MP_DRAW_DETAILED)
2670 {
2671 MicroProfileDrawDetailedView(nWidth, nHeight);
2672 }
2673 else if(S.nDisplay == MP_DRAW_BARS && S.nBars)
2674 {
2675 MicroProfileDrawBarView(nWidth, nHeight);
2676 }
2677
2678 MicroProfileDrawMenu(nWidth, nHeight);
2679 bool bMouseOverGraph = MicroProfileDrawGraph(nWidth, nHeight);
2680 MicroProfileDrawCustom(nWidth, nHeight);
2681 bool bHidden = S.nDisplay == MP_DRAW_HIDDEN;
2682 if(!bHidden)
2683 {
2684 uint32_t nLockedToolTipX = 3;
2685 bool bDeleted = false;
2686 for(int i = 0; i < MICROPROFILE_TOOLTIP_MAX_LOCKED; ++i)
2687 {
2688 int nIndex = (g_MicroProfileUI.LockedToolTipFront + i) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2689 if(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0])
2690 {
2691 uint32_t nToolTipWidth = 0, nToolTipHeight = 0;
2692 MicroProfileFloatWindowSize(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings, g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, 0, nToolTipWidth, nToolTipHeight, 0);
2693 uint32_t nStartY = nHeight - nToolTipHeight - 2;
2694 if(!bDeleted && UI.nMouseY > nStartY && UI.nMouseX > nLockedToolTipX && UI.nMouseX <= nLockedToolTipX + nToolTipWidth && (UI.nMouseLeft || UI.nMouseRight) )
2695 {
2696 bDeleted = true;
2697 int j = i;
2698 for(; j < MICROPROFILE_TOOLTIP_MAX_LOCKED-1; ++j)
2699 {
2700 int nIndex0 = (g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2701 int nIndex1 = (g_MicroProfileUI.LockedToolTipFront + j+1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2702 MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex0], &g_MicroProfileUI.LockedToolTips[nIndex1]);
2703 }
2704 MicroProfileStringArrayClear(&g_MicroProfileUI.LockedToolTips[(g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED]);
2705 }
2706 else
2707 {
2708 MicroProfileDrawFloatWindow(nLockedToolTipX, nHeight-nToolTipHeight-2, &g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0], g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, g_MicroProfileUI.nLockedToolTipColor[nIndex]);
2709 nLockedToolTipX += nToolTipWidth + 4;
2710 }
2711 }
2712 }
2713
2714 if(UI.nActiveMenu == 8)
2715 {
2716 if(S.nDisplay & MP_DRAW_DETAILED)
2717 {
2718 MicroProfileStringArray DetailedHelp;
2719 MicroProfileStringArrayClear(&DetailedHelp);
2720 MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_LEFT);
2721 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Toggle Graph");
2722 MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_ALT);
2723 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2724 MicroProfileStringArrayFormat(&DetailedHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2725 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Lock Tooltip");
2726 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Drag");
2727 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Pan View");
2728 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Mouse Wheel");
2729 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2730 MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, DetailedHelp.ppStrings, DetailedHelp.nNumStrings, 0xff777777);
2731
2732 MicroProfileStringArray DetailedHistoryHelp;
2733 MicroProfileStringArrayClear(&DetailedHistoryHelp);
2734 MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_LEFT);
2735 MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Center View");
2736 MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_ALT);
2737 MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Zoom to frame");
2738 MicroProfileDrawFloatWindow(nWidth, 20, DetailedHistoryHelp.ppStrings, DetailedHistoryHelp.nNumStrings, 0xff777777);
2739
2740
2741
2742 }
2743 else if(0 != (S.nDisplay & MP_DRAW_BARS) && S.nBars)
2744 {
2745 MicroProfileStringArray BarHelp;
2746 MicroProfileStringArrayClear(&BarHelp);
2747 MicroProfileStringArrayFormat(&BarHelp, "%s", MICROPROFILE_HELP_LEFT);
2748 MicroProfileStringArrayAddLiteral(&BarHelp, "Toggle Graph");
2749 MicroProfileStringArrayFormat(&BarHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2750 MicroProfileStringArrayAddLiteral(&BarHelp, "Lock Tooltip");
2751 MicroProfileStringArrayAddLiteral(&BarHelp, "Drag");
2752 MicroProfileStringArrayAddLiteral(&BarHelp, "Pan View");
2753 MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, BarHelp.ppStrings, BarHelp.nNumStrings, 0xff777777);
2754
2755 }
2756 MicroProfileStringArray Debug;
2757 MicroProfileStringArrayClear(&Debug);
2758 MicroProfileStringArrayAddLiteral(&Debug, "Memory Usage");
2759 MicroProfileStringArrayFormat(&Debug, "%4.2fmb", S.nMemUsage / (1024.f * 1024.f));
2760 MicroProfileStringArrayAddLiteral(&Debug, "Web Server Port");
2761 MicroProfileStringArrayFormat(&Debug, "%d", MicroProfileWebServerPort());
2762 uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
2763 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
2764 MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
2765
2766
2767 MicroProfileStringArrayAddLiteral(&Debug, "");
2768 MicroProfileStringArrayAddLiteral(&Debug, "");
2769 MicroProfileStringArrayAddLiteral(&Debug, "Usage");
2770 MicroProfileStringArrayAddLiteral(&Debug, "markers [frames] ");
2771
2772#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2773 MicroProfileStringArrayAddLiteral(&Debug, "Context Switch");
2774 MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", S.nContextSwitchUsage, MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE / S.nContextSwitchUsage );
2775#endif
2776
2777 for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2778 {
2779 if(pFrameCurrent->nLogStart[i] && S.Pool[i])
2780 {
2781 uint32_t nEnd = pFrameNext->nLogStart[i];
2782 uint32_t nStart = pFrameCurrent->nLogStart[i];
2783 uint32_t nUsage = nStart < nEnd ? (nEnd - nStart) : (nEnd + MICROPROFILE_BUFFER_SIZE - nStart);
2784 uint32_t nFrameSupport = MICROPROFILE_BUFFER_SIZE / nUsage;
2785 MicroProfileStringArrayFormat(&Debug, "%s", &S.Pool[i]->ThreadName[0]);
2786 MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", nUsage, nFrameSupport);
2787 }
2788 }
2789
2790 MicroProfileDrawFloatWindow(0, nHeight-10, Debug.ppStrings, Debug.nNumStrings, 0xff777777);
2791 }
2792
2793
2794
2795 if(UI.nActiveMenu == -1 && !bMouseOverGraph)
2796 {
2797 if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2798 {
2799 MicroProfileDrawFloatTooltip(UI.nMouseX, UI.nMouseY, UI.nHoverToken, UI.nHoverTime);
2800 }
2801 else if(S.nContextSwitchHoverThreadAfter != -1 && S.nContextSwitchHoverThreadBefore != -1)
2802 {
2803 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2804 MicroProfileStringArray ToolTip;
2805 MicroProfileStringArrayClear(&ToolTip);
2806 MicroProfileStringArrayAddLiteral(&ToolTip, "Context Switch");
2807 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThread);
2808 MicroProfileStringArrayAddLiteral(&ToolTip, "Before");
2809 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadBefore);
2810 MicroProfileStringArrayAddLiteral(&ToolTip, "After");
2811 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadAfter);
2812 MicroProfileStringArrayAddLiteral(&ToolTip, "Duration");
2813 int64_t nDifference = MicroProfileLogTickDifference(S.nContextSwitchHoverTickIn, S.nContextSwitchHoverTickOut);
2814 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fToMs * nDifference );
2815 MicroProfileStringArrayAddLiteral(&ToolTip, "CPU");
2816 MicroProfileStringArrayFormat(&ToolTip, "%d", S.nContextSwitchHoverCpu);
2817 MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
2818
2819
2820 }
2821 else if(UI.nHoverFrame != -1)
2822 {
2823 uint32_t nNextFrame = (UI.nHoverFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY;
2824 int64_t nTick = S.Frames[UI.nHoverFrame].nFrameStartCpu;
2825 int64_t nTickNext = S.Frames[nNextFrame].nFrameStartCpu;
2826 int64_t nTickGpu = S.Frames[UI.nHoverFrame].nFrameStartGpu;
2827 int64_t nTickNextGpu = S.Frames[nNextFrame].nFrameStartGpu;
2828
2829 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2830 float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());
2831 float fMs = fToMs * (nTickNext - nTick);
2832 float fMsGpu = fToMsGpu * (nTickNextGpu - nTickGpu);
2833 MicroProfileStringArray ToolTip;
2834 MicroProfileStringArrayClear(&ToolTip);
2835 MicroProfileStringArrayFormat(&ToolTip, "Frame %d", UI.nHoverFrame);
2836 #if MICROPROFILE_DEBUG
2837 MicroProfileStringArrayFormat(&ToolTip, "%p", &S.Frames[UI.nHoverFrame]);
2838 #else
2839 MicroProfileStringArrayAddLiteral(&ToolTip, "");
2840 #endif
2841 MicroProfileStringArrayAddLiteral(&ToolTip, "CPU Time");
2842 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMs);
2843 MicroProfileStringArrayAddLiteral(&ToolTip, "GPU Time");
2844 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMsGpu);
2845 #if MICROPROFILE_DEBUG
2846 for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2847 {
2848 if(S.Frames[UI.nHoverFrame].nLogStart[i])
2849 {
2850 MicroProfileStringArrayFormat(&ToolTip, "%d", i);
2851 MicroProfileStringArrayFormat(&ToolTip, "%d", S.Frames[UI.nHoverFrame].nLogStart[i]);
2852 }
2853 }
2854 #endif
2855 MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
2856 }
2857 if(UI.nMouseLeft)
2858 {
2859 if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2860 MicroProfileToggleGraph(UI.nHoverToken);
2861 }
2862 }
2863 }
2864
2865#if MICROPROFILE_DRAWCURSOR
2866 {
2867 float fCursor[8] =
2868 {
2869 MicroProfileMax(0, (int)UI.nMouseX-3), UI.nMouseY,
2870 MicroProfileMin(nWidth, UI.nMouseX+3), UI.nMouseY,
2871 UI.nMouseX, MicroProfileMax((int)UI.nMouseY-3, 0),
2872 UI.nMouseX, MicroProfileMin(nHeight, UI.nMouseY+3),
2873 };
2874 MicroProfileDrawLine2D(2, &fCursor[0], 0xff00ff00);
2875 MicroProfileDrawLine2D(2, &fCursor[4], 0xff00ff00);
2876 }
2877#endif
2878 m.unlock();
2879 }
2880 else if(UI.nCustomActive != (uint32_t)-1)
2881 {
2882 std::recursive_mutex& m = MicroProfileGetMutex();
2883 m.lock();
2884 MicroProfileDrawGraph(nWidth, nHeight);
2885 MicroProfileDrawCustom(nWidth, nHeight);
2886 m.unlock();
2887
2888 }
2889 UI.nMouseLeft = UI.nMouseRight = 0;
2890 UI.nMouseLeftMod = UI.nMouseRightMod = 0;
2891 UI.nMouseWheelDelta = 0;
2892 if(S.nOverflow)
2893 S.nOverflow--;
2894
2895 UI.fDetailedOffset = UI.fDetailedOffset + (UI.fDetailedOffsetTarget - UI.fDetailedOffset) * MICROPROFILE_ANIM_DELAY_PRC;
2896 UI.fDetailedRange = UI.fDetailedRange + (UI.fDetailedRangeTarget - UI.fDetailedRange) * MICROPROFILE_ANIM_DELAY_PRC;
2897
2898
2899}
2900
2901bool MicroProfileIsDrawing()
2902{
2903 MicroProfile& S = *MicroProfileGet();
2904 return S.nDisplay != 0;
2905}
2906
2907void MicroProfileToggleGraph(MicroProfileToken nToken)
2908{
2909 MicroProfile& S = *MicroProfileGet();
2910 uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
2911 nToken &= 0xffff;
2912 int32_t nMinSort = 0x7fffffff;
2913 int32_t nFreeIndex = -1;
2914 int32_t nMinIndex = 0;
2915 int32_t nMaxSort = 0x80000000;
2916 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2917 {
2918 if(S.Graph[i].nToken == MICROPROFILE_INVALID_TOKEN)
2919 nFreeIndex = i;
2920 if(S.Graph[i].nToken == nToken)
2921 {
2922 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2923 S.TimerInfo[nTimerId].bGraph = false;
2924 return;
2925 }
2926 if(S.Graph[i].nKey < nMinSort)
2927 {
2928 nMinSort = S.Graph[i].nKey;
2929 nMinIndex = i;
2930 }
2931 if(S.Graph[i].nKey > nMaxSort)
2932 {
2933 nMaxSort = S.Graph[i].nKey;
2934 }
2935 }
2936 int nIndex = nFreeIndex > -1 ? nFreeIndex : nMinIndex;
2937 if (nFreeIndex == -1)
2938 {
2939 uint32_t idx = MicroProfileGetTimerIndex(S.Graph[nIndex].nToken);
2940 S.TimerInfo[idx].bGraph = false;
2941 }
2942 S.Graph[nIndex].nToken = nToken;
2943 S.Graph[nIndex].nKey = nMaxSort+1;
2944 memset(&S.Graph[nIndex].nHistory[0], 0, sizeof(S.Graph[nIndex].nHistory));
2945 S.TimerInfo[nTimerId].bGraph = true;
2946}
2947
2948
2949void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta)
2950{
2951 UI.nMouseX = nX;
2952 UI.nMouseY = nY;
2953 UI.nMouseWheelDelta = nWheelDelta;
2954}
2955
2956void MicroProfileModKey(uint32_t nKeyState)
2957{
2958 UI.nModDown = nKeyState ? 1 : 0;
2959}
2960
2961void MicroProfileClearGraph()
2962{
2963 MicroProfile& S = *MicroProfileGet();
2964 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2965 {
2966 if(S.Graph[i].nToken != 0)
2967 {
2968 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2969 }
2970 }
2971}
2972
2973void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight)
2974{
2975 bool bCanRelease = abs((int)(UI.nMouseDownX - UI.nMouseX)) + abs((int)(UI.nMouseDownY - UI.nMouseY)) < 3;
2976
2977 if(0 == nLeft && UI.nMouseDownLeft && bCanRelease)
2978 {
2979 if(UI.nModDown)
2980 UI.nMouseLeftMod = 1;
2981 else
2982 UI.nMouseLeft = 1;
2983 }
2984
2985 if(0 == nRight && UI.nMouseDownRight && bCanRelease)
2986 {
2987 if(UI.nModDown)
2988 UI.nMouseRightMod = 1;
2989 else
2990 UI.nMouseRight = 1;
2991 }
2992 if((nLeft || nRight) && !(UI.nMouseDownLeft || UI.nMouseDownRight))
2993 {
2994 UI.nMouseDownX = UI.nMouseX;
2995 UI.nMouseDownY = UI.nMouseY;
2996 }
2997
2998 UI.nMouseDownLeft = nLeft;
2999 UI.nMouseDownRight = nRight;
3000
3001}
3002
3003void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor)
3004{
3005 MicroProfileDrawBox(nX, nTop, nX + 1, nBottom, nColor);
3006}
3007
3008void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor)
3009{
3010 MicroProfileDrawBox(nLeft, nY, nRight, nY + 1, nColor);
3011}
3012
3013
3014
3015#include <stdio.h>
3016
3017#define MICROPROFILE_PRESET_HEADER_MAGIC 0x28586813
3018#define MICROPROFILE_PRESET_HEADER_VERSION 0x00000102
3019struct MicroProfilePresetHeader
3020{
3021 uint32_t nMagic;
3022 uint32_t nVersion;
3023 //groups, threads, aggregate, reference frame, graphs timers
3024 uint32_t nGroups[MICROPROFILE_MAX_GROUPS];
3025 uint32_t nThreads[MICROPROFILE_MAX_THREADS];
3026 uint32_t nGraphName[MICROPROFILE_MAX_GRAPHS];
3027 uint32_t nGraphGroupName[MICROPROFILE_MAX_GRAPHS];
3028 uint32_t nAllGroupsWanted;
3029 uint32_t nAllThreadsWanted;
3030 uint32_t nAggregateFlip;
3031 float fReferenceTime;
3032 uint32_t nBars;
3033 uint32_t nDisplay;
3034 uint32_t nOpacityBackground;
3035 uint32_t nOpacityForeground;
3036 uint32_t nShowSpikes;
3037};
3038
3039#ifndef MICROPROFILE_PRESET_FILENAME_FUNC
3040#define MICROPROFILE_PRESET_FILENAME_FUNC MicroProfilePresetFilename
3041static const char* MicroProfilePresetFilename(const char* pSuffix)
3042{
3043 static char filename[512];
3044 snprintf(filename, sizeof(filename)-1, ".microprofilepreset.%s", pSuffix);
3045 return filename;
3046}
3047#endif
3048
3049void MicroProfileSavePreset(const char* pPresetName)
3050{
3051 std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3052 FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pPresetName), "wb");
3053 if(!F) return;
3054
3055 MicroProfile& S = *MicroProfileGet();
3056
3057 MicroProfilePresetHeader Header;
3058 memset(&Header, 0, sizeof(Header));
3059 Header.nAggregateFlip = S.nAggregateFlip;
3060 Header.nBars = S.nBars;
3061 Header.fReferenceTime = S.fReferenceTime;
3062 Header.nAllGroupsWanted = S.nAllGroupsWanted;
3063 Header.nAllThreadsWanted = S.nAllThreadsWanted;
3064 Header.nMagic = MICROPROFILE_PRESET_HEADER_MAGIC;
3065 Header.nVersion = MICROPROFILE_PRESET_HEADER_VERSION;
3066 Header.nDisplay = S.nDisplay;
3067 Header.nOpacityBackground = UI.nOpacityBackground;
3068 Header.nOpacityForeground = UI.nOpacityForeground;
3069 Header.nShowSpikes = UI.bShowSpikes ? 1 : 0;
3070 fwrite(&Header, sizeof(Header), 1, F);
3071 uint64_t nMask = 1;
3072 for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3073 {
3074 if(S.nActiveGroupWanted & nMask)
3075 {
3076 uint32_t offset = ftell(F);
3077 const char* pName = S.GroupInfo[i].pName;
3078 int nLen = (int)strlen(pName)+1;
3079 fwrite(pName, nLen, 1, F);
3080 Header.nGroups[i] = offset;
3081 }
3082 nMask <<= 1;
3083 }
3084 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3085 {
3086 MicroProfileThreadLog* pLog = S.Pool[i];
3087 if(pLog && S.nThreadActive[i])
3088 {
3089 uint32_t nOffset = ftell(F);
3090 const char* pName = &pLog->ThreadName[0];
3091 int nLen = (int)strlen(pName)+1;
3092 fwrite(pName, nLen, 1, F);
3093 Header.nThreads[i] = nOffset;
3094 }
3095 }
3096 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3097 {
3098 MicroProfileToken nToken = S.Graph[i].nToken;
3099 if(nToken != MICROPROFILE_INVALID_TOKEN)
3100 {
3101 uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken);
3102 uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken);
3103 const char* pGroupName = S.GroupInfo[nGroupIndex].pName;
3104 const char* pTimerName = S.TimerInfo[nTimerIndex].pName;
3105 MP_ASSERT(pGroupName);
3106 MP_ASSERT(pTimerName);
3107 int nGroupLen = (int)strlen(pGroupName)+1;
3108 int nTimerLen = (int)strlen(pTimerName)+1;
3109
3110 uint32_t nOffsetGroup = ftell(F);
3111 fwrite(pGroupName, nGroupLen, 1, F);
3112 uint32_t nOffsetTimer = ftell(F);
3113 fwrite(pTimerName, nTimerLen, 1, F);
3114 Header.nGraphName[i] = nOffsetTimer;
3115 Header.nGraphGroupName[i] = nOffsetGroup;
3116 }
3117 }
3118 fseek(F, 0, SEEK_SET);
3119 fwrite(&Header, sizeof(Header), 1, F);
3120
3121 fclose(F);
3122
3123}
3124
3125
3126
3127void MicroProfileLoadPreset(const char* pSuffix)
3128{
3129 std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3130 FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pSuffix), "rb");
3131 if(!F)
3132 {
3133 return;
3134 }
3135 fseek(F, 0, SEEK_END);
3136 int nSize = ftell(F);
3137 char* const pBuffer = (char*)alloca(nSize);
3138 fseek(F, 0, SEEK_SET);
3139 int nRead = (int)fread(pBuffer, nSize, 1, F);
3140 fclose(F);
3141 if(1 != nRead)
3142 return;
3143
3144 MicroProfile& S = *MicroProfileGet();
3145
3146 MicroProfilePresetHeader& Header = *(MicroProfilePresetHeader*)pBuffer;
3147
3148 if(Header.nMagic != MICROPROFILE_PRESET_HEADER_MAGIC || Header.nVersion != MICROPROFILE_PRESET_HEADER_VERSION)
3149 {
3150 return;
3151 }
3152
3153 S.nAggregateFlip = Header.nAggregateFlip;
3154 S.nBars = Header.nBars;
3155 S.fReferenceTime = Header.fReferenceTime;
3156 S.fRcpReferenceTime = 1.f / Header.fReferenceTime;
3157 S.nAllGroupsWanted = Header.nAllGroupsWanted;
3158 S.nAllThreadsWanted = Header.nAllThreadsWanted;
3159 S.nDisplay = Header.nDisplay;
3160 S.nActiveGroupWanted = 0;
3161 UI.nOpacityBackground = Header.nOpacityBackground;
3162 UI.nOpacityForeground = Header.nOpacityForeground;
3163 UI.bShowSpikes = Header.nShowSpikes == 1;
3164
3165 memset(&S.nThreadActive[0], 0, sizeof(S.nThreadActive));
3166
3167 for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3168 {
3169 if(Header.nGroups[i])
3170 {
3171 const char* pGroupName = pBuffer + Header.nGroups[i];
3172 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
3173 {
3174 if(0 == MP_STRCASECMP(pGroupName, S.GroupInfo[j].pName))
3175 {
3176 S.nActiveGroupWanted |= (1ll << j);
3177 }
3178 }
3179 }
3180 }
3181 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3182 {
3183 if(Header.nThreads[i])
3184 {
3185 const char* pThreadName = pBuffer + Header.nThreads[i];
3186 for(uint32_t j = 0; j < MICROPROFILE_MAX_THREADS; ++j)
3187 {
3188 MicroProfileThreadLog* pLog = S.Pool[j];
3189 if(pLog && 0 == MP_STRCASECMP(pThreadName, &pLog->ThreadName[0]))
3190 {
3191 S.nThreadActive[j] = 1;
3192 }
3193 }
3194 }
3195 }
3196 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3197 {
3198 MicroProfileToken nPrevToken = S.Graph[i].nToken;
3199 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3200 if(Header.nGraphName[i] && Header.nGraphGroupName[i])
3201 {
3202 const char* pGraphName = pBuffer + Header.nGraphName[i];
3203 const char* pGraphGroupName = pBuffer + Header.nGraphGroupName[i];
3204 for(uint32_t j = 0; j < S.nTotalTimers; ++j)
3205 {
3206 uint64_t nGroupIndex = S.TimerInfo[j].nGroupIndex;
3207 if(0 == MP_STRCASECMP(pGraphName, S.TimerInfo[j].pName) && 0 == MP_STRCASECMP(pGraphGroupName, S.GroupInfo[nGroupIndex].pName))
3208 {
3209 MicroProfileToken nToken = MicroProfileMakeToken(1ll << nGroupIndex, (uint16_t)j);
3210 S.Graph[i].nToken = nToken; // note: group index is stored here but is checked without in MicroProfileToggleGraph()!
3211 S.TimerInfo[j].bGraph = true;
3212 if(nToken != nPrevToken)
3213 {
3214 memset(&S.Graph[i].nHistory, 0, sizeof(S.Graph[i].nHistory));
3215 }
3216 break;
3217 }
3218 }
3219 }
3220 }
3221}
3222
3223uint32_t MicroProfileCustomGroupFind(const char* pCustomName)
3224{
3225 for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3226 {
3227 if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3228 {
3229 return i;
3230 }
3231 }
3232 return (uint32_t)-1;
3233}
3234
3235uint32_t MicroProfileCustomGroup(const char* pCustomName)
3236{
3237 for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3238 {
3239 if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3240 {
3241 return i;
3242 }
3243 }
3244 MP_ASSERT(UI.nCustomCount < MICROPROFILE_CUSTOM_MAX);
3245 uint32_t nIndex = UI.nCustomCount;
3246 UI.nCustomCount++;
3247 memset(&UI.Custom[nIndex], 0, sizeof(UI.Custom[nIndex]));
3248 uint32_t nLen = (uint32_t)strlen(pCustomName);
3249 if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
3250 nLen = MICROPROFILE_NAME_MAX_LEN-1;
3251 memcpy(&UI.Custom[nIndex].pName[0], pCustomName, nLen);
3252 UI.Custom[nIndex].pName[nLen] = '\0';
3253 return nIndex;
3254}
3255void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags)
3256{
3257 uint32_t nIndex = MicroProfileCustomGroup(pCustomName);
3258 MP_ASSERT(UI.Custom[nIndex].pTimers == 0);//only call once!
3259 UI.Custom[nIndex].pTimers = &UI.CustomTimer[UI.nCustomTimerCount];
3260 UI.Custom[nIndex].nMaxTimers = nMaxTimers;
3261 UI.Custom[nIndex].fReference = fReferenceTime;
3262 UI.nCustomTimerCount += nMaxTimers;
3263 MP_ASSERT(UI.nCustomTimerCount <= MICROPROFILE_CUSTOM_MAX_TIMERS); //bump MICROPROFILE_CUSTOM_MAX_TIMERS
3264 UI.Custom[nIndex].nFlags = nFlags;
3265 UI.Custom[nIndex].nAggregateFlip = nAggregateFlip;
3266}
3267
3268void MicroProfileCustomGroupEnable(uint32_t nIndex)
3269{
3270 if(nIndex < UI.nCustomCount)
3271 {
3272 MicroProfile& S = *MicroProfileGet();
3273 S.nForceGroupUI = UI.Custom[nIndex].nGroupMask;
3274 MicroProfileSetAggregateFrames(UI.Custom[nIndex].nAggregateFlip);
3275 S.fReferenceTime = UI.Custom[nIndex].fReference;
3276 S.fRcpReferenceTime = 1.f / UI.Custom[nIndex].fReference;
3277 UI.nCustomActive = nIndex;
3278
3279 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3280 {
3281 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
3282 {
3283 uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3284 S.TimerInfo[nTimerId].bGraph = false;
3285 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3286 }
3287 }
3288
3289 for(uint32_t i = 0; i < UI.Custom[nIndex].nNumTimers; ++i)
3290 {
3291 if(i == MICROPROFILE_MAX_GRAPHS)
3292 {
3293 break;
3294 }
3295 S.Graph[i].nToken = UI.Custom[nIndex].pTimers[i];
3296 S.Graph[i].nKey = i;
3297 uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3298 S.TimerInfo[nTimerId].bGraph = true;
3299 }
3300 }
3301}
3302
3303void MicroProfileCustomGroupToggle(const char* pCustomName)
3304{
3305 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3306 if(nIndex == (uint32_t)-1 || nIndex == UI.nCustomActive)
3307 {
3308 MicroProfileCustomGroupDisable();
3309 }
3310 else
3311 {
3312 MicroProfileCustomGroupEnable(nIndex);
3313 }
3314}
3315
3316void MicroProfileCustomGroupEnable(const char* pCustomName)
3317{
3318 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3319 MicroProfileCustomGroupEnable(nIndex);
3320}
3321void MicroProfileCustomGroupDisable()
3322{
3323 MicroProfile& S = *MicroProfileGet();
3324 S.nForceGroupUI = 0;
3325 UI.nCustomActive = (uint32_t)-1;
3326}
3327
3328void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer)
3329{
3330 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3331 if((uint32_t)-1 == nIndex)
3332 {
3333 return;
3334 }
3335 uint32_t nTimerIndex = UI.Custom[nIndex].nNumTimers;
3336 MP_ASSERT(nTimerIndex < UI.Custom[nIndex].nMaxTimers);
3337 uint64_t nToken = MicroProfileFindToken(pGroup, pTimer);
3338 MP_ASSERT(nToken != MICROPROFILE_INVALID_TOKEN); //Timer must be registered first.
3339 UI.Custom[nIndex].pTimers[nTimerIndex] = nToken;
3340 uint16_t nGroup = MicroProfileGetGroupIndex(nToken);
3341 UI.Custom[nIndex].nGroupMask |= (1ll << nGroup);
3342 UI.Custom[nIndex].nNumTimers++;
3343}
3344
3345#undef UI
3346
3347#endif
3348#endif
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index d6fcb66a5..46f4a07c9 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -6,6 +6,9 @@
6#include <thread> 6#include <thread>
7#include <iostream> 7#include <iostream>
8 8
9// This needs to be included before getopt.h because the latter #defines symbols used by it
10#include "common/microprofile.h"
11
9#ifdef _MSC_VER 12#ifdef _MSC_VER
10#include <getopt.h> 13#include <getopt.h>
11#else 14#else
@@ -59,6 +62,8 @@ int main(int argc, char **argv) {
59 Log::Filter log_filter(Log::Level::Debug); 62 Log::Filter log_filter(Log::Level::Debug);
60 Log::SetFilter(&log_filter); 63 Log::SetFilter(&log_filter);
61 64
65 MicroProfileOnThreadCreate("EmuThread");
66
62 if (boot_filename.empty()) { 67 if (boot_filename.empty()) {
63 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); 68 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
64 return -1; 69 return -1;
@@ -89,5 +94,7 @@ int main(int argc, char **argv) {
89 94
90 delete emu_window; 95 delete emu_window;
91 96
97 MicroProfileShutdown();
98
92 return 0; 99 return 0;
93} 100}
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index a96fbea5f..f8aacb527 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -14,6 +14,7 @@
14#include "common/string_util.h" 14#include "common/string_util.h"
15#include "common/scm_rev.h" 15#include "common/scm_rev.h"
16#include "common/key_map.h" 16#include "common/key_map.h"
17#include "common/microprofile.h"
17 18
18#include "core/core.h" 19#include "core/core.h"
19#include "core/settings.h" 20#include "core/settings.h"
@@ -37,6 +38,8 @@ EmuThread::EmuThread(GRenderWindow* render_window) :
37void EmuThread::run() { 38void EmuThread::run() {
38 render_window->MakeCurrent(); 39 render_window->MakeCurrent();
39 40
41 MicroProfileOnThreadCreate("EmuThread");
42
40 stop_run = false; 43 stop_run = false;
41 44
42 // holds whether the cpu was running during the last iteration, 45 // holds whether the cpu was running during the last iteration,
@@ -69,6 +72,8 @@ void EmuThread::run() {
69 } 72 }
70 } 73 }
71 74
75 MicroProfileOnThreadExit();
76
72 render_window->moveContext(); 77 render_window->moveContext();
73} 78}
74 79
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 89b28c2f4..5261d4836 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -2,9 +2,21 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QMouseEvent>
6#include <QPainter>
7#include <QString>
8
5#include "profiler.h" 9#include "profiler.h"
6 10
11#include "citra_qt/util/util.h"
12
7#include "common/profiler_reporting.h" 13#include "common/profiler_reporting.h"
14#include "common/microprofile.h"
15
16// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
17// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
18#define MICROPROFILEUI_IMPL 1
19#include "common/microprofileui.h"
8 20
9using namespace Common::Profiling; 21using namespace Common::Profiling;
10 22
@@ -136,3 +148,193 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable)
136 update_timer.stop(); 148 update_timer.stop();
137 } 149 }
138} 150}
151
152class MicroProfileWidget : public QWidget {
153public:
154 MicroProfileWidget(QWidget* parent = 0);
155
156protected:
157 void paintEvent(QPaintEvent* ev) override;
158 void showEvent(QShowEvent* ev) override;
159 void hideEvent(QHideEvent* ev) override;
160
161 void mouseMoveEvent(QMouseEvent* ev) override;
162 void mousePressEvent(QMouseEvent* ev) override;
163 void mouseReleaseEvent(QMouseEvent* ev) override;
164 void wheelEvent(QWheelEvent* ev) override;
165
166 void keyPressEvent(QKeyEvent* ev) override;
167 void keyReleaseEvent(QKeyEvent* ev) override;
168
169private:
170 /// This timer is used to redraw the widget's contents continuously. To save resources, it only
171 /// runs while the widget is visible.
172 QTimer update_timer;
173};
174
175MicroProfileDialog::MicroProfileDialog(QWidget* parent)
176 : QWidget(parent, Qt::Dialog)
177{
178 setObjectName("MicroProfile");
179 setWindowTitle(tr("MicroProfile"));
180 resize(1000, 600);
181 // Remove the "?" button from the titlebar and enable the maximize button
182 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint);
183
184 MicroProfileWidget* widget = new MicroProfileWidget(this);
185
186 QLayout* layout = new QVBoxLayout(this);
187 layout->setContentsMargins(0, 0, 0, 0);
188 layout->addWidget(widget);
189 setLayout(layout);
190
191 // Configure focus so that widget is focusable and the dialog automatically forwards focus to it.
192 setFocusProxy(widget);
193 widget->setFocusPolicy(Qt::StrongFocus);
194 widget->setFocus();
195}
196
197QAction* MicroProfileDialog::toggleViewAction() {
198 if (toggle_view_action == nullptr) {
199 toggle_view_action = new QAction(windowTitle(), this);
200 toggle_view_action->setCheckable(true);
201 toggle_view_action->setChecked(isVisible());
202 connect(toggle_view_action, SIGNAL(toggled(bool)), SLOT(setVisible(bool)));
203 }
204
205 return toggle_view_action;
206}
207
208void MicroProfileDialog::showEvent(QShowEvent* ev) {
209 if (toggle_view_action) {
210 toggle_view_action->setChecked(isVisible());
211 }
212 QWidget::showEvent(ev);
213}
214
215void MicroProfileDialog::hideEvent(QHideEvent* ev) {
216 if (toggle_view_action) {
217 toggle_view_action->setChecked(isVisible());
218 }
219 QWidget::hideEvent(ev);
220}
221
222/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the
223/// QPainter available inside the drawing callbacks.
224static QPainter* mp_painter = nullptr;
225
226MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
227 // Send mouse motion events even when not dragging.
228 setMouseTracking(true);
229
230 MicroProfileSetDisplayMode(1); // Timers screen
231 MicroProfileInitUI();
232
233 connect(&update_timer, SIGNAL(timeout()), SLOT(update()));
234}
235
236void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
237 QPainter painter(this);
238
239 painter.setBackground(Qt::black);
240 painter.eraseRect(rect());
241
242 QFont font = GetMonospaceFont();
243 font.setPixelSize(MICROPROFILE_TEXT_HEIGHT);
244 painter.setFont(font);
245
246 mp_painter = &painter;
247 MicroProfileDraw(rect().width(), rect().height());
248 mp_painter = nullptr;
249}
250
251void MicroProfileWidget::showEvent(QShowEvent* ev) {
252 update_timer.start(15); // ~60 Hz
253 QWidget::showEvent(ev);
254}
255
256void MicroProfileWidget::hideEvent(QHideEvent* ev) {
257 update_timer.stop();
258 QWidget::hideEvent(ev);
259}
260
261void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) {
262 MicroProfileMousePosition(ev->x(), ev->y(), 0);
263 ev->accept();
264}
265
266void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) {
267 MicroProfileMousePosition(ev->x(), ev->y(), 0);
268 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
269 ev->accept();
270}
271
272void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
273 MicroProfileMousePosition(ev->x(), ev->y(), 0);
274 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
275 ev->accept();
276}
277
278void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
279 MicroProfileMousePosition(ev->x(), ev->y(), ev->delta() / 120);
280 ev->accept();
281}
282
283void MicroProfileWidget::keyPressEvent(QKeyEvent* ev) {
284 if (ev->key() == Qt::Key_Control) {
285 // Inform MicroProfile that the user is holding Ctrl.
286 MicroProfileModKey(1);
287 }
288 QWidget::keyPressEvent(ev);
289}
290
291void MicroProfileWidget::keyReleaseEvent(QKeyEvent* ev) {
292 if (ev->key() == Qt::Key_Control) {
293 MicroProfileModKey(0);
294 }
295 QWidget::keyReleaseEvent(ev);
296}
297
298// These functions are called by MicroProfileDraw to draw the interface elements on the screen.
299
300void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 text_length) {
301 // hex_color does not include an alpha, so it must be assumed to be 255
302 mp_painter->setPen(QColor::fromRgb(hex_color));
303
304 // It's impossible to draw a string using a monospaced font with a fixed width per cell in a
305 // way that's reliable across different platforms and fonts as far as I (yuriks) can tell, so
306 // draw each character individually in order to precisely control the text advance.
307 for (u32 i = 0; i < text_length; ++i) {
308 // Position the text baseline 1 pixel above the bottom of the text cell, this gives nice
309 // vertical alignment of text for a wide range of tested fonts.
310 mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i]));
311 x += MICROPROFILE_TEXT_WIDTH + 1;
312 }
313}
314
315void MicroProfileDrawBox(int left, int top, int right, int bottom, u32 hex_color, MicroProfileBoxType type) {
316 QColor color = QColor::fromRgba(hex_color);
317 QBrush brush = color;
318 if (type == MicroProfileBoxTypeBar) {
319 QLinearGradient gradient(left, top, left, bottom);
320 gradient.setColorAt(0.f, color.lighter(125));
321 gradient.setColorAt(1.f, color.darker(125));
322 brush = gradient;
323 }
324 mp_painter->fillRect(left, top, right - left, bottom - top, brush);
325}
326
327void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color) {
328 // Temporary vector used to convert between the float array and QPointF. Marked static to reuse
329 // the allocation across calls.
330 static std::vector<QPointF> point_buf;
331
332 for (u32 i = 0; i < vertices_length; ++i) {
333 point_buf.emplace_back(vertices[i*2 + 0], vertices[i*2 + 1]);
334 }
335
336 // hex_color does not include an alpha, so it must be assumed to be 255
337 mp_painter->setPen(QColor::fromRgb(hex_color));
338 mp_painter->drawPolyline(point_buf.data(), vertices_length);
339 point_buf.clear();
340}
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index fabf279b8..2199eaef1 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -48,3 +48,20 @@ private:
48 48
49 QTimer update_timer; 49 QTimer update_timer;
50}; 50};
51
52class MicroProfileDialog : public QWidget {
53 Q_OBJECT
54
55public:
56 MicroProfileDialog(QWidget* parent = 0);
57
58 /// Returns a QAction that can be used to toggle visibility of this dialog.
59 QAction* toggleViewAction();
60
61protected:
62 void showEvent(QShowEvent* ev) override;
63 void hideEvent(QHideEvent* ev) override;
64
65private:
66 QAction* toggle_view_action = nullptr;
67};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 8bf2a3e13..7fb1b0dcb 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -17,6 +17,7 @@
17#include "common/logging/backend.h" 17#include "common/logging/backend.h"
18#include "common/logging/filter.h" 18#include "common/logging/filter.h"
19#include "common/make_unique.h" 19#include "common/make_unique.h"
20#include "common/microprofile.h"
20#include "common/platform.h" 21#include "common/platform.h"
21#include "common/scm_rev.h" 22#include "common/scm_rev.h"
22#include "common/scope_exit.h" 23#include "common/scope_exit.h"
@@ -64,6 +65,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
64 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); 65 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
65 profilerWidget->hide(); 66 profilerWidget->hide();
66 67
68 microProfileDialog = new MicroProfileDialog(this);
69 microProfileDialog->hide();
70
67 disasmWidget = new DisassemblerWidget(this, emu_thread.get()); 71 disasmWidget = new DisassemblerWidget(this, emu_thread.get());
68 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); 72 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
69 disasmWidget->hide(); 73 disasmWidget->hide();
@@ -102,6 +106,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
102 106
103 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 107 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
104 debug_menu->addAction(profilerWidget->toggleViewAction()); 108 debug_menu->addAction(profilerWidget->toggleViewAction());
109 debug_menu->addAction(microProfileDialog->toggleViewAction());
105 debug_menu->addAction(disasmWidget->toggleViewAction()); 110 debug_menu->addAction(disasmWidget->toggleViewAction());
106 debug_menu->addAction(registersWidget->toggleViewAction()); 111 debug_menu->addAction(registersWidget->toggleViewAction());
107 debug_menu->addAction(callstackWidget->toggleViewAction()); 112 debug_menu->addAction(callstackWidget->toggleViewAction());
@@ -128,6 +133,8 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
128 restoreGeometry(settings.value("geometry").toByteArray()); 133 restoreGeometry(settings.value("geometry").toByteArray());
129 restoreState(settings.value("state").toByteArray()); 134 restoreState(settings.value("state").toByteArray());
130 render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray()); 135 render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray());
136 microProfileDialog->restoreGeometry(settings.value("microProfileDialogGeometry").toByteArray());
137 microProfileDialog->setVisible(settings.value("microProfileDialogVisible").toBool());
131 138
132 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); 139 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
133 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); 140 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
@@ -434,6 +441,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
434 settings.setValue("geometry", saveGeometry()); 441 settings.setValue("geometry", saveGeometry());
435 settings.setValue("state", saveState()); 442 settings.setValue("state", saveState());
436 settings.setValue("geometryRenderWindow", render_window->saveGeometry()); 443 settings.setValue("geometryRenderWindow", render_window->saveGeometry());
444 settings.setValue("microProfileDialogGeometry", microProfileDialog->saveGeometry());
445 settings.setValue("microProfileDialogVisible", microProfileDialog->isVisible());
437 settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); 446 settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked());
438 settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked()); 447 settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked());
439 settings.setValue("firstStart", false); 448 settings.setValue("firstStart", false);
@@ -456,6 +465,11 @@ int main(int argc, char* argv[]) {
456 Log::Filter log_filter(Log::Level::Info); 465 Log::Filter log_filter(Log::Level::Info);
457 Log::SetFilter(&log_filter); 466 Log::SetFilter(&log_filter);
458 467
468 MicroProfileOnThreadCreate("Frontend");
469 SCOPE_EXIT({
470 MicroProfileShutdown();
471 });
472
459 // Init settings params 473 // Init settings params
460 QSettings::setDefaultFormat(QSettings::IniFormat); 474 QSettings::setDefaultFormat(QSettings::IniFormat);
461 QCoreApplication::setOrganizationName("Citra team"); 475 QCoreApplication::setOrganizationName("Citra team");
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 6f1292295..32523fded 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -14,6 +14,7 @@ class GImageInfo;
14class GRenderWindow; 14class GRenderWindow;
15class EmuThread; 15class EmuThread;
16class ProfilerWidget; 16class ProfilerWidget;
17class MicroProfileDialog;
17class DisassemblerWidget; 18class DisassemblerWidget;
18class RegistersWidget; 19class RegistersWidget;
19class CallstackWidget; 20class CallstackWidget;
@@ -104,6 +105,7 @@ private:
104 std::unique_ptr<EmuThread> emu_thread; 105 std::unique_ptr<EmuThread> emu_thread;
105 106
106 ProfilerWidget* profilerWidget; 107 ProfilerWidget* profilerWidget;
108 MicroProfileDialog* microProfileDialog;
107 DisassemblerWidget* disasmWidget; 109 DisassemblerWidget* disasmWidget;
108 RegistersWidget* registersWidget; 110 RegistersWidget* registersWidget;
109 CallstackWidget* callstackWidget; 111 CallstackWidget* callstackWidget;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e743a026d..7f3712efa 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -11,6 +11,7 @@ set(SRCS
11 logging/text_formatter.cpp 11 logging/text_formatter.cpp
12 logging/backend.cpp 12 logging/backend.cpp
13 memory_util.cpp 13 memory_util.cpp
14 microprofile.cpp
14 misc.cpp 15 misc.cpp
15 profiler.cpp 16 profiler.cpp
16 scm_rev.cpp 17 scm_rev.cpp
@@ -43,6 +44,8 @@ set(HEADERS
43 make_unique.h 44 make_unique.h
44 math_util.h 45 math_util.h
45 memory_util.h 46 memory_util.h
47 microprofile.h
48 microprofileui.h
46 platform.h 49 platform.h
47 profiler.h 50 profiler.h
48 profiler_reporting.h 51 profiler_reporting.h
diff --git a/src/common/microprofile.cpp b/src/common/microprofile.cpp
new file mode 100644
index 000000000..ee25dd37f
--- /dev/null
+++ b/src/common/microprofile.cpp
@@ -0,0 +1,7 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// Includes the MicroProfile implementation in this file for compilation
6#define MICROPROFILE_IMPL 1
7#include "common/microprofile.h"
diff --git a/src/common/microprofile.h b/src/common/microprofile.h
new file mode 100644
index 000000000..9eb6016a8
--- /dev/null
+++ b/src/common/microprofile.h
@@ -0,0 +1,25 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7// Customized Citra settings.
8// This file wraps the MicroProfile header so that these are consistent everywhere.
9#define MICROPROFILE_WEBSERVER 0
10#define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3
11#define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
12#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<12) // 8 MB
13
14#include <microprofile.h>
15
16#define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0)
17
18// On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
19// identifiers we use.
20#ifdef PAGE_SIZE
21#undef PAGE_SIZE
22#endif
23#ifdef PAGE_MASK
24#undef PAGE_MASK
25#endif
diff --git a/src/common/microprofileui.h b/src/common/microprofileui.h
new file mode 100644
index 000000000..97c369bd9
--- /dev/null
+++ b/src/common/microprofileui.h
@@ -0,0 +1,16 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/microprofile.h"
8
9// Customized Citra settings.
10// This file wraps the MicroProfile header so that these are consistent everywhere.
11#define MICROPROFILE_TEXT_WIDTH 6
12#define MICROPROFILE_TEXT_HEIGHT 12
13#define MICROPROFILE_HELP_ALT "Right-Click"
14#define MICROPROFILE_HELP_MOD "Ctrl"
15
16#include <microprofileui.h>
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 422e80b50..01c712f24 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -9,6 +9,7 @@
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/microprofile.h"
12#include "common/profiler.h" 13#include "common/profiler.h"
13 14
14#include "core/memory.h" 15#include "core/memory.h"
@@ -3522,8 +3523,11 @@ enum {
3522 FETCH_EXCEPTION 3523 FETCH_EXCEPTION
3523}; 3524};
3524 3525
3526MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64));
3527
3525static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { 3528static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3526 Common::Profiling::ScopeTimer timer_decode(profile_decode); 3529 Common::Profiling::ScopeTimer timer_decode(profile_decode);
3530 MICROPROFILE_SCOPE(DynCom_Decode);
3527 3531
3528 // Decode instruction, get index 3532 // Decode instruction, get index
3529 // Allocate memory and init InsCream 3533 // Allocate memory and init InsCream
@@ -3588,8 +3592,11 @@ static int clz(unsigned int x) {
3588 return n; 3592 return n;
3589} 3593}
3590 3594
3595MICROPROFILE_DEFINE(DynCom_Execute, "DynCom", "Execute", MP_RGB(255, 0, 0));
3596
3591unsigned InterpreterMainLoop(ARMul_State* cpu) { 3597unsigned InterpreterMainLoop(ARMul_State* cpu) {
3592 Common::Profiling::ScopeTimer timer_execute(profile_execute); 3598 Common::Profiling::ScopeTimer timer_execute(profile_execute);
3599 MICROPROFILE_SCOPE(DynCom_Execute);
3593 3600
3594 #undef RM 3601 #undef RM
3595 #undef RS 3602 #undef RS
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index fde508a13..c3d0d28a5 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/bit_field.h" 5#include "common/bit_field.h"
6#include "common/microprofile.h"
6 7
7#include "core/memory.h" 8#include "core/memory.h"
8#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
@@ -229,6 +230,10 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
229 230
230 if (Pica::g_debug_context) 231 if (Pica::g_debug_context)
231 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); 232 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
233
234 if (screen_id == 0) {
235 MicroProfileFlip();
236 }
232} 237}
233 238
234/** 239/**
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 89ac45a6f..19f750d72 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -5,6 +5,7 @@
5#include <map> 5#include <map>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/microprofile.h"
8#include "common/profiler.h" 9#include "common/profiler.h"
9#include "common/string_util.h" 10#include "common/string_util.h"
10#include "common/symbols.h" 11#include "common/symbols.h"
@@ -969,8 +970,11 @@ static const FunctionDef* GetSVCInfo(u32 func_num) {
969 return &SVC_Table[func_num]; 970 return &SVC_Table[func_num];
970} 971}
971 972
973MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
974
972void CallSVC(u32 immediate) { 975void CallSVC(u32 immediate) {
973 Common::Profiling::ScopeTimer timer_svc(profiler_svc); 976 Common::Profiling::ScopeTimer timer_svc(profiler_svc);
977 MICROPROFILE_SCOPE(Kernel_SVC);
974 978
975 const FunctionDef* info = GetSVCInfo(immediate); 979 const FunctionDef* info = GetSVCInfo(immediate);
976 if (info) { 980 if (info) {
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 68ae38289..bc7bde903 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -9,6 +9,7 @@
9#include "common/color.h" 9#include "common/color.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/microprofile.h"
12#include "common/vector_math.h" 13#include "common/vector_math.h"
13 14
14#include "core/settings.h" 15#include "core/settings.h"
@@ -85,6 +86,9 @@ static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_
85 } 86 }
86} 87}
87 88
89MICROPROFILE_DEFINE(GPU_DisplayTransfer, "GPU", "DisplayTransfer", MP_RGB(100, 100, 255));
90MICROPROFILE_DEFINE(GPU_CmdlistProcessing, "GPU", "Cmdlist Processing", MP_RGB(100, 255, 100));
91
88template <typename T> 92template <typename T>
89inline void Write(u32 addr, const T data) { 93inline void Write(u32 addr, const T data) {
90 addr -= HW::VADDR_GPU; 94 addr -= HW::VADDR_GPU;
@@ -150,6 +154,8 @@ inline void Write(u32 addr, const T data) {
150 154
151 case GPU_REG_INDEX(display_transfer_config.trigger): 155 case GPU_REG_INDEX(display_transfer_config.trigger):
152 { 156 {
157 MICROPROFILE_SCOPE(GPU_DisplayTransfer);
158
153 const auto& config = g_regs.display_transfer_config; 159 const auto& config = g_regs.display_transfer_config;
154 if (config.trigger & 1) { 160 if (config.trigger & 1) {
155 161
@@ -344,6 +350,8 @@ inline void Write(u32 addr, const T data) {
344 const auto& config = g_regs.command_processor_config; 350 const auto& config = g_regs.command_processor_config;
345 if (config.trigger & 1) 351 if (config.trigger & 1)
346 { 352 {
353 MICROPROFILE_SCOPE(GPU_CmdlistProcessing);
354
347 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); 355 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
348 356
349 if (Pica::g_debug_context && Pica::g_debug_context->recorder) { 357 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index d82e20f86..a78985510 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -4,6 +4,7 @@
4 4
5#include <boost/range/algorithm/fill.hpp> 5#include <boost/range/algorithm/fill.hpp>
6 6
7#include "common/microprofile.h"
7#include "common/profiler.h" 8#include "common/profiler.h"
8 9
9#include "core/hle/service/gsp_gpu.h" 10#include "core/hle/service/gsp_gpu.h"
@@ -43,6 +44,8 @@ static const u32 expand_bits_to_bytes[] = {
43 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff 44 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
44}; 45};
45 46
47MICROPROFILE_DEFINE(GPU_Drawing, "GPU", "Drawing", MP_RGB(50, 50, 240));
48
46static void WritePicaReg(u32 id, u32 value, u32 mask) { 49static void WritePicaReg(u32 id, u32 value, u32 mask) {
47 auto& regs = g_state.regs; 50 auto& regs = g_state.regs;
48 51
@@ -126,6 +129,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
126 case PICA_REG_INDEX(trigger_draw_indexed): 129 case PICA_REG_INDEX(trigger_draw_indexed):
127 { 130 {
128 Common::Profiling::ScopeTimer scope_timer(category_drawing); 131 Common::Profiling::ScopeTimer scope_timer(category_drawing);
132 MICROPROFILE_SCOPE(GPU_Drawing);
129 133
130#if PICA_LOG_TEV 134#if PICA_LOG_TEV
131 DebugUtils::DumpTevStageConfig(regs.GetTevStages()); 135 DebugUtils::DumpTevStageConfig(regs.GetTevStages());
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index b83798b0f..4a159da8e 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -7,6 +7,7 @@
7#include "common/color.h" 7#include "common/color.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/math_util.h" 9#include "common/math_util.h"
10#include "common/microprofile.h"
10#include "common/profiler.h" 11#include "common/profiler.h"
11 12
12#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
@@ -267,6 +268,7 @@ static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
267}; 268};
268 269
269static Common::Profiling::TimingCategory rasterization_category("Rasterization"); 270static Common::Profiling::TimingCategory rasterization_category("Rasterization");
271MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
270 272
271/** 273/**
272 * Helper function for ProcessTriangle with the "reversed" flag to allow for implementing 274 * Helper function for ProcessTriangle with the "reversed" flag to allow for implementing
@@ -279,6 +281,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
279{ 281{
280 const auto& regs = g_state.regs; 282 const auto& regs = g_state.regs;
281 Common::Profiling::ScopeTimer timer(rasterization_category); 283 Common::Profiling::ScopeTimer timer(rasterization_category);
284 MICROPROFILE_SCOPE(GPU_Rasterization);
282 285
283 // vertex positions in rasterizer coordinates 286 // vertex positions in rasterizer coordinates
284 static auto FloatToFix = [](float24 flt) { 287 static auto FloatToFix = [](float24 flt) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 9f1552adf..deb9971bb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/color.h" 8#include "common/color.h"
9#include "common/math_util.h" 9#include "common/math_util.h"
10#include "common/microprofile.h"
10#include "common/profiler.h" 11#include "common/profiler.h"
11 12
12#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
@@ -777,12 +778,16 @@ void RasterizerOpenGL::SyncDrawState() {
777 state.Apply(); 778 state.Apply();
778} 779}
779 780
781MICROPROFILE_DEFINE(OpenGL_FramebufferReload, "OpenGL", "FB Reload", MP_RGB(70, 70, 200));
782
780void RasterizerOpenGL::ReloadColorBuffer() { 783void RasterizerOpenGL::ReloadColorBuffer() {
781 u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress()); 784 u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress());
782 785
783 if (color_buffer == nullptr) 786 if (color_buffer == nullptr)
784 return; 787 return;
785 788
789 MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
790
786 u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format); 791 u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
787 792
788 std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); 793 std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
@@ -822,6 +827,8 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
822 if (depth_buffer == nullptr) 827 if (depth_buffer == nullptr)
823 return; 828 return;
824 829
830 MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
831
825 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); 832 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
826 833
827 // OpenGL needs 4 bpp alignment for D24 834 // OpenGL needs 4 bpp alignment for D24
@@ -868,6 +875,7 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
868} 875}
869 876
870Common::Profiling::TimingCategory buffer_commit_category("Framebuffer Commit"); 877Common::Profiling::TimingCategory buffer_commit_category("Framebuffer Commit");
878MICROPROFILE_DEFINE(OpenGL_FramebufferCommit, "OpenGL", "FB Commit", MP_RGB(70, 70, 200));
871 879
872void RasterizerOpenGL::CommitColorBuffer() { 880void RasterizerOpenGL::CommitColorBuffer() {
873 if (last_fb_color_addr != 0) { 881 if (last_fb_color_addr != 0) {
@@ -875,6 +883,7 @@ void RasterizerOpenGL::CommitColorBuffer() {
875 883
876 if (color_buffer != nullptr) { 884 if (color_buffer != nullptr) {
877 Common::Profiling::ScopeTimer timer(buffer_commit_category); 885 Common::Profiling::ScopeTimer timer(buffer_commit_category);
886 MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
878 887
879 u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format); 888 u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
880 889
@@ -911,6 +920,7 @@ void RasterizerOpenGL::CommitDepthBuffer() {
911 920
912 if (depth_buffer != nullptr) { 921 if (depth_buffer != nullptr) {
913 Common::Profiling::ScopeTimer timer(buffer_commit_category); 922 Common::Profiling::ScopeTimer timer(buffer_commit_category);
923 MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
914 924
915 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); 925 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
916 926
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 70f0ba5f1..e4247051c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/make_unique.h" 5#include "common/make_unique.h"
6#include "common/math_util.h" 6#include "common/math_util.h"
7#include "common/microprofile.h"
7#include "common/vector_math.h" 8#include "common/vector_math.h"
8 9
9#include "core/memory.h" 10#include "core/memory.h"
@@ -16,6 +17,8 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
16 FullFlush(); 17 FullFlush();
17} 18}
18 19
20MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
21
19void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) { 22void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) {
20 PAddr texture_addr = config.config.GetPhysicalAddress(); 23 PAddr texture_addr = config.config.GetPhysicalAddress();
21 24
@@ -25,6 +28,8 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text
25 state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle; 28 state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle;
26 state.Apply(); 29 state.Apply();
27 } else { 30 } else {
31 MICROPROFILE_SCOPE(OpenGL_TextureUpload);
32
28 std::unique_ptr<CachedTexture> new_texture = Common::make_unique<CachedTexture>(); 33 std::unique_ptr<CachedTexture> new_texture = Common::make_unique<CachedTexture>();
29 34
30 new_texture->texture.Create(); 35 new_texture->texture.Create();
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 4e9836c80..be5588c00 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -9,6 +9,7 @@
9 9
10#include "common/hash.h" 10#include "common/hash.h"
11#include "common/make_unique.h" 11#include "common/make_unique.h"
12#include "common/microprofile.h"
12#include "common/profiler.h" 13#include "common/profiler.h"
13 14
14#include "video_core/debug_utils/debug_utils.h" 15#include "video_core/debug_utils/debug_utils.h"
@@ -55,11 +56,13 @@ void Shutdown() {
55} 56}
56 57
57static Common::Profiling::TimingCategory shader_category("Vertex Shader"); 58static Common::Profiling::TimingCategory shader_category("Vertex Shader");
59MICROPROFILE_DEFINE(GPU_VertexShader, "GPU", "Vertex Shader", MP_RGB(50, 50, 240));
58 60
59OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attributes) { 61OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
60 auto& config = g_state.regs.vs; 62 auto& config = g_state.regs.vs;
61 63
62 Common::Profiling::ScopeTimer timer(shader_category); 64 Common::Profiling::ScopeTimer timer(shader_category);
65 MICROPROFILE_SCOPE(GPU_VertexShader);
63 66
64 state.program_counter = config.main_offset; 67 state.program_counter = config.main_offset;
65 state.debug.max_offset = 0; 68 state.debug.max_offset = 0;