src/Sim/Recoverer/Recoverer.cpp

説明を見る。
00001 // 
00002 // Copyright (c) 2005-2008 Kenichi Watanabe.
00003 // Copyright (c) 2005-2008 Yasuhiro Watari.
00004 // Copyright (c) 2005-2008 Hironori Ichibayashi.
00005 // Copyright (c) 2008-2009 Kazuo Horio.
00006 // Copyright (c) 2009-2013 Naruki Kurata.
00007 // Copyright (c) 2005-2013 Ryota Shioya.
00008 // Copyright (c) 2005-2013 Masahiro Goshima.
00009 // 
00010 // This software is provided 'as-is', without any express or implied
00011 // warranty. In no event will the authors be held liable for any damages
00012 // arising from the use of this software.
00013 // 
00014 // Permission is granted to anyone to use this software for any purpose,
00015 // including commercial applications, and to alter it and redistribute it
00016 // freely, subject to the following restrictions:
00017 // 
00018 // 1. The origin of this software must not be misrepresented; you must not
00019 // claim that you wrote the original software. If you use this software
00020 // in a product, an acknowledgment in the product documentation would be
00021 // appreciated but is not required.
00022 // 
00023 // 2. Altered source versions must be plainly marked as such, and must not be
00024 // misrepresented as being the original software.
00025 // 
00026 // 3. This notice may not be removed or altered from any source
00027 // distribution.
00028 // 
00029 // 
00030 
00031 
00032 #include <pch.h>
00033 
00034 #include "Recoverer.h"
00035 
00036 #include "Sim/Foundation/Hook/HookUtil.h"
00037 #include "Sim/Foundation/Checkpoint/CheckpointMaster.h"
00038 #include "Sim/Foundation/Checkpoint/CheckpointedData.h"
00039 
00040 #include "Sim/Op/Op.h"
00041 #include "Sim/Core/Core.h"
00042 #include "Sim/Thread/Thread.h"
00043 #include "Sim/InorderList/InorderList.h"
00044 #include "Sim/Memory/MemOrderManager/MemOrderManager.h"
00045 #include "Sim/Pipeline/Scheduler/Scheduler.h"
00046 #include "Sim/Pipeline/Fetcher/Fetcher.h"
00047 
00048 
00049 using namespace Onikiri;
00050 
00051 Recoverer::Recoverer() : 
00052     m_core(0),
00053     m_thread(0),
00054     m_inorderList(0),
00055     m_checkpointMaster(0),
00056     m_latPredRecoveryCount(0),
00057     m_addrPredRecoveryCount(0),
00058     m_valuePredRecoveryCount(0),
00059     m_partialReadRecoveryCount(0),
00060     m_latPredRecoveryOps(0),
00061     m_addrPredRecoveryOps(0),
00062     m_valuePredRecoveryOps(0),
00063     m_partialReadRecoveryOps(0),
00064     m_brPredRecoveryCount(0),
00065     m_brPredRecoveryOps(0),
00066     m_exceptionRecoveryCount(0),
00067     m_exceptionRecoveryOps(0),
00068     m_brPredRecoveryLatency(0),
00069     m_exceptionRecoveryLatency(0)
00070 {
00071 }
00072 
00073 Recoverer::~Recoverer()
00074 {
00075 }
00076 
00077 void Recoverer::Initialize( InitPhase phase )
00078 {
00079     if( phase == INIT_PRE_CONNECTION ){
00080         LoadParam();
00081     }
00082     else if( phase == INIT_POST_CONNECTION ){
00083 
00084         // Policy checking.
00085         // Other policy checking is done in Scheduler.
00086         const DataPredMissRecovery& pmr = m_core->GetPartialLoadRecovery();
00087         if( pmr.FromNextOfProducer() || pmr.FromProducer() ){
00088             // Partial load violation may be detected after a producer is committed.
00089             THROW_RUNTIME_ERROR( "Partial load recovery supports only a mode 'from Consumer'." );
00090         }
00091     }
00092 }
00093 
00094 void Recoverer::Finalize()
00095 {
00096     ReleaseParam();
00097 }
00098 
00099 // Recover a processor from miss branch prediction.
00100 // Ops after 'branch' are flushed and re-fetched.
00101 void Recoverer::RecoverBPredMiss( OpIterator branch )
00102 {
00103     // Recover processor state to a checkpoint after the branch.
00104     RecoverCheckpoint( branch->GetAfterCheckpoint() );
00105 
00106     // Flush backward ops.
00107     m_brPredRecoveryOps +=
00108         m_inorderList->FlushBackward( m_inorderList->GetNextPCOp(branch) );
00109 
00110     // Set a correct branch result.
00111     m_thread->SetFetchPC( branch->GetNextPC() );
00112 
00113     // Stall a fetcher for a recovery latency.
00114     int latency = m_brPredRecoveryLatency;
00115     if( latency > 0 ){
00116         m_thread->GetCore()->GetFetcher()->StallNextCycle( latency );
00117     }
00118 
00119     m_brPredRecoveryCount++;
00120 }
00121 
00122 // Recover a processor from exception.
00123 void Recoverer::RecoverException( OpIterator causer )
00124 {
00125     ASSERT(
00126         !causer->GetOpClass().IsSyscall(), 
00127         "Exception of a system call is not supported."
00128     );
00129 
00130     m_exceptionRecoveryOps += 
00131         RecoverByRefetch( causer, causer );
00132 
00133     // Clear an exception state
00134     Exception exception = causer->GetException();
00135     exception.exception = false;
00136     causer->SetException( exception );
00137 
00138     // Stall a fetcher for a recovery latency.
00139     int latency = m_exceptionRecoveryLatency;
00140     if( latency > 0 ){
00141         m_thread->GetCore()->GetFetcher()->StallNextCycle( latency );
00142     }
00143 
00144     m_exceptionRecoveryCount++;
00145 }
00146 
00147 // Recover a processor data miss prediction.
00148 int Recoverer::RecoverDataPredMiss( 
00149     OpIterator producer, 
00150     OpIterator consumer, 
00151     Recovery::Type dataPredType 
00152 ){
00153     // Select a recovery method by a specified type.
00154     Recovery dpmr;
00155     typedef Recovery DPMR;
00156 
00157     switch( dataPredType ){
00158     case DPMR::TYPE_LATENCY:
00159         dpmr = m_core->GetLatPredMissRecovery();
00160         // Miss prediction of latency requires reset of dependencies,
00161         // which are equivalent to ready bits of destinations of 'op'.
00162         // This is because a producer does not finish when miss prediction 
00163         // is detected.
00164         producer->ResetDependency();
00165         break;
00166 
00167     case DPMR::TYPE_ADDRESS_MATCH:
00168         dpmr = m_core->GetAddrPredMissRecovery();
00169         break;
00170 
00171     case DPMR::TYPE_VALUE:
00172         dpmr = m_core->GetValuePredMissRecovery();
00173         break;
00174 
00175     case DPMR::TYPE_PARTIAL_LOAD:
00176         dpmr = m_core->GetPartialLoadRecovery();
00177         break;
00178 
00179     default:
00180         THROW_RUNTIME_ERROR( "Unknown data prediction type." );
00181         break;
00182     }
00183 
00184     int recoveredInsns = 
00185         RecoverDataPredMiss( producer, consumer, dpmr );
00186 
00187     UpdateRecoveryStatistics( recoveredInsns, dataPredType );
00188 
00189     return recoveredInsns;
00190 }
00191 
00192 int Recoverer::RecoverDataPredMiss( 
00193     OpIterator producer, OpIterator consumer, const Recovery& dpmr
00194 ){
00195     // Recovered from:
00196     const Recovery::From& from      = dpmr.GetFrom();
00197 
00198     // Recover policy:
00199     const Recovery::Policy& policy  = dpmr.GetPolicy();
00200 
00201     if( policy == Recovery::POLICY_REISSUE_SELECTIVE ){
00202         // In the case of Recovery::FROM_CONSUMER, 
00203         // multiple consumers must be re-scheduled and 
00204         // the bellow codes including GetFirstConsumer() cannnot treat this.
00205         return RecoverByRescheduleSelective( producer, from );  
00206     }
00207 
00208 
00209     // Select a start point of recovery.
00210     OpIterator startOp = GetRecoveryStartOp( producer, consumer, from );
00211 
00212     // Return if there are no ops recovered...
00213     if( startOp.IsNull() ) {
00214         return 0;
00215     }
00216 
00217     int  recovered = 0;
00218 
00219     switch( policy ){
00220 
00221     case Recovery::POLICY_REFETCH:
00222         recovered = RecoverByRefetch( producer, startOp );
00223         break;
00224 
00225     case Recovery::POLICY_REISSUE_ALL:
00226         recovered = RecoverByRescheduleAll( producer, startOp );
00227         break;
00228     
00229     case Recovery::POLICY_REISSUE_NOT_FINISHED:
00230         recovered = RecoverByRescheduleNotFinished( producer, startOp );
00231         break;
00232 
00233     default:
00234         ASSERT( 0, "Unknown recovery policy." );
00235         break;
00236     }
00237 
00238     return recovered;
00239 
00240 }
00241 
00242 
00243 // Re-fetch from 'startOp'.
00244 int Recoverer::RecoverByRefetch( OpIterator /*missedOp*/, OpIterator startOp )
00245 {
00246     // A pc that fetch is resumed from.
00247     PC fetchPC = startOp->GetPC();
00248     
00249     ASSERT( 
00250         startOp->GetStatus() < OpStatus::OS_COMITTING,
00251         "Cannot re-fetch from this op because this op is already committed. op: %s", 
00252         startOp->ToString(6).c_str()
00253     );
00254 
00255     // Recover the state to 'checkpoint'.
00256     Checkpoint* checkpoint = startOp->GetBeforeCheckpoint();
00257     if( !checkpoint ){
00258         OpIterator prevOp = m_inorderList->GetPrevPCOp( startOp );
00259         if( prevOp.IsNull() ){
00260             THROW_RUNTIME_ERROR( "A necessary checkpoint is not taken. op: %s", startOp->ToString(6).c_str() );
00261         }
00262         checkpoint = m_inorderList->GetFrontOpOfSamePC(prevOp)->GetAfterCheckpoint();
00263         if( !checkpoint ){
00264             THROW_RUNTIME_ERROR( "A necessary checkpoint is not taken. op: %s", startOp->ToString(6).c_str() );
00265         }
00266     }
00267     RecoverCheckpoint( checkpoint );
00268     
00269     // Flush backward ops.
00270     int flushedInsns = 
00271         m_inorderList->FlushBackward( m_inorderList->GetFrontOpOfSamePC( startOp ) );
00272 
00273     // Set a correct branch result.
00274     m_thread->SetFetchPC( fetchPC );
00275 
00276     return flushedInsns;
00277 }
00278 
00279 
00280 // Re-schedule all ops.
00281 int Recoverer::RecoverByRescheduleAll( OpIterator missedOp, OpIterator startOp )
00282 {
00283     int recoveredInsns = 0;
00284     for( OpIterator i = startOp; !i.IsNull(); i = m_inorderList->GetNextIndexOp( i ) ){
00285         if( i->GetScheduler()->Reschedule( i ) ){
00286             recoveredInsns++;
00287         }
00288     }
00289 
00290     return recoveredInsns;
00291 }
00292 
00293 // Reschedule only not finished ops.
00294 int Recoverer::RecoverByRescheduleNotFinished( OpIterator missedOp, OpIterator startOp )
00295 {
00296     int recoveredInsns = 0;
00297     for( OpIterator i = startOp; !i.IsNull(); i = m_inorderList->GetNextIndexOp( i ) ){
00298         if( i->GetStatus() <= OpStatus::OS_EXECUTING ){
00299             if( i->GetScheduler()->Reschedule( i ) ){
00300                 recoveredInsns++;
00301             }
00302         }
00303     }
00304 
00305     return recoveredInsns;
00306 }
00307 
00308 // Selective re-scheduler.
00309 int Recoverer::RecoverByRescheduleSelective( OpIterator producerOp, Recovery::From from )
00310 {
00311     ASSERT(
00312         from != Recovery::FROM_NEXT_OF_PRODUCER,
00313         "cannot reschedule selective next of producer"
00314     );
00315 
00316     int recoveredInsns = 0;
00317     if( from == Recovery::FROM_PRODUCER ){
00318         if( producerOp->GetScheduler()->Reschedule( producerOp ) ){
00319             recoveredInsns++;
00320         }
00321     }
00322     //recoveredInsns += producerOp->RescheduleConsumers( producerOp );
00323     RescheduleConsumers( producerOp );
00324 
00325     return recoveredInsns;
00326 }
00327 
00328 // checkpoint Jos
00329 void Recoverer::RecoverCheckpoint( Checkpoint* checkpoint )
00330 {
00331     ASSERT( checkpoint != 0, "no checkpoint for recovery" );
00332     m_checkpointMaster->Recover( checkpoint );
00333 }
00334 
00335 void Recoverer::UpdateRecoveryStatistics( 
00336     int recoveredInsns, 
00337     Recovery::Type dataPredType 
00338 ){
00339     typedef Recovery DPMR;
00340 
00341     switch( dataPredType ){
00342 
00343     case DPMR::TYPE_LATENCY:
00344         m_latPredRecoveryOps += recoveredInsns;
00345         m_latPredRecoveryCount++;
00346         break;
00347 
00348     case DPMR::TYPE_ADDRESS_MATCH:
00349         m_addrPredRecoveryOps += recoveredInsns;
00350         m_addrPredRecoveryCount++;
00351         break;
00352 
00353     case DPMR::TYPE_VALUE:
00354         m_valuePredRecoveryOps += recoveredInsns;
00355         m_valuePredRecoveryCount++;
00356         break;
00357 
00358     case DPMR::TYPE_PARTIAL_LOAD:
00359         m_partialReadRecoveryOps += recoveredInsns;
00360         m_partialReadRecoveryCount++;
00361         break;
00362 
00363     default:
00364         THROW_RUNTIME_ERROR( "Unknown data prediction type." );
00365         break;
00366 
00367     }
00368 }
00369 
00370 // Re-schedule the consumers of a producer.
00371 // This is for RecoverByRescheduleSelective().
00372 int Recoverer::RescheduleConsumers( OpIterator producer )
00373 {
00374     int reshceduledInsns = 0;
00375 
00376     // Reschedule consumers.
00377     int depNum = producer->GetDstDepNum();
00378     for( int i = 0; i < depNum; ++i ){
00379         Dependency* dep = producer->GetDstDep(i);
00380         const Dependency::ConsumerListType& consumers = dep->GetConsumers();
00381         for(Dependency::ConsumerListConstIterator j = consumers.begin();
00382             j != consumers.end(); 
00383             ++j
00384         ){
00385             OpIterator consumer = *j;
00386             if( consumer->GetScheduler()->Reschedule( consumer ) ){
00387                 reshceduledInsns++;
00388             }
00389             reshceduledInsns += RescheduleConsumers( consumer );
00390         }
00391     }
00392     
00393     // Rescheduling speculatively executed load instructions.
00394     if( producer->GetOpClass().IsStore() ) {
00395         MemOrderManager* memOrder = m_thread->GetMemOrderManager();
00396         const MemAccess& memAccess = producer->GetMemAccess();
00397         for( int i = 0; ; i++ ){
00398             OpIterator consumer = memOrder->GetConsumerLoad( producer, memAccess, i );
00399             if( consumer.IsNull() )
00400                 break;
00401             if( consumer->GetScheduler()->Reschedule( consumer ) ){
00402                 reshceduledInsns++;
00403             }
00404             reshceduledInsns += RescheduleConsumers( consumer );
00405         }
00406     }
00407 
00408     return reshceduledInsns;
00409 
00410 }
00411 
00412 OpIterator Recoverer::GetRecoveryStartOp( OpIterator producer, OpIterator consumer, Recovery::From from )
00413 {
00414     // Select a start point of recovery.
00415     OpIterator startOp(0);
00416     switch( from ){
00417     case Recovery::FROM_PRODUCER:
00418         ASSERT( 
00419             !producer.IsNull(),
00420             "The start point of recovery is specified as 'Producer', but a passed producer is null." 
00421             "This may occur when a producer is already retired when violation is detected."
00422         );
00423         startOp = producer;
00424         break;
00425 
00426     case Recovery::FROM_NEXT_OF_PRODUCER:
00427         ASSERT( 
00428             !producer.IsNull(), 
00429             "The start point of recovery is specified as 'NextOfProducer', but a passed producer is null." 
00430             "This may occur when a producer is already retired when violation is detected."
00431         );
00432         startOp = m_inorderList->GetNextPCOp( producer );
00433         break;
00434 
00435     case Recovery::FROM_CONSUMER:
00436         startOp = consumer;
00437         break;
00438 
00439     default:
00440         ASSERT( 0, "An unknown recovery start point." );
00441         break;
00442     }
00443     return startOp;
00444 }

Onikiri2に対してTue Jun 18 14:34:25 2013に生成されました。  doxygen 1.4.7