dpctl icon indicating copy to clipboard operation
dpctl copied to clipboard

Provide Python hook for asynchronous exception handler

Open oleksandr-pavlyk opened this issue 5 years ago • 6 comments

When creating a SyclQueue, or SyclContext one should be able to define an exception handler in Python.

One operation that can through an exception, or asynchronous SYCL exception should be wrapped in try{ } catch(std::exception &e) { }.

Per https://github.com/IntelPython/dpnp/issues/201#issuecomment-719569082 the asynchronous exception can be caught, converted to dpctl.SyclException instances, and provided to a user-defined function for handling.

oleksandr-pavlyk avatar Feb 03 '21 00:02 oleksandr-pavlyk

@oleksandr-pavlyk I was thinking of implementing it as follows:

In the C API, add a functor that is initialized with a Python callback function and invokes the callback inside a async_handler function. In the Cython-layer, we need a function that switches over the error codes passed to the callback function and then raise a PyErr.

I am actually not totally sure on the Cython/Python side of things, but for the C-API, following is what I had in mind:

#include <iostream>
#include <functional>
#include <CL/sycl.hpp>

class invalid_kernel;
using namespace cl::sycl;

namespace {
void py_exception_handler (int err_code) {
    std::cerr << "This is the callback that Cython passed to  dpctl C-API."
                 "Error code (" << err_code << ")\n";
}

struct DPCTL_AsycErrorHandler {
    void (*exception_handler)(int err_code) = nullptr;

    DPCTL_AsycErrorHandler (void (*py_err_handler)(int err_code))
    :  exception_handler(py_err_handler)
    {  }

    void operator() (const exception_list &exceptions) {
        for (std::exception_ptr const& e : exceptions) {
            try {
                std::rethrow_exception(e);
            } catch(cl::sycl::exception const& e) {
                std::cerr << "ASYNC error handling\n";
                std::cerr << "Caught asynchronous SYCL exception:\n"
                          << e.what() << std::endl;
                if(exception_handler) {
                    // In the spec but not supported yet
                    //auto err_code = e.code().value();
                    auto err_code = -1;
                    exception_handler(err_code);
                }
            }
        }
    }
};
} /* end of anonymous namespace */

int main(int, char**) {
    cl::sycl::queue queue(cl::sycl::default_selector{}, 
                          DPCTL_AsycErrorHandler(py_exception_handler));

    queue.submit([&] (cl::sycl::handler& cgh) {
        auto range = cl::sycl::nd_range<1>(cl::sycl::range<1>(1), cl::sycl::range<1>(10));
        cgh.parallel_for<class invalid_kernel>(range, [=] (cl::sycl::nd_item<1>) {});
    });

    try {
        queue.wait_and_throw();
    } catch (cl::sycl::exception const& e) {
        std::cerr << "Caught synchronous SYCL exception:\n"  << e.what() << std::endl;
    }
    return 0;
}

diptorupd avatar Feb 09 '21 22:02 diptorupd

@oleksandr-pavlyk I pushed an as yet untested implementation of DPCTLSyclQueue_Create to my WIP branch that implements the async_handler feature. I expect this function to replace the DPCTLQueueMgr_GetQueueFromContextAndDevice function and to be used everywhere we create queues in C API and Cython.

Will appreciate your feedback.

diptorupd avatar Feb 10 '21 05:02 diptorupd

@diptorupd The sycl::exception currently provides get_cl_code() method.

oleksandr-pavlyk avatar Feb 10 '21 15:02 oleksandr-pavlyk

Configurable Python async error handler is not as useful as I thought it might be.

Instead of allowing a user to write one, dpctl provides a default async error handler in branch featute/queue_manager_v2

oleksandr-pavlyk avatar Mar 19 '21 12:03 oleksandr-pavlyk

dpctl already supports setting of sycl::async_handler in sycl::queue and sycl::context. The default handler implemented in dpctl/_sycl_queue.pyx` is used.

It is not user configurable.

C-API should support custom synchronous error handler to allow information contained in C++ exceptions to cross C-interface. The handler should take an error code enum and a string (e.what()) as artguments and return void.

The default handler for C user may be to echo to std::cerr, but dpctl should set to translate error code & error message to Python exceptions.

oleksandr-pavlyk avatar Apr 16 '21 19:04 oleksandr-pavlyk

@oleksandr-pavlyk @vlad-perevezentsev Is solving this issue still on the cards? Can we close the issue based on Vlad's error handler redesign?

diptorupd avatar Apr 06 '22 01:04 diptorupd

Closing as no longer relevant. The async exception handler is a C++ callable which takes a C++ argument. Passing such a callable from C (created in Python, but most importantly, passed to queue construction via C interface just does not work).

Moreover, we could not identify sensible use-cases that would become possible should custom async handler be available for Python user to program.

oleksandr-pavlyk avatar May 21 '24 21:05 oleksandr-pavlyk