Ptex
PtexCache.h
Go to the documentation of this file.
1 #ifndef PtexCache_h
2 #define PtexCache_h
3 
4 /*
5 PTEX SOFTWARE
6 Copyright 2009 Disney Enterprises, Inc. All rights reserved
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11 
12  * Redistributions of source code must retain the above copyright
13  notice, this list of conditions and the following disclaimer.
14 
15  * Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in
17  the documentation and/or other materials provided with the
18  distribution.
19 
20  * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
21  Studios" or the names of its contributors may NOT be used to
22  endorse or promote products derived from this software without
23  specific prior written permission from Walt Disney Pictures.
24 
25 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
26 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
27 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
28 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
29 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
30 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37 */
38 
39 #include "PtexPlatform.h"
40 #include <assert.h>
41 
42 #include "PtexMutex.h"
43 #include "Ptexture.h"
44 #include "PtexDict.h"
45 
46 #define USE_SPIN // use spinlocks instead of mutex for main cache lock
47 
48 namespace PtexInternal {
49 
50 #ifdef USE_SPIN
52 #else
53  typedef Mutex CacheLock;
54 #endif
56 
57 #ifndef NDEBUG
58 #define GATHER_STATS
59 #endif
60 
61 #ifdef GATHER_STATS
62  struct CacheStats{
63  int nfilesOpened;
64  int nfilesClosed;
65  int ndataAllocated;
66  int ndataFreed;
67  int nblocksRead;
68  long int nbytesRead;
69  int nseeks;
70 
71  CacheStats()
72  : nfilesOpened(0),
73  nfilesClosed(0),
74  ndataAllocated(0),
75  ndataFreed(0),
76  nblocksRead(0),
77  nbytesRead(0),
78  nseeks(0) {}
79 
80  ~CacheStats();
81  void print();
82  static void inc(int& val) {
83  static SpinLock spinlock;
84  AutoSpin lock(spinlock);
85  val++;
86  }
87  static void add(long int& val, int inc) {
88  static SpinLock spinlock;
89  AutoSpin lock(spinlock);
90  val+=inc;
91  }
92  };
93  extern CacheStats stats;
94 #define STATS_INC(x) stats.inc(stats.x);
95 #define STATS_ADD(x, y) stats.add(stats.x, y);
96 #else
97 #define STATS_INC(x)
98 #define STATS_ADD(x, y)
99 #endif
100 }
101 using namespace PtexInternal;
102 
104 class PtexLruItem {
105 public:
106  bool inuse() { return _prev == 0; }
107  void orphan()
108  {
109  // parent no longer wants me
110  void** p = _parent;
111  _parent = 0;
112  assert(p && *p == this);
113  if (!inuse()) delete this;
114  *p = 0;
115  }
116  template <typename T> static void orphanList(T& list)
117  {
118  for (typename T::iterator i=list.begin(); i != list.end(); i++) {
119  PtexLruItem* obj = *i;
120  if (obj) {
121  assert(obj->_parent == (void**)&*i);
122  obj->orphan();
123  }
124  }
125  }
126 
127 protected:
128  PtexLruItem(void** parent=0)
129  : _parent(parent), _prev(0), _next(0) {}
130  virtual ~PtexLruItem()
131  {
132  // detach from parent (if any)
133  if (_parent) { assert(*_parent == this); *_parent = 0; }
134  // unlink from lru list (if in list)
135  if (_prev) {
136  _prev->_next = _next;
137  _next->_prev = _prev;
138  }
139  }
140 
141 private:
142  friend class PtexLruList; // maintains prev/next, deletes
143  void** _parent; // pointer to this item within parent
144  PtexLruItem* _prev; // prev in lru list (0 if in-use)
145  PtexLruItem* _next; // next in lru list (0 if in-use)
146 };
147 
148 
149 
152 class PtexLruList {
153 public:
154  PtexLruList() { _end._prev = _end._next = &_end; }
155  ~PtexLruList() { while (pop()) continue; }
156 
157  void extract(PtexLruItem* node)
158  {
159  // remove from list
160  node->_prev->_next = node->_next;
161  node->_next->_prev = node->_prev;
162  node->_next = node->_prev = 0;
163  }
164 
165  void push(PtexLruItem* node)
166  {
167  // delete node if orphaned
168  if (!node->_parent) delete node;
169  else {
170  // add to end of list
171  node->_next = &_end;
172  node->_prev = _end._prev;
173  _end._prev->_next = node;
174  _end._prev = node;
175  }
176  }
177 
178  bool pop()
179  {
180  if (_end._next == &_end) return 0;
181  delete _end._next; // item will unlink itself
182  return 1;
183  }
184 
185 private:
187 };
188 
189 
192 class PtexCacheImpl : public PtexCache {
193 public:
194  PtexCacheImpl(int maxFiles, int maxMem)
195  : _pendingDelete(false),
196  _maxFiles(maxFiles), _unusedFileCount(0),
197  _maxDataSize(maxMem),
198  _unusedDataSize(0), _unusedDataCount(0)
199  {
200  /* Allow for a minimum number of data blocks so cache doesn't
201  thrash too much if there are any really big items in the
202  cache pushing over the limit. It's better to go over the
203  limit in this case and make sure there's room for at least
204  a modest number of objects in the cache.
205  */
206 
207  // try to allow for at least 10 objects per file (up to 100 files)
208  _minDataCount = 10 * maxFiles;
209  // but no more than 1000
210  if (_minDataCount > 1000) _minDataCount = 1000;
211  }
212 
213  virtual void release() { delete this; }
214 
217 
218  // internal use - only call from reader classes for deferred deletion
219  void setPendingDelete() { _pendingDelete = true; }
220  void handlePendingDelete() { if (_pendingDelete) delete this; }
221 
222  // internal use - only call from PtexCachedFile, PtexCachedData
223  static void addFile() { STATS_INC(nfilesOpened); }
224  void setFileInUse(PtexLruItem* file);
225  void setFileUnused(PtexLruItem* file);
226  void removeFile();
227  static void addData() { STATS_INC(ndataAllocated); }
228  void setDataInUse(PtexLruItem* data, int size);
229  void setDataUnused(PtexLruItem* data, int size);
230  void removeData(int size);
231 
232  void purgeFiles() {
233  while (_unusedFileCount > _maxFiles)
234  {
235  if (!_unusedFiles.pop()) break;
236  // note: pop will destroy item and item destructor will
237  // call removeFile which will decrement _unusedFileCount
238  }
239  }
240  void purgeData() {
241  while ((_unusedDataSize > _maxDataSize) &&
242  (_unusedDataCount > _minDataCount))
243  {
244  if (!_unusedData.pop()) break;
245  // note: pop will destroy item and item destructor will
246  // call removeData which will decrement _unusedDataSize
247  // and _unusedDataCount
248  }
249  }
250 
251 protected:
252  ~PtexCacheImpl();
253 
254 private:
255  bool _pendingDelete; // flag set if delete is pending
256 
257  int _maxFiles, _unusedFileCount; // file limit, current unused file count
258  long int _maxDataSize, _unusedDataSize; // data limit (bytes), current size
259  int _minDataCount, _unusedDataCount; // min, current # of unused data blocks
260  PtexLruList _unusedFiles, _unusedData; // lists of unused items
261 };
262 
263 
266 {
267 public:
268  PtexCachedFile(void** parent, PtexCacheImpl* cache)
269  : PtexLruItem(parent), _cache(cache), _refcount(1)
270  { _cache->addFile(); }
271  void ref() { assert(_cache->cachelock.locked()); if (!_refcount++) _cache->setFileInUse(this); }
272  void unref() { assert(_cache->cachelock.locked()); if (!--_refcount) _cache->setFileUnused(this); }
273 protected:
274  virtual ~PtexCachedFile() { _cache->removeFile(); }
276 private:
278 };
279 
280 
283 {
284 public:
285  PtexCachedData(void** parent, PtexCacheImpl* cache, int size)
286  : PtexLruItem(parent), _cache(cache), _refcount(1), _size(size)
287  { _cache->addData(); }
288  void ref() { assert(_cache->cachelock.locked()); if (!_refcount++) _cache->setDataInUse(this, _size); }
289  void unref() { assert(_cache->cachelock.locked()); if (!--_refcount) _cache->setDataUnused(this, _size); }
290 protected:
291  void incSize(int size) { _size += size; }
292  virtual ~PtexCachedData() { _cache->removeData(_size); }
294 private:
296  int _size;
297 };
298 
299 
300 #endif
void handlePendingDelete()
Definition: PtexCache.h:220
void ** _parent
Definition: PtexCache.h:143
bool inuse()
Definition: PtexCache.h:106
bool _pendingDelete
Definition: PtexCache.h:255
void incSize(int size)
Definition: PtexCache.h:291
long int _unusedDataSize
Definition: PtexCache.h:258
void purgeData()
Definition: PtexCache.h:240
void unref()
Definition: PtexCache.h:272
PtexLruItem _end
Definition: PtexCache.h:186
File-handle and memory cache for reading ptex files.
Definition: Ptexture.h:634
int _unusedFileCount
Definition: PtexCache.h:257
Platform-specific classes, functions, and includes.
void setPendingDelete()
Definition: PtexCache.h:219
#define STATS_INC(x)
Definition: PtexCache.h:97
int _unusedDataCount
Definition: PtexCache.h:259
PtexCacheImpl * _cache
Definition: PtexCache.h:275
bool pop()
Definition: PtexCache.h:178
void unref()
Definition: PtexCache.h:289
virtual ~PtexCachedFile()
Definition: PtexCache.h:274
static void addData()
Definition: PtexCache.h:227
void purgeFiles()
Definition: PtexCache.h:232
PtexCachedFile(void **parent, PtexCacheImpl *cache)
Definition: PtexCache.h:268
virtual ~PtexCachedData()
Definition: PtexCache.h:292
void push(PtexLruItem *node)
Definition: PtexCache.h:165
SpinLock CacheLock
Definition: PtexCache.h:51
Cache entry for allocated memory block.
Definition: PtexCache.h:282
Mutex openlock
Definition: PtexCache.h:215
One item in a cache, typically an open file or a block of memory.
Definition: PtexCache.h:104
static void orphanList(T &list)
Definition: PtexCache.h:116
PtexCacheImpl * _cache
Definition: PtexCache.h:293
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexCache.h:213
AutoLock< CacheLock > AutoLockCache
Definition: PtexCache.h:55
For internal use only.
Definition: PtexCache.h:48
PtexCachedData(void **parent, PtexCacheImpl *cache, int size)
Definition: PtexCache.h:285
PtexLruItem * _next
Definition: PtexCache.h:145
virtual ~PtexLruItem()
Definition: PtexCache.h:130
Cache entry for open file handle.
Definition: PtexCache.h:265
CacheLock cachelock
Definition: PtexCache.h:216
Ptex cache implementation.
Definition: PtexCache.h:192
Contains PtexDict, a string-keyed hash table.
PtexLruItem * _prev
Definition: PtexCache.h:144
void orphan()
Definition: PtexCache.h:107
Automatically acquire and release lock within enclosing scope.
Definition: PtexMutex.h:58
PtexLruItem(void **parent=0)
Definition: PtexCache.h:128
PtexCacheImpl(int maxFiles, int maxMem)
Definition: PtexCache.h:194
A list of items kept in least-recently-used (LRU) order.
Definition: PtexCache.h:152
static void addFile()
Definition: PtexCache.h:223
Public API classes for reading, writing, caching, and filtering Ptex files.
PtexLruList _unusedFiles
Definition: PtexCache.h:260
void extract(PtexLruItem *node)
Definition: PtexCache.h:157