@@ -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 }
@@ -1162,11 +1163,12 @@ PYBIND11_MODULE(PYBIND11_MODULE_NAME, m)
11621163 static constexpr const char *exception_nvbench_runtime_error_doc = R"XXXX(
11631164An exception raised if running benchmarks encounters an error
11641165)XXXX" ;
1165- py::object benchmark_exc_ =
1166- py::exception<nvbench_run_error>(m, " NVBenchRuntimeError" , PyExc_RuntimeError);
1167- benchmark_exc_.attr (" __doc__" ) = exception_nvbench_runtime_error_doc;
1168-
1169- benchmark_exc = benchmark_exc_.release ();
1166+ exc_storage.call_once_and_store_result ([&]() {
1167+ py::object benchmark_exc_ =
1168+ py::exception<nvbench_run_error>(m, " NVBenchRuntimeError" , PyExc_RuntimeError);
1169+ benchmark_exc_.attr (" __doc__" ) = exception_nvbench_runtime_error_doc;
1170+ return benchmark_exc_;
1171+ });
11701172
11711173 // ATTN: nvbench::benchmark_manager is a singleton, it is exposed through
11721174 // GlobalBenchmarkRegistry class
@@ -1175,7 +1177,7 @@ An exception raised if running benchmarks encounters an error
11751177 py::nodelete{});
11761178
11771179 // function register
1178- auto func_register_impl = [& ](py::object fn) { return std::ref (global_registry->add_bench (fn)); };
1180+ auto func_register_impl = [](py::object fn) { return std::ref (global_registry->add_bench (fn)); };
11791181 static constexpr const char *func_register_doc = R"XXXX(
11801182Register benchmark function of type Callable[[nvbench.State], None]
11811183)XXXX" ;
@@ -1210,7 +1212,7 @@ Register benchmark function of type Callable[[nvbench.State], None]
12101212 // Testing utilities
12111213 m.def (" test_cpp_exception" , []() { throw nvbench_run_error (" Test" ); });
12121214 m.def (" test_py_exception" , []() {
1213- py::set_error (benchmark_exc , " Test" );
1215+ py::set_error (exc_storage. get_stored () , " Test" );
12141216 throw py::error_already_set ();
12151217 });
12161218}
0 commit comments