Adds generic memcache limitor (used by the new sequencer to cache
authorPeter Schlaile <peter@schlaile.de>
Sun, 5 Feb 2006 18:56:30 +0000 (18:56 +0000)
committerPeter Schlaile <peter@schlaile.de>
Sun, 5 Feb 2006 18:56:30 +0000 (18:56 +0000)
only a certain amount of frames).

intern/memutil/MEM_Allocator.h [new file with mode: 0644]
intern/memutil/MEM_CacheLimiter.h [new file with mode: 0644]
intern/memutil/MEM_CacheLimiterC-Api.h [new file with mode: 0644]
intern/memutil/SConscript
intern/memutil/intern/MEM_CacheLimiterC-Api.cpp [new file with mode: 0644]
intern/memutil/intern/Makefile

diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h
new file mode 100644 (file)
index 0000000..4071649
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __MEM_Allocator_h_included__
+#define __MEM_Allocator_h_included__ 1
+
+#include "guardedalloc/MEM_guardedalloc.h"
+
+template<typename _Tp>
+struct MEM_Allocator
+{
+       typedef size_t    size_type;
+       typedef ptrdiff_t difference_type;
+       typedef _Tp*       pointer;
+       typedef const _Tp* const_pointer;
+       typedef _Tp&       reference;
+       typedef const _Tp& const_reference;
+       typedef _Tp        value_type;
+
+       template<typename _Tp1>
+        struct rebind { 
+               typedef MEM_Allocator<_Tp1> other; 
+       };
+
+       MEM_Allocator() throw() {}
+       MEM_Allocator(const MEM_Allocator& __a) throw() {}
+
+       template<typename _Tp1>
+        MEM_Allocator(const MEM_Allocator<_Tp1> __a) throw() { }
+
+       ~MEM_Allocator() throw() {}
+
+       pointer address(reference __x) const { return &__x; }
+
+       const_pointer address(const_reference __x) const { return &__x; }
+
+       // NB: __n is permitted to be 0.  The C++ standard says nothing
+       // about what the return value is when __n == 0.
+       _Tp* allocate(size_type __n, const void* = 0) {
+               _Tp* __ret = 0;
+               if (__n)
+                       __ret = static_cast<_Tp*>(
+                               MEM_mallocN(__n * sizeof(_Tp),
+                                           "STL MEM_Allocator"));
+               return __ret;
+       }
+
+       // __p is not permitted to be a null pointer.
+       void deallocate(pointer __p, size_type){ 
+               MEM_freeN(__p);
+       }
+
+       size_type max_size() const throw() { 
+               return size_t(-1) / sizeof(_Tp); 
+       }
+
+       void construct(pointer __p, const _Tp& __val) { 
+               new(__p) _Tp(__val); 
+       }
+
+       void destroy(pointer __p) { 
+               __p->~_Tp(); 
+       }
+};
+
+#endif
diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h
new file mode 100644 (file)
index 0000000..3026e82
--- /dev/null
@@ -0,0 +1,170 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __MEM_cache_limiter_h_included__
+#define __MEM_cache_limiter_h_included__ 1
+
+/**
+ * @section MEM_CacheLimiter
+ * This class defines a generic memory cache management system
+ * to limit memory usage to a fixed global maximum.
+ * 
+ * Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C.
+ *
+ * Usage example:
+ *
+ * class BigFatImage {
+ * public:
+ *       ~BigFatImage() { tell_everyone_we_are_gone(this); }
+ * };
+ * 
+ * void doit() {
+ *     MEM_Cache<BigFatImage> BigFatImages;
+ *
+ *     MEM_Cache_Handle<BigFatImage>* h = BigFatImages.insert(new BigFatImage);
+ * 
+ *     BigFatImages.enforce_limits();
+ *     h->ref();
+ *
+ *     work with image...
+ *
+ *     h->unref();
+ *
+ *     leave image in cache.
+ */
+
+#include <list>
+#include "MEM_Allocator.h"
+
+template<class T>
+class MEM_CacheLimiter;
+
+#ifndef __MEM_cache_limiter_c_api_h_included__
+extern "C" {
+       extern void MEM_CacheLimiter_set_maximum(int m);
+       extern int MEM_CacheLimiter_get_maximum();
+};
+#endif
+
+template<class T>
+class MEM_CacheLimiterHandle {
+public:
+       explicit MEM_CacheLimiterHandle(T * data_, 
+                                        MEM_CacheLimiter<T> * parent_) 
+               : data(data_), refcount(0), parent(parent_) { }
+
+       void ref() { 
+               refcount++; 
+       }
+       void unref() { 
+               refcount--; 
+       }
+       T * get() { 
+               return data; 
+       }
+       const T * get() const { 
+               return data; 
+       }
+       int get_refcount() const { 
+               return refcount; 
+       }
+       bool can_destroy() const { 
+               return !data || !refcount; 
+       }
+       bool destroy_if_possible() {
+               if (can_destroy()) {
+                       delete data;
+                       data = 0;
+                       unmanage();
+                       return true;
+               }
+               return false;
+       }
+       void unmanage() {
+               parent->unmanage(this);
+       }
+       void touch() {
+               parent->touch(this);
+       }
+private:
+       friend class MEM_CacheLimiter<T>;
+
+       T * data;
+       int refcount;
+       typename std::list<MEM_CacheLimiterHandle<T> *, 
+         MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me;
+       MEM_CacheLimiter<T> * parent;
+};
+
+template<class T>
+class MEM_CacheLimiter {
+public:
+       typedef typename std::list<MEM_CacheLimiterHandle<T> *,
+         MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator iterator;
+       ~MEM_CacheLimiter() {
+               for (iterator it = queue.begin(); it != queue.end(); it++) {
+                       delete *it;
+               }
+       }
+       MEM_CacheLimiterHandle<T> * insert(T * elem) {
+               queue.push_back(new MEM_CacheLimiterHandle<T>(elem, this));
+               iterator it = queue.end();
+               --it;
+               queue.back()->me = it;
+               return queue.back();
+       }
+       void unmanage(MEM_CacheLimiterHandle<T> * handle) {
+               queue.erase(handle->me);
+               delete handle;
+       }
+       void enforce_limits() {
+               // this is rather _ugly_!
+               extern int mem_in_use;
+
+               int max = MEM_CacheLimiter_get_maximum();
+               if (max == 0) {
+                       return;
+               }
+               for (iterator it = queue.begin(); 
+                    it != queue.end() && mem_in_use > max;) {
+                       iterator jt = it;
+                       ++it;
+                       (*jt)->destroy_if_possible();
+               }
+       }
+       void touch(MEM_CacheLimiterHandle<T> * handle) {
+               queue.push_back(handle);
+               queue.erase(handle->me);
+               iterator it = queue.end();
+               --it;
+               handle->me = it;
+       }
+private:
+       std::list<MEM_CacheLimiterHandle<T>*,
+         MEM_Allocator<MEM_CacheLimiterHandle<T> *> > queue;
+};
+
+#endif
diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h
new file mode 100644 (file)
index 0000000..c21b914
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __MEM_cache_limiter_c_api_h_included__
+#define __MEM_cache_limiter_c_api_h_included__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+       
+struct MEM_CacheLimiter_s;
+struct MEM_CacheLimiterHandle_s;
+
+typedef struct MEM_CacheLimiter_s MEM_CacheLimiterC;
+typedef struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC;
+
+#ifndef __MEM_cache_limiter_h_included__
+extern void MEM_CacheLimiter_set_maximum(int m);
+extern int MEM_CacheLimiter_get_maximum();
+#endif
+/** 
+ * Create new MEM_CacheLimiter object 
+ * managed objects are destructed with the data_destructor
+ *
+ * @param data_destructor
+ * @return A new MEM_CacheLimter object
+ */
+
+extern MEM_CacheLimiterC * new_MEM_CacheLimiter(
+       void (*data_destructor) (void * data));
+
+/** 
+ * Delete MEM_CacheLimiter
+ * 
+ * Frees the memory of the CacheLimiter but does not touch managed objects!
+ *
+ * @param This "This" pointer
+ */
+
+extern void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This);
+
+/** 
+ * Manage object
+ * 
+ * @param This "This" pointer, data data object to manage
+ * @return CacheLimiterHandle to ref, unref, touch the managed object
+ */
+       
+extern MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert(
+       MEM_CacheLimiterC * This, void * data);
+
+/** 
+ * Free objects until memory constraints are satisfied
+ * 
+ * @param This "This" pointer
+ */
+
+extern void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This);
+
+/** 
+ * Unmanage object previously inserted object. 
+ * Does _not_ delete managed object!
+ * 
+ * @param This "This" pointer, handle of object
+ */
+       
+extern void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle);
+
+
+/** 
+ * Raise priority of object (put it at the tail of the deletion chain)
+ * 
+ * @param handle of object
+ */
+       
+extern void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle);
+
+/** 
+ * Increment reference counter. Objects with reference counter != 0 are _not_
+ * deleted.
+ * 
+ * @param handle of object
+ */
+       
+extern void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle);
+
+/** 
+ * Decrement reference counter. Objects with reference counter != 0 are _not_
+ * deleted.
+ * 
+ * @param handle of object
+ */
+       
+extern void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle);
+
+/** 
+ * Get reference counter.
+ * 
+ * @param This "This" pointer, handle of object
+ */
+       
+extern int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle);
+
+/** 
+ * Get pointer to managed object
+ * 
+ * @param handle of object
+ */
+       
+extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
index 4d17f13f2143f0145ac9dee5c60447a7d7a3fe7a..dace305e91dc1f8e5ddf542666754c68a145ba8a 100644 (file)
@@ -3,6 +3,6 @@ Import ('env')
 
 sources = env.Glob('intern/*.cpp')
 
