Skip to content

Converge LP/MIP remote execution on the explicit-client pattern (remove remote-solve registry) #1692

Description

@ramakrishnap-nv

Background

LP/MIP remote execution is triggered implicitly: solve_lp / solve_mip check is_remote_execution_enabled() (set by CUOPT_REMOTE_HOST / CUOPT_REMOTE_PORT) and reroute. Because that check lives inside cuopt_mathematical_optimization, the engine needs to call into cuopt_grpc — the reverse of the dependency direction, since cuopt_grpc already links the engine.

The workaround is a function-pointer registry: cuopt_mathematical_optimization holds nullable slots that libcuopt_grpc.so's ELF constructor fills via register_remote_solvers(), reached through a lazy dlopen. That lazy load is also why the slots have to be atomic — the constructor publishes them on whichever thread triggers the load while others may be reading.

Raised by @hlinsen in #1622:

The umbrella/CLI/Python layer should select local versus remote, with cuopt_grpc depending one-way on mathematical-optimization types. Can we remove the dlopen/atomic registration mechanism entirely?

The pattern already exists

#1597 (routing over gRPC) does this the clean way. Zero uses of CUOPT_REMOTE_HOST, is_remote_execution_enabled or get_memory_backend_type; no registry, no dlopen, no constructor registration. The user asks for remote explicitly:

client = RoutingClient("gpu-host:50051")
client.solve(data_model, settings)

cpu_routing_problem_t is a plain data type in cuopt_routing; the mapper, client and server live in cuopt_grpc. The dependency stays one-way and the routing engine stays local-only.

LP/MIP is the outlier, not the pattern.

Proposal

Add LPClient / MIPClient mirroring RoutingClient, then delete the registry:

  • cpp/include/cuopt/mathematical_optimization/remote_solve_registry.hpp
  • cpp/src/pdlp/remote_solve_registry.cpp
  • cpp/src/grpc/client/grpc_registration.cpp
  • the remote branches in cpp/src/pdlp/solve.cu, cpp/src/mip_heuristics/solve.cu, cpp/src/pdlp/utilities/cython_solve.cu and cpp/cuopt_cli.cpp

cuopt_mathematical_optimization becomes local-only and every component dependency is one-way. The dlopen, the atomics and the ELF constructor all go with it.

Open question

What happens to CUOPT_REMOTE_HOST / CUOPT_REMOTE_PORT. Keeping them as a deprecated compatibility path preserves existing users' setups; removing them is cleaner but is a user-visible break. This is a product decision, not a build one.

Sequencing

Depends on #1622 (component split) and #1597 (routing over gRPC). Best done in or right after #1597, which already owns the gRPC client layer and establishes the pattern — rather than in #1622, which would mean duplicating that design work and adding a user-visible API change to a build-focused PR.

Metadata

Metadata

Assignees

Labels

awaiting responseThis expects a response from maintainer or contributor depending on who requested in last comment.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions