fix(motor): 清掉存量 4ms PDO 周期缓存, 测试对齐 pcore_mask

- transport-ecat: localStorage 的 dcu_ecat_period_ms 是 Python 时代默认
  4ms 存进去的(browser_check_period.mjs 收尾也写 "4"), native 后端默认
  已改小, 存量 "4" 会在每次 ensureStarted 把总线压回旧默认。加一次性
  迁移标记 dcu_ecat_period_mig, 只删一次; 之后显式设 4 视为用户选择。
  "恢复默认"从 setPdoPeriod(4) 改为删键跟随后端默认(固件修好前别低于
  1ms)。
- test_motor_transport: 自旋钉核显示早已改用快照字段 pcore_mask(P 核),
  测试还停在 ecore_mask 旧字段旧措辞, 本次对齐(含跨 32 位掩码、不连续
  核号区间用例)。

验证: node scripts/test_motor_transport.mjs 66/66 通过。
This commit is contained in:
cbb
2026-09-05 19:58:45 +08:00
parent 9cbde690c6
commit 12879aa81a
2 changed files with 34 additions and 20 deletions
+18 -18
View File
@@ -354,40 +354,40 @@ section("[8] 快照→契约翻译(构造快照,跑生产代码)");
parts.some((p) => p.includes("自旋") && p.includes("1 核")),
JSON.stringify(parts));
/* (i3b) 钉到 E 核时要写出核号 —— 用户看到"占 1 核"会担心抢了性能核,
* 显示实际落在哪些逻辑处理器才能证明它是能效核。掩码是 64 位,
/* (i3b) 钉到 P 核时要写出核号 —— 自旋吃满一个核是用户能感知的代价,
* 列出实际落在哪些逻辑处理器,用户才知道占的是不是性能核。掩码是 64 位,
* JS 移位只有 32 位,所以高低两段分别取,这里专门覆盖跨 32 位的情况。 */
snap = mkSnap([stale], { period_ms: 1, slot_period_ms: 1, spin: true,
ecore_mask: 0xfff0000 });
pcore_mask: 0xfff0000 });
await tp.fetchMotorState();
parts = tp.describeStatus({ slave: { state: 8, name: "DCU Project" } });
check("(i3b) 钉到 E 核时列出核号区间(16-27,不逐个罗列挤掉从站名)",
parts.some((p) => p.includes("E 核 16-27")),
check("(i3b) 钉到 P 核时列出核号区间(16-27,不逐个罗列挤掉从站名)",
parts.some((p) => p.includes("P 核 16-27")),
JSON.stringify(parts));
check("(i3b) 已列出 E 核号时不再写笼统的『占 1 核』",
check("(i3b) 已列出 P 核号时不再写笼统的『占 1 核』",
!parts.some((p) => p.includes("占 1 核")), JSON.stringify(parts));
check("(i3b) debug() 暴露 ecores 列表便于现场核对",
tp.debug().ecores.length === 12 && tp.debug().ecores[0] === 16 &&
tp.debug().ecores[11] === 27,
JSON.stringify(tp.debug().ecores));
check("(i3b) debug() 暴露 pcores 列表便于现场核对",
tp.debug().pcores.length === 12 && tp.debug().pcores[0] === 16 &&
tp.debug().pcores[11] === 27,
JSON.stringify(tp.debug().pcores));
/* 高 32 位之外的核(>31)不能丢:用 2^40 验证跨段位 */
snap = mkSnap([stale], { period_ms: 1, slot_period_ms: 1, spin: true,
ecore_mask: 1 + 2 ** 40 });
pcore_mask: 1 + 2 ** 40 });
await tp.fetchMotorState();
check("(i3b) 掩码跨 32 位时高段核号不丢(0 与 40)",
JSON.stringify(tp.debug().ecores) === JSON.stringify([0, 40]),
JSON.stringify(tp.debug().ecores));
JSON.stringify(tp.debug().pcores) === JSON.stringify([0, 40]),
JSON.stringify(tp.debug().pcores));
/* 掩码为 0 = 探测失败/对称 CPU,要退回笼统措辞而不是显示空列表 */
snap = mkSnap([stale], { period_ms: 1, slot_period_ms: 1, spin: true,
ecore_mask: 0 });
pcore_mask: 0 });
await tp.fetchMotorState();
parts = tp.describeStatus({ slave: { state: 8, name: "DCU Project" } });
check("(i3b) 没钉核时退回『占 1 核』而不是列出空的 E 核",
parts.some((p) => p.includes("占 1 核") && !p.includes("E 核")),
check("(i3b) 没钉核时退回『占 1 核』而不是列出空的 P 核",
parts.some((p) => p.includes("占 1 核") && !p.includes("P 核")),
JSON.stringify(parts));
/* 不连续的核(混合架构常见:E 核未必连成一段)要压成多段而不是硬凑一个区间 */
/* 不连续的核(混合架构常见:P 核未必连成一段)要压成多段而不是硬凑一个区间 */
snap = mkSnap([stale], { period_ms: 1, slot_period_ms: 1, spin: true,
ecore_mask: (1 << 16) | (1 << 17) | (1 << 20) | (1 << 24) });
pcore_mask: (1 << 16) | (1 << 17) | (1 << 20) | (1 << 24) });
await tp.fetchMotorState();
parts = tp.describeStatus({ slave: { state: 8, name: "DCU Project" } });
check("(i3b) 不连续核压成 16-17,20,24(不硬凑区间)",