Pyrogenesis  trunk
Profiler2.h
Go to the documentation of this file.
1 /* Copyright (c) 2016 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 struct mg_context;
85 
86 // Note: Lots of functions are defined inline, to hypothetically
87 // minimise performance overhead.
88 
89 class CProfiler2GPU;
90 
92 {
93  friend class CProfiler2GPU_base;
94  friend class CProfile2SpikeRegion;
96 public:
97  // Items stored in the buffers:
98 
99  /// Item type identifiers
100  enum EItem
101  {
102  ITEM_NOP = 0,
103  ITEM_SYNC = 1, // magic value used for parse syncing
104  ITEM_EVENT = 2, // single event
105  ITEM_ENTER = 3, // entering a region
106  ITEM_LEAVE = 4, // leaving a region (must be correctly nested)
107  ITEM_ATTRIBUTE = 5, // arbitrary string associated with current region, or latest event (if the previous item was an event)
108  };
109 
110  static const size_t MAX_ATTRIBUTE_LENGTH = 256; // includes null terminator, which isn't stored
111 
112  /// An arbitrary number to help resyncing with the item stream when parsing.
113  static const u8 RESYNC_MAGIC[8];
114 
115  /**
116  * An item with a relative time and an ID string pointer.
117  */
118  struct SItem_dt_id
119  {
120  float dt; // time relative to last event
121  const char* id;
122  };
123 
124 private:
125  // TODO: what's a good size?
126  // TODO: different threads might want different sizes
127  static const size_t BUFFER_SIZE = 4*1024*1024;
128  static const size_t HOLD_BUFFER_SIZE = 128 * 1024;
129 
130  /**
131  * Class instantiated in every registered thread.
132  */
134  {
136  public:
137  ThreadStorage(CProfiler2& profiler, const std::string& name);
138  ~ThreadStorage();
139 
140  enum { BUFFER_NORMAL, BUFFER_SPIKE, BUFFER_AGGREGATE };
141 
142  void RecordSyncMarker(double t)
143  {
144  // Store the magic string followed by the absolute time
145  // (to correct for drift caused by the precision of relative
146  // times stored in other items)
147  u8 buffer[sizeof(RESYNC_MAGIC) + sizeof(t)];
148  memcpy(buffer, &RESYNC_MAGIC, sizeof(RESYNC_MAGIC));
149  memcpy(buffer + sizeof(RESYNC_MAGIC), &t, sizeof(t));
150  Write(ITEM_SYNC, buffer, ARRAY_SIZE(buffer));
151  m_LastTime = t;
152  }
153 
154  void Record(EItem type, double t, const char* id)
155  {
156  // Store a relative time instead of absolute, so we can use floats
157  // (to save memory) without suffering from precision problems
158  SItem_dt_id item = { (float)(t - m_LastTime), id };
159  Write(type, &item, sizeof(item));
160  }
161 
162  void RecordFrameStart(double t)
163  {
164  RecordSyncMarker(t);
165  Record(ITEM_EVENT, t, "__framestart"); // magic string recognised by the visualiser
166  }
167 
168  void RecordLeave(double t)
169  {
170  float time = (float)(t - m_LastTime);
171  Write(ITEM_LEAVE, &time, sizeof(float));
172  }
173 
174  void RecordAttribute(const char* fmt, va_list argp) VPRINTF_ARGS(2);
175 
176  void RecordAttributePrintf(const char* fmt, ...) PRINTF_ARGS(2)
177  {
178  va_list argp;
179  va_start(argp, fmt);
180  RecordAttribute(fmt, argp);
181  va_end(argp);
182  }
183 
184  size_t HoldLevel();
185  u8 HoldType();
186  void PutOnHold(u8 type);
187  void HoldToBuffer(bool condensed);
188  void ThrowawayHoldBuffer();
189 
191  {
192  return m_Profiler;
193  }
194 
195  const std::string& GetName()
196  {
197  return m_Name;
198  }
199 
200  /**
201  * Returns a copy of a subset of the thread's buffer.
202  * Not guaranteed to start on an item boundary.
203  * May be called by any thread.
204  */
205  std::string GetBuffer();
206 
207  private:
208  /**
209  * Store an item into the buffer.
210  */
211  void Write(EItem type, const void* item, u32 itemSize);
212 
213  void WriteHold(EItem type, const void* item, u32 itemSize);
214 
216  std::string m_Name;
217 
218  double m_LastTime; // used for computing relative times
219 
221 
222  struct HoldBuffer
223  {
224  friend class ThreadStorage;
225  public:
227  {
228  buffer = new u8[HOLD_BUFFER_SIZE];
229  memset(buffer, ITEM_NOP, HOLD_BUFFER_SIZE);
230  pos = 0;
231  }
233  {
234  delete[] buffer;
235  }
236  void clear()
237  {
238  pos = 0;
239  }
240  void setType(u8 newType)
241  {
242  type = newType;
243  }
247  };
248 
249  HoldBuffer m_HoldBuffers[8];
250  size_t m_HeldDepth;
251 
252  // To allow hopefully-safe reading of the buffer from a separate thread,
253  // without any expensive synchronisation in the recording thread,
254  // two copies of the current buffer write position are stored.
255  // BufferPos0 is updated before writing; BufferPos1 is updated after writing.
256  // GetBuffer can read Pos1, copy the buffer, read Pos0, then assume any bytes
257  // outside the range Pos1 <= x < Pos0 are safe to use. (Any in that range might
258  // be half-written and corrupted.) (All ranges are modulo BUFFER_SIZE.)
259  // Outside of Write(), these will always be equal.
260  //
261  // TODO: does this attempt at synchronisation (plus use of COMPILER_FENCE etc)
262  // actually work in practice?
265  };
266 
267 public:
268  CProfiler2();
269  ~CProfiler2();
270 
271  /**
272  * Call in main thread to set up the profiler,
273  * before calling any other profiler functions.
274  */
275  void Initialise();
276 
277  /**
278  * Call in main thread to enable the HTTP server.
279  * (Disabled by default for security and performance
280  * and to avoid annoying a firewall.)
281  */
282  void EnableHTTP();
283 
284  /**
285  * Call in main thread to enable the GPU profiling support,
286  * after OpenGL has been initialised.
287  */
288  void EnableGPU();
289 
290  /**
291  * Call in main thread to shut down the GPU profiling support,
292  * before shutting down OpenGL.
293  */
294  void ShutdownGPU();
295 
296  /**
297  * Call in main thread to shut down the profiler's HTTP server
298  */
299  void ShutDownHTTP();
300 
301  /**
302  * Call in main thread to enable/disable the profiler
303  */
304  void Toggle();
305 
306  /**
307  * Call in main thread to shut everything down.
308  * All other profiled threads should have been terminated already.
309  */
310  void Shutdown();
311 
312  /**
313  * Call in any thread to enable the profiler in that thread.
314  * @p name should be unique, and is used by the visualiser to identify
315  * this thread.
316  */
317  void RegisterCurrentThread(const std::string& name);
318 
319  /**
320  * Non-main threads should call this occasionally,
321  * especially if it's been a long time since their last call to the profiler,
322  * or if they've made thousands of calls since the last sync marker.
323  */
325  {
327  }
328 
329  /**
330  * Call in main thread at the start of a frame.
331  */
333  {
336  }
337 
338  void RecordEvent(const char* id)
339  {
341  }
342 
343  void RecordRegionEnter(const char* id)
344  {
346  }
347 
348  void RecordRegionEnter(const char* id, double time)
349  {
350  GetThreadStorage().Record(ITEM_ENTER, time, id);
351  }
352 
354  {
356  }
357 
358  void RecordAttribute(const char* fmt, ...) PRINTF_ARGS(2)
359  {
360  va_list argp;
361  va_start(argp, fmt);
362  GetThreadStorage().RecordAttribute(fmt, argp);
363  va_end(argp);
364  }
365 
366  void RecordGPUFrameStart();
367  void RecordGPUFrameEnd();
368  void RecordGPURegionEnter(const char* id);
369  void RecordGPURegionLeave(const char* id);
370 
371  /**
372  * Hold onto messages until a call to release or write the held messages.
373  */
374  size_t HoldLevel()
375  {
376  return GetThreadStorage().HoldLevel();
377  }
378 
380  {
381  return GetThreadStorage().HoldType();
382  }
383 
384  void HoldMessages(u8 type)
385  {
386  GetThreadStorage().PutOnHold(type);
387  }
388 
389  void StopHoldingMessages(bool writeToBuffer, bool condensed = false)
390  {
391  if (writeToBuffer)
392  GetThreadStorage().HoldToBuffer(condensed);
393  else
395  }
396 
397  /**
398  * Call in any thread to produce a JSON representation of the general
399  * state of the application.
400  */
401  void ConstructJSONOverview(std::ostream& stream);
402 
403  /**
404  * Call in any thread to produce a JSON representation of the buffer
405  * for a given thread.
406  * Returns NULL on success, or an error string.
407  */
408  const char* ConstructJSONResponse(std::ostream& stream, const std::string& thread);
409 
410  /**
411  * Call in any thread to save a JSONP representation of the buffers
412  * for all threads, to a file named profile2.jsonp in the logs directory.
413  */
414  void SaveToFile();
415 
416  double GetTime()
417  {
418  return timer_Time();
419  }
420 
422  {
423  return m_FrameNumber;
424  }
425 
427  {
428  ++m_FrameNumber;
429  }
430 
431  void AddThreadStorage(ThreadStorage* storage);
432  void RemoveThreadStorage(ThreadStorage* storage);
433 
434 private:
435  void InitialiseGPU();
436 
437  static void TLSDtor(void* data);
438 
440  {
442  ASSERT(storage);
443  return *storage;
444  }
445 
447 
449 
451 
453 
455 
457  std::vector<ThreadStorage*> m_Threads; // thread-safe; protected by m_Mutex
458 };
459 
460 extern CProfiler2 g_Profiler2;
461 
462 /**
463  * Scope-based enter/leave helper.
464  */
466 {
467 public:
468  CProfile2Region(const char* name) : m_Name(name)
469  {
470  g_Profiler2.RecordRegionEnter(m_Name);
471  }
473  {
474  g_Profiler2.RecordRegionLeave();
475  }
476 protected:
477  const char* m_Name;
478 };
479 
480 /**
481 * Scope-based enter/leave helper.
482 */
484 {
485 public:
486  CProfile2SpikeRegion(const char* name, double spikeLimit);
488 private:
489  const char* m_Name;
490  double m_Limit;
491  double m_StartTime;
493 };
494 
495 /**
496 * Scope-based enter/leave helper.
497 */
499 {
500 public:
501  CProfile2AggregatedRegion(const char* name, double spikeLimit);
503 private:
504  const char* m_Name;
505  double m_Limit;
506  double m_StartTime;
508 };
509 
510 /**
511  * Scope-based GPU enter/leave helper.
512  */
514 {
515 public:
516  CProfile2GPURegion(const char* name) : m_Name(name)
517  {
518  g_Profiler2.RecordGPURegionEnter(m_Name);
519  }
521  {
522  g_Profiler2.RecordGPURegionLeave(m_Name);
523  }
524 private:
525  const char* m_Name;
526 };
527 
528 /**
529  * Starts timing from now until the end of the current scope.
530  * @p region is the name to associate with this region (should be
531  * a constant string literal; the pointer must remain valid forever).
532  * Regions may be nested, but preferably shouldn't be nested deeply since
533  * it hurts the visualisation.
534  */
535 #define PROFILE2(region) CProfile2Region profile2__(region)
536 
537 #define PROFILE2_IFSPIKE(region, limit) CProfile2SpikeRegion profile2__(region, limit)
538 
539 #define PROFILE2_AGGREGATED(region, limit) CProfile2AggregatedRegion profile2__(region, limit)
540 
541 #define PROFILE2_GPU(region) CProfile2GPURegion profile2gpu__(region)
542 
543 /**
544  * Record the named event at the current time.
545  */
546 #define PROFILE2_EVENT(name) g_Profiler2.RecordEvent(name)
547 
548 /**
549  * Associates a string (with printf-style formatting) with the current
550  * region or event.
551  * (If the last profiler call was PROFILE2_EVENT, it associates with that
552  * event; otherwise it associates with the currently-active region.)
553  */
554 #define PROFILE2_ATTR g_Profiler2.RecordAttribute
555 
556 #endif // INCLUDED_PROFILER2
const char * m_Name
Definition: Profiler2.h:489
#define NONCOPYABLE(className)
Indicates that a class is noncopyable (usually due to const or reference members, or because the clas...
Definition: code_annotation.h:217
bool m_Initialised
Definition: Profiler2.h:446
Definition: Profiler2.h:104
static const size_t HOLD_BUFFER_SIZE
Definition: Profiler2.h:128
u8 type
Definition: Profiler2.h:246
const std::string & GetName()
Definition: Profiler2.h:195
friend class CProfile2AggregatedRegion
Definition: Profiler2.h:95
#define VPRINTF_ARGS(fmtpos)
Definition: code_annotation.h:244
CProfile2Region(const char *name)
Definition: Profiler2.h:468
int m_FrameNumber
Definition: Profiler2.h:448
Scope-based enter/leave helper.
Definition: Profiler2.h:483
void AddThreadStorage(ThreadStorage *storage)
Definition: Profiler2.cpp:297
void clear()
Definition: Profiler2.h:236
void RecordFrameStart()
Call in main thread at the start of a frame.
Definition: Profiler2.h:332
u8 * buffer
Definition: Profiler2.h:244
void RecordAttribute(const char *fmt,...) PRINTF_ARGS(2)
Definition: Profiler2.h:358
u32 m_BufferPos0
Definition: Profiler2.h:263
void PutOnHold(u8 type)
Definition: Profiler2.cpp:423
Definition: Profiler2.h:222
u8 HoldType()
Definition: Profiler2.h:379
CMutex m_Mutex
Definition: Profiler2.h:456
CProfiler2 & m_Profiler
Definition: Profiler2.h:215
CProfile2GPURegion(const char *name)
Definition: Profiler2.h:516
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:315
Definition: Profiler2GPU.cpp:34
CProfiler2 g_Profiler2
Definition: Profiler2.cpp:36
#define PRINTF_ARGS(fmtpos)
Definition: code_annotation.h:243
A non-recursive mutual exclusion lock.
Definition: ThreadUtil.h:45
void EnableHTTP()
Call in main thread to enable the HTTP server.
Definition: Profiler2.cpp:163
Scope-based enter/leave helper.
Definition: Profiler2.h:465
uint8_t u8
Definition: types.h:37
Definition: Profiler2.h:102
void ShutDownHTTP()
Call in main thread to shut down the profiler&#39;s HTTP server.
Definition: Profiler2.cpp:197
void RecordAttributePrintf(const char *fmt,...) PRINTF_ARGS(2)
Definition: Profiler2.h:176
void RecordLeave(double t)
Definition: Profiler2.h:168
void HoldToBuffer(bool condensed)
Definition: Profiler2.cpp:672
bool m_PushedHold
Definition: Profiler2.h:492
#define ARRAY_SIZE(name)
Definition: code_annotation.h:336
const char * id
Definition: Profiler2.h:121
u32 pos
Definition: Profiler2.h:245
HoldBuffer()
Definition: Profiler2.h:226
size_t HoldLevel()
Hold onto messages until a call to release or write the held messages.
Definition: Profiler2.h:374
void RecordGPURegionEnter(const char *id)
Definition: Profiler2.cpp:257
void RecordRegionEnter(const char *id, double time)
Definition: Profiler2.h:348
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:287
double m_Limit
Definition: Profiler2.h:505
uint32_t u32
Definition: types.h:39
Definition: Profiler2.h:103
void IncrementFrameNumber()
Definition: Profiler2.h:426
void RecordSyncMarker(double t)
Definition: Profiler2.h:142
EItem
Item type identifiers.
Definition: Profiler2.h:100
const char * m_Name
Definition: Profiler2.h:504
void setType(u8 newType)
Definition: Profiler2.h:240
static const u8 RESYNC_MAGIC[8]
An arbitrary number to help resyncing with the item stream when parsing.
Definition: Profiler2.h:113
void RegisterCurrentThread(const std::string &name)
Call in any thread to enable the profiler in that thread.
Definition: Profiler2.cpp:281
double GetTime()
Definition: Profiler2.h:416
const char * m_Name
Definition: Profiler2.h:525
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:933
void RecordAttribute(const char *fmt, va_list argp) VPRINTF_ARGS(2)
Definition: Profiler2.cpp:394
ThreadStorage & GetThreadStorage()
Definition: Profiler2.h:439
size_t HoldLevel()
Definition: Profiler2.cpp:413
void ShutdownGPU()
Call in main thread to shut down the GPU profiling support, before shutting down OpenGL.
Definition: Profiler2.cpp:191
static const size_t BUFFER_SIZE
Definition: Profiler2.h:127
const char * m_Name
Definition: Profiler2.h:477
void Record(EItem type, double t, const char *id)
Definition: Profiler2.h:154
Definition: Profiler2.h:91
void RecordGPURegionLeave(const char *id)
Definition: Profiler2.cpp:263
void ThrowawayHoldBuffer()
Definition: Profiler2.cpp:715
void Initialise()
Call in main thread to set up the profiler, before calling any other profiler functions.
Definition: Profiler2.cpp:147
~CProfile2Region()
Definition: Profiler2.h:472
CProfiler2 & GetProfiler()
Definition: Profiler2.h:190
double timer_Time()
Definition: timer.cpp:98
u8 * m_Buffer
Definition: Profiler2.h:220
void * pthread_getspecific(pthread_key_t key)
Definition: wpthread.cpp:184
Definition: Profiler2.h:105
void RecordRegionLeave()
Definition: Profiler2.h:353
u8 HoldType()
Definition: Profiler2.cpp:418
Definition: Profiler2.h:140
std::string m_Name
Definition: Profiler2.h:216
double m_Limit
Definition: Profiler2.h:490
void RecordRegionEnter(const char *id)
Definition: Profiler2.h:343
Scope-based enter/leave helper.
Definition: Profiler2.h:498
void Shutdown()
Call in main thread to shut everything down.
Definition: Profiler2.cpp:222
mg_context * m_MgContext
Definition: Profiler2.h:450
double m_LastTime
Definition: Profiler2.h:218
Used by CProfiler2 for GPU profiling support.
Definition: Profiler2GPU.h:31
Definition: Profiler2.h:107
void RecordGPUFrameStart()
Definition: Profiler2.cpp:245
CProfiler2GPU * m_GPU
Definition: Profiler2.h:454
void EnableGPU()
Call in main thread to enable the GPU profiling support, after OpenGL has been initialised.
Definition: Profiler2.cpp:181
~CProfiler2()
Definition: Profiler2.cpp:46
double m_StartTime
Definition: Profiler2.h:506
~CProfile2GPURegion()
Definition: Profiler2.h:520
void StopHoldingMessages(bool writeToBuffer, bool condensed=false)
Definition: Profiler2.h:389
void Toggle()
Call in main thread to enable/disable the profiler.
Definition: Profiler2.cpp:207
pthread_key_t m_TLS
Definition: Profiler2.h:452
void RecordEvent(const char *id)
Definition: Profiler2.h:338
bool IsMainThread()
Returns whether the current thread is the &#39;main&#39; thread (i.e.
Definition: ThreadUtil.cpp:25
void RemoveThreadStorage(ThreadStorage *storage)
Definition: Profiler2.cpp:303
float dt
Definition: Profiler2.h:120
Definition: Profiler2.h:106
size_t m_HeldDepth
Definition: Profiler2.h:250
Definition: format.h:119
CProfiler2()
Definition: Profiler2.cpp:41
double m_StartTime
Definition: Profiler2.h:491
static const size_t MAX_ATTRIBUTE_LENGTH
Definition: Profiler2.h:110
friend class CProfile2SpikeRegion
Definition: Profiler2.h:94
void InitialiseGPU()
Definition: Profiler2.cpp:157
void RecordGPUFrameEnd()
Definition: Profiler2.cpp:251
Scope-based GPU enter/leave helper.
Definition: Profiler2.h:513
void ConstructJSONOverview(std::ostream &stream)
Call in any thread to produce a JSON representation of the general state of the application.
Definition: Profiler2.cpp:722
bool m_PushedHold
Definition: Profiler2.h:507
void Write(u64 reg, u64 value)
Definition: msr.cpp:136
unsigned int pthread_key_t
Definition: wpthread.h:93
u32 m_BufferPos1
Definition: Profiler2.h:264
void RecordSyncMarker()
Non-main threads should call this occasionally, especially if it&#39;s been a long time since their last ...
Definition: Profiler2.h:324
Definition: mongoose.cpp:481
An item with a relative time and an ID string pointer.
Definition: Profiler2.h:118
~HoldBuffer()
Definition: Profiler2.h:232
void HoldMessages(u8 type)
Definition: Profiler2.h:384
std::vector< ThreadStorage * > m_Threads
Definition: Profiler2.h:457
int GetFrameNumber()
Definition: Profiler2.h:421
static void TLSDtor(void *data)
Called by pthreads when a registered thread is destroyed.
Definition: Profiler2.cpp:272
Class instantiated in every registered thread.
Definition: Profiler2.h:133
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:895
void RecordFrameStart(double t)
Definition: Profiler2.h:162