I am new to OpenCL and I have read in several places that if/else structures should be avoided, mainly because when the evaluation of threads is different (divergent branching) there is a significant slowdown.
Nonetheless, I used one if(cond) followed by some prints to guarantee that when a forbidden condition is met I can debug what caused it. The point is, whenever the if() is true for a single thread I will kill the process, therefore I am not worried about different threads evaluating the condition differently.
Yet, I found out that even when all threads evaluate false in this if(), there is a massive slowdown when compared to not using the if() -- I commented out the conditional and its body statements to verify.
An observation: I have a kernel (128 workgroups, each one with 128 workitems) that calls a function foo(), and the if/prints are inside foo(). The relevant part of foo() is as follows:
foo(){
bool leftCorrect, rightCorrect, topCorrect, bottomCorrect, topLeftCorrect, topRightCorrect, bottomLeftCorrect, bottomRightCorrect;
for(i=0;i<11;i++){
for(j=0;j<11;j++){
// Initial assignments. Using select() to avoid branch divergence
leftCorrect = select(true,false,condition);
rightCorrect = select(true,false,condition);
topCorrect = select(true,false,condition);
bottomCorrect = select(true,false, condition);
// Use the previous variables to compute the other bool variables and update them
// Some boolean operations ...
// This if basically tests if more than one is true
if(leftCorrect + rightCorrect + topCorrect + bottomCorrect + topLeftCorrect + topRightCorrect + bottomLeftCorrect + bottomRightCorrect > 1){
printf("@@@@@\nFATAL ERROR: Multiple corrections in gid=%d\n",get_local_id(0));
printf("L %d\n", leftCorrect);
printf("R %d\n", rightCorrect);
printf("T %d\n", topCorrect);
printf("B %d\n", bottomCorrect);
printf("TL %d\n", topLeftCorrect);
printf("TR %d\n", topRightCorrect);
printf("BL %d\n", bottomLeftCorrect);
printf("BR %d\n", bottomRightCorrect);
}
// Do something with the boolean variables and select() statements before return
}
}
}
Relevant information:
- With the code I showed, the entire program (main host + kernel + foo) takes around 90 seconds to run
- If I comment out the entire if() statement (condition + prints), the program takes around 2 (two) seconds to run
- If I remove all the prints and use a single dummy assignment (z=0, for instance) on the if(), the program takes around 2 seconds to run
- If I remove all the prints and use a single assignment involving get_local_id(0) (z=get_local_id(0), for instance) on the if(), the program takes around 2 seconds to run
- If I remove all the prints and use a single assignment involving get_local_id(0) and print it afterward, the program takes around 7 seconds to run
- By removing all printf() statements from the original code and adding one at a time (only the first print, then the 1st and 2nd, then from 1st to 3rd, ...), I found out that up to the fourth print the running time is around 7 seconds, but after adding the 5th print the running time jumps to 90 seconds
Another relevant information, discovered in the previous tests: I am printing the maximum workgroup size in the host code to know the differences in different platforms. In the cases with a small running time (cases 2-5, up to 7 seconds), the host outputs that the maximum WG size is 8192. However, in the cases of long running time, it outputs a maximum WG size of 4096.
The clinfo command shows me the following information:
Platform Name Intel(R) CPU Runtime for OpenCL(TM)
Device Name Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
Max work item sizes 8192x8192x8192
Max work group size 8192
And the host code to show the maximum WG size is:
size_t size_ret;
cl_uint maximum_size;
error = clGetKernelWorkGroupInfo(kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE,
size_ret, &maximum_size, NULL);
cout << "-- Maximum WG size " << maximum_size << endl;
All this information is summarized in the two questions:
- Why is this tiny modification in the code causing such a massive slowdown, when the if() code is never executed?
- How can my code interfere in the maximum WG size, which is a property of the device?