Hi,
On Thursday, May 22, 2014 03:38:12 Jose Fonseca wrote:
> In short, besides the existing gallivm_context (which is actually not per
> context, but rather per module/ compilation unit) there should be a new
> object, that's truly per context, that holds two things:
>
> - LLVMContextRef
> - src/gallium/auxiliary/gallivm/lp_bld_misc.cpp's ShaderMemoryManager.
I have played around with the mentioned pool of LLVMContexts around.
The patch doing that is attached.
Sadly the introduction of the ShaderMemoryManager breaks again
multithreading in a fatal way.
So, the attached patch seems to fix the races and should in theory help
for your observed leakage.
But only if applied to a state before the introduction of
ShaderMemoryManager...
Greetings
Mathias
>From 73b5447df1c329d7fb5d16193655822aa69a840c Mon Sep 17 00:00:00 2001
Message-Id: <73b5447df1c329d7fb5d16193655822aa69a840c.1401131738.git.mathias.froehl...@gmx.net>
From: =?UTF-8?q?Mathias=20Fr=C3=B6hlich?= <mathias.froehl...@gmx.net>
Date: Mon, 26 May 2014 19:48:41 +0200
Subject: [PATCH] Pool the LLVMContexts in use.
---
src/gallium/auxiliary/gallivm/lp_bld_init.c | 80 +++++++++++++++++++++++++----
1 file changed, 70 insertions(+), 10 deletions(-)
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_init.c b/src/gallium/auxiliary/gallivm/lp_bld_init.c
index 8b8686d..3a9d10f 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_init.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_init.c
@@ -32,6 +32,7 @@
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "util/u_simple_list.h"
+#include "os/os_thread.h"
#include "os/os_time.h"
#include "lp_bld.h"
#include "lp_bld_debug.h"
@@ -74,11 +75,73 @@ void LLVMLinkInMCJIT();
* owned by the context, so if we freeing contexts causes
* memory leaks and false cache hits when these objects are destroyed.
*
- * TODO: For thread safety on multi-threaded OpenGL we should use one LLVM
- * context per thread, and put them in a pool when threads are destroyed.
+ * Namely, lib/CodeGen/SelectionDAG/SelectionDAG.cpp holds a static
+ * cache of llvm::EVT instances that belong to a LLVMContext. The cached
+ * llvm::EVT instances are keyed there by their LLVMContext pointer address
+ * as well as by their internal type enumeration value.
+ * By that we introduce massive leaks filling up this static cache
+ * if we use newly created LLVMContext instances that are destroyed
+ * after use.
*/
-#define USE_GLOBAL_CONTEXT 1
+struct llvm_context_pool_node {
+ struct llvm_context_pool_node *prev, *next;
+ LLVMContextRef context;
+};
+
+/* Protect the two lists below */
+pipe_static_mutex(llvm_pool_mutex);
+/* Contains all the LLVMContexts currently not in use. */
+static struct llvm_context_pool_node llvm_context_pool = {
+ &llvm_context_pool, &llvm_context_pool, NULL
+};
+/*
+ * Contains all the llvm_context_pool_node's currently not in use
+ * in llvm_context_pool pool.
+ */
+static struct llvm_context_pool_node llvm_empty_node_pool = {
+ &llvm_empty_node_pool, &llvm_empty_node_pool, NULL
+};
+
+static LLVMContextRef get_llvm_context()
+{
+ LLVMContextRef context = NULL;
+
+ pipe_mutex_lock(llvm_pool_mutex);
+
+ if (!is_empty_list(&llvm_context_pool)) {
+ struct llvm_context_pool_node *element;
+ element = first_elem(&llvm_context_pool);
+ remove_from_list(element);
+ context = element->context;
+ element->context = NULL;
+ insert_at_head(&llvm_empty_node_pool, element);
+ }
+
+ pipe_mutex_unlock(llvm_pool_mutex);
+
+ if (!context)
+ context = LLVMContextCreate();
+
+ return context;
+}
+
+static void put_llvm_context(LLVMContextRef context)
+{
+ pipe_mutex_lock(llvm_pool_mutex);
+
+ struct llvm_context_pool_node *element;
+ if (is_empty_list(&llvm_empty_node_pool)) {
+ element = CALLOC_STRUCT(llvm_context_pool_node);
+ } else {
+ element = first_elem(&llvm_empty_node_pool);
+ remove_from_list(element);
+ }
+ element->context = context;
+ insert_at_head(&llvm_context_pool, element);
+
+ pipe_mutex_unlock(llvm_pool_mutex);
+}
#ifdef DEBUG
unsigned gallivm_debug = 0;
@@ -193,8 +256,8 @@ gallivm_free_ir(struct gallivm_state *gallivm)
if (gallivm->builder)
LLVMDisposeBuilder(gallivm->builder);
- if (!USE_GLOBAL_CONTEXT && gallivm->context)
- LLVMContextDispose(gallivm->context);
+ if (gallivm->context)
+ put_llvm_context(gallivm->context);
gallivm->engine = NULL;
gallivm->target = NULL;
@@ -202,6 +265,7 @@ gallivm_free_ir(struct gallivm_state *gallivm)
gallivm->passmgr = NULL;
gallivm->context = NULL;
gallivm->builder = NULL;
+ gallivm->context = NULL;
}
@@ -292,11 +356,7 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name)
lp_build_init();
- if (USE_GLOBAL_CONTEXT) {
- gallivm->context = LLVMGetGlobalContext();
- } else {
- gallivm->context = LLVMContextCreate();
- }
+ gallivm->context = get_llvm_context();
if (!gallivm->context)
goto fail;
--
1.9.3
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev