Export the C++ runtime for another GPU

Prepare robot artifacts on a development GPU, then deploy them to a different CUDA GPU, including an ARM64 Jetson Thor. The deployment machine needs the C++ runtime, CUDA driver and runtime libraries, and exported artifacts. PyTorch, Warp, and cuRobo Python packages are needed only on the export machine. Mesh scenes additionally need Warp’s native mesh backend; the cuboid-only benchmark does not.

Describe the deployment GPU

Copy the standalone device probe to the deployment machine and run it with system Python. It uses only Python’s standard library and libcuda.so.1:

scp cpp_runtime/robot/tools/export_device.py user@target-host:/tmp/export_device.py
ssh user@target-host \
  'python3 /tmp/export_device.py --out /tmp/thor.json'
scp user@target-host:/tmp/thor.json ./thor.json

Replace user@target-host with your deployment machine’s SSH destination. --device N selects a visible CUDA device ordinal; the default is zero. The JSON records the GPU name, cubin architecture, SM count, and opt-in shared-memory limit. Probe the intended GPU partition when using MIG.

Export robot artifacts

Run the exporter in the development environment:

source .venv/bin/activate
python cpp_runtime/robot/tools/export_robot.py \
  --robot-config curobo/content/configs/robot/franka.yml \
  --target-device thor.json \
  --out cpp_runtime/robot/artifacts/franka_thor

Omit --target-device to keep exporting for the active local GPU. Use a separate output directory for each target. The robot kinematics manifest retains the device description; all exported CUDA and Warp cubins use its architecture. L-BFGS uses its shared-memory limit, and RNEA launch profiles use its SM count. Foreign cubins are compiled without loading them on the export GPU; validate them on the deployment GPU before relying on performance results.

The development machine still needs a supported CUDA GPU for robot preparation and IK input sampling. Its NVRTC and Warp compilers must both support the target architecture. Warp bundles its own CUDA compiler: installing CUDA 13 on the host does not upgrade a CUDA 12 Warp wheel. For Thor (sm_110), use a CUDA 13 Warp build on the export host. For example, the Linux x86-64 CUDA 13 wheel for Warp 1.17 is available from NVIDIA’s Warp releases:

uv pip install \
  'https://github.com/NVIDIA/warp/releases/download/v1.17.0/warp_lang-1.17.0+cu13-py3-none-manylinux_2_28_x86_64.whl'

Choose the release and CPU architecture matching your development environment. The exporter checks compiler architecture support before writing robot artifacts. See Warp installation instructions for other builds.

Prepare benchmark inputs locally

The benchmark runner can prepare target artifacts and frozen inputs without building or executing a host benchmark:

python cpp_runtime/benchmarks/run_benchmarks.py \
  --suite motion --max-problems 2 --prepare-only \
  --target-device thor.json \
  --output cpp_runtime/benchmarks/outputs/thor_smoke

The example prepares a partial smoke workload. Remove --max-problems 2 for the full motion corpus; use --suite all to include IK. Preparation needs the repository’s benchmark extra on the development machine. The device description participates in the export cache key, and --target-device requires --prepare-only to prevent execution of target kernels locally.

Copy the prepared output directory to the deployment machine. Keep inputs.json, source provenance, exclusions, and artifact hashes with the results. Paths in inputs.json refer to the export machine: replace their output-directory prefix when supplying native arguments.

Build and run on the deployment machine

GPU cubins are independent of the host CPU architecture. The runtime library and benchmark executable must be built for the deployment CPU. An x86-64 executable cannot run on ARM64 Thor. Building on Thor avoids needing an ARM64 cross-compilation toolchain.

Transfer these source paths, preserving their repository-relative layout:

  • cpp_runtime/robot/ (exclude generated artifacts and caches);

  • cpp_runtime/benchmarks/CMakeLists.txt and cpp_runtime/benchmarks/benchmark.cpp;

  • curobo/_src/curobolib/kernels/.

On Thor, build with the existing CUDA toolkit and C++17 compiler:

export PATH=/usr/local/cuda/bin:$PATH
cmake -S cpp_runtime/benchmarks -B build/thor \
  -DCMAKE_BUILD_TYPE=Release -DCMAKE_CUDA_ARCHITECTURES=110 -DBUILD_TESTING=OFF
cmake --build build/thor --target curobo_benchmark -j2

For another GPU, replace 110 with the device description’s architecture number. Keep the matching libcurobo_robot_runtime.so with the executable, preserving the build layout or setting LD_LIBRARY_PATH to the library directory. A CUDA toolkit supporting the target architecture is required for this build. Export with a toolkit compatible with the target driver; a newer driver capability reported by nvidia-smi does not identify the installed toolkit version.

The native motion invocation is:

curobo_benchmark motion ARTIFACT INPUT RESULTS PAYLOAD_3KG UNUSED MAX_CUBOIDS NUM_KNOTS

Use the dataset artifact/input and capacities from inputs.json. PAYLOAD_3KG=0 selects the unloaded case and 1 selects the 3 kg case. Both enable inverse dynamics and planning effort limits by default. Append --disable-inverse-dynamics to disable effort checks in IK, RRT, and TrajOpt while retaining the payload mass. Time optimization and its final dynamics validation remain enabled. Pass 0 for the unused argument; the executable runs every problem in the prepared input. The native IK invocation is:

curobo_benchmark ik ARTIFACT INPUT RESULTS COLLISION_FREE CONFIG

Run each dataset/payload or robot/mode separately. Copy native .jsonl and .states.f32 results back to the development environment for full trajectory scoring. The executable retains its normal CUDA graphs and sustained warmup.

Capture kernel timings

Measure the unprofiled workload first, then run the same native command in a separate output directory with Nsight Systems:

nsys profile --trace=cuda,nvtx --sample=none --cpuctxsw=none \
  --cuda-graph-trace=node --capture-range=cudaProfilerApi \
  --capture-range-end=stop --export=sqlite --output=thor_profile \
  build/thor/curobo_benchmark motion \
  ARTIFACT INPUT PROFILE_RESULTS DYNAMICS 0 MAX_CUBOIDS NUM_KNOTS --profile
nsys stats --report cuda_gpu_kern_sum thor_profile.nsys-rep

The benchmark captures up to 50 warmed motion calls or five IK batches. Node tracing exposes individual graph kernels. Summed kernel durations can exceed wall time because streams overlap; profile timings are diagnostic. Monitor actual clocks, temperature, and concurrent GPU activity during measurement. Use Nsight Compute on the dominant kernels when hardware counter access is available.