[Bf-blender-cvs] [6b97c36] object_nodes: Generalization of function caching to avoid unnecessary recompilation.

Lukas Tönne noreply at git.blender.org
Mon Dec 14 08:41:14 CET 2015


Commit: 6b97c36df3d9a61c7c265e11cb8f2d16e6d248d9
Author: Lukas Tönne
Date:   Mon Dec 14 07:52:38 2015 +0100
Branches: object_nodes
https://developer.blender.org/rB6b97c36df3d9a61c7c265e11cb8f2d16e6d248d9

Generalization of function caching to avoid unnecessary recompilation.

The function cache allows callers to store functions in a cache (hash table).
The functions also have a reference count, so replacing the function
in the cache (when the node tree changes) does not immediately delete
the current instance. This allows background threads to keep using the
old function until they can cleanly return (tasks should be restarted
when the nodes become outdated, but this is up to the caller system).

===================================================================

M	source/blender/blenkernel/intern/depsgraph.c
M	source/blender/blenkernel/intern/texture.c
M	source/blender/blenvm/BVM_api.h
M	source/blender/blenvm/bvm/bvm_function.cc
M	source/blender/blenvm/bvm/bvm_function.h
M	source/blender/blenvm/intern/bvm_api.cc
M	source/blender/blenvm/util/bvm_util_thread.h
M	source/blender/render/intern/source/render_texture.c

===================================================================

diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 2d6b054..54652e7 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -2649,7 +2649,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
 
 		if (ELEM(idtype, ID_TE)) {
 			Tex *tex = (Tex *)id;
-			BVM_texture_cache_invalidate(tex);
+			BVM_function_cache_remove(BVM_texture_key(tex));
 		}
 
 		if (idtype == ID_MC) {
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index a35dbf0..5d4dc94 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -1689,6 +1689,6 @@ void BKE_texture_get_value(
 
 void BKE_texture_invalidate(EvaluationContext *UNUSED(eval_ctx), Tex *tex)
 {
-	BVM_texture_cache_invalidate(tex);
+	BVM_function_cache_remove(BVM_texture_key(tex));
 }
 
diff --git a/source/blender/blenvm/BVM_api.h b/source/blender/blenvm/BVM_api.h
index 1910286..0b24a01 100644
--- a/source/blender/blenvm/BVM_api.h
+++ b/source/blender/blenvm/BVM_api.h
@@ -48,8 +48,16 @@ void BVM_free(void);
 
 /* ------------------------------------------------------------------------- */
 
+typedef unsigned int BVMFunctionKey;
+
 void BVM_function_free(struct BVMFunction *fn);
 
+struct BVMFunction *BVM_function_cache_acquire(BVMFunctionKey key);
+void BVM_function_release(struct BVMFunction *_fn);
+void BVM_function_cache_set(BVMFunctionKey key, struct BVMFunction *_fn);
+void BVM_function_cache_remove(BVMFunctionKey key);
+void BVM_function_cache_clear(void);
+
 /* ------------------------------------------------------------------------- */
 
 struct BVMNodeGraph;
@@ -130,10 +138,7 @@ void BVM_eval_texture(struct BVMEvalContext *context, struct BVMFunction *fn,
                       float coord[3], float dxt[3], float dyt[3], int osatex,
                       short which_output, int cfra, int preview);
 
-struct BVMFunction *BVM_texture_cache_acquire(struct Tex *tex);
-void BVM_texture_cache_release(struct Tex *tex);
-void BVM_texture_cache_invalidate(struct Tex *tex);
-void BVM_texture_cache_clear(void);
+BVMFunctionKey BVM_texture_key(struct Tex *tex);
 
 /* ------------------------------------------------------------------------- */
 
@@ -148,8 +153,6 @@ struct DerivedMesh *BVM_eval_modifier(struct BVMEvalGlobals *globals,
                                       struct Object *ob,
                                       struct Mesh *base_mesh);
 
-/* ------------------------------------------------------------------------- */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenvm/bvm/bvm_function.cc b/source/blender/blenvm/bvm/bvm_function.cc
index 4f99a9d..a2180ef 100644
--- a/source/blender/blenvm/bvm/bvm_function.cc
+++ b/source/blender/blenvm/bvm/bvm_function.cc
@@ -33,8 +33,12 @@
 
 namespace bvm {
 
+mutex Function::users_mutex = mutex();
+spin_lock Function::users_lock = spin_lock(Function::users_mutex);
+
 Function::Function() :
-    m_entry_point(0)
+    m_entry_point(0),
+    m_users(0)
 {
 }
 
@@ -42,6 +46,29 @@ Function::~Function()
 {
 }
 
+void Function::retain(Function *fn)
+{
+	if (fn) {
+		users_lock.lock();
+		++fn->m_users;
+		users_lock.unlock();
+	}
+}
+
+void Function::release(Function **fn)
+{
+	if (*fn) {
+		users_lock.lock();
+		assert((*fn)->m_users > 0);
+		--(*fn)->m_users;
+		if ((*fn)->m_users == 0) {
+			delete *fn;
+			*fn = NULL;
+		}
+		users_lock.unlock();
+	}
+}
+
 void Function::add_instruction(Instruction v)
 {
 	m_instructions.push_back(v);
diff --git a/source/blender/blenvm/bvm/bvm_function.h b/source/blender/blenvm/bvm/bvm_function.h
index a961d65..84f7e9c 100644
--- a/source/blender/blenvm/bvm/bvm_function.h
+++ b/source/blender/blenvm/bvm/bvm_function.h
@@ -39,6 +39,7 @@
 
 #include "bvm_opcode.h"
 #include "bvm_util_string.h"
+#include "bvm_util_thread.h"
 #include "bvm_util_typedesc.h"
 
 namespace bvm {
@@ -96,6 +97,9 @@ struct Function {
 	Function();
 	~Function();
 	
+	static void retain(Function *fn);
+	static void release(Function **fn);
+	
 	OpCode read_opcode(int *instr) const
 	{
 		OpCode op = (OpCode)m_instructions[*instr];
@@ -209,7 +213,12 @@ private:
 	ArgumentList m_return_values;
 	InstructionList m_instructions;
 	int m_entry_point;
-
+	
+	int m_users;
+	
+	static mutex users_mutex;
+	static spin_lock users_lock;
+	
 	MEM_CXX_CLASS_ALLOC_FUNCS("BVM:Function")
 };
 
diff --git a/source/blender/blenvm/intern/bvm_api.cc b/source/blender/blenvm/intern/bvm_api.cc
index c46ead9..129ce68 100644
--- a/source/blender/blenvm/intern/bvm_api.cc
+++ b/source/blender/blenvm/intern/bvm_api.cc
@@ -35,6 +35,7 @@
 
 extern "C" {
 #include "BLI_utildefines.h"
+#include "BLI_ghash.h"
 #include "BLI_listbase.h"
 
 #include "DNA_node_types.h"
@@ -76,7 +77,7 @@ void BVM_free(void)
 {
 	using namespace bvm;
 	
-	BVM_texture_cache_clear();
+	BVM_function_cache_clear();
 	
 	nodes_free();
 	
@@ -91,6 +92,111 @@ BLI_INLINE bvm::Function *_FUNC(struct BVMFunction *fn)
 void BVM_function_free(struct BVMFunction *fn)
 { delete _FUNC(fn); }
 
+namespace bvm {
+
+typedef unordered_map<BVMFunctionKey, Function*> FunctionCache;
+typedef std::pair<BVMFunctionKey, Function*> FunctionCachePair;
+
+static FunctionCache bvm_function_cache;
+static mutex bvm_function_cache_mutex;
+static spin_lock bvm_function_cache_lock = spin_lock(bvm_function_cache_mutex);
+
+} /* namespace bvm */
+
+struct BVMFunction *BVM_function_cache_acquire(BVMFunctionKey key)
+{
+	using namespace bvm;
+	
+	bvm_function_cache_lock.lock();
+	FunctionCache::const_iterator it = bvm_function_cache.find(key);
+	Function *fn = NULL;
+	if (it != bvm_function_cache.end()) {
+		fn = it->second;
+		Function::retain(fn);
+	}
+	bvm_function_cache_lock.unlock();
+	return (BVMFunction *)fn;
+}
+
+void BVM_function_release(BVMFunction *_fn)
+{
+	using namespace bvm;
+	Function *fn = _FUNC(_fn);
+	
+	if (!fn)
+		return;
+	
+	Function::release(&fn);
+	
+	if (fn == NULL) {
+		bvm_function_cache_lock.lock();
+		FunctionCache::iterator it = bvm_function_cache.begin();
+		while (it != bvm_function_cache.end()) {
+			if (it->second == fn) {
+				FunctionCache::iterator it_del = it++;
+				bvm_function_cache.erase(it_del);
+			}
+			else
+				++it;
+		}
+		bvm_function_cache_lock.unlock();
+	}
+}
+
+void BVM_function_cache_set(BVMFunctionKey key, BVMFunction *_fn)
+{
+	using namespace bvm;
+	Function *fn = _FUNC(_fn);
+	
+	bvm_function_cache_lock.lock();
+	if (fn) {
+		FunctionCache::iterator it = bvm_function_cache.find(key);
+		if (it == bvm_function_cache.end()) {
+			Function::retain(fn);
+			bvm_function_cache.insert(FunctionCachePair(key, fn));
+		}
+		else if (fn != it->second) {
+			Function::release(&it->second);
+			Function::retain(fn);
+			it->second = fn;
+		}
+	}
+	else {
+		FunctionCache::iterator it = bvm_function_cache.find(key);
+		if (it != bvm_function_cache.end()) {
+			Function::release(&it->second);
+			bvm_function_cache.erase(it);
+		}
+	}
+	bvm_function_cache_lock.unlock();
+}
+
+void BVM_function_cache_remove(BVMFunctionKey key)
+{
+	using namespace bvm;
+	
+	bvm_function_cache_lock.lock();
+	FunctionCache::iterator it = bvm_function_cache.find(key);
+	if (it != bvm_function_cache.end()) {
+		Function::release(&it->second);
+		
+		bvm_function_cache.erase(it);
+	}
+	bvm_function_cache_lock.unlock();
+}
+
+void BVM_function_cache_clear(void)
+{
+	using namespace bvm;
+	
+	bvm_function_cache_lock.lock();
+	for (FunctionCache::iterator it = bvm_function_cache.begin(); it != bvm_function_cache.end(); ++it) {
+		Function::release(&it->second);
+	}
+	bvm_function_cache.clear();
+	bvm_function_cache_lock.unlock();
+}
+
 /* ------------------------------------------------------------------------- */
 
 BLI_INLINE bvm::NodeGraph *_GRAPH(struct BVMNodeGraph *graph)
@@ -308,6 +414,7 @@ struct BVMFunction *BVM_gen_forcefield_function(bNodeTree *btree, FILE *debug_fi
 	
 	BVMCompiler compiler;
 	Function *fn = compiler.compile_function(graph);
+	Function::retain(fn);
 	
 	return (BVMFunction *)fn;
 }
@@ -823,6 +930,7 @@ struct BVMFunction *BVM_gen_texture_function(struct Tex */*tex*/, bNodeTree *btr
 	
 	BVMCompiler compiler;
 	Function *fn = compiler.compile_function(graph);
+	Function::retain(fn);
 	
 	return (BVMFunction *)fn;
 }
@@ -858,63 +966,9 @@ void BVM_eval_texture(struct BVMEvalContext *ctx, struct BVMFunction *fn,
 	}
 }
 
-/* TODO using shared_ptr or similar here could help relax
- * order of acquire/release/invalidate calls (keep alive as long as used)
- */
-typedef unordered_map<Tex*, bvm::Function*> FunctionCache;
-
-static FunctionCache bvm_tex_cache;
-static bvm::mutex bvm_tex_mutex;
-
-struct BVMFunction *BVM_texture_cache_acquire(Tex *tex)
-{
-	using namespace bvm;
-	
-	scoped_lock lock(bvm_tex_mutex);
-	
-	FunctionCache::const_iterator it = bvm_tex_cache.find(tex);
-	if (it != bvm_tex_cache.end()) {
-		return (BVMFunction *)it->second;
-	}
-	else if (tex->use_nodes && tex->nodetree) {
-		BVMFunction *fn = BVM_gen_texture_function(tex, tex->nodetree, NULL);
-		
-		bvm_tex_cache[tex] = _FUNC(fn);
-		
-		return fn;
-	}
-	else
-		return NULL;
-}
-
-void BVM_texture_cache_release(Tex *tex)
+BVMFunctionKey BVM_texture_key(struct Tex *tex)
 {
-	(void)tex;
-}
-
-void BVM_texture_cache_invalidate(Tex *tex)
-{
-	using namespace bvm;
-	
-	scoped_lock lock(bvm_tex_mutex);
-	
-	FunctionCache::iterator it = bvm_tex_cache.find(tex);
-	if (it != bvm_tex_cache.end()) {
-		delete it->second;
-		bvm_tex_cache.erase(it);
-	}
-}
-
-void BVM_texture_cache_clear(void)
-{
-	using namespace bvm;
-	
-	scoped_lock lock(bvm_tex_mutex);
-	
-	for (FunctionCache::iterator it = bvm_tex_cache.begin(); it != bvm_tex_cache.end(); ++it) {
-		delete it->second;
-	}
-	bvm_tex_cache.clear();
+	return BLI_ghashutil_ptrhash(tex);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -940,6 +994,7 @@ struct BVMFunction *BVM_gen_modifier_function(struct Object */*ob*/, struct bNod
 	
 	BVMCompiler compiler;
 	Function *fn = compiler.compile_function(graph);
+	Function::retain(fn);
 	
 	return (BVMFunction *)fn;
 }
diff --git a/source/blender/blenvm/util/bvm_util_thr

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list