[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [48526] branches/soc-2011-tomato: Tomato: improved cache management for movie clips

Sergey Sharybin sergey.vfx at gmail.com
Tue Jul 3 12:56:37 CEST 2012


Revision: 48526
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=48526
Author:   nazgul
Date:     2012-07-03 10:56:33 +0000 (Tue, 03 Jul 2012)
Log Message:
-----------
Tomato: improved cache management for movie clips

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.

Modified Paths:
--------------
    branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiter.h
    branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiterC-Api.h
    branches/soc-2011-tomato/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
    branches/soc-2011-tomato/source/blender/blenkernel/intern/movieclip.c
    branches/soc-2011-tomato/source/blender/blenkernel/intern/seqcache.c
    branches/soc-2011-tomato/source/blender/imbuf/IMB_moviecache.h
    branches/soc-2011-tomato/source/blender/imbuf/intern/colormanagement.c
    branches/soc-2011-tomato/source/blender/imbuf/intern/moviecache.c

Modified: branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiter.h
===================================================================
--- branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiter.h	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiter.h	2012-07-03 10:56:33 UTC (rev 48526)
@@ -58,6 +58,8 @@
  */
 
 #include <list>
+#include <queue>
+#include <vector>
 #include "MEM_Allocator.h"
 
 template<class T>
@@ -110,11 +112,18 @@
 	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;
+	int priority;
 	typename std::list<MEM_CacheLimiterHandle<T> *,
 	  MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me;
 	MEM_CacheLimiter<T> * parent;
@@ -123,9 +132,8 @@
 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_) {
 	}
@@ -146,6 +154,7 @@
 		delete handle;
 	}
 	void enforce_limits() {
+		MEM_CachePriorityQueue priority_queue;
 		size_t max = MEM_CacheLimiter_get_maximum();
 		size_t mem_in_use, cur_size;
 
@@ -159,24 +168,29 @@
 			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;
+		}
 
+		priority_queue = get_priority_queue();
+
+		while (!priority_queue.empty() && mem_in_use > max) {
+			MEM_CacheElementPtr elem = priority_queue.top();
+
 			if(getDataSize) {
-				cur_size= getDataSize((*jt)->get()->get_data());
+				cur_size = getDataSize(elem->get()->get_data());
 			} else {
-				cur_size= mem_in_use;
+				cur_size = mem_in_use;
 			}
 
-			(*jt)->destroy_if_possible();
+			elem->destroy_if_possible();
 
-			if(getDataSize) {
-				mem_in_use-= cur_size;
+			priority_queue.pop();
+
+			if (getDataSize) {
+				mem_in_use -= cur_size;
 			} else {
-				mem_in_use-= cur_size - MEM_get_memory_in_use();
+				mem_in_use -= cur_size - MEM_get_memory_in_use();
 			}
 		}
 	}
@@ -187,7 +201,22 @@
 		--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 +225,32 @@
 		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;
+
+			priority = i;
+
+			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: branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiterC-Api.h
===================================================================
--- branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiterC-Api.h	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/intern/memutil/MEM_CacheLimiterC-Api.h	2012-07-03 10:56:33 UTC (rev 48526)
@@ -44,6 +44,9 @@
 /* function used to measure stored data element size */
 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);
@@ -140,6 +143,9 @@
 	
 extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle);
 
+extern void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This,
+                                                   MEM_CacheLimiter_ItemPriority_Func item_priority_func);
+
 #ifdef __cplusplus
 }
 #endif

Modified: branches/soc-2011-tomato/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp
===================================================================
--- branches/soc-2011-tomato/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp	2012-07-03 10:56:33 UTC (rev 48526)
@@ -197,3 +197,9 @@
 {
 	return cast(handle)->get()->get_data();
 }
+
+void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This,
+                                            MEM_CacheLimiter_ItemPriority_Func item_priority_func)
+{
+	cast(This)->get_cache()->set_item_priority_func(item_priority_func);
+}

Modified: branches/soc-2011-tomato/source/blender/blenkernel/intern/movieclip.c
===================================================================
--- branches/soc-2011-tomato/source/blender/blenkernel/intern/movieclip.c	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/source/blender/blenkernel/intern/movieclip.c	2012-07-03 10:56:33 UTC (rev 48526)
@@ -338,6 +338,10 @@
 	short render_flag;
 } MovieClipImBufCacheKey;
 
