src/Lib/shttl/lru.h

説明を見る。
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 #ifndef SHTTL_LRU_H
00033 #define SHTTL_LRU_H
00034 
00035 #include <limits>
00036 #include <cassert>
00037 #include <stdexcept>
00038 #include <vector>
00039 #include <algorithm>
00040 
00041 #include "shttl_types.h"
00042 #include "bit.h"
00043 #include "replacement.h"
00044 
00045 
00046 namespace shttl 
00047 {
00048     //
00049     // --- LRU replacer (time stamp based) ---
00050     //
00051     template< typename key_type >
00052     class lru_time : public replacer< key_type >
00053     {
00054 
00055     public:
00056         typedef typename replacer< key_type >::size_type size_type;
00057 
00058         void construct( const size_type set_num , const size_type way_num )
00059         {
00060             m_lru.resize( set_num );
00061             for( size_t i = 0; i < m_lru.size(); i++ ){
00062                 m_lru[i].construct( way_num );
00063             }
00064         }
00065 
00066         size_type size()
00067         {
00068             return m_lru.size();
00069         }
00070 
00071         void touch(
00072             const size_type index,
00073             const size_type way,
00074             const key_type  key
00075         ){
00076             m_lru[ index ].touch( way );
00077         }
00078 
00079         size_type target(
00080             const size_type index
00081         ){
00082             return m_lru[ index ].target();
00083         }
00084 
00085     protected:
00086         class set
00087         {
00088         public:
00089 
00090             // Types
00091             typedef u8 counter_type;
00092             typedef size_t size_type;
00093 
00094             static const std::numeric_limits<counter_type>  counter_info;
00095             static const std::numeric_limits<size_type>     size_info;
00096 
00097             // Accessors(s)
00098             size_type size() const { return m_way_num; }
00099 
00100 
00101             // Constructors
00102             set( const size_type size ) :
00103             m_way_num(size), 
00104                 m_stamp( new counter_type[size] )
00105             {
00106                 reset();
00107             }
00108 
00109             set() : 
00110             m_way_num(0), 
00111                 m_stamp(NULL)
00112             {
00113                 m_mru  = 0;
00114                 m_tick = 0;
00115             }
00116 
00117             void reset()
00118             {
00119                 for (size_type w = 0; w < m_way_num; ++w)
00120                     m_stamp[w] = (counter_type)w;
00121 
00122                 m_mru = m_way_num - 1;
00123                 m_tick = (counter_type)m_way_num;
00124             }
00125 
00126             ~set()
00127             {
00128                 if(m_stamp)
00129                     delete[] m_stamp;
00130             }
00131 
00132             void construct( const size_type way_num )
00133             {
00134                 if(m_stamp)
00135                     delete[] m_stamp;
00136 
00137                 m_way_num  = way_num;
00138                 m_stamp = new counter_type[way_num];
00139                 reset();
00140             }
00141 
00142             void touch( const size_type i )
00143             {
00144                 if(size() <= i)
00145                     throw std::out_of_range("set::touch");
00146 
00147                 if (i == m_mru) return;    // nothing to do
00148 
00149                 if (m_tick == counter_info.max())
00150                     rewind();
00151 
00152                 m_stamp[i] = m_tick++;      // main work of touch()
00153                 m_mru = i;
00154             }
00155 
00156             size_type target()
00157             {                           // find i that m_stamp[i] is minimum
00158                 size_type i   =        0;
00159                 size_type min = m_stamp[0];
00160                 for (size_type j = 1; j < size(); ++j) {
00161                     if (m_stamp[j] < min) {
00162                         i   =        j;
00163                         min = m_stamp[j];
00164                     }
00165                 }
00166                 return i;
00167             }
00168 
00169 
00170         protected:
00171 
00172             // Data Members
00173             size_type      m_way_num; // size
00174 
00175             counter_type*  m_stamp; // time stamp
00176             counter_type   m_tick;  // tick
00177             size_type      m_mru;   // index to most recently used entry
00178 
00179             void rewind()
00180             {
00181                 std::vector< std::pair<counter_type, size_type> > v(size());
00182 
00183                 for (size_type i = 0; i < size(); ++i)
00184                     v[i] = std::pair<counter_type, size_type>(m_stamp[i], i);
00185 
00186                 sort(v.begin(), v.end());
00187 
00188                 for (size_type i = 0; i < size(); ++i)
00189                     m_stamp[v[i].second] = (counter_type)i;
00190 
00191                 SHTTL_ASSERT(m_stamp[m_mru] == size() - 1);
00192                 m_tick = (counter_type)size();
00193             }
00194 
00195         }; // class set
00196 
00197         typedef std::vector<set> lru_array;
00198         typedef typename lru_array::reference reference;
00199 
00200         lru_array m_lru;
00201     };
00202 
00203 
00204 
00205     //
00206     // --- LRU replacer (order based) ---
00207     //
00208 
00209     template< typename key_type, typename order_type = u8 >
00210     class lru_order : public replacer< key_type >
00211     {
00212     public:
00213         typedef typename replacer< key_type >::size_type size_type;
00214         typedef typename std::vector<order_type>         order_array_type;
00215         typedef typename order_array_type::iterator      iterator;
00216 
00217         lru_order()
00218         {
00219             m_way_num = 0;
00220             m_set_num = 0;
00221         }
00222 
00223         void construct( const size_type set_num, const size_type way_num )
00224         {
00225             m_way_num = way_num;
00226             m_set_num = set_num;
00227             
00228             size_t size = set_num * way_num;
00229 
00230             if( std::numeric_limits<order_type>().max() <= way_num ){
00231                 throw std::invalid_argument( 
00232                     "shttl::lru_order() \n THe specified way number is too large." 
00233                 );
00234             }
00235 
00236             m_order.resize( size );
00237 
00238             for( size_t i = 0; i < set_num; i++ ){
00239                 reset_set( i );
00240             }
00241 
00242         }
00243 
00244         size_type size()
00245         {
00246             return m_set_num;
00247         }
00248 
00249         size_type target( const size_type index )
00250         {
00251             return get_set( index )[0];
00252         }
00253 
00254         void touch( const size_type index, const size_type way, const key_type key )
00255         {
00256             iterator set = get_set( index );
00257             //         LRU             MRU
00258             // initial : 0 1 2 3 4 5 6 7
00259             // touch 0 : 1 2 3 4 5 6 7 0
00260             // touch 3 : 0 1 2 4 5 6 7 3
00261             bool sride = false;
00262             for( size_t w = 0; w < m_way_num; w++ ){
00263                 if( sride ){
00264                     set[ w-1 ] = set[ w ];
00265                 }
00266                 else{
00267                     if( set[ w ] == way ){
00268                         sride = true;
00269                     }
00270                 }
00271             }
00272             set[ m_way_num - 1 ] = (order_type)way;
00273 
00274         }
00275 
00276     protected:
00277 
00278         size_t           m_way_num; 
00279         size_t           m_set_num; 
00280         order_array_type m_order;
00281 
00282         iterator get_set( const size_type index )
00283         {
00284             size_t offset = index * m_way_num;
00285             return m_order.begin() + offset;
00286         }
00287 
00288         void reset_set( size_type index )
00289         {
00290             iterator set = get_set( index );
00291             for( size_t i = 0; i < m_way_num; i++ ){
00292                 set[i] = (order_type)i; // compatible original lru
00293             }
00294         }
00295 
00296 
00297     };
00298 
00299 
00300     //
00301     // --- LRU replacer (linked list based) ---
00302     // 'lru_list' can touch()/target() in O(1) time.
00303     // ('lru_order' can do them in O(way_num) time, but it consumes
00304     // only half as much memory as 'lru_list'.
00305     //
00306     // LRU cannot be implemented by an usual linked list (ex. std::list),
00307     // because a replacer cannot know which entry should be touched.  
00308     //
00309     // This implementation uses a linked list that is constructed in a fixed size array.
00310     // On touch(), a touched entry is moved to the last of a list.
00311     // Thus, the first entry of a list is always LRU.
00312     // Way numbers corresponds to entries in a list respectively and 
00313     // which entry should be touched can be determined easily.
00314     //
00315     template< typename key_type, typename pointer_type = u8 >
00316     class lru_list : public replacer< key_type >
00317     {
00318     public:
00319         typedef typename replacer< key_type >::size_type size_type;
00320 
00321         struct element_type
00322         {
00323             pointer_type prev;
00324             pointer_type next;
00325         };
00326 
00327         typedef typename std::vector<element_type>  array_type;
00328         typedef typename array_type::iterator       iterator;
00329 
00330         lru_list()
00331         {
00332             m_way_num = 0;
00333             m_set_num = 0;
00334             m_pitch   = 0;
00335         }
00336 
00337         void construct( const size_type set_num, const size_type way_num )
00338         {
00339             m_way_num = way_num;
00340             m_set_num = set_num;
00341             m_pitch   = way_num + 1;
00342             size_t size = set_num * m_pitch;
00343 
00344             if( std::numeric_limits<pointer_type>().max() <= m_pitch ){
00345                 throw std::invalid_argument( 
00346                     "shttl::lru_list() \n The specified way number is too large." 
00347                 );
00348             }
00349 
00350             m_array.resize( size );
00351 
00352             for( size_t i = 0; i < set_num; i++ ){
00353                 reset_set( i );
00354             }
00355 
00356         }
00357 
00358         size_type size()
00359         {
00360             return m_set_num;
00361         }
00362 
00363         size_type target( const size_type index )
00364         {
00365             return get_footer( index )->next;
00366         }
00367 
00368         void touch( const size_type index, const size_type way, const key_type key )
00369         {
00370             iterator set = get_set( index );
00371             iterator cur = set + way;
00372             
00373             // Erase 'cur' from list.
00374             erase( set, cur );    
00375 
00376             // Insert 'cur' before a footer.
00377             insert( 
00378                 set, 
00379                 set + m_way_num,  // This is a footer
00380                 cur
00381             );
00382 
00383             //           Array&Pointer Image             List Image
00384             //           way-0 way-1 way-2 way-3 footer
00385             // initial : [4,1] [0,2] [1,3] [2,4] [3,0] / w0 -> w1 -> w2 -> w3 -> footer -> w0(LRU)
00386             // touch 0 : [3,4] [4,2] [1,3] [2,0] [0,1] / w1 -> w2 -> w3 -> w0 -> footer -> w1(LRU)
00387             // touch 3 : [2,3] [4,2] [1,0] [0,4] [3,1] / w1 -> w2 -> w0 -> w3 -> footer -> w1(LRU)
00388             //                                      ^
00389             //                                     LRU
00390 
00391         }
00392 
00393     protected:
00394 
00395         size_t     m_way_num; 
00396         size_t     m_pitch; 
00397         size_t     m_set_num; 
00398         array_type m_array;
00399 
00400         iterator get_set( const size_type index )
00401         {
00402             size_t offset = index * m_pitch;
00403 
00404             // LRU information of each cache set consists of a list with 'm_way_num + 1' ways.
00405             // (m_pitch = m_way_num + 1
00406             // The last entry in each list is a footer pointing an LRU entry.
00407             //
00408             // An example of 4-way array:
00409             // set-0: | way-0 | way-1 | way-2 | way-3 | footer |
00410             // set-1: | way-0 | way-1 | way-2 | way-3 | footer |
00411             // set-2: ...
00412             
00413             return m_array.begin() + offset;
00414         }
00415 
00416 
00417         iterator get_footer( const size_type index )
00418         {
00419             return get_set( index ) + m_way_num;
00420         }
00421 
00422 
00423         void reset_set( size_type index )
00424         {
00425             //      LRU <--------------------> MRU
00426             //       0        1        2        3    m_way_num
00427             // |-> way-0 -> way-1 -> way-2 -> way-3 -> footer ->|
00428             // ^                                                |
00429             // ^------------------------------------------------|
00430 
00431             iterator set = get_set( index );
00432 
00433             for( size_t i = 0; i < m_way_num + 1; i++ ){
00434                 ( set + i )->prev = (pointer_type)(i - 1);
00435                 ( set + i )->next = (pointer_type)(i + 1);
00436             }
00437 
00438             (set + 0)->prev = (pointer_type)m_way_num;
00439             (set + m_way_num)->next = (pointer_type)0;
00440         }
00441 
00442         // Erase 'cur' from a list of 'set'.
00443         void erase( iterator set, iterator cur )
00444         {
00445             iterator prev = set + cur->prev;
00446             iterator next = set + cur->next;
00447             prev->next = cur->next;
00448             next->prev = cur->prev;
00449         }
00450 
00451         // Insert 'cur' before 'pos'.
00452         void insert( iterator set, iterator pos, iterator cur )
00453         {
00454             iterator prev = set + pos->prev;
00455             cur->prev  = pos->prev;
00456             cur->next  = (pointer_type)(pos - set);
00457             prev->next = (pointer_type)(cur - set);
00458             pos->prev  = (pointer_type)(cur - set);
00459         }
00460 
00461     };
00462 
00463 
00464 
00465     // Use order based implementation.
00466     template< typename key_type >
00467     class lru : public lru_list< key_type >
00468     {
00469     };
00470 
00471 } // namespace shttl
00472 
00473 #endif // SHTTL_LRU_H

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