Tokenization throughput: process pool capped at 4 workers, GIL-bound thread path (benchmark: caladan 059 batches)
I maintainer di solito rispondono entro 1 giorno
@shobhitagnihotri69 ci sta già lavorando.
Dal 23/9/2026.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
- Tipo di issue
- Refactoring
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- python
- Ambito
- backend, performance
Direzione di ricerca
Inizia da src/art/trajectories/_parallel.py e dal punto di ingresso art.tokenize, quindi riproduci il carico di lavoro descritto in caladan/experiments/059-robust-policy.py usando una piccola porzione di traiettoria. Misura il throughput di processi e thread, il warm-up, la serializzazione e il comportamento delle chiamate concorrenti. Il lavoro è completato quando un miglioramento di parallelizzazione scelto è stato sottoposto a benchmark rispetto al limite superiore riportato di 84k tokens/s senza regressioni nel comportamento esistente.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
art.tokenize parallelizes through src/art/trajectories/_parallel.py, but on a 64-CPU driver the steady-state ceiling is ~84k tokens/s because the process pool is hard-capped at _PROCESS_MAX_WORKERS = 4 and the thread path is GIL-bound at ~30k tokens/s. Proposing caladan experiment 059's per-step tokenization as a concrete benchmark workload for improving this.
Benchmark workload (caladan experiments/059-robust-policy.py)
Per training step the driver tokenizes two things back to back:
art.tokenize(groups, multi_history=True, base_model="Qwen/Qwen3.6-35B-A3B")— 8TrajectoryGroups x 5 trajectories (1 real corpus trajectory + 4 dynamics-model rollouts), each rollout carrying two ~20k-token histories (policy view + adversary/dynamics view with captured sampled tokens and logprobs). ~40 leaves, ~1.5M tokens.art.tokenize([cal.dynamics.trajectory(t, model=adversary) for t in reals], model=adversary, base_model=...)— 8 single-history adversary views of the real trajectories, ~20k tokens each.
The corpus is tau-bench retail-49 transcripts (corpus4096, ~7 MB per trajectory materialized). A self-contained reproduction only needs 8–16 of those trajectories; happy to share a slice.
Measurements (this box: 120 CPUs, cgroup limit 64, tokenizer cached)
16 adversary-view trajectories, ~300k tokens, art.tokenize(..., model="adv", base_model="Qwen/Qwen3.6-35B-A3B"):
| run | wall | throughput | backend |
|---|---|---|---|
| 0 | 11.8 s | 26k tok/s | threads (4 workers) |
| 1 | 9.2 s | 33k tok/s | threads |
| 2 | 26.7 s | 11k tok/s | process pool spawn + tokenizer load in 4 workers |
| 3 | 3.6 s | 84k tok/s | processes (4 workers) |
| 8 + 8 sequential, warm | 4.0 s | processes | |
8 + 8 asyncio.gather, warm |
3.5 s | processes, shared pool |
Observations from _parallel.py
_PROCESS_MAX_WORKERS = 4regardless of_cpu_capacity(); with 64 CPUs available, 60 sit idle.- Processes are only enabled after a tuning key has >= 2 thread runs each >= 1 s (
_consider_processes). The tuning key includes_size_bucket(len(values)), so every distinct batch-size bucket pays that warm-up again, and the first process run also pays a ~25 s spawn + tokenizer load. - Thread path:
trajectory.tokenizeis mostly Python (chat template render, message/sampled-token matching, flag construction); only the Rust encode releases the GIL, soworkers > ~4doesn't help. - Process path: one pickle round trip per trajectory (
_process_payloadsserial on one thread,_deserialize_process_result+_rebind_process_resultper item). For ~7 MB trajectories this is a nontrivial share of the 3.6 s. - The autotuner (
_observe_process) assumes exclusive use of the pool; concurrentart.tokenizecalls contend for the same 4 workers and skew each other's rate measurements (it disables processes if they don't beat threads by 5%).
Ideas
- Derive the process cap from capacity (e.g.
min(capacity, 16)), or expose it (ART_TOKENIZE_PROCESSES). - Let callers opt into processes up front instead of waiting for two slow thread runs per size bucket; or warm the pool at import/first call in the background.
- Batch several trajectories per process task to amortize pickling and the per-task scheduling overhead.
- Reuse the pickled payload for
tensorizerather than re-pickling. - Make the tuner concurrency-aware (share
next_workersacross in-flight calls, or measure per-pool rather than per-call).
Would be glad to run any candidate against the 059 shapes above.
- Lingua principale
- Python
- Stelle
- 10.8k
- Fork
- 1k
- Merge medio
- 16h 14m
- PR unite (30g)
- 148
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di OpenPipe/ART
-
Distributed group_mean casts group ids to float32, losing precision vs non-distributed pathForse già presa @OnePunchMonk l’ha presa 14 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Add from_entity parameter to _experimental_fork_checkpointForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
-
Nonfused column LoRA misses input-gradient SUM when TP>1 and sequence parallelism is disabledForse già presa @bradhilton l’ha presa 14 giorni fa. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di OpenPipe/ART
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
sierra-research/tau2-bench#635 ·
I maintainer di solito rispondono entro 1 giorno
-
The add-ssm-model skill requires a Cython simulator; the contributing guide allows Python onesForse già presa @fmuia l’ha presa oggi. Apertadocumentation skill
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
lnccbrown/ssm-simulators#406 ·
I maintainer di solito rispondono entro 4 giorni
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 95/100
btclib-org/btclib-ecc#309 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
jbacalso24/mimry#459 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
[Bug] POST /revoke with a FastMCP access token is a silent no-op (ownership gate never matches)Apertaauth bug high-priority
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno