rewrite profiler
This commit is contained in:
parent
9bb4314cea
commit
63bc6c8674
122
examples/testbed/framework/json_profiler.cpp
Normal file
122
examples/testbed/framework/json_profiler.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <testbed/framework/json_profiler.h>
|
||||||
|
|
||||||
|
#define STRING(x) String(x, sizeof(x) - 1)
|
||||||
|
|
||||||
|
JsonProfiler::JsonProfiler()
|
||||||
|
{
|
||||||
|
m_file = nullptr;
|
||||||
|
m_stream = nullptr;
|
||||||
|
m_writer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonProfiler::~JsonProfiler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProfiler::BeginEvents()
|
||||||
|
{
|
||||||
|
if (m_file)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_file = fopen("profile.json", "wt");
|
||||||
|
if (!m_file)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buffer[512];
|
||||||
|
m_stream = new FileWriteStream(m_file, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
m_writer = new Writer<FileWriteStream>(*m_stream);
|
||||||
|
|
||||||
|
m_writer->StartObject();
|
||||||
|
m_writer->STRING("traceEvents");
|
||||||
|
m_writer->StartArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProfiler::EndEvents()
|
||||||
|
{
|
||||||
|
if (!m_writer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_writer->EndArray();
|
||||||
|
m_writer->EndObject();
|
||||||
|
|
||||||
|
delete m_writer;
|
||||||
|
m_writer = nullptr;
|
||||||
|
|
||||||
|
delete m_stream;
|
||||||
|
m_stream = nullptr;
|
||||||
|
|
||||||
|
fclose(m_file);
|
||||||
|
m_file = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProfiler::BeginEvent(i32 tid, i32 pid, const char* name, float64 t)
|
||||||
|
{
|
||||||
|
if (!m_writer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* phase = "B";
|
||||||
|
|
||||||
|
float64 scale = 1000.0;
|
||||||
|
|
||||||
|
m_writer->StartObject();
|
||||||
|
m_writer->STRING("pid"); m_writer->Int(pid);
|
||||||
|
m_writer->STRING("tid"); m_writer->Int(tid);
|
||||||
|
m_writer->STRING("ts"); m_writer->Int64((u64)(t * scale));
|
||||||
|
m_writer->STRING("ph"); m_writer->String(phase, 1);
|
||||||
|
m_writer->STRING("cat"); m_writer->STRING("physics");
|
||||||
|
m_writer->STRING("name"); m_writer->String(name, strlen(name));
|
||||||
|
m_writer->STRING("args"); m_writer->StartObject(); m_writer->EndObject();
|
||||||
|
m_writer->EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProfiler::EndEvent(i32 tid, i32 pid, const char* name, float64 t)
|
||||||
|
{
|
||||||
|
if (!m_writer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* phase = "E";
|
||||||
|
|
||||||
|
float64 scale = 1000.0;
|
||||||
|
|
||||||
|
m_writer->StartObject();
|
||||||
|
m_writer->STRING("pid"); m_writer->Int(pid);
|
||||||
|
m_writer->STRING("tid"); m_writer->Int(tid);
|
||||||
|
m_writer->STRING("ts"); m_writer->Int64((u64)(t * scale));
|
||||||
|
m_writer->STRING("ph"); m_writer->String(phase, 1);
|
||||||
|
m_writer->STRING("cat"); m_writer->STRING("physics");
|
||||||
|
m_writer->STRING("name"); m_writer->String(name, strlen(name));
|
||||||
|
m_writer->STRING("args"); m_writer->StartObject(); m_writer->EndObject();
|
||||||
|
m_writer->EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef STRING
|
55
examples/testbed/framework/json_profiler.h
Normal file
55
examples/testbed/framework/json_profiler.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JSON_PROFILER_H
|
||||||
|
#define JSON_PROFILER_H
|
||||||
|
|
||||||
|
#include <bounce/common/settings.h>
|
||||||
|
|
||||||
|
#include <rapidjson/filewritestream.h>
|
||||||
|
#include <rapidjson/writer.h>
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
// The following profiler listener is notified by a profiler when events are initiated
|
||||||
|
// or terminated.
|
||||||
|
// When it receives the notification it immediately saves its data into a .json file format.
|
||||||
|
// The .json file can be read and interpreted by the Google Chrome Tracing.
|
||||||
|
// Say chrome://tracing to the web browser and load the file
|
||||||
|
// This file is by default called "profile.json". Any name can be given.
|
||||||
|
// For implementation details, see json_profile.cpp.
|
||||||
|
class JsonProfiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JsonProfiler();
|
||||||
|
~JsonProfiler();
|
||||||
|
|
||||||
|
void BeginEvents();
|
||||||
|
|
||||||
|
void EndEvents();
|
||||||
|
|
||||||
|
void BeginEvent(i32 tid, i32 pid, const char* name, float64 time);
|
||||||
|
|
||||||
|
void EndEvent(i32 tid, i32 pid, const char* name, float64 time);
|
||||||
|
private:
|
||||||
|
FILE * m_file;
|
||||||
|
FileWriteStream* m_stream;
|
||||||
|
Writer<FileWriteStream>* m_writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -40,9 +40,11 @@
|
|||||||
// error
|
// error
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <testbed/framework/testbed_listener.h>
|
||||||
#include <testbed/tests/test.h>
|
#include <testbed/tests/test.h>
|
||||||
#include <glfw/glfw3.h>
|
#include <glfw/glfw3.h>
|
||||||
|
|
||||||
|
//
|
||||||
GLFWwindow* g_window;
|
GLFWwindow* g_window;
|
||||||
Settings g_settings;
|
Settings g_settings;
|
||||||
Test* g_test;
|
Test* g_test;
|
||||||
@ -50,12 +52,27 @@ u32 g_testCount;
|
|||||||
Camera g_camera;
|
Camera g_camera;
|
||||||
DebugDraw* g_debugDraw;
|
DebugDraw* g_debugDraw;
|
||||||
Profiler* g_profiler;
|
Profiler* g_profiler;
|
||||||
|
TestbedListener g_testbedListener;
|
||||||
|
ProfilerListener* g_profilerListener = &g_testbedListener;
|
||||||
|
RecorderProfiler g_recorderProfiler;
|
||||||
bool g_leftDown;
|
bool g_leftDown;
|
||||||
bool g_rightDown;
|
bool g_rightDown;
|
||||||
bool g_shiftDown;
|
bool g_shiftDown;
|
||||||
b3Vec2 g_ps0;
|
b3Vec2 g_ps0;
|
||||||
const char* g_logName = { "log" };
|
const char* g_logName = { "log" };
|
||||||
|
|
||||||
|
// These two functions below implement Bounce's profiling interfaces.
|
||||||
|
// If you're not concerned with profiling then just define two slut functions.
|
||||||
|
bool b3PushProfileScope(const char* name)
|
||||||
|
{
|
||||||
|
return g_profiler->PushEvent(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void b3PopProfileScope()
|
||||||
|
{
|
||||||
|
g_profiler->PopEvent();
|
||||||
|
}
|
||||||
|
|
||||||
static void WindowSize(int w, int h)
|
static void WindowSize(int w, int h)
|
||||||
{
|
{
|
||||||
g_camera.m_width = float32(w);
|
g_camera.m_width = float32(w);
|
||||||
|
@ -17,200 +17,72 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <testbed/framework/profiler.h>
|
#include <testbed/framework/profiler.h>
|
||||||
#include <bounce/common/time.h>
|
|
||||||
#include <bounce/common/template/queue.h>
|
|
||||||
|
|
||||||
struct Event
|
Profiler::Profiler()
|
||||||
{
|
{
|
||||||
i32 tid;
|
m_top = nullptr;
|
||||||
i32 pid;
|
}
|
||||||
const char* name;
|
|
||||||
float64 t0;
|
|
||||||
float64 t1;
|
|
||||||
Event* parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
static b3Time s_time;
|
Profiler::~Profiler()
|
||||||
static b3BoundedQueue<Event, 256> s_events;
|
|
||||||
static Event* s_top = NULL;
|
|
||||||
|
|
||||||
bool b3PushProfileScope(const char* name)
|
|
||||||
{
|
{
|
||||||
s_time.Update();
|
}
|
||||||
|
|
||||||
Event e;
|
bool Profiler::PushEvent(const char* name)
|
||||||
|
{
|
||||||
|
m_time.Update();
|
||||||
|
|
||||||
|
ProfilerEvent e;
|
||||||
e.tid = -1;
|
e.tid = -1;
|
||||||
e.pid = -1;
|
e.pid = -1;
|
||||||
e.t0 = s_time.GetCurrentMilis();
|
e.t0 = m_time.GetCurrentMilis();
|
||||||
e.t1 = 0;
|
e.t1 = 0.0;
|
||||||
e.name = name;
|
e.name = name;
|
||||||
e.parent = s_top;
|
e.parent = m_top;
|
||||||
|
|
||||||
Event* back = s_events.Push(e);
|
ProfilerEvent* back = m_events.Push(e);
|
||||||
if (back)
|
if (back)
|
||||||
{
|
{
|
||||||
s_top = back;
|
m_top = back;
|
||||||
}
|
}
|
||||||
|
|
||||||
return back != NULL;
|
return back != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3PopProfileScope()
|
void Profiler::PopEvent()
|
||||||
{
|
{
|
||||||
B3_ASSERT(s_top);
|
B3_ASSERT(m_top);
|
||||||
B3_ASSERT(s_top->t1 == 0);
|
B3_ASSERT(m_top->t1 == 0.0);
|
||||||
|
|
||||||
s_time.Update();
|
m_time.Update();
|
||||||
s_top->t1 = s_time.GetCurrentMilis();
|
m_top->t1 = m_time.GetCurrentMilis();
|
||||||
B3_ASSERT(s_top->t1 != 0);
|
B3_ASSERT(m_top->t1 != 0.0);
|
||||||
s_top = s_top->parent;
|
m_top = m_top->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileBegin()
|
void Profiler::Begin()
|
||||||
{
|
{
|
||||||
B3_ASSERT(s_events.IsEmpty());
|
// If this assert is hit then it means Profiler::End hasn't been called.
|
||||||
|
B3_ASSERT(m_events.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileEnd()
|
void Profiler::End(ProfilerListener* listener)
|
||||||
{
|
{
|
||||||
ProfileBeginEvents();
|
listener->BeginEvents();
|
||||||
|
|
||||||
while (s_events.IsEmpty() == false)
|
while (m_events.IsEmpty() == false)
|
||||||
{
|
{
|
||||||
const Event& e = s_events.Front();
|
const ProfilerEvent& e = m_events.Front();
|
||||||
s_events.Pop();
|
|
||||||
|
|
||||||
ProfileEvent(e.tid, e.pid, e.name, e.t0, e_begin);
|
m_events.Pop();
|
||||||
ProfileEvent(e.tid, e.pid, e.name, e.t1, e_end);
|
|
||||||
ProfileEvent(e.tid, e.pid, e.name, e.t1 - e.t0);
|
listener->BeginEvent(e.tid, e.pid, e.name, e.t0);
|
||||||
|
|
||||||
|
listener->EndEvent(e.tid, e.pid, e.name, e.t1);
|
||||||
|
|
||||||
|
listener->Duration(e.name, e.t1 - e.t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
B3_ASSERT(s_events.IsEmpty());
|
B3_ASSERT(m_events.IsEmpty());
|
||||||
|
|
||||||
ProfileEndEvents();
|
listener->EndEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
#define PROFILER_SCREEN 1
|
|
||||||
#define PROFILER_JSON 2
|
|
||||||
|
|
||||||
#define PROFILER_OUTPUT PROFILER_SCREEN
|
|
||||||
|
|
||||||
#if PROFILER_OUTPUT == PROFILER_SCREEN
|
|
||||||
|
|
||||||
extern Profiler* g_profiler;
|
|
||||||
|
|
||||||
void ProfileBeginEvents()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 t, ProfileType type)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 elapsed)
|
|
||||||
{
|
|
||||||
g_profiler->Add(name, elapsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEndEvents()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif PROFILER_OUTPUT == PROFILER_JSON
|
|
||||||
|
|
||||||
#include <rapidjson/filewritestream.h>
|
|
||||||
#include <rapidjson/writer.h>
|
|
||||||
|
|
||||||
using namespace rapidjson;
|
|
||||||
|
|
||||||
static FILE* s_file = NULL;
|
|
||||||
static FileWriteStream* s_stream = NULL;
|
|
||||||
static Writer<FileWriteStream>* s_writer = NULL;
|
|
||||||
|
|
||||||
#define STRING(x) String(x, sizeof(x) - 1)
|
|
||||||
|
|
||||||
void ProfileBeginEvents()
|
|
||||||
{
|
|
||||||
if (s_file)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_file = fopen("profile.json", "wt");
|
|
||||||
if (!s_file)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char buffer[512];
|
|
||||||
s_stream = new FileWriteStream(s_file, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
s_writer = new Writer<FileWriteStream>(*s_stream);
|
|
||||||
|
|
||||||
s_writer->StartObject();
|
|
||||||
s_writer->STRING("traceEvents");
|
|
||||||
s_writer->StartArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 t, ProfileType type)
|
|
||||||
{
|
|
||||||
if (!s_writer)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* phase = 0;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case ProfileType::e_begin: phase = "B"; break;
|
|
||||||
case ProfileType::e_end: phase = "E"; break;
|
|
||||||
default: B3_ASSERT(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
float64 scale = 1000.0;
|
|
||||||
|
|
||||||
s_writer->StartObject();
|
|
||||||
s_writer->STRING("pid"); s_writer->Int(pid);
|
|
||||||
s_writer->STRING("tid"); s_writer->Int(tid);
|
|
||||||
s_writer->STRING("ts"); s_writer->Int64((u64)(t * scale));
|
|
||||||
s_writer->STRING("ph"); s_writer->String(phase, 1);
|
|
||||||
s_writer->STRING("cat"); s_writer->STRING("physics");
|
|
||||||
s_writer->STRING("name"); s_writer->String(name, strlen(name));
|
|
||||||
s_writer->STRING("args"); s_writer->StartObject(); s_writer->EndObject();
|
|
||||||
s_writer->EndObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 elapsed)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileEndEvents()
|
|
||||||
{
|
|
||||||
if (!s_writer)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_writer->EndArray();
|
|
||||||
s_writer->EndObject();
|
|
||||||
|
|
||||||
delete s_writer;
|
|
||||||
s_writer = NULL;
|
|
||||||
|
|
||||||
delete s_stream;
|
|
||||||
s_stream = NULL;
|
|
||||||
|
|
||||||
fclose(s_file);
|
|
||||||
s_file = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef STRING
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#endif
|
|
@ -20,64 +20,94 @@
|
|||||||
#define PROFILER_H
|
#define PROFILER_H
|
||||||
|
|
||||||
#include <bounce/common/math/math.h>
|
#include <bounce/common/math/math.h>
|
||||||
|
#include <bounce/common/time.h>
|
||||||
|
#include <bounce/common/template/queue.h>
|
||||||
#include <bounce/common/template/array.h>
|
#include <bounce/common/template/array.h>
|
||||||
|
|
||||||
enum ProfileType
|
// This defines the maximum number of profiler events that can be
|
||||||
|
// queued per frame until the function Profiler::Flush is called.
|
||||||
|
#define MAX_PROFILER_EVENTS 256
|
||||||
|
|
||||||
|
class ProfilerListener;
|
||||||
|
|
||||||
|
// A time-stamped profiler event.
|
||||||
|
struct ProfilerEvent
|
||||||
{
|
{
|
||||||
e_begin,
|
i32 tid;
|
||||||
e_end
|
i32 pid;
|
||||||
};
|
|
||||||
|
|
||||||
void ProfileBeginEvents();
|
|
||||||
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 time, ProfileType type);
|
|
||||||
void ProfileEvent(i32 tid, i32 pid, const char* name, float64 elapsed);
|
|
||||||
|
|
||||||
void ProfileEndEvents();
|
|
||||||
|
|
||||||
void ProfileBegin();
|
|
||||||
void ProfileEnd();
|
|
||||||
|
|
||||||
struct ProfileRecord
|
|
||||||
{
|
|
||||||
float64 elapsed;
|
|
||||||
float64 maxElapsed;
|
|
||||||
const char* name;
|
const char* name;
|
||||||
|
float64 t0;
|
||||||
|
float64 t1;
|
||||||
|
ProfilerEvent* parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A single-threaded event-based profiler.
|
||||||
class Profiler
|
class Profiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Clear()
|
Profiler();
|
||||||
|
|
||||||
|
~Profiler();
|
||||||
|
|
||||||
|
// Must be called before profiling.
|
||||||
|
void Begin();
|
||||||
|
|
||||||
|
// Must be called after profiling.
|
||||||
|
// The function will report all events in this profiler
|
||||||
|
// to the given event listener in the correct calling order.
|
||||||
|
// This function also flushes the profiler.
|
||||||
|
void End(ProfilerListener* listener);
|
||||||
|
|
||||||
|
// Add a profiler event to the queue.
|
||||||
|
// Return true if the even has been added to the event queue
|
||||||
|
// or false if the queue is full.
|
||||||
|
bool PushEvent(const char* name);
|
||||||
|
|
||||||
|
// Remove the top profiler event.
|
||||||
|
void PopEvent();
|
||||||
|
private:
|
||||||
|
b3Time m_time;
|
||||||
|
b3BoundedQueue<ProfilerEvent, MAX_PROFILER_EVENTS> m_events;
|
||||||
|
ProfilerEvent* m_top;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Any implementation of this interface passed to Profiler::End will listen to profile events.
|
||||||
|
class ProfilerListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ProfilerListener() { }
|
||||||
|
|
||||||
|
// This function is called when profiling has began.
|
||||||
|
virtual void BeginEvents() { }
|
||||||
|
|
||||||
|
// This function is called when profiling has ended.
|
||||||
|
virtual void EndEvents() { }
|
||||||
|
|
||||||
|
// This function is called when a profiler event begins.
|
||||||
|
virtual void BeginEvent(i32 tid, i32 pid, const char* name, float64 time)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
B3_NOT_USED(tid);
|
||||||
{
|
B3_NOT_USED(pid);
|
||||||
m_records[i].elapsed = 0;
|
B3_NOT_USED(name);
|
||||||
}
|
B3_NOT_USED(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Add(const char* name, float64 elapsed)
|
// This function is called when a profiler event ends.
|
||||||
|
virtual void EndEvent(i32 tid, i32 pid, const char* name, float64 time)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
B3_NOT_USED(tid);
|
||||||
{
|
B3_NOT_USED(pid);
|
||||||
ProfileRecord& r = m_records[i];
|
B3_NOT_USED(name);
|
||||||
if (r.name == name)
|
B3_NOT_USED(time);
|
||||||
{
|
|
||||||
r.elapsed += elapsed;
|
|
||||||
r.maxElapsed = b3Max(r.maxElapsed, r.elapsed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfileRecord r;
|
|
||||||
r.elapsed = elapsed;
|
|
||||||
r.maxElapsed = 0;
|
|
||||||
r.name = name;
|
|
||||||
|
|
||||||
m_records.PushBack(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b3StackArray<ProfileRecord, 256> m_records;
|
// This function is called when a profiler event ends.
|
||||||
|
// However it supplies the duration of the last begin and end events.
|
||||||
|
virtual void Duration(const char* name, float64 duration)
|
||||||
|
{
|
||||||
|
B3_NOT_USED(name);
|
||||||
|
B3_NOT_USED(duration);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
52
examples/testbed/framework/recorder_profiler.cpp
Normal file
52
examples/testbed/framework/recorder_profiler.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <testbed/framework/recorder_profiler.h>
|
||||||
|
|
||||||
|
void RecorderProfiler::BeginEvents()
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||||
|
{
|
||||||
|
m_records[i].elapsed = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecorderProfiler::EndEvents()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecorderProfiler::Add(const char* name, float64 elapsedTime)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||||
|
{
|
||||||
|
ProfilerRecord& r = m_records[i];
|
||||||
|
if (r.name == name)
|
||||||
|
{
|
||||||
|
r.elapsed += elapsedTime;
|
||||||
|
r.maxElapsed = b3Max(r.maxElapsed, elapsedTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfilerRecord r;
|
||||||
|
r.name = name;
|
||||||
|
r.elapsed = 0.0;
|
||||||
|
r.maxElapsed = 0.0;
|
||||||
|
|
||||||
|
m_records.PushBack(r);
|
||||||
|
}
|
50
examples/testbed/framework/recorder_profiler.h
Normal file
50
examples/testbed/framework/recorder_profiler.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RECORDER_PROFILER_H
|
||||||
|
#define RECORDER_PROFILER_H
|
||||||
|
|
||||||
|
#include <bounce/common/template/array.h>
|
||||||
|
#include <bounce/common/math/math.h>
|
||||||
|
|
||||||
|
// An event in the profiler event recorder.
|
||||||
|
struct ProfilerRecord
|
||||||
|
{
|
||||||
|
float64 elapsed;
|
||||||
|
float64 maxElapsed;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The profiler recorder simply keeps profile events in an event buffer,
|
||||||
|
// so that they can be rendered, saved to a file, etc. later in a
|
||||||
|
// particular position in code.
|
||||||
|
class RecorderProfiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BeginEvents();
|
||||||
|
|
||||||
|
void EndEvents();
|
||||||
|
|
||||||
|
void Add(const char* name, float64 elapsedTime);
|
||||||
|
|
||||||
|
const b3Array<ProfilerRecord>& GetRecords() const { return m_records; }
|
||||||
|
private:
|
||||||
|
b3StackArray<ProfilerRecord, 256> m_records;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -28,6 +28,8 @@ extern Settings g_settings;
|
|||||||
extern DebugDraw* g_debugDraw;
|
extern DebugDraw* g_debugDraw;
|
||||||
extern Camera g_camera;
|
extern Camera g_camera;
|
||||||
extern Profiler* g_profiler;
|
extern Profiler* g_profiler;
|
||||||
|
extern ProfilerListener* g_profilerListener;
|
||||||
|
extern RecorderProfiler g_recorderProfiler;
|
||||||
|
|
||||||
Test::Test()
|
Test::Test()
|
||||||
{
|
{
|
||||||
@ -117,13 +119,13 @@ void Test::Step()
|
|||||||
b3_convexCacheHits = 0;
|
b3_convexCacheHits = 0;
|
||||||
|
|
||||||
// Step
|
// Step
|
||||||
ProfileBegin();
|
g_profiler->Begin();
|
||||||
|
|
||||||
m_world.SetSleeping(g_settings.sleep);
|
m_world.SetSleeping(g_settings.sleep);
|
||||||
m_world.SetWarmStart(g_settings.warmStart);
|
m_world.SetWarmStart(g_settings.warmStart);
|
||||||
m_world.Step(dt, g_settings.velocityIterations, g_settings.positionIterations);
|
m_world.Step(dt, g_settings.velocityIterations, g_settings.positionIterations);
|
||||||
|
|
||||||
ProfileEnd();
|
g_profiler->End(g_profilerListener);
|
||||||
|
|
||||||
g_debugDraw->Submit();
|
g_debugDraw->Submit();
|
||||||
|
|
||||||
@ -191,15 +193,15 @@ void Test::Step()
|
|||||||
|
|
||||||
if (g_settings.drawProfile)
|
if (g_settings.drawProfile)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < g_profiler->m_records.Count(); ++i)
|
const b3Array<ProfilerRecord>& records = g_recorderProfiler.GetRecords();
|
||||||
|
for (u32 i = 0; i < records.Count(); ++i)
|
||||||
{
|
{
|
||||||
const ProfileRecord& r = g_profiler->m_records[i];
|
const ProfilerRecord& r = records[i];
|
||||||
|
|
||||||
ImGui::Text("%s %.4f (%.4f) [ms]", r.name, r.elapsed, r.maxElapsed);
|
ImGui::Text("%s %.4f (%.4f) [ms]", r.name, r.elapsed, r.maxElapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_profiler->Clear();
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
85
examples/testbed/framework/testbed_listener.h
Normal file
85
examples/testbed/framework/testbed_listener.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TESTBED_LISTENER_H
|
||||||
|
#define TESTBED_LISTENER_H
|
||||||
|
|
||||||
|
#include <testbed\framework\profiler.h>
|
||||||
|
#include <testbed\framework\recorder_profiler.h>
|
||||||
|
|
||||||
|
// Set to 1 then the testbed listener will write profile events into a .json file.
|
||||||
|
// Set to 0 otherwise.
|
||||||
|
#define PROFILE_JSON 0
|
||||||
|
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
#include <testbed\framework\json_profiler.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern RecorderProfiler g_recorderProfiler;
|
||||||
|
|
||||||
|
class TestbedListener : public ProfilerListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BeginEvents() override
|
||||||
|
{
|
||||||
|
g_recorderProfiler.BeginEvents();
|
||||||
|
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
m_jsonListener.BeginEvents();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndEvents() override
|
||||||
|
{
|
||||||
|
g_recorderProfiler.EndEvents();
|
||||||
|
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
m_jsonListener.EndEvents();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginEvent(i32 tid, i32 pid, const char* name, float64 time) override
|
||||||
|
{
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
m_jsonListener.BeginEvent(tid, pid, name, time);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndEvent(i32 tid, i32 pid, const char* name, float64 time) override
|
||||||
|
{
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
m_jsonListener.EndEvent(tid, pid, name, time);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Duration(const char* name, float64 time) override
|
||||||
|
{
|
||||||
|
g_recorderProfiler.Add(name, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (PROFILE_JSON == 1)
|
||||||
|
JsonProfiler m_jsonListener;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <testbed/framework/debug_draw.h>
|
#include <testbed/framework/debug_draw.h>
|
||||||
#include <testbed/framework/profiler.h>
|
#include <testbed/framework/profiler.h>
|
||||||
|
#include <testbed/framework/recorder_profiler.h>
|
||||||
|
|
||||||
inline float32 RandomFloat(float32 a, float32 b)
|
inline float32 RandomFloat(float32 a, float32 b)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user