summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebecca N. Palmer <rebecca_palmer@zoho.com>2018-07-21 19:19:38 +0100
committerYang Rong <rong.r.yang@intel.com>2018-08-20 15:31:30 +0800
commit815eb963a1ad430c64694ffedbb208abe5ad2365 (patch)
treeedaa2a37b2b2b2d766a8405b9653fc5bd95dd516
parent7e181af2ea4d37f67406f2563c0e13fa1fdbb14b (diff)
downloadbeignet-815eb963a1ad430c64694ffedbb208abe5ad2365.tar.gz
Don't leak memory on long chains of events
Delete event->depend_events when it is no longer needed, to allow the event objects it refers to to be freed. This avoids out-of-memory hangs in large dependency trees (e.g. long iterative calculations): https://launchpad.net/bugs/1354086 Signed-off-by: Rebecca N. Palmer <rebecca_palmer@zoho.com> Reviewed-by: Yang Rong <rong.r.yang@intel.com>
-rw-r--r--src/cl_event.c31
-rw-r--r--src/cl_event.h2
2 files changed, 25 insertions, 8 deletions
diff --git a/src/cl_event.c b/src/cl_event.c
index a2b16be4..3ecfc3f1 100644
--- a/src/cl_event.c
+++ b/src/cl_event.c
@@ -183,6 +183,25 @@ cl_event_new(cl_context ctx, cl_command_queue queue, cl_command_type type,
return e;
}
+/* This exists to prevent long chains of events from filling up memory (https://bugs.launchpad.net/ubuntu/+source/beignet/+bug/1354086). Call only after the dependencies are complete, or failed and marked as such in this event's status, or when this event is being destroyed */
+LOCAL void
+cl_event_delete_depslist(cl_event event)
+{
+ CL_OBJECT_LOCK(event);
+ cl_event *old_depend_events = event->depend_events;
+ int depend_count = event->depend_event_num;
+ event->depend_event_num = 0;
+ event->depend_events = NULL;
+ CL_OBJECT_UNLOCK(event);
+ if (old_depend_events) {
+ assert(depend_count);
+ for (int i = 0; i < depend_count; i++) {
+ cl_event_delete(old_depend_events[i]);
+ }
+ cl_free(old_depend_events);
+ }
+}
+
LOCAL void
cl_event_delete(cl_event event)
{
@@ -199,13 +218,7 @@ cl_event_delete(cl_event event)
assert(list_node_out_of_list(&event->enqueue_node));
- if (event->depend_events) {
- assert(event->depend_event_num);
- for (i = 0; i < event->depend_event_num; i++) {
- cl_event_delete(event->depend_events[i]);
- }
- cl_free(event->depend_events);
- }
+ cl_event_delete_depslist(event);
/* Free all the callbacks. Last ref, no need to lock. */
while (!list_empty(&event->callbacks)) {
@@ -565,8 +578,12 @@ cl_event_exec(cl_event event, cl_int exec_to_status, cl_bool ignore_depends)
assert(depend_status <= CL_COMPLETE || ignore_depends || exec_to_status == CL_QUEUED);
if (depend_status < CL_COMPLETE) { // Error happend, cancel exec.
ret = cl_event_set_status(event, depend_status);
+ cl_event_delete_depslist(event);
return depend_status;
}
+ if (depend_status == CL_COMPLETE) { // Avoid memory leak
+ cl_event_delete_depslist(event);
+ }
if (cur_status <= exec_to_status) {
return ret;
diff --git a/src/cl_event.h b/src/cl_event.h
index f28844af..e1dc856b 100644
--- a/src/cl_event.h
+++ b/src/cl_event.h
@@ -44,7 +44,7 @@ typedef struct _cl_event {
cl_command_type event_type; /* Event type. */
cl_bool is_barrier; /* Is this event a barrier */
cl_int status; /* The execution status */
- cl_event *depend_events; /* The events must complete before this. */
+ cl_event *depend_events; /* The events must complete before this. May disappear after they have completed - see cl_event_delete_depslist*/
cl_uint depend_event_num; /* The depend events number. */
list_head callbacks; /* The events The event callback functions */
list_node enqueue_node; /* The node in the enqueue list. */