#ifndef SAMPLE_PREFETCHER_H #define SAMPLE_PREFETCHER_H #include #include #include #include #include #include #include #include #include #include using namespace std; /////////////////////////////////////////////////////////////////////////////// // Basic Classes and Templates /////////////////////////////////////////////////////////////////////////////// /// Nodes in the LRU-like queues template class _List_Node { public: ItemType _item; _List_Node* _next; _List_Node* _prev; _List_Node(ItemType item = ItemType()) :_item(item), _next(0), _prev(0) {} _List_Node(_List_Node& node) :_item(node._item), _next(0), _prev(0) {} ~_List_Node(){} }; /// template class for any LRU-like queues. /// The queue is implemented in a form of double-linked list. /// The template provides constructor/destructor, and a "bring to head" method. /// Inherite from LRUList to create your new queue class, /// where ItemType is the class of queue items. /// Requirement of ItemType: /// o. It should provide default/copy constructors. /// o. It should provide a Dump() routine for dumpping out its content to stdout. This is useful in debugging. template class LRUList{ public: typedef _List_Node Node; protected: Node* mListHead; Node* mListTail; UINT32 mListLength; /// Brings the node to the head of the queue. /// This makes it Most Recently Used void BringsToHead(Node* ptr){ if( ptr->_prev != NULL ) { // Pull the entry out chain previous and next elements // to each other ptr->_prev->_next = ptr->_next; if( ptr->_next ) { ptr->_next->_prev = ptr->_prev; } else { // If tail is being removed, set the tail to the // previous guy in the link-list mListTail = ptr->_prev; } // Since we are bringing this to the head, next // element is going to be the current head. ptr->_next = mListHead; ptr->_prev = NULL; // set current head's previous to this mListHead->_prev = ptr; // This is now the current head mListHead = ptr; } } /// Brings the node to the tail of the queue. /// This makes it Least Recently Used void BringsToTail(Node* ptr){ if( ptr->_next != NULL ) { // Pull the entry out chain previous and next elements // to each other ptr->_next->_prev = ptr->_prev; if( ptr->_prev ) { ptr->_prev->_next = ptr->_next; } else { // If head is being removed, set the head to the // next guy in the link-list mListHead = ptr->_next; } // Since we are bringing this to the tail, next // element is going to be the current tail. ptr->_prev = mListTail; ptr->_next = NULL; mListTail->_next = ptr; // This is now the current tail mListTail = ptr; } } public: /// Create the list with specified length. LRUList(UINT32 listLength): mListHead(0), mListTail(0), mListLength(listLength) { Node* prevNode = 0; for (UINT32 i=0; i_prev = prevNode; if (prevNode) prevNode->_next = node; prevNode = node; } mListTail = prevNode; } ~LRUList() { while (mListHead) { Node* node = mListHead->_next; delete mListHead; mListHead = node; } } /// Utillity routine for debugging in gdb. Dump out the list. void Dump() { Node* node=mListHead; for (UINT32 i=0; i_next) { ;//cout<_item.Dump(); ;//cout<ip = ip; } /// copy constructor MemLogEntry(const MemLogEntry& ent) :ip(ent.ip), last_mem_addr(ent.last_mem_addr), stride(ent.stride), count(ent.count), trained(ent.trained) { // Nothing } ~MemLogEntry() { // Nothing } /// Dump routine void Dump(){ ;//cout << hex << ip << "," << last_mem_addr << "," << dec < { private: map PClist; map::iterator iter; public: static const UINT32 DEFAULT_STRIDE_PREFETCH_TABLE_SIZE = 256; StridePrefetchTable(UINT32 tableSize=DEFAULT_STRIDE_PREFETCH_TABLE_SIZE) : LRUList(tableSize){} ~StridePrefetchTable(){} /// Look-up in the prefetch table. This leeds to a subsequent LRU update in the table. /// Returns the entry if hit. MemLogEntry* AccessEntry(UINT32 threadId, ADDRINT ip, ADDRINT memAddr){ // find the ip log in the table Node* node = mListHead; while (node && node->_item.ip!=ip) node=node->_next; MemLogEntry* entry; if ( node == NULL ) { /// Replace tail node = mListTail; entry = &(node->_item); DelFrmPClist( entry->ip ); entry->ip = ip; entry->last_mem_addr = memAddr; entry->stride = 0; entry->trained = false; AddToPClist( ip, node ); } else /// update { entry = &(node->_item); // ;//cout <<"Found IP: "<last_mem_addr // <<" Curr Mem Addr: "<last_mem_addr; entry->last_mem_addr = memAddr; if (newstride && (newstride == entry->stride)) { ++(entry->count); if( entry->count >= 1 ) { if(!(entry->trained)) entry->trained = true; } } else { entry->count = 0; entry->stride = newstride; entry->trained = false; } } BringsToHead(node); return entry; } Node* FindPC( ADDRINT ip ) { iter = PClist.find(ip); if( iter != PClist.end() ) { return iter->second; } return NULL; } inline void AddToPClist( ADDRINT ip, Node *tmp ) { PClist[ ip ] = tmp; } inline void DelFrmPClist( ADDRINT ip ) { PClist.erase( ip ); } }; class SamplePrefetcher : public StridePrefetchTable { private: public: SamplePrefetcher() : StridePrefetchTable() { } ~SamplePrefetcher() { } }; // ahmad's code begins here.... #ifndef __GLOBALS_H__ #define __GLOBALS_H__ #include #include ///#include #include #include #include #include "interface.h" // cache defines. #define LINE_BITS (6) #define LINE_SIZE (1<>LINE_BITS) #define REGION_SIZE (1<>REGION_BITS) #define REGION(x) (x&~((1<>LINE_BITS)<>LINE_BITS)< PCMap; typedef std::vector > PCVector; typedef std::deque AddressList; typedef std::vector< AddressList > Regions; typedef std::map LHB; PCMap::iterator GetHighest(PCMap & l2MissPCs); void PrintHighestPCs(PCMap & l2MissPCs); typedef std::deque History; typedef std::map PCHistory; typedef std::deque HistoryPtr; #define HISTORY_SIZE 64 #define GLOBAL_HISTORY_SIZE 64 extern bool AddToHistory(History & h, PrefetchData_t & d, int type); extern bool AddToPCHistory(PCHistory & h, PrefetchData_t & d, int type); extern void PrintPCHistory(History & h, int mask); extern void PrintGlobalHistory(History & h); extern void PrintHistory(HistoryPtr & h); template extern void PRINT_DELTAS(const T& coll, const U& a); template extern void PRINT_ABS(const T& coll); template extern void GET_NN(T & output, U & input, CacheAddr_t current, CacheAddr_t threshold); template extern void FindStride(T & region, U i, std::map & strideMap); template extern void GetN(V & output, T & region, typename T::iterator i, int n); template extern void PRINT_DELTAS_P(const T & coll, const U & now); template extern void GET_DELTAS(T&coll, U&output); #endif /*__GLOBALS_H__*/ #ifndef __BASE_PREFETCHER_H__ #define __BASE_PREFETCHER_H__ ///#include "globals.h" struct PrefetchInfo { COUNTER cycle; unsigned int hits; CacheAddr_t delta; PrefetchInfo(COUNTER c, CacheAddr_t d) { hits=0; cycle=c; delta=d; } PrefetchInfo() { assert(0); } }; #if 1 // This is the ideal prefetch filter... it tracks N prefetches issued so far and // removes duplicates. // Algorithm for checking if previously set.... // Upon prefetch, look in the queue. If hit, make it MRU. // Go through the list again, see if any is in the cache. If so make it LRU. struct PrefetchStats { // This map is used only for SIMULATION PERFORMANCE reasons... // It is not included in storage budget... I could do a lookup using l alone, but map // is a red-black tree that gives me O(logn) lookup time instead of O(n). // again, sim perf is good with map. :) std::map m; AddressList l; unsigned int max; COUNTER cycles; COUNTER total; COUNTER dupe; COUNTER hits; COUNTER wasted; PrefetchStats(int s) { cycles=0; total=0; dupe=0; wasted=0; max=s; } void Demand(COUNTER cycle, CacheAddr_t a) { if(m.find(a)!=m.end()) { assert(cycle>=m[a].cycle); if(m[a].hits==0) { ;//signed long long int d=m[a].delta; ;//cout<<"PHIT: "<<(a>>LINE_BITS)<<" "<>LINE_BITS) <::iterator i; i=m.find(l.front()); assert(i!=m.end()); if(i->second.hits==0) { ;//cout<<"WASTED PREFETCH: "<< LINE_NUMBER(i->first)<DataAddr); ;//cout<<"PREFETCHING: "<<(((signed long long int)b)>>LINE_BITS) ; m.insert(std::make_pair(a, PrefetchInfo(cycle, b))); assert(m[a].cycle==cycle); return true; } else { dupe++; return false; } } void PrintStats() { COUNTER average; ;//cout<<"Printing prefetcher stats: "< struct MyPrefetchData_t : public PrefetchData_t { MyPrefetchData_t(PrefetchData_t & d, int type) : PrefetchData_t(d) { AccessType^=type; } MyPrefetchData_t() { } }; // Time sorted addresses typedef deque TSA; // Space sorted addresses typedef list SSA; struct SLHBL { // for global history buffer, PC is not used at all... so it is not counted. CacheAddr_t PC; TSA tsa; // in hardware, this wont be seperate... this is only seperate for SIMULATION PERFORMANCE! SSA ssa; unsigned int max; SLHBL(unsigned int m) { max=m; } void Clear() { tsa.clear(); ssa.clear(); } bool Find(CacheAddr_t a) { for( TSA::reverse_iterator i=tsa.rbegin() ; i!=tsa.rend() ; i++ ) { if(i->DataAddr==a) return true; } return false; } bool Find(MyPrefetchData_t * d, TSA::iterator & i) { for( i=tsa.begin() ; i!=tsa.end() ; i++ ) { if(i->DataAddr==d->DataAddr) return true; } return false; } bool Add(MyPrefetchData_t * d) { TSA::iterator i; // If we can find it, don't add it. if(Find(d, i)==true) { if(IS_L1(d->AccessType)==0 && IS_L1(i->AccessType)!=0) { // We need to change it to L2. i->AccessType=d->AccessType; for( SSA::iterator j=ssa.begin() ; j!=ssa.end() ; j++ ) { if(j->DataAddr==d->DataAddr) { j->AccessType=d->AccessType; } } return true; } return false; } assert(tsa.size()==ssa.size()); if(tsa.size()==max) { RemoveFront(); } PushBack(d); return true; } void AddWithoutCheck(MyPrefetchData_t * d) { Add(d); } void PushBack(MyPrefetchData_t * d) { tsa.push_back(*d); SSA::iterator i; for( i=ssa.begin() ; i!=ssa.end() ; i++ ) { if(i->DataAddr>d->DataAddr) break; } ssa.insert(i, *d); } void RemoveFront() { if(tsa.size()==0) return; MyPrefetchData_t & d=*(tsa.begin()); SSA::iterator i=ssa.begin(); while(i->DataAddr!=d.DataAddr) i++; assert(i!=ssa.end()); ssa.erase(i); tsa.pop_front(); } void Print() { #if 0 Clusterer c; // to keep the clusterer happy unsigned int total; priority_queue< pair > sorted; AddressList l2Hits; AddressList l2Misses; AddressList l1Hits; AddressList l1Misses; AddressList all; if(tsa.begin()==tsa.end()) { ;//cout<<"List empty!"<DataAddr); if(i->AccessType&L1_ACCESS) ;//cout<<"_L1"; else ;//cout<<"_L2"; if(i->hit==true) ;//cout<<"_H"; else ;//cout<<"_M"; ;//cout<<" "; if( (i->AccessType&L1_ACCESS) && i->hit==true) { l1Hits.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS) && i->hit==false) { l1Misses.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS)==0 && i->hit==true) { l2Hits.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS)==0 && i->hit==false) { l2Misses.push_back(LINE_NUMBER(i->DataAddr)); } all.push_back(LINE_NUMBER(i->DataAddr)); } ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<20) { c.Cluster(l2Misses, sorted, total); ;//cout<DataAddr); if(i->AccessType&L1_ACCESS) ;//cout<<"_L1"; else ;//cout<<"_L2"; if(i->hit==true) ;//cout<<"_H"; else ;//cout<<"_M"; ;//cout<<" "; if( (i->AccessType&L1_ACCESS) && i->hit==true) { l1Hits.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS) && i->hit==false) { l1Misses.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS)==0 && i->hit==true) { l2Hits.push_back(LINE_NUMBER(i->DataAddr)); } else if((i->AccessType&L1_ACCESS)==0 && i->hit==false) { l2Misses.push_back(LINE_NUMBER(i->DataAddr)); } all.push_back(LINE_NUMBER(i->DataAddr)); } ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout<DataAddr)-a); if(i->AccessType&L1_ACCESS) ;//cout<<"_L1"; else ;//cout<<"_L2"; if(i->hit==true) ;//cout<<"_H"; else ;//cout<<"_M"; ;//cout<<" "; a=LINE_NUMBER(i->DataAddr); } ;//cout<DataAddr)); } if(al.size()>1) { ;//cout<<"PRINTING TSA"< l; unsigned int lhl; unsigned int ghl; unsigned int nlh; unsigned int hits; unsigned int misses; bool printLocal; map l1Prefetches; map l2Prefetches; PrefetchData_t * currentP; NNLPrefetcher(unsigned int localHistoryLength, unsigned int numLocalHistories, unsigned int globalHistoryLength) : g(globalHistoryLength) { lhl=localHistoryLength; ghl=globalHistoryLength; nlh=numLocalHistories; hits=0; misses=0; l.resize(nlh, lhl); } void IssuePrefetches( COUNTER cycle, PrefetchData_t *L1Data, PrefetchData_t * L2Data ) { BasePrefetcher::IssuePrefetches(cycle, L1Data, L2Data); list::iterator it; bool added=false; bool addedLocal=false; for( unsigned int i=0 ; i<4 ; i++ ) { if(L1Data[i].LastRequestCycle==cycle && L1Data[i].LastRequestPrefetch==false) { MyPrefetchData_t d(L1Data[i], L1_ACCESS); currentP=L2Data; added=g.Add(&d); if(added) { PrefetchPattern(cycle, &d, g); } addedLocal=AddLocal(&d, cycle, it); if(addedLocal) { PrefetchPattern(cycle, &d, *(l.rbegin()) ); PrefetchGeoPattern(cycle, &d, *(l.rbegin()) ); } } } if(L2Data[0].LastRequestCycle==cycle&&L2Data[0].LastRequestPrefetch==false) { MyPrefetchData_t d(L2Data[0], 0); added=g.Add(&d); addedLocal=AddLocal(&d, cycle, it); PDEBUG(added); PDEBUG(addedLocal); #if 1 if(added) { PrintPattern(cycle, &d, g); PrefetchPattern(cycle, &d, g); PrefetchSSAPattern(cycle, &d, g); } if(addedLocal) { PrintPattern(cycle, &d, *(l.rbegin()) ); PrefetchPattern(cycle, &d, *(l.rbegin()) ); } #endif } FinallyIssue(); /// if(cycle>9000) /// exit(0); } bool TestGlobalAndLocal(CacheAddr_t a) { if(g.Find(a)==true) return true; for( list::reverse_iterator i=l.rbegin() ; i!=l.rend() ; i++ ) { if(i->Find(a)==true) return true; } return false; } void FinallyIssue() { for( map::iterator i=l1Prefetches.begin() ; i!=l1Prefetches.end() ; i++ ) { if(TestGlobalAndLocal(i->first)==false) IssueL2(currentP->LastRequestCycle, i->first, currentP); } for( map::iterator i=l2Prefetches.begin() ; i!=l2Prefetches.end() ; i++ ) { if(TestGlobalAndLocal(i->first)==false) IssueL2(currentP->LastRequestCycle, i->first, currentP); } l2Prefetches.clear(); l1Prefetches.clear(); } void PrintPattern(COUNTER cycle, MyPrefetchData_t * d, SLHBL & buffer) { // Get raw addresses of L2 misses from the time-ordered buffer and see if there is any // pattern in them. AddressList tsaL2Misses; AddressList tsaAccesses; AddressList all; AddressList allSorted; for( TSA::iterator i=buffer.tsa.begin() ; i!=buffer.tsa.end() ; i++ ) { /// ;//cout<<"Comparing: "<DataAddr)<<" and "<DataAddr); if( IS_L1(i->AccessType)==0 && labs(i->DataAddr-d->DataAddr)<= (1<<(10+LINE_BITS)) ) { /// ;//cout<<" MATCH"<DataAddr) ); } if( labs(i->DataAddr-d->DataAddr)<=(1<<(10+LINE_BITS))) { tsaAccesses.push_back(LINE_NUMBER(i->DataAddr) ); } all.push_back(LINE_NUMBER(i->DataAddr)); } for( SSA::iterator i=buffer.ssa.begin() ; i!=buffer.ssa.end() ; i++ ) { allSorted.push_back(LINE_NUMBER(i->DataAddr)); } if(tsaL2Misses.size()>1) { #if 1 ;//cout<<"ADDR: "<DataAddr)<DataAddr) ); ;//cout<1) { #if 1 ;//cout<<"ADDR: "<DataAddr)<DataAddr) ); ;//cout<1) { if(&buffer==&g) ;//cout<<"GLOBAL "; else ;//cout<<"LOCAL "; ;//cout<<"FULL tsaAccesses: "<DataAddr)); ;//cout<DataAddr)); ;//cout<3) { // Check if they follow a geometric pattern. CacheAddr_t r; int score=0; AddressList::reverse_iterator i=al.rbegin(); AddressList::reverse_iterator j=i; j++; r=(*i)/(*j); while(j!=al.rend() && r*(*j)==(*i) ) { if(r==(*i)/(*j) ) { score++; } i++; j++; } if(score) { /// ;//cout<<"Score is: "<DataAddr)<DataAddr+*(al.rbegin())*r ) <DataAddr+*(al.rbegin())*r*r ) <DataAddr+*(al.rbegin())*r, 50); AddPrefetch(0, d->DataAddr+*(al.rbegin())*r+*(al.rbegin())*r*r, 25); /// exit(0); } else { // Try with a more fuzzy match. i=al.rbegin(); j=i; j++; double dr=(double) (*i)/(*j); score=0; if(dr>1) { while(j!=al.rend()) { double newdr; newdr=(double) (*i)/(*j); CacheAddr_t newdra=(CacheAddr_t)round(newdr); /// PDEBUG(newdra); /// PDEBUG(*i); /// PDEBUG(*j); // FIXME: This should be LINE_SIZE*newdra if( labs(newdra*(*j)-(*i) ) < LINE_SIZE*2) /// if(abs(newdr-dr)<0.02) { score++; } else break; i++;j++; } if(score>1) { // We have a fuzzy match. // ;//cout<<"FUZZY MATCH score: "<DataAddr+ *(al.rbegin())*dra, 50); AddPrefetch(0, d->DataAddr+*(al.rbegin())*r+*(al.rbegin())*r*r, 25); } } // TODO: Add one for decreasing ones. } } } void PrefetchSSAPattern(COUNTER cycle, MyPrefetchData_t * d, SLHBL & buffer) { // Try to prefetch from // Obtain a few samples in the left direction... right now hard-coded to 8 if(buffer.ssa.size()<4) return; SSA::iterator i=buffer.ssa.begin(); while(i->DataAddr!=d->DataAddr) { i++; } assert(i!=buffer.ssa.end()); SSA::reverse_iterator j(i); AddressList left; AddressList right; j--; while(j!=buffer.ssa.rend() && labs(j->DataAddr-d->DataAddr)<=(1<<(10+LINE_BITS)) ) { left.push_front(LINE_NUMBER(j->DataAddr)); j++; } SSA::iterator k=i; while(k!=buffer.ssa.end() && labs(d->DataAddr-k->DataAddr)<=(1<<(10+LINE_BITS)) ) { right.push_front(LINE_NUMBER(k->DataAddr)); k++; } // TODO: TODO: TODO: Make sure our own address is part of the future accesses? // Should reduce number of prefetches technically.... not sure about PERF! if(left.size()>4) { ;//cout<<"**** LEFT"<<__FUNCTION__<<"****"<DataAddr)); ;//cout< strideMap; AddressList::iterator it=left.end(); it--; /// if(IS_L1(d->AccessType)==0) { FindStride(left, it, strideMap); AddStrides(strideMap, d, left, 0, 100); } } if(right.size()>4) { ;//cout<<"**** RIGHT"<<__FUNCTION__<<"****"<DataAddr)); ;//cout< strideMap; AddressList::iterator it=right.end(); it--; /// if(IS_L1(d->AccessType)==0) { FindStride(right, it, strideMap); AddStrides(strideMap, d, right, 0, 100); } } } void PrefetchPattern(COUNTER cycle, MyPrefetchData_t * d, SLHBL & buffer) { // Get raw addresses of L2 misses from the time-ordered buffer and see if there is any // pattern in them. AddressList tsaL2Misses; AddressList tsaAccesses; AddressList all; AddressList allSorted; for( TSA::iterator i=buffer.tsa.begin() ; i!=buffer.tsa.end() ; i++ ) { /// ;//cout<<"Comparing: "<DataAddr)<<" and "<DataAddr); if( IS_L1(i->AccessType)==0 && labs(i->DataAddr-d->DataAddr)<= (1<<(10+LINE_BITS)) ) { /// ;//cout<<" MATCH"<DataAddr) ); } if( labs(i->DataAddr-d->DataAddr)<=(1<<(10+LINE_BITS))) { tsaAccesses.push_back(LINE_NUMBER(i->DataAddr) ); } all.push_back(LINE_NUMBER(i->DataAddr)); } for( SSA::iterator i=buffer.ssa.begin() ; i!=buffer.ssa.end() ; i++ ) { allSorted.push_back(LINE_NUMBER(i->DataAddr)); } if(tsaL2Misses.size()>1) { #if 0 ;//cout<<"ADDR: "<DataAddr)<DataAddr) ); ;//cout< strideMap; AddressList::iterator it=tsaL2Misses.end(); it--; /// if(IS_L1(d->AccessType)==0) { FindStride(tsaL2Misses, it, strideMap); AddStrides(strideMap, d, tsaL2Misses, 0, 100); } } if(tsaAccesses.size()>1) { #if 0 ;//cout<<"ADDR: "<DataAddr)<DataAddr) ); ;//cout<DataAddr)); ;//cout<DataAddr)); ;//cout< strideMap; AddressList::iterator it=tsaAccesses.end(); it--; /// if(IS_L1(d->AccessType)==0) { FindStride(tsaAccesses, it, strideMap); AddStrides(strideMap, d, tsaAccesses, 0, 20); } } } void AddStrides(map & strideMap, MyPrefetchData_t * d, AddressList & region, int type, int baseConfidence) { int maxStride=0; int maxStrideSteps=0; if(region.size()<2) { /// ;//cout<<"Region size is less than 2"<::iterator i=strideMap.begin() ; i!=strideMap.end() ; i++ ) { // Interpret it as preferring many smaller loops over one larger one. /// PDEBUG(i->first); /// PDEBUG(i->second); if(i->second>maxStride || (i->second==maxStride && i->firstsecond; maxStrideSteps=i->first; } } // added to take into account ssa... #if 0 for( AddressList::reverse_iterator i=region.rbegin() ; ; ) { if(*i==LINE_NUMBER(d->DataAddr)) { break; } i++; if(i==region.rend()) { return; } } #endif /// ;//cout<<"maxStride: "<3 && (float)maxStride/maxStrideSteps > 0.8) /// if(maxStride>3 && (float)maxStride/maxStrideSteps>0.8) { AddressList::iterator currentIt; CacheAddr_t a=LINE_NUMBER(d->DataAddr); AddressList strides; currentIt=region.end(); currentIt--; ;//cout<<"maxStride: "< & m=(type==0)?l2Prefetches:l1Prefetches; m[a]+=confidence; if(type==0) ;//cout<<"Added L2 prefetch: "; else ;//cout<<"Added L1 prefetch: "; ;//cout<Print(); BasePrefetcher::PrintStats(); } void PrintStats() { BasePrefetcher::PrintStats(); unsigned int GHBBits=ghl*32; unsigned int LHBBits=(1+lhl)*nlh*32; unsigned int FilterBits=l2Stats.max*32; unsigned int TotalBits=FilterBits+LHBBits+GHBBits; cout<<"NNLPrefetcher: ghl: "<::iterator i) { l.splice(l.end(), l, i); return; } bool AddLocal(MyPrefetchData_t * d, COUNTER cycle, list::iterator & pos) { bool ret; list::reverse_iterator i; list::iterator it; for( i=l.rbegin() ; i!=l.rend() ; i++ ) { if(i->PC==d->LastRequestAddr) break; } if(i==l.rend()) { it=l.begin(); it->Clear(); it->PC=d->LastRequestAddr; misses++; } else { i++; it=i.base(); hits++; } ret=it->Add(d); Touch(it); pos=it; return ret; } }; #endif /*__NNL_PREFETCHER_H__*/ #endif