优化原生结果编码传输与浏览器缓存,记录八路性能基线

原生结果series通过字节索引直传,C端使用Ryu精确回读编码和64 KiB批量写出;网页采用Float64缓存和CSV工作线程,减少结果处理与保存等待。

补充八路AME曲线核查、全流程分阶段计时、独立编码基准和复现工具,固定后续优化采用修正八路及rtol=1e-8。C写出1.1808→0.1638 s,点击到可查看8.0100→6.9756 s。

验证:最终10项编码专项、29项相关后端回归通过;8份原生结果逐位一致,16次网页结果/CSV/刷新恢复通过。前端构建及缓存/CSV专项在本轮结果处理工作中通过。环境、原始大结果与临时构建不纳入Git。
This commit is contained in:
lujingze committed 2026-09-11 15:09:15 +00:00
1 parent 808c484f5b
commit 3bc4be3c06
55 files changed
+20522 -141

No files matched your search

@@ -0,0 +1,179 @@
import { expect, test, type Page } from "@playwright/test";
import { resultSnapshot, prepareApp } from "./fixtures";
async function probePage(page: Page) {
await prepareApp(page);
await page.route("**/result-persistence-probe", route => route.fulfill({ contentType: "text/html", body: "<title>Persistence probe</title>" }));
await page.goto("/result-persistence-probe");
}
test("eight-branch shaped results save atomically with few writes and restore every number", async ({ page }) => {
await probePage(page);
const saved = await page.evaluate(async template => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
const series: Record<string, number[]> = { emptyFirst: [] };
for (let column = 0; column < 1785; column++) {
series[column === 0 ? "time" : `output.${column}`] = Array.from({ length: 1002 }, (_, row) => column * 100000 + row + 0.125);
}
series.emptyLast = [];
series["output.17"][31] = -0;
const snapshot = { ...template, result: { ...template.result, series } };
const originalTransaction = IDBDatabase.prototype.transaction;
const originalPut = IDBObjectStore.prototype.put;
let writes = 0;
let transactions = 0;
let pointerBeforeCommit: string | null | undefined;
let pointerAtCommit: string | null | undefined;
IDBDatabase.prototype.transaction = function (...args: Parameters<typeof originalTransaction>) {
const transaction = originalTransaction.apply(this, args);
if (this.name === "system-simulation-results" && transaction.mode === "readwrite") {
transactions++;
pointerBeforeCommit = sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY);
transaction.addEventListener("complete", () => { pointerAtCommit = sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY); });
}
return transaction;
};
IDBObjectStore.prototype.put = function (...args: Parameters<typeof originalPut>) {
writes++;
return originalPut.apply(this, args);
};
const start = performance.now();
await api.storeResultSnapshot(snapshot);
const saveMs = performance.now() - start;
IDBDatabase.prototype.transaction = originalTransaction;
IDBObjectStore.prototype.put = originalPut;
const readStart = performance.now();
const restored = await api.loadStoredResultSnapshot();
return { writes, transactions, saveMs, readMs: performance.now() - readStart,
pointerBeforeCommit, pointerAtCommit, hasPointer: Boolean(sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY)),
pending: api.resultSavePending(),
exact: Object.entries(series).every(([key, values]) => values.length === restored.result.series[key].length && values.every((value, i) => Object.is(value, restored.result.series[key][i]))) };
}, resultSnapshot);
expect(saved).toMatchObject({ transactions: 1, pointerBeforeCommit: null, pointerAtCommit: null, hasPointer: true, pending: false, exact: true });
// Thousands of short output columns must not cause thousands of writes or
// one transaction per small batch; the workload bound is independent of packing size.
expect(saved.writes).toBeLessThan(16);
console.log(JSON.stringify({ probe: "eight-branch-packed-persistence", ...saved }));
await page.reload();
const restored = await page.evaluate(async () => {
// @ts-expect-error browser-side Vite module
const { loadStoredResultSnapshot } = await import("/src/resultPersistence.ts");
const snapshot = await loadStoredResultSnapshot();
return { columns: Object.keys(snapshot.result.series).length, last: snapshot.result.series["output.1784"][1001], empty: snapshot.result.series.emptyFirst };
});
expect(restored).toEqual({ columns: 1787, last: 178401001.125, empty: [] });
});
test("legacy session snapshots and old column chunks remain readable; gaps and overlaps fail", async ({ page }) => {
await probePage(page);
const result = await page.evaluate(async template => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
sessionStorage.setItem(api.RESULT_SNAPSHOT_KEY, JSON.stringify(template));
const sessionLegacy = (await api.loadStoredResultSnapshot()).id === template.id;
// Create legacy records independently of the new writer and its format.
const db = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open("system-simulation-results", 1);
request.onupgradeneeded = () => { request.result.createObjectStore("headers"); request.result.createObjectStore("chunks"); };
request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error);
});
async function legacy(chunks: [number, number[]][]) {
await new Promise<void>((resolve, reject) => {
const tx = db.transaction(["headers", "chunks"], "readwrite");
tx.oncomplete = () => resolve(); tx.onabort = () => reject(tx.error);
tx.objectStore("headers").put({ snapshot: { ...template, result: { ...template.result, series: {} } }, lengths: { time: 6, empty: 0 } }, "legacy");
tx.objectStore("chunks").clear();
for (const [offset, values] of chunks) tx.objectStore("chunks").put(new Float64Array(values), ["legacy", "time", offset]);
});
sessionStorage.setItem(api.RESULT_SNAPSHOT_KEY, JSON.stringify({ storage: "indexeddb", version: 1, cacheId: "legacy" }));
try { return { values: (await api.loadStoredResultSnapshot()).result.series.time, rejected: false }; }
catch { return { rejected: true }; }
}
const complete = await legacy([[0, [1, 2, 3]], [3, [4, 5, 6]]]);
const gap = await legacy([[0, [1, 2]], [3, [4, 5, 6]]]);
const overlap = await legacy([[0, [1, 2, 3, 4]], [2, [3, 4]]]);
db.close();
return { sessionLegacy, complete, gap, overlap };
}, resultSnapshot);
expect(result).toEqual({ sessionLegacy: true, complete: { values: [1, 2, 3, 4, 5, 6], rejected: false }, gap: { rejected: true }, overlap: { rejected: true } });
});
test("in-flight superseded commits and failed writes cannot replace the latest complete pointer", async ({ page }) => {
await probePage(page);
const result = await page.evaluate(async template => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
await api.storeResultSnapshot(template);
const stablePointer = sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY);
const originalPut = IDBObjectStore.prototype.put;
let puts = 0;
IDBObjectStore.prototype.put = function (...args: Parameters<typeof originalPut>) {
if (++puts === 2) throw new DOMException("Injected header failure after data write", "QuotaExceededError");
return originalPut.apply(this, args);
};
let failed = false;
try { await api.storeResultSnapshot({ ...template, id: "failed" }); } catch { failed = true; }
IDBObjectStore.prototype.put = originalPut;
const preserved = sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY) === stablePointer;
const originalTransaction = IDBDatabase.prototype.transaction;
let latest: Promise<boolean> | undefined;
let armed = true;
IDBDatabase.prototype.transaction = function (...args: Parameters<typeof originalTransaction>) {
const transaction = originalTransaction.apply(this, args);
if (armed && this.name === "system-simulation-results" && transaction.mode === "readwrite") {
armed = false;
// Replace an older save after its transaction starts but before commit.
queueMicrotask(() => { latest = api.storeResultSnapshot({ ...template, id: "newest" }); });
}
return transaction;
};
const old = await api.storeResultSnapshot({ ...template, id: "older" });
const newer = await latest;
IDBDatabase.prototype.transaction = originalTransaction;
const restored = await api.loadStoredResultSnapshot();
return { failed, preserved, old, newer, id: restored.id, pending: api.resultSavePending() };
}, resultSnapshot);
expect(result).toEqual({ failed: true, preserved: true, old: false, newer: true, id: "newest", pending: false });
});
test("saving in another page preserves its borrowed cache and corrupt packed records are rejected", async ({ page, context }) => {
await probePage(page);
const pointer = await page.evaluate(async template => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
await api.storeResultSnapshot(template);
return sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY)!;
}, resultSnapshot);
const other = await context.newPage();
await probePage(other);
await other.evaluate(async ({ template, pointer }) => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
sessionStorage.setItem(api.RESULT_SNAPSHOT_KEY, pointer);
await api.loadStoredResultSnapshot();
await api.storeResultSnapshot({ ...template, id: "other-page" });
}, { template: resultSnapshot, pointer });
const outcome = await page.evaluate(async () => {
// @ts-expect-error browser-side Vite module
const api = await import("/src/resultPersistence.ts");
const before = await api.loadStoredResultSnapshot();
const marker = JSON.parse(sessionStorage.getItem(api.RESULT_SNAPSHOT_KEY)!);
const db = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open("system-simulation-results", 1);
request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error);
});
await new Promise<void>((resolve, reject) => {
const tx = db.transaction("chunks", "readwrite");
tx.oncomplete = () => resolve(); tx.onabort = () => reject(tx.error);
const cursor = tx.objectStore("chunks").openCursor(IDBKeyRange.bound([marker.cacheId], [marker.cacheId, []]));
cursor.onsuccess = () => { const entry = cursor.result; if (entry) entry.update({ ...entry.value, offset: 1 }); };
});
db.close();
let rejected = false;
try { await api.loadStoredResultSnapshot(); } catch { rejected = true; }
return { originalId: before.id, rejected };
});
expect(outcome).toEqual({ originalId: resultSnapshot.id, rejected: true });
await other.close();
});