+typedef struct MovieClipCachePriorityData {
+	int framenr;
+} MovieClipCachePriorityData;
+
 static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
 {
 	MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey;
@@ -378,6 +382,32 @@
 	return 0;
 }
 
+void *moviecache_getprioritydata(void *key_v)
+{
+	MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *) key_v;
+	MovieClipCachePriorityData *priority_data;
+
+	priority_data = MEM_callocN(sizeof(priority_data), "movie cache clip priority data");
+	priority_data->framenr = key->framenr;
+
+	return priority_data;
+}
+
+int moviecache_getitempriority(void *last_userkey_v, void *priority_data_v)
+{
+	MovieClipImBufCacheKey *last_userkey = (MovieClipImBufCacheKey *) last_userkey_v;
+	MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+
+	return -abs(last_userkey->framenr - priority_data->framenr);
+}
+
+void moviecache_prioritydeleter(void *priority_data_v)
+{
+	MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+
+	MEM_freeN(priority_data);
+}
+
 static ImBuf *get_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
 {
 	if (clip->cache) {
@@ -405,10 +435,17 @@
 	MovieClipImBufCacheKey key;
 
 	if (!clip->cache) {
+		struct MovieCache *moviecache;
+
 		clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
 
-		clip->cache->moviecache = IMB_moviecache_create(sizeof(MovieClipImBufCacheKey), NULL, moviecache_hashhash,
-		                                                moviecache_hashcmp, moviecache_keydata, NULL);
+		moviecache = IMB_moviecache_create(sizeof(MovieClipImBufCacheKey), moviecache_hashhash, moviecache_hashcmp);
+
+		IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
+		IMB_moviecache_set_priority_callback(moviecache, moviecache_getprioritydata, moviecache_getitempriority,
+		                                     moviecache_prioritydeleter);
+
+		clip->cache->moviecache = moviecache;
 	}
 
 	key.framenr = user->framenr;

Modified: branches/soc-2011-tomato/source/blender/blenkernel/intern/seqcache.c
===================================================================
--- branches/soc-2011-tomato/source/blender/blenkernel/intern/seqcache.c	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/source/blender/blenkernel/intern/seqcache.c	2012-07-03 10:56:33 UTC (rev 48526)
@@ -98,8 +98,7 @@
 {
 	if (moviecache) {
 		IMB_moviecache_free(moviecache);
-		moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), NULL, seqcache_hashhash,
-		                                   seqcache_hashcmp, NULL, NULL);
+		moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
 	}
 }
 
@@ -133,8 +132,7 @@
 	}
 
 	if (!moviecache) {
-		moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), NULL, seqcache_hashhash,
-		                                   seqcache_hashcmp, NULL, NULL);
+		moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
 	}
 
 	key.seq = seq;

Modified: branches/soc-2011-tomato/source/blender/imbuf/IMB_moviecache.h
===================================================================
--- branches/soc-2011-tomato/source/blender/imbuf/IMB_moviecache.h	2012-07-03 10:48:04 UTC (rev 48525)
+++ branches/soc-2011-tomato/source/blender/imbuf/IMB_moviecache.h	2012-07-03 10:56:33 UTC (rev 48526)
@@ -43,16 +43,24 @@
 struct MovieCache;
 
 typedef void (*MovieCacheGetKeyDataFP) (void *userkey, int *framenr, int *proxy, int *render_flags);
-typedef void (*MoviKeyDeleterFP) (void *userkey);
+typedef void (*MovieCacheKeyDeleterFP) (void *userkey);
 typedef int (*MovieCacheCheckKeyUnusedFP) (void *userkey);
 
+typedef void  *(*MovieCacheGetPriorityDataFP) (void *userkey);
+typedef int    (*MovieCacheGetItemPriorityFP) (void *last_userkey, void *priority_data);
+typedef void   (*MovieCachePriorityDeleterFP) (void *priority_data);
+
 void IMB_moviecache_init(void);
 void IMB_moviecache_destruct(void);
 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list