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 2014 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 <cstddef>
41 
42 #include "PtexMutex.h"
43 #include "PtexHashMap.h"
44 #include "PtexReader.h"
45 
47 
48 // Intrusive LRU list item (to be used only by PtexLruList)
50 {
53 
54  void extract() {
55  _next->_prev = _prev;
56  _prev->_next = _next;
57  _next = _prev = this;
58  }
59 
60 public:
61  PtexLruItem() : _prev(this), _next(this) {}
62 
63  // add item to end of list (pointed to by _prev)
64  void push(PtexLruItem* item) {
65  item->extract();
66  _prev->_next = item;
67  item->_next = this;
68  item->_prev = _prev;
69  _prev = item;
70  }
71 
72  // remove item from front of list (pointed to by _next)
74  if (_next == this) return 0;
75  PtexLruItem* item = _next;
76  _next->extract();
77  return item;
78  }
79 };
80 
81 // Intrusive LRU list (with LRU item stored as member of T)
82 template<class T, PtexLruItem T::*item>
84 {
86 
87 public:
88  void push(T* node)
89  {
90  // the item is added to the intrusive pointer specified by the template
91  // templatization allows more than one intrusive list to be in the object
92  _end.push(&(node->*item));
93  }
94 
95  T* pop()
96  {
97  PtexLruItem* it = _end.pop();
98  // "it" points to the intrusive item, a member within T
99  // subtract off the pointer-to-member offset to get a pointer to the containing T object
100  static const T* dummy = 0;
101  static const std::ptrdiff_t itemOffset = (const char*)&(dummy->*item) - (const char*)dummy;
102  return it ? (T*) ((char*)it - itemOffset) : 0;
103  }
104 };
105 
106 class PtexReaderCache;
107 
109 {
111  volatile int32_t _refCount;
117  friend class PtexReaderCache;
118 
119  bool trylock()
120  {
121  return AtomicCompareAndSwap(&_refCount, 0, -1);
122  }
123 
124  void unlock()
125  {
126  AtomicStore(&_refCount, 0);
127  }
128 
129 public:
130  PtexCachedReader(bool premultiply, PtexInputHandler* inputHandler, PtexErrorHandler* errorHandler, PtexReaderCache* cache)
131  : PtexReader(premultiply, inputHandler, errorHandler), _cache(cache), _refCount(1),
133  {
134  }
135 
137 
138  void ref() {
139  // Note: a negative ref count indicates the texture is locked, e.g. for pruning or purging.
140  // This should happen rarely, and only for a brief instant, but when it does we must wait
141  // for the ref count to become non-negative again. We do so by making CompareAndSwap fail
142  // when the old value is negative.
143  while (1) {
144  int32_t oldCount = std::max(0, int32_t(_refCount));
145  int32_t newCount = oldCount+1;
146  if (AtomicCompareAndSwap(&_refCount, oldCount, newCount))
147  return;
148  }
149  }
150 
151  int32_t unref() {
152  int32_t newCount = AtomicDecrement(&_refCount);
153  if (newCount < 0) {
154  // A negative ref count here indicates an application error. The negative ref count also
155  // means the texture is now inadvertently locked. Set an error state, unlock the
156  // texture.
157  setError("PtexTexture Error: unref() called with refCount <= 0");
158  unlock();
159  }
160  return newCount;
161  }
162 
163  virtual void release();
164 
165  bool tryPrune(size_t& memUsedChange) {
166  if (trylock()) {
167  prune();
168  memUsedChange = getMemUsedChange();
169  unlock();
170  return true;
171  }
172  return false;
173  }
174 
175  bool tryPurge(size_t& memUsedChange) {
176  if (trylock()) {
177  purge();
178  memUsedChange = getMemUsedChange();
179  unlock();
180  return true;
181  }
182  setPendingPurge();
183  return false;
184  }
185 
186  size_t getMemUsedChange() {
187  size_t memUsedTmp = _memUsed;
188  size_t result = memUsedTmp - _memUsedAccountedFor;
189  _memUsedAccountedFor = memUsedTmp;
190  return result;
191  }
192 
193  size_t getOpensChange() {
194  size_t opensTmp = _opens;
195  size_t result = opensTmp - _opensAccountedFor;
196  _opensAccountedFor = opensTmp;
197  return result;
198  }
199 
201  size_t blockReadsTmp = _blockReads;
202  size_t result = blockReadsTmp - _blockReadsAccountedFor;
203  _blockReadsAccountedFor = blockReadsTmp;
204  return result;
205  }
206 };
207 
208 
211 {
212 public:
213  PtexReaderCache(int maxFiles, size_t maxMem, bool premultiply, PtexInputHandler* inputHandler, PtexErrorHandler* errorHandler)
214  : _maxFiles(maxFiles), _maxMem(maxMem), _io(inputHandler), _err(errorHandler), _premultiply(premultiply),
215  _memUsed(sizeof(*this)), _filesOpen(0), _mruList(&_mruLists[0]), _prevMruList(&_mruLists[1]),
217  {
218  memset((void*)&_mruLists[0], 0, sizeof(_mruLists));
219  CACHE_LINE_PAD_INIT(_memUsed); // keep cppcheck happy
222  }
223 
225  {}
226 
227  virtual void release() { delete this; }
228 
229  virtual void setSearchPath(const char* path)
230  {
231  // record path
232  _searchpath = path ? path : "";
233 
234  // split into dirs
235  _searchdirs.clear();
236 
237  if (path) {
238  const char* cp = path;
239  while (1) {
240  const char* delim = strchr(cp, ':');
241  if (!delim) {
242  if (*cp) _searchdirs.push_back(cp);
243  break;
244  }
245  int len = int(delim-cp);
246  if (len) _searchdirs.push_back(std::string(cp, len));
247  cp = delim+1;
248  }
249  }
250  }
251 
252  virtual const char* getSearchPath()
253  {
254  return _searchpath.c_str();
255  }
256 
257  virtual PtexTexture* get(const char* path, Ptex::String& error);
258 
259  virtual void purge(PtexTexture* /*texture*/);
260  virtual void purge(const char* /*filename*/);
261  virtual void purgeAll();
262  virtual void getStats(Stats& stats);
263 
264  void purge(PtexCachedReader* reader);
265 
266  void adjustMemUsed(size_t amount) {
267  if (amount) {
268  size_t memUsed = AtomicAdd(&_memUsed, amount);
269  _peakMemUsed = std::max(_peakMemUsed, memUsed);
270  }
271  }
272  void adjustFilesOpen(size_t amount) {
273  if (amount) {
274  size_t filesOpen = AtomicAdd(&_filesOpen, amount);
275  _peakFilesOpen = std::max(_peakFilesOpen, filesOpen);
276  }
277  }
278  void logRecentlyUsed(PtexCachedReader* reader);
279 
280 private:
281  struct Purger {
284  void operator() (PtexCachedReader* reader);
285  };
286 
287  bool findFile(const char*& filename, std::string& buffer, Ptex::String& error);
288  void processMru();
289  void pruneFilesIfNeeded();
290  void pruneDataIfNeeded();
291  size_t _maxFiles;
292  size_t _maxMem;
295  std::string _searchpath;
296  std::vector<std::string> _searchdirs;
300  volatile size_t _memUsed; CACHE_LINE_PAD(_memUsed,size_t);
301  volatile size_t _filesOpen; CACHE_LINE_PAD(_filesOpen,size_t);
303 
304  static constexpr int maxMruFiles = 50;
305  struct MruList {
306  volatile int next;
308  };
310  MruList* volatile _mruList;
312 
315 
316  size_t _peakMemUsed;
318  size_t _fileOpens;
319  size_t _blockReads;
320 };
321 
323 
324 #endif
Contains PtexHashMap, a lightweight multi-threaded hash table.
Platform-specific classes, functions, and includes.
PTEX_INLINE T AtomicAdd(volatile T *target, T value)
Definition: PtexPlatform.h:211
#define CACHE_LINE_PAD_INIT(var)
Definition: PtexPlatform.h:303
PTEX_INLINE T AtomicDecrement(volatile T *target)
Definition: PtexPlatform.h:249
PTEX_INLINE void AtomicStore(T volatile *target, T value)
Definition: PtexPlatform.h:286
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:280
#define PTEX_NAMESPACE_END
Definition: PtexVersion.h:62
File-handle and memory cache for reading ptex files.
Definition: Ptexture.h:693
size_t _memUsedAccountedFor
Definition: PtexCache.h:112
PtexReaderCache * _cache
Definition: PtexCache.h:110
size_t _opensAccountedFor
Definition: PtexCache.h:113
int32_t unref()
Definition: PtexCache.h:151
bool tryPurge(size_t &memUsedChange)
Definition: PtexCache.h:175
size_t getMemUsedChange()
Definition: PtexCache.h:186
PtexCachedReader(bool premultiply, PtexInputHandler *inputHandler, PtexErrorHandler *errorHandler, PtexReaderCache *cache)
Definition: PtexCache.h:130
bool tryPrune(size_t &memUsedChange)
Definition: PtexCache.h:165
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexCache.cpp:83
PtexLruItem _activeFilesItem
Definition: PtexCache.h:116
size_t _blockReadsAccountedFor
Definition: PtexCache.h:114
PtexLruItem _openFilesItem
Definition: PtexCache.h:115
size_t getBlockReadsChange()
Definition: PtexCache.h:200
size_t getOpensChange()
Definition: PtexCache.h:193
volatile int32_t _refCount
Definition: PtexCache.h:111
Custom handler interface redirecting Ptex error messages.
Definition: Ptexture.h:667
Custom handler interface for intercepting and redirecting Ptex input stream calls.
Definition: Ptexture.h:628
void extract()
Definition: PtexCache.h:54
PtexLruItem * _prev
Definition: PtexCache.h:51
PtexLruItem * pop()
Definition: PtexCache.h:73
void push(PtexLruItem *item)
Definition: PtexCache.h:64
PtexLruItem * _next
Definition: PtexCache.h:52
PtexLruItem _end
Definition: PtexCache.h:85
T * pop()
Definition: PtexCache.h:95
void push(T *node)
Definition: PtexCache.h:88
Cache for reading Ptex texture files.
Definition: PtexCache.h:211
PtexLruList< PtexCachedReader, &PtexCachedReader::_activeFilesItem > _activeFiles
Definition: PtexCache.h:314
std::string _searchpath
Definition: PtexCache.h:295
PtexInputHandler * _io
Definition: PtexCache.h:293
size_t _maxMem
Definition: PtexCache.h:292
void adjustFilesOpen(size_t amount)
Definition: PtexCache.h:272
size_t _fileOpens
Definition: PtexCache.h:318
volatile size_t _memUsed
Definition: PtexCache.h:300
virtual const char * getSearchPath()
Query the search path.
Definition: PtexCache.h:252
void logRecentlyUsed(PtexCachedReader *reader)
Definition: PtexCache.cpp:184
MruList *volatile _prevMruList
Definition: PtexCache.h:311
void pruneFilesIfNeeded()
Definition: PtexCache.cpp:249
FileMap _files
Definition: PtexCache.h:298
void adjustMemUsed(size_t amount)
Definition: PtexCache.h:266
size_t _peakMemUsed
Definition: PtexCache.h:316
virtual void release()
Release PtexCache. Cache will be immediately destroyed and all resources will be released.
Definition: PtexCache.h:227
virtual void setSearchPath(const char *path)
Set a search path for finding textures.
Definition: PtexCache.h:229
virtual PtexTexture * get(const char *path, Ptex::String &error)
Access a texture.
Definition: PtexCache.cpp:125
bool findFile(const char *&filename, std::string &buffer, Ptex::String &error)
Definition: PtexCache.cpp:95
static constexpr int maxMruFiles
Definition: PtexCache.h:304
virtual void getStats(Stats &stats)
Get stats.
Definition: PtexCache.cpp:331
PtexReaderCache(int maxFiles, size_t maxMem, bool premultiply, PtexInputHandler *inputHandler, PtexErrorHandler *errorHandler)
Definition: PtexCache.h:213
size_t _maxFiles
Definition: PtexCache.h:291
size_t _peakFilesOpen
Definition: PtexCache.h:317
PtexErrorHandler * _err
Definition: PtexCache.h:294
CACHE_LINE_PAD(_memUsed, size_t)
PtexLruList< PtexCachedReader, &PtexCachedReader::_openFilesItem > _openFiles
Definition: PtexCache.h:313
PtexHashMap< StringKey, PtexCachedReader * > FileMap
Definition: PtexCache.h:297
virtual void purgeAll()
Remove all texture files from the cache.
Definition: PtexCache.cpp:324
size_t _blockReads
Definition: PtexCache.h:319
void pruneDataIfNeeded()
Definition: PtexCache.cpp:268
volatile size_t _filesOpen
Definition: PtexCache.h:301
MruList *volatile _mruList
Definition: PtexCache.h:310
virtual void purge(PtexTexture *)
Remove a texture file from the cache.
Definition: PtexCache.cpp:292
MruList _mruLists[2]
Definition: PtexCache.h:309
std::vector< std::string > _searchdirs
Definition: PtexCache.h:296
void setPendingPurge()
Definition: PtexReader.h:62
volatile size_t _opens
Definition: PtexReader.h:709
void purge()
Definition: PtexReader.cpp:117
void setError(const char *error, bool ioError=false)
Definition: PtexReader.h:549
void prune()
Definition: PtexReader.cpp:106
volatile size_t _memUsed
Definition: PtexReader.h:708
volatile size_t _blockReads
Definition: PtexReader.h:710
Interface for reading data from a ptex file.
Definition: Ptexture.h:460
Memory-managed string.
Definition: Ptexture.h:299
PtexCachedReader *volatile files[maxMruFiles]
Definition: PtexCache.h:307
void operator()(PtexCachedReader *reader)
Definition: PtexCache.cpp:316