Add first rudimentary way to dump profiler measurements to CSV. More work to do!
This commit is contained in:
parent
0e722b30a3
commit
8227e1c092
@ -29,6 +29,7 @@
|
||||
#include "main_loop.hpp"
|
||||
#include "replay/replay_recorder.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/profiler.hpp"
|
||||
#include <IGUIEnvironment.h>
|
||||
#include <IGUIContextMenu.h>
|
||||
using namespace irr;
|
||||
@ -57,6 +58,7 @@ enum DebugMenuCommand
|
||||
DEBUG_GRAPHICS_BULLET_1,
|
||||
DEBUG_GRAPHICS_BULLET_2,
|
||||
DEBUG_PROFILER,
|
||||
DEBUG_PROFILER_GENERATE_REPORT,
|
||||
DEBUG_FPS,
|
||||
DEBUG_SAVE_REPLAY,
|
||||
DEBUG_SAVE_HISTORY,
|
||||
@ -135,6 +137,8 @@ bool onEvent(const SEvent &event)
|
||||
sub->addItem(L"Nitro", DEBUG_POWERUP_NITRO );
|
||||
|
||||
mnu->addItem(L"Profiler",DEBUG_PROFILER);
|
||||
if (UserConfigParams::m_profiler_enabled)
|
||||
mnu->addItem(L"Toggle capture profiler report", DEBUG_PROFILER_GENERATE_REPORT);
|
||||
mnu->addItem(L"Do not limit FPS", DEBUG_THROTTLE_FPS);
|
||||
mnu->addItem(L"FPS",DEBUG_FPS);
|
||||
mnu->addItem(L"Save replay", DEBUG_SAVE_REPLAY);
|
||||
@ -254,6 +258,10 @@ bool onEvent(const SEvent &event)
|
||||
UserConfigParams::m_profiler_enabled =
|
||||
!UserConfigParams::m_profiler_enabled;
|
||||
}
|
||||
else if (cmdID == DEBUG_PROFILER_GENERATE_REPORT)
|
||||
{
|
||||
profiler.setCaptureReport(!profiler.getCaptureReport());
|
||||
}
|
||||
else if (cmdID == DEBUG_THROTTLE_FPS)
|
||||
{
|
||||
main_loop->setThrottleFPS(false);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "guiengine/event_handler.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "io/xml_writer.hpp"
|
||||
#include <assert.h>
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
@ -71,6 +72,9 @@ Profiler::Profiler()
|
||||
m_time_last_sync = _getTimeMilliseconds();
|
||||
m_time_between_sync = 0.0;
|
||||
m_freeze_state = UNFROZEN;
|
||||
m_capture_report = false;
|
||||
m_first_capture_sweep = true;
|
||||
m_capture_report_buffer = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -78,6 +82,31 @@ Profiler::~Profiler()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Profiler::setCaptureReport(bool captureReport)
|
||||
{
|
||||
if (!m_capture_report && captureReport)
|
||||
{
|
||||
m_capture_report = true;
|
||||
m_first_capture_sweep = true;
|
||||
// TODO: a 20 MB hardcoded buffer for now. That should amply suffice for
|
||||
// all reasonable purposes. But it's not too clean to hardcode
|
||||
m_capture_report_buffer = new StringBuffer(20 * 1024 * 1024);
|
||||
}
|
||||
else if (m_capture_report && !captureReport)
|
||||
{
|
||||
// when disabling capture to file, flush captured data to a file
|
||||
{
|
||||
XMLWriter writer(file_manager->getUserConfigFile("profiling.csv").c_str());
|
||||
writer << m_capture_report_buffer->getRawBuffer();
|
||||
}
|
||||
m_capture_report = false;
|
||||
delete m_capture_report_buffer;
|
||||
m_capture_report_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Push a new marker that starts now
|
||||
void Profiler::pushCpuMarker(const char* name, const video::SColor& color)
|
||||
@ -194,7 +223,7 @@ void Profiler::draw()
|
||||
// Force to show the pointer
|
||||
irr_driver->showPointer();
|
||||
|
||||
int read_id = !m_write_id;
|
||||
int read_id = (m_freeze_state == FROZEN ? !m_write_id : m_write_id);
|
||||
|
||||
// Compute some values for drawing (unit: pixels, but we keep floats for reducing errors accumulation)
|
||||
core::dimension2d<u32> screen_size = driver->getScreenSize();
|
||||
@ -232,19 +261,34 @@ void Profiler::draw()
|
||||
core::vector2di mouse_pos = GUIEngine::EventHandler::get()->getMousePos();
|
||||
|
||||
// For each thread:
|
||||
for(size_t i=0 ; i < nb_thread_infos ; i++)
|
||||
for (size_t i = 0; i < nb_thread_infos; i++)
|
||||
{
|
||||
// Draw all markers
|
||||
MarkerList& markers = m_thread_infos[i].markers_done[read_id];
|
||||
|
||||
if(markers.empty())
|
||||
if (markers.empty())
|
||||
continue;
|
||||
|
||||
if (m_capture_report)
|
||||
{
|
||||
if (m_first_capture_sweep)
|
||||
m_capture_report_buffer->getStdStream() << "\"Thread\";";
|
||||
else
|
||||
m_capture_report_buffer->getStdStream() << i << ";";
|
||||
}
|
||||
MarkerList::const_iterator it_end = markers.end();
|
||||
for(MarkerList::const_iterator it = markers.begin() ; it != it_end ; it++)
|
||||
for (MarkerList::const_iterator it = markers.begin(); it != it_end; it++)
|
||||
{
|
||||
const Marker& m = *it;
|
||||
assert(m.end >= 0.0);
|
||||
|
||||
if (m_capture_report)
|
||||
{
|
||||
if (m_first_capture_sweep)
|
||||
m_capture_report_buffer->getStdStream() << "\"" << m.name << "\";";
|
||||
else
|
||||
m_capture_report_buffer->getStdStream() << (int)std::round((m.end - m.start) * 1000) << ";";
|
||||
}
|
||||
core::rect<s32> pos((s32)( x_offset + factor*m.start ),
|
||||
(s32)( y_offset + i*line_height ),
|
||||
(s32)( x_offset + factor*m.end ),
|
||||
@ -260,6 +304,12 @@ void Profiler::draw()
|
||||
if(pos.isPointInside(mouse_pos))
|
||||
hovered_markers.push(m);
|
||||
}
|
||||
|
||||
if (m_capture_report)
|
||||
{
|
||||
m_capture_report_buffer->getStdStream() << "\n";
|
||||
m_first_capture_sweep = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the end of the frame
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <streambuf>
|
||||
|
||||
|
||||
class Profiler;
|
||||
extern Profiler profiler;
|
||||
@ -50,6 +52,41 @@ extern Profiler profiler;
|
||||
|
||||
using namespace irr;
|
||||
|
||||
/** For profiling reports, we need a custom strijng stream that writes to a large
|
||||
pre-allocated buffer, to avoid allocating as much as possible durign profiling */
|
||||
template <typename char_type>
|
||||
struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> >
|
||||
{
|
||||
ostreambuf(char_type* buffer, std::streamsize bufferLength)
|
||||
{
|
||||
// set the "put" pointer the start of the buffer and record it's length.
|
||||
setp(buffer, buffer + bufferLength);
|
||||
}
|
||||
};
|
||||
|
||||
class StringBuffer
|
||||
{
|
||||
private:
|
||||
char* m_buffer;
|
||||
ostreambuf<char> ostreamBuffer;
|
||||
std::ostream messageStream;
|
||||
|
||||
public:
|
||||
|
||||
StringBuffer(unsigned int size) : m_buffer(new char[size]), ostreamBuffer(m_buffer, size), messageStream(&ostreamBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
~StringBuffer()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
std::ostream& getStdStream() { return messageStream; }
|
||||
|
||||
char* getRawBuffer() { return m_buffer; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief class that allows run-time graphical profiling through the use of markers
|
||||
* \ingroup utils
|
||||
@ -104,6 +141,10 @@ private:
|
||||
|
||||
FreezeState m_freeze_state;
|
||||
|
||||
bool m_capture_report;
|
||||
bool m_first_capture_sweep;
|
||||
StringBuffer* m_capture_report_buffer;
|
||||
|
||||
public:
|
||||
Profiler();
|
||||
virtual ~Profiler();
|
||||
@ -116,10 +157,13 @@ public:
|
||||
|
||||
void onClick(const core::vector2di& mouse_pos);
|
||||
|
||||
bool getCaptureReport() const { return m_capture_report; }
|
||||
void setCaptureReport(bool captureReport);
|
||||
protected:
|
||||
// TODO: detect on which thread this is called to support multithreading
|
||||
ThreadInfo& getThreadInfo() { return m_thread_infos[0]; }
|
||||
void drawBackground();
|
||||
|
||||
};
|
||||
|
||||
#endif // PROFILER_HPP
|
||||
|
Loading…
Reference in New Issue
Block a user