improve profiler
This commit is contained in:
@ -19,6 +19,8 @@
|
||||
#ifndef JSON_PROFILER_H
|
||||
#define JSON_PROFILER_H
|
||||
|
||||
#include <testbed/framework/profiler.h>
|
||||
|
||||
#include <bounce/common/settings.h>
|
||||
|
||||
#include <rapidjson/filewritestream.h>
|
||||
@ -33,19 +35,19 @@ using namespace rapidjson;
|
||||
// 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
|
||||
class JsonProfiler : public ProfilerListener
|
||||
{
|
||||
public:
|
||||
JsonProfiler();
|
||||
~JsonProfiler();
|
||||
|
||||
void BeginEvents();
|
||||
void BeginEvents() override;
|
||||
|
||||
void EndEvents();
|
||||
void EndEvents() override;
|
||||
|
||||
void BeginEvent(const char* name, float64 time);
|
||||
void BeginEvent(const char* name, float64 time) override;
|
||||
|
||||
void EndEvent(const char* name, float64 time);
|
||||
void EndEvent(const char* name, float64 time) override;
|
||||
private:
|
||||
FILE * m_file;
|
||||
FileWriteStream* m_stream;
|
||||
|
@ -101,6 +101,8 @@ static void Run()
|
||||
glfwGetWindowSize(g_window, &w, &h);
|
||||
g_view->Event_SetWindowSize(u32(w), u32(h));
|
||||
|
||||
b3StackArray<ProfilerRecord*, 256> records;
|
||||
|
||||
while (glfwWindowShouldClose(g_window) == 0)
|
||||
{
|
||||
g_profiler->Begin();
|
||||
@ -120,14 +122,10 @@ static void Run()
|
||||
|
||||
if (g_settings->drawProfile)
|
||||
{
|
||||
const b3Array<ProfilerRecord>& records = g_recorderProfiler->GetRecords();
|
||||
for (u32 i = 0; i < records.Count(); ++i)
|
||||
{
|
||||
const ProfilerRecord& r = records[i];
|
||||
if (r.call != 0)
|
||||
{
|
||||
g_draw->DrawString(b3Color_white, "%s %.4f (%.4f) [ms]", r.name, r.elapsed, r.maxElapsed);
|
||||
}
|
||||
ProfilerRecord* r = records[i];
|
||||
g_draw->DrawString(b3Color_white, "%s %.4f (min = %.4f) (max = %.4f) (calls = %d) [ms]", r->name, r->elapsed, r->minElapsed, r->maxElapsed, r->callCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,6 +137,14 @@ static void Run()
|
||||
|
||||
g_profiler->EndScope();
|
||||
|
||||
g_recorderProfiler->BuildRecords();
|
||||
|
||||
if (g_settings->drawProfile)
|
||||
{
|
||||
records.Resize(0);
|
||||
g_recorderProfiler->BuildSortedRecords(records);
|
||||
}
|
||||
|
||||
g_profiler->End();
|
||||
|
||||
glfwSwapBuffers(g_window);
|
||||
|
@ -26,8 +26,11 @@ Model::Model()
|
||||
g_draw = &m_draw;
|
||||
g_camera = &m_camera;
|
||||
g_profiler = &m_profiler;
|
||||
g_recorderProfiler = &m_profilerListener.m_recorderListener;
|
||||
g_profilerListener = &m_profilerListener;
|
||||
g_recorderProfiler = &m_recorderProfiler;
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
g_profilerListener = &m_jsonListener;
|
||||
#endif
|
||||
|
||||
m_test = nullptr;
|
||||
|
||||
@ -54,7 +57,10 @@ Model::~Model()
|
||||
g_camera = nullptr;
|
||||
g_profiler = nullptr;
|
||||
g_recorderProfiler = nullptr;
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
g_profilerListener = nullptr;
|
||||
#endif
|
||||
|
||||
delete m_test;
|
||||
}
|
||||
|
@ -20,7 +20,15 @@
|
||||
#define MODEL_H
|
||||
|
||||
#include <testbed/framework/draw.h>
|
||||
#include <testbed/framework/testbed_profiler.h>
|
||||
#include <testbed/framework/profiler.h>
|
||||
#include <testbed/framework/recorder_profiler.h>
|
||||
|
||||
// Set to 1 to write profile events into a .json file. Set to 0 otherwise.
|
||||
#define PROFILE_JSON 1
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
#include <testbed\framework\json_profiler.h>
|
||||
#endif
|
||||
|
||||
class Test;
|
||||
|
||||
@ -63,7 +71,12 @@ private:
|
||||
Draw m_draw;
|
||||
Camera m_camera;
|
||||
Profiler m_profiler;
|
||||
TestbedProfiler m_profilerListener;
|
||||
RecorderProfiler m_recorderProfiler;
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
JsonProfiler m_jsonListener;
|
||||
#endif
|
||||
|
||||
Test* m_test;
|
||||
bool m_setTest;
|
||||
bool m_pause;
|
||||
|
@ -59,6 +59,8 @@ public:
|
||||
// End the top scope.
|
||||
void EndScope();
|
||||
private:
|
||||
friend class RecorderProfiler;
|
||||
|
||||
ProfilerNode* CreateNode();
|
||||
void DestroyNode(ProfilerNode* node);
|
||||
|
||||
|
@ -17,37 +17,10 @@
|
||||
*/
|
||||
|
||||
#include <testbed/framework/recorder_profiler.h>
|
||||
#include <testbed/framework/profiler.h>
|
||||
|
||||
RecorderProfiler* g_recorderProfiler = nullptr;
|
||||
|
||||
void RecorderProfiler::BeginEvents()
|
||||
{
|
||||
m_call = 0;
|
||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||
{
|
||||
m_records[i].elapsed = 0.0;
|
||||
m_records[i].call = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RecorderProfiler::EndEvents()
|
||||
{
|
||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||
{
|
||||
ProfilerRecord& r1 = m_records[i];
|
||||
|
||||
for (u32 j = i + 1; j < m_records.Count(); ++j)
|
||||
{
|
||||
ProfilerRecord& r2 = m_records[j];
|
||||
|
||||
if (r2.call < r1.call)
|
||||
{
|
||||
b3Swap(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfilerRecord* RecorderProfiler::FindRecord(const char* name)
|
||||
{
|
||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||
@ -61,35 +34,87 @@ ProfilerRecord* RecorderProfiler::FindRecord(const char* name)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RecorderProfiler::BeginEvent(const char* name, float64 time)
|
||||
void RecorderProfiler::RecurseBuildRecords(ProfilerNode* node)
|
||||
{
|
||||
++m_call;
|
||||
|
||||
ProfilerRecord* fr = FindRecord(name);
|
||||
ProfilerRecord* fr = FindRecord(node->name);
|
||||
if (fr)
|
||||
{
|
||||
fr->time = time;
|
||||
fr->call = m_call;
|
||||
return;
|
||||
float64 elapsedTime = node->t1 - node->t0;
|
||||
|
||||
fr->elapsed += elapsedTime;
|
||||
fr->minElapsed = b3Min(fr->minElapsed, elapsedTime);
|
||||
fr->maxElapsed = b3Max(fr->maxElapsed, elapsedTime);
|
||||
++fr->callCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
float64 elapsedTime = node->t1 - node->t0;
|
||||
|
||||
ProfilerRecord r;
|
||||
r.name = node->name;
|
||||
r.elapsed = elapsedTime;
|
||||
r.minElapsed = elapsedTime;
|
||||
r.maxElapsed = elapsedTime;
|
||||
r.callCount = 1;
|
||||
|
||||
m_records.PushBack(r);
|
||||
}
|
||||
|
||||
ProfilerRecord r;
|
||||
r.name = name;
|
||||
r.time = time;
|
||||
r.elapsed = 0.0;
|
||||
r.maxElapsed = 0.0;
|
||||
r.call = m_call;
|
||||
|
||||
m_records.PushBack(r);
|
||||
for (u32 i = 0; i < node->children.Count(); ++i)
|
||||
{
|
||||
RecurseBuildRecords(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void RecorderProfiler::EndEvent(const char* name, float64 time)
|
||||
void RecorderProfiler::BuildRecords()
|
||||
{
|
||||
ProfilerRecord* fr = FindRecord(name);
|
||||
B3_ASSERT(fr != nullptr);
|
||||
for (u32 i = 0; i < m_records.Count(); ++i)
|
||||
{
|
||||
m_records[i].elapsed = 0.0;
|
||||
m_records[i].callCount = 0;
|
||||
}
|
||||
|
||||
float64 elapsedTime = time - fr->time;
|
||||
|
||||
fr->elapsed += elapsedTime;
|
||||
fr->maxElapsed = b3Max(fr->maxElapsed, elapsedTime);
|
||||
RecurseBuildRecords(g_profiler->m_root);
|
||||
}
|
||||
|
||||
static ProfilerRecord* FindSortedRecord(b3Array<ProfilerRecord*>& records, const char* name)
|
||||
{
|
||||
for (u32 i = 0; i < records.Count(); ++i)
|
||||
{
|
||||
ProfilerRecord* r = records[i];
|
||||
if (r->name == name)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RecorderProfiler::RecurseBuildSortedRecords(ProfilerNode* node, b3Array<ProfilerRecord*>& output)
|
||||
{
|
||||
ProfilerRecord* fsr = FindSortedRecord(output, node->name);
|
||||
|
||||
if (fsr == nullptr)
|
||||
{
|
||||
ProfilerRecord* fr = FindRecord(node->name);
|
||||
|
||||
assert(fr != nullptr);
|
||||
|
||||
// Push back the first ocurrence of call in calling order
|
||||
output.PushBack(fr);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < node->children.Count(); ++i)
|
||||
{
|
||||
RecurseBuildSortedRecords(node->children[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
void RecorderProfiler::BuildSortedRecords(b3Array<ProfilerRecord*>& output)
|
||||
{
|
||||
assert(output.Count() == 0);
|
||||
|
||||
output.Reserve(m_records.Count());
|
||||
|
||||
RecurseBuildSortedRecords(g_profiler->m_root, output);
|
||||
}
|
@ -19,39 +19,38 @@
|
||||
#ifndef RECORDER_PROFILER_H
|
||||
#define RECORDER_PROFILER_H
|
||||
|
||||
#include <bounce/common/template/array.h>
|
||||
#include <bounce/common/math/math.h>
|
||||
#include <bounce/common/template/array.h>
|
||||
|
||||
// An event in the profiler event recorder.
|
||||
struct ProfilerNode;
|
||||
|
||||
// A persistent profiler record
|
||||
struct ProfilerRecord
|
||||
{
|
||||
const char* name;
|
||||
float64 time;
|
||||
float64 elapsed;
|
||||
float64 minElapsed;
|
||||
float64 maxElapsed;
|
||||
u32 call;
|
||||
u32 callCount;
|
||||
};
|
||||
|
||||
// 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.
|
||||
// This class maintains persistent profiler records
|
||||
class RecorderProfiler
|
||||
{
|
||||
public:
|
||||
void BeginEvents();
|
||||
void BuildRecords();
|
||||
|
||||
void EndEvents();
|
||||
|
||||
void BeginEvent(const char* name, float64 time);
|
||||
|
||||
void EndEvent(const char* name, float64 time);
|
||||
void BuildSortedRecords(b3Array<ProfilerRecord*>& output);
|
||||
|
||||
const b3Array<ProfilerRecord>& GetRecords() const { return m_records; }
|
||||
private:
|
||||
void RecurseBuildRecords(ProfilerNode* node);
|
||||
|
||||
void RecurseBuildSortedRecords(ProfilerNode* node, b3Array<ProfilerRecord*>& output);
|
||||
|
||||
ProfilerRecord* FindRecord(const char* name);
|
||||
|
||||
b3StackArray<ProfilerRecord, 256> m_records; // persistent records sorted by call order
|
||||
u32 m_call;
|
||||
b3StackArray<ProfilerRecord, 256> m_records; // persistent profiler records
|
||||
};
|
||||
|
||||
extern RecorderProfiler* g_recorderProfiler;
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
|
||||
*
|
||||
* 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_PROFILER_H
|
||||
#define TESTBED_PROFILER_H
|
||||
|
||||
#include <testbed/framework/profiler.h>
|
||||
#include <testbed/framework/recorder_profiler.h>
|
||||
|
||||
// Set to 1 then the testbed profiler 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
|
||||
|
||||
class TestbedProfiler : public ProfilerListener
|
||||
{
|
||||
public:
|
||||
void BeginEvents() override
|
||||
{
|
||||
m_recorderListener.BeginEvents();
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
m_jsonListener.BeginEvents();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void EndEvents() override
|
||||
{
|
||||
m_recorderListener.EndEvents();
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
m_jsonListener.EndEvents();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void BeginEvent(const char* name, float64 time) override
|
||||
{
|
||||
m_recorderListener.BeginEvent(name, time);
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
m_jsonListener.BeginEvent(name, time);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EndEvent(const char* name, float64 time) override
|
||||
{
|
||||
m_recorderListener.EndEvent(name, time);
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
m_jsonListener.EndEvent(name, time);
|
||||
#endif
|
||||
}
|
||||
|
||||
RecorderProfiler m_recorderListener;
|
||||
|
||||
#if (PROFILE_JSON == 1)
|
||||
JsonProfiler m_jsonListener;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user