src/Sim/Pipeline/Retirer/Retirer.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 "Sim/Pipeline/Retirer/Retirer.h"
00035 
00036 #include "Env/Env.h"
00037 #include "Utility/RuntimeError.h"
00038 #include "Sim/Dumper/Dumper.h"
00039 #include "Sim/Op/OpContainer/OpList.h"
00040 #include "Sim/Foundation/Hook/HookUtil.h"
00041 #include "Sim/Op/Op.h"
00042 #include "Sim/Core/Core.h"
00043 #include "Sim/InorderList/InorderList.h"
00044 #include "Sim/Thread/Thread.h"
00045 #include "Sim/System/ForwardEmulator.h"
00046 #include "Sim/Pipeline/Retirer/RetireEvent.h"
00047 #include "Sim/Recoverer/Recoverer.h"
00048 
00049 using namespace Onikiri;
00050 
00051 // Define hook points.
00052 namespace Onikiri 
00053 {
00054     Retirer::CommitHookPoint            Retirer::s_commitHook;
00055     Retirer::RetireHookPoint            Retirer::s_retireHook;
00056     Retirer::CommitSteeringHookPoint    Retirer::s_commitSteeringHook;
00057     Retirer::CommitDecisionHookPoint    Retirer::s_commitDecisionHook;
00058 };
00059 
00060 void Retirer::Evaluated::Reset()
00061 {
00062     committing.clear();
00063     exceptionOccur = false;
00064     exceptionCauser = OpIterator(0);
00065     evaluated = false;
00066     storePortFull = false;
00067 }
00068 
00069 Retirer::Retirer() :
00070     m_commitWidth(0),
00071     m_retireWidth(0),
00072     m_noCommitLimit(0),
00073     m_commitLatency(0),
00074     m_fixCommitLatency(false),
00075     m_committableStatus( OpStatus::OS_INVALID ),
00076     m_numCommittedOps(0),
00077     m_numCommittedInsns(0),
00078     m_numRetiredOps(0),
00079     m_numRetiredInsns(0),
00080     m_numStorePortFullStalledCycles(0),
00081     m_noCommittedCycle(0),
00082     m_numSimulationEndInsns(0),
00083     m_currentRetireThread(0),
00084     m_endOfProgram(false),
00085     m_emulator(0),
00086     m_forwardEmulator(0)
00087 {
00088 }
00089 
00090 Retirer::~Retirer()
00091 {
00092     ReleaseParam();
00093 }
00094 
00095 void Retirer::Initialize( InitPhase phase )
00096 {
00097     PipelineNodeBase::Initialize( phase );
00098 
00099     if( phase == INIT_PRE_CONNECTION ){
00100         SetPriority( RP_COMMIT );
00101         LoadParam();
00102     }
00103     else if( phase == INIT_POST_CONNECTION ){
00104         DisableLatch();
00105     }
00106 
00107 }
00108 
00109 void Retirer::Evaluate()
00110 {
00111     m_evaluated.Reset();
00112     EvaluateCommit();
00113     PipelineNodeBase::Evaluate();
00114 }
00115 
00116 // Evaluate commitment
00117 void Retirer::EvaluateCommit()
00118 {
00119     Thread* thread = GetCommitableThread();
00120     if( !thread ){
00121         m_evaluated.evaluated = true;
00122         return;
00123     }
00124 
00125     InorderList* inorderList = thread->GetInorderList();
00126 
00127     int comittedOps = 0;
00128     
00129     OpIterator headOp = inorderList->GetFrontOp();
00130     if( !headOp.IsNull() && headOp->GetException().exception ){
00131         m_evaluated.exceptionOccur = true;
00132         m_evaluated.exceptionCauser = headOp;
00133 
00134         // Sanity checking for commitment
00135         CheckCommitCounters( 0, inorderList );
00136         m_evaluated.evaluated = true;
00137         return;
00138     }
00139 
00140     // Check head ops in an in-order list and retire completed ops.
00141     for( OpIterator op = inorderList->GetFrontOp();
00142           !op.IsNull() && CanCommitInsn( op ) ;
00143          // Blank
00144     ){
00145         if( m_numSimulationEndInsns != 0 && 
00146             m_numCommittedInsns + comittedOps >= m_numSimulationEndInsns 
00147         ){
00148             break;
00149         }
00150 
00151         int microOpNum = op->GetOpInfo()->GetMicroOpNum();
00152         if( comittedOps + microOpNum > m_commitWidth ){
00153             break;
00154         }
00155 
00156         // Commit ops.
00157         for( int i = 0; i < microOpNum; i++ ){
00158             m_evaluated.committing.push_back( op );
00159             op = inorderList->GetNextIndexOp( op );
00160             comittedOps++;
00161         }
00162     }
00163 
00164     // Sanity checking for commitment
00165     CheckCommitCounters( comittedOps, inorderList );
00166 
00167     m_evaluated.evaluated = true;
00168     if( m_evaluated.storePortFull ){
00169         m_numStorePortFullStalledCycles++;
00170     }
00171 }
00172 
00173 void Retirer::Transition()
00174 {
00175     BaseType::Transition();
00176 
00177     // On a stalled cycle, evaluated results must be cleared, because
00178     // the evaluated results may appear to be illegally flushed.
00179     if( IsStalledThisCycle() ){
00180         m_evaluated.Reset();
00181     }
00182 }
00183 
00184 // Update commitment
00185 void Retirer::Update()
00186 {
00187     if( m_numSimulationEndInsns != 0 && m_numRetiredInsns > m_numSimulationEndInsns ){
00188         THROW_RUNTIME_ERROR( "Simulation was done in excess of 'System/@SimulationInsns'" );
00189     }
00190 
00191     UpdateException();
00192     UpdateCommit();
00193 }
00194 
00195 // Set the number of retired ops/insns.
00196 // This is called when a simulation mode is changed from an emulation mode.
00197 void Retirer::SetInitialNumRetiredOp( s64 numInsns, s64 numOp, s64 simulationEndInsns )
00198 {
00199     m_numCommittedInsns = numInsns;
00200     m_numCommittedOps   = numOp;
00201 
00202     m_numRetiredInsns   = numInsns;
00203     m_numRetiredOps     = numOp;
00204 
00205     m_numSimulationEndInsns = simulationEndInsns;
00206 }
00207 
00208 // Called from OpRetireEvent when the op is retired.
00209 void Retirer::Retire( OpIterator op )
00210 {
00211     HOOK_SECTION_OP( s_retireHook, op )
00212     {
00213         op->GetInorderList()->Retire( op );
00214 
00215         if( op->GetNo() == 0 ) {
00216             m_numRetiredInsns++;
00217         }
00218         m_numRetiredOps++;
00219     }
00220 }
00221 
00222 // Called when the op is flushed.
00223 void Retirer::Flush( OpIterator op )
00224 {
00225 #if ONIKIRI_DEBUG
00226     CommitingOps* committing = &m_evaluated.committing;
00227     for( CommitingOps::iterator i = committing->begin(); i != committing->end(); ){
00228         // Committing ops must not be flushed.
00229         // This may occur when a wrong recovery policy is set.
00230         ASSERT( op != *i, "A committing op is flushed.\n%s", op->ToString().c_str() );
00231         ++i;
00232     }
00233     /*
00234     ASSERT(
00235         !(m_evaluated.exceptionOccur && m_evaluated.exceptionCauser == op ),
00236         "A exception causing op is flushed."
00237     );
00238     */
00239 #endif
00240 }
00241 
00242 // Returns whether 'op' can retire or not.
00243 bool Retirer::CanCommitOp( OpIterator op )
00244 {
00245     CommitDecisionHookParam param = { op, false };
00246     HOOK_SECTION_OP_PARAM( s_commitDecisionHook, op, param )
00247     {
00248         param.canCommit = true;
00249 
00250         if( op->GetException().exception ){
00251             // Exception occurs.
00252             param.canCommit = false;
00253         }
00254         else{
00255             // An op can commit if the state of 'op' is 
00256             // after than FINISHED or COMPLETED.
00257             if( op->GetStatus() < m_committableStatus ){
00258                 param.canCommit = false;
00259             }
00260             else{
00261                 // Store
00262                 const OpClass& opClass = op->GetOpClass();
00263                 if( opClass.IsStore() ){
00264                     ExecUnitIF* execUnit = op->GetExecUnit();
00265                     if( execUnit->CanReserve( op, 0 ) ){
00266                         execUnit->Reserve( op, 0 );
00267                     }
00268                     else{
00269                         param.canCommit = false;
00270                         m_evaluated.storePortFull = true;
00271                     }
00272                 }
00273             }
00274         }
00275     }
00276 
00277     return param.canCommit;
00278 }
00279 
00280 // Returns whether 'ops' that belongs to the same instruction can commit or not.
00281 bool Retirer::CanCommitInsn( OpIterator op )
00282 {
00283     OpInfo* opInfo = op->GetOpInfo();
00284     InorderList* inorderList = op->GetInorderList();
00285 
00286     int microOps = opInfo->GetMicroOpNum();
00287     OpIterator cur = inorderList->GetFrontOpOfSamePC( op );
00288     
00289     for( int i = 0; i < microOps; i++ ){
00290         ASSERT( cur->GetNo() == i, "Micro op indices mismatch." );
00291         if( cur.IsNull() || !CanCommitOp( cur ) ){
00292             return false;
00293         }
00294         cur = inorderList->GetNextIndexOp( cur );
00295     }
00296 
00297     return true;
00298 }
00299 
00300 // Decide a thread that is retired in this cycle.
00301 Thread* Retirer::GetCommitableThread()
00302 {
00303     CommitSteeringHookParam param = { &m_thread, NULL };
00304     HOOK_SECTION_PARAM( s_commitSteeringHook, param )
00305     {
00306         int index;
00307         int count = 0;
00308         int threadSize = m_thread.GetSize();
00309         do{
00310             index = m_currentRetireThread;
00311             m_currentRetireThread++;
00312             if( m_currentRetireThread >= threadSize ){
00313                 m_currentRetireThread = 0;
00314             }
00315 
00316             count++;
00317             if( count > threadSize ){
00318                 THROW_RUNTIME_ERROR( "No thread can retire." );
00319             }
00320         }
00321         while( !m_thread[index]->IsActive() );
00322 
00323         param.targetThread = m_thread[index];
00324     }
00325     return param.targetThread;
00326 }
00327 
00328 void Retirer::Commit( OpIterator op )
00329 {
00330     HOOK_SECTION_OP( s_commitHook, op )
00331     {
00332         // Simulation is finished when a committed 'op' is a branch 
00333         // that jumps to an address 0.
00334         if( op->GetOpClass().IsBranch() && op->GetTakenPC().address == 0 ) {
00335             FinishThread( op->GetThread() );
00336         }
00337 
00338         m_forwardEmulator->OnCommit( op );
00339         m_emulator->Commit( &(*op), op->GetOpInfo() );
00340         op->GetInorderList()->Commit( op );
00341 
00342         // Decide the latency of commit and register a retire event. 
00343         int commitLatency = m_commitLatency;
00344         if( !m_fixCommitLatency && op->GetOpClass().IsStore() ){
00345             // The cache access of a store is done in MemOrderManager::Commit and 
00346             // its result is set to an op.
00347             int storeLatency = op->GetCacheAccessResult().latency;
00348             commitLatency = std::max( storeLatency, commitLatency );
00349         }
00350         EventPtr retireEvent( OpRetireEvent::Construct( op, this ) );
00351         op->AddEvent( retireEvent, GetLowerPipeline(), commitLatency );
00352     }
00353 }
00354 
00355 void Retirer::UpdateCommit()
00356 {
00357     int committedOps = 0;
00358     for( CommitingOps::iterator i = m_evaluated.committing.begin(); i != m_evaluated.committing.end(); i++ ){
00359 
00360         OpIterator op = *i;
00361 
00362         // Commit an op.
00363         Commit( op );
00364 
00365         ++m_numCommittedOps;
00366         ++committedOps;
00367 
00368         // The number of committed instructions are incremented when a head 
00369         // op of an instruction is committed because multiple ops may be 
00370         // generated from a instruction.
00371         if( op->GetNo() == 0 ) {
00372             ++m_numCommittedInsns;
00373         }
00374     }
00375 
00376     // Count cycles from a cycle when a last op is retired.
00377     if( committedOps > 0 ) {
00378         m_noCommittedCycle = 0;
00379     } else {
00380         ++m_noCommittedCycle;
00381     }
00382 }
00383 
00384 void Retirer::UpdateException()
00385 {
00386     if( m_evaluated.exceptionOccur ){
00387         OpIterator causer = m_evaluated.exceptionCauser;
00388         Recoverer* recoverer = causer->GetThread()->GetRecoverer();
00389         recoverer->RecoverException( causer );
00390         m_evaluated.exceptionOccur = false;
00391     }
00392 }
00393 
00394 // Check counters related to commit.
00395 void Retirer::CheckCommitCounters( int committedOps, InorderList* inorderList )
00396 {
00397     if( m_noCommittedCycle >= m_noCommitLimit ) {
00398         OpIterator uncommitted = inorderList->GetFrontOp();
00399         if( uncommitted.IsNull() ) {
00400             if( inorderList->IsEmpty() ){
00401                 THROW_RUNTIME_ERROR(
00402                     "InOrderList is empty and no op commits while %d cycle(numRetiredOp = %d). ",
00403                     m_noCommittedCycle, m_numCommittedOps
00404                 );
00405             }
00406             else{
00407                 THROW_RUNTIME_ERROR(
00408                     "No op committed while %d cycle. A next retireable op( the front of InOrderList ) is %s",
00409                     m_noCommittedCycle, inorderList->GetCommittedFrontOp()->ToString(6).c_str() 
00410                 );
00411             }
00412         }
00413         else {
00414             THROW_RUNTIME_ERROR(
00415                 "No op committed while %d cycle. Next committable op( the front of InOrderList ) is %s",
00416                 m_noCommittedCycle, uncommitted->ToString(6).c_str() 
00417             );
00418         }
00419     }
00420 }
00421 
00422 // Finish a thread.
00423 void Retirer::FinishThread( Thread* tread )
00424 {
00425     tread->Activate( false );
00426     Core* core = GetCore();
00427 
00428     // Search unfinished threads.
00429     bool active = false;
00430     for( int i = 0; i < core->GetThreadCount(); i++ ){
00431         if( core->GetThread(i)->IsActive() ){
00432             active = true;
00433         }
00434     }
00435 
00436     m_endOfProgram = !active;
00437 }
00438 

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