#include "interface.h" // Do NOT edit interface .h #include "sample_prefetcher.h" MyStream *pref1; // This is the L1 prefetcher MyStream *pref2; // Thss is the L2 prefetcher using namespace std; INT32 AddrOperation::GetLog2(ADDRINT blocksize) { UINT32 i = 0; if( (blocksize & (blocksize-1)) != 0) return -1; while(blocksize != 0) { blocksize >>= 1; i++; } return i-1; } /////////////////////////////////////////////////////////////////////////////// // Methods of Class MyStream /////////////////////////////////////////////////////////////////////////////// /************************************************************************************* * MSHR::AddEntry * * Insert an entry to MSHR, replace LRU if necessary * ************************************************************************************/ MSHR::Node* MSHR::AddEntry(ADDRINT addr) { Node *node = Find(addr); if(node != NULL) { return node; } else { node = mListTail; MSHREntry* entry = &(node->_item); DelFrmMSHRlist(entry->addr); entry->addr = addr; AddToMSHRlist(entry->addr, node); BringsToHead(node); return node; } } /************************************************************************************* * MSHR::AddEntry * * Delete an entry * ************************************************************************************/ void MSHR::DelEntry(ADDRINT addr) { Node *node = Find(addr); if(node != NULL) { MSHREntry* entry = &(node->_item); DelFrmMSHRlist(entry->addr); entry->addr = 0; BringsToTail(node); } else { return; } } /************************************************************************************* * MSHR::Find, AddToMSHRlist, DelFrmMSHRlist * * Address indexing operations * ************************************************************************************/ MSHR::Node* MSHR::Find( ADDRINT addr ) { ADDRINT baddr = AddrOperation::GetCacheBlockAddr(addr, blocksize); iter = mshrlist.find(baddr); if( iter != mshrlist.end() ) { return iter->second; } return NULL; } void MSHR::AddToMSHRlist( ADDRINT addr, Node *tmp ) { ADDRINT baddr = AddrOperation::GetCacheBlockAddr(addr, blocksize); mshrlist[ baddr ] = tmp; } void MSHR::DelFrmMSHRlist( ADDRINT addr ) { ADDRINT baddr = AddrOperation::GetCacheBlockAddr(addr, blocksize); mshrlist.erase( baddr ); } void MSHR::ShowMSHR(stringstream& ss) { Node *node = mListHead; ss << "ShowMSHR:"; while(node != NULL) { MSHREntry *entry = &(node->_item); ss << hex << "(" << entry->addr << ")"; node = node->_next; } } /////////////////////////////////////////////////////////////////////////////// // Methods of Class MyStream /////////////////////////////////////////////////////////////////////////////// /************************************************************************************* * MyStream::OnMiss * * Miss handing: * 1.Look for the stream entry which monitors the miss, if found, go to 2 * if not found, use the not MSHR filtered miss to train new stream; * 2.Use the miss (MSHR filtered or not) to revise/detect constant stride * 3.Issue prefetch requests: * If the miss is regarded as a late prefetch (prefetched, but not in cache now, detect in AccessTrainedEntry function), * then ignore it, no prefetches made * Otherwise, do normal prefetch requests * ************************************************************************************/ void MyStream::OnMiss(stringstream& ss, PrefetchData_t& prefdata, vector& requests, COUNTER cycle, bool isfiltered) { ADDRINT miss_baddr; // block address of the miss MyStreamEntry *entry = NULL; //ignore the first cycle if(prefdata.LastRequestCycle == 0) return; //clear the result first requests.clear(); //update the prefetch table miss_baddr = GetBlockFromAddr(prefdata.DataAddr); bool islatepref; if(!isfiltered) entry = _stream_table->AccessTrainedEntry(miss_baddr, islatepref, cycle); if( entry == NULL ) { /****** if not found in streams, train it in training table *****/ if(!isfiltered) { // train stream in the training table: MyTrainingTable::Node *tnode = _training_table->AccessEntry(0, miss_baddr, cycle); // if the training succeeds, then move the entry to stream table: if( (tnode != NULL) && tnode->_item.trained ) { MyStreamEntry sentry; // copy data: MoveFromTrainingToStream(tnode->_item, sentry); // add a stream entry to stream table: _stream_table->AddEntry(sentry, cycle); _stream_table->ShowAll(); // clear up the training entry tnode->_item.Clear(); _training_table->BringsToTail(tnode); } } return; } ConstantStrideRevise(entry, prefdata.DataAddr); // detect for constant stride ConstantStrideDetect(entry, prefdata.DataAddr); // update the original access is is repeating stream if(entry->isrepeat) { entry->original_baddr = GetBAddrFromAddr(prefdata.DataAddr); entry->isrepeat = false; } // update the last access _stream_table->SetLastAccessAddressToDist(*entry, prefdata.DataAddr); if(!isfiltered) { if(!islatepref) MyIssuePrefetches(ss, entry, cycle); } } /************************************************************************************* * MyStream::OnHit * * Hit handing: * 1.Look for the stream entry which monitors the hit address, if found, go to 2 * 2.Use the hit to revise/detect constant stride * 3.If it's a repeat stream and the first time hit, set the original-addr with the hit address * 4.Issue prefetch requests: * If the hit is regarded as a early prefetch (hit, but fall behind the stream's region, detect in AccessTrainedEntry function), * then ignore it, no prefetches made * Otherwise, do normal prefetch requests * ************************************************************************************/ void MyStream::OnHit(stringstream& ss, PrefetchData_t& prefdata, vector& requests, COUNTER cycle) { ADDRINT hit_baddr; // block address of the miss //ignore the first cycle if(prefdata.LastRequestCycle == 0) return; //clear the result first requests.clear(); //update the prefetch table bool islatepref; hit_baddr = GetBlockFromAddr(prefdata.DataAddr); MyStreamEntry *entry = _stream_table->AccessTrainedEntry(hit_baddr, islatepref, cycle); ss << "on hit,"; if(entry == NULL) { return; } ConstantStrideRevise(entry, prefdata.DataAddr); // detect for constant stride ConstantStrideDetect(entry, prefdata.DataAddr); // update the original access is is repeating stream if(entry->isrepeat) { entry->original_baddr = GetBAddrFromAddr(prefdata.DataAddr); entry->isrepeat = false; } // update the last access _stream_table->SetLastAccessAddressToDist(*entry, prefdata.DataAddr); // issue prefetch requests if(!islatepref) MyIssuePrefetches(ss, entry, cycle); } /************************************************************************************* * MyStream::MyIssuePrefetches * 1. Get prefetch candidates; * If there's a more than 1 block stride confirmed, then prefetch p+s, p+2s, p+d*s, where d is the prefetch degree (4) * otherwise prefetch p+64, p+2*64, ..p+d*64, where 64 is the block size * 2. Issue prefetch requests; * By calling IssueL2Prefetch() function, it makes prefetches. Stop when the function return the flag of queue full. * 3. Forward the monitored region; * 4. Check for repeated stream. If found, trigger early prefetches * Detail of check is in LookForRepeatStream function. * ************************************************************************************/ void MyStream::MyIssuePrefetches(stringstream& ss, MyStreamEntry *entry, COUNTER cycle) { if(entry == NULL) return; vector requests; //1. Get prefetch candidates; GetPrefetchCandidates(ss, entry, requests, cycle); //2. Issue prefetch requests: int prefmade = 0; for(unsigned int j = 0; j < requests.size(); j++) { if(j==0) ss << " ---> prefetch "; bool queuefull = IssueL2Prefetch(cycle, requests[j]); if(queuefull) { ss << "q full,"; break; } else { ss << hex << requests[j] << ","; prefmade ++; IncPrefnum(); if(_enable_stream_merge) { SetPrefetchBit(1, requests[j]); } } } //3. forward the monitored region _stream_table->ForwardTrackingRegion(entry, _stream_prefetch_distance, prefmade); _stream_table->ShowMyStreamEntry(*entry); //4. check for possible stream repeat and early prefetches if(_enable_stream_repeat) { vector new_requests; MyStreamEntry *repeat_entry = _stream_table->LookForRepeatStream(new_requests, *entry); unsigned int j; for( j = 0; j < new_requests.size(); j++) { if(j==0) ss << " ---> repeat prefetch "; bool queuefull = IssueL2Prefetch(cycle, new_requests[j]); if(queuefull) { ss << "q full,"; break; } else { ss << hex << new_requests[j] << ","; IncPrefnum(); } } if(j >0) { ADDRINT region_start_baddr = _stream_table->GetRegionStartBAddrFromBDist(*repeat_entry); ADDRINT last_access_addr = _stream_table->GetLastAccessAddressFromDist(*repeat_entry); repeat_entry->region_end_addr = new_requests[j-1]; _stream_table->SetRegionStartBAddrToBDist(*repeat_entry, region_start_baddr); _stream_table->SetLastAccessAddressToDist(*repeat_entry, last_access_addr); repeat_entry->isrepeat = true; cout << "repeat stream:"; _stream_table->ShowMyStreamEntry(*repeat_entry); } } } /************************************************************************************* * MyStream::GetPrefetchCandidates * If there's a more than 1 block stride confirmed, then prefetch p+s, p+2s, p+d*s, where d is the prefetch degree (4) * otherwise prefetch p+64, p+2*64, ..p+d*64, where 64 is the block size * ************************************************************************************/ void MyStream::GetPrefetchCandidates(stringstream& ss, MyStreamEntry *entry, vector& requests, COUNTER cycle) { UINT32 j; ADDRINT stride; ADDRINT last_access_addr; ADDRINT last_prefetch_addr; if(entry == NULL) return; requests.clear(); ss << " recommend "; //prefetch for "pref_degree" of next addresses stride = (entry->stride_confirm)?entry->stride:_blocksize; // >= 1 block last_access_addr = _stream_table->GetLastAccessAddressFromDist(*entry); if(entry->ascending) { ADDRINT maxaddr = ( GetAddrFromBAddr(GetBAddrFromAddr(entry->region_end_addr)+1) ) - 1; ADDRINT num_stride = (maxaddr - last_access_addr)/stride; last_prefetch_addr = last_access_addr + (num_stride * stride); } else { ADDRINT minaddr = GetAddrFromBAddr( GetBAddrFromAddr(entry->region_end_addr) ); ADDRINT num_stride = (last_access_addr - minaddr)/stride; last_prefetch_addr = last_access_addr - (num_stride * stride); } ADDRINT pref_addr; for(j = 1; j <= _pref_degree; j++) { if(entry->ascending) pref_addr = (last_prefetch_addr + j*stride); else pref_addr = (last_prefetch_addr - j*stride); ss << hex << pref_addr << ","; //entry->prefmade ++; requests.push_back( pref_addr ); } } /************************************************************************************* * MyStream::ClearConstantStride * Reset the constant stride related bits * ************************************************************************************/ void MyStream::ClearConstantStride(MyStreamEntry *entry) { entry->stride_confirm = false; entry->csd1 = false; entry->csd2 = false; entry->stride = _blocksize; } /************************************************************************************* * MyStream::ConstantStrideRevise * Check for any hit/miss which may violate the constant stride. * If so, reset the stride to 1 block and keep detecting for constant stride * ************************************************************************************/ void MyStream::ConstantStrideRevise(MyStreamEntry* entry, ADDRINT addr) { if(!_enable_constant_stride) return; ADDRINT stride = (entry->stride_confirm)?entry->stride:_blocksize; // >= 1 block if(entry->ascending) { if( entry->stride_confirm && (entry->stride>_blocksize) && (addr <= entry->region_end_addr) ) { if( ((entry->region_end_addr - addr) % stride) != 0 ) { ClearConstantStride(entry); } } } else { if( entry->stride_confirm && (entry->stride>_blocksize) && (addr >= entry->region_end_addr) ) { if( ((addr - entry->region_end_addr) % stride) != 0 ) { ClearConstantStride(entry); } } } } /************************************************************************************* * MyStream::ConstantStrideDetect * Use the last 3 accesses (hit/miss) to detect a constant stride. * If two stride are identical, then turn on the stride_confirm bit. * In case the stride is less than 1 block, set it to 1 block; otherwise keep the detected stride * If no two consecutive identical strides found, keep looking for. * ************************************************************************************/ void MyStream::ConstantStrideDetect(MyStreamEntry* entry, ADDRINT addr) { if(!_enable_constant_stride) return; if(entry == NULL) return; if(entry->stride_confirm && (entry->stride > _blocksize) ) return; _stream_table->ShowMyStreamEntry(*entry); ADDRINT old_last_access_addr = _stream_table->GetLastAccessAddressFromDist(*entry); signed long long diff = (signed long long)addr - (signed long long)old_last_access_addr; ADDRINT udiff = (diff>0)?diff:-diff; if( !entry->csd1 ) { _stream_table->SetLastAccessAddressToDist(*entry, addr); entry->csd1 = true; } else if( entry->csd1 && !entry->csd2 ) { // if the stride is opposite to the direction, then quit stride detection, use 1 block as stride if( (entry->ascending && (diff<=0)) || (!entry->ascending && (diff>=0)) ) { entry->stride_confirm = false; entry->stride = _blocksize; } else { entry->stride = udiff; entry->csd2 = true; } } else { if( (entry->ascending && (diff<=0)) || (!entry->ascending && (diff>=0)) || (udiff != entry->stride) ) { entry->stride_confirm = false; entry->stride = _blocksize; entry->csd2 = false; } else { //found a constant stride in byte address: if the stride <= 1 block, set it as 1 block. entry->stride_confirm = true; if(udiff>_blocksize) { entry->stride = udiff; //cout << "found constant stride " << dec << udiff << ","; } else { //cout << "found constant stride " << dec << udiff << ","; entry->stride = _blocksize; } } } _stream_table->SetLastAccessAddressToDist(*entry, addr); _stream_table->ShowMyStreamEntry(*entry); } /************************************************************************************* * MyStream::OnPrefetchHit * * Prefetch Hit handing: * For statistics purpose only * ************************************************************************************/ void MyStream::OnPrefetchHit(stringstream& ss, PrefetchData_t& prefdata, vector& requests, COUNTER cycle) { //ignore the first cycle if(prefdata.LastRequestCycle == 0) return; //clear the result first requests.clear(); //increment the counter } /************************************************************************************* * MyStream::MoveFromTrainingToStream * * After a stream is trained, move it from training table to stream table; * Set the region end address of the stream as end_addr + (distance between end_addr and second_addr) * ************************************************************************************/ void MyStream::MoveFromTrainingToStream(MyTrainingEntry& tent, MyStreamEntry& sent) { if(!tent.trained) return; sent.Clear(); sent.original_baddr = tent.start_baddr; ADDRINT region_end_baddr = tent.start_baddr + tent.end_baddr_dist + (tent.end_baddr_dist - tent.second_baddr_dist); sent.region_end_addr = GetAddrFromBAddr(region_end_baddr); sent.ascending = tent.ascending; _stream_table->SetRegionStartBAddrToBDist(sent, sent.original_baddr); _stream_table->SetLastAccessAddressToDist(sent, sent.region_end_addr); } /////////////////////////////////////////////////////////////////////////////// // Methods of Class MyTrainingTable /////////////////////////////////////////////////////////////////////////////// /************************************************************************************* * MyTrainingTable::RenewEntry * * Reclaim the failed training entry: * Shift out start_addr, use the second and end address as the new start and second address * If the distance of the second and end address exceeds the 16 blocks, only set the start addr * ************************************************************************************/ void MyTrainingTable::RenewEntry(MyTrainingEntry& entry, COUNTER cycle) { INT32 end_second_dist = entry.end_baddr_dist - entry.second_baddr_dist; ADDRINT second_baddr = entry.GetSecondBAddr(); ADDRINT end_baddr = entry.GetEndBAddr(); entry.Clear(); if( (end_baddr >= second_baddr - Common::STREAM_MAX_NEIGHBOR_DISTANCE) && (end_baddr <= second_baddr + Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) { entry.start_baddr = second_baddr; entry.second_baddr_dist = end_second_dist; } else { entry.start_baddr = end_baddr; } } /************************************************************************************* * MyTrainingTable::AccessEntry * * Train the stream: * 1.Look for the entry into which the new miss falls into its training window (+/- 16 blocks), * if none found, create a new entry; * 2.If it’s the second address, stores it in the second_addr field; * 3.If it’s the third address, check whether the three misses are in same direction. * If so, create a stream entry, set the ascending bit and release the training entry. * Otherwise, go to 3; * 4 If the address distance between the start_addr and second_addr is +/- 1, * turn on the noise flag, ignore the second address, * and use the third one as the second to continue training. * ************************************************************************************/ MyTrainingTable::Node * MyTrainingTable::AccessEntry(UINT32 threadId, ADDRINT baddr, COUNTER cycle) { if(baddr == 0) return NULL; /* 1.Look for the entry into which the new miss falls into its training window (+/- 16 blocks), */ Node* node = mListHead; while (node != NULL) { MyTrainingEntry* ent = &(node->_item); // end of search if start_addr =0 if(ent->start_baddr == 0) { node = NULL; break; } // check whether it falles into +/- 16 blocks of start_addr, to get trained if( (baddr >= ent->start_baddr - Common::STREAM_MAX_NEIGHBOR_DISTANCE) && (baddr <= ent->start_baddr + Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) { break; } node=node->_next; } MyTrainingEntry* entry; // If none found, allocate an entry for it to train if ( node == NULL ) { /// Replace tail node = mListTail; entry = &(node->_item); // create a new entry entry->Clear(); entry->start_baddr = baddr; ShowEntry(*entry); } // If found one entry existing, train the stream else { entry = &(node->_item); // proceed only when the addr not equal to start_addr and second_addr, but within +/- 16 blocks if( (baddr != entry->start_baddr) && (baddr != entry->GetSecondBAddr()) && ( baddr >= entry->start_baddr - Common::STREAM_MAX_NEIGHBOR_DISTANCE ) && ( baddr <= entry->start_baddr + Common::STREAM_MAX_NEIGHBOR_DISTANCE ) ) { /* 2.If it’s the second address, stores it in the second_addr field; */ if( entry->second_baddr_dist == 0) { entry->second_baddr_dist = entry->GetBAddrDist(baddr); entry->noise_flag = 0; } /* 3 */ else { entry->end_baddr_dist = entry->GetBAddrDist(baddr); INT32 end_second_dist = entry->end_baddr_dist - entry->second_baddr_dist; // Case 1: if(entry->second_baddr_dist > 1) { if(end_second_dist >= 1) { entry->trained = true; entry->ascending = true; //trained } else if (end_second_dist < -1) { RenewEntry(*entry, cycle); } else if(end_second_dist == -1) { if(entry->noise_flag) { } else { RenewEntry(*entry, cycle); } } } // Case 2: else if(entry->second_baddr_dist == 1) { if(end_second_dist >= 1) { entry->trained = true; //trained entry->ascending = true; } else if(end_second_dist < 0) { if(_enable_noise_removal) { /* 4. turn on the noise flag, ignore the second address */ entry->second_baddr_dist += end_second_dist; entry->noise_flag = true; } else { RenewEntry(*entry, cycle); } } } // Case 3: else if(entry->second_baddr_dist == -1) { if(end_second_dist <= -1) { entry->trained = true; //trained entry->ascending = false; } else if(end_second_dist > 0) { if(_enable_noise_removal) { /* 4. turn on the noise flag, ignore the second address */ entry->second_baddr_dist += end_second_dist; entry->noise_flag = true; } else { RenewEntry(*entry, cycle); } } } // Case 4: else if(entry->second_baddr_dist < -1) { if(end_second_dist <= -1) { entry->trained = true; //trained entry->ascending = false; } else if (end_second_dist > 1) { RenewEntry(*entry, cycle); } else if(end_second_dist == 1) { if(entry->noise_flag) { } else { RenewEntry(*entry, cycle); } } } } } else { /* NA */ } } ShowEntry(*entry); BringsToHead(node); return node; } void MyTrainingTable::ShowEntry(MyTrainingEntry& entry) { return; cout << hex << (entry.start_baddr << _blockbitnum) << "," << dec << entry.second_baddr_dist << "," << entry.end_baddr_dist << "," << dec << entry.trained << "," << entry.ascending << ","; cout << endl; } void MyTrainingTable::ShowTable() { return; Node *node = mListHead; cout << "StreamTrainingTable:" << endl; while(node != NULL) { if(node->_item.start_baddr == 0) break; ShowEntry(node->_item); node = node->_next; } } ////////////////////////////////////////////////////////////////////////////////////// // Methods of class MyStreamPrefetchTable, the stream table // // Provides functions to make prefetch requests ////////////////////////////////////////////////////////////////////////////////////// /************************************************************************************* * MyTrainingTable::AddEntry * * Add a new trained entry into stream table, replacing the LRU, and move to MRU * ************************************************************************************/ void MyStreamPrefetchTable::AddEntry(MyStreamEntry& newentry, COUNTER cycle) { /// Replace tail Node *node = mListTail; // clone the new entry node->_item = newentry; BringsToHead(node); } /************************************************************************************* * MyStreamPrefetchTable::AccessTrainedEntry * * Look for a stream entry that monitors the access, returns if found * To handle with the hit/miss that falls behind the prefetch region, * * one extra window with size of prefetch degree is given to collect the possible * late prefetches (miss, behind the region) or early prefetches (hit, behind the region) * These special miss/hit will be used in constant stride detection/revise, but not trigger prefetches * ************************************************************************************/ MyStreamEntry* MyStreamPrefetchTable::AccessTrainedEntry(ADDRINT baddr, bool& islatepref, COUNTER cycle) { if(baddr == 0) return NULL; islatepref = false; Node* node = mListHead; while (node != NULL) { MyStreamEntry* ent = &(node->_item); // end of search if start_addr =0 if(ent->original_baddr == 0) { return NULL; } ADDRINT region_start_baddr = GetRegionStartBAddrFromBDist(*ent); ADDRINT region_end_baddr = GetBAddrFromAddr(ent->region_end_addr); ADDRINT stride = (ent->stride_confirm)?ent->stride:_blocksize; // >= 1 block if(ent->ascending) { if( (baddr >= region_start_baddr) && (baddr <= region_end_baddr) ) { BringsToHead(node); return ent; } else if( (baddr < region_start_baddr) && (baddr > region_start_baddr - GetBAddrFromAddr(_pref_degree * stride)) ) { islatepref = true; return ent; } } else { if( (baddr <= region_start_baddr) && (baddr >= region_end_baddr) ) { BringsToHead(node); return ent; } else if( (baddr > region_start_baddr) && (baddr < region_start_baddr + GetBAddrFromAddr(_pref_degree * stride)) ) { islatepref = true; return ent; } } node=node->_next; } return NULL; } /************************************************************************************* * MyStreamPrefetchTable::FindPrefetchStream * * Look for the stream which may have issues prefetch for the given addr. * This is done by checking the boundary of original_baddr and region_end_addr * If the given addr falls on the region, it would have been prefetched by the stream. * This function is used in statistics. * ************************************************************************************/ MyStreamPrefetchTable::Node * MyStreamPrefetchTable::FindPrefetchStream(ADDRINT baddr) { if(baddr == 0) return NULL; Node* node = mListHead; while (node != NULL) { MyStreamEntry* ent = &(node->_item); // end of search if start_addr =0 if(ent->original_baddr == 0) { return NULL; } if(ent->ascending) { // the second_addr of trained stream is the last block which is NOT prefetched //if((baddr > ent->second_addr) && (baddr <= ent->end_addr)) { if((baddr > ent->original_baddr) && (baddr <= GetBAddrFromAddr(ent->region_end_addr)) ) { return node; } } else { if((baddr < ent->original_baddr) && (baddr >= GetBAddrFromAddr(ent->region_end_addr)) ) { return node; } } node=node->_next; } return NULL; } /************************************************************************************* * MyStreamPrefetchTable::ForwardTrackingRegion * * After prefetches have been made, move forward the stream's monitored region. * How many blocks to move depends on the number of prefetches made and the stride of the stream. * For example, 8 prefetches are made and stride is 3 blocks, then move the region by 24 blocks * When startup, the region size may be less than the prefetch distance (64*stride), in this case, only the region_end_addr * increases/decreases. Until the region size becomes more or equal to 64*stride, move both boundaries to keep the region size 64*stride. * ************************************************************************************/ void MyStreamPrefetchTable::ForwardTrackingRegion(MyStreamEntry* entry, UINT32 prefdistance, UINT32 prefdegree) { ADDRINT stride; ADDRINT last_prefetch_addr; ADDRINT region_start_baddr; ADDRINT last_access_addr; if(entry == NULL) return; stride = (entry->stride_confirm)?entry->stride:_blocksize; // >= 1 block last_access_addr = GetLastAccessAddressFromDist(*entry); region_start_baddr = GetRegionStartBAddrFromBDist(*entry); if(entry->ascending) { ADDRINT maxaddr = ( GetAddrFromBAddr(GetBAddrFromAddr(entry->region_end_addr)+1) ) - 1; ADDRINT num_stride = (maxaddr - last_access_addr)/stride; last_prefetch_addr = last_access_addr + (num_stride * stride); entry->region_end_addr = last_prefetch_addr + prefdegree*stride; } else { ADDRINT minaddr = GetAddrFromBAddr( GetBAddrFromAddr(entry->region_end_addr) ); ADDRINT num_stride = (last_access_addr - minaddr)/stride; last_prefetch_addr = last_access_addr - (num_stride * stride); entry->region_end_addr = last_prefetch_addr - prefdegree*stride; } SetLastAccessAddressToDist(*entry, last_access_addr); if(entry->ascending) { //keep prefdistance the max distance ADDRINT num_stride = ( entry->region_end_addr - GetAddrFromBAddr(region_start_baddr) )/stride; if(num_stride > prefdistance) { region_start_baddr = GetBAddrFromAddr(entry->region_end_addr - prefdistance*stride); } SetRegionStartBAddrToBDist(*entry, region_start_baddr); } else { //keep prefdistance the max distance ADDRINT num_stride = ( GetAddrFromBAddr(region_start_baddr) - entry->region_end_addr )/stride; if(num_stride > prefdistance) { region_start_baddr = GetBAddrFromAddr(entry->region_end_addr + prefdistance*stride); } SetRegionStartBAddrToBDist(*entry, region_start_baddr); } ShowMyStreamEntry(*entry); } /************************************************************************************* * MyStreamPrefetchTable::ShowAll, ShowMyStreamEntry * * Output the stream table on screen. * ************************************************************************************/ void MyStreamPrefetchTable::ShowMyStreamEntry(MyStreamEntry& entry) { return; cout << hex << (entry.original_baddr << _blockbitnum) << "," << dec << entry.region_start_baddr_dist << "," << hex << entry.region_end_addr << "," << GetLastAccessAddressFromDist(entry) << "," << dec << entry.stride << "," << entry.ascending << "," << entry.stride_confirm << "," << endl; } void MyStreamPrefetchTable::ShowAll() { return; Node *node = mListHead; cout << "StreamPrefetchTable:" << endl; while(node != NULL) { if(node->_item.original_baddr == 0) break; ShowMyStreamEntry(node->_item); node = node->_next; } } /************************************************************************************* * MyStreamPrefetchTable::LookForRepeatStream * * Detect a repeated stream and trigger early prefetches of the starting area of the stream * After one stream moves forward by prefetch degree, it checks for another stream which * has almost the same orginal_addr and almost the same last access address, * also both entries are longer than a threshold ( 2*prefetch_distance in this prefetcher). * If such a stream is found, then the current stream can be regarded as repetition of the old stream. * Thus at this point, begins to prefetch the starting area of the current stream. * ************************************************************************************/ MyStreamEntry * MyStreamPrefetchTable::LookForRepeatStream(vector& requests, MyStreamEntry& newentry) { Node *node = mListHead; //ADDRINT new_region_start_baddr = GetRegionStartBAddrFromBDist(newentry); ADDRINT new_region_end_baddr = GetBAddrFromAddr(newentry.region_end_addr); ADDRINT new_original_baddr = newentry.original_baddr; ADDRINT new_last_access_baddr = GetBAddrFromAddr( GetLastAccessAddressFromDist(newentry) ); ADDRINT new_length = (newentry.ascending)?(new_region_end_baddr - new_original_baddr):(new_original_baddr - new_region_end_baddr ); while(node != NULL) { MyStreamEntry & entry = node->_item; //ADDRINT region_start_baddr = GetRegionStartBAddrFromBDist(entry); //ADDRINT region_end_baddr = GetBAddrFromAddr(entry.region_end_addr); ADDRINT original_baddr = entry.original_baddr; ADDRINT last_access_baddr = GetBAddrFromAddr( GetLastAccessAddressFromDist(entry) ); //ADDRINT length = (entry.ascending)?(region_end_baddr - original_baddr):(original_baddr - region_end_baddr ); if(entry.original_baddr == 0) break; if( &newentry == &entry) { node = node->_next; continue; } if( (newentry.ascending && entry.ascending) || (!newentry.ascending && !entry.ascending) ) { if( (new_last_access_baddr <= (last_access_baddr + Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) && (new_last_access_baddr >= (last_access_baddr - Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) && (new_original_baddr <= (original_baddr + Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) && (new_original_baddr >= (original_baddr - Common::STREAM_MAX_NEIGHBOR_DISTANCE) ) && (new_length > 2*_stream_prefetch_distance) ) { cout << "repeat stream "; ShowMyStreamEntry(newentry); ShowMyStreamEntry(entry); entry.original_baddr = (new_original_baddr < original_baddr)?new_original_baddr:original_baddr; entry.region_end_addr = GetAddrFromBAddr(entry.original_baddr); entry.region_start_baddr_dist = 0; entry.stride_confirm = false; entry.csd1 = false; entry.csd2 = false; entry.last_access_addr_dist = 0; for(unsigned int j = 0; j < _stream_prefetch_distance/2; j++) { if(entry.ascending) requests.push_back( GetAddrFromBAddr(entry.original_baddr +j) ); else requests.push_back( GetAddrFromBAddr(entry.original_baddr -j) ); } ShowMyStreamEntry(entry); BringsToHead(node); return(&entry); //break; } } node = node->_next; } return NULL; } void MyStream::GetSpecificStatistics() { /* Show the customized statistics */ } // // Function to initialize the prefetchers. DO NOT change the prototype of this // function. You can change the body of the function by calling your necessary // initialization functions. // // Only have L2 prefetcher!!! void InitPrefetchers() // DO NOT CHANGE THE PROTOTYPE { pref2 = new MyStream(); if(pref2 != NULL) { map::iterator it; cout << pref2->GetPrefName() << " parameters: "; for( it=pref2->params.begin(); it!= pref2->params.end(); it++) cout << it->first << " = " << it->second << ", "; cout << endl; } } // // Function that is called every cycle to issue prefetches should the // prefetcher want to. The arguments to the function are the current cycle, // the demand requests to L1 and L2 cache. Again, DO NOT change the prototype of this // function. You can change the body of the function by calling your necessary // routines to invoke your prefetcher. // // DO NOT CHANGE THE PROTOTYPE void IssuePrefetches( COUNTER cycle, PrefetchData_t *L1Data, PrefetchData_t * L2Data ) { // INSERT YOUR CHANGES IN HERE //unsigned int i, j; stringstream ss,ss1; // Issue L1 prefetches: no l1 prefetcher here!!! /*if(pref1 != NULL) { for(i = 0; i < 4; i++) { if((cycle == L1Data[i].LastRequestCycle) && (L1Data[i].hit == 0)) { vector prefl1_requests; pref1->OnMiss(ss, L1Data[i], prefl1_requests, cycle, false); for(j=0; jIsMSHREnabled() ) { MSHR::Node *mshrnode = pref2->GetMSHR()->mListHead; while(mshrnode != NULL) { ADDRINT testaddr = mshrnode->_item.addr; if(testaddr == 0) break; if( GetPrefetchBit(1, testaddr) != -1 ) { // in cache now pref2->DelMSHREntry(testaddr); } mshrnode = mshrnode->_next; } } vector prefl2_requests; if( pref2 != NULL ) { if((cycle == L2Data->LastRequestCycle) && (L2Data->LastRequestAddr != 0) ) { if(L2Data->hit == 0) { //Only when there's no matching entry in MSHR, the miss is a real miss: bool isfiltered = false; if( pref2->IsMSHREnabled() ) { isfiltered = pref2->LookupMSHR(L2Data->DataAddr); } // OnMiss handling: make prefetch requests, or train stream pref2->OnMiss(ss, *L2Data, prefl2_requests,cycle, isfiltered); } else { // OnHit handling: make prefetch requests pref2->OnHit(ss, *L2Data, prefl2_requests, cycle); } if(L2Data->hit == 1) { //hit info will also cause MSHR entry deletion: pref2->DelMSHREntry(L2Data->DataAddr); if( GetPrefetchBit(1, L2Data->DataAddr) == 1 ) { pref2->IncPrefhit(); UnSetPrefetchBit(1, L2Data->DataAddr); ss << "hit prefetch,"; // OnPrefetchHit handling: pref2->OnPrefetchHit(ss, *L2Data, prefl2_requests, cycle); } } } } }