Description
The issue relates to an overhaul of the exception handling design in the libsyclinterface
helper library.
Background
libsyclinterface
tries to follow the so-called Abrahams Guarantees design for exception handling. Our intent is to ensure:
- No throw: No C++ exceptions will be raised inside
libsyclinterface
, i.e., all exceptions should be caught. - Basic exception safety: No resources should be leaked in the case of an exception. All previously allocated resources in the function prior to encountering an exception should get freed inside the
catch
block. (Note: Klockwork is able to catch these issues.) - Strong exception safety: Rollback of any externally visible side-effects. If an argument passed into a function was updated prior to encountering the exception, it should be reverted back to its original value.
- No guarantees: 😃
Requirements
-
Ensure proper exception safety is implemented in
libsyclinterface
by auditing the code and adding negative test cases. -
Make the handling of exceptions more informative and user configurable.
Currently,libsyclinterface
only prints out the exception message inside a catch block. The behavior is very rudimentary and not configurable at all. Instead, we can introduce ahandler
function that can log exceptions in different ways, such as print out messages with different levels of verbosity or even write them to a file. The handler function should be added to thehelper
directory.
We can use a library such as Boost Log for this purpose. Boost logs allows creating a global logger that I believe is thread safe. Most probably we can control the logger behavior using environment variables. -
We are repeating the same code in every function in
libsyclinterface
. Instead, a better way can be to just catchstd::exception
and then pass the exception object to the handler function. We can introduce a big switch inside the handler as shown in the following snippet . Doing so will also address Update sycl interface library to use SYCL 2020 exceptions #628.
// a_sycl2020_conformant.cpp
#include <CL/sycl.hpp>
#include <iostream>
int main(void) {
sycl::device d;
try {
sycl::device pd = d.get_info<sycl::info::device::parent_device>();
} catch (const sycl::exception &e) {
handler(e);
}
return 0;
}
/*
void handler(const std::exception &e) {
if (e.category() == sycl::sycl_category() && e.code() == sycl::errc::runtime) {
std::cerr << "No parent" << std::endl;
} else {
std::cerr << "Unknown exception occurred: " << ex.what() << std::endl;
std::terminate();
}
}
*/
- C++ allows writing code such as
throw 1
, so technically not all exceptions arestd::exception
objects. We should evaluate if handling of non-std::exception
objects is required (Improve exception handling insidelibsyclinterface
#351). I seriously doubt SYCL/dpcpp_cpp_rt is going to do any such a thing, but maybe we can add a special handler to catch all non-std::exception
objects? - Make it possible to see the exact file, function, and line where the exception was thrown either using
BOOST.log
or directly by using the__FILE__
,__func__
,__LINE__
macros.
Subtasks: