@@ -124,7 +124,8 @@ struct nvbench_run_error : std::runtime_error
124124 // that are defined for the base class
125125 using std::runtime_error::runtime_error;
126126};
127- py::handle benchmark_exc{};
127+
128+ PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> exc_storage;
128129
129130void run_interruptible (nvbench::option_parser &parser)
130131{
@@ -223,18 +224,18 @@ class GlobalBenchmarkRegistry
223224 }
224225 catch (py::error_already_set &e)
225226 {
226- py::raise_from (e, benchmark_exc .ptr (), " Python error raised " );
227+ py::raise_from (e, exc_storage. get_stored () .ptr (), " Python error raised " );
227228 throw py::error_already_set ();
228229 }
229230 catch (const std::exception &e)
230231 {
231232 const std::string &exc_message = e.what ();
232- py::set_error (benchmark_exc , exc_message.c_str ());
233+ py::set_error (exc_storage. get_stored () , exc_message.c_str ());
233234 throw py::error_already_set ();
234235 }
235236 catch (...)
236237 {
237- py::set_error (benchmark_exc , " Caught unknown exception in nvbench_main" );
238+ py::set_error (exc_storage. get_stored () , " Caught unknown exception in nvbench_main" );
238239 throw py::error_already_set ();
239240 }
240241 }
@@ -1158,11 +1159,12 @@ PYBIND11_MODULE(_nvbench, m)
11581159 static constexpr const char *exception_nvbench_runtime_error_doc = R"XXXX(
11591160An exception raised if running benchmarks encounters an error
11601161)XXXX" ;
1161- py::object benchmark_exc_ =
1162- py::exception<nvbench_run_error>(m, " NVBenchRuntimeError" , PyExc_RuntimeError);
1163- benchmark_exc_.attr (" __doc__" ) = exception_nvbench_runtime_error_doc;
1164-
1165- benchmark_exc = benchmark_exc_.release ();
1162+ exc_storage.call_once_and_store_result ([&]() {
1163+ py::object benchmark_exc_ =
1164+ py::exception<nvbench_run_error>(m, " NVBenchRuntimeError" , PyExc_RuntimeError);
1165+ benchmark_exc_.attr (" __doc__" ) = exception_nvbench_runtime_error_doc;
1166+ return benchmark_exc_;
1167+ });
11661168
11671169 // ATTN: nvbench::benchmark_manager is a singleton, it is exposed through
11681170 // GlobalBenchmarkRegistry class
@@ -1171,7 +1173,7 @@ An exception raised if running benchmarks encounters an error
11711173 py::nodelete{});
11721174
11731175 // function register
1174- auto func_register_impl = [& ](py::object fn) { return std::ref (global_registry->add_bench (fn)); };
1176+ auto func_register_impl = [](py::object fn) { return std::ref (global_registry->add_bench (fn)); };
11751177 static constexpr const char *func_register_doc = R"XXXX(
11761178Register benchmark function of type Callable[[nvbench.State], None]
11771179)XXXX" ;
@@ -1206,7 +1208,7 @@ Register benchmark function of type Callable[[nvbench.State], None]
12061208 // Testing utilities
12071209 m.def (" test_cpp_exception" , []() { throw nvbench_run_error (" Test" ); });
12081210 m.def (" test_py_exception" , []() {
1209- py::set_error (benchmark_exc , " Test" );
1211+ py::set_error (exc_storage. get_stored () , " Test" );
12101212 throw py::error_already_set ();
12111213 });
12121214}
0 commit comments