Pyrogenesis  trunk
Profiler2.h
Go to the documentation of this file.
1 /* Copyright (C) 2022 Wildfire Games.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /**
24  * @file
25  * New profiler (complementing the older CProfileManager)
26  *
27  * The profiler is designed for analysing framerate fluctuations or glitches,
28  * and temporal relationships between threads.
29  * This contrasts with CProfilerManager and most external profiling tools,
30  * which are designed more for measuring average throughput over a number of
31  * frames.
32  *
33  * To view the profiler output, press F11 to enable the HTTP output mode
34  * and then open source/tools/profiler2/profiler2.html in a web browser.
35  *
36  * There is a single global CProfiler2 instance (g_Profiler2),
37  * providing the API used by the rest of the game.
38  * The game can record the entry/exit timings of a region of code
39  * using the PROFILE2 macro, and can record other events using
40  * PROFILE2_EVENT.
41  * Regions and events can be annotated with arbitrary string attributes,
42  * specified with printf-style format strings, using PROFILE2_ATTR
43  * (e.g. PROFILE2_ATTR("frame: %d", m_FrameNum) ).
44  *
45  * This is designed for relatively coarse-grained profiling, or for rare events.
46  * Don't use it for regions that are typically less than ~0.1msecs, or that are
47  * called hundreds of times per frame. (The old CProfilerManager is better
48  * for that.)
49  *
50  * New threads must call g_Profiler2.RegisterCurrentThread before any other
51  * profiler functions.
52  *
53  * The main thread should call g_Profiler2.RecordFrameStart at the start of
54  * each frame.
55  * Other threads should call g_Profiler2.RecordSyncMarker occasionally,
56  * especially if it's been a long time since their last call to the profiler,
57  * or if they've made thousands of calls since the last sync marker.
58  *
59  * The profiler is implemented with thread-local fixed-size ring buffers,
60  * which store a sequence of variable-length items indicating the time
61  * of the event and associated data (pointers to names, attribute strings, etc).
62  * An HTTP server provides access to the data: when requested, it will make
63  * a copy of a thread's buffer, then parse the items and return them in JSON
64  * format. The profiler2.html requests and processes and visualises this data.
65  *
66  * The RecordSyncMarker calls are necessary to correct for time drift and to
67  * let the buffer parser accurately detect the start of an item in the byte stream.
68  *
69  * This design aims to minimise the performance overhead of recording data,
70  * and to simplify the visualisation of the data by doing it externally in an
71  * environment with better UI tools (i.e. HTML) instead of within the game engine.
72  *
73  * The initial setup of g_Profiler2 must happen in the game's main thread.
74  * RegisterCurrentThread and the Record functions may be called from any thread.
75  * The HTTP server runs its own threads, which may call the ConstructJSON functions.
76  */
77 
78 #ifndef INCLUDED_PROFILER2
79 #define INCLUDED_PROFILER2
80 
81 #include "lib/timer.h"
82 #include "ps/ThreadUtil.h"
83 
84 #include <mutex>
85 #include <string>
86 #include <thread>
87 #include <vector>
88 
89 struct mg_context;
90 
91 // Note: Lots of functions are defined inline, to hypothetically
92 // minimise performance overhead.
93 
94 class CProfiler2GPU;
95 
97 {
98  friend class CProfiler2GPUARB;
99  friend class CProfile2SpikeRegion;
101 public:
102  // Items stored in the buffers:
103 
104  /// Item type identifiers
105  enum EItem
106  {
107  ITEM_NOP = 0,
108  ITEM_SYNC = 1, // magic value used for parse syncing
109  ITEM_EVENT = 2, // single event
110  ITEM_ENTER = 3, // entering a region
111  ITEM_LEAVE = 4, // leaving a region (must be correctly nested)
112  ITEM_ATTRIBUTE = 5, // arbitrary string associated with current region, or latest event (if the previous item was an event)
113  };
114 
115  static const size_t MAX_ATTRIBUTE_LENGTH; // includes null terminator, which isn't stored
116 
117  /// An arbitrary number to help resyncing with the item stream when parsing.
118  static const u8 RESYNC_MAGIC[8];
119 
120  /**
121  * An item with a relative time and an ID string pointer.
122  */
123  struct SItem_dt_id
124  {
125  float dt; // time relative to last event
126  const char* id;
127  };
128 
129 private:
130  // TODO: different threads might want different sizes
131  static const size_t BUFFER_SIZE;
132  static const size_t HOLD_BUFFER_SIZE;
133 
134  /**
135  * Class instantiated in every registered thread.
136  */
138  {
140  public:
141  ThreadStorage(CProfiler2& profiler, const std::string& name);
142  ~ThreadStorage();
143 
144  enum { BUFFER_NORMAL, BUFFER_SPIKE, BUFFER_AGGREGATE };
145 
146  void RecordSyncMarker(double t)
147  {
148  // Store the magic string followed by the absolute time
149  // (to correct for drift caused by the precision of relative
150  // times stored in other items)
151  u8 buffer[sizeof(RESYNC_MAGIC) + sizeof(t)];
152  memcpy(buffer, &RESYNC_MAGIC, sizeof(RESYNC_MAGIC));
153  memcpy(buffer + sizeof(RESYNC_MAGIC), &t, sizeof(t));
154  Write(ITEM_SYNC, buffer, ARRAY_SIZE(buffer));
155  m_LastTime = t;
156  }
157 
158  void Record(EItem type, double t, const char* id)
159  {
160  // Store a relative time instead of absolute, so we can use floats
161  // (to save memory) without suffering from precision problems
162  SItem_dt_id item = { (float)(t - m_LastTime), id };
163  Write(type, &item, sizeof(item));
164  }
165 
166  void RecordFrameStart(double t)
167  {
168  RecordSyncMarker(t);
169  Record(ITEM_EVENT, t, "__framestart"); // magic string recognised by the visualiser
170  }
171 
172  void RecordLeave(double t)
173  {
174  float time = (float)(t - m_LastTime);
175  Write(ITEM_LEAVE, &time, sizeof(float));
176  }
177 
178  void RecordAttribute(const char* fmt, va_list argp) VPRINTF_ARGS(2);
179 
180  void RecordAttributePrintf(const char* fmt, ...) PRINTF_ARGS(2)
181  {
182  va_list argp;
183  va_start(argp, fmt);
184  RecordAttribute(fmt, argp);
185  va_end(argp);
186  }
187 
188  size_t HoldLevel();
189  u8 HoldType();
190  void PutOnHold(u8 type);
191  void HoldToBuffer(bool condensed);
192  void ThrowawayHoldBuffer();
193 
195  {
196  return m_Profiler;
197  }
198 
199  const std::string& GetName()
200  {
201  return m_Name;
202  }
203 
204  /**
205  * Returns a copy of a subset of the thread's buffer.
206  * Not guaranteed to start on an item boundary.
207  * May be called by any thread.
208  */
209  std::string GetBuffer();
210 
211  private:
212  /**
213  * Store an item into the buffer.
214  */
215  void Write(EItem type, const void* item, u32 itemSize);
216 
217  void WriteHold(EItem type, const void* item, u32 itemSize);
218 
220  std::string m_Name;
221 
222  double m_LastTime; // used for computing relative times
223 
225 
226  struct HoldBuffer
227  {
228  friend class ThreadStorage;
229  public:
231  {
232  buffer = new u8[HOLD_BUFFER_SIZE];
233  memset(buffer, ITEM_NOP, HOLD_BUFFER_SIZE);
234  pos = 0;
235  }
237  {
238  delete[] buffer;
239  }
240  void clear()
241  {
242  pos = 0;
243  }
244  void setType(u8 newType)
245  {
246  type = newType;
247  }
251  };
252 
253  HoldBuffer m_HoldBuffers[8];
254  size_t m_HeldDepth;
255 
256  // To allow hopefully-safe reading of the buffer from a separate thread,
257  // without any expensive synchronisation in the recording thread,
258  // two copies of the current buffer write position are stored.
259  // BufferPos0 is updated before writing; BufferPos1 is updated after writing.
260  // GetBuffer can read Pos1, copy the buffer, read Pos0, then assume any bytes
261  // outside the range Pos1 <= x < Pos0 are safe to use. (Any in that range might
262  // be half-written and corrupted.) (All ranges are modulo BUFFER_SIZE.)
263  // Outside of Write(), these will always be equal.
264  //
265  // TODO: does this attempt at synchronisation (plus use of COMPILER_FENCE etc)
266  // actually work in practice?
269  };
270 
271 public:
272  CProfiler2();
273  ~CProfiler2();
274 
275  /**
276  * Call in main thread to set up the profiler,
277  * before calling any other profiler functions.
278  */
279  void Initialise();
280 
281  /**
282  * Call in main thread to enable the HTTP server.
283  * (Disabled by default for security and performance
284  * and to avoid annoying a firewall.)
285  */
286  void EnableHTTP();
287 
288  /**
289  * Call in main thread to enable the GPU profiling support,
290  * after OpenGL has been initialised.
291  */
292  void EnableGPU();
293 
294  /**
295  * Call in main thread to shut down the GPU profiling support,
296  * before shutting down OpenGL.
297  */
298  void ShutdownGPU();
299 
300  /**
301  * Call in main thread to shut down the profiler's HTTP server
302  */
303  void ShutDownHTTP();
304 
305  /**
306  * Call in main thread to enable/disable the profiler
307  */
308  void Toggle();
309 
310  /**
311  * Call in main thread to shut everything down.
312  * All other profiled threads should have been terminated already.
313  */
314  void Shutdown();
315 
316  /**
317  * Call in any thread to enable the profiler in that thread.
318  * @p name should be unique, and is used by the visualiser to identify
319  * this thread.
320  */
321  void RegisterCurrentThread(const std::string& name);
322 
323  /**
324  * Non-main threads should call this occasionally,
325  * especially if it's been a long time since their last call to the profiler,
326  * or if they've made thousands of calls since the last sync marker.
327  */
329  {
331  }
332 
333  /**
334  * Call in main thread at the start of a frame.
335  */
337  {
340  }
341 
342  void RecordEvent(const char* id)
343  {
345  }
346 
347  void RecordRegionEnter(const char* id)
348  {
350  }
351 
352  void RecordRegionEnter(const char* id, double time)
353  {
354  GetThreadStorage().Record(ITEM_ENTER, time, id);
355  }
356 
358  {
360  }
361 
362  void RecordAttribute(const char* fmt, ...) PRINTF_ARGS(2)
363  {
364  va_list argp;
365  va_start(argp, fmt);
366  GetThreadStorage().RecordAttribute(fmt, argp);
367  va_end(argp);
368  }
369 
370  void RecordGPUFrameStart();
371  void RecordGPUFrameEnd();
372  void RecordGPURegionEnter(const char* id);
373  void RecordGPURegionLeave(const char* id);
374 
375  /**
376  * Hold onto messages until a call to release or write the held messages.
377  */
378  size_t HoldLevel()
379  {
380  return GetThreadStorage().HoldLevel();
381  }
382 
384  {
385  return GetThreadStorage().HoldType();
386  }
387 
388  void HoldMessages(u8 type)
389  {
390  GetThreadStorage().PutOnHold(type);
391  }
392 
393  void StopHoldingMessages(bool writeToBuffer, bool condensed = false)
394  {
395  if (writeToBuffer)
396  GetThreadStorage().HoldToBuffer(condensed);
397  else
399  }
400 
401  /**
402  * Call in any thread to produce a JSON representation of the general
403  * state of the application.
404  */
405  void ConstructJSONOverview(std::ostream& stream);
406 
407  /**
408  * Call in any thread to produce a JSON representation of the buffer
409  * for a given thread.
410  * Returns NULL on success, or an error string.
411  */
412  const char* ConstructJSONResponse(std::ostream& stream, const std::string& thread);
413 
414  /**
415  * Call in any thread to save a JSONP representation of the buffers
416  * for all threads, to a file named profile2.jsonp in the logs directory.
417  */
418  void SaveToFile();
419 
420  double GetTime()
421  {
422  return timer_Time();
423  }
424 
426  {
427  return m_FrameNumber;
428  }
429 
431  {
432  ++m_FrameNumber;
433  }
434 
435  void AddThreadStorage(ThreadStorage* storage);
436  void RemoveThreadStorage(ThreadStorage* storage);
437 
438 private:
439  void InitialiseGPU();
440 
442  {
444  return *m_CurrentStorage;
445  }
446 
448 
450 
452 
454 
455  std::mutex m_Mutex;
456 
457  static thread_local ThreadStorage* m_CurrentStorage;
458  std::vector<std::unique_ptr<ThreadStorage>> m_Threads; // thread-safe; protected by m_Mutex
459 };
460 
461 extern CProfiler2 g_Profiler2;
462 
463 /**
464  * Scope-based enter/leave helper.
465  */
467 {
468 public:
469  CProfile2Region(const char* name) : m_Name(name)
470  {
471  g_Profiler2.RecordRegionEnter(m_Name);
472  }
474  {
475  g_Profiler2.RecordRegionLeave();
476  }
477 protected:
478  const char* m_Name;
479 };
480 
481 /**
482 * Scope-based enter/leave helper.
483 */
485 {
486 public:
487  CProfile2SpikeRegion(const char* name, double spikeLimit);
489 private:
490  const char* m_Name;
491  double m_Limit;
492  double m_StartTime;
494 };
495 
496 /**
497 * Scope-based enter/leave helper.
498 */
500 {
501 public:
502  CProfile2AggregatedRegion(const char* name, double spikeLimit);
504 private:
505  const char* m_Name;
506  double m_Limit;
507  double m_StartTime;
509 };
510 
511 /**
512  * Scope-based GPU enter/leave helper.
513  */
515 {
516 public:
517  CProfile2GPURegion(const char* name) : m_Name(name)
518  {
519  g_Profiler2.RecordGPURegionEnter(m_Name);
520  }
522  {
523  g_Profiler2.RecordGPURegionLeave(m_Name);
524  }
525 private:
526  const char* m_Name;
527 };
528 
529 /**
530  * Starts timing from now until the end of the current scope.
531  * @p region is the name to associate with this region (should be
532  * a constant string literal; the pointer must remain valid forever).
533  * Regions may be nested, but preferably shouldn't be nested deeply since
534  * it hurts the visualisation.
535  */
536 #define PROFILE2(region) CProfile2Region profile2__(region)
537 
538 #define PROFILE2_IFSPIKE(region, limit) CProfile2SpikeRegion profile2__(region, limit)
539 
540 #define PROFILE2_AGGREGATED(region, limit) CProfile2AggregatedRegion profile2__(region, limit)
541 
542 #define PROFILE2_GPU(region) CProfile2GPURegion profile2gpu__(region)
543 
544 /**
545  * Record the named event at the current time.
546  */
547 #define PROFILE2_EVENT(name) g_Profiler2.RecordEvent(name)
548 
549 /**
550  * Associates a string (with printf-style formatting) with the current
551  * region or event.
552  * (If the last profiler call was PROFILE2_EVENT, it associates with that
553  * event; otherwise it associates with the currently-active region.)
554  */
555 #define PROFILE2_ATTR g_Profiler2.RecordAttribute
556 
557 #endif // INCLUDED_PROFILER2
const char * m_Name
Definition: Profiler2.h:490
#define NONCOPYABLE(className)
Indicates that a class is noncopyable (usually due to const or reference members, or because the clas...
Definition: code_annotation.h:227
bool m_Initialised
Definition: Profiler2.h:447
Definition: Profiler2.h:109
static const size_t HOLD_BUFFER_SIZE
Definition: Profiler2.h:132
u8 type
Definition: Profiler2.h:250
Definition: Profiler2.h:144
const std::string & GetName()
Definition: Profiler2.h:199
friend class CProfile2AggregatedRegion
Definition: Profiler2.h:100
#define VPRINTF_ARGS(fmtpos)
Definition: code_annotation.h:256
std::vector< std::unique_ptr< ThreadStorage > > m_Threads
Definition: Profiler2.h:458
CProfile2Region(const char *name)
Definition: Profiler2.h:469
int m_FrameNumber
Definition: Profiler2.h:449
Scope-based enter/leave helper.
Definition: Profiler2.h:484
void AddThreadStorage(ThreadStorage *storage)
Definition: Profiler2.cpp:303
void clear()
Definition: Profiler2.h:240
void RecordFrameStart()
Call in main thread at the start of a frame.
Definition: Profiler2.h:336
u8 * buffer
Definition: Profiler2.h:248
void RecordAttribute(const char *fmt,...) PRINTF_ARGS(2)
Definition: Profiler2.h:362
u32 m_BufferPos0
Definition: Profiler2.h:267
void PutOnHold(u8 type)
Definition: Profiler2.cpp:430
Definition: Profiler2.h:226
u8 HoldType()
Definition: Profiler2.h:383
CProfiler2 & m_Profiler
Definition: Profiler2.h:219
CProfile2GPURegion(const char *name)
Definition: Profiler2.h:517
CProfiler2 g_Profiler2
Definition: Profiler2.cpp:44
#define PRINTF_ARGS(fmtpos)
Definition: code_annotation.h:255
void EnableHTTP()
Call in main thread to enable the HTTP server.
Definition: Profiler2.cpp:177
Scope-based enter/leave helper.
Definition: Profiler2.h:466
uint8_t u8
Definition: types.h:37
Definition: Profiler2.h:107
void ShutDownHTTP()
Call in main thread to shut down the profiler&#39;s HTTP server.
Definition: Profiler2.cpp:222
void RecordAttributePrintf(const char *fmt,...) PRINTF_ARGS(2)
Definition: Profiler2.h:180
void RecordLeave(double t)
Definition: Profiler2.h:172
void HoldToBuffer(bool condensed)
Definition: Profiler2.cpp:681
bool m_PushedHold
Definition: Profiler2.h:493
#define ARRAY_SIZE(name)
Definition: code_annotation.h:348
const char * id
Definition: Profiler2.h:126
u32 pos
Definition: Profiler2.h:249
HoldBuffer()
Definition: Profiler2.h:230
size_t HoldLevel()
Hold onto messages until a call to release or write the held messages.
Definition: Profiler2.h:378
void RecordGPURegionEnter(const char *id)
Definition: Profiler2.cpp:277
std::mutex m_Mutex
Definition: Profiler2.h:455
void RecordRegionEnter(const char *id, double time)
Definition: Profiler2.h:352
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:290
double m_Limit
Definition: Profiler2.h:506
uint32_t u32
Definition: types.h:39
Definition: Profiler2.h:108
void IncrementFrameNumber()
Definition: Profiler2.h:430
void RecordSyncMarker(double t)
Definition: Profiler2.h:146
bool IsMainThread()
Returns whether the current thread is the &#39;main&#39; thread (i.e.
Definition: Threading.cpp:27
Definition: Profiler2GPU.cpp:48
EItem
Item type identifiers.
Definition: Profiler2.h:105
const char * m_Name
Definition: Profiler2.h:505
void setType(u8 newType)
Definition: Profiler2.h:244
static const u8 RESYNC_MAGIC[8]
An arbitrary number to help resyncing with the item stream when parsing.
Definition: Profiler2.h:118
void RegisterCurrentThread(const std::string &name)
Call in any thread to enable the profiler in that thread.
Definition: Profiler2.cpp:289
static thread_local ThreadStorage * m_CurrentStorage
Definition: Profiler2.h:457
double GetTime()
Definition: Profiler2.h:420
const char * m_Name
Definition: Profiler2.h:526
void SaveToFile()
Call in any thread to save a JSONP representation of the buffers for all threads, to a file named pro...
Definition: Profiler2.cpp:939
void RecordAttribute(const char *fmt, va_list argp) VPRINTF_ARGS(2)
Definition: Profiler2.cpp:400
ThreadStorage & GetThreadStorage()
Definition: Profiler2.h:441
size_t HoldLevel()
Definition: Profiler2.cpp:419
void ShutdownGPU()
Call in main thread to shut down the GPU profiling support, before shutting down OpenGL.
Definition: Profiler2.cpp:216
static const size_t BUFFER_SIZE
Definition: Profiler2.h:131
const char * m_Name
Definition: Profiler2.h:478
void Record(EItem type, double t, const char *id)
Definition: Profiler2.h:158
Definition: Profiler2.h:96
void RecordGPURegionLeave(const char *id)
Definition: Profiler2.cpp:283
void ThrowawayHoldBuffer()
Definition: Profiler2.cpp:724
void Initialise()
Call in main thread to set up the profiler, before calling any other profiler functions.
Definition: Profiler2.cpp:163
~CProfile2Region()
Definition: Profiler2.h:473
CProfiler2 & GetProfiler()
Definition: Profiler2.h:194
double timer_Time()
Definition: timer.cpp:130
u8 * m_Buffer
Definition: Profiler2.h:224
Definition: Profiler2.h:110
void RecordRegionLeave()
Definition: Profiler2.h:357
u8 HoldType()
Definition: Profiler2.cpp:424
std::string m_Name
Definition: Profiler2.h:220
double m_Limit
Definition: Profiler2.h:491
void RecordRegionEnter(const char *id)
Definition: Profiler2.h:347
Scope-based enter/leave helper.
Definition: Profiler2.h:499
void Shutdown()
Call in main thread to shut everything down.
Definition: Profiler2.cpp:247
mg_context * m_MgContext
Definition: Profiler2.h:451
double m_LastTime
Definition: Profiler2.h:222
Used by CProfiler2 for GPU profiling support.
Definition: Profiler2GPU.h:33
Definition: Profiler2.h:112
void RecordGPUFrameStart()
Definition: Profiler2.cpp:265
CProfiler2GPU * m_GPU
Definition: Profiler2.h:453
void EnableGPU()
Call in main thread to enable the GPU profiling support, after OpenGL has been initialised.
Definition: Profiler2.cpp:206
~CProfiler2()
Definition: Profiler2.cpp:62
double m_StartTime
Definition: Profiler2.h:507
~CProfile2GPURegion()
Definition: Profiler2.h:521
void StopHoldingMessages(bool writeToBuffer, bool condensed=false)
Definition: Profiler2.h:393
void Toggle()
Call in main thread to enable/disable the profiler.
Definition: Profiler2.cpp:232
void RecordEvent(const char *id)
Definition: Profiler2.h:342
void RemoveThreadStorage(ThreadStorage *storage)
Definition: Profiler2.cpp:309
float dt
Definition: Profiler2.h:125
Definition: Profiler2.h:111
size_t m_HeldDepth
Definition: Profiler2.h:254
CProfiler2()
Definition: Profiler2.cpp:57
double m_StartTime
Definition: Profiler2.h:492
static const size_t MAX_ATTRIBUTE_LENGTH
Definition: Profiler2.h:115
friend class CProfile2SpikeRegion
Definition: Profiler2.h:99
void InitialiseGPU()
Definition: Profiler2.cpp:171
void RecordGPUFrameEnd()
Definition: Profiler2.cpp:271
Scope-based GPU enter/leave helper.
Definition: Profiler2.h:514
void ConstructJSONOverview(std::ostream &stream)
Call in any thread to produce a JSON representation of the general state of the application.
Definition: Profiler2.cpp:731
bool m_PushedHold
Definition: Profiler2.h:508
u32 m_BufferPos1
Definition: Profiler2.h:268
void RecordSyncMarker()
Non-main threads should call this occasionally, especially if it&#39;s been a long time since their last ...
Definition: Profiler2.h:328
Definition: mongoose.cpp:489
An item with a relative time and an ID string pointer.
Definition: Profiler2.h:123
~HoldBuffer()
Definition: Profiler2.h:236
void HoldMessages(u8 type)
Definition: Profiler2.h:388
int GetFrameNumber()
Definition: Profiler2.h:425
Class instantiated in every registered thread.
Definition: Profiler2.h:137
const char * ConstructJSONResponse(std::ostream &stream, const std::string &thread)
Call in any thread to produce a JSON representation of the buffer for a given thread.
Definition: Profiler2.cpp:906
void RecordFrameStart(double t)
Definition: Profiler2.h:166