
把缓存从HBM移到主机内存,再按需换回,是一个容易讲清楚、很容易把模拟写错的题目。常见错误是用len(active)分配新页:释放中间页以后,字典长度可能恰好等于仍在使用的页号,下一次分配就发生碰撞。
先解决所有权,再讨论性能。每个活动页号只能属于一个对象;空闲页和活动页互不相交;容量耗尽就明确失败。一个连页号都可能重复的模拟器,不能拿来推导显存节省比例。
显式维护空闲页
下例只模拟固定页分配,不执行GPU复制。活动对象映射到页号,释放时把页号归还到堆中;对同一对象重复分配返回原页,不会泄漏容量。

图中四个槽位表示独立示意:B、C占用1、2,D取得此前空闲的0。图叠加了分配前后的转移过程;分配完成后0必须从空闲表移除。下面代码另用三页容量、释放中间页1来测试碰撞反例。
封面是旧持有者释放以后向新持有者移交页号的顺序示意,底下进程标签不表示移交后的同步快照;真实活动集合与空闲集合必须始终互斥。
import heapq
class Pages:
def __init__(self, capacity):
self.free = list(range(capacity))
heapq.heapify(self.free)
self.active = {}
self.capacity = capacity
def acquire(self, key):
if key in self.active:
return self.active[key]
if not self.free:
raise MemoryError('no free page')
page = heapq.heappop(self.free)
self.active[key] = page
self.check()
return page
def release(self, key):
if key not in self.active:
raise KeyError(key)
heapq.heappush(self.free, self.active.pop(key))
self.check()
def check(self):
owned = list(self.active.values())
assert len(owned) == len(set(owned))
assert set(owned).isdisjoint(self.free)
assert set(owned) | set(self.free) == set(range(self.capacity))
pages = Pages(3)
assert [pages.acquire(k) for k in 'ABC'] == [0, 1, 2]
pages.release('B')
assert pages.acquire('D') == 1 and pages.active['C'] == 2
assert pages.acquire('D') == 1
try:
pages.acquire('E')
except MemoryError:
pass
else:
raise AssertionError('over-allocation accepted')
print('middle-page reuse, unique ownership, capacity: PASS')
从页号正确到换入正确,还差什么
真实换入需要异步拷贝完成事件、引用计数、正在生成的请求与驱逐之间的协调。地址已分配不等于数据已可读,CPU副本存在也不等于可以提前复用HBM页。错误往往发生在这两组状态被合并以后。
llm-d分层前缀缓存指南讨论从HBM卸载到CPU内存,并可进一步使用共享文件系统;这不是“任何CXL机器直接获得同样收益”的承诺。Mooncake在10月加入新的连接能力,后端可接入性和具体工作负载上的效果仍需分别测试。
本地只验证页号管理,没有GPU、HBM、CXL设备或DMA计时。这里不提供节省百分比。下一步应先增加拷贝中、可读、被引用三个状态及其非法转移测试,再在固定模型、序列长度与并发下测实际吞吐。
本文探讨HBM分层缓存模拟中页号回收的关键问题,指出仅依赖字典长度判断空闲页会导致页号重复分配错误。强调显式维护空闲页集合、保障页号唯一所有权、活动页与空闲页互斥等核心原则,并指出从页号正确到换入正确还需建模异步拷贝、引用计数及状态协调等关键环节。

324

被折叠的 条评论
为什么被折叠?



