From 9f9bc14c28aed7b2571e641bfeeca81876ec48ec Mon Sep 17 00:00:00 2001 From: José Fonseca Date: Mon, 6 Oct 2014 20:32:07 +0100 Subject: 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. --- common/trace_model.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) (limited to 'common') 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 +#include #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(other).size = 0; + const_cast(other).buf = 0; + } + + // Disallow assignment operator + BoundBlob& operator = (const BoundBlob &); +}; + +size_t BoundBlob::totalSize = 0; + +typedef std::deque 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() { -- cgit v1.2.3