Files
wehub-resource-sync 59a0a3844c
PR Test AMD / cancel-on-close (push) Has been skipped
PR Test NVIDIA ARM / scan (push) Has been skipped
PR Test NVIDIA / cancel-on-close (push) Has been skipped
PR Test AMD / scan (push) Has been skipped
PR Test NVIDIA ARM / cancel-on-close (push) Has been skipped
PR Test NVIDIA / scan (push) Has been skipped
Release Docker Images / build (cu129-torch-2.11.0) (push) Has been skipped
Release Docker Images / build (cu130-torch-2.11.0) (push) Has been skipped
Release PyPI / publish (push) Has been skipped
Scheduler Python Test / test (push) Successful in 27m19s
Docs / build (push) Successful in 28m8s
Scheduler C++ Test / test (push) Successful in 28m19s
Scheduler C++ Test / test-flat (push) Successful in 28m18s
Docs / deploy (push) Has been cancelled
PR Test AMD / finish (push) Has been cancelled
PR Test NVIDIA / finish (push) Has been cancelled
PR Test NVIDIA ARM / finish (push) Has been cancelled
PR Test NVIDIA ARM / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test AMD / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test NVIDIA / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:31 +08:00

381 lines
15 KiB
Python

"""FlatHostMirror (M15 Phase D1): byte-blind pinned-CPU slab mirror.
Pins the transport contract only (no engine wiring): one mirror per
distinct device KV tensor, whole-page row-range copies both directions,
per-tensor load events, and the layer -> tensor-index mapping D2 fences on.
"""
from __future__ import annotations
import os
import sys
import unittest
from unittest import mock
# CI Registration (parsed via AST, runtime no-op)
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ci_system.ci_register import register_cuda_ci
register_cuda_ci(est_time=60, suite="runtime-1gpu")
_PKG_FLAT_PROBE = (
"tokenspeed.runtime.configs.paged_cache_spec.scheduler_ext_flat_kvcache"
)
LAYER_TYPES = ("sliding_attention", "full_attention") * 2
# GDN hybrid: layers 0/2 are state layers (pairs 0/1); linear_attention
# disables slab pairing, so the KV side stays per-layer -- and under the
# flat GDN predicate the state layers' k/v slots are None (M18a T4).
GDN_LAYER_TYPES = ("linear_attention", "full_attention") * 2
class FlatHostMirrorTest(unittest.TestCase):
"""Real (tiny) MHATokenToKVPool on GPU, slab and legacy layouts."""
def setUp(self):
try:
import torch
from tokenspeed.runtime.cache.flat_host_mirror import (
FlatHostMirror,
)
from tokenspeed.runtime.layers.attention.kv_cache.mha import (
MHATokenToKVPool,
)
except (ImportError, ModuleNotFoundError) as exc:
self.skipTest(f"needs torch + tokenspeed_kernel: {exc}")
if not torch.cuda.is_available():
self.skipTest("needs a CUDA device")
self.torch = torch
self.FlatHostMirror = FlatHostMirror
self.MHATokenToKVPool = MHATokenToKVPool
def _pool(self, *, flat_ext: bool = True):
kwargs = dict(
size=32,
dtype=self.torch.bfloat16,
head_num=1,
head_dim=8,
layer_num=4,
device="cuda",
enable_memory_saver=False,
max_batch_size=2,
max_context_len=64,
page_size=4,
rank=0,
layer_types=LAYER_TYPES,
sliding_window_tokens=128,
enable_alt_stream=False,
)
with mock.patch(_PKG_FLAT_PROBE, return_value=flat_ext):
return self.MHATokenToKVPool(**kwargs)
def _fill_device_pages(self, mirror, device_pages):
# Sentinels distinct per (tensor, page); bf16-exact small ints.
p = mirror.page_size
for tensor_idx, (dev, _) in enumerate(mirror.tensor_pairs):
for d in device_pages:
dev[d * p : (d + 1) * p].fill_(tensor_idx * 16 + d + 1)
self.torch.cuda.synchronize()
def _snapshot(self, mirror, device_pages):
p = mirror.page_size
return [
{d: dev[d * p : (d + 1) * p].cpu().clone() for d in device_pages}
for dev, _ in mirror.tensor_pairs
]
def _roundtrip_assert(self, mirror, pairs):
torch = self.torch
p = mirror.page_size
device_pages = [d for d, _ in pairs]
self._fill_device_pages(mirror, device_pages)
before = self._snapshot(mirror, device_pages)
stream = torch.cuda.Stream()
mirror.store_pages(pairs, stream)
stream.synchronize()
for dev, _ in mirror.tensor_pairs:
for d in device_pages:
dev[d * p : (d + 1) * p].zero_()
torch.cuda.synchronize()
mirror.load_pages(pairs, stream)
stream.synchronize()
after = self._snapshot(mirror, device_pages)
for tensor_idx in range(len(mirror.tensor_pairs)):
for d in device_pages:
self.assertTrue(
torch.equal(
before[tensor_idx][d].view(torch.uint8),
after[tensor_idx][d].view(torch.uint8),
),
f"tensor {tensor_idx} device page {d} not byte-exact",
)
def test_slab_roundtrip(self):
pool = self._pool(flat_ext=True)
mirror = self.FlatHostMirror(pool, num_host_pages=8)
# 4 layers dedup to 2 K + 2 V slabs.
self.assertEqual(len(mirror.tensor_pairs), 4)
self._roundtrip_assert(mirror, [(1, 5), (2, 6), (3, 7)])
# 4 mirrors x page_size 4 x row 1*8 bf16 (16 B) = 256 B per page.
self.assertEqual(mirror.bytes_per_host_page(), 4 * 4 * 16)
def test_interleaved_groups_roundtrip(self):
# Pages owned by different groups: byte-blind copies need no
# group awareness (id-exclusivity keeps rows disjoint).
pool = self._pool(flat_ext=True)
mirror = self.FlatHostMirror(pool, num_host_pages=4)
self._roundtrip_assert(mirror, [(2, 0), (3, 1)])
def test_legacy_roundtrip(self):
# Legacy layout: all 4+4 per-layer mirrors carry data; copying
# rows dead for a page's owner group is harmless (byte-exact).
pool = self._pool(flat_ext=False)
mirror = self.FlatHostMirror(pool, num_host_pages=8)
self.assertEqual(len(mirror.tensor_pairs), 8)
self._roundtrip_assert(mirror, [(1, 3), (2, 4)])
def test_events_and_layer_mapping(self):
torch = self.torch
pool = self._pool(flat_ext=True)
mirror = self.FlatHostMirror(pool, num_host_pages=8)
self._fill_device_pages(mirror, [1])
stream = torch.cuda.Stream()
events = mirror.load_pages_with_events([(1, 5)], stream)
self.assertEqual(len(events), len(mirror.tensor_pairs))
stream.synchronize()
self.assertTrue(all(event.query() for event in events))
# Slab: paired layers map to the same K-tensor index.
self.assertEqual(mirror.num_k_tensors, 2)
self.assertEqual(
mirror.tensor_index_of_layer(0), mirror.tensor_index_of_layer(1)
)
self.assertEqual(
mirror.tensor_index_of_layer(2), mirror.tensor_index_of_layer(3)
)
self.assertNotEqual(
mirror.tensor_index_of_layer(0), mirror.tensor_index_of_layer(2)
)
for layer_id in range(4):
idx = mirror.tensor_index_of_layer(layer_id)
self.assertIs(mirror.tensor_pairs[idx][0], pool.k_buffer[layer_id])
self.assertIs(
mirror.tensor_pairs[idx + mirror.num_k_tensors][0],
pool.v_buffer[layer_id],
)
# Legacy: every layer maps to a distinct index.
legacy = self.FlatHostMirror(self._pool(flat_ext=False), num_host_pages=2)
self.assertEqual(
{legacy.tensor_index_of_layer(i) for i in range(4)}, {0, 1, 2, 3}
)
class FlatHostMirrorStateSlabTest(unittest.TestCase):
"""State slabs join the mirrored set: tensor_pairs order is K*, V*,
then (conv, ssm) flattened in slab order; state mirrors use 1-row
PAGE spans (state slabs are page-indexed) while KV mirrors span
page_size token rows."""
CONV_SHAPE = (2, 4) # 16 B/row bf16
SSM_SHAPE = (2, 8) # 32 B/row bf16
def setUp(self):
try:
import torch
from tokenspeed.runtime.cache.flat_host_mirror import (
FlatHostMirror,
flat_bytes_per_host_page,
)
from tokenspeed.runtime.layers.attention.kv_cache.mha import (
MHATokenToKVPool,
)
except (ImportError, ModuleNotFoundError) as exc:
self.skipTest(f"needs torch + tokenspeed_kernel: {exc}")
if not torch.cuda.is_available():
self.skipTest("needs a CUDA device")
self.torch = torch
self.FlatHostMirror = FlatHostMirror
self.flat_bytes_per_host_page = flat_bytes_per_host_page
self.MHATokenToKVPool = MHATokenToKVPool
def _pool(self, *, with_state: bool = True):
kwargs = dict(
size=32,
dtype=self.torch.bfloat16,
head_num=1,
head_dim=8,
layer_num=4,
device="cuda",
enable_memory_saver=False,
max_batch_size=2,
max_context_len=64,
page_size=4,
rank=0,
layer_types=GDN_LAYER_TYPES,
sliding_window_tokens=None,
enable_alt_stream=False,
)
if with_state:
kwargs.update(
conv_state_shape=self.CONV_SHAPE,
temporal_state_shape=self.SSM_SHAPE,
)
with mock.patch(_PKG_FLAT_PROBE, return_value=True):
return self.MHATokenToKVPool(**kwargs)
def _fill_device_pages(self, mirror, device_pages):
# Sentinels distinct per (tensor, page); bf16-exact small ints.
for tensor_idx, ((dev, _), span) in enumerate(
zip(mirror.tensor_pairs, mirror.row_spans)
):
for d in device_pages:
dev[d * span : (d + 1) * span].fill_(tensor_idx * 16 + d + 1)
self.torch.cuda.synchronize()
def _snapshot(self, mirror, device_pages):
return [
{d: dev[d * span : (d + 1) * span].cpu().clone() for d in device_pages}
for (dev, _), span in zip(mirror.tensor_pairs, mirror.row_spans)
]
def test_state_tensors_follow_kv_in_slab_order(self):
pool = self._pool()
mirror = self.FlatHostMirror(pool, num_host_pages=8)
# Flat GDN: state layers carry no KV (k/v slots are None, M18a T4),
# so only the 2 attention layers mirror KV (2 K + 2 V), then
# conv0, ssm0, conv1, ssm1 -- PINNED order: K*, V*, state tensors
# flattened in slab order.
self.assertEqual(mirror.num_k_tensors, 2)
self.assertEqual(len(mirror.tensor_pairs), 8)
self.assertEqual(len(pool.state_slabs), 2)
for n, (conv, ssm) in enumerate(pool.state_slabs):
self.assertIs(mirror.tensor_pairs[4 + 2 * n][0], conv)
self.assertIs(mirror.tensor_pairs[4 + 2 * n + 1][0], ssm)
# Per-pair row spans: page_size token rows for KV, 1 page row for
# state (state slabs are page-indexed).
self.assertEqual(mirror.row_spans, (4,) * 4 + (1,) * 4)
for (dev, host), span in zip(mirror.tensor_pairs, mirror.row_spans):
if span == 1:
self.assertEqual(host.shape, (8, *dev.shape[1:]))
else:
self.assertEqual(host.shape, (8 * 4, *dev.shape[1:]))
def test_bytes_per_host_page_includes_state_rows(self):
# Without state shapes the flat GDN predicate is off: all 4 layers
# keep KV -> 8 mirrors x page_size 4 x 16 B rows = 512 B.
base = self.flat_bytes_per_host_page(self._pool(with_state=False))
self.assertEqual(base, 512)
# Flat GDN: state layers carry no KV -> 4 KV mirrors (256 B) plus
# 2 state layers x (conv 2*4 + ssm 2*8) bf16 page rows (2 x 48 B).
pool = self._pool()
with_state = self.flat_bytes_per_host_page(pool)
self.assertEqual(with_state, 4 * 4 * 16 + 96)
mirror = self.FlatHostMirror(pool, num_host_pages=2)
self.assertEqual(mirror.bytes_per_host_page(), with_state)
def test_state_roundtrip(self):
torch = self.torch
pool = self._pool()
mirror = self.FlatHostMirror(pool, num_host_pages=8)
pairs = [(1, 5), (2, 6), (3, 7)]
device_pages = [d for d, _ in pairs]
self._fill_device_pages(mirror, device_pages)
before = self._snapshot(mirror, device_pages)
stream = torch.cuda.Stream()
mirror.store_pages(pairs, stream)
stream.synchronize()
for (dev, _), span in zip(mirror.tensor_pairs, mirror.row_spans):
for d in device_pages:
dev[d * span : (d + 1) * span].zero_()
torch.cuda.synchronize()
events = mirror.load_pages_with_events(pairs, stream)
self.assertEqual(len(events), len(mirror.tensor_pairs))
stream.synchronize()
self.assertTrue(all(event.query() for event in events))
after = self._snapshot(mirror, device_pages)
for tensor_idx in range(len(mirror.tensor_pairs)):
for d in device_pages:
self.assertTrue(
torch.equal(
before[tensor_idx][d].view(torch.uint8),
after[tensor_idx][d].view(torch.uint8),
),
f"tensor {tensor_idx} device page {d} not byte-exact",
)
def test_state_tensor_indices_of_layer(self):
pool = self._pool()
mirror = self.FlatHostMirror(pool, num_host_pages=2)
# State layers 0/2 bind slab pairs 0/1 -> flattened indices after
# the 4 KV mirrors; conv immediately precedes its ssm.
self.assertEqual(mirror.state_tensor_indices_of_layer(0), (4, 5))
self.assertEqual(mirror.state_tensor_indices_of_layer(2), (6, 7))
self.assertIsNone(mirror.state_tensor_indices_of_layer(1))
self.assertIsNone(mirror.state_tensor_indices_of_layer(3))
# Pools without state slabs expose no state indices for any layer.
kv_only = self.FlatHostMirror(self._pool(with_state=False), num_host_pages=2)
for layer_id in range(4):
self.assertIsNone(kv_only.state_tensor_indices_of_layer(layer_id))
class FlatHostMirrorNoneKVTest(unittest.TestCase):
"""Flat GDN pools carry None k/v slots on state layers (M18a T4): the
mirror's identity-dedup walks must skip them and mirror only the real
slabs. CPU stub pool, no CUDA, no scheduler ext -- state mirroring via
get_state_buffers is a separate surface and unaffected."""
def setUp(self):
try:
import torch
from tokenspeed.runtime.cache.flat_host_mirror import (
FlatHostMirror,
flat_bytes_per_host_page,
)
except (ImportError, ModuleNotFoundError) as exc:
self.skipTest(f"needs torch: {exc}")
self.torch = torch
self.FlatHostMirror = FlatHostMirror
self.flat_bytes_per_host_page = flat_bytes_per_host_page
def _stub_pool(self):
import types
torch = self.torch
rows = 8
kv = [torch.zeros((rows, 1, 8), dtype=torch.bfloat16) for _ in range(4)]
return types.SimpleNamespace(
page_size=4,
k_buffer=[None, kv[0], None, kv[1]],
v_buffer=[None, kv[2], None, kv[3]],
)
def test_mirror_skips_none_kv_entries(self):
stub = self._stub_pool()
# 4 real mirrors x page_size 4 x 16 B rows = 256 B per host page.
self.assertEqual(self.flat_bytes_per_host_page(stub), 256)
mirror = self.FlatHostMirror(stub, num_host_pages=2)
self.assertEqual(mirror.num_k_tensors, 2)
self.assertEqual(len(mirror.tensor_pairs), 4)
self.assertIs(mirror.tensor_pairs[0][0], stub.k_buffer[1])
self.assertIs(mirror.tensor_pairs[1][0], stub.k_buffer[3])
# KV layers keep their tensor-index mapping; state layers have no
# KV mirror and must fail loud if D2 fencing ever asks for one.
self.assertEqual(mirror.tensor_index_of_layer(1), 0)
self.assertEqual(mirror.tensor_index_of_layer(3), 1)
with self.assertRaisesRegex(ValueError, r"state layer"):
mirror.tensor_index_of_layer(0)
if __name__ == "__main__":
unittest.main()