Profiler graph

This commit is contained in:
Perttu Ahola 2012-03-21 03:33:02 +02:00
parent 2f2ef80ec2
commit 7d1ac4d1f6
3 changed files with 214 additions and 40 deletions

@ -656,9 +656,11 @@ void Client::step(float dtime)
/*infostream<<"Mesh update result queue size is " /*infostream<<"Mesh update result queue size is "
<<m_mesh_update_thread.m_queue_out.size() <<m_mesh_update_thread.m_queue_out.size()
<<std::endl;*/ <<std::endl;*/
int num_processed_meshes = 0;
while(m_mesh_update_thread.m_queue_out.size() > 0) while(m_mesh_update_thread.m_queue_out.size() > 0)
{ {
num_processed_meshes++;
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front(); MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
if(block) if(block)
@ -699,6 +701,8 @@ void Client::step(float dtime)
m_con.Send(PEER_ID_SERVER, 1, reply, true); m_con.Send(PEER_ID_SERVER, 1, reply, true);
} }
} }
if(num_processed_meshes > 0)
g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
} }
/* /*
@ -752,6 +756,7 @@ void Client::ReceiveAll()
try{ try{
Receive(); Receive();
g_profiler->graphAdd("client_received_packets", 1);
} }
catch(con::NoIncomingDataException &e) catch(con::NoIncomingDataException &e)
{ {

@ -55,6 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "quicktune_shortcutter.h" #include "quicktune_shortcutter.h"
#include "clientmap.h" #include "clientmap.h"
#include "sky.h" #include "sky.h"
#include <list>
/* /*
Setting this to 1 enables a special camera mode that forces Setting this to 1 enables a special camera mode that forces
@ -602,6 +603,159 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
} }
} }
class ProfilerGraph
{
private:
struct Piece{
Profiler::GraphValues values;
};
struct Meta{
float min;
float max;
video::SColor color;
Meta(float initial=0, video::SColor color=
video::SColor(255,255,255,255)):
min(initial),
max(initial),
color(color)
{}
};
std::list<Piece> m_log;
public:
u32 m_log_max_size;
ProfilerGraph():
m_log_max_size(200)
{}
void put(const Profiler::GraphValues &values)
{
Piece piece;
piece.values = values;
m_log.push_back(piece);
while(m_log.size() > m_log_max_size)
m_log.erase(m_log.begin());
}
void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
gui::IGUIFont* font) const
{
std::map<std::string, Meta> m_meta;
for(std::list<Piece>::const_iterator k = m_log.begin();
k != m_log.end(); k++)
{
const Piece &piece = *k;
for(Profiler::GraphValues::const_iterator i = piece.values.begin();
i != piece.values.end(); i++){
const std::string &id = i->first;
const float &value = i->second;
std::map<std::string, Meta>::iterator j =
m_meta.find(id);
if(j == m_meta.end()){
m_meta[id] = Meta(value);
continue;
}
if(value < j->second.min)
j->second.min = value;
if(value > j->second.max)
j->second.max = value;
}
}
// Assign colors
static const video::SColor usable_colors[] = {
video::SColor(255,255,100,100),
video::SColor(255,90,225,90),
video::SColor(255,100,100,255)
};
static const u32 usable_colors_count =
sizeof(usable_colors) / sizeof(*usable_colors);
u32 next_color_i = 0;
for(std::map<std::string, Meta>::iterator i = m_meta.begin();
i != m_meta.end(); i++){
Meta &meta = i->second;
video::SColor color(255,200,200,200);
if(next_color_i < usable_colors_count)
color = usable_colors[next_color_i++];
meta.color = color;
}
s32 graphh = 50;
s32 textx = x_left + m_log_max_size + 15;
s32 textx2 = textx + 200 - 15;
// Draw background
/*{
u32 num_graphs = m_meta.size();
core::rect<s32> rect(x_left, y_bottom - num_graphs*graphh,
textx2, y_bottom);
video::SColor bgcolor(120,0,0,0);
driver->draw2DRectangle(bgcolor, rect, NULL);
}*/
s32 meta_i = 0;
for(std::map<std::string, Meta>::const_iterator i = m_meta.begin();
i != m_meta.end(); i++){
const std::string &id = i->first;
const Meta &meta = i->second;
s32 x = x_left;
s32 y = y_bottom - meta_i * 50;
float show_min = meta.min;
float show_max = meta.max;
if(show_min >= 0 && show_max >= 0){
if(show_min <= show_max * 0.5)
show_min = 0;
}
s32 texth = 15;
char buf[10];
snprintf(buf, 10, "%.3g", show_max);
font->draw(narrow_to_wide(buf).c_str(),
core::rect<s32>(textx, y - graphh,
textx2, y - graphh + texth),
meta.color);
snprintf(buf, 10, "%.3g", show_min);
font->draw(narrow_to_wide(buf).c_str(),
core::rect<s32>(textx, y - texth,
textx2, y),
meta.color);
font->draw(narrow_to_wide(id).c_str(),
core::rect<s32>(textx, y - graphh/2 - texth/2,
textx2, y - graphh/2 + texth/2),
meta.color);
for(std::list<Piece>::const_iterator j = m_log.begin();
j != m_log.end(); j++)
{
const Piece &piece = *j;
float value = 0;
bool value_exists = false;
Profiler::GraphValues::const_iterator k =
piece.values.find(id);
if(k != piece.values.end()){
value = k->second;
value_exists = true;
}
if(!value_exists){
x++;
continue;
}
float scaledvalue = 1.0;
if(show_max != show_min)
scaledvalue = (value - show_min) / (show_max - show_min);
if(scaledvalue == 1.0 && value == 0){
x++;
continue;
}
s32 ivalue = scaledvalue * graphh;
driver->draw2DLine(v2s32(x, y),
v2s32(x, y - ivalue),
meta.color);
x++;
}
meta_i++;
}
}
};
void the_game( void the_game(
bool &kill, bool &kill,
bool random_input, bool random_input,
@ -938,7 +1092,7 @@ void the_game(
L"<Profiler>", L"<Profiler>",
core::rect<s32>(0,0,0,0), core::rect<s32>(0,0,0,0),
false, false); false, false);
guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0)); guitext_profiler->setBackgroundColor(video::SColor(120,0,0,0));
guitext_profiler->setVisible(false); guitext_profiler->setVisible(false);
/*GUIQuickInventory *quick_inventory = new GUIQuickInventory /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
@ -968,13 +1122,14 @@ void the_game(
u32 beginscenetime = 0; u32 beginscenetime = 0;
u32 scenetime = 0; u32 scenetime = 0;
u32 endscenetime = 0; u32 endscenetime = 0;
u32 alltime = 0;
// A test // A test
//throw con::PeerNotFoundException("lol"); //throw con::PeerNotFoundException("lol");
float recent_turn_speed = 0.0; float recent_turn_speed = 0.0;
core::list<float> frametime_log; ProfilerGraph graph;
float nodig_delay_timer = 0.0; float nodig_delay_timer = 0.0;
float dig_time = 0.0; float dig_time = 0.0;
@ -1000,7 +1155,7 @@ void the_game(
bool force_fog_off = false; bool force_fog_off = false;
bool disable_camera_update = false; bool disable_camera_update = false;
bool show_debug = g_settings->getBool("show_debug"); bool show_debug = g_settings->getBool("show_debug");
bool show_debug_frametime = false; bool show_profiler_graph = false;
u32 show_profiler = 0; u32 show_profiler = 0;
u32 show_profiler_max = 3; // Number of pages u32 show_profiler_max = 3; // Number of pages
@ -1022,9 +1177,12 @@ void the_game(
// NOTE: So we have to use getTime() and call run()s between them // NOTE: So we have to use getTime() and call run()s between them
u32 lasttime = device->getTimer()->getTime(); u32 lasttime = device->getTimer()->getTime();
while(device->run() && kill == false) for(;;)
{ {
//std::cerr<<"frame"<<std::endl; TimeTaker tt_all("mainloop: all");
if(device->run() == false || kill == true)
break;
if(client.accessDenied()) if(client.accessDenied())
{ {
@ -1142,16 +1300,6 @@ void the_game(
g_profiler->add("Elapsed time", dtime); g_profiler->add("Elapsed time", dtime);
g_profiler->avg("FPS", 1./dtime); g_profiler->avg("FPS", 1./dtime);
/*
Log frametime for visualization
*/
frametime_log.push_back(dtime);
if(frametime_log.size() > 100)
{
core::list<float>::Iterator i = frametime_log.begin();
frametime_log.erase(i);
}
/* /*
Visualize frametime in terminal Visualize frametime in terminal
*/ */
@ -1434,25 +1582,25 @@ void the_game(
{ {
// Initial / 3x toggle: Chat only // Initial / 3x toggle: Chat only
// 1x toggle: Debug text with chat // 1x toggle: Debug text with chat
// 2x toggle: Debug text with frametime // 2x toggle: Debug text with profiler graph
if(!show_debug) if(!show_debug)
{ {
show_debug = true; show_debug = true;
show_debug_frametime = false; show_profiler_graph = false;
statustext = L"Debug info shown"; statustext = L"Debug info shown";
statustext_time = 0; statustext_time = 0;
} }
else if(show_debug_frametime) else if(show_profiler_graph)
{ {
show_debug = false; show_debug = false;
show_debug_frametime = false; show_profiler_graph = false;
statustext = L"Debug info and frametime graph hidden"; statustext = L"Debug info and profiler graph hidden";
statustext_time = 0; statustext_time = 0;
} }
else else
{ {
show_debug_frametime = true; show_profiler_graph = true;
statustext = L"Frametime graph shown"; statustext = L"Profiler graph shown";
statustext_time = 0; statustext_time = 0;
} }
} }
@ -2413,7 +2561,7 @@ void the_game(
Drawing begins Drawing begins
*/ */
TimeTaker drawtimer("Drawing"); TimeTaker tt_draw("mainloop: draw");
{ {
@ -2479,22 +2627,11 @@ void the_game(
} }
/* /*
Frametime log Profiler graph
*/ */
if(show_debug_frametime) if(show_profiler_graph)
{ {
s32 x = 10; graph.draw(10, screensize.Y - 10, driver, font);
s32 y = screensize.Y - 10;
for(core::list<float>::Iterator
i = frametime_log.begin();
i != frametime_log.end();
i++)
{
driver->draw2DLine(v2s32(x,y),
v2s32(x,y-(*i)*1000),
video::SColor(255,255,255,255));
x++;
}
} }
/* /*
@ -2559,7 +2696,8 @@ void the_game(
endscenetime = timer.stop(true); endscenetime = timer.stop(true);
} }
drawtime = drawtimer.stop(true); drawtime = tt_draw.stop(true);
g_profiler->graphAdd("mainloop_draw", (float)drawtime/1000.0f);
/* /*
End of drawing End of drawing
@ -2579,6 +2717,16 @@ void the_game(
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
lastFPS = fps; lastFPS = fps;
} }
alltime = tt_all.stop(true);
g_profiler->graphAdd("mainloop_other", (float)(alltime-drawtime)/1000.0f);
/*
Log times and stuff for visualization
*/
Profiler::GraphValues values;
g_profiler->graphGet(values);
graph.put(values);
} }
/* /*

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h" #include "utility.h"
#include <jmutex.h> #include <jmutex.h>
#include <jmutexautolock.h> #include <jmutexautolock.h>
#include <map>
/* /*
Time profiler Time profiler
@ -146,10 +147,30 @@ public:
} }
} }
typedef std::map<std::string, float> GraphValues;
void graphAdd(const std::string &id, float value)
{
JMutexAutoLock lock(m_mutex);
std::map<std::string, float>::iterator i =
m_graphvalues.find(id);
if(i == m_graphvalues.end())
m_graphvalues[id] = value;
else
i->second += value;
}
void graphGet(GraphValues &result)
{
JMutexAutoLock lock(m_mutex);
result = m_graphvalues;
m_graphvalues.clear();
}
private: private:
JMutex m_mutex; JMutex m_mutex;
core::map<std::string, float> m_data; core::map<std::string, float> m_data;
core::map<std::string, int> m_avgcounts; core::map<std::string, int> m_avgcounts;
std::map<std::string, float> m_graphvalues;
}; };
enum ScopeProfilerType{ enum ScopeProfilerType{