Debugging one complex application manually without any help of debugger is realy tiresome job. On the other hand debuggers make it a simple and enjoyable experiences. The GNU Project Debugger( gdb ) is one of the best debugger available for developers. Programmers like it because of its simplicity and easy-to-use features.
gdb helps us in following things.
- breakpoints : gdb allow you to pause at any point of execution and see the state of any variable currently in the scope.
- next : using next command we can do line by line execution. Also can do dry-run of our application. Which makes debugging a very easy job. The complete flow of execution come alive while we do dry-run. It is very reliable way to identify logical errors of an application.
- display : using display command developers can constantly monitor, state of one variable and can find the bug.
- backtrace : if any code gives core dump, with help of backtrace features , developer can exactly pinpoint , from which location of code , problem started.
There are many other useful features provided by gdb. One can certainly explore by referring to official gdb documentation here http://www.gnu.org/software/gdb/documentation/
OpenCL(Open Computing Language) is open standard for General Purpose Parallel Programming Across GPU, CPU , DSP and Cell/BE Processor. OpenCL Program mainly having two part. The main program part, which is also called host code, is simple C or CPP Code with some API provided by OpenCL Library. The second part of the program is called OpenCL Kernel Code, which needs to be written in a different file. OpenCL Kernel code is having different syntax, though it is quite similar to C syntax.
While compiling any normal C or CPP Program , we can pass many flag to compiler which give instruction to compiler to do certain task ,like generating binary executable with optimized instruction set. Similarly one very important compiler flag is “-g”. This flag tells compiler like gcc or icc, to generate binary executable of an application with debugging information.
Ex. gcc -g HelloWorld.c
But developer face difficulties while compiling OpenCL Program . After compilation of OpenCL host code, binary executable will be generated for host code only because OpenCL kernel code gets loaded, linked, compiled and get executed on the fly at runtime. So the compiler does not create any separate binary file for Kernel code. After execution of host code binary , there will be no executable of the kernel code as well, available on system.
While using GDB, to debug OpenCL Program main problem comes with the OpenCL kernel code section. Because no executable is generated for OpenCL kernel source, so we can not pass kernel executable’s directory path to gdb. That is why, we need to take different approach to debug OpenCL Program using gdb.
In the following section I will describe how to debug OpenCL Kernel and OpenCL host code using GDB.
Following picture shows generic structure of OpenCL host code.
If host program file name is HelloWorldOpenCL.c , then at the time of compilation , we can pass “-g” compiler flag to gcc compiler.
gcc -g -o run HelloWorldOpenCL.c
This will create one binary with debugging information. But how to pass -g flag while compiling OpenCL kernel code? If we look at above picture, we can notice that, at step 1.8. we are firing one API “ClBuildProgram()”. This is the API we use to build OpenCL Kernel code. The fourth parameter of this API allows us to pass compiler flag or options to OpenCL compiler on runtime.
So to enable gdb to debug your OpenCL program , This code section should be written something like bellow code snippet….
91 char *options = new char;
92 strcpy( options, “-g”);
93 status = clBuildProgram( *hProgram,1, *devices, options,NULL,NULL);
Compile your host code with -g flag. Now we can start debugging our program with following command
gdb will start and will wait for further user command. Find out the line number of the statement “status = clBuildProgram( *hProgram,1, *devices, options,NULL,NULL);” in host code. According to the above code snippet , in my program line number of this statement is 93. Then put one breakpoint at the very next statement , say “STATUSCHKMSG(“build”);”. gdb will halt its execution on this statement. Now we are all set to put break point in our OpenCL Kernel Code.
Because the kernel code is loaded , compiled and build with -g compiler flag so Kernel executable code will contain debugging information. But to put break point and debug Kernel code , we need any of the two thing. One : either kernel subroutine name , Two : The line number on which the statement is written. As the the code is compiled on runtime, there is no way that we can come to know, on which line which particular kernel code statement is placed. So there is one way to find the starting point of the code or subroutine. Use bellow command on gdb interactive shell to find out that , the kernel source code is successfully loaded.
info func __OpenCL_<your-kernel-subroutine-name>_kernel
say suppose my kernel name is “hello_world_OpenCL_kernel” then OpenCL compiler will mangle this soubroutine name as
now we can put break point at starting of kernel subroutine as follows
Now as the break point is set at starting of OpenCL kernel subroutine , we can reach to that point with following gdb command.
With this command control will reach to line __OpenCL_hello_world_OpenCL_kernel_kernel (). Which is the starting line of OpenCL kernel subroutine. To check , if everything is going well, type following command to gdb
This command will display next ten line of your source code. As your current source code file will be kernel source code file , you should be able to see OpenCL kernel source code. So that it. You are ready to rock with gdb … to debug OpenCL program. Put as many break points , as you want on that kernel source. use display command to constantly monitor any variable value …debug line by line of the source code by next command. Good luck..
NOTE : with thanks to “brg” from AMD Developer forum.