[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [48808] trunk/blender: Improved cache management for movie clips from tomato branch

Sergey Sharybin sergey.vfx at gmail.com
Tue Jul 10 16:43:51 CEST 2012


Revision: 48808
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=48808
Author:   nazgul
Date:     2012-07-10 14:43:50 +0000 (Tue, 10 Jul 2012)
Log Message:
-----------
Improved cache management for movie clips from tomato branch

Replace pseudo-LRU approach of determining which buffer
to remove when running out of space allowed for cache
with approach which would remove the frame which is most
far away from newly added frame.

This is still a bit tricky because it's impossible to
distinguish which frame to delete in situation of:

        CCCC...CC
           ^

it's either user wants to extend left segment of cached
frames and buffers from right segment should be removed
or he wants to join this two segments and in that case
buffers from right segment should be removed.

Would need a bit more investigation which situation
is more common in general usecase.

Additional changes:

- Cleanup some memutil files (which are familiar to cache limiter)

- Add option to make moviecache verbose. If DEBUG_MESSAGES is
  defined in moviecache.c detailed logs would be printed to the
  console.

- Movie caches are now named which helps reading debug messages.

Modified Paths:
--------------
    trunk/blender/intern/memutil/MEM_CacheLimiter.h
    trunk/blender/intern/memutil/MEM_CacheLimiterC-Api.h
    trunk/blender/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
    trunk/blender/source/blender/blenkernel/intern/movieclip.c
    trunk/blender/source/blender/blenkernel/intern/seqcache.c
    trunk/blender/source/blender/imbuf/IMB_moviecache.h
    trunk/blender/source/blender/imbuf/intern/moviecache.c

Modified: trunk/blender/intern/memutil/MEM_CacheLimiter.h
===================================================================
--- trunk/blender/intern/memutil/MEM_CacheLimiter.h	2012-07-10 14:42:37 UTC (rev 48807)
+++ trunk/blender/intern/memutil/MEM_CacheLimiter.h	2012-07-10 14:43:50 UTC (rev 48808)
@@ -32,7 +32,7 @@
  * @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:
@@ -41,12 +41,12 @@
  * 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();
  *
@@ -58,6 +58,8 @@
  */
 
 #include <list>
+#include <queue>
+#include <vector>
 #include "MEM_Allocator.h"
 
 template<class T>
@@ -65,36 +67,44 @@
 
 #ifndef __MEM_CACHELIMITERC_API_H__
 extern "C" {
-	extern void MEM_CacheLimiter_set_maximum(size_t m);
-	extern size_t MEM_CacheLimiter_get_maximum();
+	void MEM_CacheLimiter_set_maximum(size_t m);
+	size_t 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_) { }
+	explicit MEM_CacheLimiterHandle(T * data_,MEM_CacheLimiter<T> *parent_) :
+		data(data_),
+		refcount(0),
+		parent(parent_)
+	{ }
 
-	void ref() { 
-		refcount++; 
+	void ref() {
+		refcount++;
 	}
-	void unref() { 
-		refcount--; 
+
+	void unref() {
+		refcount--;
 	}
-	T * get() { 
-		return data; 
+
+	T *get() {
+		return data;
 	}
-	const T * get() const { 
-		return data; 
+
+	const T *get() const {
+		return data;
 	}
-	int get_refcount() const { 
-		return refcount; 
+
+	int get_refcount() const {
+		return refcount;
 	}
-	bool can_destroy() const { 
-		return !data || !refcount; 
+
+	bool can_destroy() const {
+		return !data || !refcount;
 	}
+
 	bool destroy_if_possible() {
 		if (can_destroy()) {
 			delete data;
@@ -104,48 +114,64 @@
 		}
 		return false;
 	}
+
 	void unmanage() {
 		parent->unmanage(this);
 	}
+
 	void touch() {
 		parent->touch(this);
 	}
+
+	void set_priority(int priority) {
+		this->priority = priority;
+	}
+
+	int get_priority(void) {
+		return this->priority;
+	}
+
 private:
 	friend class MEM_CacheLimiter<T>;
 
 	T * data;
 	int refcount;
-	typename std::list<MEM_CacheLimiterHandle<T> *,
-	  MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me;
+	int priority;
+	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;
 	typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data);
+	typedef int    (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority);
+
 	MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func getDataSize_)
 		: getDataSize(getDataSize_) {
 	}
+
 	~MEM_CacheLimiter() {
 		for (iterator it = queue.begin(); it != queue.end(); it++) {
 			delete *it;
 		}
 	}
-	MEM_CacheLimiterHandle<T> * insert(T * elem) {
+
+	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) {
+
+	void unmanage(MEM_CacheLimiterHandle<T> *handle) {
 		queue.erase(handle->me);
 		delete handle;
 	}
+
 	void enforce_limits() {
+		MEM_CachePriorityQueue priority_queue;
 		size_t max = MEM_CacheLimiter_get_maximum();
 		size_t mem_in_use, cur_size;
 
@@ -159,27 +185,33 @@
 			mem_in_use = MEM_get_memory_in_use();
 		}
 
-		for (iterator it = queue.begin(); 
-		     it != queue.end() && mem_in_use > max;)
-		{
-			iterator jt = it;
-			++it;
+		if (mem_in_use <= max) {
+			return;
+		}
 
-			if(getDataSize) {
-				cur_size= getDataSize((*jt)->get()->get_data());
-			} else {
-				cur_size= mem_in_use;
-			}
+		priority_queue = get_priority_queue();
 
-			(*jt)->destroy_if_possible();
+		while (!priority_queue.empty() && mem_in_use > max) {
+			MEM_CacheElementPtr elem = priority_queue.top();
 
+			priority_queue.pop();
+
 			if(getDataSize) {
-				mem_in_use-= cur_size;
+				cur_size = getDataSize(elem->get()->get_data());
 			} else {
-				mem_in_use-= cur_size - MEM_get_memory_in_use();
+				cur_size = mem_in_use;
 			}
+
+			if (elem->destroy_if_possible()) {
+				if (getDataSize) {
+					mem_in_use -= cur_size;
+				} else {
+					mem_in_use -= cur_size - MEM_get_memory_in_use();
+				}
+			}
 		}
 	}
+
 	void touch(MEM_CacheLimiterHandle<T> * handle) {
 		queue.push_back(handle);
 		queue.erase(handle->me);
@@ -187,7 +219,24 @@
 		--it;
 		handle->me = it;
 	}
+
+	void set_item_priority_func(MEM_CacheLimiter_ItemPriority_Func item_priority_func) {
+		getItemPriority = item_priority_func;
+	}
+
 private:
+	typedef MEM_CacheLimiterHandle<T> *MEM_CacheElementPtr;
+	typedef std::list<MEM_CacheElementPtr, MEM_Allocator<MEM_CacheElementPtr> > MEM_CacheQueue;
+	typedef typename MEM_CacheQueue::iterator iterator;
+
+	struct compare_element_priority : public std::binary_function<MEM_CacheElementPtr, MEM_CacheElementPtr, bool> {
+		bool operator()(const MEM_CacheElementPtr left_elem, const MEM_CacheElementPtr right_elem) const {
+			return left_elem->get_priority() > right_elem->get_priority();
+		}
+	};
+
+	typedef std::priority_queue<MEM_CacheElementPtr, std::vector<MEM_CacheElementPtr>, compare_element_priority > MEM_CachePriorityQueue;
+
 	size_t total_size() {
 		size_t size = 0;
 		for (iterator it = queue.begin(); it != queue.end(); it++) {
@@ -196,9 +245,33 @@
 		return size;
 	}
 
-	std::list<MEM_CacheLimiterHandle<T>*,
-	  MEM_Allocator<MEM_CacheLimiterHandle<T> *> > queue;
+	MEM_CachePriorityQueue get_priority_queue(void) {
+		MEM_CachePriorityQueue priority_queue;
+		iterator it;
+		int i;
+
+		for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) {
+			MEM_CacheElementPtr elem = *it;
+			int priority;
+
+			/* by default 0 means higherst priority element */
+			priority = -(queue.size() - i - 1);
+
+			if (getItemPriority) {
+				priority = getItemPriority(elem->get()->get_data(), priority);
+			}
+
+			elem->set_priority(priority);
+
+			priority_queue.push(elem);
+		}
+
+		return priority_queue;
+	}
+
+	MEM_CacheQueue queue;
 	MEM_CacheLimiter_DataSize_Func getDataSize;
+	MEM_CacheLimiter_ItemPriority_Func getItemPriority;
 };
 
 #endif // __MEM_CACHELIMITER_H__

Modified: trunk/blender/intern/memutil/MEM_CacheLimiterC-Api.h
===================================================================
--- trunk/blender/intern/memutil/MEM_CacheLimiterC-Api.h	2012-07-10 14:42:37 UTC (rev 48807)
+++ trunk/blender/intern/memutil/MEM_CacheLimiterC-Api.h	2012-07-10 14:43:50 UTC (rev 48808)
@@ -31,7 +31,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-	
+
 struct MEM_CacheLimiter_s;
 struct MEM_CacheLimiterHandle_s;
 
@@ -39,107 +39,112 @@
 typedef struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC;
 
 /* function used to remove data from memory */
-typedef void(*MEM_CacheLimiter_Destruct_Func)(void*);
+typedef void (*MEM_CacheLimiter_Destruct_Func)(void*);
 
 /* function used to measure stored data element size */
-typedef size_t(*MEM_CacheLimiter_DataSize_Func) (void*);
+typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void*);
 
+/* function used to measure priority of item when freeing memory */
+typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void*, int);
+
 #ifndef __MEM_CACHELIMITER_H__
-extern void MEM_CacheLimiter_set_maximum(size_t m);
-extern int MEM_CacheLimiter_get_maximum(void);
+void MEM_CacheLimiter_set_maximum(size_t m);
+int MEM_CacheLimiter_get_maximum(void);
 #endif /* __MEM_CACHELIMITER_H__ */
-/** 
- * Create new MEM_CacheLimiter object 
+
+/**
+ * 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(
-	MEM_CacheLimiter_Destruct_Func data_destructor,
-	MEM_CacheLimiter_DataSize_Func data_size);
+MEM_CacheLimiterC *new_MEM_CacheLimiter(MEM_CacheLimiter_Destruct_Func data_destructor,
+                                         MEM_CacheLimiter_DataSize_Func data_size);
 
-/** 
+/**
  * 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);
+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);
 
-/** 
+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);
+void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC *This);
 
-/** 
- * Unmanage object previously inserted object. 
+/**
+ * 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);
 
+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);
 
-/** 
+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);
 
-/** 
+void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC *handle);
+
+/**
  * Decrement reference counter. Objects with reference counter != 0 are _not_
  * deleted.
- * 
+ *

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list