15 / 24 · 实验
实验:检查 1024 种停顿模式
用全部十周期 ready 模式测试保持、替换和置空。
课时内容可免费阅读,选课后可保存学习进度。
在停顿下保持数值与顺序
手动创建 elastic-model.mjs,保存以下代码,运行 node elastic-model.mjs。源端提供四个有序数据项,只在被接收时推进。模式的位零控制时钟沿 0,位一控制时钟沿 1,依此类推。穷举全部 1024 种十位 ready 模式,再让接收端持续 ready,排空尚未完成的工作。
先从旧槽交付,再决定替换。空槽即使面对停顿的接收端,也能接收一个数据项。已满且停顿的槽不能让源端推进。如果每个时钟沿都递增 next,就会丢弃未接收的数据项,即使缓冲正确,测试源端仍然错误。
import assert from 'node:assert/strict';
const values = [0, 9, 255, 12];
let deliveries = 0;
for (let pattern = 0; pattern < 1024; pattern++) {
let slot = null, next = 0;
const seen = [];
for (let edge = 0; edge < 20; edge++) {
const ready = edge >= 10 || ((pattern >>> edge) & 1) === 1;
const old = slot;
const inReady = old === null || ready;
if (old !== null && ready) seen.push(old);
if (inReady) {
slot = next < values.length ? { tag: next, y: values[next] } : null;
if (slot !== null) next++;
} else {
assert.deepEqual(slot, old);
}
assert.equal(next - seen.length, Number(slot !== null));
}
assert.deepEqual(seen, values.map((y, tag) => ({ tag, y })));
assert.equal(slot, null);
deliveries += seen.length;
}
console.log(`ELASTIC PASS: 1024 patterns, ${deliveries} deliveries`);模式为零时,接收端在前十个时钟沿停顿。Tag0,y0 在时钟沿 0 进入空槽,并保持到时钟沿 9。时钟沿 10 交付它,同时存储 tag1,y9。标签 1、2、3 随后分别在时钟沿 11、12、13 传送。不能把有效零误认为 null。成功运行会报告 1024 种模式和 4096 次交付。
每个时钟沿之后,接收数减交付数等于当前占用量。相比最终输出比较,这种局部计数能更早缩小故障范围。保持检查覆盖载荷保存,但比较实际实现时,需要观察其真实输出,而不只是模型中未变化的变量。穷举十周期模式属于有界测试,并不能证明任意停顿长度都正确。最终完成还假定接收端最终会 ready;无限背压要求保持数据,而不能保证交付。
自己试试
模式为零时,源端 next 在时钟沿 0 到 9 期间推进了多少?时钟沿 10 之后,占用量和 next-seen.length 分别是多少?
阅读解释
只有时钟沿 0 的数据项被接收,因此 next=1。时钟沿 10 时,tag0 传送,tag1 进入:next=2、seen.length=1,二者之差和槽占用量都为一。