NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cache_inl.h
Go to the documentation of this file.
1 /*
2  * nvbio
3  * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the NVIDIA CORPORATION nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #pragma once
29 
30 namespace nvbio {
31 
32 template <typename CacheManager>
33 LRU<CacheManager>::LRU(CacheManager& manager) : m_first(0xFFFFFFFFu), m_last(0xFFFFFFFFu), m_manager(&manager) {}
34 
35 template <typename CacheManager>
37 {
38  typename std::map<uint32,uint32>::iterator it = m_cache_map.find( item );
39  if (it == m_cache_map.end())
40  {
41  uint32 list_idx;
42  if (m_cache_pool.size())
43  {
44  list_idx = m_cache_pool.top();
45  m_cache_pool.pop();
46  }
47  else
48  {
49  list_idx = uint32( m_cache_list.size() );
50  m_cache_list.push_back( List() );
51  }
52 
53  m_cache_map.insert( std::make_pair( item, list_idx ) );
54 
55  List& list = m_cache_list[ list_idx ];
56  list.m_item = item;
57  list.m_next = m_first;
58  list.m_prev = 0xFFFFFFFFu;
59  list.m_pinned = true;
60 
61  // insert at the beginning of the LRU list
62  if (m_first != 0xFFFFFFFFu)
63  {
64  List& first = m_cache_list[ m_first ];
65  first.m_prev = list_idx;
66  }
67 
68  m_first = list_idx;
69  if (m_last == 0xFFFFFFFFu)
70  m_last = m_first;
71 
72  if (m_manager->acquire( item ) == false)
73  release_cycle( item );
74  }
75  else
76  {
77  // pin element
78  List& list = m_cache_list[ it->second ];
79  list.m_pinned = true;
80 
81  // move at the beginning of the LRU list
82  touch( it->second, list );
83  }
84 }
85 
86 template <typename CacheManager>
88 {
89  typename std::map<uint32,uint32>::iterator it = m_cache_map.find( item );
90  const uint32 list_idx = it->second;
91 
92  List& list = m_cache_list[ list_idx ];
93  list.m_pinned = false;
94 
95  // move at the beginning of the LRU list
96  touch( list_idx, list );
97 }
98 
99 template <typename CacheManager>
100 void LRU<CacheManager>::touch(const uint32 list_idx, List& list)
101 {
102  // check whether this element is already at the beginning of the LRU list
103  if (m_first == list_idx)
104  return;
105 
106  // extract element from the LRU list
107  if (list.m_prev != 0xFFFFFFFFu)
108  {
109  List& prev = m_cache_list[ list.m_prev ];
110  prev.m_next = list.m_next;
111  }
112  if (list.m_next != 0xFFFFFFFFu)
113  {
114  List& next = m_cache_list[ list.m_next ];
115  next.m_next = list.m_prev;
116  }
117  else // mark the new end of list
118  m_last = list.m_prev;
119 
120  // re-insert at the beginning of the LRU list
121  m_first = list_idx;
122 }
123 
124 template <typename CacheManager>
125 void LRU<CacheManager>::release_cycle(const uint32 item_to_acquire)
126 {
127  // walk the list from the end
128  uint32 list_idx = m_last;
129  bool acquired = false;
130 
131  do
132  {
133  if (list_idx == 0xFFFFFFFFu)
134  {
135  if (acquired)
136  break;
137  else
138  throw cache_overflow();
139  }
140 
141  List& list = m_cache_list[ list_idx ];
142  if (list.m_pinned)
143  {
144  list_idx = list.m_prev;
145  continue;
146  }
147 
148  const uint32 prev = list.m_prev;
149 
150  // extract element from the LRU list
151  if (list.m_prev != 0xFFFFFFFFu)
152  {
153  List& prev = m_cache_list[ list.m_prev ];
154  prev.m_next = list.m_next;
155  }
156  else // mark the list as empty
157  m_first = 0xFFFFFFFFu;
158 
159  if (list.m_next != 0xFFFFFFFFu)
160  {
161  List& next = m_cache_list[ list.m_next ];
162  next.m_next = list.m_prev;
163  }
164  else // mark the new end of list
165  m_last = list.m_prev;
166 
167  const uint32 item = list.m_item;
168 
169  // release this list entry
170  m_cache_pool.push( list_idx );
171 
172  // and remove from the map
173  m_cache_map.erase( m_cache_map.find( item ) );
174 
175  m_manager->release( item );
176  if (acquired == false && m_manager->acquire( item_to_acquire ))
177  acquired = true;
178 
179  // jump to the previous
180  list_idx = prev;
181  }
182  while (m_manager->low_watermark() == false);
183 }
184 
185 } // namespace nvbio