src/Sim/Memory/Prefetcher/StreamPrefetcher.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 #include "Sim/Memory/Prefetcher/StreamPrefetcher.h"
00034 #include "Sim/Dumper/Dumper.h"
00035 
00036 
00037 using namespace Onikiri;
00038 
00039 //#define STREAM_PREFETCHER_DEBUG 1
00040 
00041 String StreamPrefetcher::Stream::ToString() const
00042 {
00043     String str;
00044 
00045     // Status
00046     str += "status: ";
00047     switch( status ){
00048     default:
00049     case SS_INVALID:
00050         str += "INVALID ";
00051         break;
00052     case SS_TRAINING:
00053         str += "TRAINING";
00054         break;
00055     case SS_MONITOR:
00056         str += "MONITOR ";
00057         break;
00058     }
00059 
00060     // Window
00061     str += "  addr: ";
00062     str += String().format( "%016llx", addr.address );
00063     str += "  dir: ";
00064     str += ascending ? "a" : "d";
00065     str += "  orig: ";
00066     str += String().format( "%016llx", orig.address );
00067 
00068     // Count
00069     str += "  count: ";
00070     str += String().format( "%d", count );
00071     return str;
00072 }
00073 
00074 
00075 StreamPrefetcher::StreamPrefetcher()
00076 {
00077     m_distance = 0;
00078     m_degree = 0;
00079     m_trainingWindowSize = 0;
00080     m_trainingThreshold = 0;
00081     m_streamTableSize = 0;
00082     m_effectiveDistance = 0;
00083     m_effectiveTrainingWindow = 0;
00084 
00085     m_numMonitioredStream = 0;
00086     m_numAllocatedStream = 0;
00087     m_numTrainingAccess = 0;
00088     m_numAlocatingAccess = 0;
00089                 
00090     m_numAscendingMonitioredStream = 0;
00091     m_numDesscendingMonitioredStream = 0;
00092     
00093     m_numAvgMonitoredStreamLength = 0.0;
00094 }
00095 
00096 
00097 StreamPrefetcher::~StreamPrefetcher()
00098 {
00099     if( m_numMonitioredStream ){
00100         m_numAvgMonitoredStreamLength = 
00101             (double)m_numPrefetch / (double)m_numMonitioredStream;
00102     }
00103 
00104     ReleaseParam();
00105 }
00106 
00107 
00108 // --- PhysicalResourceNode
00109 void StreamPrefetcher::Initialize(InitPhase phase)
00110 {
00111     PrefetcherBase::Initialize( phase );
00112 
00113     if(phase == INIT_PRE_CONNECTION){
00114         
00115         LoadParam();
00116 
00117         // Setup remaining members from loaded parameters.
00118         m_streamTable.construct( m_streamTableSize );
00119         m_effectiveDistance = m_distance * m_lineSize;
00120         m_effectiveTrainingWindow = m_lineSize * m_trainingWindowSize;
00121 
00122     }
00123     else if(phase == INIT_POST_CONNECTION){
00124     
00125     }
00126 }
00127 
00128 
00129 // Returns whether the 'addr' is in a window specified 
00130 // by the remaining arguments or not. The 'ascending' means
00131 // a direction of a window. 
00132 bool StreamPrefetcher::IsInWindow( u64 addr, u64 start, u64 windowSize, bool ascending )
00133 {
00134     if( ascending ){
00135         return ( start <= addr && addr < start + windowSize );
00136     }
00137     else{
00138         return ( start - windowSize <= addr && addr < start );
00139     }
00140 }
00141 
00142 
00143 bool StreamPrefetcher::IsInWindow( const Addr& addr, const Addr& start, u64 windowSize, bool ascending )
00144 {
00145     if( addr.pid != start.pid )
00146         return false;
00147     
00148     u64 rawAddr  = MaskLineOffset( addr.address  );
00149     u64 rawStart = MaskLineOffset( start.address );
00150     return IsInWindow( rawAddr, rawStart, windowSize, ascending );
00151 }
00152 
00153 
00154 // Do prefetch an address specified by the 'stream' and update the 'stream'. 
00155 void StreamPrefetcher::Prefetch( const CacheAccess& kickerAccess,Stream* stream )
00156 {
00157     for( int i = 0; i < m_degree; i++ ){
00158 
00159         CacheAccess prefetch;
00160         prefetch.op = kickerAccess.op;
00161         prefetch.type = CacheAccess::OT_PREFETCH;
00162         
00163         // Prefetch 'end' point of a window.
00164         prefetch.address = stream->addr;
00165         if( stream->ascending )
00166             prefetch.address.address += m_effectiveDistance;
00167         else
00168             prefetch.address.address -= m_effectiveDistance;
00169 
00170         PrefetcherBase::Prefetch( prefetch );
00171         //m_prefetchTarget->Read( prefetch, NULL );
00172 
00173 #ifdef STREAM_PREFETCHER_DEBUG
00174         g_env.Print( ( String( "  prefetch\t" ) + prefetch.address.ToString() + "\n" ).c_str() );
00175 #endif
00176 
00177         // Update a stream
00178         stream->addr.address += 
00179             stream->ascending ? m_lineSize : -m_lineSize;
00180 
00181     }
00182 
00183     IncrementPrefetchNum();
00184 }
00185 
00186 
00187 // Check and update entries with MONITOR status in the stream table.
00188 // Returns whether any entries are updated or not.
00189 bool StreamPrefetcher::UpdateMonitorStream( const CacheAccess& access )
00190 {
00191     Addr missAddr = access.address;
00192     missAddr.address = MaskLineOffset( missAddr.address );
00193 
00194     // Monitor
00195     for( size_t i = 0; i < m_streamTable.size(); i++ ){
00196         Stream* stream = &m_streamTable[i];
00197         if( stream->status != SS_MONITOR )
00198             continue;
00199 
00200         // Check a missed address is in a prefetch window.
00201         if( !IsInWindow( missAddr, stream->addr, m_effectiveDistance, stream->ascending ) ){
00202             continue;
00203         }
00204 
00205 #ifdef STREAM_PREFETCHER_DEBUG
00206         g_env.Print( 
00207             ( String( "  monitor\t" ) + stream->ToString() + "\n" ).c_str() 
00208             );
00209 #endif
00210 
00211         // Prefetch
00212         // Note: The 'Prefetch' method may update a entry in the stream table.
00213         Prefetch( access, stream );
00214 
00215         // Update the table
00216         m_streamTable.touch( i );
00217         stream->count++;
00218 
00219         return true; // A prefetch process is finished.
00220     }
00221 
00222     return false;
00223 }
00224 
00225 
00226 // Check and update entries with SS_TRAINING status in the stream table.
00227 bool StreamPrefetcher::UpdateTrainingStream( const CacheAccess& access )
00228 {
00229     Addr missAddr = access.address;
00230     missAddr.address = MaskLineOffset( missAddr.address );
00231 
00232     for( size_t i = 0; i < m_streamTable.size(); i++ ){
00233         Stream* stream = &m_streamTable[i];
00234         if( stream->status != SS_TRAINING )
00235             continue;
00236 
00237         u64 window = m_effectiveTrainingWindow;
00238         const Addr& start = stream->orig;
00239 
00240         // Check a missed address is in a training window.
00241         bool inWindow  = false;
00242         bool ascending = false;
00243         if( IsInWindow( missAddr, start, window, true ) ){
00244             inWindow  = true;
00245             ascending = true;
00246         }
00247         else if( IsInWindow( missAddr, start, window, false ) ){
00248             inWindow  = true;
00249             ascending = false;
00250         }
00251 
00252         if( !inWindow )
00253             continue;
00254 
00255 #ifdef STREAM_PREFETCHER_DEBUG
00256         g_env.Print( ( String( "  train\t" ) + missAddr.ToString() + " " + stream->ToString() + "\n" ).c_str() );
00257 #endif
00258 
00259         // Decide a stream direction of a stream when 
00260         // an access is a first access (stream->count == 0)
00261         // in a training mode.
00262         if( stream->count == 0 ){
00263             stream->ascending = ascending;
00264         }
00265 
00266         if( stream->ascending == ascending ){
00267             // Update the training count.
00268             stream->count++;
00269         }
00270         else{
00271             // Reset a counter and a direction flag.
00272             stream->ascending = ascending;
00273             stream->count = 0;
00274             continue;   // A prefetch process is continued.
00275         }
00276 
00277         // State transition to MONITOR status.
00278         if( stream->count >= m_trainingThreshold ){
00279             stream->status = SS_MONITOR;
00280             m_numMonitioredStream++;
00281             if( ascending )
00282                 m_numAscendingMonitioredStream++;
00283             else
00284                 m_numDesscendingMonitioredStream++;
00285 
00286 #ifdef STREAM_PREFETCHER_DEBUG
00287             g_env.Print( ( String( "  to monitor\t" ) + missAddr.ToString() + " " + stream->ToString() + "\n" ).c_str() );
00288 #endif
00289         }
00290 
00291         // Training
00292         m_numTrainingAccess++;
00293         m_streamTable.touch( i );
00294         //stream->addr = missAddr;
00295 
00296         return true; // A prefetch process is finished.
00297     }
00298 
00299     return false;
00300 }
00301 
00302 
00303 // Allocate a new entry in the stream table.
00304 void StreamPrefetcher::AllocateStream( const CacheAccess& access )
00305 {
00306     Addr missAddr = access.address;
00307     missAddr.address = MaskLineOffset( missAddr.address );
00308 
00309     Stream stream;
00310     stream.addr = missAddr;
00311     stream.orig = missAddr;
00312     stream.status = SS_TRAINING;
00313     stream.count = 0;
00314 
00315     int target = (int)m_streamTable.replacement_target();
00316     m_streamTable[ target ] = stream;
00317     m_streamTable.touch( target );
00318     m_numAlocatingAccess++;
00319     m_numAllocatedStream++;
00320 
00321 #ifdef STREAM_PREFETCHER_DEBUG
00322     g_env.Print( ( String( "  alloc\t" ) + missAddr.ToString() + " " + stream.ToString() + "\n" ).c_str() );
00323 #endif
00324 }
00325 
00326 
00327 // This method is called by any cache accesses occurred in a connected cache.
00328 void StreamPrefetcher::OnCacheAccess( 
00329     Cache* cache, 
00330     const CacheAccess& access,
00331     bool hit
00332 ){
00333     if( !m_enabled ){
00334         return;
00335     }
00336 
00337 #ifdef STREAM_PREFETCHER_DEBUG
00338     g_env.Print( ( String( "access\t" ) + access.address.ToString() + "\n" ).c_str() );
00339 #endif
00340 
00341     bool streamTableHit = false;
00342 
00343     // Update monitor streams.
00344     if( UpdateMonitorStream( access ) ){
00345         streamTableHit = true;
00346     }
00347 
00348     // Training and allocation are done by a cache missed access only.
00349     if( hit ){
00350         return;
00351     }
00352 
00353     // Update training streams.
00354     if( UpdateTrainingStream( access ) ){   
00355         streamTableHit = true;
00356     }
00357 
00358     // Allocate a new stream.
00359     if( !streamTableHit ){
00360         AllocateStream( access );
00361     }
00362 }
00363 

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