mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 13:52:19 +00:00
Let the flights' fix history fill before the long soak measures the heap, and say why a context-loss case drew no frame
The long soak's heap slope counted the per-aircraft dead-reckoning history (POSITION_HISTORY_LIMIT fixes for 10 000 aircraft, about 14 MiB over the first 2.5 min of polls) as switch growth: a run with the same workload and no switches grows as much and then levels off. With --assert the soak now waits until the flights feed has been read more times than the history keeps before it switches; over 500 switches the heap then grows 1.07 KiB per switch. qa-strict-context-loss records, only when no non-blank frame came, how many frames the running and the watched engine drew in 3 s and how much of the last one differs from its first pixel.
This commit is contained in:
1 parent
f89aee1eac
commit
1100cdcff5
2 files changed
+63
-1
No files matched your search
@@ -164,6 +164,51 @@ await strict.run({ args: ['--use-angle=metal', '--enable-gpu'] }, async (b) => {
|
|||||||
const outcome = after.engine === to ? 'switched' : 'rolled back';
|
const outcome = after.engine === to ? 'switched' : 'rolled back';
|
||||||
if (after.running) await rememberEngine(p);
|
if (after.running) await rememberEngine(p);
|
||||||
const drawn = after.running ? await draws(after.engine) : false;
|
const drawn = after.running ? await draws(after.engine) : false;
|
||||||
|
// Why no frame passed, when none did: frames drawn in 3 s by the engine
|
||||||
|
// the page runs and by the one the probe watched, and how many of 48x48
|
||||||
|
// samples of the last frame differ from the first one.
|
||||||
|
const noFrame =
|
||||||
|
after.running && !drawn
|
||||||
|
? await p.evaluate(async (kind) => {
|
||||||
|
const running = window.__godsEyeView.engine;
|
||||||
|
const watched = window.__qaEngines.get(kind);
|
||||||
|
const probe = document.createElement('canvas');
|
||||||
|
probe.width = probe.height = 48;
|
||||||
|
const context = probe.getContext('2d', {
|
||||||
|
willReadFrequently: true,
|
||||||
|
});
|
||||||
|
const count = { running: 0, watched: 0, differing: null };
|
||||||
|
const offs = [
|
||||||
|
running.frames.postRender.addEventListener(() => {
|
||||||
|
count.running++;
|
||||||
|
context.drawImage(running.host.canvas, 0, 0, 48, 48);
|
||||||
|
const d = context.getImageData(0, 0, 48, 48).data;
|
||||||
|
let differing = 0;
|
||||||
|
for (let i = 4; i < d.length; i += 4)
|
||||||
|
if (
|
||||||
|
Math.abs(d[i] - d[0]) +
|
||||||
|
Math.abs(d[i + 1] - d[1]) +
|
||||||
|
Math.abs(d[i + 2] - d[2]) >
|
||||||
|
24
|
||||||
|
)
|
||||||
|
differing++;
|
||||||
|
count.differing = differing;
|
||||||
|
}),
|
||||||
|
watched === running
|
||||||
|
? () => {}
|
||||||
|
: watched?.frames.postRender.addEventListener(
|
||||||
|
() => count.watched++,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
|
offs.forEach((off) => off?.());
|
||||||
|
return {
|
||||||
|
...count,
|
||||||
|
sameEngine: watched === running,
|
||||||
|
connected: running.host.canvas.isConnected,
|
||||||
|
};
|
||||||
|
}, after.engine)
|
||||||
|
: null;
|
||||||
console.log(
|
console.log(
|
||||||
'after',
|
'after',
|
||||||
label,
|
label,
|
||||||
@@ -205,6 +250,7 @@ await strict.run({ args: ['--use-angle=metal', '--enable-gpu'] }, async (b) => {
|
|||||||
sessionIntact: intact(after),
|
sessionIntact: intact(after),
|
||||||
history: after.history - before.history,
|
history: after.history - before.history,
|
||||||
drawn,
|
drawn,
|
||||||
|
...(noFrame ? { noFrame } : {}),
|
||||||
back,
|
back,
|
||||||
backEngine: backState?.engine ?? null,
|
backEngine: backState?.engine ?? null,
|
||||||
backSessionIntact: backState ? intact(backState) : false,
|
backSessionIntact: backState ? intact(backState) : false,
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
//
|
//
|
||||||
// Checked on every switch: the same session (manager and every layer
|
// Checked on every switch: the same session (manager and every layer
|
||||||
// model), the radio still playing the same station with one play() call.
|
// model), the radio still playing the same station with one play() call.
|
||||||
// With --assert (the long run), after the warm-up (switch 20): live WebGL
|
// With --assert (the long run), the flights' fix history fills first (see
|
||||||
|
// below), then after the warm-up (switch 20): live WebGL
|
||||||
// objects per engine context grow by at most 0.1 per switch (least-squares
|
// objects per engine context grow by at most 0.1 per switch (least-squares
|
||||||
// slope over the checkpoints) and by at most 64 overall; no new WebGL
|
// slope over the checkpoints) and by at most 64 overall; no new WebGL
|
||||||
// context; JS heap slope at most 10 KiB per switch; no new document; the
|
// context; JS heap slope at most 10 KiB per switch; no new document; the
|
||||||
@@ -42,6 +43,7 @@ import {
|
|||||||
} from './qa-strict-session.mjs';
|
} from './qa-strict-session.mjs';
|
||||||
import { installRadioFixture, stations } from './fixtures/w2/radio.mjs';
|
import { installRadioFixture, stations } from './fixtures/w2/radio.mjs';
|
||||||
import { trafficFixtureResponse } from './traffic-fixtures.mjs';
|
import { trafficFixtureResponse } from './traffic-fixtures.mjs';
|
||||||
|
import { POSITION_HISTORY_LIMIT } from '../src/layers/flights/recordPolicy.js';
|
||||||
|
|
||||||
const base = localPreview(process.argv[2]);
|
const base = localPreview(process.argv[2]);
|
||||||
const option = (name, fallback) => {
|
const option = (name, fallback) => {
|
||||||
@@ -193,6 +195,20 @@ for (let run = 1; run <= runs; run++) {
|
|||||||
window.__godsEyeView.dataManager.layers.get('radio').module.getUIState()
|
window.__godsEyeView.dataManager.layers.get('radio').module.getUIState()
|
||||||
.audioState === 'playing',
|
.audioState === 'playing',
|
||||||
);
|
);
|
||||||
|
// Each aircraft keeps its last POSITION_HISTORY_LIMIT fixes for dead
|
||||||
|
// reckoning, so the first polls of the flights feed grow the heap by
|
||||||
|
// itself (about 14 MiB here, over 2.5 min; a run without switches then
|
||||||
|
// levels off). The long run lets that history fill before it switches,
|
||||||
|
// so the heap slope it asserts is the switches' own.
|
||||||
|
if (strictMode) {
|
||||||
|
const filling = Date.now();
|
||||||
|
await p.waitForFunction(
|
||||||
|
(polls) => window.__qaReads.flights > polls,
|
||||||
|
{ timeout: 300000, polling: 1000 },
|
||||||
|
POSITION_HISTORY_LIMIT,
|
||||||
|
);
|
||||||
|
row.historyFillSeconds = Math.round((Date.now() - filling) / 1000);
|
||||||
|
}
|
||||||
row.workload = await p.evaluate(() => {
|
row.workload = await p.evaluate(() => {
|
||||||
const layers = window.__godsEyeView.dataManager.layers;
|
const layers = window.__godsEyeView.dataManager.layers;
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
|
|||||||
Reference in new issue
Block a user