Skip to content

Improving exception handling and logging in libsyclinterface #677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
diptorupd opened this issue Nov 17, 2021 · 2 comments
Closed
1 task done

Improving exception handling and logging in libsyclinterface #677

diptorupd opened this issue Nov 17, 2021 · 2 comments
Assignees
Labels
libsyclinterface Issues related to libsyclinterface
Milestone

Comments

@diptorupd
Copy link
Contributor

diptorupd commented Nov 17, 2021

Related #35 #628 #351

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:

  1. No throw: No C++ exceptions will be raised inside libsyclinterface, i.e., all exceptions should be caught.
  2. 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.)
  3. 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.
  4. No guarantees: 😃

Requirements

  1. Ensure proper exception safety is implemented in libsyclinterface by auditing the code and adding negative test cases.

  2. 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 a handler 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 the helper 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.

  3. We are repeating the same code in every function in libsyclinterface. Instead, a better way can be to just catch std::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();
     }
}
*/
  1. C++ allows writing code such as throw 1, so technically not all exceptions are std::exception objects. We should evaluate if handling of non-std::exception objects is required (Improve exception handling inside libsyclinterface #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?
  2. 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:

@oleksandr-pavlyk
Copy link
Contributor

So we need to create an overloaded error_handler C++ function with signatures:

void error_handler(
     const std::exception &e,
     const char *file_name,
     const char *func_name,
     int line_num,
     int level = 0   /* or an enum */
);

void error_handler(
     const std::string &what,
     const char *file_name,
     const char *func_name,
     int line_num,
     int level = 0   /* or an enum */
);

The former signature would be used from within catch(const std::exception &e) { /* code */ } block, while the latter one can be used for other occasions, e.g. input reference was null, or we are in catch(...) { /* code */ } block.

The error handling should look like

   try {
       do_something();
   } catch(const std::exception &e) {
       do_resource_cleanup(); // this may need to be done differently for different e.category() and e.code() values
       error_handler(e, __FILE__, __func__, __LINE__);
   } catch(...) {
       error_handler(fatal_exeception_string, __FILE__, __func__, __LINE__, FATAL_ERROR_LEVEL);
       std::terminate();
  }

@diptorupd diptorupd changed the title Improving exception handling and logging in libsyclinterface Improving exception handling and logging in libsyclinterface Jan 8, 2022
@diptorupd diptorupd added the libsyclinterface Issues related to libsyclinterface label Jan 8, 2022
@oleksandr-pavlyk
Copy link
Contributor

I suppose this has been implemented and needs to be closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libsyclinterface Issues related to libsyclinterface
Projects
None yet
Development

No branches or pull requests

4 participants