improve profiler

This commit is contained in:
Irlan
2019-04-01 11:03:12 -03:00
parent 3f55504a91
commit f195e77be7
8 changed files with 133 additions and 162 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -59,6 +59,8 @@ public:
// End the top scope.
void EndScope();
private:
friend class RecorderProfiler;
ProfilerNode* CreateNode();
void DestroyNode(ProfilerNode* node);

View File

@ -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;
}
ProfilerRecord r;
r.name = name;
r.time = time;
r.elapsed = 0.0;
r.maxElapsed = 0.0;
r.call = m_call;
m_records.PushBack(r);
}
void RecorderProfiler::EndEvent(const char* name, float64 time)
{
ProfilerRecord* fr = FindRecord(name);
B3_ASSERT(fr != nullptr);
float64 elapsedTime = time - fr->time;
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);
}
for (u32 i = 0; i < node->children.Count(); ++i)
{
RecurseBuildRecords(node->children[i]);
}
}
void RecorderProfiler::BuildRecords()
{
for (u32 i = 0; i < m_records.Count(); ++i)
{
m_records[i].elapsed = 0.0;
m_records[i].callCount = 0;
}
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);
}

View File

@ -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;

View File

@ -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