test: measure constrained character workloads
This commit is contained in:
parent
4b01a853fb
commit
8d7511cdbf
@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- **Constrained workload coverage.** Added a 4× CPU-throttled 500-character browser workload regression that
|
||||
records bounded DOM/audio/heap/image-cache metrics while preserving pagination.
|
||||
- **Bounded library image lifecycle.** Profile, concept-art, and voice-library images now use a viewport-aware
|
||||
browser cache with normal/low-memory limits and restoration URLs for evicted off-screen sources.
|
||||
- **Shared provider-health probes.** TTS, STT, and container connectivity checks now use one bounded helper with
|
||||
|
||||
3
TODO.md
3
TODO.md
@ -73,7 +73,8 @@ split, and full constrained-device workloads.
|
||||
a 4 GB VM/container, and measure browser, Docker and temporary-disk usage. Automated browser emulation proves
|
||||
the 4 GB shared-pool cap, and the current `1.23.3` image served successfully under a hard 4 GiB cgroup limit
|
||||
without OOM; desktop Chromium now has a 4× CPU-throttled navigation regression with DOM/audio/heap probes,
|
||||
while full workload resource measurements remain.
|
||||
and a 500-character 4× CPU-throttled workload regression with bounded image-cache, DOM, and audio measurements;
|
||||
rerunning the hard 4 GiB cgroup measurement for the current release image remains.
|
||||
- [x] **L — Add background jobs and bounded queues.** Image generation already has the full interactive job path,
|
||||
and transcription, voice design, and casting now have optional ID/status/cancel/timeout paths while preserving
|
||||
synchronous callers. Job metadata now persists in SQLite and marks interrupted work after restart; durable binary
|
||||
|
||||
@ -44,6 +44,7 @@ initBenchmarkSampleControls();
|
||||
loadSettings().then(() => {
|
||||
refreshSttBackends();
|
||||
renderIntegrationSnippets();
|
||||
if (!localStorage.getItem(SETTINGS_SEEN_KEY)) openSettings(true);
|
||||
// Do not let the first-run settings dialog's deferred navigation overwrite a
|
||||
// section the user opened while the loader was still finishing its startup.
|
||||
if (!localStorage.getItem(SETTINGS_SEEN_KEY) && !window._navRequestedSection) openSettings(true);
|
||||
}).catch(e => status('Settings load failed: ' + e.message));
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ test('large character productions keep the rendered DOM paginated', async ({ pag
|
||||
await page.waitForFunction(() => typeof window.libraryRenderCharacters === 'function', null, { timeout: 15_000 });
|
||||
await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 });
|
||||
await page.evaluate(() => window.navTo('s-library'));
|
||||
await page.locator('.lib-tab[data-library-view="characters"]').click();
|
||||
await page.locator('.lib-tab[data-library-view="characters"]').evaluate(el => el.click());
|
||||
await expect.poll(() => page.locator('#lib-chars-list .lib-char-card').count()).toBeLessThanOrEqual(50);
|
||||
await page.locator('#lib-chars-list .lib-chars-load-more').click();
|
||||
await expect.poll(() => page.locator('#lib-chars-list .lib-char-card').count()).toBeLessThanOrEqual(100);
|
||||
@ -64,6 +64,42 @@ test('desktop navigation remains usable under Chrome CPU throttling', async ({ p
|
||||
}
|
||||
});
|
||||
|
||||
test('large character workload stays bounded under CPU throttling', async ({ page }, testInfo) => {
|
||||
test.skip(testInfo.project.name !== 'desktop', 'Chromium CDP throttling is a desktop measurement');
|
||||
const characters = Array.from({ length: 500 }, (_, index) => ({
|
||||
id: 'workload-' + index, book: 'Bounded Workload', name: 'Workload Character ' + index,
|
||||
tags: '', voice: null, image: '/profile-' + index + '.png',
|
||||
sheet: { gender: index % 2 ? 'F' : 'M', physical: 'A character with a bounded test profile.' },
|
||||
}));
|
||||
await page.route('**/api/characters*', route => route.fulfill({ json: { characters } }));
|
||||
await page.route('**/api/voices*', route => route.fulfill({ json: [] }));
|
||||
await page.route('**/api/settings*', route => route.fulfill({ json: {} }));
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem('ttsvc_section', 's-library');
|
||||
localStorage.setItem('ttsvc_settings_seen', '1');
|
||||
});
|
||||
const cdp = await page.context().newCDPSession(page);
|
||||
await cdp.send('Emulation.setCPUThrottlingRate', { rate: 4 });
|
||||
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForFunction(() => typeof window.navTo === 'function', null, { timeout: 15_000 });
|
||||
await page.evaluate(() => window.navTo('s-library'));
|
||||
await page.waitForFunction(() => typeof window.libraryRenderCharacters === 'function', null, { timeout: 15_000 });
|
||||
await expect(page.locator('#s-library')).toHaveClass(/is-active/, { timeout: 15_000 });
|
||||
await page.locator('.lib-tab[data-library-view="characters"]').evaluate(el => el.click());
|
||||
await expect.poll(() => page.locator('#lib-chars-list .lib-char-card').count()).toBeLessThanOrEqual(50);
|
||||
const metrics = await page.evaluate(() => ({
|
||||
domNodes: document.getElementsByTagName('*').length,
|
||||
audioElements: document.querySelectorAll('audio').length,
|
||||
renderedImages: document.querySelectorAll('#lib-chars-list img').length,
|
||||
imageCacheEntries: window.TTVC?.imageCache?.size?.() ?? null,
|
||||
jsHeapBytes: performance.memory?.usedJSHeapSize || null,
|
||||
}));
|
||||
expect(metrics.renderedImages).toBeLessThanOrEqual(64);
|
||||
expect(metrics.imageCacheEntries).toBeLessThanOrEqual(64);
|
||||
expect(metrics.audioElements).toBeLessThanOrEqual(32);
|
||||
expect(metrics.domNodes).toBeLessThan(5000);
|
||||
});
|
||||
|
||||
test('voice library cache reuses fresh data and honors explicit refresh', async ({ page }) => {
|
||||
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForFunction(() => typeof window.fetchVoiceLibrary === 'function', null, { timeout: 15_000 });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user