AI芯片动态形状为何总掉速?内存池怎么稳?
扫描二维码
随时随地手机看文章
同一模型换个序列长度、分辨率或专家路由比例,延迟就抖,这类问题往往不是算子突然退化,而是运行时没能把变化中的形状稳稳接住。AI芯片一旦从静态基准走进动态业务,调度和内存池会比峰值算力更早暴露短板。
动态形状的第一层难点,是最优执行计划本身会随输入改变。某个序列长度下最合适的 tile、并行度和 workspace 大小,换到另一个长度后可能完全不是同一组答案。若系统仍硬套静态编译时的最佳计划,就会出现有的输入把阵列切得太碎,有的输入又把局部缓存挤得太满,平均性能看起来就像被随机拉扯。
很多运行时尝试为常见形状缓存多份计划,这是必要的,但不够。真实业务里的形状分布往往长尾明显,请求不会永远只落在那几档典型值。每遇到一个偏离缓存的形状,系统就可能触发新的调度决策、workspace 申请甚至重新编译或重排,这些额外动作在低频场景可忽略,一到高并发就会堆成明显抖动。
内存池碎片化则是另一条更隐蔽的掉速路径。不同形状的激活、KV 缓存和临时 buffer 大小各异,生命周期又交错重叠,长期运行后池中会留下许多大小不一的空洞。表面上总空闲容量还不少,可真正需要的一块连续区却拿不出来,只能触发更远层次的回退分配、额外拷贝或保守的串行调度。
对AI芯片运行时来说,碎片问题不只是容量浪费,还会直接改写带宽和时序。某些 buffer 若因连续空间不足被拆成多段,后续 DMA 和地址生成都更复杂;某些算子为了迁就可用内存,只能选择更保守的 tile 或更低并发。于是掉速并不是突然没内存,而是为了躲碎片,系统一步步放弃了原本能跑得更快的执行方式。
稳住动态形状通常需要两层折中。一层是用 padding、bucketing 或形状分桶,把过于离散的输入拉回有限几类,让编译计划和内存复用更稳定;另一层是让内存池按生命周期和大小分区,减少大块和小块互相污染。前者会牺牲一部分额外计算,后者会牺牲部分池利用率,但两者都比频繁重分配和碎片扩散可控得多。
排查这类问题时,单看平均延迟很难抓住根因。要把不同形状下的计划命中率、workspace 回退次数、连续块申请失败率和内存池碎片分布一起记录,才能分清是调度缓存不够,还是池化策略已经把自己耗散掉了。
多模型混部会把问题再放大。不同模型的形状波动、workspace 峰值和生命周期彼此交错,若共用一套过于简单的内存池,单模型下还算平稳的策略到了混部时就会迅速碎掉。把池化策略按模型族或大小层级做隔离,通常比单纯扩大池容量更有效,也更稳,回收滞后时更明显些。
所以,动态形状掉速,往往不是模型天然不稳定,而是计划缓存和内存池没有围着形状分布设计。把形状分桶和分配策略一起稳住,吞吐与时延不会一忙起来就乱。





