diff options
author | José Fonseca <jfonseca@vmware.com> | 2014-10-06 20:32:07 +0100 |
---|---|---|
committer | José Fonseca <jfonseca@vmware.com> | 2014-10-06 20:37:59 +0100 |
commit | 9f9bc14c28aed7b2571e641bfeeca81876ec48ec (patch) | |
tree | bf7ff90e818823ef2007a83edc84538d65bc75f5 | |
parent | 9eec93462df6d01fe33a737bb4a185e9ad6cee15 (diff) |
retrace: Put a ceiling into the total size of bound blobs.
Some OpenGL applications that use vertex arrays in user memory were
exausting all memory with bound buffers. This change enables retrace to
complete.
Merit for the idea goes to idinev, in issue #222. This implemetation
limits total size of bound blobs, instead of total number.
-rw-r--r-- | common/trace_model.cpp | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/common/trace_model.cpp b/common/trace_model.cpp index 6dec4240..c91a9943 100644 --- a/common/trace_model.cpp +++ b/common/trace_model.cpp @@ -25,6 +25,7 @@ #include <string.h> +#include <deque> #include "trace_model.hpp" @@ -79,17 +80,75 @@ Array::~Array() { } } + +#define BLOB_MAX_BOUND_SIZE (1*1024*1024*1024) + +class BoundBlob { +public: + static size_t totalSize; + +private: + size_t size; + char *buf; + +public: + inline + BoundBlob(size_t _size, char *_buf) : + size(_size), + buf(_buf) + { + assert(totalSize + size >= totalSize); + totalSize += size; + } + + inline + ~BoundBlob() { + assert(totalSize >= size); + totalSize -= size; + delete [] buf; + } + + // Fake move constructor + // std::deque:push_back with move semantics was added only from c++11. + BoundBlob(const BoundBlob & other) + { + size = other.size; + buf = other.buf; + const_cast<BoundBlob &>(other).size = 0; + const_cast<BoundBlob &>(other).buf = 0; + } + + // Disallow assignment operator + BoundBlob& operator = (const BoundBlob &); +}; + +size_t BoundBlob::totalSize = 0; + +typedef std::deque<BoundBlob> BoundBlobQueue; +static BoundBlobQueue boundBlobQueue; + + Blob::~Blob() { // Blobs are often bound and referred during many calls, so we can't delete // them here in that case. // // Once bound there is no way to know when they were unbound, which - // effectively means we have to leak them. A better solution would be to - // keep a list of bound pointers, and defer the destruction to when the - // trace in question has been fully processed. + // effectively means we have to leak them. But some applications + // (particularly OpenGL applications that use vertex arrays in user memory) + // we can easily exhaust all memory. So instead we maintain a queue of + // bound blobs and keep the total size bounded. + if (!bound) { delete [] buf; + return; + } + + while (!boundBlobQueue.empty() && + BoundBlob::totalSize + size > BLOB_MAX_BOUND_SIZE) { + boundBlobQueue.pop_front(); } + + boundBlobQueue.push_back(BoundBlob(size, buf)); } StackFrame::~StackFrame() { |