23 #include "precompiled.h"
41 m_Initialised(false), m_FrameNumber(0), m_MgContext(NULL), m_GPU(NULL)
59 void* handled = (
void*)
"";
61 const char* header200 =
63 "Access-Control-Allow-Origin: *\r\n"
64 "Content-Type: text/plain; charset=utf-8\r\n\r\n";
66 const char* header404 =
67 "HTTP/1.1 404 Not Found\r\n"
68 "Content-Type: text/plain; charset=utf-8\r\n\r\n"
71 const char* header400 =
72 "HTTP/1.1 400 Bad Request\r\n"
73 "Content-Type: text/plain; charset=utf-8\r\n\r\n"
80 std::stringstream stream;
82 std::string uri = request_info->
uri;
83 if (uri ==
"/overview")
87 else if (uri ==
"/query")
91 mg_printf(conn,
"%s (no query string)", header400);
100 mg_printf(conn,
"%s (no 'thread')", header400);
103 std::string thread(buf);
108 mg_printf(conn,
"%s (%s)", header400, err);
119 std::string str = stream.str();
120 mg_write(conn, str.c_str(), str.length());
165 const char *options[] = {
166 "listening_ports",
"127.0.0.1:8000",
270 m_Profiler(profiler), m_Name(name), m_BufferPos0(0), m_BufferPos1(0), m_LastTime(
timer_Time())
289 u32 pos1 = m_BufferPos1;
295 u32 pos0 = m_BufferPos0;
300 return std::string(buffer.get()+pos0, buffer.get()+
BUFFER_SIZE) + std::string(buffer.get(), buffer.get()+pos1);
302 return std::string(buffer.get()+pos0, buffer.get()+pos1);
319 memcpy(buffer, &len,
sizeof(len));
327 TIMER(L
"profile2 overview");
331 stream <<
"{\"threads\":[";
332 for (
size_t i = 0; i <
m_Threads.size(); ++i)
336 stream <<
"{\"name\":\"" << CStr(
m_Threads[i]->GetName()).EscapeToPrintableASCII() <<
"\"}";
348 TIMER(L
"profile2 visitor");
371 double lastTime = -1;
375 while (pos < buffer.length())
377 u8 type = buffer[pos];
391 memcpy(magic, buffer.c_str()+pos,
ARRAY_SIZE(magic));
394 memcpy(&t, buffer.c_str()+pos,
sizeof(t));
397 visitor.OnSync(lastTime);
403 memcpy(&item, buffer.c_str()+pos,
sizeof(item));
407 lastTime = lastTime + (double)item.
dt;
408 visitor.OnEvent(lastTime, item.
id);
415 memcpy(&item, buffer.c_str()+pos,
sizeof(item));
419 lastTime = lastTime + (double)item.
dt;
420 visitor.OnEnter(lastTime, item.
id);
427 memcpy(&item, buffer.c_str()+pos,
sizeof(item));
431 lastTime = lastTime + (double)item.
dt;
432 visitor.OnLeave(lastTime, item.
id);
439 memcpy(&len, buffer.c_str()+pos,
sizeof(len));
442 std::string attribute(buffer.c_str()+pos, buffer.c_str()+pos+len);
446 visitor.OnAttribute(attribute);
451 debug_warn(L
"Invalid profiler item when parsing buffer");
473 m_Stream <<
"null], [\n";
478 m_Stream <<
"[1," <<
std::fixed << std::setprecision(9) << time;
479 m_Stream <<
",\"" << CStr(
id).EscapeToPrintableASCII() <<
"\"],\n";
484 m_Stream <<
"[2," <<
std::fixed << std::setprecision(9) << time;
485 m_Stream <<
",\"" << CStr(
id).EscapeToPrintableASCII() <<
"\"],\n";
490 m_Stream <<
"[3," <<
std::fixed << std::setprecision(9) << time;
491 m_Stream <<
",\"" << CStr(
id).EscapeToPrintableASCII() <<
"\"],\n";
496 m_Stream <<
"[4,\"" << CStr(attr).EscapeToPrintableASCII() <<
"\"],\n";
504 TIMER(L
"profile2 query");
509 TIMER(L
"profile2 get buffer");
514 for (
size_t i = 0; i <
m_Threads.size(); ++i)
524 return "cannot find named thread";
526 stream <<
"{\"events\":[\n";
535 stream <<
"null]\n]}";
546 std::vector<ThreadStorage*> threads;
553 stream <<
"profileDataCB({\"threads\": [\n";
554 for (
size_t i = 0; i < threads.size(); ++i)
558 stream <<
"{\"name\":\"" << CStr(threads[i]->GetName()).EscapeToPrintableASCII() <<
"\",\n";
559 stream <<
"\"data\": ";
563 stream <<
"\n]});\n";
#define NONCOPYABLE(className)
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
#define COMPILER_FENCE
prevent the compiler from reordering loads or stores across this point.
CFixed_15_16 fixed
Default fixed-point type used by the engine.
const OsPath & psLogDir()
void AddThreadStorage(ThreadStorage *storage)
ThreadStorage(CProfiler2 &profiler, const std::string &name)
void OnLeave(double time, const char *id)
static void out(const wchar_t *fmt,...)
Locks a CMutex over this object's lifetime.
void RunBufferVisitor(const std::string &buffer, V &visitor)
Given a buffer and a visitor class (with functions OnEvent, OnEnter, OnLeave, OnAttribute), calls the visitor for every item in the buffer.
void EnableHTTP()
Call in main thread to enable the HTTP server.
int pthread_key_create(pthread_key_t *key, void(*dtor)(void *))
void RecordGPURegionEnter(const char *id)
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
BufferVisitor_Dump(std::ostream &stream)
std::string GetBuffer()
Returns a copy of a subset of the thread's buffer.
static const u8 RESYNC_MAGIC[8]
An arbitrary number to help resyncing with the item stream when parsing.
void OnEnter(double time, const char *id)
void OnAttribute(const std::string &attr)
New profiler (complementing the older CProfileManager)
void RegisterCurrentThread(const std::string &name)
Call in any thread to enable the profiler in that thread.
void SaveToFile()
Call in any thread to save a JSONP representation of the buffers for all threads, to a file named pro...
int mg_get_var(const char *buf, size_t buf_len, const char *name, char *dst, size_t dst_len)
void RecordAttribute(const char *fmt, va_list argp) VPRINTF_ARGS(2)
#define SAFE_DELETE(p)
delete memory ensuing from new and set the pointer to zero (thus making double-frees safe / a no-op) ...
void ShutdownGPU()
Call in main thread to shut down the GPU profiling support, before shutting down OpenGL.
static const size_t BUFFER_SIZE
int pthread_key_delete(pthread_key_t key)
void RecordGPURegionLeave(const char *id)
void Initialise()
Call in main thread to set up the profiler, before calling any other profiler functions.
CProfiler2 & GetProfiler()
Visitor class that dumps events as JSON.
void * pthread_getspecific(pthread_key_t key)
#define TIMER(description)
Measures the time taken to execute code up until end of the current scope; displays it via debug_prin...
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static void * MgCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info)
Mongoose callback.
void Shutdown()
Call in main thread to shut everything down.
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
int pthread_setspecific(pthread_key_t key, const void *value)
Used by CProfiler2 for GPU profiling support.
void RecordGPUFrameStart()
void EnableGPU()
Call in main thread to enable the GPU profiling support, after OpenGL has been initialised.
void RecordEvent(const char *id)
void RemoveThreadStorage(ThreadStorage *storage)
void RegionLeave(const char *id)
#define debug_warn(expr)
display the error dialog with the given text.
void RegionEnter(const char *id)
static const size_t MAX_ATTRIBUTE_LENGTH
struct mg_context * mg_start(mg_callback_t user_callback, void *user_data, const char **options)
void OnEvent(double time, const char *id)
void ConstructJSONOverview(std::ostream &stream)
Call in any thread to produce a JSON representation of the general state of the application.
void Write(u64 reg, u64 value)
void RecordSyncMarker()
Non-main threads should call this occasionally, especially if it's been a long time since their last ...
An item with a relative time and an ID string pointer.
void mg_stop(struct mg_context *ctx)
std::vector< ThreadStorage * > m_Threads
static void TLSDtor(void *data)
Called by pthreads when a registered thread is destroyed.
Class instantiated in every registered thread.
static std::string OsString(const OsPath &path)
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.