Revision: 8189
http://playerstage.svn.sourceforge.net/playerstage/?rev=8189&view=rev
Author: rtv
Date: 2009-08-11 02:02:02 +0000 (Tue, 11 Aug 2009)
Log Message:
-----------
greatly simplified and improved timing code - API change requires move to
version 3.2.0
Modified Paths:
--------------
code/stage/trunk/CMakeLists.txt
code/stage/trunk/examples/ctrl/fasr.cc
code/stage/trunk/libstage/main.cc
code/stage/trunk/libstage/model.cc
code/stage/trunk/libstage/model_load.cc
code/stage/trunk/libstage/stage.hh
code/stage/trunk/libstage/test.cc
code/stage/trunk/libstage/world.cc
code/stage/trunk/libstage/worldgui.cc
code/stage/trunk/worlds/SFU.world
code/stage/trunk/worlds/benchmark/cave.world
code/stage/trunk/worlds/benchmark/hospital.world
code/stage/trunk/worlds/fasr.world
code/stage/trunk/worlds/pioneer_flocking.world
Modified: code/stage/trunk/CMakeLists.txt
===================================================================
--- code/stage/trunk/CMakeLists.txt 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/CMakeLists.txt 2009-08-11 02:02:02 UTC (rev 8189)
@@ -1,7 +1,7 @@
PROJECT(Stage)
SET( V_MAJOR 3 )
-SET( V_MINOR 1 )
+SET( V_MINOR 2 )
SET( V_BUGFIX 0 )
SET( VERSION ${V_MAJOR}.${V_MINOR}.${V_BUGFIX} )
Modified: code/stage/trunk/examples/ctrl/fasr.cc
===================================================================
--- code/stage/trunk/examples/ctrl/fasr.cc 2009-08-10 08:49:51 UTC (rev
8188)
+++ code/stage/trunk/examples/ctrl/fasr.cc 2009-08-11 02:02:02 UTC (rev
8189)
@@ -496,15 +496,17 @@
// Stage calls this when the model starts up
extern "C" int Init( Model* mod )
{
+#if 0
+ // example using the model rasterizer
if( strcmp( mod->Token(), "r0" ) == 0 )
{
const unsigned int dw = 64, dh = 32;
-
+
uint8_t* data = new uint8_t[dw*dh*2];
memset( data, 0, sizeof(uint8_t) * dw * dh );
mod->GetWorld()->GetModel( "cave" )->Rasterize( data, dw, dh,
0.25, 0.5 );
-
+
putchar( '\n' );
for( unsigned int y=0; y<dh; y++ )
{
@@ -514,7 +516,8 @@
}
delete data;
}
-
+#endif
+
new Robot( (ModelPosition*)mod,
mod->GetWorld()->GetModel( "source" ),
mod->GetWorld()->GetModel( "sink" ) );
Modified: code/stage/trunk/libstage/main.cc
===================================================================
--- code/stage/trunk/libstage/main.cc 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/main.cc 2009-08-11 02:02:02 UTC (rev 8189)
@@ -11,7 +11,7 @@
using namespace Stg;
const char* USAGE =
- "USAGE: stage [options] [<worldfile>]\n"
+ "USAGE: stage [options] <worldfile1> [worldfile2 ... worldfileN]\n"
"Available [options] are:\n"
" --clock : print simulation time peridically on standard output\n"
" -c : short for --clock\n"
@@ -19,8 +19,7 @@
" -g : short for --gui\n"
" --help : print this message\n"
" -h : short for --help\n"
- " -? : short for --help\n"
- " If <worldfile> is not specified, Stage starts with a file selector dialog";
+ " -? : short for --help";
/* options descriptor */
static struct option longopts[] = {
@@ -77,7 +76,6 @@
// arguments at index [optindex] and later are not options, so they
// must be world file names
- bool loaded_world_file = false;
optindex = optind; //points to first non-option
while( optindex < argc )
{
@@ -86,22 +84,18 @@
const char* worldfilename = argv[optindex];
World* world = ( usegui ?
new WorldGui( 400, 300, worldfilename ) :
-
new World( worldfilename ) );
+ new
World( worldfilename ) );
world->Load( worldfilename );
world->ShowClock( showclock );
- loaded_world_file = true;
+
+ if( ! world->paused )
+ world->Start();
}
optindex++;
}
- if( loaded_world_file == false )
- {
- // TODO: special window/loading dialog for this case
- new WorldGui( 400, 300 );
- }
-
if( usegui )
- while( true ) World::UpdateAll();
+ Fl::run();
else
while( ! World::UpdateAll() );
Modified: code/stage/trunk/libstage/model.cc
===================================================================
--- code/stage/trunk/libstage/model.cc 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/model.cc 2009-08-11 02:02:02 UTC (rev 8189)
@@ -210,7 +210,6 @@
log_state(false),
map_resolution(0.1),
mass(0),
- //on_velocity_list( false ),
parent(parent),
pose(),
power_pack( NULL ),
@@ -226,7 +225,7 @@
trail_length(50),
trail_interval(5),
type(type),
- update_list_num( -1 ),
+ event_queue_num( -1 ),
used(false),
velocity(),
watts(0.0),
@@ -297,6 +296,14 @@
UnMap(); // remove any old cruft rendered during startup
Map();
+ if( FindPowerPack() )
+ world->Enqueue( 0, World::Event::ENERGY, interval_energy, this );
+
+ // find the queue for update events: zero if thread safe, else we
+ // ask the world to assign us to a queue
+ if( event_queue_num < 1 )
+ event_queue_num = thread_safe ? world->GetEventQueue( this ) : 0;
+
CallCallbacks( &hooks.init );
}
@@ -322,8 +329,7 @@
{
if( flag )
{
- flag_list.erase( remove( flag_list.begin(), flag_list.end(),
flag ));
-
+ flag_list.erase( remove( flag_list.begin(), flag_list.end(),
flag ));
CallCallbacks( &hooks.flag_decr );
}
}
@@ -341,12 +347,12 @@
{
if( flag_list.size() == 0 )
return NULL;
-
+
Flag* flag = flag_list.front();
flag_list.pop_front();
-
+
CallCallbacks( &hooks.flag_decr );
-
+
return flag;
}
@@ -634,15 +640,13 @@
void Model::Startup( void )
{
- //printf( "Startup model %s\n", this->token );
-
-// if( update_list_num < 0 )
-// update_list_num = world->UpdateListAdd( this );
+ //printf( "Startup model %s\n", this->token );
+ //printf( "model %s using queue %d\n", token, event_queue_num );
- // put my first update in the world's queue
- world->Enqueue( World::Event::UPDATE, interval, this );
- world->Enqueue( World::Event::POSE, interval_pose, this );
-
+ // put my first events in the world's queue
+ world->Enqueue( event_queue_num, World::Event::UPDATE, interval, this );
+ world->Enqueue( 0, World::Event::POSE, interval_pose, this );
+
CallCallbacks( &hooks.startup );
}
@@ -655,50 +659,15 @@
void Model::Update( void )
{
- // empty - XX todo make this pure?
-}
+ CallCallbacks( &hooks.update );
-void Model::SynchronousPostUpdate( void )
-{
- CallUpdateCallbacks();
-
- // if we're drawing current and a power pack has been installed
- PowerPack* pp = FindPowerPack();
- if( pp && ( watts > 0 ))
- {
- // consume energy stored in the power pack
- stg_joules_t consumed = watts * (interval * 1e-6);
- pp->Dissipate( consumed, GetGlobalPose() );
- }
-
- if( trail_length > 0 && world->updates % trail_interval == 0 )
- {
- trail.push_back( TrailItem( world->sim_time, GetGlobalPose(),
color ) );
-
- if( trail.size() > trail_length )
- trail.pop_front();
- }
-
last_update = world->sim_time;
-
- if( subs > 0 )
- // put my next update in the world's queue
- world->Enqueue( World::Event::UPDATE, interval, this );
-
- // getchar();
- if( log_state )
- world->Log( this );
+ if( subs > 0 )
+ world->Enqueue( event_queue_num, World::Event::UPDATE, interval, this
);
}
-void Model::CallUpdateCallbacks( void )
-{
- // if we were updated this timestep, call the callbacks
- //if( last_update == world->sim_time )
- CallCallbacks( &hooks.update );
-}
-
stg_meters_t Model::ModelHeight() const
{
stg_meters_t m_child = 0; //max size of any child
@@ -764,50 +733,58 @@
}
void Model::UpdateCharge()
-{
- assert( watts_give > 0 );
-
+{
PowerPack* mypp = FindPowerPack();
assert( mypp );
- // detach charger from all the packs charged last time
- FOR_EACH( it, pps_charging )
- (*it)->ChargeStop();
- pps_charging.clear();
-
- // run through and update all appropriate touchers
- ModelPtrSet touchers;
- AppendTouchingModels( touchers );
-
- FOR_EACH( it, touchers )
+ if( watts > 0 ) // dissipation rate
{
- Model* toucher = (*it); //(Model*)touchers->data;
- PowerPack* hispp =toucher->FindPowerPack();
+ // consume energy stored in the power pack
+ stg_joules_t consumed = watts * (interval_energy * 1e-6);
+ mypp->Dissipate( consumed, GetGlobalPose() );
+ }
+
+ if( watts_give > 0 ) // transmission to other powerpacks max rate
+ {
+ // detach charger from all the packs charged last time
+ FOR_EACH( it, pps_charging )
+ (*it)->ChargeStop();
+ pps_charging.clear();
- if( hispp && toucher->watts_take > 0.0)
- {
- //printf( " toucher %s can take up to %.2f wats\n",
- // toucher->Token(), toucher->watts_take );
+ // run through and update all appropriate touchers
+ ModelPtrSet touchers;
+ AppendTouchingModels( touchers );
+
+ FOR_EACH( it, touchers )
+ {
+ Model* toucher = (*it); //(Model*)touchers->data;
+ PowerPack* hispp =toucher->FindPowerPack();
- stg_watts_t rate = std::min( watts_give,
toucher->watts_take );
- stg_joules_t amount = rate * interval_energy * 1e-6;
-
- //printf ( "moving %.2f joules from %s to %s\n",
- // amount, token, toucher->token );
-
- // set his charging flag
- hispp->ChargeStart();
-
- // move some joules from me to him
- mypp->TransferTo( hispp, amount );
-
- // remember who we are charging so we can detatch next
time
- pps_charging.push_front( hispp );
- }
- }
+ if( hispp && toucher->watts_take > 0.0)
+ {
+ //printf( " toucher %s can take up to %.2f
wats\n",
+ // toucher->Token(),
toucher->watts_take );
+
+ stg_watts_t rate = std::min( watts_give,
toucher->watts_take );
+ stg_joules_t amount = rate * interval_energy
* 1e-6;
+
+ //printf ( "moving %.2f joules from %s to
%s\n",
+ // amount, token, toucher->token
);
+
+ // set his charging flag
+ hispp->ChargeStart();
+
+ // move some joules from me to him
+ mypp->TransferTo( hispp, amount );
+
+ // remember who we are charging so we can
detatch next time
+ pps_charging.push_front( hispp );
+ }
+ }
+ }
// set up the next event
- world->Enqueue( World::Event::ENERGY, interval_energy, this );
+ world->Enqueue( 0, World::Event::ENERGY, interval_energy, this );
}
void Model::CommitTestedPose()
@@ -859,9 +836,17 @@
// ConditionalMove() returns a pointer to the model we hit, or
// NULL. We use this as a boolean for SetStall()
SetStall( ConditionalMove( pose + p ) );
+
+ if( trail_length > 0 && world->updates % trail_interval == 0 )
+ {
+ trail.push_back( TrailItem( world->sim_time, GetGlobalPose(),
color ) );
+
+ if( trail.size() > trail_length )
+ trail.pop_front();
+ }
//if( ! velocity.IsZero() )
- world->Enqueue( World::Event::POSE, interval_pose, this );
+ world->Enqueue( 0, World::Event::POSE, interval_pose, this );
}
Model* Model::GetUnsubscribedModelOfType( stg_model_type_t type ) const
Modified: code/stage/trunk/libstage/model_load.cc
===================================================================
--- code/stage/trunk/libstage/model_load.cc 2009-08-10 08:49:51 UTC (rev
8188)
+++ code/stage/trunk/libstage/model_load.cc 2009-08-11 02:02:02 UTC (rev
8189)
@@ -21,6 +21,9 @@
PRINT_DEBUG1( "Model \"%s\" loading...", token );
+ // choose the thread to run in, if thread_safe > 0
+ event_queue_num = wf->ReadInt( wf_entity, "event_queue", event_queue_num );
+
if( wf->PropertyExists( wf_entity, "joules" ) )
{
if( !power_pack )
@@ -55,10 +58,6 @@
if( (watts_give > 0.0) && !pp)
PRINT_WARN1( "Model %s: Setting \"watts_give\" has no effect unless
\"joules\" is specified for this model or a parent", token );
- if( watts_give ) // need to get the world to test this model for charging
others
- //world->ChargeListAdd( this );
- world->Enqueue( World::Event::ENERGY, interval_energy, this );
-
watts_take = wf->ReadFloat( wf_entity, "take_watts", watts_take );
if( (watts_take > 0.0) & !pp )
PRINT_WARN1( "Model %s: Setting \"watts_take\" has no effect unless
\"joules\" is specified for this model or a parent", token );
Modified: code/stage/trunk/libstage/stage.hh
===================================================================
--- code/stage/trunk/libstage/stage.hh 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/stage.hh 2009-08-11 02:02:02 UTC (rev 8189)
@@ -1003,8 +1003,21 @@
};
std::vector<std::priority_queue<Event> > event_queues;
- void Enqueue( Event::type_t type, stg_usec_t delay, Model* mod );
+ void Enqueue( unsigned int queue_num, Event::type_t type, stg_usec_t
delay, Model* mod );
+ /** The sim time of the next event in the queue. */
+ //stg_usec_t time_of_next_event;
+ uint32_t event_pending_count;
+
+ stg_usec_t sim_interval;
+
+ /** consume events from the queue up to and including the current
sim_time */
+ void ConsumeQueue( unsigned int queue_num );
+
+ /** returns an event queue index number for a model to use for
+ updates */
+ unsigned int GetEventQueue( Model* mod );
+
public:
/** returns true when time to quit, false otherwise */
static bool UpdateAll();
@@ -1403,8 +1416,6 @@
std::vector<Option*> drawOptions;
FileManager* fileMan; ///< Used to load and save worldfiles
std::vector<stg_usec_t> interval_log;
-
- stg_usec_t interval_real; ///< real-time interval between updates - set
this to zero for 'as fast as possible
/** Stage attempts to run this many times faster than real
time. If -1, Stage runs as fast as possible. */
@@ -1416,6 +1427,8 @@
stg_usec_t real_time_of_last_update;
// static callback functions
+ static void UpdateCallback( WorldGui* world );
+
static void windowCb( Fl_Widget* w, void* p );
static void fileLoadCb( Fl_Widget* w, void* p );
static void fileSaveCb( Fl_Widget* w, void* p );
@@ -1472,13 +1485,7 @@
void Show();
/** Get human readable string that describes the current global energy
state. */
- std::string EnergyString( void );
-
- /** Set the minimum real time interval between world updates, in
- microeconds. */
- void SetRealTimeInterval( stg_usec_t usec )
- { interval_real = usec; }
-
+ std::string EnergyString( void );
virtual void RemoveChild( Model* mod );
};
@@ -1807,15 +1814,15 @@
bool rebuild_displaylist; ///< iff true, regenerate block
display list before redraw
char* say_string; ///< if non-null, this string is displayed
in the GUI
- stg_bool_t stall;
- /** Thread safety flag. Iff true, Update() may be called in
- parallel with other models. Defaults to false
for safety */
- int subs; ///< the number of subscriptions to this model
- bool thread_safe;
-
- /** Cache of recent poses, used to draw the trail. */
- std::list<TrailItem> trail;
-
+ stg_bool_t stall;
+ int subs; ///< the number of subscriptions to this model
+ /** Thread safety flag. Iff true, Update() may be called in
+ parallel with other models. Defaults to false for safety */
+ bool thread_safe;
+
+ /** Cache of recent poses, used to draw the trail. */
+ std::list<TrailItem> trail;
+
/** The maxiumum length of the trail drawn. Default is 20, but
can
be set in the world file using the tail_length
model
property. */
@@ -1825,13 +1832,13 @@
long unsigned int trail_interval;
stg_model_type_t type;
- /** The index into the world's vector of update lists. Initially
- -1, to indicate that it is not on a list yet. */
- int update_list_num;
- bool used; ///< TRUE iff this model has been returned by
GetUnusedModelOfType()
- Velocity velocity;
- stg_watts_t watts;///< power consumed by this model
-
+ /** The index into the world's vector of event queues. Initially
+ -1, to indicate that it is not on a list yet. */
+ int event_queue_num;
+ bool used; ///< TRUE iff this model has been returned by
GetUnusedModelOfType()
+ Velocity velocity;
+ stg_watts_t watts;///< power consumed by this model
+
/** If >0, this model can transfer energy to models that have
watts_take >0 */
stg_watts_t watts_give;
@@ -1938,7 +1945,6 @@
virtual void Startup();
virtual void Shutdown();
virtual void Update();
- virtual void SynchronousPostUpdate();
virtual void UpdatePose();
virtual void UpdateCharge();
@@ -1946,10 +1952,6 @@
stg_meters_t ModelHeight() const;
- //bool UpdateDue( void );
- //void UpdateIfDue();
- void CallUpdateCallbacks( void );
-
void DrawBlocksTree();
virtual void DrawBlocks();
void DrawBoundingBox();
Modified: code/stage/trunk/libstage/test.cc
===================================================================
--- code/stage/trunk/libstage/test.cc 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/test.cc 2009-08-11 02:02:02 UTC (rev 8189)
@@ -37,12 +37,8 @@
Init( &argc, &argv);
WorldGui world( 400,400, "Test" );
-
- world.SetRealTimeInterval( 10000 );
-
world.Start();
-
Geom geom;
bzero( &geom, sizeof(geom) );
Modified: code/stage/trunk/libstage/world.cc
===================================================================
--- code/stage/trunk/libstage/world.cc 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/libstage/world.cc 2009-08-11 02:02:02 UTC (rev 8189)
@@ -99,7 +99,9 @@
wf( NULL ),
paused( false ),
steps(0),
- event_queues(1)
+ event_queues(1),
+ // time_of_next_event(0)
+ sim_interval( 1e5 ) // 100 msec
{
if( ! Stg::InitDone() )
{
@@ -149,57 +151,41 @@
return quit;
}
-// void* World::update_thread_entry( std::pair<World*,int> *thread_info )
-// {
-// World* world = thread_info->first;
-// int thread_instance = thread_info->second;
+void* World::update_thread_entry( std::pair<World*,int> *thread_info )
+{
+ World* world = thread_info->first;
+ int thread_instance = thread_info->second;
-// //g_mutex_lock( world->thread_mutex );
-// pthread_mutex_lock( &world->thread_mutex );
+ pthread_mutex_lock( &world->thread_mutex );
-// while( 1 )
-// {
-// // wait until the main thread signals us
-// //puts( "worker waiting for start signal" );
+ while( 1 )
+ {
+ // wait until the main thread signals us
+ //puts( "worker waiting for start signal" );
-// //g_cond_wait( world->threads_start_cond, world->thread_mutex );
-// //g_mutex_unlock( world->thread_mutex );
-// pthread_cond_wait( &world->threads_start_cond, &world->thread_mutex );
-// pthread_mutex_unlock( &world->thread_mutex );
+ pthread_cond_wait( &world->threads_start_cond, &world->thread_mutex );
+ pthread_mutex_unlock( &world->thread_mutex );
+ //puts( "worker thread awakes" );
-
-// //puts( "worker thread awakes" );
+ // consume events on the queue up to the current sim time
+ world->ConsumeQueue( thread_instance );
+
+ // done working, so increment the counter. If this was the last
+ // thread to finish working, signal the main thread, which is
+ // blocked waiting for this to happen
-// // loop over the list of rentrant models for this thread
-// FOR_EACH( it, world->update_lists[thread_instance] )
-// {
-// Model* mod = *it;
-// //printf( "thread %d updating model %s (%p)\n",
thread_instance, mod->Token(), mod );
-
-// // TODO - some of this (Model::Update()) is not thread
safe!
-// //if( mod->UpdateDue() )
-// mod->Update();
-// }
-
-// // done working, so increment the counter. If this was the last
-// // thread to finish working, signal the main thread, which is
-// // blocked waiting for this to happen
-
-// //g_mutex_lock( world->thread_mutex );
-// pthread_mutex_lock( &world->thread_mutex );
-
-// if( --world->threads_working == 0 )
-// {
-// //puts( "last worker signalling main thread" );
-// //g_cond_signal( world->threads_done_cond );
-// pthread_cond_signal( &world->threads_done_cond );
-// }
-// // keep lock going round the loop
-// }
+ pthread_mutex_lock( &world->thread_mutex );
+ if( --world->threads_working == 0 )
+ {
+ //puts( "last worker signalling main thread" );
+ pthread_cond_signal( &world->threads_done_cond );
+ }
+ // keep lock going round the loop
+ }
-// return NULL;
-// }
+ return NULL;
+}
void World::RemoveModel( Model* mod )
@@ -315,27 +301,27 @@
if( worker_threads > 0 )
{
PRINT_WARN( "\nmulti-thread support is experimental and may not
work properly, if at all." );
-// update_lists.resize( worker_threads + 1 );
-// // kick off count threads.
-// for( unsigned int t=0; t<worker_threads; t++ )
-// {
-// std::pair<World*,int> *p = new std::pair<World*,int>(
this, t+1 );
+ event_queues.resize( worker_threads + 1 );
+
+ // kick off the threads
+ for( unsigned int t=0; t<worker_threads; t++ )
+ {
+ std::pair<World*,int> *p = new std::pair<World*,int>(
this, t+1 );
-// //normal posix pthread C function pointer
-// typedef void* (*func_ptr) (void*);
+ //normal posix pthread C function pointer
+ typedef void* (*func_ptr) (void*);
-// pthread_t pt;
-// pthread_create( &pt,
-// NULL,
-//
(func_ptr)World::update_thread_entry,
-// p );
-// }
+ pthread_t pt;
+ pthread_create( &pt,
+ NULL,
+
(func_ptr)World::update_thread_entry,
+ p );
+ }
printf( "[threads %u]", worker_threads );
}
-
// Iterate through entitys and create objects of the appropriate type
for( int entity = 1; entity < wf->GetEntityCount(); entity++ )
{
@@ -486,132 +472,121 @@
}
}
-bool World::Update()
-{
- PRINT_DEBUG( "World::Update()" );
-
- // if we've run long enough, exit
- if( PastQuitTime() ) {
- if( IsGUI() == false )
- return true;
- }
-
- if( paused )
- {
- if( steps < 1 )
- return true;
- else
- {
- --steps;
- //printf( "world::update (steps remaining %d)\n", steps );
- }
- }
+void World::ConsumeQueue( unsigned int queue_num )
+{
+ std::priority_queue<Event>& queue = event_queues[queue_num];
- dirty = true; // need redraw
-
- stg_usec_t next_time = 0;
-
- // TESTING
- static unsigned int last_queue_len = 0;
- unsigned int queue_len = event_queues[0].size();
- if( last_queue_len != 0 && last_queue_len != queue_len )
- {
- printf( "queue length changed from %u to %u\n", last_queue_len,
queue_len );
- getchar();
- }
- // END TESTING
+ if( queue.empty() )
+ return;
- last_queue_len = queue_len;
-
// update everything on the event queue that happens at this time or earlier
- if( ! event_queues[0].empty() )
+ Event ev( queue.top() );
+ while( ev.time <= sim_time )
{
- Event ev( event_queues[0].top() );
- while( ev.time <= sim_time )
+ // printf( "@ %llu next event <%s %llu
%s>\n",
+ // sim_time,
+ // ev.TypeStr(
ev.type ),
+ // ev.time,
+ // ev.mod->Token()
);
+
+ queue.pop();
+
+ // only update events are allowed in queues other than zero
+ if( queue_num > 0 && ev.type != Event::UPDATE )
+ PRINT_WARN1( "event type %d in async queue", queue_num );
+
+ switch( ev.type )
{
-// printf( "@ %llu next event <%s %llu %s>\n",
-// sim_time,
-// ev.TypeStr( ev.type ),
-// ev.time,
-// ev.mod->Token() );
-
- event_queues[0].pop();
+ case Event::UPDATE:
+ ev.mod->Update();
+ break;
- switch( ev.type )
- {
- case Event::UPDATE:
- ev.mod->Update();
- ev.mod->SynchronousPostUpdate();
- break;
-
- case Event::POSE:
- ev.mod->UpdatePose();
- break;
-
- case Event::ENERGY:
- ev.mod->UpdateCharge();
- break;
-
- default:
- PRINT_WARN1( "unknown event type %d", ev.type
);
- }
+ case Event::POSE:
+ ev.mod->UpdatePose();
+ break;
- ev = event_queues[0].top();
+ case Event::ENERGY:
+ ev.mod->UpdateCharge();
+ break;
+
+ default:
+ PRINT_WARN1( "unknown event type %d", ev.type );
}
-
- next_time = ev.time;
- stg_usec_t step = next_time - sim_time;
- // smoothed interval tracking
- interval_track = 0.1 * step + 0.9 * interval_track;
-
- // printf( "@ %llu done. (next event at %llu)\n\n", sim_time,
next_time );
+ ev = queue.top();
}
-
+}
- // world callbacks
- CallUpdateCallbacks();
- // move the clock on to the next event
- sim_time = next_time;
- this->updates++;
-
-
-// // then update all models on the update lists
-// FOR_EACH( it, update_lists[0] )
+bool World::Update()
+{
+ PRINT_DEBUG( "World::Update()" );
+
+ // if we've run long enough, exit
+// if( PastQuitTime() )
// {
-// //printf( "thread MAIN updating model %s\n", (*it)->Token() );
-// (*it)->UpdateIfDue();
+// if( IsGUI() == false )
+// return true;
// }
-// if( worker_threads > 0 )
-// {
-// pthread_mutex_lock( &thread_mutex );
-// threads_working = worker_threads;
-// // unblock the workers - they are waiting on this condition var
-// //puts( "main thread signalling workers" );
-// pthread_cond_broadcast( &threads_start_cond );
-
-// // wait for all the last update job to complete - it will
-// // signal the worker_threads_done condition var
-// while( threads_working > 0 )
-// {
-// //puts( "main thread waiting for workers to finish" );
-// pthread_cond_wait( &threads_done_cond, &thread_mutex );
-// }
-// pthread_mutex_unlock( &thread_mutex );
-// //puts( "main thread awakes" );
-
-// // TODO: allow threadsafe callbacks to be called in worker
-// // threads
-
-// }
-
-// // do any sychronous updates we need to do
-// for( unsigned int i=1; i<update_lists.size(); i++ )
-// FOR_EACH( it, update_lists[i] )
-// (*it)->SynchronousPostUpdate();
+ if( event_pending_count < 1 )
+ {
+ PRINT_WARN( "event queue(s) empty." );
+ return false;
+ }
+ // if( paused )
+ // {
+ // if( steps < 1 )
+ // return true;
+ // else
+ // {
+ // --steps;
+ // //printf( "world::update (steps remaining %d)\n", steps );
+ // }
+ // }
+
+ sim_time += sim_interval;
+
+ // handle the zeroth queue synchronously in the main thread
+ ConsumeQueue( 0 );
+
+ // handle all the remaining queues asynchronously in worker threads
+ if( worker_threads > 0 )
+ {
+ pthread_mutex_lock( &thread_mutex );
+ threads_working = worker_threads;
+ // unblock the workers - they are waiting on this condition var
+ //puts( "main thread signalling workers" );
+ pthread_cond_broadcast( &threads_start_cond );
+
+ // todo - take the 1th thread work here?
+
+ // wait for all the last update job to complete - it will
+ // signal the worker_threads_done condition var
+ while( threads_working > 0 )
+ {
+ //puts( "main thread waiting for workers to finish" );
+ pthread_cond_wait( &threads_done_cond, &thread_mutex );
+ }
+ pthread_mutex_unlock( &thread_mutex );
+ //puts( "main thread awakes" );
+
+ // TODO: allow threadsafe callbacks to be called in worker
+ // threads
+ }
+
+ //stg_usec_t step = time_of_next_event - sim_time;
+ // smoothed interval tracking
+ //interval_track = 0.1 * step + 0.9 * interval_track;
+ dirty = true; // need redraw
+ // printf( "@ %llu done. (next event at %llu)\n\n", sim_time, next_time );
+
+ // world callbacks
+ CallUpdateCallbacks();
+
+ ++updates;
+
if( show_clock && ((this->updates % show_clock_interval) == 0) )
{
printf( "\r[Stage: %s]", ClockString().c_str() );
@@ -626,6 +601,13 @@
models_by_name[mod->token] = mod;
}
+unsigned int World::GetEventQueue( Model* mod )
+{
+ if( worker_threads < 1 )
+ return 0;
+ return( (random() % worker_threads) + 1);
+}
+
Model* World::GetModel( const char* name ) const
{
PRINT_DEBUG1( "looking up model name %s in models_by_name", name );
@@ -1114,11 +1096,12 @@
//LogEntry::Print();
}
-void World::Enqueue( Event::type_t type, stg_usec_t delay, Model* mod )
+void World::Enqueue( unsigned int queue_num, Event::type_t type, stg_usec_t
delay, Model* mod )
{
//printf( "enqueue at %llu %p %s\n", sim_time + delay, mod, mod->Token() );
-
- event_queues[0].push( Event( type, sim_time + delay, mod ) );
+
+ event_queues[queue_num].push( Event( type, sim_time + delay, mod ) );
+ ++event_pending_count;
}
bool World::Event::operator<( const Event& other ) const
Modified: code/stage/trunk/libstage/worldgui.cc
===================================================================
--- code/stage/trunk/libstage/worldgui.cc 2009-08-10 08:49:51 UTC (rev
8188)
+++ code/stage/trunk/libstage/worldgui.cc 2009-08-11 02:02:02 UTC (rev
8189)
@@ -190,7 +190,6 @@
drawOptions(),
fileMan( new FileManager() ),
interval_log(),
- interval_real( (stg_usec_t)1e5 ),
speedup(1.0), // real time
mbar( new Fl_Menu_Bar(0,0, W, 30)),
oDlg( NULL ),
@@ -199,7 +198,7 @@
{
interval_log.resize(16);
for( unsigned int i=0; i<interval_log.size(); i++ )
- interval_log[i] = interval_real;
+ interval_log[i] = sim_interval;
Fl::scheme( "gtk+" );
resizable(canvas);
@@ -270,23 +269,12 @@
fileMan->newWorld( filename );
World::Load( filename );
-
- int world_section = 0; // use the top-level section for some parms
- // that traditionally live there
-
- // todo - remove this and use speedup instead
- this->interval_real = (stg_usec_t)thousand *
- wf->ReadInt( world_section, "interval_real",
(int)(this->interval_real/thousand) );
- this->speedup = wf->ReadFloat( world_section, "speedup", this->speedup );
+ // worldgui exclusive properties live in the top-level section
+ int world_section = 0;
+ speedup = wf->ReadFloat( world_section, "speedup", speedup );
+ paused = wf->ReadInt( world_section, "paused", paused );
- if( sgn(speedup) < 0 )
- interval_real = 0;
-
- // this is a world property that's only load()ed in worldgui
- this->paused =
- wf->ReadInt( world_section, "paused", this->paused );
-
// use the window section for the rest
int window_section = wf->LookupEntity( "window" );
@@ -315,13 +303,17 @@
void WorldGui::UnLoad()
{
World::UnLoad();
- // canvas->camera.setPose( 0, 0 );
}
bool WorldGui::Save( const char* filename )
{
PRINT_DEBUG1( "%s.Save()", token );
-
+
+ // worldgui exclusive properties live in the top-level section
+ int world_section = 0;
+ wf->WriteFloat( world_section, "speedup", speedup );
+ wf->WriteInt( world_section, "paused", paused );
+
// use the window section for the rest
int window_section = wf->LookupEntity( "window" );
@@ -341,54 +333,25 @@
return true;
}
+void WorldGui::UpdateCallback( WorldGui* world )
+{
+ world->Update();
+}
+
bool WorldGui::Update()
-{
- //pause the simulation if quit time is set
- if( PastQuitTime() && pause_time == false ) {
- TogglePause();
- pause_time = true;
- }
-
- // if we're paused and counting down, we need to redraw the window
- // because it's not drawn on a timer when paused.
- bool need_redraw = paused && (steps > 0);
-
- bool val = World::Update();
-
- if( need_redraw )
- canvas->redraw();
-
- stg_usec_t timenow;
- stg_usec_t interval;
+{
+ double timeout = speedup > 0 ? (sim_interval/1e6) / speedup : 0;
+ Fl::repeat_timeout( timeout, (Fl_Timeout_Handler)UpdateCallback, this );
- const double sleeptime_max = 1e4;
- double sleeptime = sleeptime_max;
-
- do { // we loop over updating the GUI, sleeping if there's any spare
- // time
- Fl::check();
-
- timenow = RealTimeNow();
-
- // do
- {
- interval = timenow - real_time_of_last_update; // guaranteed to
be >= 0
-
- if( ! paused )
- sleeptime = (double)interval_real - (double)interval;
-
- if( sleeptime > 0)
- usleep( (stg_usec_t)std::min(sleeptime,sleeptime_max) ); //
check the GUI at 10Hz min
- }
- } while( interval < interval_real );
+ //printf( "speedup %.2f timeout %.6f\n", speedup, timeout );
-
- interval_log[updates%interval_log.size()] = interval;
-
-real_time_of_last_update = timenow;
-
- //puts( "FINSHED UPDATE" );
- return val;
+ stg_usec_t timenow = RealTimeNow();
+ stg_usec_t interval = timenow - real_time_of_last_update;
+ interval_log[updates%interval_log.size()] = interval;
+ real_time_of_last_update = timenow;
+
+ // inherit
+ return World::Update();
}
std::string WorldGui::ClockString()
@@ -450,23 +413,17 @@
void WorldGui::DrawTree( bool drawall )
{
- FOR_EACH( it, superregions )
-// for( std::map<stg_point_int_t,SuperRegion*>::iterator it =
superregions.begin();
-// it != superregions.end();
-// it++ )
+ FOR_EACH( it, superregions )
(*it).second->Draw( drawall );
}
void WorldGui::DrawFloor()
{
PushColor( 1,1,1,1 );
-
- FOR_EACH( it, superregions )
-// for( std::map<stg_point_int_t,SuperRegion*>::iterator it =
superregions.begin();
-// it != superregions.end();
-// it++ )
+
+ FOR_EACH( it, superregions )
(*it).second->Floor();
-
+
PopColor();
}
@@ -570,34 +527,25 @@
void WorldGui::slowerCb( Fl_Widget* w, WorldGui* wg )
{
- if( wg->interval_real == 0 )
- wg->interval_real = 10;
- else
- {
- wg->interval_real *= 1.2;
- }
+ wg->speedup *= 0.8;
}
void WorldGui::fasterCb( Fl_Widget* w, WorldGui* wg )
{
- if( wg->interval_real == 0 )
- putchar( 7 ); // bell!
+ if( wg->speedup <= 0 )
+ putchar( 7 ); // bell - can go no faster
else
- {
- wg->interval_real *= 0.8;
- if( wg->interval_real < 10 )
- wg->interval_real = 0;
- }
+ wg->speedup *= 1.2;
}
void WorldGui::realtimeCb( Fl_Widget* w, WorldGui* wg )
{
- wg->interval_real = wg->interval_track;
+ wg->speedup = 1.0;
}
void WorldGui::fasttimeCb( Fl_Widget* w, WorldGui* wg )
{
- wg->interval_real = 0;
+ wg->speedup = -1;
}
void WorldGui::Start()
@@ -608,14 +556,16 @@
Fl::add_timeout( ((double)canvas->interval/1000),
(Fl_Timeout_Handler)Canvas::TimerCallback,
canvas );
+
+ Fl::add_timeout( 0.01, (Fl_Timeout_Handler)UpdateCallback, this );
}
void WorldGui::Stop()
{
World::Stop();
- // remove the redraw timeout
Fl::remove_timeout( (Fl_Timeout_Handler)Canvas::TimerCallback );
+ Fl::remove_timeout( (Fl_Timeout_Handler)WorldGui::UpdateCallback );
// drawn 'cos we cancelled the timeout
canvas->redraw(); // in case something happened that will never be
Modified: code/stage/trunk/worlds/SFU.world
===================================================================
--- code/stage/trunk/worlds/SFU.world 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/worlds/SFU.world 2009-08-11 02:02:02 UTC (rev 8189)
@@ -6,8 +6,7 @@
include "map.inc"
include "sick.inc"
-interval_sim 100 # simulation timestep in milliseconds
-interval_real 0 # real-time interval between simulation updates in
milliseconds
+speedup -1 # as fast as possible
paused 0
resolution 0.1
Modified: code/stage/trunk/worlds/benchmark/cave.world
===================================================================
--- code/stage/trunk/worlds/benchmark/cave.world 2009-08-10 08:49:51 UTC
(rev 8188)
+++ code/stage/trunk/worlds/benchmark/cave.world 2009-08-11 02:02:02 UTC
(rev 8189)
@@ -7,8 +7,9 @@
include "../sick.inc"
resolution 0.02 # resolution of the underlying raytrace mode
-interval_sim 100 # simulation timestep in milliseconds
-interval_real 0 # real-time interval between simulation updates in
milliseconds
+
+speedup -1 # as fast as possible
+
paused 1
# configure the GUI window
Modified: code/stage/trunk/worlds/benchmark/hospital.world
===================================================================
--- code/stage/trunk/worlds/benchmark/hospital.world 2009-08-10 08:49:51 UTC
(rev 8188)
+++ code/stage/trunk/worlds/benchmark/hospital.world 2009-08-11 02:02:02 UTC
(rev 8189)
@@ -8,8 +8,7 @@
# set the resolution of the underlying raytrace model in meters
resolution 0.02
-interval_sim 100 # simulation timestep in milliseconds
-interval_real 0 # real-time interval between simulation updates in
milliseconds
+speedup -1 # as fast as possible
paused 1
Modified: code/stage/trunk/worlds/fasr.world
===================================================================
--- code/stage/trunk/worlds/fasr.world 2009-08-10 08:49:51 UTC (rev 8188)
+++ code/stage/trunk/worlds/fasr.world 2009-08-11 02:02:02 UTC (rev 8189)
@@ -6,8 +6,7 @@
include "map.inc"
include "sick.inc"
-interval_real 0 # real-time interval between simulation updates in
milliseconds
-speedup 1
+speedup -1 # fast mode
paused 1
# time to pause (in GUI mode) or quit (in headless mode) the simulation
@@ -15,7 +14,7 @@
resolution 0.02
-threads 2
+threads 0
# configure the GUI window
window
Modified: code/stage/trunk/worlds/pioneer_flocking.world
===================================================================
--- code/stage/trunk/worlds/pioneer_flocking.world 2009-08-10 08:49:51 UTC
(rev 8188)
+++ code/stage/trunk/worlds/pioneer_flocking.world 2009-08-11 02:02:02 UTC
(rev 8189)
@@ -5,8 +5,7 @@
include "pioneer.inc"
include "map.inc"
-interval_sim 100 # simulation timestep in milliseconds
-interval_real 0 # real-time interval between simulation updates in
milliseconds
+speedup 100
paused 1
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit