beignet-1.3.2-eventchain-memory-leak.patch 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. Description: Don't leak memory on long chains of events
  2. Delete event->depend_events when no longer needed to avoid keeping
  3. the whole dependency tree in memory as long as the final event exists
  4. Author: Rebecca N. Palmer <rebecca_palmer@zoho.com>
  5. Bug-Ubuntu: https://launchpad.net/bugs/1354086
  6. Forwarded: https://lists.freedesktop.org/archives/beignet/2018-July/009209.html
  7. --- a/src/cl_event.c
  8. +++ b/src/cl_event.c
  9. @@ -184,6 +184,25 @@ cl_event_new(cl_context ctx, cl_command_
  10. return e;
  11. }
  12. +/* 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 */
  13. +LOCAL void
  14. +cl_event_delete_depslist(cl_event event)
  15. +{
  16. + CL_OBJECT_LOCK(event);
  17. + cl_event *old_depend_events = event->depend_events;
  18. + int depend_count = event->depend_event_num;
  19. + event->depend_event_num = 0;
  20. + event->depend_events = NULL;
  21. + CL_OBJECT_UNLOCK(event);
  22. + if (old_depend_events) {
  23. + assert(depend_count);
  24. + for (int i = 0; i < depend_count; i++) {
  25. + cl_event_delete(old_depend_events[i]);
  26. + }
  27. + cl_free(old_depend_events);
  28. + }
  29. +}
  30. +
  31. LOCAL void
  32. cl_event_delete(cl_event event)
  33. {
  34. @@ -200,13 +219,7 @@ cl_event_delete(cl_event event)
  35. assert(list_node_out_of_list(&event->enqueue_node));
  36. - if (event->depend_events) {
  37. - assert(event->depend_event_num);
  38. - for (i = 0; i < event->depend_event_num; i++) {
  39. - cl_event_delete(event->depend_events[i]);
  40. - }
  41. - cl_free(event->depend_events);
  42. - }
  43. + cl_event_delete_depslist(event);
  44. /* Free all the callbacks. Last ref, no need to lock. */
  45. while (!list_empty(&event->callbacks)) {
  46. @@ -566,8 +579,12 @@ cl_event_exec(cl_event event, cl_int exe
  47. assert(depend_status <= CL_COMPLETE || ignore_depends || exec_to_status == CL_QUEUED);
  48. if (depend_status < CL_COMPLETE) { // Error happend, cancel exec.
  49. ret = cl_event_set_status(event, depend_status);
  50. + cl_event_delete_depslist(event);
  51. return depend_status;
  52. }
  53. + if (depend_status == CL_COMPLETE) { // Avoid memory leak
  54. + cl_event_delete_depslist(event);
  55. + }
  56. if (cur_status <= exec_to_status) {
  57. return ret;
  58. --- a/src/cl_event.h
  59. +++ b/src/cl_event.h
  60. @@ -44,7 +44,7 @@ typedef struct _cl_event {
  61. cl_command_type event_type; /* Event type. */
  62. cl_bool is_barrier; /* Is this event a barrier */
  63. cl_int status; /* The execution status */
  64. - cl_event *depend_events; /* The events must complete before this. */
  65. + cl_event *depend_events; /* The events must complete before this. May disappear after they have completed - see cl_event_delete_depslist*/
  66. cl_uint depend_event_num; /* The depend events number. */
  67. list_head callbacks; /* The events The event callback functions */
  68. list_node enqueue_node; /* The node in the enqueue list. */