src/network/nPriorizing.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "nPriorizing.h"
00029 #include "nNetwork.h"
00030 #include "tMemManager.h"
00031 
00032 tDEFINE_REFOBJ( nBandwidthTask )
00033 tDEFINE_REFOBJ( nBandwidthArbitrator )
00034 
00035 //*************************************************************************
00036 // nBandwidthTask: small task that will eat away some bandwidth
00037 //*************************************************************************
00038 
00039 // sets the task type
00040 void nBandwidthTask::SetType ( nType t )
00041 {
00042     tASSERT( priorizer_ );
00043 
00044     this->RemoveFromHeap();
00045     type_ = t;
00046     priorizer_->Tasks( type_ ).Insert( this );
00047 }
00048 
00049 // rethinks priority
00050 void nBandwidthTask::DoPriorize()
00051 {
00052     SetVal( priority_ * waiting_, *this->Heap() );
00053 }
00054 
00055 // in wich heap are we?
00056 tHeapBase *nBandwidthTask::Heap() const
00057 {
00058     tASSERT( priorizer_ );
00059 
00060     return &priorizer_->Tasks( type_ );
00061 }
00062 
00063 nBandwidthTask::~nBandwidthTask()
00064 {
00065     this->RemoveFromHeap();
00066 }
00067 
00068 nBandwidthTask::nBandwidthTask( nType type )
00069         : type_( type )
00070         , priorizer_( NULL )
00071 {
00072     waiting_ = .01f;
00073     priority_ = 0.1f;
00074 }
00075 
00076 //*************************************************************************
00077 // nBandwidthTaskPriorizer: bandwidth priorizer: selects bandwidth taks
00078 //*************************************************************************
00079 
00080 // inserts a task into the queue
00081 void nBandwidthTaskPriorizer::Insert( nBandwidthTask* task )
00082 {
00083     nTaskHeap& heap = this->Tasks( task->Type() );
00084 
00085     heap.Insert( task );
00086 
00087     tReferencer< nBandwidthTask >::AddReference( task );
00088 
00089     task->priorizer_ = this;
00090 
00091     task->Priorize();
00092 
00093     this->OnChange();
00094 }
00095 
00096 // returns the top priority task
00097 nBandwidthTask* nBandwidthTaskPriorizer::PeekNext( nType type )
00098 {
00099     nTaskHeap& heap = this->Tasks( type );
00100 
00101     if ( heap.Len() <= 0 )
00102     {
00103         return NULL;
00104     }
00105 
00106     return heap(0);
00107 }
00108 
00109 // removes and returns the top priority task
00110 tJUST_CONTROLLED_PTR<nBandwidthTask> nBandwidthTaskPriorizer::Next( nType type )
00111 {
00112     nTaskHeap& heap = this->Tasks( type );
00113 
00114     if ( heap.Len() <= 0 )
00115     {
00116         return NULL;
00117     }
00118 
00119     tJUST_CONTROLLED_PTR<nBandwidthTask> ret = heap.Remove(0);
00120 
00121     tReferencer< nBandwidthTask >::ReleaseReference( ret );
00122 
00123     ret->priorizer_ = NULL;
00124 
00125     this->OnChange();
00126 
00127     return ret;
00128 }
00129 
00130 //*************************************************************************
00131 // nBandwidthArbitrator: bandwidth arbitrator: executes bandwidth tasks
00132 //*************************************************************************
00133 
00134 nBandwidthArbitrator::nBandwidthArbitrator()
00135 {
00136     sceduler_ = NULL;
00137 }
00138 
00139 nBandwidthArbitrator::~nBandwidthArbitrator()
00140 {
00141     if ( sceduler_ )
00142     {
00143         sceduler_->RemoveArbitrator( *this );
00144     }
00145 
00146     tASSERT( NULL == sceduler_ );
00147 
00148     this->RemoveFromHeap();
00149 }
00150 
00151 // fills the send buffer with top priority messages
00152 bool nBandwidthArbitrator::Fill( nSendBuffer& buffer, nBandwidthControl& control )
00153 {
00154     // return whether a message was sent
00155     bool ret = false;
00156 
00157     // find heap to use
00158     nType type = this->FirstType();
00159     if ( type < nBandwidthTask::Type_Count )
00160     {
00161         REAL totalPriority = 0.0f;                              // total prioirty of already added messages
00162 
00163         bool first = true;
00164         bool goon = true;
00165         while ( goon )
00166         {
00167             goon = false;
00168 
00169             tJUST_CONTROLLED_PTR< nBandwidthTask > next = this->PeekNext( type );
00170             if ( next )
00171             {
00172                 REAL priority = next->Priority();
00173                 REAL value = next->Val();
00174 
00175                 // see if we have enough bandwidth reservers to send message
00176                 if ( !first || value  * this->TimeScale() > -control.Score() )
00177                 {
00178                     // see if the priority of the next sent message justifies the delay caused for the messages already in the buffer
00179                     if ( priority * this->PacketOverhead() > totalPriority * next->EstimateSize() )
00180                     {
00181                         // extract message
00182                         next = this->Next( type );
00183 
00184                         // send it
00185                         next->Execute( buffer, control );
00186 
00187                         // sum up priority
00188                         totalPriority += priority;
00189 
00190                         // try another one!
00191                         goon = true;
00192                         ret = true;
00193                     }
00194                 }
00195             }
00196 
00197             first = false;
00198         }
00199     }
00200 
00201     // reduce priority so it is not picked until the next call to Timestep
00202     this->SetVal( this->Val() - 100.0f, *this->Heap() );
00203 
00204     return ret;
00205 }
00206 
00207 // advances timers of all tasks
00208 void nBandwidthArbitrator::Timestep( REAL dt )
00209 {
00210     for ( int i = 0; i < nBandwidthTask::Type_Count; ++i )
00211     {
00212         nType type = nType(i);
00213 
00214         nTaskHeap& heap = this->Tasks( type );
00215         int j;
00216 
00217         static tArray< nBandwidthTask* > tasks;
00218         tasks.SetLen( 0 );
00219 
00220         // copy heap; otherwise, we would risk updating elements twice or not al all
00221         for ( j = heap.Len()-1; j>=0; --j )
00222         {
00223             tasks[j] = heap(j);
00224         }
00225 
00226         for ( j = tasks.Len()-1; j>=0; --j )
00227         {
00228             tasks(j)->Timestep( dt );
00229         }
00230     }
00231 
00232     this->OnChange();
00233 }
00234 
00235 // determines the type of the message to send next
00236 nBandwidthArbitrator::nType nBandwidthArbitrator::FirstType() const
00237 {
00238     for ( int i = 0; i < nBandwidthTask::Type_Count; ++i )
00239     {
00240         nType type = nType(i);
00241         if ( this->Tasks(type).Len() > 0 )
00242         {
00243             return type;
00244         }
00245     }
00246 
00247     return nBandwidthTask::Type_Count;
00248 }
00249 
00250 // called on every change of data
00251 void nBandwidthArbitrator::OnChange()
00252 {
00253     REAL value = 0.0f;
00254 
00255     for ( int i = 0; i < nBandwidthTask::Type_Count; ++i )
00256     {
00257         nType type = nType(i);
00258         const nTaskHeap& heap = this->Tasks(type);
00259         if ( heap.Len() > 0 )
00260         {
00261             value += heap(0)->Val();
00262         }
00263     }
00264 
00265     this->SetVal( value, *this->Heap() );
00266 }
00267 
00268 tHeapBase* nBandwidthArbitrator::Heap() const
00269 {
00270     if ( !sceduler_ )
00271     {
00272         return NULL;
00273     }
00274 
00275     return &sceduler_->arbitratorHeap_;
00276 }
00277 
00278 //*************************************************************************
00279 // nBandwidthSceduler: distributes bandwidth around all arbitrators
00280 //*************************************************************************
00281 nBandwidthSceduler::~nBandwidthSceduler()
00282 {
00283     while ( this->arbitratorList_.Len() > 0 )
00284     {
00285         this->RemoveArbitrator( *this->arbitratorList_(0) );
00286     }
00287 }
00288 
00289 void nBandwidthSceduler::UseBandwidth( REAL dt )
00290 {
00291     int i;
00292 
00293     // andvance all timers
00294     for ( i = this->arbitratorList_.Len()-1; i>=0; --i )
00295     {
00296         this->arbitratorList_(i)->Timestep( dt );
00297     }
00298 
00299     // let the first arbitrator do its job
00300     if ( this->arbitratorHeap_.Len() <= 0 )
00301     {
00302         return;
00303     }
00304 
00305     bool goon = true;
00306     while( goon )
00307     {
00308         goon = false;
00309 
00310         nBandwidthArbitrator* arbitrator = this->arbitratorHeap_(0);
00311         tASSERT( arbitrator );
00312 
00313         goon = arbitrator->UseBandwidth( dt );
00314     }
00315 }
00316 
00317 // adds an arbitrator
00318 void nBandwidthSceduler::AddArbitrator          ( nBandwidthArbitrator& arbitrator )
00319 {
00320     tASSERT( NULL == arbitrator.sceduler_ );
00321 
00322     tJUST_CONTROLLED_PTR< nBandwidthArbitrator > keepalive( &arbitrator );
00323 
00324     this->arbitratorHeap_.Insert( &arbitrator );
00325     this->arbitratorList_.Add( &arbitrator );
00326 
00327     arbitrator.sceduler_ = this;
00328 }
00329 
00330 // removes an arbitrator
00331 void nBandwidthSceduler::RemoveArbitrator       ( nBandwidthArbitrator& arbitrator )
00332 {
00333     tASSERT( this == arbitrator.sceduler_ );
00334 
00335     tJUST_CONTROLLED_PTR< nBandwidthArbitrator > keepalive( &arbitrator );
00336 
00337     this->arbitratorHeap_.Remove( &arbitrator );
00338     this->arbitratorList_.Remove( &arbitrator );
00339 
00340     arbitrator.sceduler_ = NULL;
00341 }
00342 
00343 
00344 
00345 
00346 // Implementation tests
00347 
00348 // bandwidth distributor: implementation of arbitrator.
00349 class nBandwitdhDistributor: public nBandwidthArbitrator
00350 {
00351 public:
00352     nSendBuffer&                SendBuffer()                            { return buffer_; }
00353     const       nSendBuffer&            SendBuffer()            const   { return buffer_; }
00354     nBandwidthControl&  BandwidthControl()                      { return control_; }
00355     const       nBandwidthControl&      BandwidthControl()      const   { return control_; }
00356 protected:
00357 private:
00358     virtual bool DoUseBandwidth( REAL dt );
00359 
00360     virtual REAL TimeScale(){ return 0.1f; }                                            // higher values let really urgent messages be sent even if the bandwidth control objectd
00361     virtual REAL PacketOverhead(){ return 60.0f; }                                      // overhead in bytes per sent packet. Determines average package size
00362 
00363     nSendBuffer buffer_;                                                                                        // buffer taking the messages
00364     nBandwidthControl control_;                                                                         // bandwidth control
00365 };
00366 
00367 
00368 // *********************************************************
00369 // bandwidth distributor: implementation of arbitrator.
00370 // *********************************************************
00371 
00372 // consumes some bandwidth
00373 bool nBandwitdhDistributor::DoUseBandwidth( REAL dt )
00374 {
00375     return this->Fill( this->buffer_, this->control_ );
00376 }
00377 
00378 
00379 
00380 // message sending bandwidth task
00381 class nBandwidthTaskMessage: public nBandwidthTask
00382 {
00383 public:
00384     nBandwidthTaskMessage( nType type, nMessage& message );
00385 
00386     nMessage& Message() const { return *message_; }
00387 protected:
00388     virtual void DoExecute( nSendBuffer& buffer, nBandwidthControl& control );                          // executes whatever it has to do
00389     virtual int  DoEstimateSize() const;                                                                                                        // estimate bandwidth usage
00390     //  virtual void DoPriorize();                                                                                                                              // rethinks priority
00391 private:
00392     tJUST_CONTROLLED_PTR< nMessage > message_;
00393 };
00394 
00395 
00396 
00397 
00398 // *********************************************************
00399 // nBandwidthTaskMessage: message sending bandwidth task
00400 // *********************************************************
00401 
00402 nBandwidthTaskMessage::nBandwidthTaskMessage( nType type, nMessage& message )
00403         :nBandwidthTask( type ), message_( &message )
00404 {
00405 }
00406 
00407 // executes whatever it has to do
00408 void nBandwidthTaskMessage::DoExecute( nSendBuffer& buffer, nBandwidthControl& control )
00409 {
00410     buffer.AddMessage( *message_, &control );
00411 }
00412 
00413 // estimate bandwidth usage
00414 int  nBandwidthTaskMessage::DoEstimateSize() const
00415 {
00416     return message_->DataLen();
00417 }
00418 
00419 
00420 
00421 
00422 
00423 
00424 
00425 
00426 
00427 
00428 
00429 
00430 
00431 
00432 
00433 
00434 
00435 
00436 #ifdef DEBUG
00437 
00438 static nDescriptor testDescriptor( 399, NULL, NULL, "test" );
00439 //static nDescriptor testDescriptor( 399, NULL, NULL, "test" );
00440 
00441 #include "nNetObject.h"
00442 
00443 class nTestObject: public nNetObject
00444 {
00445 public:
00446     nTestObject( nMessage& m ): nNetObject( m ){}
00447     nTestObject(){};
00448     virtual nDescriptor& CreatorDescriptor() const;
00449     virtual bool AcceptClientSync() const{return true;}
00450 };
00451 
00452 nDescriptor& nTestObject::CreatorDescriptor() const
00453 {
00454     static nNOInitialisator< nTestObject > cd( 398, "nTestObject" );
00455     return cd;
00456 }
00457 
00458 // Unit test
00459 class PriorizingTester
00460 {
00461 public:
00462     PriorizingTester()
00463     {
00464         nBandwidthSceduler sceduler;
00465 
00466         {
00467             tJUST_CONTROLLED_PTR< nBandwidthArbitrator > distributor = tNEW( nBandwitdhDistributor );
00468             sceduler.AddArbitrator( *distributor );
00469 
00470             {
00471                 nMessage* mess = tNEW( nMessage( testDescriptor) );
00472                 tJUST_CONTROLLED_PTR< nBandwidthTask > messageTask = tNEW( nBandwidthTaskMessage ) ( nBandwidthTask::Type_Vital, *mess );
00473                 distributor->Insert( messageTask );
00474                 sceduler.UseBandwidth( 1.0f );
00475                 distributor->Insert( messageTask );
00476                 sceduler.UseBandwidth( 1.0f );
00477                 distributor->Insert( messageTask );
00478             }
00479 
00480             {
00481                 tJUST_CONTROLLED_PTR< nNetObject > object = tNEW( nTestObject );
00482                 tJUST_CONTROLLED_PTR< nBandwidthTask > objectTask = tNEW( nBandwidthTaskCreate ) ( nBandwidthTask::Type_Vital, *object );
00483                 objectTask->AddPriority( 1.0f );
00484                 distributor->Insert( objectTask );
00485             }
00486         }
00487 
00488         sceduler.UseBandwidth( 1.0f );
00489         sceduler.UseBandwidth( 1.0f );
00490         sceduler.UseBandwidth( 1.0f );
00491     }
00492 };
00493 
00494 //static PriorizingTester tester;
00495 
00496 #endif
00497 

Generated on Sat Mar 15 22:55:51 2008 for Armagetron Advanced by  doxygen 1.5.4