00001 #include "OSDLScheduler.h"
00002
00003 #include "OSDLBasic.h"
00004 #include "OSDLVideo.h"
00005 #include "OSDLRenderer.h"
00006 #include "OSDLActiveObject.h"
00007
00008
00009 #include <iostream>
00010 using std::ostringstream ;
00011
00012 #include <iomanip>
00013
00014
00015
00016 using namespace Ceylan::Log ;
00017
00018
00019 using namespace Ceylan::System ;
00020
00021 using namespace OSDL::Events ;
00022 using namespace OSDL::Rendering ;
00023 using namespace OSDL::Engine ;
00024
00025 using std::string ;
00026 using std::list ;
00027 using std::map ;
00028
00029
00030 Scheduler * Scheduler::_internalScheduler = 0 ;
00031
00032 const Scheduler::Delay Scheduler::ShutdownBucketLevel = 100000 ;
00033
00034
00035 #ifdef OSDL_USES_CONFIG_H
00036 #include <OSDLConfig.h>
00037 #endif // OSDL_USES_CONFIG_H
00038
00039
00040
00041 #if OSDL_DEBUG_SCHEDULER
00042
00043 #include <iostream>
00044 #define OSDL_SCHEDULE_LOG(message) std::cerr << message << std::endl ;
00045
00046 #else // OSDL_DEBUG_SCHEDULER
00047
00048 #define OSDL_SCHEDULE_LOG(message)
00049
00050 #endif // OSDL_DEBUG_SCHEDULER
00051
00052
00053
00054 bool Scheduler::hasRenderer() const throw()
00055 {
00056
00057 return ( _renderer != 0 ) ;
00058
00059 }
00060
00061
00062 Renderer & Scheduler::getRenderer() const throw( SchedulingException )
00063 {
00064
00065 if ( _renderer != 0 )
00066 return * _renderer ;
00067 else
00068 throw SchedulingException(
00069 "Scheduler::getRenderer : no renderer available." ) ;
00070
00071 }
00072
00073
00074 void Scheduler::setRenderer( Rendering::Renderer & newRenderer ) throw()
00075 {
00076
00077 if ( _renderer != 0 )
00078 delete _renderer ;
00079
00080 _renderer = & newRenderer ;
00081
00082 }
00083
00084
00085
00086 void Scheduler::setScreenshotMode( bool on, const string & frameFilenamePrefix,
00087 Hertz frameFrequency ) throw()
00088 {
00089
00090 _screenshotMode = on ;
00091 _frameFilenamePrefix = frameFilenamePrefix ;
00092
00093 }
00094
00095
00096 void Scheduler::setTimeSliceDuration( Microsecond engineTickDuration ) throw()
00097 {
00098
00099 _engineTickDuration = engineTickDuration ;
00100
00101
00102 setSimulationFrequency( _desiredSimulationFrequency ) ;
00103 setRenderingFrequency( _desiredRenderingFrequency ) ;
00104 setScreenshotFrequency( _desiredScreenshotFrequency ) ;
00105 setInputPollingFrequency( _desiredInputFrequency ) ;
00106
00107 _secondToEngineTick = 1000000 / _engineTickDuration ;
00108
00109 OSDL_SCHEDULE_LOG(
00110 "Multiplicative factor to convert seconds into engine ticks : "
00111 + Ceylan::toString( _secondToEngineTick ) ) ;
00112
00113 }
00114
00115
00116 Microsecond Scheduler::getTimeSliceDuration() const throw()
00117 {
00118
00119 return _engineTickDuration ;
00120
00121 }
00122
00123
00124 void Scheduler::setSimulationFrequency( Hertz frequency )
00125 throw( SchedulingException )
00126 {
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 if ( frequency * _engineTickDuration > 1E6 )
00138 throw SchedulingException( "Scheduler::setSimulationFrequency : "
00139 " requested simulation frequency ("
00140 + Ceylan::toString( frequency )
00141 + " Hz) is too high for engine tick,"
00142 " which lasts for "
00143 + Ceylan::toString( _engineTickDuration )
00144 + " microseconds." ) ;
00145
00146 _desiredSimulationFrequency = frequency ;
00147 _simulationPeriod = static_cast<Period>(
00148 1E6 / ( frequency * _engineTickDuration ) ) ;
00149
00150 #if OSDL_DEBUG
00151
00152 LogPlug::debug( "Scheduler::setSimulationFrequency : for a requested "
00153 "simulation frequency of " + Ceylan::toString( frequency )
00154 + " Hz, the simulation period corresponds to "
00155 + Ceylan::toString( _simulationPeriod ) + " engine ticks." ) ;
00156
00157 #endif // OSDL_DEBUG
00158
00159 }
00160
00161
00162 Period Scheduler::getSimulationTickCount() const throw()
00163 {
00164
00165 return _simulationPeriod ;
00166
00167 }
00168
00169
00170 void Scheduler::setRenderingFrequency( Hertz frequency )
00171 throw( SchedulingException )
00172 {
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 if ( frequency * _engineTickDuration > 1E6 )
00185 throw SchedulingException( "Scheduler::setRenderingFrequency : "
00186 "requested rendering frequency ("
00187 + Ceylan::toString( frequency )
00188 + " Hz) is too high for engine tick,"
00189 " which lasts for "
00190 + Ceylan::toString( _engineTickDuration )
00191 + " microseconds." ) ;
00192
00193 _desiredRenderingFrequency = frequency ;
00194 _renderingPeriod = static_cast<Period>(
00195 1E6 / ( frequency * _engineTickDuration ) ) ;
00196
00197 #if OSDL_DEBUG
00198
00199 LogPlug::debug( "Scheduler::setRenderingFrequency : for a requested "
00200 "rendering frequency of " + Ceylan::toString( frequency )
00201 + " Hz, the rendering period corresponds to "
00202 + Ceylan::toString( _renderingPeriod ) + " engine ticks." ) ;
00203
00204 #endif // OSDL_DEBUG
00205
00206 }
00207
00208
00209 Period Scheduler::getRenderingTickCount() const throw()
00210 {
00211
00212 return _renderingPeriod ;
00213
00214 }
00215
00216
00217 void Scheduler::setScreenshotFrequency( Hertz frequency )
00218 throw( SchedulingException )
00219 {
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 if ( frequency * _engineTickDuration > 1E6 )
00236 throw SchedulingException( "Scheduler::setScreenshotFrequency : "
00237 " requested screenshot frequency ("
00238 + Ceylan::toString( frequency )
00239 + " Hz) is too high for engine tick,"
00240 " which lasts for " + Ceylan::toString( _engineTickDuration )
00241 + " microseconds." ) ;
00242
00243 _desiredScreenshotFrequency = frequency ;
00244 _screenshotPeriod = static_cast<Period>(
00245 1E6 / ( frequency * _engineTickDuration ) ) ;
00246
00247
00248 #if OSDL_DEBUG
00249
00250 LogPlug::debug( "Scheduler::setScreenshotFrequency : for a requested "
00251 "screenshot frequency of " + Ceylan::toString( frequency )
00252 + " Hz, the screenshot period corresponds to "
00253 + Ceylan::toString( _screenshotPeriod ) + " engine ticks." ) ;
00254
00255 #endif // OSDL_DEBUG
00256
00257 }
00258
00259
00260 Period Scheduler::getScreenshotTickCount() const throw()
00261 {
00262
00263 return _screenshotPeriod ;
00264
00265 }
00266
00267
00268 void Scheduler::setInputPollingFrequency( Hertz frequency )
00269 throw( SchedulingException )
00270 {
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 if ( frequency * _engineTickDuration > 1E6 )
00283 throw SchedulingException(
00284 "Scheduler::setInputPollingFrequency : requested input "
00285 "frequency (" + Ceylan::toString( frequency )
00286 + " Hz) is too high for engine tick,"
00287 " which lasts for "
00288 + Ceylan::toString( _engineTickDuration ) + " microseconds." ) ;
00289
00290 _desiredInputFrequency = frequency ;
00291 _inputPeriod = static_cast<Period>(
00292 1E6 / ( frequency * _engineTickDuration ) ) ;
00293
00294 #if OSDL_DEBUG
00295
00296 LogPlug::debug( "Scheduler::setInputPollingFrequency : for a requested "
00297 "input frequency of " + Ceylan::toString( frequency )
00298 + " Hz, the input period corresponds to "
00299 + Ceylan::toString( _inputPeriod ) + " engine ticks." ) ;
00300
00301 #endif // OSDL_DEBUG
00302
00303 }
00304
00305
00306 void Scheduler::setIdleCallback(
00307 Ceylan::System::Callback idleCallback,
00308 void * callbackData,
00309 Ceylan::System::Microsecond callbackExpectedMaxDuration )
00310 throw()
00311 {
00312
00313 _idleCallback = idleCallback ;
00314 _idleCallbackData = callbackData ;
00315
00316 if ( callbackExpectedMaxDuration != 0 )
00317 _idleCallbackMaxDuration = callbackExpectedMaxDuration ;
00318 else
00319 _idleCallbackMaxDuration = EventsModule::EvaluateCallbackduration(
00320 idleCallback, callbackData ) ;
00321
00322 }
00323
00324
00325 Period Scheduler::getInputPollingTickCount() const throw()
00326 {
00327
00328 return _inputPeriod ;
00329
00330 }
00331
00332
00333 EngineTick Scheduler::getCurrentEngineTick() const throw()
00334 {
00335
00336 return _currentEngineTick ;
00337
00338 }
00339
00340
00341 SimulationTick Scheduler::getCurrentSimulationTick() const throw()
00342 {
00343
00344 return _currentSimulationTick ;
00345
00346 }
00347
00348
00349 RenderingTick Scheduler::getCurrentRenderingTick() const throw()
00350 {
00351
00352 return _currentRenderingTick ;
00353
00354 }
00355
00356
00357 RenderingTick Scheduler::getCurrentInputTick() const throw()
00358 {
00359
00360 return _currentInputTick ;
00361
00362 }
00363
00364
00365 void Scheduler::registerObject( ActiveObject & objectToRegister ) throw()
00366 {
00367
00368 #if OSDL_DEBUG
00369 if ( objectToRegister.getPeriod() == 0
00370 && ! objectToRegister.hasProgrammedActivations() )
00371 LogPlug::error( "Scheduler::registerObject : "
00372 "following object will never be activated : "
00373 + objectToRegister.toString() ) ;
00374 #endif // OSDL_DEBUG
00375
00376
00377 if ( objectToRegister.getPeriod() != 0 )
00378 {
00379
00380 PeriodicSlot & slot = getPeriodicSlotFor(
00381 objectToRegister.getPeriod() ) ;
00382
00383 slot.add( objectToRegister ) ;
00384
00385 }
00386
00387
00388 if ( objectToRegister.hasProgrammedActivations() )
00389 {
00390
00391
00392
00393 const list<SimulationTick> & programmed =
00394 objectToRegister.getProgrammedActivations() ;
00395
00396 for ( list<SimulationTick>::const_iterator it = programmed.begin();
00397 it != programmed.end(); it++ )
00398 {
00399 programTriggerFor( objectToRegister, (*it) ) ;
00400 }
00401
00402 }
00403
00404 objectToRegister.setBirthTime( _currentSimulationTick ) ;
00405
00406 }
00407
00408
00409 void Scheduler::schedule() throw( SchedulingException )
00410 {
00411
00412 try
00413 {
00414
00415 _eventsModule = & OSDL::getExistingCommonModule().getEventsModule() ;
00416
00417 }
00418 catch( OSDL::Exception & e )
00419 {
00420 throw SchedulingException( "Scheduler::schedule : "
00421 "no events module available." ) ;
00422 }
00423
00424
00425 if ( _renderer != 0 )
00426 {
00427 send( "Scheduling now, using renderer : " + _renderer->toString() ) ;
00428 }
00429 else
00430 {
00431
00432 try
00433 {
00434 _videoModule = & OSDL::getExistingCommonModule().getVideoModule() ;
00435 }
00436 catch( OSDL::Exception & e )
00437 {
00438 throw SchedulingException( "Scheduler::schedule : "
00439 "no renderer nor video module available." ) ;
00440 }
00441
00442 send( "Scheduling now, using video module (no renderer)." ) ;
00443
00444 }
00445
00446
00447 if ( _screenshotMode )
00448 scheduleNoDeadline() ;
00449 else
00450 scheduleBestEffort() ;
00451
00452 }
00453
00454
00455 void Scheduler::stop() throw()
00456 {
00457
00458 _stopRequested = true ;
00459
00460 }
00461
00462
00463 const string Scheduler::toString( Ceylan::VerbosityLevels level ) const throw()
00464 {
00465
00466 ostringstream buf ;
00467 buf.precision( 2 ) ;
00468
00469 buf << setiosflags( std::ios::fixed )
00470 << "Scheduler, whose internal frequency is "
00471 << 1E6 / _engineTickDuration
00472 << " Hz (engine tick duration is "
00473 + Ceylan::toString( _engineTickDuration )
00474 + " microseconds). Current engine tick is "
00475 + Ceylan::toString( _currentEngineTick )
00476 + ", current simulation tick is "
00477 + Ceylan::toString( _currentSimulationTick )
00478 + ", current rendering tick is "
00479 + Ceylan::toString( _currentRenderingTick )
00480 + " and current input tick is "
00481 + Ceylan::toString( _currentInputTick )
00482 + ". Screenshot mode is "
00483 + ( _screenshotMode ? "on." : "off." ) ;
00484
00485
00486 if ( _scheduleStartingSecond == 0 && _scheduleStartingMicrosecond == 0 )
00487 buf << " Scheduler is stopped." ;
00488 else
00489 {
00490
00491 Ceylan::System::Second sec ;
00492 Ceylan::System::Microsecond microsec ;
00493 Ceylan::System::getPreciseTime( sec, microsec ) ;
00494
00495 buf << " Scheduler has been running for "
00496 << Ceylan::System::durationToString( _scheduleStartingSecond,
00497 _scheduleStartingMicrosecond, sec, microsec )
00498 << "." ;
00499
00500 }
00501
00502
00503 if ( _renderer != 0 )
00504 buf << " Using a renderer ("
00505 + _renderer->toString( Ceylan::low ) + ")" ;
00506 else
00507 buf << " No renderer registered, using directly video module" ;
00508
00509 if ( _idleCallback == 0 )
00510 buf << ". Using atomic sleep idle callback" ;
00511 else
00512 buf << ". Using user-specified idle callback" ;
00513
00514 if ( _idleCallbackData )
00515 if ( _idleCallback )
00516 buf << ", callback data has been set as well." ;
00517 else
00518 buf << ", callback data has been set, "
00519 " whereas it is not used by default idle callback (abnormal)." ;
00520
00521 buf << ". The estimated upper-bound for idle callback duration is "
00522 + Ceylan::toString( _idleCallbackMaxDuration )
00523 + " microseconds" ;
00524
00525
00526 if ( level == Ceylan::low )
00527 return buf.str() ;
00528
00529
00530
00531 buf << ". User-defined simulation frequency is "
00532 + Ceylan::toString( 1E6 / ( _simulationPeriod * _engineTickDuration ),
00533 2 )
00534 + " Hz (a period of "
00535 + Ceylan::toString( _simulationPeriod )
00536 + " engine ticks), rendering frequency is "
00537 + Ceylan::toString( 1E6 / ( _renderingPeriod * _engineTickDuration ),
00538 2 )
00539 + " Hz (a period of "
00540 + Ceylan::toString( _renderingPeriod )
00541 + " engine ticks), input polling frequency is "
00542 + Ceylan::toString( 1E6 / ( _inputPeriod * _engineTickDuration ),
00543 2 )
00544 + " Hz (a period of "
00545 + Ceylan::toString( _inputPeriod )
00546 + " engine ticks). There are "
00547 + Ceylan::toString( _periodicSlots.size() )
00548 + " used periodic slot(s) and "
00549 + Ceylan::toString( _programmedActivated.size() )
00550 + " programmed object(s)" ;
00551
00552
00553 if ( level == Ceylan::medium )
00554 return buf.str() ;
00555
00556
00557 if ( ! _periodicSlots.empty() )
00558 {
00559
00560 buf << ". Enumerating scheduling periodic slots : " ;
00561
00562 std::list<string> slots ;
00563
00564 for ( list<PeriodicSlot*>::const_iterator it = _periodicSlots.begin();
00565 it != _periodicSlots.end(); it++ )
00566 slots.push_back( (*it)->toString( level ) ) ;
00567
00568 buf << Ceylan::formatStringList( slots ) ;
00569
00570 }
00571
00572 if ( ! _programmedActivated.empty() )
00573 {
00574
00575 buf << ". Enumerating scheduling programmed slots : " ;
00576
00577 std::list<string> programmed ;
00578
00579 for( map<SimulationTick, ListOfActiveObjects>::const_iterator it
00580 = _programmedActivated.begin(); it
00581 != _programmedActivated.end(); it++ )
00582 programmed.push_back( "For simulation tick #"
00583 + Ceylan::toString( (*it).first )
00584 + ", there are " + Ceylan::toString( (*it).second.size() )
00585 + " object(s) programmed" ) ;
00586
00587 buf << Ceylan::formatStringList( programmed ) ;
00588
00589 }
00590
00591
00592 if ( _screenshotMode )
00593 {
00594
00595 buf << ". Current movie frame period for screenshot mode is "
00596 + Ceylan::toString( _screenshotPeriod )
00597 + " engine ticks, which corresponds to a frequency of "
00598 + Ceylan::toString( 1E6 /
00599 ( _screenshotPeriod * _engineTickDuration ), 2 )
00600 + " frames per second" ;
00601
00602
00603 return buf.str() ;
00604 }
00605
00606
00607 if ( _missedSimulationTicks == 0 )
00608 {
00609
00610 buf << ". No simulation tick was missed" ;
00611
00612 }
00613 else
00614 {
00615
00616 Ceylan::System::Second sec ;
00617 Ceylan::System::Microsecond microsec ;
00618 Ceylan::System::getPreciseTime( sec, microsec ) ;
00619
00620
00621 buf << ". " + Ceylan::toString( _missedSimulationTicks )
00622 + " simulation ticks were missed, "
00623 "it sums up to an actual average simulation frequency of "
00624 << 1E6 * ( _currentSimulationTick - _missedSimulationTicks ) /
00625 static_cast<Ceylan::Float64>(
00626 ( sec - _scheduleStartingSecond ) * 1E6
00627 + microsec - _scheduleStartingMicrosecond )
00628 << " Hz" ;
00629
00630 }
00631
00632
00633 if ( _missedRenderingTicks == 0 )
00634 buf << ". No rendering tick was missed" ;
00635 else
00636 {
00637
00638 Ceylan::System::Second sec ;
00639 Ceylan::System::Microsecond microsec ;
00640 Ceylan::System::getPreciseTime( sec, microsec ) ;
00641
00642 buf << ". " + Ceylan::toString( _missedRenderingTicks )
00643 + " rendering ticks were missed, "
00644 "it sums up to an actual average rendering frequency of "
00645 << 1E6 * ( _currentRenderingTick - _missedRenderingTicks ) /
00646 static_cast<Ceylan::Float64>(
00647 ( sec - _scheduleStartingSecond ) * 1E6
00648 + microsec - _scheduleStartingMicrosecond )
00649 << " Hz" ;
00650 }
00651
00652
00653 if ( _missedInputPollingTicks == 0 )
00654 buf << ". No input tick was missed" ;
00655 else
00656 {
00657
00658 Ceylan::System::Second sec ;
00659 Ceylan::System::Microsecond microsec ;
00660 Ceylan::System::getPreciseTime( sec, microsec ) ;
00661
00662 buf << ". " + Ceylan::toString( _missedInputPollingTicks )
00663 + " input ticks were missed, "
00664 "it sums up to an actual average input frequency of "
00665 << 1E6 * ( _currentInputTick - _missedInputPollingTicks ) /
00666 static_cast<Ceylan::Float64>(
00667 ( sec - _scheduleStartingSecond ) * 1E6
00668 + microsec - _scheduleStartingMicrosecond )
00669 << " Hz" ;
00670 }
00671
00672 return buf.str() ;
00673
00674 }
00675
00676
00677
00678
00679
00680
00681 Scheduler & Scheduler::GetExistingScheduler() throw( SchedulingException )
00682 {
00683
00684 if ( Scheduler::_internalScheduler == 0 )
00685 throw SchedulingException(
00686 "Scheduler::GetExistingScheduler : no scheduler available." ) ;
00687
00688 return * Scheduler::_internalScheduler ;
00689
00690 }
00691
00692
00693 Scheduler & Scheduler::GetScheduler() throw()
00694 {
00695
00696 if ( Scheduler::_internalScheduler == 0 )
00697 {
00698
00699 LogPlug::debug( "Scheduler::GetScheduler : "
00700 "no scheduler available, creating new one" ) ;
00701
00702 Scheduler::_internalScheduler = new Scheduler() ;
00703
00704 }
00705 else
00706 {
00707 LogPlug::debug( "Scheduler::GetScheduler : "
00708 "returning already constructed instance of scheduler, "
00709 "no creation." ) ;
00710 }
00711
00712 LogPlug::debug( "Scheduler::GetScheduler : returning Scheduler instance "
00713 + Ceylan::toString( Scheduler::_internalScheduler ) ) ;
00714
00715 return * Scheduler::_internalScheduler ;
00716
00717 }
00718
00719
00720 void Scheduler::DeleteExistingScheduler() throw( SchedulingException )
00721 {
00722
00723 if ( Scheduler::_internalScheduler != 0 )
00724 throw SchedulingException( "Scheduler::DeleteExistingScheduler : "
00725 "there was no already existing scheduler." ) ;
00726
00727 #if OSDL_DEBUG_SCHEDULER
00728 LogPlug::debug(
00729 "Scheduler::DeleteExistingScheduler : effective deleting." ) ;
00730 #endif // OSDL_DEBUG_SCHEDULER
00731
00732 delete Scheduler::_internalScheduler ;
00733 Scheduler::_internalScheduler = 0 ;
00734
00735 }
00736
00737
00738 void Scheduler::DeleteScheduler() throw()
00739 {
00740
00741 if ( Scheduler::_internalScheduler != 0 )
00742 {
00743
00744 #if OSDL_DEBUG_SCHEDULER
00745 LogPlug::debug( "Scheduler::DeleteScheduler : effective deleting." ) ;
00746 #endif // OSDL_DEBUG_SCHEDULER
00747
00748 delete Scheduler::_internalScheduler ;
00749 Scheduler::_internalScheduler = 0 ;
00750 }
00751 else
00752 {
00753
00754 #if OSDL_DEBUG_SCHEDULER
00755 LogPlug::debug( "Scheduler::DeleteScheduler : no deleting needed." ) ;
00756 #endif // OSDL_DEBUG_SCHEDULER
00757
00758 }
00759
00760 }
00761
00762
00763
00764
00765
00766
00767
00768 Scheduler::Scheduler() throw() :
00769 _screenshotMode( false ),
00770 _desiredScreenshotFrequency( DefaultMovieFrameFrequency ),
00771 _screenshotPeriod( 0 ),
00772 _periodicSlots(),
00773 _programmedActivated(),
00774 _engineTickDuration( 0 ),
00775 _secondToEngineTick( 0 ),
00776 _currentEngineTick( 0 ),
00777 _currentSimulationTick( 0 ),
00778 _currentRenderingTick( 0 ),
00779 _currentInputTick( 0 ),
00780 _simulationPeriod( 0 ),
00781 _renderingPeriod( 0 ),
00782 _inputPeriod( 0 ),
00783 _desiredSimulationFrequency( DefaultSimulationFrequency ),
00784 _desiredRenderingFrequency( DefaultRenderingFrequency ),
00785 _desiredInputFrequency( DefaultInputFrequency ),
00786 _idleCallback( 0 ),
00787 _idleCallbackData( 0 ),
00788 _idleCallbackMaxDuration( 0 ),
00789 _idleCallsCount( 0 ),
00790 _stopRequested( false ),
00791 _scheduleStartingSecond( 0 ),
00792 _scheduleStartingMicrosecond( 0 ),
00793 _recoveredSimulationTicks( 0 ),
00794 _missedSimulationTicks( 0 ),
00795 _recoveredRenderingTicks( 0 ),
00796 _missedRenderingTicks( 0 ),
00797 _recoveredInputPollingTicks( 0 ),
00798 _missedInputPollingTicks( 0 ),
00799 _scheduleFailureCount( 0 ),
00800 _eventsModule( 0 ),
00801 _renderer( 0 ),
00802 _videoModule( 0 )
00803 {
00804
00805
00806 send( "On scheduler creation, "
00807 "detected operating system scheduling granularity is about "
00808 + Ceylan::toString( getSchedulingGranularity() ) + " microseconds." ) ;
00809
00810
00811 setTimeSliceDuration( DefaultEngineTickDuration ) ;
00812
00813 send( "Scheduler created." ) ;
00814
00815 }
00816
00817
00818 Scheduler::~Scheduler() throw()
00819 {
00820
00821 for ( list<PeriodicSlot *>::iterator it = _periodicSlots.begin();
00822 it != _periodicSlots.end(); it++ )
00823 delete (*it ) ;
00824
00825 if ( _renderer != 0 )
00826 delete _renderer ;
00827
00828 send( "Scheduler deleted." ) ;
00829
00830 }
00831
00832
00833 void Scheduler::scheduleBestEffort() throw( SchedulingException )
00834 {
00835
00836
00837
00838
00839
00840
00841 if ( _idleCallback == 0 && _idleCallbackMaxDuration == 0 )
00842 _idleCallbackMaxDuration =
00843 static_cast<Microsecond>( 1.1 * getSchedulingGranularity() ) ;
00844
00845 EngineTick idleCallbackDuration = static_cast<EngineTick>(
00846 Ceylan::Maths::Ceil(
00847 static_cast<Ceylan::Float32>( _idleCallbackMaxDuration ) /
00848 _engineTickDuration ) ) ;
00849
00850 _idleCallsCount = 0 ;
00851
00852 send( "Scheduler starting in soft real-time best effort mode. "
00853 "Scheduler informations : " + toString( Ceylan::low ) ) ;
00854
00855
00856
00857
00858 _stopRequested = false ;
00859
00860 _recoveredSimulationTicks = 0 ;
00861 _missedSimulationTicks = 0 ;
00862
00863 _recoveredRenderingTicks = 0 ;
00864 _missedRenderingTicks = 0 ;
00865
00866 _recoveredInputPollingTicks = 0 ;
00867 _missedInputPollingTicks = 0 ;
00868
00869
00870 #if OSDL_DEBUG_SCHEDULER
00871
00872
00873
00874
00875
00876
00877
00878
00879 list<SimulationTick> metSimulations ;
00880 list<SimulationTick> recoveredSimulations ;
00881 list<SimulationTick> missedSimulations ;
00882
00883 list<RenderingTick> metRenderings ;
00884 list<RenderingTick> recoveredRenderings ;
00885 list<RenderingTick> missedRenderings ;
00886
00887 list<InputTick> metInputPollings ;
00888 list<InputTick> recoveredInputPollings ;
00889 list<InputTick> missedInputPollings ;
00890
00891 #endif // OSDL_DEBUG_SCHEDULER
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
00905
00906
00907
00908
00909
00910
00911
00912 _currentEngineTick = computeEngineTickFromCurrentTime() ;
00913
00914 _currentSimulationTick = _currentEngineTick / _simulationPeriod ;
00915 _currentRenderingTick = _currentEngineTick / _renderingPeriod;
00916 _currentInputTick = _currentEngineTick / _inputPeriod;
00917
00918 OSDL_SCHEDULE_LOG( "Simulation period : " << _simulationPeriod ) ;
00919 OSDL_SCHEDULE_LOG( "Rendering period : " << _renderingPeriod ) ;
00920 OSDL_SCHEDULE_LOG( "Input period : " << _inputPeriod ) ;
00921
00922 EngineTick nextSimulationDeadline = _currentEngineTick + _simulationPeriod ;
00923 EngineTick nextRenderingDeadline = _currentEngineTick + _renderingPeriod ;
00924 EngineTick nextInputDeadline = _currentEngineTick + _inputPeriod ;
00925
00926 EngineTick nextDeadline = Ceylan::Maths::Min( nextSimulationDeadline,
00927 nextRenderingDeadline, nextInputDeadline ) ;
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960 Delay delayBucket = 0 ;
00961
00962
00963 Delay maxDelayBucket = 0 ;
00964
00965
00966
00967
00968
00969
00970 Delay delayCumulativeBucket = 0 ;
00971
00972
00973 const Delay bucketFillThreshold = 750 ;
00974
00975
00976
00977
00978
00979
00980 const Ceylan::Float32 bucketLeakingFactor = 0.9 ;
00981
00982 _scheduleFailureCount = 0 ;
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 const Microsecond simulationToleranceTime = 50000 ;
00999
01000 const EngineTick simulationToleranceTick = static_cast<EngineTick>(
01001 simulationToleranceTime / _engineTickDuration ) ;
01002
01003 send( "Simulation tolerance time is "
01004 + Ceylan::toString( simulationToleranceTime ) + " microseconds, i.e. "
01005 + Ceylan::toString( simulationToleranceTick ) + " engine ticks." ) ;
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 const EngineTick renderingToleranceTick = _renderingPeriod / 4 ;
01029
01030 send( "Rendering tolerance is "
01031 + Ceylan::toString( renderingToleranceTick )
01032 + " engine ticks, which translates into a tolerance of "
01033 + Ceylan::toString( renderingToleranceTick * _engineTickDuration )
01034 + " microseconds." ) ;
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057 const EngineTick inputToleranceTick = _inputPeriod / 2 ;
01058
01059 send( "Input polling tolerance is "
01060 + Ceylan::toString( inputToleranceTick )
01061 + " engine ticks, which translates into a tolerance of "
01062 + Ceylan::toString( inputToleranceTick * _engineTickDuration )
01063 + " microseconds." ) ;
01064
01065
01066
01067 getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
01068
01069
01070
01071
01072 while ( ! _stopRequested )
01073 {
01074
01075
01076 OSDL_SCHEDULE_LOG( "[ E : " << _currentEngineTick
01077 << " ; S : " << _currentSimulationTick
01078 << " ; R : " << _currentRenderingTick
01079 << " ; I : " << _currentInputTick
01080 << " ; B : " << delayBucket << " ]" ) ;
01081
01082
01083 #if OSDL_DEBUG_SCHEDULER
01084
01085
01086 if ( _currentEngineTick % 1000 == 0 )
01087 LogPlug::debug( "[ E : " + Ceylan::toString( _currentEngineTick )
01088 + " ; S : " + Ceylan::toString( _currentSimulationTick )
01089 + " ; R : " + Ceylan::toString( _currentRenderingTick )
01090 + " ; I : " + Ceylan::toString( _currentInputTick )
01091 + " ; B : " + Ceylan::toString( delayBucket )
01092 + " ]" ) ;
01093
01094 #endif // OSDL_DEBUG_SCHEDULER
01095
01096
01097 delayCumulativeBucket += delayBucket ;
01098
01099
01100 delayBucket = static_cast<Delay>( delayBucket * bucketLeakingFactor ) ;
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121 if ( _currentEngineTick == nextSimulationDeadline )
01122 {
01123
01124
01125
01126 #if OSDL_DEBUG_SCHEDULER
01127 metSimulations.push_back( _currentSimulationTick ) ;
01128 #endif // OSDL_DEBUG_SCHEDULER
01129
01130 scheduleSimulation( _currentSimulationTick ) ;
01131
01132 _currentSimulationTick++ ;
01133 nextSimulationDeadline += _simulationPeriod ;
01134
01135 }
01136
01137
01138
01139 if ( _currentEngineTick == nextRenderingDeadline )
01140 {
01141
01142
01143
01144 #if OSDL_DEBUG_SCHEDULER
01145 metRenderings.push_back( _currentRenderingTick ) ;
01146 #endif // OSDL_DEBUG_SCHEDULER
01147
01148 scheduleRendering( _currentRenderingTick ) ;
01149
01150 _currentRenderingTick++ ;
01151 nextRenderingDeadline += _renderingPeriod ;
01152
01153 }
01154
01155
01156
01157 if ( _currentEngineTick == nextInputDeadline )
01158 {
01159
01160
01161
01162 #if OSDL_DEBUG_SCHEDULER
01163 metInputPollings.push_back( _currentInputTick ) ;
01164 #endif // OSDL_DEBUG_SCHEDULER
01165
01166 scheduleInput( _currentInputTick ) ;
01167
01168 _currentInputTick++ ;
01169 nextInputDeadline += _inputPeriod ;
01170
01171 }
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01193
01194 while ( nextSimulationDeadline < _currentEngineTick + 1 )
01195 {
01196
01197
01198 EngineTick missedTicks =
01199 _currentEngineTick + 1 - nextSimulationDeadline ;
01200
01201 if ( missedTicks > simulationToleranceTick )
01202 {
01203
01204 OSDL_SCHEDULE_LOG( "##### Simulation deadline missed of "
01205 + Ceylan::toString( missedTicks )
01206 + " engine ticks ("
01207 + Ceylan::toString( missedTicks * _engineTickDuration )
01208 + " microseconds), cancelling activations." ) ;
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234 delayBucket += 20 * static_cast<Delay>(
01235 Ceylan::Maths::Log( 2.0f * missedTicks ) ) ;
01236
01237 #if OSDL_DEBUG_SCHEDULER
01238 missedSimulations.push_back( _currentSimulationTick ) ;
01239 #endif // OSDL_DEBUG_SCHEDULER
01240
01241
01242
01243
01244
01245
01246
01247 onSimulationSkipped( _currentSimulationTick ) ;
01248
01249
01250 }
01251 else
01252 {
01253
01254
01255 _recoveredSimulationTicks++ ;
01256
01257
01258 missedTicks-- ;
01259
01260 OSDL_SCHEDULE_LOG( "@@@@@ Simulation deadline recovered from "
01261 + Ceylan::toString( missedTicks )
01262 + " engine ticks delay ("
01263 + Ceylan::toString( missedTicks * _engineTickDuration )
01264 + " microseconds)." ) ;
01265
01266
01267 delayBucket += 8 ;
01268
01269 #if OSDL_DEBUG_SCHEDULER
01270 recoveredSimulations.push_back( _currentSimulationTick ) ;
01271 #endif // OSDL_DEBUG_SCHEDULER
01272
01273 scheduleSimulation( _currentSimulationTick ) ;
01274
01275 }
01276
01277 _currentSimulationTick++ ;
01278
01279 nextSimulationDeadline += _simulationPeriod ;
01280
01281 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01282
01283 }
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297 while ( nextRenderingDeadline < _currentEngineTick + 1 )
01298 {
01299
01300
01301 EngineTick missedTicks =
01302 _currentEngineTick + 1 - nextRenderingDeadline ;
01303
01304 if ( missedTicks > renderingToleranceTick )
01305 {
01306
01307 OSDL_SCHEDULE_LOG( "##### Rendering deadline missed of "
01308 + Ceylan::toString( missedTicks )
01309 + " engine ticks ("
01310 + Ceylan::toString( missedTicks * _engineTickDuration )
01311 + " microseconds), cancelling rendering." ) ;
01312
01313
01314 delayBucket += 2 * static_cast<Delay>(
01315 Ceylan::Maths::Log( 2.0f * missedTicks ) ) ;
01316
01317
01318 #if OSDL_DEBUG_SCHEDULER
01319 missedRenderings.push_back( _currentRenderingTick ) ;
01320 #endif // OSDL_DEBUG_SCHEDULER
01321
01322 onRenderingSkipped( _currentRenderingTick ) ;
01323
01324 }
01325 else
01326 {
01327
01328
01329 _recoveredRenderingTicks++ ;
01330
01331
01332 missedTicks-- ;
01333
01334 OSDL_SCHEDULE_LOG( "@@@@@ Rendering deadline recovered from "
01335 + Ceylan::toString( missedTicks )
01336 + " engine ticks delay ("
01337 + Ceylan::toString( missedTicks * _engineTickDuration )
01338 + " microseconds)." ) ;
01339
01340
01341 delayBucket += 4 ;
01342
01343 #if OSDL_DEBUG_SCHEDULER
01344 recoveredRenderings.push_back( _currentRenderingTick ) ;
01345 #endif // OSDL_DEBUG_SCHEDULER
01346
01347 scheduleRendering( _currentRenderingTick ) ;
01348
01349 }
01350
01351 _currentRenderingTick++ ;
01352
01353 nextRenderingDeadline += _renderingPeriod ;
01354
01355 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01356
01357 }
01358
01359
01360
01361
01362
01363
01364 while ( nextInputDeadline < _currentEngineTick + 1 )
01365 {
01366
01367
01368
01369
01370
01371
01372 EngineTick missedTicks =
01373 _currentEngineTick + 1 - nextInputDeadline ;
01374
01375 if ( missedTicks > inputToleranceTick )
01376 {
01377
01378 OSDL_SCHEDULE_LOG( "##### Input deadline missed of "
01379 + Ceylan::toString( missedTicks )
01380 + " engine ticks ("
01381 + Ceylan::toString( missedTicks * _engineTickDuration )
01382 + " microseconds), cancelling input polling." ) ;
01383
01384
01385 delayBucket += static_cast<Delay>(
01386 Ceylan::Maths::Log( 2.0f * missedTicks ) ) ;
01387
01388 #if OSDL_DEBUG_SCHEDULER
01389 missedInputPollings.push_back( _currentInputTick ) ;
01390 #endif // OSDL_DEBUG_SCHEDULER
01391
01392 onInputSkipped( _currentInputTick ) ;
01393
01394 }
01395 else
01396 {
01397
01398
01399 _recoveredInputPollingTicks++ ;
01400
01401
01402 missedTicks-- ;
01403
01404 OSDL_SCHEDULE_LOG( "@@@@@ Input deadline recovered from "
01405 + Ceylan::toString( missedTicks )
01406 + " engine ticks delay ("
01407 + Ceylan::toString( missedTicks * _engineTickDuration )
01408 + " microseconds)." ) ;
01409
01410
01411 delayBucket += 2 ;
01412
01413 #if OSDL_DEBUG_SCHEDULER
01414 recoveredInputPollings.push_back( _currentInputTick ) ;
01415 #endif // OSDL_DEBUG_SCHEDULER
01416
01417 scheduleInput( _currentInputTick ) ;
01418
01419
01420 }
01421
01422 _currentInputTick++ ;
01423
01424 nextInputDeadline += _inputPeriod ;
01425
01426 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01427
01428 }
01429
01430 if ( maxDelayBucket < delayBucket )
01431 maxDelayBucket = delayBucket ;
01432
01433
01434 if ( delayBucket > bucketFillThreshold )
01435 onScheduleFailure( delayBucket ) ;
01436
01437
01438
01439
01440
01441
01442 nextDeadline = Ceylan::Maths::Min( nextSimulationDeadline,
01443 nextRenderingDeadline, nextInputDeadline ) ;
01444
01445 if ( nextDeadline < _currentEngineTick )
01446 {
01447
01448 string message = "We are at engine tick #"
01449 + Ceylan::toString( _currentEngineTick )
01450 + ", already late for next deadline, which is at "
01451 + Ceylan::toString( nextDeadline ) + "." ;
01452
01453 OSDL_SCHEDULE_LOG( message ) ;
01454 LogPlug::warning( message ) ;
01455
01456
01457 continue ;
01458 }
01459 else if ( nextDeadline <= _currentEngineTick + 1 )
01460 {
01461
01462
01463
01464
01465
01466
01467
01468 OSDL_SCHEDULE_LOG(
01469 "No jump could be performed, just continuing." ) ;
01470
01471 }
01472 else
01473 {
01474
01475
01476
01477
01478
01479
01480 EngineTick jumpLength = nextDeadline - _currentEngineTick - 1 ;
01481
01482 OSDL_SCHEDULE_LOG( "Next deadline is "
01483 + Ceylan::toString( jumpLength + 1 )
01484 + " engine tick(s) away." ) ;
01485
01486
01487
01488 while ( jumpLength > 0 )
01489 {
01490
01491 delayBucket = static_cast<Delay>(
01492 delayBucket * bucketLeakingFactor ) ;
01493 delayCumulativeBucket += delayBucket ;
01494 jumpLength-- ;
01495
01496 } ;
01497
01498 }
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508 while ( _currentEngineTick + idleCallbackDuration < nextDeadline )
01509 {
01510
01511
01512
01513
01514
01515
01516 onIdle() ;
01517
01518 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01519
01520 }
01521
01522
01523
01524 while ( _currentEngineTick < nextDeadline )
01525 _currentEngineTick = computeEngineTickFromCurrentTime() ;
01526
01527
01528
01529
01530
01531
01532
01533
01534 }
01535
01536
01537 Second scheduleStoppingSecond ;
01538 Microsecond scheduleStoppingMicrosecond ;
01539
01540 getPreciseTime( scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
01541
01542
01543 Ceylan::Float64 totalRuntimeFactor ;
01544
01545
01546 if ( scheduleStoppingSecond - _scheduleStartingSecond <
01547 MaximumDurationWithMicrosecondAccuracy )
01548 {
01549
01550 totalRuntimeFactor = 1E6 / getDurationBetween(
01551 _scheduleStartingSecond, _scheduleStartingMicrosecond,
01552 scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
01553
01554 }
01555 else
01556 {
01557
01558
01559 totalRuntimeFactor = 1.0f /
01560 ( scheduleStoppingSecond - _scheduleStartingSecond ) ;
01561
01562 }
01563
01564
01565 string table =
01566 "<table border=1>"
01567 " <tr>"
01568 " <th>Tick types</th>"
01569 " <th>Requested frequency</th>"
01570 " <th>Agreed frequency</th>"
01571 " <th>Measured frequency</th>"
01572 " <th>Tick duration (microsec)</th>"
01573 " <th>Tick duration (engine ticks)</th>"
01574 " <th>Stopped at tick</th>"
01575 " <th>Recovered count</th>"
01576 " <th>Recovered percentage</th>"
01577 " <th>Missed count</th>"
01578 " <th>Missed percentage</th>"
01579 " </tr>" ;
01580
01581
01582 Ceylan::Uint8 precision = 2 ;
01583
01584
01585 table +=
01586 " <tr>"
01587 " <td>Engine tick</td>"
01588 " <td>"
01589 + Ceylan::toString( 1E6 / DefaultEngineTickDuration, precision )
01590 + " Hz</td>"
01591 " <td>"
01592 + Ceylan::toString( 1E6 / DefaultEngineTickDuration, precision )
01593 + " Hz</td>"
01594 " <td>"
01595 + Ceylan::toString( _currentEngineTick * totalRuntimeFactor,
01596 precision )
01597 + " Hz</td>"
01598 " <td>" + Ceylan::toString( _engineTickDuration ) + "</td>"
01599 " <td>1</td>"
01600 " <td>" + Ceylan::toString( _currentEngineTick ) + "</td>"
01601 " <td>N/A</td>"
01602 " <td>N/A</td>"
01603 " <td>N/A</td>"
01604 " <td>N/A</td>"
01605 " </tr>" ;
01606
01607
01608
01609 table +=
01610 " <tr>"
01611 " <td>Simulation tick</td>"
01612 " <td>"
01613 + Ceylan::toString( _desiredSimulationFrequency )
01614 + " Hz</td>"
01615 " <td>"
01616 + Ceylan::toString( 1E6 / ( _simulationPeriod * _engineTickDuration ),
01617 precision ) + " Hz</td>"
01618 " <td>"
01619 + Ceylan::toString(
01620 ( _currentSimulationTick - _missedSimulationTicks ) *
01621 totalRuntimeFactor, precision ) + " Hz</td>"
01622 " <td>" + Ceylan::toString(
01623 _simulationPeriod * _engineTickDuration ) + "</td>"
01624 " <td>" + Ceylan::toString( _simulationPeriod ) + "</td>"
01625 " <td>" + Ceylan::toString( _currentSimulationTick ) + "</td>"
01626 " <td>" + Ceylan::toString( _recoveredSimulationTicks ) + "</td>"
01627 " <td>" + Ceylan::toString(
01628 100.0f * _recoveredSimulationTicks / _currentSimulationTick,
01629 precision )
01630 + "%</td>"
01631 " <td>" + Ceylan::toString( _missedSimulationTicks ) + "</td>"
01632 " <td>" + Ceylan::toString(
01633 100.0f * _missedSimulationTicks / _currentSimulationTick,
01634 precision )
01635 + "%</td>"
01636 " </tr>" ;
01637
01638
01639
01640 table +=
01641 " <tr>"
01642 " <td>Rendering tick</td>"
01643 " <td>"
01644 + Ceylan::toString( _desiredRenderingFrequency )
01645 + " Hz</td>"
01646 " <td>"
01647 + Ceylan::toString( 1E6 / ( _renderingPeriod * _engineTickDuration ),
01648 precision ) + " Hz</td>"
01649 " <td>"
01650 + Ceylan::toString(
01651 ( _currentRenderingTick - _missedRenderingTicks ) *
01652 totalRuntimeFactor, precision ) + " Hz</td>"
01653 " <td>" + Ceylan::toString(
01654 _renderingPeriod * _engineTickDuration ) + "</td>"
01655 " <td>" + Ceylan::toString( _renderingPeriod ) + "</td>"
01656 " <td>" + Ceylan::toString( _currentRenderingTick ) + "</td>"
01657 " <td>" + Ceylan::toString( _recoveredRenderingTicks ) + "</td>"
01658 " <td>" + Ceylan::toString(
01659 100.0f * _recoveredRenderingTicks / _currentRenderingTick,
01660 precision )
01661 + "%</td>"
01662 " <td>" + Ceylan::toString( _missedRenderingTicks ) + "</td>"
01663 " <td>" + Ceylan::toString(
01664 100.0f * _missedRenderingTicks / _currentRenderingTick, precision )
01665 + "%</td>"
01666 " </tr>" ;
01667
01668
01669 table +=
01670 " <tr>"
01671 " <td>Input polling tick</td>"
01672 " <td>"
01673 + Ceylan::toString( _desiredInputFrequency )
01674 + " Hz</td>"
01675 " <td>"
01676 + Ceylan::toString( 1E6 / ( _inputPeriod * _engineTickDuration ),
01677 precision ) + " Hz</td>"
01678 " <td>"
01679 + Ceylan::toString(
01680 ( _currentInputTick - _missedInputPollingTicks ) *
01681 totalRuntimeFactor, precision ) + " Hz</td>"
01682 " <td>" + Ceylan::toString(
01683 _inputPeriod * _engineTickDuration ) + "</td>"
01684 " <td>" + Ceylan::toString( _inputPeriod ) + "</td>"
01685 " <td>" + Ceylan::toString( _currentInputTick ) + "</td>"
01686 " <td>" + Ceylan::toString( _recoveredInputPollingTicks )
01687 + "</td>"
01688 " <td>" + Ceylan::toString(
01689 100.0f * _recoveredInputPollingTicks / _currentInputTick,
01690 precision )
01691 + "%</td>"
01692 " <td>" + Ceylan::toString( _missedInputPollingTicks ) + "</td>"
01693 " <td>" + Ceylan::toString(
01694 100.0f * _missedInputPollingTicks / _currentInputTick, precision )
01695 + "%</td>"
01696 " </tr>" ;
01697
01698 table += "</table>" ;
01699
01700 if ( Ceylan::TextDisplayable::GetOutputFormat() ==
01701 Ceylan::TextDisplayable::html )
01702 send( table ) ;
01703
01704 list<string> summary ;
01705
01706 string durationComment = "The scheduler ran for "
01707 + Ceylan::Timestamp::DescribeDuration(
01708 scheduleStoppingSecond - _scheduleStartingSecond ) ;
01709
01710
01711 if ( scheduleStoppingSecond - _scheduleStartingSecond <
01712 MaximumDurationWithMicrosecondAccuracy )
01713 durationComment += ", more precisely "
01714 + Ceylan::toString( getDurationBetween(
01715 _scheduleStartingSecond, _scheduleStartingMicrosecond,
01716 scheduleStoppingSecond, scheduleStoppingMicrosecond ) )
01717 + " microseconds." ;
01718 else
01719 durationComment += "." ;
01720
01721 summary.push_back( durationComment ) ;
01722
01723 summary.push_back( Ceylan::toString( _idleCallsCount )
01724 + " idle calls have been made." ) ;
01725
01726 summary.push_back( "Each idle call was expected to last for "
01727 + Ceylan::toString( _idleCallbackMaxDuration ) + " microseconds, i.e. "
01728 + Ceylan::toString( idleCallbackDuration ) + " engine ticks." ) ;
01729
01730 summary.push_back( "Average bucket level has been "
01731 + Ceylan::toString(
01732 ( 1.0f * delayCumulativeBucket ) / _currentEngineTick,
01733 2 )
01734 + ", maximum bucket level has been "
01735 + Ceylan::toString( maxDelayBucket )
01736 + ", bucket fill threshold is "
01737 + Ceylan::toString( bucketFillThreshold )
01738 + ", this threshold has been reached "
01739 + Ceylan::toString( _scheduleFailureCount )
01740 + " times, shutdown bucket level is "
01741 + Ceylan::toString( ShutdownBucketLevel) + "." ) ;
01742
01743 send( "Scheduler stopping, run summary is : "
01744 + Ceylan::formatStringList( summary ) ) ;
01745
01746 send( "Full scheduler infos : " + toString( Ceylan::high ) ) ;
01747
01748 _scheduleStartingSecond = 0 ;
01749 _scheduleStartingMicrosecond = 0 ;
01750
01751
01752 #if OSDL_DEBUG_SCHEDULER
01753
01754
01755
01756
01757
01758
01759
01760 bool beVerbose = true ;
01761 bool beVeryVerbose = true ;
01762
01763
01764
01765
01766
01767 SimulationTick totalSimulationTicks = metSimulations.size()
01768 + recoveredSimulations.size() + missedSimulations.size() ;
01769
01770 LogPlug::debug( "Total simulation ticks : "
01771 + Ceylan::toString( totalSimulationTicks ) + "." ) ;
01772
01773 LogPlug::debug( "Directly met simulation ticks : "
01774 + Ceylan::toString( metSimulations.size() )
01775 + " (" + Ceylan::toString( 100.0f * metSimulations.size()
01776 / totalSimulationTicks, 2 ) + "%)." ) ;
01777
01778 LogPlug::debug( "Recovered (indirectly met) simulation ticks : "
01779 + Ceylan::toString( recoveredSimulations.size() )
01780 + " (" + Ceylan::toString( 100.0f * recoveredSimulations.size()
01781 / totalSimulationTicks, 2 ) + "%)." ) ;
01782
01783 if ( recoveredSimulations.size() != _recoveredSimulationTicks )
01784 LogPlug::error( "Inconsistency in recovered simulation count." ) ;
01785
01786
01787 LogPlug::debug( "Missed simulation ticks : "
01788 + Ceylan::toString( missedSimulations.size() )
01789 + " (" + Ceylan::toString( 100.0f * missedSimulations.size()
01790 / totalSimulationTicks, 2 ) + "%)." ) ;
01791
01792 if ( missedSimulations.size() != _missedSimulationTicks )
01793 LogPlug::error( "Inconsistency in missed simulation count." ) ;
01794
01795 if ( _currentSimulationTick - _recoveredSimulationTicks
01796 - _missedSimulationTicks != metSimulations.size() )
01797 LogPlug::error( "Inconsistency in overall simulation count." ) ;
01798
01799
01800 string res ;
01801
01802
01803 if ( beVerbose )
01804 {
01805
01806 if ( beVeryVerbose )
01807 {
01808
01809 for ( list<SimulationTick>::const_iterator it
01810 = metSimulations.begin(); it != metSimulations.end(); it++ )
01811 res += Ceylan::toString( *it ) + " - " ;
01812
01813 LogPlug::debug( "Met simulation ticks : " + res ) ;
01814 res.clear() ;
01815
01816 }
01817
01818
01819 for ( list<SimulationTick>::const_iterator it
01820 = recoveredSimulations.begin();
01821 it != recoveredSimulations.end(); it++ )
01822 res += Ceylan::toString( *it ) + " - " ;
01823
01824 LogPlug::debug( "Recovered simulation ticks : " + res ) ;
01825 res.clear() ;
01826
01827 for ( list<SimulationTick>::const_iterator it
01828 = missedSimulations.begin(); it != missedSimulations.end();
01829 it++ )
01830 res += Ceylan::toString( *it ) + " - " ;
01831
01832 LogPlug::debug( "Missed simulation ticks : " + res ) ;
01833 res.clear() ;
01834 }
01835
01836
01837
01838
01839
01840
01841
01842 SimulationTick newSimulationTick ;
01843
01844 bool * simulationTicks = new bool[ _currentSimulationTick ] ;
01845
01846 for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
01847 simulationTicks[i] = false ;
01848
01849 for ( list<SimulationTick>::const_iterator it = metSimulations.begin();
01850 it != metSimulations.end(); it++ )
01851 {
01852
01853 newSimulationTick = (*it) ;
01854
01855 if ( simulationTicks[ newSimulationTick ] == false )
01856 simulationTicks[ newSimulationTick ] = true ;
01857 else
01858 LogPlug::error( "Met simulation tick #"
01859 + Ceylan::toString( newSimulationTick )
01860 + " should not have been scheduled more than once." ) ;
01861
01862 }
01863
01864
01865 for ( list<SimulationTick>::const_iterator it =
01866 recoveredSimulations.begin(); it != recoveredSimulations.end(); it++ )
01867 {
01868
01869 newSimulationTick = (*it) ;
01870
01871 if ( simulationTicks[ newSimulationTick ] == false )
01872 simulationTicks[ newSimulationTick ] = true ;
01873 else
01874 LogPlug::error( "Recovered simulation tick #"
01875 + Ceylan::toString( newSimulationTick )
01876 + " should not have been scheduled more than once." ) ;
01877
01878 }
01879
01880
01881 for ( list<SimulationTick>::const_iterator it = missedSimulations.begin();
01882 it != missedSimulations.end(); it++ )
01883 {
01884
01885 newSimulationTick = (*it) ;
01886
01887 if ( simulationTicks[ newSimulationTick ] == false )
01888 simulationTicks[ newSimulationTick ] = true ;
01889 else
01890 LogPlug::error( "Missed simulation tick #"
01891 + Ceylan::toString( newSimulationTick )
01892 + " should not have been skipped, "
01893 "since had already been taken into account." ) ;
01894
01895 }
01896
01897 for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
01898 if ( simulationTicks[ i ] == false )
01899 LogPlug::error( "Simulation tick #" + Ceylan::toString( i )
01900 + " has never been scheduled." ) ;
01901
01902 delete simulationTicks ;
01903
01904
01905
01906
01907
01908 RenderingTick totalRenderingTicks = metRenderings.size()
01909 + recoveredRenderings.size() + missedRenderings.size() ;
01910
01911 LogPlug::debug( "Total rendering ticks : "
01912 + Ceylan::toString( totalRenderingTicks ) + "." ) ;
01913
01914 LogPlug::debug( "Directly met rendering ticks : "
01915 + Ceylan::toString( metRenderings.size() )
01916 + " (" + Ceylan::toString( 100.0f * metRenderings.size()
01917 / totalRenderingTicks, 2 ) + "%)." ) ;
01918
01919 LogPlug::debug( "Recovered (indirectly met) rendering ticks : "
01920 + Ceylan::toString( recoveredRenderings.size() )
01921 + " (" + Ceylan::toString( 100.0f * recoveredRenderings.size()
01922 / totalRenderingTicks, 2 ) + "%)." ) ;
01923
01924 if ( recoveredRenderings.size() != _recoveredRenderingTicks )
01925 LogPlug::error( "Inconsistency in recovered rendering count." ) ;
01926
01927
01928 LogPlug::debug( "Missed rendering ticks : "
01929 + Ceylan::toString( missedRenderings.size() )
01930 + " (" + Ceylan::toString( 100.0f * missedRenderings.size()
01931 / totalRenderingTicks, 2 ) + "%)." ) ;
01932
01933 if ( missedRenderings.size() != _missedRenderingTicks )
01934 LogPlug::error( "Inconsistency in missed rendering count." ) ;
01935
01936 if ( _currentRenderingTick - _recoveredRenderingTicks
01937 - _missedRenderingTicks != metRenderings.size() )
01938 LogPlug::error( "Inconsistency in overall rendering count." ) ;
01939
01940
01941
01942 if ( beVerbose )
01943 {
01944
01945 if ( beVeryVerbose )
01946 {
01947
01948 for ( list<RenderingTick>::const_iterator it
01949 = metRenderings.begin(); it != metRenderings.end(); it++ )
01950 res += Ceylan::toString( *it ) + " - " ;
01951
01952 LogPlug::debug( "Met rendering ticks : " + res ) ;
01953 res.clear() ;
01954
01955 }
01956
01957 for ( list<RenderingTick>::const_iterator it
01958 = recoveredRenderings.begin();
01959 it != recoveredRenderings.end(); it++ )
01960 res += Ceylan::toString( *it ) + " - " ;
01961
01962 LogPlug::debug( "Recovered rendering ticks : " + res ) ;
01963 res.clear() ;
01964
01965 for ( list<RenderingTick>::const_iterator it
01966 = missedRenderings.begin(); it != missedRenderings.end(); it++ )
01967 res += Ceylan::toString( *it ) + " - " ;
01968
01969 LogPlug::debug( "Missed rendering ticks : " + res ) ;
01970 res.clear() ;
01971
01972 }
01973
01974
01975
01976
01977
01978
01979
01980
01981 RenderingTick newRenderingTick ;
01982
01983 bool * renderingTicks = new bool[ _currentRenderingTick ] ;
01984
01985 for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
01986 renderingTicks[i] = false ;
01987
01988 for ( list<RenderingTick>::const_iterator it = metRenderings.begin();
01989 it != metRenderings.end(); it++ )
01990 {
01991
01992 newRenderingTick = (*it) ;
01993 if ( renderingTicks[ newRenderingTick ] == false )
01994 renderingTicks[ newRenderingTick ] = true ;
01995 else
01996 LogPlug::error( "Met rendering tick #"
01997 + Ceylan::toString( newRenderingTick )
01998 + " should not have been scheduled more than once." ) ;
01999
02000 }
02001
02002 for ( list<RenderingTick>::const_iterator it =
02003 recoveredRenderings.begin(); it != recoveredRenderings.end(); it++ )
02004 {
02005
02006 newRenderingTick = (*it) ;
02007 if ( renderingTicks[ newRenderingTick ] == false )
02008 renderingTicks[ newRenderingTick ] = true ;
02009 else
02010 LogPlug::error( "Recovered rendering tick #"
02011 + Ceylan::toString( newRenderingTick )
02012 + " should not have been scheduled more than once." ) ;
02013
02014 }
02015
02016
02017 for ( list<RenderingTick>::const_iterator it = missedRenderings.begin();
02018 it != missedRenderings.end(); it++ )
02019 {
02020 newRenderingTick = (*it) ;
02021 if ( renderingTicks[ newRenderingTick ] == false )
02022 renderingTicks[ newRenderingTick ] = true ;
02023 else
02024 LogPlug::error( "Missed rendering tick #"
02025 + Ceylan::toString( newRenderingTick )
02026 + " should not have been been skipped, "
02027 "since had already been taken into account." ) ;
02028
02029 }
02030
02031 for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
02032 if ( renderingTicks[ i ] == false )
02033 LogPlug::error( "Rendering tick #" + Ceylan::toString( i )
02034 + " has never been scheduled." ) ;
02035
02036 delete renderingTicks ;
02037
02038
02039
02040
02041
02042
02043 InputTick totalInputTicks = metInputPollings.size()
02044 + recoveredInputPollings.size() + missedInputPollings.size() ;
02045
02046 LogPlug::debug( "Total input ticks : "
02047 + Ceylan::toString( totalInputTicks ) + "." ) ;
02048
02049 LogPlug::debug( "Directly met input ticks : "
02050 + Ceylan::toString( metInputPollings.size() )
02051 + " (" + Ceylan::toString( 100.0f * metInputPollings.size()
02052 / totalInputTicks, 2 ) + "%)." ) ;
02053
02054 LogPlug::debug( "Recovered (indirectly met) input ticks : "
02055 + Ceylan::toString( recoveredInputPollings.size() )
02056 + " (" + Ceylan::toString( 100.0f * recoveredInputPollings.size()
02057 / totalInputTicks, 2 ) + "%)." ) ;
02058
02059 if ( recoveredInputPollings.size() != _recoveredInputPollingTicks )
02060 LogPlug::error( "Inconsistency in recovered input polling count." ) ;
02061
02062
02063 LogPlug::debug( "Missed input ticks : "
02064 + Ceylan::toString( missedInputPollings.size() )
02065 + " (" + Ceylan::toString( 100.0f * missedInputPollings.size()
02066 / totalInputTicks, 2 ) + "%)." ) ;
02067
02068 if ( missedInputPollings.size() != _missedInputPollingTicks )
02069 LogPlug::error( "Inconsistency in missed input polling count." ) ;
02070
02071 if ( _currentInputTick - _recoveredInputPollingTicks
02072 - _missedInputPollingTicks != metInputPollings.size() )
02073 LogPlug::error( "Inconsistency in overall input polling count." ) ;
02074
02075
02076 if ( beVerbose )
02077 {
02078
02079 if ( beVeryVerbose )
02080 {
02081
02082 for ( list<InputTick>::const_iterator it
02083 = metInputPollings.begin();
02084 it != metInputPollings.end(); it++ )
02085 res += Ceylan::toString( *it ) + " - " ;
02086
02087 LogPlug::debug( "Met input ticks : " + res ) ;
02088 res.clear() ;
02089
02090 }
02091
02092 for ( list<InputTick>::const_iterator it
02093 = recoveredInputPollings.begin();
02094 it != recoveredInputPollings.end(); it++ )
02095 res += Ceylan::toString( *it ) + " - " ;
02096
02097 LogPlug::debug( "Recovered input ticks : " + res ) ;
02098 res.clear() ;
02099
02100 for ( list<InputTick>::const_iterator it
02101 = missedInputPollings.begin();
02102 it != missedInputPollings.end(); it++ )
02103 res += Ceylan::toString( *it ) + " - " ;
02104
02105 LogPlug::debug( "Missed input ticks : " + res ) ;
02106 res.clear() ;
02107
02108 }
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118 InputTick newInputTick ;
02119
02120 bool * inputTicks = new bool[ _currentInputTick ] ;
02121
02122 for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
02123 inputTicks[i] = false ;
02124
02125 for ( list<InputTick>::const_iterator it = metInputPollings.begin();
02126 it != metInputPollings.end(); it++ )
02127 {
02128
02129 newInputTick = (*it) ;
02130 if ( inputTicks[ newInputTick ] == false )
02131 inputTicks[ newInputTick ] = true ;
02132 else
02133 LogPlug::error( "Met input tick #"
02134 + Ceylan::toString( newInputTick )
02135 + " should not have been scheduled more than once." ) ;
02136
02137 }
02138
02139 for ( list<InputTick>::const_iterator it = recoveredInputPollings.begin();
02140 it != recoveredInputPollings.end(); it++ )
02141 {
02142
02143 newInputTick = (*it) ;
02144 if ( inputTicks[ newInputTick ] == false )
02145 inputTicks[ newInputTick ] = true ;
02146 else
02147 LogPlug::error( "Recovered input tick #"
02148 + Ceylan::toString( newInputTick )
02149 + " should not have been scheduled more than once." ) ;
02150
02151 }
02152
02153
02154 for ( list<InputTick>::const_iterator it = missedInputPollings.begin();
02155 it != missedInputPollings.end(); it++ )
02156 {
02157 newInputTick = (*it) ;
02158 if ( inputTicks[ newInputTick ] == false )
02159 inputTicks[ newInputTick ] = true ;
02160 else
02161 LogPlug::error( "Missed input tick #"
02162 + Ceylan::toString( newInputTick )
02163 + " should not have been been skipped, "
02164 "since had already been taken into account." ) ;
02165
02166 }
02167
02168 for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
02169 if ( inputTicks[ i ] == false )
02170 LogPlug::error( "Input tick #" + Ceylan::toString( i )
02171 + " has never been scheduled." ) ;
02172
02173 delete inputTicks ;
02174
02175 #endif // OSDL_DEBUG_SCHEDULER
02176
02177 }
02178
02179
02180
02181
02182
02183
02184
02185 void Scheduler::scheduleNoDeadline( bool pollInputs )
02186 throw( SchedulingException )
02187 {
02188
02189
02190
02191 _stopRequested = false ;
02192
02193 #if OSDL_DEBUG_SCHEDULER
02194
02195
02196
02197
02198
02199
02200
02201
02202 list<SimulationTick> metSimulations ;
02203 list<RenderingTick> metRenderings ;
02204 list<InputTick> metInputPollings ;
02205
02206 #endif // OSDL_DEBUG_SCHEDULER
02207
02208
02209
02210 getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
02211
02212
02213 _currentEngineTick = 0 ;
02214
02215 _currentSimulationTick = 0 ;
02216 _currentRenderingTick = 0 ;
02217 _currentInputTick = 0 ;
02218
02219 OSDL_SCHEDULE_LOG( "Simulation period : " << _simulationPeriod ) ;
02220 OSDL_SCHEDULE_LOG( "Rendering period : " << _renderingPeriod ) ;
02221 OSDL_SCHEDULE_LOG( "Input period : " << _inputPeriod ) ;
02222
02223
02224 EngineTick nextSimulationDeadline = _currentEngineTick + _simulationPeriod ;
02225 EngineTick nextRenderingDeadline = _currentEngineTick + _renderingPeriod ;
02226 EngineTick nextInputDeadline = _currentEngineTick + _inputPeriod ;
02227
02228 EngineTick countBeforeSleep = 0 ;
02229
02230
02231
02232 while ( ! _stopRequested )
02233 {
02234
02235 OSDL_SCHEDULE_LOG( "[ E : " << _currentEngineTick
02236 << " ; S : " << _currentSimulationTick
02237 << " ; R : " << _currentRenderingTick
02238 << " ; I : " << _currentInputTick << " ]" ) ;
02239
02240 countBeforeSleep++ ;
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257 if ( _currentEngineTick == nextSimulationDeadline )
02258 {
02259
02260
02261
02262 #if OSDL_DEBUG_SCHEDULER
02263 metSimulations.push_back( _currentSimulationTick ) ;
02264 #endif // OSDL_DEBUG_SCHEDULER
02265
02266 scheduleSimulation( _currentSimulationTick ) ;
02267
02268 _currentSimulationTick++ ;
02269 nextSimulationDeadline += _simulationPeriod ;
02270
02271 }
02272
02273 if ( _currentEngineTick == nextRenderingDeadline )
02274 {
02275
02276
02277
02278 #if OSDL_DEBUG_SCHEDULER
02279 metRenderings.push_back( _currentRenderingTick ) ;
02280 #endif // OSDL_DEBUG_SCHEDULER
02281
02282 scheduleRendering( _currentRenderingTick ) ;
02283
02284 _currentRenderingTick++ ;
02285 nextRenderingDeadline += _renderingPeriod ;
02286 }
02287
02288 if ( pollInputs && _currentEngineTick == nextInputDeadline )
02289 {
02290
02291
02292
02293 #if OSDL_DEBUG_SCHEDULER
02294 metInputPollings.push_back( _currentInputTick ) ;
02295 #endif // OSDL_DEBUG_SCHEDULER
02296
02297 scheduleInput( _currentInputTick ) ;
02298
02299 _currentInputTick++ ;
02300 nextInputDeadline += _inputPeriod ;
02301 }
02302
02303 _currentEngineTick++ ;
02304
02305
02306 if ( countBeforeSleep == 500 )
02307 {
02308 countBeforeSleep = 0 ;
02309 atomicSleep() ;
02310 }
02311
02312
02313
02314
02315
02316
02317
02318 }
02319
02320 Second scheduleStoppingSecond ;
02321 Microsecond scheduleStoppingMicrosecond ;
02322
02323 getPreciseTime( scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
02324
02325
02326
02327 Ceylan::Float64 totalRuntimeFactor ;
02328
02329
02330 if ( scheduleStoppingSecond - _scheduleStartingSecond <
02331 MaximumDurationWithMicrosecondAccuracy )
02332 {
02333
02334 totalRuntimeFactor = 1E6 / getDurationBetween(
02335 _scheduleStartingSecond, _scheduleStartingMicrosecond,
02336 scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
02337
02338 }
02339 else
02340 {
02341
02342
02343 totalRuntimeFactor = 1.0f /
02344 ( scheduleStoppingSecond - _scheduleStartingSecond ) ;
02345
02346 }
02347
02348
02349 send( "Scheduler stopping. Scheduler infos : "
02350 + toString( Ceylan::high ) ) ;
02351
02352
02353 ostringstream buf ;
02354
02355 buf.precision( 4 ) ;
02356
02357 buf << "Actual average engine frequency was "
02358 << Ceylan::toString( totalRuntimeFactor * _currentEngineTick,
02359 2 )
02360 << " Hz, average simulation frequency was "
02361 << Ceylan::toString( totalRuntimeFactor * _currentSimulationTick,
02362 2 )
02363 << " Hz, average rendering frequency was "
02364 << Ceylan::toString( totalRuntimeFactor * _currentRenderingTick,
02365 2 )
02366 << " Hz, average input frequency was "
02367 << Ceylan::toString( totalRuntimeFactor * _currentInputTick,
02368 2 )
02369 << " Hz." ;
02370
02371 send( buf.str() ) ;
02372
02373 #if OSDL_DEBUG_SCHEDULER
02374
02375
02376
02377
02378
02379
02380
02381
02382 LogPlug::debug( "Total simulation ticks : "
02383 + Ceylan::toString( metSimulations.size() ) + "." ) ;
02384
02385
02386
02387
02388
02389
02390 SimulationTick newSimulationTick ;
02391
02392 bool * simulationTicks = new bool[ _currentSimulationTick ] ;
02393
02394 for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
02395 simulationTicks[i] = false ;
02396
02397 for ( list<SimulationTick>::const_iterator it = metSimulations.begin();
02398 it != metSimulations.end(); it++ )
02399 {
02400
02401 newSimulationTick = (*it) ;
02402 if ( simulationTicks[ newSimulationTick ] == false )
02403 simulationTicks[ newSimulationTick ] = true ;
02404 else
02405 LogPlug::error( "Simulation tick #"
02406 + Ceylan::toString( newSimulationTick )
02407 + " should not have been scheduled more than once." ) ;
02408
02409 }
02410
02411 for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
02412 if ( simulationTicks[ i ] == false )
02413 LogPlug::error( "Simulation tick #" + Ceylan::toString( i )
02414 + " has never been scheduled." ) ;
02415
02416 delete simulationTicks ;
02417
02418
02419
02420
02421 LogPlug::debug( "Total rendering ticks : "
02422 + Ceylan::toString( metRenderings.size() ) + "." ) ;
02423
02424
02425
02426
02427
02428
02429 RenderingTick newRenderingTick ;
02430
02431 bool * renderingTicks = new bool[ _currentRenderingTick ] ;
02432
02433 for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
02434 renderingTicks[i] = false ;
02435
02436 for ( list<RenderingTick>::const_iterator it = metRenderings.begin();
02437 it != metRenderings.end(); it++ )
02438 {
02439
02440 newRenderingTick = (*it) ;
02441 if ( renderingTicks[ newRenderingTick ] == false )
02442 renderingTicks[ newRenderingTick ] = true ;
02443 else
02444 LogPlug::error( "Rendering tick #"
02445 + Ceylan::toString( newRenderingTick )
02446 + " should not have been scheduled more than once." ) ;
02447
02448 }
02449
02450 for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
02451 if ( renderingTicks[ i ] == false )
02452 LogPlug::error( "Rendering tick #" + Ceylan::toString( i )
02453 + " has never been scheduled." ) ;
02454
02455 delete renderingTicks ;
02456
02457
02458
02459 LogPlug::debug( "Total input polling ticks : "
02460 + Ceylan::toString( metInputPollings.size() ) + "." ) ;
02461
02462
02463
02464
02465
02466 if ( pollInputs )
02467 {
02468
02469 InputTick newInputTick ;
02470
02471 bool * inputTicks = new bool[ _currentInputTick ] ;
02472
02473 for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
02474 inputTicks[i] = false ;
02475
02476 for ( list<InputTick>::const_iterator it = metInputPollings.begin();
02477 it != metInputPollings.end(); it++ )
02478 {
02479
02480 newInputTick = (*it) ;
02481 if ( inputTicks[ newInputTick ] == false )
02482 inputTicks[ newInputTick ] = true ;
02483 else
02484 LogPlug::error( "Input tick #"
02485 + Ceylan::toString( newInputTick )
02486 + " should not have been scheduled more than once." ) ;
02487
02488 }
02489
02490 for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
02491 if ( inputTicks[ i ] == false )
02492 LogPlug::error( "Input tick #" + Ceylan::toString( i )
02493 + " has never been scheduled." ) ;
02494
02495 delete inputTicks ;
02496
02497 }
02498
02499 #endif // OSDL_DEBUG_SCHEDULER
02500
02501
02502 }
02503
02504
02505
02506 EngineTick Scheduler::computeEngineTickFromCurrentTime() throw()
02507 {
02508
02509 Second currentSecond ;
02510 Microsecond currentMicrosecond ;
02511 getPreciseTime( currentSecond, currentMicrosecond ) ;
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531 if ( currentMicrosecond < _scheduleStartingMicrosecond )
02532 {
02533
02534
02535 #if OSDL_DEBUG_SCHEDULER
02536 if ( currentSecond == 0 )
02537 {
02538
02539 LogPlug::fatal( "Scheduler::computeEngineTickFromCurrentTime : "
02540 "abnormal clock skew." ) ;
02541
02542 _stopRequested = true ;
02543
02544 }
02545 #endif // OSDL_DEBUG_SCHEDULER
02546
02547 currentSecond-- ;
02548 currentMicrosecond += 1000000 ;
02549
02550 }
02551
02552 return static_cast<EngineTick>(
02553 ( currentSecond - _scheduleStartingSecond ) * _secondToEngineTick
02554 + ( currentMicrosecond - _scheduleStartingMicrosecond )
02555 / _engineTickDuration ) ;
02556
02557 }
02558
02559
02560 void Scheduler::scheduleSimulation( SimulationTick current ) throw()
02561 {
02562
02563
02564
02565 OSDL_SCHEDULE_LOG( "--- simulating ! " ) ;
02566
02567
02568 scheduleProgrammedObjects( current ) ;
02569
02570
02571 schedulePeriodicObjects( current ) ;
02572
02573 }
02574
02575
02576 void Scheduler::scheduleProgrammedObjects(
02577 SimulationTick currentSimulationTick ) throw()
02578 {
02579
02580 map<SimulationTick, ListOfActiveObjects>::iterator it
02581 = _programmedActivated.find( currentSimulationTick ) ;
02582
02583 if ( it != _programmedActivated.end() )
02584 {
02585 scheduleActiveObjectList( currentSimulationTick, (*it).second ) ;
02586
02587
02588 _programmedActivated.erase( it ) ;
02589 }
02590
02591
02592
02593 }
02594
02595
02596 void Scheduler::schedulePeriodicObjects( SimulationTick current ) throw()
02597 {
02598
02599
02600
02601 for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin();
02602 it != _periodicSlots.end(); it++ )
02603 {
02604 (*it)->onNextTick( current ) ;
02605 }
02606
02607 }
02608
02609
02610 void Scheduler::scheduleRendering( RenderingTick current ) throw()
02611 {
02612
02613 OSDL_SCHEDULE_LOG( "--- rendering !" ) ;
02614
02615 if ( _renderer != 0 )
02616 _renderer->render( current ) ;
02617 else
02618 {
02619
02620 #if OSDL_DEBUG
02621 if ( _videoModule == 0 )
02622 Ceylan::emergencyShutdown( "Scheduler::scheduleRendering : "
02623 "no video module available." ) ;
02624 #endif // OSDL_DEBUG
02625 _videoModule->redraw() ;
02626 }
02627
02628 }
02629
02630
02631 void Scheduler::scheduleInput( InputTick current ) throw()
02632 {
02633
02634 OSDL_SCHEDULE_LOG( "--- input polling !" ) ;
02635
02636 #if OSDL_DEBUG
02637 if ( _eventsModule == 0 )
02638 Ceylan::emergencyShutdown( "Scheduler::scheduleRendering : "
02639 "no events module available." ) ;
02640 #endif // OSDL_DEBUG
02641
02642 _eventsModule->updateInputState() ;
02643
02644 }
02645
02646
02647 void Scheduler::scheduleActiveObjectList(
02648 Events::RenderingTick currentSimulationTick,
02649 ListOfActiveObjects & objectList ) throw()
02650 {
02651
02652 for ( ListOfActiveObjects::iterator it = objectList.begin();
02653 it != objectList.end(); it++ )
02654 {
02655 (*it)->onActivation( currentSimulationTick ) ;
02656 }
02657
02658 }
02659
02660
02661 void Scheduler::onSimulationSkipped( SimulationTick skipped )
02662 throw( SchedulingException )
02663 {
02664
02665 _missedSimulationTicks++ ;
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680 for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin();
02681 it != _periodicSlots.end(); it++ )
02682 {
02683 (*it)->onSimulationSkipped( skipped ) ;
02684 }
02685
02686
02687
02688 map<SimulationTick, ListOfActiveObjects>::iterator it
02689 = _programmedActivated.find( skipped ) ;
02690
02691 if ( it != _programmedActivated.end() )
02692 {
02693 for ( ListOfActiveObjects::iterator itObjects = (*it).second.begin() ;
02694 itObjects != (*it).second.end(); itObjects++ )
02695 (*itObjects)->onSkip( skipped ) ;
02696 }
02697
02698 #if OSDL_DEBUG_SCHEDULER
02699 LogPlug::warning( "Simulation tick " + Ceylan::toString( skipped )
02700 + " had to be skipped." ) ;
02701 #endif // OSDL_DEBUG_SCHEDULER
02702
02703 }
02704
02705
02706 void Scheduler::onRenderingSkipped( RenderingTick skipped )
02707 throw( SchedulingException )
02708 {
02709
02710 _missedRenderingTicks++ ;
02711
02712 if ( _renderer != 0 )
02713 _renderer->onRenderingSkipped( skipped ) ;
02714
02715 #if OSDL_DEBUG_SCHEDULER
02716 LogPlug::warning( "Rendering tick " + Ceylan::toString( skipped )
02717 + " had to be skipped." ) ;
02718 #endif // OSDL_DEBUG_SCHEDULER
02719
02720 }
02721
02722
02723 void Scheduler::onInputSkipped( InputTick skipped )
02724 throw( SchedulingException )
02725 {
02726
02727 _missedInputPollingTicks++ ;
02728
02729
02730
02731 }
02732
02733
02734 void Scheduler::onIdle() throw()
02735 {
02736
02737 OSDL_SCHEDULE_LOG( "--- idle callback called !" ) ;
02738
02739 _idleCallsCount++ ;
02740
02741 if ( _idleCallback != 0 )
02742 {
02743
02744
02745 (*_idleCallback)( _idleCallbackData ) ;
02746
02747 }
02748 else
02749 {
02750
02751
02752
02753
02754
02755
02756 Ceylan::System::atomicSleep() ;
02757
02758 }
02759
02760 }
02761
02762
02763 void Scheduler::onScheduleFailure( Delay currentBucket ) throw()
02764 {
02765
02766 _scheduleFailureCount++ ;
02767
02768
02769
02770 if ( currentBucket < ShutdownBucketLevel )
02771 {
02772
02773 string message = "Non-fatal schedule failure for engine tick #"
02774 + Ceylan::toString( _currentEngineTick )
02775 + ", delay bucket reached level "
02776 + Ceylan::toString( currentBucket )
02777 + ", this computer does not seem able to satisfy "
02778 "the requested load." ;
02779
02780
02781 OSDL_SCHEDULE_LOG( "!!!!! " + message ) ;
02782
02783 LogPlug::error( message) ;
02784
02785 }
02786 else
02787 {
02788
02789 string message = "Fatal schedule failure for engine tick #"
02790 + Ceylan::toString( _currentEngineTick )
02791 + ", delay bucket reached level "
02792 + Ceylan::toString( currentBucket )
02793 + ", this computer cannot take in charge the requested load, "
02794 "stopping the scheduler now." ;
02795
02796
02797 OSDL_SCHEDULE_LOG( "XXXXX " + message ) ;
02798
02799 LogPlug::fatal( message) ;
02800
02801 stop() ;
02802
02803 }
02804
02805 }
02806
02807
02808 void Scheduler::programTriggerFor( ActiveObject & objectToProgram,
02809 SimulationTick targetTick ) throw()
02810 {
02811
02812
02813 if ( ! objectToProgram.areProgrammedActivationsAbsolute() )
02814 targetTick += _currentSimulationTick ;
02815
02816 map<SimulationTick, ListOfActiveObjects>::iterator it
02817 = _programmedActivated.find( targetTick ) ;
02818
02819 if ( it != _programmedActivated.end() )
02820 {
02821
02822 (*it).second.push_back( & objectToProgram ) ;
02823 }
02824 else
02825 {
02826
02827
02828 ListOfActiveObjects newList ;
02829 newList.push_back( & objectToProgram ) ;
02830 _programmedActivated[ targetTick ] = newList ;
02831
02832 }
02833
02834 }
02835
02836
02837 PeriodicSlot & Scheduler::getPeriodicSlotFor( Events::Period period ) throw()
02838 {
02839
02840 for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin();
02841 it != _periodicSlots.end(); it++ )
02842 {
02843
02844 if ( (*it)->getPeriod() == period )
02845 return * (*it) ;
02846
02847 if ( (*it)->getPeriod() > period )
02848 {
02849
02850
02851
02852
02853
02854
02855 PeriodicSlot * newSlot = new PeriodicSlot( period ) ;
02856 _periodicSlots.insert( it, newSlot ) ;
02857 return * newSlot ;
02858 }
02859
02860 }
02861
02862
02863
02864
02865
02866
02867 PeriodicSlot * newSlot = new PeriodicSlot( period ) ;
02868 _periodicSlots.push_back( newSlot ) ;
02869
02870 return * newSlot ;
02871
02872 }
02873
02874