Reduced the CPU usage of the sent block selector algorithm

This commit is contained in:
Perttu Ahola 2011-05-31 00:15:43 +03:00
parent 16fdb42590
commit 223b379348
11 changed files with 355 additions and 55 deletions

@ -92,10 +92,6 @@
# Server side stuff # Server side stuff
# #
# Set to true to enable experimental features
# (varies from version to version, see wiki)
#enable_experimental = false
# Map directory (everything in the world is stored here) # Map directory (everything in the world is stored here)
#map-dir = /home/palle/custom_map #map-dir = /home/palle/custom_map
@ -112,6 +108,13 @@
# Gives some stuff to players at the beginning # Gives some stuff to players at the beginning
#give_initial_stuff = false #give_initial_stuff = false
# Set to true to enable experimental features
# (varies from version to version, see wiki)
#enable_experimental = false
# Profiler data print interval. 0 = disable.
#profiler_print_interval = 10
# Player and object positions are sent at intervals specified by this # Player and object positions are sent at intervals specified by this
#objectdata_inverval = 0.2 #objectdata_inverval = 0.2

@ -74,12 +74,13 @@ void set_default_settings()
g_settings.setDefault("give_initial_stuff", "false"); g_settings.setDefault("give_initial_stuff", "false");
g_settings.setDefault("default_password", ""); g_settings.setDefault("default_password", "");
g_settings.setDefault("default_privs", "build, shout"); g_settings.setDefault("default_privs", "build, shout");
g_settings.setDefault("profiler_print_interval", "0");
g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2"); g_settings.setDefault("active_object_range", "2");
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1"); g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "2"); //g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "4"); g_settings.setDefault("max_simultaneous_block_sends_server_total", "8");
g_settings.setDefault("max_block_send_distance", "8"); g_settings.setDefault("max_block_send_distance", "8");
g_settings.setDefault("max_block_generate_distance", "8"); g_settings.setDefault("max_block_generate_distance", "8");
g_settings.setDefault("time_send_interval", "20"); g_settings.setDefault("time_send_interval", "20");

@ -903,6 +903,10 @@ void the_game(
bool first_loop_after_window_activation = true; bool first_loop_after_window_activation = true;
// TODO: Convert the static interval timers to these
// Interval limiter for profiler
IntervalLimiter m_profiler_interval;
// Time is in milliseconds // Time is in milliseconds
// NOTE: getRealTime() causes strange problems in wine (imprecision?) // NOTE: getRealTime() causes strange problems in wine (imprecision?)
// 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
@ -1089,6 +1093,21 @@ void the_game(
} }
} }
/*
Profiler
*/
float profiler_print_interval =
g_settings.getFloat("profiler_print_interval");
if(profiler_print_interval != 0)
{
if(m_profiler_interval.step(0.030, profiler_print_interval))
{
dstream<<"Profiler:"<<std::endl;
g_profiler.print(dstream);
g_profiler.clear();
}
}
/* /*
Direct handling of user input Direct handling of user input
*/ */

@ -215,6 +215,8 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
FIXME: The new optimized map sending doesn't sometimes send enough blocks FIXME: The new optimized map sending doesn't sometimes send enough blocks
from big caves and such from big caves and such
* Take player's walking direction into account in GetNextBlocks
Environment: Environment:
------------ ------------
@ -308,6 +310,10 @@ Making it more portable:
Stuff to do before release: Stuff to do before release:
--------------------------- ---------------------------
Fixes to the current release:
-----------------------------
- Make AuthManager to save only when data has changed
Stuff to do after release: Stuff to do after release:
--------------------------- ---------------------------
- Make sure server handles removing grass when a block is placed (etc) - Make sure server handles removing grass when a block is placed (etc)
@ -386,6 +392,9 @@ Settings g_settings;
// This is located in defaultsettings.cpp // This is located in defaultsettings.cpp
extern void set_default_settings(); extern void set_default_settings();
// Global profiler
Profiler g_profiler;
/* /*
Random stuff Random stuff
*/ */
@ -436,7 +445,14 @@ std::ostream *derr_client_ptr = &dstream;
class TimeGetter class TimeGetter
{ {
public: public:
TimeGetter(IrrlichtDevice *device): virtual u32 getTime() = 0;
};
// A precise irrlicht one
class IrrlichtTimeGetter: public TimeGetter
{
public:
IrrlichtTimeGetter(IrrlichtDevice *device):
m_device(device) m_device(device)
{} {}
u32 getTime() u32 getTime()
@ -448,8 +464,18 @@ public:
private: private:
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
}; };
// Not so precise one which works without irrlicht
class SimpleTimeGetter: public TimeGetter
{
public:
u32 getTime()
{
return porting::getTimeMs();
}
};
// A pointer to a global instance of the time getter // A pointer to a global instance of the time getter
// TODO: why?
TimeGetter *g_timegetter = NULL; TimeGetter *g_timegetter = NULL;
u32 getTimeMs() u32 getTimeMs()
@ -1208,6 +1234,9 @@ int main(int argc, char *argv[])
{ {
DSTACK("Dedicated server branch"); DSTACK("Dedicated server branch");
// Create time getter
g_timegetter = new SimpleTimeGetter();
// Create server // Create server
Server server(map_dir.c_str()); Server server(map_dir.c_str());
server.start(port); server.start(port);
@ -1290,7 +1319,7 @@ int main(int argc, char *argv[])
device = device; device = device;
// Create time getter // Create time getter
g_timegetter = new TimeGetter(device); g_timegetter = new IrrlichtTimeGetter(device);
// Create game callback for menus // Create game callback for menus
g_gamecallback = new MainGameCallback(device); g_gamecallback = new MainGameCallback(device);

@ -28,6 +28,10 @@ extern Settings g_settings;
#include "tile.h" #include "tile.h"
extern ITextureSource *g_texturesource; extern ITextureSource *g_texturesource;
// Global profiler
#include "profiler.h"
extern Profiler g_profiler;
// Debug streams // Debug streams
#include <fstream> #include <fstream>

@ -5692,9 +5692,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
p_nodes_min.Y / MAP_BLOCKSIZE - 1, p_nodes_min.Y / MAP_BLOCKSIZE - 1,
p_nodes_min.Z / MAP_BLOCKSIZE - 1); p_nodes_min.Z / MAP_BLOCKSIZE - 1);
v3s16 p_blocks_max( v3s16 p_blocks_max(
p_nodes_max.X / MAP_BLOCKSIZE + 1, p_nodes_max.X / MAP_BLOCKSIZE,
p_nodes_max.Y / MAP_BLOCKSIZE + 1, p_nodes_max.Y / MAP_BLOCKSIZE,
p_nodes_max.Z / MAP_BLOCKSIZE + 1); p_nodes_max.Z / MAP_BLOCKSIZE);
u32 vertex_count = 0; u32 vertex_count = 0;

@ -540,10 +540,10 @@ void updateFastFaceRow(
v3s16 p_next; v3s16 p_next;
bool next_makes_face; bool next_makes_face = false;
v3s16 next_p_corrected; v3s16 next_p_corrected;
v3s16 next_face_dir_corrected; v3s16 next_face_dir_corrected;
u8 next_lights[4]; u8 next_lights[4] = {0,0,0,0};
TileSpec next_tile; TileSpec next_tile;
// If at last position, there is nothing to compare to and // If at last position, there is nothing to compare to and

131
src/profiler.h Normal file

@ -0,0 +1,131 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef PROFILER_HEADER
#define PROFILER_HEADER
#include "common_irrlicht.h"
#include <string>
#include "utility.h"
#include <jmutex.h>
#include <jmutexautolock.h>
/*
Time profiler
*/
class Profiler
{
public:
Profiler()
{
m_mutex.Init();
}
void add(const std::string &name, u32 duration)
{
JMutexAutoLock lock(m_mutex);
core::map<std::string, u32>::Node *n = m_data.find(name);
if(n == NULL)
{
m_data[name] = duration;
}
else
{
n->setValue(n->getValue()+duration);
}
}
void clear()
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, u32>::Iterator
i = m_data.getIterator();
i.atEnd() == false; i++)
{
i.getNode()->setValue(0);
}
}
void print(std::ostream &o)
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, u32>::Iterator
i = m_data.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
o<<name<<": ";
s32 clampsize = 40;
s32 space = clampsize-name.size();
for(s32 j=0; j<space; j++)
{
if(j%2 == 0 && j < space - 1)
o<<"-";
else
o<<" ";
}
o<<i.getNode()->getValue();
o<<std::endl;
}
}
private:
JMutex m_mutex;
core::map<std::string, u32> m_data;
};
class ScopeProfiler
{
public:
ScopeProfiler(Profiler *profiler, const std::string &name):
m_profiler(profiler),
m_name(name),
m_timer(NULL)
{
if(m_profiler)
m_timer = new TimeTaker(m_name.c_str());
}
// name is copied
ScopeProfiler(Profiler *profiler, const char *name):
m_profiler(profiler),
m_name(name),
m_timer(NULL)
{
if(m_profiler)
m_timer = new TimeTaker(m_name.c_str());
}
~ScopeProfiler()
{
if(m_timer)
{
u32 duration = m_timer->stop(true);
if(m_profiler)
m_profiler->add(m_name, duration);
delete m_timer;
}
}
private:
Profiler *m_profiler;
std::string m_name;
TimeTaker *m_timer;
};
#endif

@ -312,11 +312,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/ TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
// Increment timers // Increment timers
m_nearest_unsent_reset_timer += dtime;
m_nothing_to_send_pause_timer -= dtime; m_nothing_to_send_pause_timer -= dtime;
if(m_nothing_to_send_pause_timer >= 0) if(m_nothing_to_send_pause_timer >= 0)
{
// Keep this reset
m_nearest_unsent_reset_timer = 0;
return; return;
}
// Won't send anything if already sending // Won't send anything if already sending
if(m_blocks_sending.size() >= g_settings.getU16 if(m_blocks_sending.size() >= g_settings.getU16
@ -326,14 +329,21 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
return; return;
} }
//TimeTaker timer("RemoteClient::GetNextBlocks");
Player *player = server->m_env.getPlayer(peer_id); Player *player = server->m_env.getPlayer(peer_id);
assert(player != NULL); assert(player != NULL);
v3f playerpos = player->getPosition(); v3f playerpos = player->getPosition();
v3f playerspeed = player->getSpeed(); v3f playerspeed = player->getSpeed();
v3f playerspeeddir(0,0,0);
if(playerspeed.getLength() > 1.0*BS)
playerspeeddir = playerspeed / playerspeed.getLength();
// Predict to next block
v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
v3s16 center_nodepos = floatToInt(playerpos, BS); v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
v3s16 center = getNodeBlockPos(center_nodepos); v3s16 center = getNodeBlockPos(center_nodepos);
@ -344,6 +354,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateYZBy(player->getPitch());
camera_dir.rotateXZBy(player->getYaw()); camera_dir.rotateXZBy(player->getYaw());
/*dstream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
<<camera_dir.Z<<")"<<std::endl;*/
/* /*
Get the starting value of the block finder radius. Get the starting value of the block finder radius.
*/ */
@ -356,11 +369,18 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*dstream<<"m_nearest_unsent_reset_timer=" /*dstream<<"m_nearest_unsent_reset_timer="
<<m_nearest_unsent_reset_timer<<std::endl;*/ <<m_nearest_unsent_reset_timer<<std::endl;*/
if(m_nearest_unsent_reset_timer > 5.0)
// This has to be incremented only when the nothing to send pause
// is not active
m_nearest_unsent_reset_timer += dtime;
// Reset periodically to avoid possible bugs or other mishaps
if(m_nearest_unsent_reset_timer > 10.0)
{ {
m_nearest_unsent_reset_timer = 0; m_nearest_unsent_reset_timer = 0;
m_nearest_unsent_d = 0; m_nearest_unsent_d = 0;
//dstream<<"Resetting m_nearest_unsent_d"<<std::endl; dstream<<"Resetting m_nearest_unsent_d for "
<<server->getPlayerName(peer_id)<<std::endl;
} }
//s16 last_nearest_unsent_d = m_nearest_unsent_d; //s16 last_nearest_unsent_d = m_nearest_unsent_d;
@ -402,11 +422,22 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
s16 d_max = g_settings.getS16("max_block_send_distance"); s16 d_max = g_settings.getS16("max_block_send_distance");
s16 d_max_gen = g_settings.getS16("max_block_generate_distance"); s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
// Don't loop very much at a time
if(d_max > d_start+1)
d_max = d_start+1;
/*if(d_max_gen > d_start+2)
d_max_gen = d_start+2;*/
//dstream<<"Starting from "<<d_start<<std::endl; //dstream<<"Starting from "<<d_start<<std::endl;
bool sending_something = false; bool sending_something = false;
for(s16 d = d_start; d <= d_max; d++) bool no_blocks_found_for_sending = true;
bool queue_is_full = false;
s16 d;
for(d = d_start; d <= d_max; d++)
{ {
//dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl; //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
@ -451,7 +482,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
// Don't select too many blocks for sending // Don't select too many blocks for sending
if(num_blocks_selected >= max_simul_dynamic) if(num_blocks_selected >= max_simul_dynamic)
goto queue_full; {
queue_is_full = true;
goto queue_full_break;
}
// Don't send blocks that are currently being transferred // Don't send blocks that are currently being transferred
if(m_blocks_sending.find(p) != NULL) if(m_blocks_sending.find(p) != NULL)
@ -513,6 +547,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
} }
#endif #endif
//dstream<<"d="<<d<<std::endl;
/* /*
Don't generate or send if not in sight Don't generate or send if not in sight
*/ */
@ -527,8 +563,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
*/ */
{ {
if(m_blocks_sent.find(p) != NULL) if(m_blocks_sent.find(p) != NULL)
{
continue; continue;
} }
}
/* /*
Check if map has this block Check if map has this block
@ -539,11 +577,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
bool block_is_invalid = false; bool block_is_invalid = false;
if(block != NULL) if(block != NULL)
{ {
// Block is dummy if data doesn't exist.
// It means it has been not found from disk and not generated
if(block->isDummy()) if(block->isDummy())
{ {
surely_not_found_on_disk = true; surely_not_found_on_disk = true;
} }
// Block is valid if lighting is up-to-date and data exists
if(block->isValid() == false) if(block->isValid() == false)
{ {
block_is_invalid = true; block_is_invalid = true;
@ -564,8 +605,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
If block is not close, don't send it unless it is near If block is not close, don't send it unless it is near
ground level. ground level.
Block is not near ground level if night-time mesh Block is near ground level if night-time mesh
doesn't differ from day-time mesh. differs from day-time mesh.
*/ */
if(d > 3) if(d > 3)
{ {
@ -586,15 +627,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
} }
/* /*
Record the lowest d from which a a block has been Record the lowest d from which a block has been
found being not sent and possibly to exist found being not sent and possibly to exist
*/ */
if(new_nearest_unsent_d == -1 || d < new_nearest_unsent_d) if(no_blocks_found_for_sending)
{ {
if(generate == true) if(generate == true)
new_nearest_unsent_d = d; new_nearest_unsent_d = d;
} }
no_blocks_found_for_sending = false;
/* /*
Add inexistent block to emerge queue. Add inexistent block to emerge queue.
*/ */
@ -633,20 +676,30 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
sending_something = true; sending_something = true;
} }
} }
queue_full: queue_full_break:
//dstream<<"Stopped at "<<d<<std::endl;
if(no_blocks_found_for_sending)
{
if(queue_is_full == false)
new_nearest_unsent_d = d;
}
if(new_nearest_unsent_d != -1) if(new_nearest_unsent_d != -1)
{
m_nearest_unsent_d = new_nearest_unsent_d; m_nearest_unsent_d = new_nearest_unsent_d;
}
if(sending_something == false) if(sending_something == false)
{ {
m_nothing_to_send_counter++; m_nothing_to_send_counter++;
if(m_nothing_to_send_counter >= 3) if((s16)m_nothing_to_send_counter >=
g_settings.getS16("max_block_send_distance"))
{ {
// Pause time in seconds // Pause time in seconds
m_nothing_to_send_pause_timer = 2.0; m_nothing_to_send_pause_timer = 1.0;
dstream<<"nothing to send to "
<<server->getPlayerName(peer_id)
<<" (d="<<d<<")"<<std::endl;
} }
} }
else else
@ -1130,8 +1183,12 @@ void Server::AsyncRunStep()
dtime = m_step_dtime; dtime = m_step_dtime;
} }
{
ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
"blocks to clients");
// Send blocks to clients // Send blocks to clients
SendBlocks(dtime); SendBlocks(dtime);
}
if(dtime < 0.001) if(dtime < 0.001)
return; return;
@ -1196,12 +1253,14 @@ void Server::AsyncRunStep()
{ {
// Process connection's timeouts // Process connection's timeouts
JMutexAutoLock lock2(m_con_mutex); JMutexAutoLock lock2(m_con_mutex);
ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
m_con.RunTimeouts(dtime); m_con.RunTimeouts(dtime);
} }
{ {
// This has to be called so that the client list gets synced // This has to be called so that the client list gets synced
// with the peer list of the connection // with the peer list of the connection
ScopeProfiler sp(&g_profiler, "Server: peer change handling");
handlePeerChanges(); handlePeerChanges();
} }
@ -1209,6 +1268,7 @@ void Server::AsyncRunStep()
// Step environment // Step environment
// This also runs Map's timers // This also runs Map's timers
JMutexAutoLock lock(m_env_mutex); JMutexAutoLock lock(m_env_mutex);
ScopeProfiler sp(&g_profiler, "Server: environment step");
m_env.step(dtime); m_env.step(dtime);
} }
@ -1226,6 +1286,8 @@ void Server::AsyncRunStep()
JMutexAutoLock lock(m_env_mutex); JMutexAutoLock lock(m_env_mutex);
ScopeProfiler sp(&g_profiler, "Server: liquid transform");
core::map<v3s16, MapBlock*> modified_blocks; core::map<v3s16, MapBlock*> modified_blocks;
m_env.getMap().transformLiquids(modified_blocks); m_env.getMap().transformLiquids(modified_blocks);
#if 0 #if 0
@ -1298,10 +1360,11 @@ void Server::AsyncRunStep()
*/ */
{ {
//dstream<<"Server: Checking added and deleted active objects"<<std::endl; //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex); JMutexAutoLock conlock(m_con_mutex);
ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
// Radius inside which objects are active // Radius inside which objects are active
s16 radius = 32; s16 radius = 32;
@ -1446,6 +1509,8 @@ void Server::AsyncRunStep()
JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex); JMutexAutoLock conlock(m_con_mutex);
ScopeProfiler sp(&g_profiler, "Server: sending object messages");
// Key = object id // Key = object id
// Value = data sent by object // Value = data sent by object
core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages; core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
@ -1598,6 +1663,9 @@ void Server::AsyncRunStep()
{ {
JMutexAutoLock lock1(m_env_mutex); JMutexAutoLock lock1(m_env_mutex);
JMutexAutoLock lock2(m_con_mutex); JMutexAutoLock lock2(m_con_mutex);
ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
SendObjectData(counter); SendObjectData(counter);
counter = 0.0; counter = 0.0;
@ -1613,6 +1681,8 @@ void Server::AsyncRunStep()
JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex); JMutexAutoLock conlock(m_con_mutex);
ScopeProfiler sp(&g_profiler, "Server: stepping node metadata");
core::map<v3s16, MapBlock*> changed_blocks; core::map<v3s16, MapBlock*> changed_blocks;
m_env.getMap().nodeMetadataStep(dtime, changed_blocks); m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
@ -1655,6 +1725,8 @@ void Server::AsyncRunStep()
{ {
counter = 0.0; counter = 0.0;
ScopeProfiler sp(&g_profiler, "Server: saving stuff");
// Auth stuff // Auth stuff
m_authmanager.save(); m_authmanager.save();
@ -3647,6 +3719,9 @@ void Server::SendBlocks(float dtime)
s32 total_sending = 0; s32 total_sending = 0;
{
ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
for(core::map<u16, RemoteClient*>::Iterator for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator(); i = m_clients.getIterator();
i.atEnd() == false; i++) i.atEnd() == false; i++)
@ -3661,6 +3736,7 @@ void Server::SendBlocks(float dtime)
client->GetNextBlocks(this, dtime, queue); client->GetNextBlocks(this, dtime, queue);
} }
}
// Sort. // Sort.
// Lowest priority number comes first. // Lowest priority number comes first.
@ -4531,25 +4607,48 @@ void dedicated_server_loop(Server &server, bool &kill)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
std::cout<<DTIME<<std::endl; dstream<<DTIME<<std::endl;
std::cout<<"========================"<<std::endl; dstream<<"========================"<<std::endl;
std::cout<<"Running dedicated server"<<std::endl; dstream<<"Running dedicated server"<<std::endl;
std::cout<<"========================"<<std::endl; dstream<<"========================"<<std::endl;
std::cout<<std::endl; dstream<<std::endl;
IntervalLimiter m_profiler_interval;
for(;;) for(;;)
{ {
// This is kind of a hack but can be done like this // This is kind of a hack but can be done like this
// because server.step() is very light // because server.step() is very light
{
ScopeProfiler sp(&g_profiler, "dedicated server sleep");
sleep_ms(30); sleep_ms(30);
}
server.step(0.030); server.step(0.030);
if(server.getShutdownRequested() || kill) if(server.getShutdownRequested() || kill)
{ {
std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl; dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
break; break;
} }
/*
Profiler
*/
float profiler_print_interval =
g_settings.getFloat("profiler_print_interval");
if(profiler_print_interval != 0)
{
if(m_profiler_interval.step(0.030, profiler_print_interval))
{
dstream<<"Profiler:"<<std::endl;
g_profiler.print(dstream);
g_profiler.clear();
}
}
/*
Player info
*/
static int counter = 0; static int counter = 0;
counter--; counter--;
if(counter <= 0) if(counter <= 0)
@ -4562,10 +4661,10 @@ void dedicated_server_loop(Server &server, bool &kill)
u32 sum = PIChecksum(list); u32 sum = PIChecksum(list);
if(sum != sum_old) if(sum != sum_old)
{ {
std::cout<<DTIME<<"Player info:"<<std::endl; dstream<<DTIME<<"Player info:"<<std::endl;
for(i=list.begin(); i!=list.end(); i++) for(i=list.begin(); i!=list.end(); i++)
{ {
i->PrintLine(&std::cout); i->PrintLine(&dstream);
} }
} }
sum_old = sum; sum_old = sum;

@ -500,6 +500,15 @@ private:
// When called, connection mutex should be locked // When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id); RemoteClient* getClient(u16 peer_id);
// When called, environment mutex should be locked
std::string getPlayerName(u16 peer_id)
{
Player *player = m_env.getPlayer(peer_id);
if(player == NULL)
return "[id="+itos(peer_id);
return player->getName();
}
/* /*
Get a player from memory or creates one. Get a player from memory or creates one.
If player is already connected, return NULL If player is already connected, return NULL
@ -627,6 +636,8 @@ private:
*/ */
u16 m_ignore_map_edit_events_peer_id; u16 m_ignore_map_edit_events_peer_id;
Profiler *m_profiler;
friend class EmergeThread; friend class EmergeThread;
friend class RemoteClient; friend class RemoteClient;
}; };

@ -244,6 +244,9 @@ inline f32 readF1000(std::istream &is)
{ {
char buf[2]; char buf[2];
is.read(buf, 2); is.read(buf, 2);
// TODO: verify if this gets rid of the valgrind warning
//if(is.gcount() != 2)
// return 0;
return readF1000((u8*)buf); return readF1000((u8*)buf);
} }