virtual InvalidateReply writeRemoteAction( const DataAccess& access ) { cache_iter_t cacheIter; bool noOtherCachesHaveLine = true; for ( cacheIter = allCaches->begin(); cacheIter != allCaches->end(); cacheIter++ ) { SMPCache<State, Addr_t> *otherCache = *cacheIter; if ( otherCache->CPUId == this->CPUId ) { continue; } State* otherLine = NULL; CacheResponse r = otherCache->L1cache->search( access.addr(), otherLine ); if ( r == MISSED_TO_MEMORY ) { // not found in this cache continue; } switch ( otherLine->getState() ) { case MESI_MODIFIED: case MESI_EXCLUSIVE: case MESI_SHARED: otherLine->invalidate(); noOtherCachesHaveLine = false; // have to keep searching to find all Shared copies break; case MESI_INVALID: // keep searching for more copies break; default: assert(false); } } // done with other caches return InvalidateReply( noOtherCachesHaveLine ); } // end writeRemoteAction()
virtual RemoteReadService readRemoteAction( const DataAccess& access ) { cache_iter_t cacheIter; for ( cacheIter = allCaches->begin(); cacheIter != allCaches->end(); cacheIter++ ) { SMPCache<State, Addr_t> *otherCache = *cacheIter; if ( otherCache->CPUId == this->CPUId ) { continue; } State* otherLine = NULL; CacheResponse r = otherCache->L1cache->search( access.addr(), otherLine ); if ( r == MISSED_TO_MEMORY ) { continue; // not found in this cache } // found in a remote cache! switch ( otherLine->getState() ) { case MESI_EXCLUSIVE: case MESI_MODIFIED: otherLine->changeStateTo( MESI_SHARED ); return RemoteReadService( false, true ); case MESI_SHARED: // everyone else will be in Shared state as well, so return now return RemoteReadService( true, false ); case MESI_INVALID: // keep searching for other copies break; default: assert(false); } } // done with other caches // this happens if everyone was MESI_INVALID return RemoteReadService( false, false ); } // end readRemoteAction()
/** Make a write request. * @param access the memory access being made * @param doStoreBufferAccess whether to use the det store buffer for this write */ virtual void write( const DataAccess& access, bool doStoreBufferAccess ) { State* myLine = NULL; CacheResponse r = L1cache->search( access.addr(), myLine ); if ( r != MISSED_TO_MEMORY ) { switch (r) { case L1_HIT: timeInMemoryHierarchy += L1_HIT_LATENCY; // default det cache latency is an L1 hit, so it doesn't matter whether we hit to a dirty line or not deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; break; case L2_HIT: { timeInMemoryHierarchy += L2_HIT_LATENCY; if ( myLine->isDirty() ) { deterministicTimeInMemoryHierarchy += L2_HIT_LATENCY; } else { deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; } break; } case L3_HIT: timeInMemoryHierarchy += L3_HIT_LATENCY; // shared cache hits aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; break; default: assert(false); } // we either hit somewhere in our private cache(s) or we hit in the shared cache, // but we may not have write permissions L1cache->access( access.addr(), myLine ); switch ( myLine->getState() ) { case MESI_SHARED: // upgrade miss numUpgradeMisses++; writeRemoteAction( access ); // invalidate other copies timeInMemoryHierarchy += REMOTE_HIT_LATENCY; myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } return; case MESI_EXCLUSIVE: // write hit case MESI_MODIFIED: numWriteHits++; // TODO: fix this duplication from the MESI_SHARED case myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } return; default: assert(false); } } // we didn't have the line at all - need to check for remote copies InvalidateReply inv_ack = writeRemoteAction( access ); // remote hits and missing to memory aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; if ( inv_ack.nobodyHasThisLine ) { numWriteMisses++; timeInMemoryHierarchy += MEMORY_ACCESS_LATENCY; } else { numWriteRemoteHits++; timeInMemoryHierarchy += REMOTE_HIT_LATENCY; } L1cache->access( access.addr(), myLine ); myLine->changeStateTo( MESI_MODIFIED ); if ( useDetStoreBuffers && doStoreBufferAccess ) { myLine->setDirty(); StoreBufferIsEmpty = false; } } // end write()
/** Perform a data read specified by the given `access'. */ virtual void read( const DataAccess& access ) { State* line = NULL; CacheResponse r = L1cache->search( access.addr(), line ); if ( r != MISSED_TO_MEMORY ) { // we hit somewhere in our private cache(s), or a shared cache numReadHits++; switch ( r ) { case L1_HIT: timeInMemoryHierarchy += L1_HIT_LATENCY; // default det cache latency is an L1 hit, so it doesn't matter whether we hit to a dirty line or not deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; return; case L2_HIT: { timeInMemoryHierarchy += L2_HIT_LATENCY; if ( line->isDirty() ) { deterministicTimeInMemoryHierarchy += L2_HIT_LATENCY; } else { deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; } return; } case L3_HIT: timeInMemoryHierarchy += L3_HIT_LATENCY; // shared cache hits aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; return; default: assert(false); } } // we missed, so check remote caches for data RemoteReadService rrs = readRemoteAction( access ); // remote hits and missing to memory aren't det deterministicTimeInMemoryHierarchy += L1_HIT_LATENCY; MESIState newMesiState = MESI_INVALID; if ( rrs.providedData == false ) { // No Valid Read-Reply: Need to get this data from Memory numReadMisses++; timeInMemoryHierarchy += MEMORY_ACCESS_LATENCY-1; /* NB: we always fetch from memory into Exclusive. */ newMesiState = MESI_EXCLUSIVE; } else if ( rrs.isShared ) { newMesiState = MESI_SHARED; numReadRemoteHits++; timeInMemoryHierarchy += REMOTE_HIT_LATENCY; } else { //Valid Read-Reply From Modified/Exclusive newMesiState = MESI_SHARED; numReadRemoteHits++; timeInMemoryHierarchy += REMOTE_HIT_LATENCY; } assert( newMesiState != MESI_INVALID ); // pull in the actual line L1cache->access( access.addr(), line ); line->changeStateTo( newMesiState ); } // end read()