Bug 102844

Summary: memory leak with glDeleteProgram for shader program type GL_COMPUTE_SHADER
Product: Mesa Reporter: adam <adambarta>
Component: Drivers/DRI/i965Assignee: Intel 3D Bugs Mailing List <intel-3d-bugs>
Status: RESOLVED FIXED QA Contact: Intel 3D Bugs Mailing List <intel-3d-bugs>
Severity: critical    
Priority: medium    
Version: unspecified   
Hardware: x86-64 (AMD64)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments: fix

Description adam 2017-09-18 17:44:04 UTC
Attached example program shows a memory leak from brwNewProgram for shader type GL_COMPUTE_SHADER

ltraces shows glDeleteProgram is called however doesn't call brwDeleteProgram for the compute_shader program.


//gcc compute_shader_test.c -lGL -lX11 -o compute_shader_test

#include <stdio.h>
#include <stdlib.h>

#define GL_GLEXT_PROTOTYPES
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glext.h>

typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);

int main (int argc, char ** argv)
{
  Display *display = XOpenDisplay(0);

  glXCreateContextAttribsARBProc glXCreateContextAttribsARB = NULL;

  const char *extensions = glXQueryExtensionsString(display, DefaultScreen(display));

  static int visual_attribs[] =
  {
    GLX_RENDER_TYPE, GLX_RGBA_BIT,
    GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
    GLX_DOUBLEBUFFER, 1,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    None
  };

  int fbcount;
  GLXFBConfig *fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount);
  if (!fbc)
    return 1;
  
  XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbc[0]);

  XSetWindowAttributes swa;
  swa.colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
  swa.border_pixel = 0;
  swa.event_mask = StructureNotifyMask;

  Window win = XCreateWindow(display, RootWindow(display, vi->screen), 0, 0, 100, 100, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
  if (!win)
    return 1;

  GLXContext ctx_old = glXCreateContext(display, vi, 0, GL_TRUE);
  glXCreateContextAttribsARB =  (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
  glXMakeCurrent(display, 0, 0);
  glXDestroyContext(display, ctx_old);

  if (glXCreateContextAttribsARB == NULL)
    return 1;

  static int context_attribs[] = {
    GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
    GLX_CONTEXT_MINOR_VERSION_ARB, 5,
    None
  };

  GLXContext ctx = glXCreateContextAttribsARB(display, fbc[0], NULL, GL_TRUE, context_attribs);
  if (!ctx)
    return 1;

  glXMakeCurrent(display, win, ctx);
  
  GLuint csp = glCreateProgram();
  GLuint cs = glCreateShader(GL_COMPUTE_SHADER);

        const char *src[] = {
                "#version 450\n",
                "writeonly uniform image2D destTex;\
                 layout (local_size_x = 16, local_size_y = 16) in;\
                 void main() {\
                         ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\
                         imageStore(destTex, storePos, vec4(0.0, 0.0, 0.0, 0.0));\
                 }"
        };

  glShaderSource(cs, 2, src, NULL);
  glCompileShader(cs);
  
  int rvalue;
  glGetShaderiv(cs, GL_COMPILE_STATUS, &rvalue);
  if (!rvalue) {
    fprintf(stderr, "Error in compiling the compute shader\n");
    GLchar log[10240];
    GLsizei length;
    glGetShaderInfoLog(cs, 10239, &length, log);
    fprintf(stderr, "Compiler log:\n%s\n", log);
    exit(40);
  }

  glAttachShader(csp, cs);
  
  
  glDeleteShader(cs);


  glLinkProgram(csp);
  glGetProgramiv(csp, GL_LINK_STATUS, &rvalue);
  if (!rvalue) {
    fprintf(stderr, "Error in linking compute shader program\n");
    GLchar log[10240];
    GLsizei length;
    glGetProgramInfoLog(csp, 10239, &length, log);
    fprintf(stderr, "Linker log:\n%s\n", log);
    exit(41);
  }   

  glUseProgram(csp);
  glUniform1i(glGetUniformLocation(csp, "destTex"), 0);

  glDispatchCompute(512/16, 512/16, 1);

  
  glDeleteProgram(csp);


  glXMakeCurrent(display, 0, 0);
  glXDestroyContext(display, ctx);

  XFree(fbc);
  XFreeColormap(display, swa.colormap);
  XFree(vi);
  XCloseDisplay(display);

  return 0;
}


ltrace ./compute_shader_test 
XOpenDisplay(nil)                                                = 0x55d1fb3c7010
glXQueryExtensionsString(0x55d1fb3c7010, 0, 0, 0)                = 0x55d1fb3df650
glXChooseFBConfig(0x55d1fb3c7010, 0, 0x55d1fa992140, 0x7ffd7f0cb754) = 0x55d1fb3df940
glXGetVisualFromFBConfig(0x55d1fb3c7010, 0x55d1fb513d30, 0x55d1fb513d30, 0x55d1fb3dfa28) = 0x55d1fb3dfb50
XCreateColormap(0x55d1fb3c7010, 246, 0x55d1fb3c8be8, 0)          = 0x1e00001
XCreateWindow(0x55d1fb3c7010, 246, 0, 0)                         = 0x1e00002
glXCreateContext(0x55d1fb3c7010, 0x55d1fb3dfb50, 0, 1)           = 0x55d1fb3dfde0
glXGetProcAddress(0x55d1fa791738, 0, 0x8014, 0)                  = 0x7f403adc19b0
glXMakeCurrent(0x55d1fb3c7010, 0, 0, 0xfffd)                     = 1
glXDestroyContext(0x55d1fb3c7010, 0x55d1fb3dfde0, 0x55d1fb3dfde0, 0x7f4037eaf760) = 0
glXMakeCurrent(0x55d1fb3c7010, 0x1e00002, 0x55d1fb3dfde0, 0x1e00002) = 1
glCreateProgram(0, 0, 0x7f403b014a60, 3075)                      = 1
glCreateShader(0x91b9, 0, 0x55d1fb3e15e0, 1)                     = 2
glShaderSource(2, 2, 0x7ffd7f0cb6d0, 0)                          = 0
glCompileShader(2, 0, 0xffffffff, 0)                             = 1
glGetShaderiv(2, 0x8b81, 0x7ffd7f0cb6cc, 0x55d1fb53e7b0)         = 1
glAttachShader(1, 2, 2, 1)                                       = 0x55d1fb53dfe0
glDeleteShader(2, 0x55d1fb53dfe0, 0x55d1fb53df20, 0x7f403aa62b00) = 2
glLinkProgram(1, 0x7ffd7f0c8e98, 0, 1)                           = 0x55d1fb53dac0
glGetProgramiv(1, 0x8b82, 0x7ffd7f0cb6cc, 1)                     = 1
glUseProgram(1, 1, 3, 1)                                         = 0x55d1fb53d980
glGetUniformLocation(1, 0x55d1fa7918c1, 0x55d1fb53d980, 1)       = 0
glUniform1i(0, 0, 0, 0x7f4037413340)                             = 0x8000000000
glDispatchCompute(32, 32, 1, 0x7ffd7f0c8ea0)                     = -1
glGetError(0x55d1fb544850, 0xe000, 135, 0x7f403b22321c)          = 0
glDeleteProgram(1, 0xe000, 135, 0x7f403b22321c)                  = 3
glXMakeCurrent(0x55d1fb3c7010, 0, 0, 1)                          = 1
glXDestroyContext(0x55d1fb3c7010, 0x55d1fb3dfde0, 0x55d1fb3dfde0, 0) = 0
XFree(0x55d1fb3df940, 0, 0x7f403b014a60, 0)                      = 1
XFreeColormap(0x55d1fb3c7010, 0x1e00001, 0x1e00001, 0)           = 1
XFree(0x55d1fb3dfb50, 0, 0xffffffff, 0x55d1fb50e5a0)             = 1
XCloseDisplay(0x55d1fb3c7010)                                    = <void>
+++ exited (status 0) +++


==2414== Command: ./cst
==2414== 
==2414== 
==2414== HEAP SUMMARY:
==2414==     in use at exit: 106,885 bytes in 206 blocks
==2414==   total heap usage: 86,334 allocs, 86,128 frees, 35,353,433 bytes allocated
==2414== 
==2414== 17,813 (1,560 direct, 16,253 indirect) bytes in 1 blocks are definitely lost in loss record 79 of 80
==2414==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==2414==    by 0x90F888C: ralloc_size (ralloc.c:121)
==2414==    by 0x90F897D: rzalloc_size (ralloc.c:153)
==2414==    by 0x920D774: brwNewProgram (brw_program.c:141)
==2414==    by 0x910C913: link_intrastage_shaders(void*, gl_context*, gl_shader_program*, gl_shader**, unsigned int, bool) (linker.cpp:2266)
==2414==    by 0x910E599: link_shaders(gl_context*, gl_shader_program*) (linker.cpp:4844)
==2414==    by 0x904167A: _mesa_glsl_link_shader (ir_to_mesa.cpp:3108)
==2414==    by 0x8F45C78: link_program (shaderapi.c:1171)
==2414==    by 0x8F45C78: link_program_error (shaderapi.c:1249)
==2414==    by 0x10951D: main ()
==2414== 
==2414== LEAK SUMMARY:
==2414==    definitely lost: 1,560 bytes in 1 blocks
==2414==    indirectly lost: 16,253 bytes in 94 blocks
==2414==      possibly lost: 0 bytes in 0 blocks
==2414==    still reachable: 89,072 bytes in 111 blocks
==2414==         suppressed: 0 bytes in 0 blocks
==2414== Reachable blocks (those to which a pointer was found) are not shown.
==2414== To see them, rerun with: --leak-check=full --show-leak-kinds=all
Comment 1 Tapani Pälli 2017-09-19 05:54:26 UTC
Leak happens because of reference count increment during _mesa_update_state in glDispatchCompute (if glDispatchCompute is commented out, there is no leak). Will try to understand why this is never decremented.
Comment 2 adam 2017-09-19 17:23:02 UTC
Thanks for the heads up. Stepping through the code it seems _mesa_update_state_locked updates the fixed function vertex and fragment shaders for the compute shader program is this necessary?
Comment 3 Tapani Pälli 2017-09-20 04:58:34 UTC
(In reply to adam from comment #2)
> Thanks for the heads up. Stepping through the code it seems
> _mesa_update_state_locked updates the fixed function vertex and fragment
> shaders for the compute shader program is this necessary?

Only the active/existing programs get updated, in your case ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE] should be the only one.
Comment 4 Tapani Pälli 2017-09-20 06:26:56 UTC
will send a fix soon ..
Comment 6 adam 2017-09-20 07:24:46 UTC
Nice, a one liner, thanks for the fix!
Comment 7 Tapani Pälli 2017-09-21 05:13:53 UTC
commit 589457d97fa8e95f227e7179e9c89a01dff495a0
Author: Tapani Pälli <tapani.palli@intel.com>
Date:   Wed Sep 20 09:29:16 2017 +0300

    mesa: free current ComputeProgram state in _mesa_free_context_data
    
    This is already done for other programs stages, fixes a leak when using
    compute programs.
    
    Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
    Cc: mesa-stable@lists.freedesktop.org
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=102844
    Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
    Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.