1

I am developing an algorithm using PyOpenCL. To avoid code duplication I am trying to use templating along with C macros to replace function calls, since OpenCL 1.2 does not support function pointers.

I currently have the following macro section in my OpenCL kernel code:

#define LINEAR_FIT_SEARCH_METHOD ${linear_fit_search_method}

#if LINEAR_FIT_SEARCH_METHOD == MIN_MAX_INTENSITY_SEARCH
#define LINEAR_FIT_SEARCH_METHOD_CALL() determineFitUsingMinMaxIntensitySearch(lineIntensities,imgSizeY,linFitParameter,linFitSearchRangeXvalues)
#elif LINEAR_FIT_SEARCH_METHOD == MAX_INCLINE_SEARCH
#define LINEAR_FIT_SEARCH_METHOD_CALL() determineFitUsingInclineSearch(lineIntensities,imgSizeY,linFitParameter,linFitSearchRangeXvalues,inclineRefinementRange)
#endif

In the kernel code I also define the corresponding functions determineFitUsingMinMaxIntensitySearch and determineFitUsingInclineSearch. I am now attempting to use the macro to exchange the function call like this:

__private struct linearFitResultStruct fitResult = LINEAR_FIT_SEARCH_METHOD_CALL();

so that I select the desired call (note: I always only need either one or the other and configuration is done before the program runs (no need for dynamically switching the two)).

Using PyOpenCL templating I now do something like this:

def applyTemplating(self):
    tpl = Template(self.kernelString)
    if self.positioningMethod == "maximumIntensityIncline":
        linear_fit_search_method="MAX_INCLINE_SEARCH"
    if self.positioningMethod == "meanIntensityIntercept":
        linear_fit_search_method="MIN_MAX_INTENSITY_SEARCH"
    rendered_tpl = tpl.render(linear_fit_search_method=linear_fit_search_method)
    self.kernelString=str(rendered_tpl)

Where self.kernelString contains the macro above along with the code.

Unfortunately I am getting this error, which I do not understand:

1:455:53: error: implicit declaration of function 'determineFitUsingInclineSearch' is invalid in OpenCL 1:9:41: note: expanded from macro 'LINEAR_FIT_SEARCH_METHOD_CALL' 1:455:41: error: initializing 'struct linearFitResultStruct' with an expression of incompatible type 'int' 1:536:30: error: conflicting types for 'determineFitUsingInclineSearch' 1:455:53: note: previous implicit declaration is here 1:9:41: note: expanded from macro 'LINEAR_FIT_SEARCH_METHOD_CALL' 1:616:41: error: initializing 'struct linearFitResultStruct' with an expression of incompatible type 'int'

I have very little experience with macros so:

Is what I am attempting even possible in this way or do I need to go a different route?

UPDATE 1: This code runs fine when I set self.positioningMethod = "meanIntensityIntercept" in my unit test, but fails when setting self.positioningMethod = "maximumIntensityIncline" with the error message above. I cannot spot the error at the yet.

UPDATE 2: I was also inspired by this post, if that helps: how to compare string in C conditional preprocessor-directives

Community
  • 1
  • 1
packoman
  • 1,230
  • 1
  • 16
  • 36
  • C macros replicate code. Trust the compiler and write proper functions if you’re worried about code density. – Jens Apr 30 '17 at 20:40
  • Not sure I understand your point. What I am attempting is to "inject" the function call using macros to modify the behavior of that call inside of another function. This is necessary since function pointer are not available under OpenCL 1.2. A related post is this one: http://stackoverflow.com/questions/7391166/does-opencl-support-function-pointers – packoman Apr 30 '17 at 20:46
  • It turns out that the method proposed above works as expected. The problem was that one of the two methods (by "injecting" throught the macro) – packoman May 01 '17 at 21:28
  • It turns out that the method above works as expected. The problem was that one of the two functions was defined after the first reference to that function, when "injecting" it using the macro. This was the reason that injecting the first function worked and the second did not (the one defined after its first call). I am not sure whether I should post this as the answer, since the problem had nothing to do with the macro itself and the solution to the problem could not have been found by anyone else with the information that was provided ... – packoman May 01 '17 at 21:37

1 Answers1

0

As you say you have very little experience with macros then I would go for something simple. determineFitUsingMinMaxIntensitySearch and determineFitUsingInclineSearch accept different number of arguments, so this could done this way:

kernel_code = """

#ifdef USE_FUNCTION_A

void function_a(
    int x,
    int y,
    int extra_param,
    __global const int* restrict in,
    __global int* restrict out
)
{
    //...
}

#else

void function_b(
    int x,
    int y,
    __global const int* restrict in,
    __global int* restrict out
)
{
    //...
}

#endif

__kernel void my_kernel(
    int x,
    int y,
    __global const int* restrict in,
    __global int* restrict out
)
{
    // ...
#ifdef USE_FUNCTION_A
    function_a(x,y,5,in,out);
#else
    function_b(x,y,in,out);
#endif
    // ...
}
"""

if use_function_a:
    prg = cl.Program(ctx, kernel_code).build("-DUSE_FUNCTION_A")
else:
    prg = cl.Program(ctx, kernel_code).build("")
doqtor
  • 8,414
  • 2
  • 20
  • 36