Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/mng/prefetch_pool.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2003-2004 Roman Dementiev <dementiev@mpi-sb.mpg.de> 00007 * Copyright (C) 2009 Andreas Beckmann <beckmann@cs.uni-frankfurt.de> 00008 * 00009 * Distributed under the Boost Software License, Version 1.0. 00010 * (See accompanying file LICENSE_1_0.txt or copy at 00011 * http://www.boost.org/LICENSE_1_0.txt) 00012 **************************************************************************/ 00013 00014 #ifndef STXXL_PREFETCH_POOL_HEADER 00015 #define STXXL_PREFETCH_POOL_HEADER 00016 00017 #include <list> 00018 00019 #ifdef STXXL_BOOST_CONFIG 00020 #include <boost/config.hpp> 00021 #endif 00022 00023 #include <stxxl/bits/mng/write_pool.h> 00024 #include <stxxl/bits/compat_hash_map.h> 00025 00026 00027 __STXXL_BEGIN_NAMESPACE 00028 00029 //! \addtogroup schedlayer 00030 //! \{ 00031 00032 //! \brief Implements dynamically resizable prefetching pool 00033 template <class BlockType> 00034 class prefetch_pool : private noncopyable 00035 { 00036 public: 00037 typedef BlockType block_type; 00038 typedef typename block_type::bid_type bid_type; 00039 00040 protected: 00041 struct bid_hash 00042 { 00043 size_t operator () (const bid_type & bid) const 00044 { 00045 size_t result = size_t(bid.storage) + 00046 size_t(bid.offset & 0xffffffff) + size_t(bid.offset >> 32); 00047 return result; 00048 } 00049 #ifdef BOOST_MSVC 00050 bool operator () (const bid_type & a, const bid_type & b) const 00051 { 00052 return (a.storage < b.storage) || (a.storage == b.storage && a.offset < b.offset); 00053 } 00054 enum 00055 { // parameters for hash table 00056 bucket_size = 4, // 0 < bucket_size 00057 min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N 00058 }; 00059 #endif 00060 }; 00061 typedef std::pair<block_type *, request_ptr> busy_entry; 00062 typedef typename compat_hash_map<bid_type, busy_entry, bid_hash>::result hash_map_type; 00063 typedef typename std::list<block_type *>::iterator free_blocks_iterator; 00064 typedef typename hash_map_type::iterator busy_blocks_iterator; 00065 00066 // contains free prefetch blocks 00067 std::list<block_type *> free_blocks; 00068 // blocks that are in reading or already read but not retrieved by user 00069 hash_map_type busy_blocks; 00070 00071 unsigned_type free_blocks_size; 00072 00073 public: 00074 //! \brief Constructs pool 00075 //! \param init_size initial number of blocks in the pool 00076 explicit prefetch_pool(unsigned_type init_size = 1) : free_blocks_size(init_size) 00077 { 00078 unsigned_type i = 0; 00079 for ( ; i < init_size; ++i) 00080 free_blocks.push_back(new block_type); 00081 } 00082 00083 void swap(prefetch_pool & obj) 00084 { 00085 std::swap(free_blocks, obj.free_blocks); 00086 std::swap(busy_blocks, obj.busy_blocks); 00087 std::swap(free_blocks_size, obj.free_blocks_size); 00088 } 00089 00090 //! \brief Waits for completion of all ongoing read requests and frees memory 00091 virtual ~prefetch_pool() 00092 { 00093 while (!free_blocks.empty()) 00094 { 00095 delete free_blocks.back(); 00096 free_blocks.pop_back(); 00097 } 00098 00099 try 00100 { 00101 busy_blocks_iterator i2 = busy_blocks.begin(); 00102 for ( ; i2 != busy_blocks.end(); ++i2) 00103 { 00104 i2->second.second->wait(); 00105 delete i2->second.first; 00106 } 00107 } 00108 catch (...) 00109 { } 00110 } 00111 //! \brief Returns number of owned blocks 00112 unsigned_type size() const { return free_blocks_size + busy_blocks.size(); } 00113 00114 //! \brief Gives a hint for prefetching a block 00115 //! \param bid address of a block to be prefetched 00116 //! \return \c true if there was a free block to do prefetch and prefetching 00117 //! was scheduled, \c false otherwise 00118 //! \note If there are no free blocks available (all blocks 00119 //! are already in reading or read but not retrieved by user calling \c read 00120 //! method) calling \c hint function has no effect 00121 bool hint(bid_type bid) 00122 { 00123 // if block is already hinted, no need to hint it again 00124 if (in_prefetching(bid)) { 00125 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached"); 00126 return true; 00127 } 00128 00129 if (free_blocks_size) // only if we have a free block 00130 { 00131 --free_blocks_size; 00132 block_type * block = free_blocks.back(); 00133 free_blocks.pop_back(); 00134 STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => prefetching"); 00135 request_ptr req = block->read(bid); 00136 busy_blocks[bid] = busy_entry(block, req); 00137 return true; 00138 } 00139 STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => no free blocks for prefetching"); 00140 return false; 00141 } 00142 00143 bool hint(bid_type bid, write_pool<block_type> & w_pool) 00144 { 00145 // if block is already hinted, no need to hint it again 00146 if (in_prefetching(bid)) { 00147 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached"); 00148 return true; 00149 } 00150 00151 if (free_blocks_size) // only if we have a free block 00152 { 00153 --free_blocks_size; 00154 block_type * block = free_blocks.back(); 00155 free_blocks.pop_back(); 00156 if (w_pool.has_request(bid)) 00157 { 00158 busy_entry wp_request = w_pool.steal_request(bid); 00159 STXXL_VERBOSE1("prefetch_pool::hint2 bid=" << bid << " was in write cache at " << wp_request.first); 00160 assert(wp_request.first != 0); 00161 w_pool.add(block); //in exchange 00162 busy_blocks[bid] = wp_request; 00163 return true; 00164 } 00165 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => prefetching"); 00166 request_ptr req = block->read(bid); 00167 busy_blocks[bid] = busy_entry(block, req); 00168 return true; 00169 } 00170 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => no free blocks for prefetching"); 00171 return false; 00172 } 00173 00174 bool invalidate(bid_type bid) 00175 { 00176 busy_blocks_iterator cache_el = busy_blocks.find(bid); 00177 if (cache_el == busy_blocks.end()) 00178 return false; 00179 00180 // cancel request if it is a read request, there might be 00181 // write requests 'stolen' from a write_pool that may not be canceled 00182 if (cache_el->second.second->get_type() == request::READ) 00183 cache_el->second.second->cancel(); 00184 // finish the request 00185 cache_el->second.second->wait(); 00186 ++free_blocks_size; 00187 free_blocks.push_back(cache_el->second.first); 00188 busy_blocks.erase(cache_el); 00189 return true; 00190 } 00191 00192 bool in_prefetching(bid_type bid) 00193 { 00194 return (busy_blocks.find(bid) != busy_blocks.end()); 00195 } 00196 00197 //! \brief Reads block. If this block is cached block is not read but passed from the cache 00198 //! \param block block object, where data to be read to. If block was cached \c block 's 00199 //! ownership goes to the pool and block from cache is returned in \c block value. 00200 //! \param bid address of the block 00201 //! \warning \c block parameter must be allocated dynamically using \c new . 00202 //! \return request pointer object of read operation 00203 request_ptr read(block_type * & block, bid_type bid) 00204 { 00205 busy_blocks_iterator cache_el = busy_blocks.find(bid); 00206 if (cache_el == busy_blocks.end()) 00207 { 00208 // not cached 00209 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block); 00210 return block->read(bid); 00211 } 00212 00213 // cached 00214 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists"); 00215 ++free_blocks_size; 00216 free_blocks.push_back(block); 00217 block = cache_el->second.first; 00218 request_ptr result = cache_el->second.second; 00219 busy_blocks.erase(cache_el); 00220 return result; 00221 } 00222 00223 request_ptr read(block_type * & block, bid_type bid, write_pool<block_type> & w_pool) 00224 { 00225 // try cache 00226 busy_blocks_iterator cache_el = busy_blocks.find(bid); 00227 if (cache_el != busy_blocks.end()) 00228 { 00229 // cached 00230 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists"); 00231 ++free_blocks_size; 00232 free_blocks.push_back(block); 00233 block = cache_el->second.first; 00234 request_ptr result = cache_el->second.second; 00235 busy_blocks.erase(cache_el); 00236 return result; 00237 } 00238 00239 // try w_pool cache 00240 if (w_pool.has_request(bid)) 00241 { 00242 busy_entry wp_request = w_pool.steal_request(bid); 00243 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " was in write cache at " << wp_request.first); 00244 assert(wp_request.first != 0); 00245 w_pool.add(block); //in exchange 00246 block = wp_request.first; 00247 return wp_request.second; 00248 } 00249 00250 // not cached 00251 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block); 00252 return block->read(bid); 00253 } 00254 00255 //! \brief Resizes size of the pool 00256 //! \param new_size desired size of the pool. If some 00257 //! blocks are used for prefetching, these blocks can't be freed. 00258 //! Only free blocks (not in prefetching) can be freed by reducing 00259 //! the size of the pool calling this method. 00260 //! \return new size of the pool 00261 unsigned_type resize(unsigned_type new_size) 00262 { 00263 int_type diff = int_type(new_size) - int_type(size()); 00264 if (diff > 0) 00265 { 00266 free_blocks_size += diff; 00267 while (--diff >= 0) 00268 free_blocks.push_back(new block_type); 00269 00270 00271 return size(); 00272 } 00273 00274 while (diff < 0 && free_blocks_size > 0) 00275 { 00276 ++diff; 00277 --free_blocks_size; 00278 delete free_blocks.back(); 00279 free_blocks.pop_back(); 00280 } 00281 return size(); 00282 } 00283 }; 00284 00285 //! \} 00286 00287 __STXXL_END_NAMESPACE 00288 00289 namespace std 00290 { 00291 template <class BlockType> 00292 void swap(stxxl::prefetch_pool<BlockType> & a, 00293 stxxl::prefetch_pool<BlockType> & b) 00294 { 00295 a.swap(b); 00296 } 00297 } 00298 00299 #endif // !STXXL_PREFETCH_POOL_HEADER 00300 // vim: et:ts=4:sw=4