Responding to review from mux85

nythrix
2010-03-25
2012-12-21
  • nythrix
    nythrix
    2010-03-25

    … i see that in some functions some parameters are passed as pointers. why not to use out or ref? this would avoid the use of unsafe code and make the code cleaner…

    I suppose you're talking about the bindings layer because the objects public API is fully safe.
    This was a deliberate design decission which I'll try to explain in this post.
    First, let's examine one of the OpenCL bindings:

    [DllImport( dll, EntryPoint = "clEnqueueTask" )]
    public extern static unsafe ComputeErrorCode EnqueueTask(
        IntPtr command_queue,
        IntPtr kernel,
        Int32 num_events_in_wait_list,
        IntPtr* event_wait_list,
        IntPtr* newEvent );
    

    The OpenCL specs state that we could obtain an event object identifying this command. This event object is stored into the newEvent parameter. So far it looks like we could indeed trade the pointer for a ref parameter. But what if we DON''T want to obtain such an event object? And we better don't since generating event objects carries a performance penalty (tested this myself). We cannot opt out of a ref parameter, but we can pass null if a pointer is involved, thus preventing the creation of an event object.
    I know, not every call generates event objects, and the rest of the bindings could do without unsafe. But that is horribly inconsistent and the host application ends up being a total mess (earlier versions of Cloo).
    The raw bindings were made public only recently (0.7.0) for those that need extreme control (and have the appropriate knowledge of OpenCL). The recommended way of accessing OpenCL remains the object layer which incidentally is the main target of this project.

     
  • mux85
    mux85
    2010-03-26

    thanks for your reply, now i fully understand and in fact i am now using object layer.
    I have 2 more question:
    1) I wrote deliberately wrong code for a kernel to see which exception would be called, i expected it to be BuildProgramFailureComputeException, instead it was only ComputeException. Is that right?
    2)here is a piece of code i was trying

    try
                {
                    ComputeKernel kernel = program.CreateKernel("VectorAdd");
                }
                catch (InvalidProgramExecutableComputeException e)
                {
                    Console.WriteLine("{0}",e.GetType());
                    Console.Read();
                }
    

    obviously when trying to use kernel in the rest of the program i get "The name 'kernel' does not exist in the current context" but if i define kernel outside the try block i get "Use of unassigned local variable 'kernel' " because ComputeKernel has no constructor. how can i resolve this?
    thanks in advance

     
  • nythrix
    nythrix
    2010-03-26

    ad 1) I've seen the drivers throw all kind of exceptions when building programs. You can even get an AccessViolationException on a perfectly working and tested .NET program when building a hairy OpenCL source. And that, if you think about it, doesn't make any sense. At least you were lucky to get a ComputeException :)
    That said, the drivers need some time to mature.

    ad 2) If you do: ComputeKernel kernel = null; before the try block you can override this situation. But if you ask me I wouldn't catch this exception right after it is thrown. Your program will continue execution with the kernel set to null and that's not very healthy. You need to let the exception skip over all of the code that's using the kernel and if you do that you won't face this issue in the first place.

     
  • mux85
    mux85
    2010-03-26

    1) yeah drivers have some problem indeed.
    2) i thought to this shortly after posting. but anyway wouldn't it be better to have a constructor for every class that can be instanced? at least from a purely formal point of view.

     
  • nythrix
    nythrix
    2010-03-26

    In theory a constructor is little more than syntatic sugar. The factory pattern works just as good. Even more than that, it allows things that are impossible to achieve through a constructor. The ComputeProgram.CreateAllKernels() method, which creates all the kernels in a given program and returns their list is a good example. For consistency's sake I also forced the creation of individual kernels (which CAN be done with a classic constructor) through the same mechanism.

    For several reasons three more classes have non-public constructors. Apart from kernels you cannot directly create platforms, devices and events. So yes, constructors are quite useful but sometimes they can't cut it.

     
  • mux85
    mux85
    2010-03-27

    ok, i see your point :)