b12x CompilePool: compiling in a worker that already described the job publishes nothing (lru_cache in mla_compress escapes evict_planning_artifacts)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
Direzione di ricerca
Start with b12x/attention/mla_compress/_cute.py and b12x/_lib/program_cache.py to trace how compile_compress is memoized and which caches evict_planning_artifacts() clears. Then inspect the _run_job path in b12x/_lib/compile_pool.py and the other memoized compile helpers mentioned in the issue. Reproduce with the supplied one-worker script; done means the job publishes its expected artifact after describing and compiling in the same worker.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
In b12x's CompilePool, a compile job that runs in a worker which has already described the same job returns successfully but publishes nothing to B12X_COMPILE_CACHE_DIR. The cause is compile_compress in b12x/attention/mla_compress/_cute.py. It is memoized with a plain functools.lru_cache, so describing the job stores the planning placeholder in that memo. evict_planning_artifacts() only clears caches registered through b12x._lib.program_cache, so it never removes that entry. The later _run_job in the same process gets the placeholder back, the program keys still match, and nothing is compiled.
The same pattern exists in flashinfer-ai/flashinfer main (flashinfer/experimental/b12x/attention/mla_compress/_cute.py:277). Other compile helpers also memoize with lru_cache, for example norm/vision.py:125 and comm/pcie/_dma_kernels.py. We have not checked whether they behave the same way.
Reproduction
Environment: Flare ca1f960e with its pinned FlashInfer 344e4837, torch 2.14.1+cu132, NVIDIA GB10. The script uses only CompilePool with one worker, so compile() describes and compiles in the same process. The worker never initializes CUDA.
repro.py
"""CompilePool.compile() reports success but publishes no artifact for mla_compress.
A one-worker pool describes the job (CompilePool.plan -> _describe_jobs) and then compiles
it (_run_job) in the same process. compile_compress is memoized with functools.lru_cache,
which evict_planning_artifacts() does not reach, so the compile returns the planning
placeholder and nothing is written to B12X_COMPILE_CACHE_DIR.
"""
import os
import sys
import tempfile
if "B12X_COMPILE_CACHE_DIR" not in os.environ: # spawned workers inherit the parent's choice
root = tempfile.mkdtemp(prefix="b12x-repro-")
os.environ.update(B12X_COMPILE_CACHE_DIR=f"{root}/b12x", TRITON_CACHE_DIR=f"{root}/triton")
import torch
from b12x._lib.compile_pool import CompileJob, CompilePool
from b12x._lib.compile_plan import compiled_program_available
if os.environ.get("B12X_REPRO_FIX") == "1":
# Candidate fix: memoize with b12x's program_cache, which evict_planning_artifacts() reaches.
# Module scope runs in spawned workers too, so they compile with the patched factory.
from b12x._lib.program_cache import program_cache
from b12x.attention.mla_compress import _cute
_cute.compile_compress = program_cache(_cute.compile_compress.__wrapped__)
JOB = CompileJob.create(
"b12x.attention.mla_compress._preparation:compile_mla_compress",
{"max_tokens": 2560, "max_states": 1, "max_requests": 1, "ratio": 1, "head_dim": 512},
CompileJob.DEVICE_ORDINAL,
)
def run(workers, describe_in_worker=True):
properties = torch.cuda.get_device_properties(0)
with CompilePool(
device_ordinal=0,
compute_capability=(properties.major, properties.minor),
device_uuid=str(properties.uuid),
product_name=properties.name,
sm_count=properties.multi_processor_count,
max_shared_memory_per_block=properties.shared_memory_per_block_optin,
max_shared_memory_per_multiprocessor=properties.shared_memory_per_multiprocessor,
workers=workers,
) as pool:
if describe_in_worker:
summary = pool.compile([JOB]) # plan() describes in the worker, then it compiles there
else:
from b12x._lib.compile_pool import describe_compilation
plan = describe_compilation(JOB) # describe in this process; the worker only compiles
pool.wait(pool.submit_plans([plan]))
summary = pool.summary()
programs = sorted(pool.programs, key=lambda p: (p.dialect, p.key))
return summary, [(p.name, compiled_program_available(p)) for p in programs]
if __name__ == "__main__":
print(f"torch {torch.__version__}, {torch.cuda.get_device_name(0)}")
mode = sys.argv[1] if len(sys.argv) > 1 else "worker"
summary, published = run(workers=1, describe_in_worker=mode == "worker")
print(f"describe in {mode}: jobs={summary.jobs} cute_compilations={summary.cute_compilations} "
f"published={published}")
sys.exit(0 if all(ok for _, ok in published) else 1)
$ python repro.py worker # CompilePool.compile(): describe and compile in the same worker
describe in worker: jobs=1 cute_compilations=0 published=[('attention.mla_compress.cute', False)]
$ python repro.py parent # describe in the parent, the worker only compiles
describe in parent: jobs=1 cute_compilations=1 published=[('attention.mla_compress.cute', True)]
$ B12X_"""CompilePool.compile() reports success but publishes no artifact for mla_compress.
A one-worker pool describes the job (CompilePool.plan -> _describe_jobs) and then compiles
it (_run_job) in the same process. compile_compress is memoized with functools.lru_cache,
which evict_planning_artifacts() does not reach, so the compile returns the planning
placeholder and nothing is written to B12X_COMPILE_CACHE_DIR.
"""
import os
import sys
import tempfile
if "B12X_COMPILE_CACHE_DIR" not in os.environ: # spawned workers inherit the parent's choice
root = tempfile.mkdtemp(prefix="b12x-repro-")
os.environ.update(B12X_COMPILE_CACHE_DIR=f"{root}/b12x", TRITON_CACHE_DIR=f"{root}/triton")
import torch
from b12x._lib.compile_pool import CompileJob, CompilePool
from b12x._lib.compile_plan import compiled_program_available
if os.environ.get("B12X_REPRO_FIX") == "1":
# Candidate fix: memoize with b12x's program_cache, which evict_planning_artifacts() reaches.
# Module scope runs in spawned workers too, so they compile with the patched factory.
from b12x._lib.program_cache import program_cache
from b12x.attention.mla_compress import _cute
_cute.compile_compress = program_cache(_cute.compile_compress.__wrapped__)
JOB = CompileJob.create(
"b12x.attention.mla_compress._preparation:compile_mla_compress",
{"max_tokens": 2560, "max_states": 1, "max_requests": 1, "ratio": 1, "head_dim": 512},
CompileJob.DEVICE_ORDINAL,
)
def run(workers, describe_in_worker=True):
properties = torch.cuda.get_device_properties(0)
with CompilePool(
device_ordinal=0,
compute_capability=(properties.major, properties.minor),
device_uuid=str(properties.uuid),
product_name=properties.name,
sm_count=properties.multi_processor_count,
max_shared_memory_per_block=properties.shared_memory_per_block_optin,
max_shared_memory_per_multiprocessor=properties.shared_memory_per_multiprocessor,
workers=workers,
) as pool:
if describe_in_worker:
summary = pool.compile([JOB]) # plan() describes in the worker, then it compiles there
else:
from b12x._lib.compile_pool import describe_compilation
plan = describe_compilation(JOB) # describe in this process; the worker only compiles
pool.wait(pool.submit_plans([plan]))
summary = pool.summary()
programs = sorted(pool.programs, key=lambda p: (p.dialect, p.key))
return summary, [(p.name, compiled_program_available(p)) for p in programs]
if __name__ == "__main__":
print(f"torch {torch.__version__}, {torch.cuda.get_device_name(0)}")
mode = sys.argv[1] if len(sys.argv) > 1 else "worker"
summary, published = run(workers=1, describe_in_worker=mode == "worker")
print(f"describe in {mode}: jobs={summary.jobs} cute_compilations={summary.cute_compilations} "
f"published={published}")
sys.exit(0 if all(ok for _, ok in published) else 1)_FIX=1 python repro.py worker # compile_compress memoized with program_cache instead
describe in worker: jobs=1 cute_compilations=1 published=[('attention.mla_compress.cute', True)]
In the first case, compile() returns with no error and the summary counts the job, but zero CuTe compilations ran and the program is missing from the cache.
Where we hit it
We were testing kernel precompilation for DeepSeek V4.1 Flash TP3 on three DGX Sparks. The candidate compile jobs were recorded, then described and compiled in a separate many-worker pool before the export loads the model. With 20 workers per host, 16 of the 96 distinct attention.mla_compress.cute programs were never published. Each of those programs has three equivalent payloads, so about 3 of the 20 workers held a stale memo entry for it. Compiling in fresh workers after describing, or applying the fix below, removes the gap.
Stock preparation also describes candidates through the pool (_discover_candidates, preparation/session.py:1658) and then compiles in the same workers. In our stock exports we did not see a failure from this, so we cannot say whether any current family reaches it there. If it does, _wait_programs should report "compiler completed without publishing required artifacts" rather than leave a silent gap.
Suggested fix
Memoize compile_compress with b12x._lib.program_cache.program_cache instead of functools.lru_cache, so that evict_planning_artifacts() reaches it. That is the third case above. The other lru_cache compile helpers may need the same change.
A second, more defensive option: _run_job could check compiled_program_available() for its expected programs after job.invoke() and raise if any is missing, so a stale memo shows up as an error rather than a silent no-op.
- Lingua principale
- Rust
- Stelle
- 800
- Fork
- 106
- Merge medio
- 1g 3h
- PR unite (30g)
- 100
Preparare l'ambiente
- Include un Dockerfile o un 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 NVIDIA/hyperflare-inference
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
NVIDIA/hyperflare-inference#268 ·
I maintainer di solito rispondono entro 1 giorno
-
break out engram wait timeApertaarea:caching area:engram enhancement performance triage:design-review
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
NVIDIA/hyperflare-inference#230 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 15/100
NVIDIA/hyperflare-inference#278 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
NVIDIA/hyperflare-inference#276 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
NVIDIA/hyperflare-inference#271 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di NVIDIA/hyperflare-inference
Issue simili
-
bug UI
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
wardian-app/Wardian#1746 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
jlcodes99/cockpit-tools#3125 ·
I maintainer di solito rispondono entro 2 giorni
-
bug user-sprint
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Vondor/KassenSturz#967 ·
I maintainer di solito rispondono entro 1 giorno
-
area/ci
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno
-
[BUG] Incremental sync warns "no stored highest_uid" on every round for folders with no new mailApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
rustmailer/bichon#411 ·