-incs = '.'
+incs = '. ..'
 
 env.BlenderLib ('blender_MEM', sources, Split(incs), [], libtype='intern', priority = 10 )
diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
new file mode 100644 (file)
index 0000000..a259569
--- /dev/null
@@ -0,0 +1,195 @@
+/**
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_CacheLimiter.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+static int & get_max() 
+{
+       static int m = 32*1024*1024;
+       return m;
+}
+
+void MEM_CacheLimiter_set_maximum(int m)
+{
+       get_max() = m;
+}
+
+int MEM_CacheLimiter_get_maximum()
+{
+       return get_max();
+}
+
+class MEM_CacheLimiterHandleCClass;
+class MEM_CacheLimiterCClass;
+
+typedef MEM_CacheLimiterHandle<MEM_CacheLimiterHandleCClass> handle_t;
+typedef MEM_CacheLimiter<MEM_CacheLimiterHandleCClass> cache_t;
+typedef std::list<MEM_CacheLimiterHandleCClass*,
+                 MEM_Allocator<MEM_CacheLimiterHandleCClass* > > list_t;
+
+class MEM_CacheLimiterCClass {
+public:
+       MEM_CacheLimiterCClass(void (*data_destructor_) (void * data))
+               : data_destructor(data_destructor_) { 
+       }
+        ~MEM_CacheLimiterCClass();
+       
+       handle_t * insert(void * data);
+
+       void destruct(void * data,
+                     list_t::iterator it);
+
+       cache_t * get_cache() {
+               return &cache;
+       }
+private:
+       void (*data_destructor) (void * data);
+
+       MEM_CacheLimiter<MEM_CacheLimiterHandleCClass> cache;
+       
+       list_t cclass_list;
+};
+
+class MEM_CacheLimiterHandleCClass {
+public:
+       MEM_CacheLimiterHandleCClass(void * data_,
+                                  MEM_CacheLimiterCClass * parent_)
+               : data(data_), parent(parent_) { }
+        ~MEM_CacheLimiterHandleCClass();
+       void set_iter(list_t::iterator it_) {
+               it = it_;
+       }
+       void set_data(void * data_) {
+               data = data_;
+       }
+       void * get_data() const {
+               return data;
+       }
+private:
+       void * data;
+       MEM_CacheLimiterCClass * parent;
+       list_t::iterator it;
+};
+
+handle_t * MEM_CacheLimiterCClass::insert(void * data) 
+{
+       cclass_list.push_back(new MEM_CacheLimiterHandleCClass(data, this));
+       list_t::iterator it = cclass_list.end();
+       --it;
+       cclass_list.back()->set_iter(it);
+       
+       return cache.insert(cclass_list.back());
+}
+
+void MEM_CacheLimiterCClass::destruct(void * data, list_t::iterator it) 
+{
+       data_destructor(data);
+       cclass_list.erase(it);
+}
+
+MEM_CacheLimiterHandleCClass::~MEM_CacheLimiterHandleCClass()
+{
+       if (data) {
+               parent->destruct(data, it);
+       }
+}
+
+MEM_CacheLimiterCClass::~MEM_CacheLimiterCClass()
+{
+       // should not happen, but don't leak memory in this case...
+       for (list_t::iterator it = cclass_list.begin();
+            it != cclass_list.end(); it++) {
+               (*it)->set_data(0);
+               delete *it;
+       }
+}
+
+// ----------------------------------------------------------------------
+
+static inline MEM_CacheLimiterCClass* cast(MEM_CacheLimiterC * l)
+{
+       return (MEM_CacheLimiterCClass*) l;
+}
+
+static inline handle_t* cast(MEM_CacheLimiterHandleC * l)
+{
+       return (handle_t*) l;
+}
+
+MEM_CacheLimiterC * new_MEM_CacheLimiter(
+       void (*data_destructor) (void * data))
+{
+       return (MEM_CacheLimiterC*) new MEM_CacheLimiterCClass(
+               data_destructor);
+}
+
+void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This)
+{
+       delete cast(This);
+}
+
+MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert(
+       MEM_CacheLimiterC * This, void * data)
+{
+       return (MEM_CacheLimiterHandleC *) cast(This)->insert(data);
+}
+
+void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This)
+{
+       cast(This)->get_cache()->enforce_limits();
+}
+       
+void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle)
+{
+       cast(handle)->unmanage();
+}
+       
+void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle)
+{
+       cast(handle)->touch();
+}
+       
+void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle)
+{
+       cast(handle)->ref();
+}
+       
+void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle)
+{
+       cast(handle)->unref();
+}
+
+int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle)
+{
+       return cast(handle)->get_refcount();
+}
+
+       
+void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle)
+{
+       return cast(handle)->get()->get_data();
+}
index 0d0d3af6327afecb0981a73f9acc5c2a8a44b5b5..71ffa6fa7e426bb818b1295894ead215d6c920f1 100644 (file)
@@ -38,5 +38,5 @@ include nan_compile.mk
 
 CCFLAGS += $(LEVEL_2_CPP_WARNINGS)
 
-CPPFLAGS += -I..
+CPPFLAGS += -I.. -I../..