Fix paused SIM_STEP resume sequencing
This commit is contained in:
@@ -57,7 +57,7 @@
|
||||
},
|
||||
"published_browser_smoke": {
|
||||
"url": "https://49.232.250.35:58010/",
|
||||
"release": "20260902-linuxcnc-wasm-continuous-r10",
|
||||
"release": "20260902-linuxcnc-wasm-pause-resume-r11",
|
||||
"status": "verified",
|
||||
"startup_pause_resume_stop": "verified",
|
||||
"pause_tick": 140,
|
||||
@@ -73,15 +73,25 @@
|
||||
"screenshot_sha256": "c93fd23e648e49bfa9359af245372f03f3fccee123497909f3dcc005f5a59749",
|
||||
"browser_errors": 0
|
||||
},
|
||||
"pause_resume_runtime": {
|
||||
"before_pause": {"line": 62, "tick": 140, "queue_depth": 1, "velocity": 28.2842712475},
|
||||
"paused": {"line": 62, "tick": 145, "queue_depth": 1, "velocity": 28.2842712475},
|
||||
"paused_after_1_5s": {"tick": 145},
|
||||
"resumed": {"line": 62, "tick": 160, "queue_depth": 1, "velocity": 4.96408252063},
|
||||
"after_resume": {"line": 68, "tick": 360, "queue_depth": 2, "velocity": 32.829526006},
|
||||
"status": "verified",
|
||||
"browser_errors": 0,
|
||||
"screenshot_sha256": "9d1660fd043dd0628ff2989a3e139a3239acd6386d141657a5834c9d2f1bc5a7"
|
||||
},
|
||||
"screenshot_sha256": {
|
||||
"authority": "e58205228a04b386c7b7514bf03c71df7b53f66f2d9ebe2292931b36ef0edb55",
|
||||
"running": "7fc474d0cb31a0fdd4afb198061e9812c753684e3d2963cc004ec4483c5c4990",
|
||||
"switchkins": "920b85ad7fd6451dfb134255ffdcc4f03a7aa615ebf486c63cde8582e17af195"
|
||||
},
|
||||
"resource_sha256": {
|
||||
"index-Byst0JhC.js": "26d3f21f496c8223218761ba641dab8b4f36fd18892f260c7bf5b5cfa83cafec",
|
||||
"sim-worker-entry-BTVfbu6g.js": "adf2ac5621ba388408f31ceab4bbcbfa6ba2923577d8eb69aa79ea54f3be0134",
|
||||
"linuxcnc-sim-core-B2786u4k.wasm": "3163f5ff63c5f3e1d2c07d1d948fce328bf3ad919eee188e432f7ba57468fc71"
|
||||
"index-EXbw4yiL.js": "6759738df285bc5e2f5c3fb84043dc09fb82292bbc1c3c1011a558c8654c96ab",
|
||||
"sim-worker-entry-DjXIMZ0D.js": "190515af943d70e93037e88a5cf63b3b8e9cda675a8338cfc1fb4bb954bfd685",
|
||||
"linuxcnc-sim-core-D3Qw0e1g.wasm": "f1b1961279cf8ff7ef2e3fcd0068b3ba79de57abe1e56d5c32b16d17568b9536"
|
||||
},
|
||||
"authority_dom": {
|
||||
"data-axis-authority": "linuxcnc-wasm-worker",
|
||||
|
||||
@@ -172,6 +172,26 @@ bash -n run-5axis-rtcp.sh
|
||||
|
||||
本轮连续性修复后,`3D_Chips.ngc` 3000 tick 执行到第 337 行,`running_queue_gaps=0`;这证明长距离运行中的中间停顿已不再由 Worker 队列饥饿制造。
|
||||
|
||||
暂停/恢复修复:暂停期间若有一个 `SIM_STEP` 已在浏览器与 Worker 之间传输,WASM protocol 现在接受该帧为稳定无动作轮询,不会消耗错误序号;随后 `PROGRAM_RESUME` 正常恢复 source TP。
|
||||
|
||||
发布站点 r11 暂停/恢复验证:
|
||||
|
||||
```text
|
||||
url: https://49.232.250.35:58010/
|
||||
release: 20260902-linuxcnc-wasm-pause-resume-r11
|
||||
resource_sha256: index-EXbw4yiL.js 6759738df285bc5e2f5c3fb84043dc09fb82292bbc1c3c1011a558c8654c96ab
|
||||
sim-worker-entry-DjXIMZ0D.js 190515af943d70e93037e88a5cf63b3b8e9cda675a8338cfc1fb4bb954bfd685
|
||||
linuxcnc-sim-core-D3Qw0e1g.wasm f1b1961279cf8ff7ef2e3fcd0068b3ba79de57abe1e56d5c32b16d17568b9536
|
||||
before_pause: line=62, tick=140, queue_depth=1, velocity=28.2842712475
|
||||
paused: line=62, tick=145, queue_depth=1, velocity=28.2842712475
|
||||
paused_after_1.5s: tick=145 (stable)
|
||||
resumed: line=62, tick=160, queue_depth=1, velocity=4.96408252063
|
||||
after_resume: line=68, tick=360, queue_depth=2, velocity=32.8295260060
|
||||
PROGRAM_RESUME: acknowledged; browser_errors: 0
|
||||
screenshot: /tmp/published-pause-resume-final-r11c.png
|
||||
screenshot_sha256: 9d1660fd043dd0628ff2989a3e139a3239acd6386d141657a5834c9d2f1bc5a7
|
||||
```
|
||||
|
||||
发布站点 r10 连续性验证:
|
||||
|
||||
```text
|
||||
@@ -249,6 +269,7 @@ wasm_io_c_source 09bce1430d6f71702ca0b3bf29ac50db377a6f232ce0d1a9b2c1eaa
|
||||
panel_button_test_source 80782fc1f85f88beb48ec3dfaf638a93f2edb912e694840199dbff504477fe74
|
||||
switchkins_direct_test_output 24e6cb8ec1195a97f71294b49217db0cbc0d7c3ecfa4bc8aa244ba3921c816a7
|
||||
panel_r10_output 9bddcd8b0219925e00598e081dc7a4ed0f4868e8822a21f0ccd08d8e9d355d45
|
||||
pause_resume_browser_screenshot 9d1660fd043dd0628ff2989a3e139a3239acd6386d141657a5834c9d2f1bc5a7
|
||||
```
|
||||
|
||||
报告对应提交前工作树保留了既有 coverage 大文件和 LinuxCNC 子模块改动;本轮提交包含 WASM TP/IO/HOME authority、无 JS JOG 运动计算、前端 pending 投影、长程序快照性能修正、聚合测试和本报告。
|
||||
|
||||
@@ -49,6 +49,7 @@ static int state_accepts_kind(uint32_t current, const char *kind) {
|
||||
return is_kind(kind, "PROGRAM_RESUME") || is_kind(kind, "RESUME") ||
|
||||
is_kind(kind, "PROGRAM_ABORT") || is_kind(kind, "ESTOP") ||
|
||||
is_kind(kind, "POWER") || is_kind(kind, "SET_OVERRIDE") ||
|
||||
is_kind(kind, "SIM_STEP") ||
|
||||
is_kind(kind, "PING") || is_kind(kind, "SNAPSHOT_REQUEST") ||
|
||||
is_kind(kind, "DESTROY");
|
||||
}
|
||||
|
||||
@@ -14,16 +14,17 @@ int main(void) {
|
||||
assert(sim_protocol_accept(1, 4, "RESET", "reset-machine", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_last_seq() == 4);
|
||||
assert(sim_protocol_accept(1, 5, "PROGRAM_PAUSE", "op-4", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 6, "MDI_EXECUTE", "op-5", 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 6, "PROGRAM_ABORT", "op-5", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 6, "SIM_STEP", "op-5-step", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 7, "MDI_EXECUTE", "op-5", 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 7, "PROGRAM_ABORT", "op-5", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_state_value() == SIM_PROTOCOL_READY);
|
||||
assert(sim_protocol_accept(1, 7, "PROGRAM_PAUSE", "op-6", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 8, "PROGRAM_RESUME", "op-7", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(2, 9, "PING", NULL, 2) == SIM_PROTOCOL_ERR_SCHEMA);
|
||||
assert(sim_protocol_accept(1, 9, "PING", NULL, 1) == SIM_PROTOCOL_ERR_TICK);
|
||||
assert(sim_protocol_accept(1, 9, "DESTROY", NULL, 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 10, "PING", NULL, 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 11, "RESET", "reset-1", 0) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 8, "PROGRAM_PAUSE", "op-6", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 9, "PROGRAM_RESUME", "op-7", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(2, 10, "PING", NULL, 2) == SIM_PROTOCOL_ERR_SCHEMA);
|
||||
assert(sim_protocol_accept(1, 10, "PING", NULL, 1) == SIM_PROTOCOL_ERR_TICK);
|
||||
assert(sim_protocol_accept(1, 10, "DESTROY", NULL, 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 11, "PING", NULL, 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 12, "RESET", "reset-1", 0) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_state_value() == SIM_PROTOCOL_NEW);
|
||||
assert(sim_protocol_set_tick(4) == SIM_PROTOCOL_ERR_TICK);
|
||||
return 0;
|
||||
|
||||
@@ -1188,7 +1188,8 @@ export class SimSession {
|
||||
});
|
||||
}
|
||||
if (Number.isSafeInteger(input.simulation_tick) && input.simulation_tick >= this.tick) this.tick = input.simulation_tick;
|
||||
const eventTick = input.kind === "SIM_STEP" && Number.isSafeInteger(input.payload?.cycles)
|
||||
const pausedStep = input.kind === "SIM_STEP" && this.xyzacProgram && (this.task.state.state === "PAUSED" || this.xyzacProgram.snapshot().status === 3);
|
||||
const eventTick = input.kind === "SIM_STEP" && Number.isSafeInteger(input.payload?.cycles) && !pausedStep
|
||||
? this.tick + input.payload.cycles : this.tick;
|
||||
try {
|
||||
this.timeline.appendEvent(input.seq, eventTick, input.kind, input.payload ?? {});
|
||||
@@ -1535,6 +1536,26 @@ export class SimSession {
|
||||
const cycles = input.payload?.cycles;
|
||||
const limit = validateLimit("max_tick_step", cycles);
|
||||
if (limit.status !== "accepted") return finish(this.envelope("ERROR", input, { ...limit, operation_id: input.operation_id ?? null, simulation_tick: this.tick, retryable: false }), "failed");
|
||||
// A poll may already be in flight when PROGRAM_PAUSE reaches the
|
||||
// worker. LinuxCNC keeps the paused task/TP state stable; accept that
|
||||
// transport frame as a no-op instead of rejecting it at the protocol
|
||||
// layer and leaving the next PROGRAM_RESUME with a sequence gap.
|
||||
if (this.xyzacProgram && (this.task.state.state === "PAUSED" || this.xyzacProgram.snapshot().status === 3)) {
|
||||
const pausedProgram = this.xyzacProgram.snapshot();
|
||||
return finish(this.envelope("COMMAND_RESULT", input, {
|
||||
status: "verified",
|
||||
cycles,
|
||||
program_steps: [],
|
||||
execution_trace: [],
|
||||
snapshot_mode: input.payload?.response === "motion_delta" ? "motion_delta" : "full",
|
||||
program: pausedProgram,
|
||||
task: this.task.export(),
|
||||
wasm_motion: this.wasmMotion.read(),
|
||||
motion: this.wasmMotionProjection(),
|
||||
motion_authority: "wasm",
|
||||
operation_id: input.operation_id ?? null,
|
||||
}), "verified");
|
||||
}
|
||||
let program_steps = [];
|
||||
const motion_trace = [];
|
||||
let sourceLookaheadReady = false;
|
||||
|
||||
@@ -30,6 +30,9 @@ const cursorPaused = paused.payload.program.current_line;
|
||||
const pausedSnapshot = send("SNAPSHOT_REQUEST", "paused-snapshot");
|
||||
assert.equal(pausedSnapshot.payload.task.state, "PAUSED");
|
||||
assert.equal(pausedSnapshot.payload.panel_snapshot.program.current_line, cursorPaused);
|
||||
const pausedPoll = send("SIM_STEP", "paused-poll", { cycles: 5, response: "motion_delta" });
|
||||
assert.equal(pausedPoll.payload.task.state, "PAUSED");
|
||||
assert.equal(pausedPoll.payload.program.program_status, "paused");
|
||||
const resumed = send("PROGRAM_RESUME", "resume");
|
||||
assert.equal(resumed.payload.task.state, "RUNNING");
|
||||
const second = send("SIM_STEP", "step-2", { cycles: 1 });
|
||||
|
||||
Reference in New Issue
Block a user