00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00085
00086 const DataPredMissRecovery& pmr = m_core->GetPartialLoadRecovery();
00087 if( pmr.FromNextOfProducer() || pmr.FromProducer() ){
00088
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
00100
00101 void Recoverer::RecoverBPredMiss( OpIterator branch )
00102 {
00103
00104 RecoverCheckpoint( branch->GetAfterCheckpoint() );
00105
00106
00107 m_brPredRecoveryOps +=
00108 m_inorderList->FlushBackward( m_inorderList->GetNextPCOp(branch) );
00109
00110
00111 m_thread->SetFetchPC( branch->GetNextPC() );
00112
00113
00114 int latency = m_brPredRecoveryLatency;
00115 if( latency > 0 ){
00116 m_thread->GetCore()->GetFetcher()->StallNextCycle( latency );
00117 }
00118
00119 m_brPredRecoveryCount++;
00120 }
00121
00122
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
00134 Exception exception = causer->GetException();
00135 exception.exception = false;
00136 causer->SetException( exception );
00137
00138
00139 int latency = m_exceptionRecoveryLatency;
00140 if( latency > 0 ){
00141 m_thread->GetCore()->GetFetcher()->StallNextCycle( latency );
00142 }
00143
00144 m_exceptionRecoveryCount++;
00145 }
00146
00147
00148 int Recoverer::RecoverDataPredMiss(
00149 OpIterator producer,
00150 OpIterator consumer,
00151 Recovery::Type dataPredType
00152 ){
00153
00154 Recovery dpmr;
00155 typedef Recovery DPMR;
00156
00157 switch( dataPredType ){
00158 case DPMR::TYPE_LATENCY:
00159 dpmr = m_core->GetLatPredMissRecovery();
00160
00161
00162
00163
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
00196 const Recovery::From& from = dpmr.GetFrom();
00197
00198
00199 const Recovery::Policy& policy = dpmr.GetPolicy();
00200
00201 if( policy == Recovery::POLICY_REISSUE_SELECTIVE ){
00202
00203
00204
00205 return RecoverByRescheduleSelective( producer, from );
00206 }
00207
00208
00209
00210 OpIterator startOp = GetRecoveryStartOp( producer, consumer, from );
00211
00212
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
00244 int Recoverer::RecoverByRefetch( OpIterator , OpIterator startOp )
00245 {
00246
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
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
00270 int flushedInsns =
00271 m_inorderList->FlushBackward( m_inorderList->GetFrontOpOfSamePC( startOp ) );
00272
00273
00274 m_thread->SetFetchPC( fetchPC );
00275
00276 return flushedInsns;
00277 }
00278
00279
00280
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
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
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
00323 RescheduleConsumers( producerOp );
00324
00325 return recoveredInsns;
00326 }
00327
00328
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
00371
00372 int Recoverer::RescheduleConsumers( OpIterator producer )
00373 {
00374 int reshceduledInsns = 0;
00375
00376
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
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
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 }