Skip to content

Commit d3b220b

Browse files
Fix Python wrapper cleanup and forward pass diagnostics
Release Python-owned wrapper references under the GIL so bound solver components are cleaned up safely. Also log partial forward-pass thread failures in verbose mode to make solver issues easier to diagnose.
1 parent 098ece1 commit d3b220b

2 files changed

Lines changed: 35 additions & 2 deletions

File tree

python/src/bind_solver.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ void validateInitialTrajectory(cddp::CDDP &solver,
4242
try {
4343
state_dim = solver.getStateDim();
4444
control_dim = solver.getControlDim();
45-
} catch (const std::exception &) {
45+
} catch (const std::exception &e) {
4646
throw py::value_error(
47-
"set_initial_trajectory requires a dynamical system to be set first.");
47+
std::string("set_initial_trajectory failed while querying dimensions "
48+
"(is a dynamical system set?): ") + e.what());
4849
}
4950

5051
const std::size_t expected_state_count =
@@ -95,6 +96,15 @@ class PythonBackedDynamicalSystem : public cddp::DynamicalSystem {
9596
wrapped->getIntegrationType()),
9697
owner_(std::move(owner)), wrapped_(wrapped) {}
9798

99+
~PythonBackedDynamicalSystem() override {
100+
try {
101+
if (Py_IsInitialized()) {
102+
py::gil_scoped_acquire gil;
103+
owner_.release().dec_ref();
104+
}
105+
} catch (...) {}
106+
}
107+
98108
Eigen::VectorXd getContinuousDynamics(const Eigen::VectorXd &state,
99109
const Eigen::VectorXd &control,
100110
double time) const override {
@@ -163,6 +173,15 @@ class PythonBackedObjective : public cddp::Objective {
163173
PythonBackedObjective(py::object owner, cddp::Objective *wrapped)
164174
: owner_(std::move(owner)), wrapped_(wrapped) {}
165175

176+
~PythonBackedObjective() override {
177+
try {
178+
if (Py_IsInitialized()) {
179+
py::gil_scoped_acquire gil;
180+
owner_.release().dec_ref();
181+
}
182+
} catch (...) {}
183+
}
184+
166185
double evaluate(const std::vector<Eigen::VectorXd> &states,
167186
const std::vector<Eigen::VectorXd> &controls) const override {
168187
py::gil_scoped_acquire gil;
@@ -265,6 +284,15 @@ class PythonBackedConstraint : public cddp::Constraint {
265284
: cddp::Constraint(wrapped->getName()), owner_(std::move(owner)),
266285
wrapped_(wrapped) {}
267286

287+
~PythonBackedConstraint() override {
288+
try {
289+
if (Py_IsInitialized()) {
290+
py::gil_scoped_acquire gil;
291+
owner_.release().dec_ref();
292+
}
293+
} catch (...) {}
294+
}
295+
268296
int getDualDim() const override {
269297
py::gil_scoped_acquire gil;
270298
return wrapped_->getDualDim();

src/cddp_core/cddp_solver_base.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ ForwardPassResult CDDPSolverBase::performForwardPass(CDDP &context) {
302302
std::cerr << getSolverName()
303303
<< ": ALL forward pass threads failed. Last error: "
304304
<< last_error << std::endl;
305+
} else if (failed_count > 0 && options.verbose) {
306+
std::cerr << getSolverName() << ": " << failed_count << " of "
307+
<< futures.size()
308+
<< " forward pass threads failed. Last error: " << last_error
309+
<< std::endl;
305310
}
306311
if (first_exception && !best_result.success) {
307312
std::rethrow_exception(first_exception);

0 commit comments

Comments
 (0)