Improved the profiler: a bar is displayed to show the end of the analyzed frame, there are more markers, now the profiler can be frozen/unfrozen by clicking on it...

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9211 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
funto66 2011-07-10 00:04:12 +00:00
parent 1b2a6bec27
commit 49ea3a9cf9
5 changed files with 166 additions and 65 deletions

View File

@ -1204,7 +1204,10 @@ void IrrDriver::update(float dt)
true, video::SColor(255,100,101,140)); true, video::SColor(255,100,101,140));
} }
{ // Just to mark the begin/end scene block {
PROFILER_PUSH_CPU_MARKER("Update GUI widgets", 0x7F, 0x7F, 0x00);
// Just to mark the begin/end scene block
GUIEngine::GameState state = StateManager::get()->getGameState(); GUIEngine::GameState state = StateManager::get()->getGameState();
if (state != GUIEngine::GAME) if (state != GUIEngine::GAME)
{ {
@ -1217,6 +1220,8 @@ void IrrDriver::update(float dt)
} }
} }
PROFILER_POP_CPU_MARKER();
if (inRace) if (inRace)
{ {
irr_driver->getVideoDriver()->enableMaterial2D(); irr_driver->getVideoDriver()->enableMaterial2D();
@ -1227,8 +1232,17 @@ void IrrDriver::update(float dt)
Kart *kart=world->getKart(i); Kart *kart=world->getKart(i);
if(kart->getCamera()) if(kart->getCamera())
{ {
{
char marker_name[100];
sprintf(marker_name, "drawAll() for kart %d", i);
PROFILER_PUSH_CPU_MARKER(marker_name, (i+1)*60, 0x00, 0x00);
}
kart->getCamera()->activate(); kart->getCamera()->activate();
m_scene_manager->drawAll(); m_scene_manager->drawAll();
PROFILER_POP_CPU_MARKER();
// Note that drawAll must be called before rendering // Note that drawAll must be called before rendering
// the bullet debug view, since otherwise the camera // the bullet debug view, since otherwise the camera
// is not set up properly. This is only used for // is not set up properly. This is only used for
@ -1248,7 +1262,17 @@ void IrrDriver::update(float dt)
{ {
Kart *kart = world->getKart(i); Kart *kart = world->getKart(i);
if(kart->getCamera()) if(kart->getCamera())
{
{
char marker_name[100];
sprintf(marker_name, "renderPlayerView() for kart %d", i);
PROFILER_PUSH_CPU_MARKER(marker_name, 0x00, 0x00, (i+1)*60);
}
rg->renderPlayerView(kart); rg->renderPlayerView(kart);
PROFILER_POP_CPU_MARKER();
}
} // for i<getNumKarts } // for i<getNumKarts
} }
else else

View File

@ -31,6 +31,7 @@
#include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp"
#include "input/input_manager.hpp" #include "input/input_manager.hpp"
#include "states_screens/state_manager.hpp" #include "states_screens/state_manager.hpp"
#include "utils/profiler.hpp"
using GUIEngine::EventHandler; using GUIEngine::EventHandler;
using GUIEngine::EventPropagation; using GUIEngine::EventPropagation;
@ -138,6 +139,10 @@ bool EventHandler::OnEvent (const SEvent &event)
m_mouse_pos.X = event.MouseInput.X; m_mouse_pos.X = event.MouseInput.X;
m_mouse_pos.Y = event.MouseInput.Y; m_mouse_pos.Y = event.MouseInput.Y;
// Notify the profiler
if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && UserConfigParams::m_profiler_enabled)
profiler.onClick(m_mouse_pos);
// FIXME? it may be a bit unclean that all input events go trough the gui module // FIXME? it may be a bit unclean that all input events go trough the gui module
const EventPropagation blockPropagation = input_manager->input(event); const EventPropagation blockPropagation = input_manager->input(event);
return blockPropagation == EVENT_BLOCK; return blockPropagation == EVENT_BLOCK;

View File

@ -148,7 +148,7 @@ void MainLoop::run()
input_manager->update(dt); input_manager->update(dt);
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Music manager update", 0x00, 0x00, 0x7F); PROFILER_PUSH_CPU_MARKER("IrrDriver update", 0x00, 0x00, 0x7F);
irr_driver->update(dt); irr_driver->update(dt);
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();

View File

@ -30,9 +30,9 @@ Profiler profiler;
#define MARGIN_Y 0.02 // top margin #define MARGIN_Y 0.02 // top margin
#define LINE_HEIGHT 0.015 // height of a line representing a thread #define LINE_HEIGHT 0.015 // height of a line representing a thread
#define MARKERS_NAMES_POS core::rect<s32>(10,50,260,80) #define MARKERS_NAMES_POS core::rect<s32>(50,50,150,150)
#define TIME_DRAWN_MS 100.0 // the width of the profiler corresponds to TIME_DRAWN_MS milliseconds #define TIME_DRAWN_MS 30.0 // the width of the profiler corresponds to TIME_DRAWN_MS milliseconds
// --- Begin portable precise timer --- // --- Begin portable precise timer ---
#ifdef WIN32 #ifdef WIN32
@ -63,9 +63,11 @@ Profiler profiler;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
Profiler::Profiler() Profiler::Profiler()
{ {
thread_infos.resize(1); // TODO: monothread now, should support multithreading m_thread_infos.resize(1); // TODO: monothread now, should support multithreading
write_id = 0; m_write_id = 0;
time_last_sync = _getTimeMilliseconds(); m_time_last_sync = _getTimeMilliseconds();
m_time_between_sync = 0.0;
m_freeze_state = UNFROZEN;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -77,9 +79,13 @@ Profiler::~Profiler()
/// Push a new marker that starts now /// Push a new marker that starts now
void Profiler::pushCpuMarker(const char* name, const video::SColor& color) void Profiler::pushCpuMarker(const char* name, const video::SColor& color)
{ {
// Don't do anything when frozen
if(m_freeze_state == FROZEN || m_freeze_state == WAITING_FOR_UNFREEZE)
return;
ThreadInfo& ti = getThreadInfo(); ThreadInfo& ti = getThreadInfo();
MarkerStack& markers_stack = ti.markers_stack[write_id]; MarkerStack& markers_stack = ti.markers_stack[m_write_id];
double start = _getTimeMilliseconds() - time_last_sync; double start = _getTimeMilliseconds() - m_time_last_sync;
size_t layer = markers_stack.size(); size_t layer = markers_stack.size();
// Add to the stack of current markers // Add to the stack of current markers
@ -90,15 +96,19 @@ void Profiler::pushCpuMarker(const char* name, const video::SColor& color)
/// Stop the last pushed marker /// Stop the last pushed marker
void Profiler::popCpuMarker() void Profiler::popCpuMarker()
{ {
ThreadInfo& ti = getThreadInfo(); // Don't do anything when frozen
assert(ti.markers_stack[write_id].size() > 0); if(m_freeze_state == FROZEN || m_freeze_state == WAITING_FOR_UNFREEZE)
return;
MarkerStack& markers_stack = ti.markers_stack[write_id]; ThreadInfo& ti = getThreadInfo();
MarkerList& markers_done = ti.markers_done[write_id]; assert(ti.markers_stack[m_write_id].size() > 0);
MarkerStack& markers_stack = ti.markers_stack[m_write_id];
MarkerList& markers_done = ti.markers_done[m_write_id];
// Update the date of end of the marker // Update the date of end of the marker
Marker& marker = markers_stack.top(); Marker& marker = markers_stack.top();
marker.end = _getTimeMilliseconds() - time_last_sync; marker.end = _getTimeMilliseconds() - m_time_last_sync;
// Remove the marker from the stack and add it to the list of markers done // Remove the marker from the stack and add it to the list of markers done
markers_done.push_front(marker); markers_done.push_front(marker);
@ -109,16 +119,20 @@ void Profiler::popCpuMarker()
/// Swap buffering for the markers /// Swap buffering for the markers
void Profiler::synchronizeFrame() void Profiler::synchronizeFrame()
{ {
// Don't do anything when frozen
if(m_freeze_state == FROZEN)
return;
// Avoid using several times _getTimeMilliseconds(), which would yield different results // Avoid using several times _getTimeMilliseconds(), which would yield different results
double now = _getTimeMilliseconds(); double now = _getTimeMilliseconds();
// Swap buffers // Swap buffers
int old_write_id = write_id; int old_write_id = m_write_id;
write_id = !write_id; m_write_id = !m_write_id;
// For each thread: // For each thread:
ThreadInfoList::iterator it_end = thread_infos.end(); ThreadInfoList::iterator it_end = m_thread_infos.end();
for(ThreadInfoList::iterator it = thread_infos.begin() ; it != it_end ; it++) for(ThreadInfoList::iterator it = m_thread_infos.begin() ; it != it_end ; it++)
{ {
// Get the thread information // Get the thread information
ThreadInfo& ti = *it; ThreadInfo& ti = *it;
@ -126,8 +140,8 @@ void Profiler::synchronizeFrame()
MarkerList& old_markers_done = ti.markers_done[old_write_id]; MarkerList& old_markers_done = ti.markers_done[old_write_id];
MarkerStack& old_markers_stack = ti.markers_stack[old_write_id]; MarkerStack& old_markers_stack = ti.markers_stack[old_write_id];
MarkerList& new_markers_done = ti.markers_done[write_id]; MarkerList& new_markers_done = ti.markers_done[m_write_id];
MarkerStack& new_markers_stack = ti.markers_stack[write_id]; MarkerStack& new_markers_stack = ti.markers_stack[m_write_id];
// Clear the containers for the new frame // Clear the containers for the new frame
new_markers_done.clear(); new_markers_done.clear();
@ -142,7 +156,7 @@ void Profiler::synchronizeFrame()
{ {
// - finish the marker for the previous frame and add it to the old "done" list // - finish the marker for the previous frame and add it to the old "done" list
Marker& m = old_markers_stack.top(); Marker& m = old_markers_stack.top();
m.end = now - time_last_sync; m.end = now - m_time_last_sync;
old_markers_done.push_front(m); old_markers_done.push_front(m);
// - start a new one for the new frame // - start a new one for the new frame
@ -155,7 +169,14 @@ void Profiler::synchronizeFrame()
} }
// Remember the date of last synchronization // Remember the date of last synchronization
time_last_sync = now; m_time_between_sync = now - m_time_last_sync;
m_time_last_sync = now;
// Freeze/unfreeze as needed
if(m_freeze_state == WAITING_FOR_FREEZE)
m_freeze_state = FROZEN;
else if(m_freeze_state == WAITING_FOR_UNFREEZE)
m_freeze_state = UNFROZEN;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -170,27 +191,27 @@ void Profiler::draw()
// Force to show the pointer // Force to show the pointer
irr_driver->showPointer(); irr_driver->showPointer();
int read_id = !write_id; int read_id = !m_write_id;
// Compute some values for drawing (unit: pixels, but we keep floats for reducing errors accumulation) // Compute some values for drawing (unit: pixels, but we keep floats for reducing errors accumulation)
core::dimension2d<u32> screen_size = driver->getScreenSize(); core::dimension2d<u32> screen_size = driver->getScreenSize();
const float profiler_width = (1.0 - 2.0*MARGIN_X) * screen_size.Width; const double profiler_width = (1.0 - 2.0*MARGIN_X) * screen_size.Width;
const float x_offset = MARGIN_X*screen_size.Width; const double x_offset = MARGIN_X*screen_size.Width;
const float y_offset = (MARGIN_Y + LINE_HEIGHT)*screen_size.Height; const double y_offset = (MARGIN_Y + LINE_HEIGHT)*screen_size.Height;
const float line_height = LINE_HEIGHT*screen_size.Height; const double line_height = LINE_HEIGHT*screen_size.Height;
size_t nb_thread_infos = thread_infos.size(); size_t nb_thread_infos = m_thread_infos.size();
const float factor = profiler_width / TIME_DRAWN_MS; const double factor = profiler_width / TIME_DRAWN_MS;
// Get the mouse pos // Get the mouse pos
core::position2di mouse_pos = GUIEngine::EventHandler::get()->getMousePos(); core::vector2di mouse_pos = GUIEngine::EventHandler::get()->getMousePos();
// For each thread: // 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 // Draw all markers
MarkerList& markers = thread_infos[i].markers_done[read_id]; MarkerList& markers = m_thread_infos[i].markers_done[read_id];
if(markers.empty()) if(markers.empty())
continue; continue;
@ -200,11 +221,12 @@ void Profiler::draw()
{ {
const Marker& m = *it; const Marker& m = *it;
assert(m.end >= 0.0); assert(m.end >= 0.0);
core::rect<s32> pos(x_offset + factor*m.start, core::rect<s32> pos((s32)( x_offset + factor*m.start ),
y_offset + i*line_height, (s32)( y_offset + i*line_height ),
x_offset + factor*m.end, (s32)( x_offset + factor*m.end ),
y_offset + (i+1)*line_height); (s32)( y_offset + (i+1)*line_height ));
// Reduce vertically the size of the markers according to their layer
pos.UpperLeftCorner.Y += m.layer; pos.UpperLeftCorner.Y += m.layer;
pos.LowerRightCorner.Y -= m.layer; pos.LowerRightCorner.Y -= m.layer;
@ -216,7 +238,21 @@ void Profiler::draw()
} }
} }
// Draw the end of the frame
{
s32 x_sync = (s32)(x_offset + factor*m_time_between_sync);
s32 y_up_sync = (s32)(MARGIN_Y*screen_size.Height);
s32 y_down_sync = (s32)( (MARGIN_Y + (2+nb_thread_infos)*LINE_HEIGHT)*screen_size.Height );
driver->draw2DLine(core::vector2di(x_sync, y_up_sync),
core::vector2di(x_sync, y_down_sync),
video::SColor(0xFF, 0x00, 0x00, 0x00));
}
// Draw the hovered markers' names // Draw the hovered markers' names
gui::ScalableFont* font = GUIEngine::getFont();
if(font)
{
core::stringw text; core::stringw text;
while(!hovered_markers.empty()) while(!hovered_markers.empty())
{ {
@ -224,20 +260,42 @@ void Profiler::draw()
text += std::string(m.name + "\n").c_str(); text += std::string(m.name + "\n").c_str();
hovered_markers.pop(); hovered_markers.pop();
} }
font->draw(text, MARKERS_NAMES_POS, video::SColor(0xFF, 0xFF, 0x00, 0x00));
}
}
/*//! draws an text and clips it to the specified rectangle if wanted //-----------------------------------------------------------------------------
virtual void draw(const core::stringw& text, const core::rect<s32>& position, /// Handle freeze/unfreeze
video::SColor color, bool hcenter=false, void Profiler::onClick(const core::vector2di& mouse_pos)
bool vcenter=false, const core::rect<s32>* clip=0); {
video::IVideoDriver* driver = irr_driver->getVideoDriver();
const core::dimension2d<u32>& screen_size = driver->getScreenSize();
virtual void draw(const core::stringw& text, const core::rect<s32>& position, core::rect<s32>background_rect( MARGIN_X * screen_size.Width,
video::SColor color, bool hcenter, MARGIN_Y * screen_size.Height,
bool vcenter, const core::rect<s32>* clip, bool ignoreRTL);*/ (1.0-MARGIN_X) * screen_size.Width,
(MARGIN_Y + 3.0*LINE_HEIGHT) * screen_size.Height);
if(!background_rect.isPointInside(mouse_pos))
return;
gui::ScalableFont* font = GUIEngine::getFont(); switch(m_freeze_state)
//font->draw(text, MARKERS_NAMES_POS, video::SColor(0xFF, 0xFF, 0xFF, 0xFF)); {
font->draw(text, core::rect<s32>(50,50,150,150), video::SColor(0xFF, 0xFF, 0xFF, 0xFF)); case UNFROZEN:
m_freeze_state = WAITING_FOR_FREEZE;
break;
case FROZEN:
m_freeze_state = WAITING_FOR_UNFREEZE;
break;
case WAITING_FOR_FREEZE:
case WAITING_FOR_UNFREEZE:
// the user should not be that quick, and we prefer avoiding to introduce
// bugs by unfrozing it while it has not frozen yet.
// Same the other way around.
break;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -247,11 +305,11 @@ void Profiler::drawBackground()
video::IVideoDriver* driver = irr_driver->getVideoDriver(); video::IVideoDriver* driver = irr_driver->getVideoDriver();
const core::dimension2d<u32>& screen_size = driver->getScreenSize(); const core::dimension2d<u32>& screen_size = driver->getScreenSize();
core::rect<s32> pos(MARGIN_X * screen_size.Width, core::rect<s32>background_rect( MARGIN_X * screen_size.Width,
MARGIN_Y * screen_size.Height, MARGIN_Y * screen_size.Height,
(1.0-MARGIN_X) * screen_size.Width, (1.0-MARGIN_X) * screen_size.Width,
(MARGIN_Y + 3.0*LINE_HEIGHT) * screen_size.Height); (MARGIN_Y + 3.0*LINE_HEIGHT) * screen_size.Height);
video::SColor color(0xFF, 0xFF, 0xFF, 0xFF); video::SColor color(0xFF, 0xFF, 0xFF, 0xFF);
driver->draw2DRectangle(color, pos); driver->draw2DRectangle(color, background_rect);
} }

View File

@ -44,7 +44,7 @@ using namespace irr;
*/ */
class Profiler class Profiler
{ {
public: private:
struct Marker struct Marker
{ {
double start; // Times of start and end, in milliseconds, double start; // Times of start and end, in milliseconds,
@ -76,9 +76,21 @@ public:
typedef std::vector<ThreadInfo> ThreadInfoList; typedef std::vector<ThreadInfo> ThreadInfoList;
ThreadInfoList thread_infos; ThreadInfoList m_thread_infos;
int write_id; int m_write_id;
double time_last_sync; double m_time_last_sync;
double m_time_between_sync;
// Handling freeze/unfreeze by clicking on the display
enum FreezeState
{
UNFROZEN,
WAITING_FOR_FREEZE,
FROZEN,
WAITING_FOR_UNFREEZE,
};
FreezeState m_freeze_state;
public: public:
Profiler(); Profiler();
@ -90,9 +102,11 @@ public:
void draw(); void draw();
void onClick(const core::vector2di& mouse_pos);
protected: protected:
// TODO: detect on which thread this is called to support multithreading // TODO: detect on which thread this is called to support multithreading
ThreadInfo& getThreadInfo() { return thread_infos[0]; } ThreadInfo& getThreadInfo() { return m_thread_infos[0]; }
void drawBackground(); void drawBackground();
}; };