mirror of
https://github.com/kvcache-ai/ktransformers.git
synced 2026-11-05 01:07:28 +00:00
[GH-ISSUE #2218] RAWINT4 direct-pointer MoE frees safetensors mmap owners and segfaults on first inference (AVX2) #1306
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/ktransformers#1306
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @f-wunderlich on GitHub (Sep 30, 2026).
Original GitHub issue: https://github.com/kvcache-ai/ktransformers/issues/2218
Environment
v0.7.0.post4, release commit5632f7197e7a9898f0723755c2fc187a946a85a6mainatc40722bf04c494f2492b7eb9e86ef01a4ede45b3moonshotai/Kimi-K2.6, revision7eb5002f6aadc958aed6a9177b7ed26bb94011bbRAWINT4, TP1, one CPU pool, 24 CPU threads, zero GPU expertsSymptom
Model loading completes, the API starts, and the scheduler segfaults on its
first RAWINT4 GEMM. Disabling CUDA graphs, overlap scheduling and GPU experts
does not prevent it.
The 136 GB core is usable. Its crashing thread is a KTransformers task-queue
worker:
The module mapping base is
0x7f024e3cb000, giving offsets0x9c703,0x15b1a5and0x15b8bb. The latter frames are in the internalTaskQueue::workerregion.At the fault:
GDB reports the address around
r13as unmapped.Root cause
operators/avx2/rawint4-moe.hppintentionally assignsBufferB.bdirectly tothe per-expert safetensor tensor:
After submitting and synchronizing that load task,
kt-kernel/python/utils/amx.pydeletes the tensor lists and releases the sharedloader:
_release_loader()clearsSafeTensorLoader.file_handle_mapand callsgc.collect(). Consequently no Python object owns the mmap-backed storage, butthe native
BufferB.bpointers remain. The first GEMM dereferences one of thosedangling pointers.
Confirmed workaround
Retain
self.gate_weights,self.up_weightsandself.down_weightswhenself.method == "RAWINT4". Scale tensors may still be released because thenative loader converts/copies them. Loader handles may also be cleared: the
retained tensor storage objects keep the mappings alive.
With that one change, the same image, checkpoint and launch arguments:
No model-weight copy is required; retaining tensor owners preserves the mmap
design and avoids allocating a second copy of the checkpoint.
Suggested fix
Make mmap ownership explicit for every native direct-pointer backend. At
minimum, RAWINT4 wrappers must retain the source tensors for at least as long
as their native MoE object can access
BufferB.b. A small regression test canload a direct-pointer RAWINT4 layer, release the loader and run one GEMM after
forcing Python garbage collection.
@yyj6666667 commented on GitHub (Oct 1, 2026):
Thanks for feedback. i will check this out
@yyj6666667 commented on GitHub (Oct 6, 2026):
Confirmed. I reproduced this issue on qj5090 and pushed a minimal fix to fix/rawint4-mmap-lifetime-2218.
The fix retains the source weight tensors specifically for the AVX2 RAWINT4 backend. Scale tensors and loader handles are still released, and copying backends keep their existing cleanup behavior. The branch changes only
kt-kernel/python/utils/amx.py.Verified on qj5090 with AVX2 explicitly selected: