OpenNMT / OpenNMT/CTranslate2

macOS Python 3.14 CPU backend: intra_threads=0 aborts on 4.7.2 and oversubscribes on 4.8.0

Open
#2,063 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
4.7k
Forks
536
Avg merge
12h 12m
Merged PRs (30d)
4

Description

Summary

On macOS arm64 with Python 3.14.5, the no-OpenMP CTranslate2 CPU backend behaves poorly when intra_threads=0 is used through Argos Translate. In 4.7.2 it produced a native abort during a sustained translation workload. In 4.8.0 the same workload no longer aborted in my test, but the automatic backend threading path was still pathologically slow and CPU-heavy compared with intra_threads=1.

Environment

macOS 26.5.1 arm64
Python 3.14.5
CTranslate2 4.7.2 and 4.8.0 wheels
Argos Translate / argostranslate-lt 1.12.1
English -> Russian Argos model

4.7.2 crash

With CTranslate2 4.7.2 and Argos' default ARGOS_INTRA_THREADS=0, a sustained Markdown translation workload aborted after several hundred translation calls:

libc++abi: terminating due to uncaught exception of type std::__1::system_error:
condition_variable wait failed: Invalid argument

Crash report showed the faulting thread inside the vendored CPU backend thread pool:

BS::thread_pool_light::worker()
std::__1::condition_variable::wait(...)

The main thread was waiting in:

ctranslate2::python::wait_on_futures<ctranslate2::TranslationResult>(...)
ctranslate2::python::TranslatorWrapper::translate_batch(...)

4.8.0 performance problem

I upgraded the same environment to CTranslate2 4.8.0. The crash-adjacent segment completed, and a full sustained run completed when using intra_threads=1.

However, with the unpatched default intra_threads=0, the process became extremely CPU-heavy and slow:

CPU: ~1470%
Hot path: ctranslate2::TranslatorWrapper::translate_batch
          ctranslate2::ops::Gemm::compute
          ruy::ThreadPool::ExecuteImpl
          ruy::BlockingCounter::Wait
          BS::thread_pool...

Benchmark on the same 30-unit Markdown slice with CTranslate2 4.8.0:

intra=0  TIMEOUT >60s
intra=1  elapsed=31.012s user=36.103s  sys=0.120s
intra=2  elapsed=48.529s user=84.297s  sys=19.564s
intra=4  elapsed=38.526s user=139.771s sys=28.153s
intra=8  elapsed=37.895s user=275.805s sys=28.084s

For this workload, intra_threads=1 is both fastest and most stable.

Notes

Argos Translate is mitigating this by defaulting ARGOS_INTRA_THREADS to 1 on Darwin while preserving explicit user overrides:

https://github.com/argosopentech/argos-translate/pull/528

I am filing this here because the 4.7.2 abort and 4.8.0 oversubscription both appear to originate in the CTranslate2 macOS no-OpenMP CPU backend path when the backend default thread count is selected.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the macOS arm64 workload with CTranslate2 4.8.0, comparing intra_threads=0 with 1, and inspect TranslatorWrapper::translate_batch, the vendored BS::thread_pool, and ruy::ThreadPool::ExecuteImpl. Done means explaining and correcting the abort or oversubscription path while preserving explicit thread-count overrides, then validating the sustained translation benchmark.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, macos, python
Domain
backend, operating-systems, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.