Skip to content

Import-time cpp_extension JIT can hang forever on a stale build lock (FileBaton spin-wait); please add a timeout or lock-staleness check #207

Description

@JinukMoon

Summary

import openequivariance (v0.4.1) JIT-builds two torch extensions at import time in openequivariance/extlib/__init__.py:

torch_module = torch.utils.cpp_extension.load("libtorch_tp_jit", ...)
generic_module = torch.utils.cpp_extension.load("generic_module", ...)

torch.utils.cpp_extension.load has two properties that combine badly on shared/limited hosts:

  1. ninja parallelism defaults to nproc (only bounded by the MAX_JOBS env var), and
  2. concurrent/subsequent builds serialize on a lock file in the extension build dir via torch's FileBaton, which spin-waits indefinitely with no timeout.

If a first build is killed part-way (OOM-killer, cgroup pids limit, user Ctrl-C, batch scheduler), the stale lock file remains, and every later import openequivariance hangs forever, silently — no traceback, no log, nothing on the GPU.

Observed in the field

On a login node with a per-user cgroup pids.max=100 (Fedora 36, RTX A4500, torch 2.x cu128, openequivariance 0.4.1, installed as the enable_OpenEquivariance modifier path of nequip-compile):

  • the first import's ninja swarm (-j <nproc>) exceeded the pids limit and died;
  • the stale lock remained in ~/.cache/torch_extensions/<tag>/libtorch_tp_jit/;
  • every subsequent nequip-compile ... --modifiers enable_OpenEquivariance then hung deterministically at model load, reproducibly, with zero diagnostics.

The same workload with prebuilt-kernel backends (cuEquivariance) on the same host was unaffected, which is what isolated the JIT path.

Suggested fixes (any of these would prevent the silent hang)

  1. Wrap the two cpp_extension.load calls with a bounded wait: if the baton does not clear within N minutes, raise with a message naming the lock path instead of spinning forever.
  2. Detect a stale lock proactively (lock exists but no live ninja/compiler process) and remove it before building.
  3. Default MAX_JOBS to a small value (e.g. 4) for these two import-time builds unless the user overrides — an import-time side effect should not fan out to nproc compile jobs.
  4. At minimum, document MAX_JOBS and the stale-lock failure mode in the install docs.

Our downstream workaround (for reference): set MAX_JOBS=4 for any process importing oeq, and pre-clean libtorch_tp_jit/lock + generic_module/lock under $TORCH_EXTENSIONS_DIR when no ninja process is alive.

Thanks for the great kernels — happy to test a patch.

Metadata

Metadata

Assignees

Labels

duplicateThis issue or pull request already exists

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions