mirror of
https://github.com/stablyai/orca.git
synced 2026-09-24 16:02:41 +00:00
fix(terminal): bound invisible WebGL glyph cache entries
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -21,7 +21,7 @@ index 742f0879ff4f04509e4a07c8efdf0d5743fe8ee5..885a206a394fff783737a412c0b75bf9
|
||||
}
|
||||
|
||||
diff --git a/src/TextureAtlas.ts b/src/TextureAtlas.ts
|
||||
index 4977ad741065e26bbfd35bc50e7558a033b13340..f55805ddc3f266415f7f8e81e5b8c318e7db194c 100644
|
||||
index 4977ad741065e26bbfd35bc50e7558a033b13340..ccf57dbcfff85eeb4c383fa987bcc07aa28e5d14 100644
|
||||
--- a/src/TextureAtlas.ts
|
||||
+++ b/src/TextureAtlas.ts
|
||||
@@ -3,6 +3,7 @@
|
||||
@@ -32,7 +32,28 @@ index 4977ad741065e26bbfd35bc50e7558a033b13340..f55805ddc3f266415f7f8e81e5b8c318
|
||||
import { IColorContrastCache } from 'browser/Types';
|
||||
import { DIM_OPACITY, TEXT_BASELINE } from './Constants';
|
||||
import { tryDrawCustomGlyph } from './customGlyphs/CustomGlyphRasterizer';
|
||||
@@ -135,21 +136,23 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
@@ -42,7 +43,8 @@ const enum Constants {
|
||||
* is enforced to ensure uploading the texture still finishes in a reasonable amount of time. A
|
||||
* 4096 squared image takes up 16MB of GPU memory.
|
||||
*/
|
||||
- FORCED_MAX_TEXTURE_SIZE = 4096
|
||||
+ FORCED_MAX_TEXTURE_SIZE = 4096,
|
||||
+ EMPTY_GLYPH_CACHE_LIMIT = 4096
|
||||
}
|
||||
|
||||
interface ICharAtlasActiveRow {
|
||||
@@ -60,6 +62,10 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
private _cacheMap: FourKeyMap<number, number, number, number, IRasterizedGlyph> = new FourKeyMap();
|
||||
private _cacheMapCombined: FourKeyMap<string, number, number, number, IRasterizedGlyph> = new FourKeyMap();
|
||||
|
||||
+ private _emptyCacheMap: FourKeyMap<number, number, number, number, IRasterizedGlyph> = new FourKeyMap();
|
||||
+ private _emptyCacheMapCombined: FourKeyMap<string, number, number, number, IRasterizedGlyph> = new FourKeyMap();
|
||||
+ private _emptyGlyphCount = 0;
|
||||
+
|
||||
// The texture that the atlas is drawn to
|
||||
private _pages: AtlasPage[] = [];
|
||||
public get pages(): { canvas: HTMLCanvasElement, version: number }[] { return this._pages; }
|
||||
@@ -135,21 +141,24 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
private _pageLayoutVersion = 0;
|
||||
public get pageLayoutVersion(): number { return this._pageLayoutVersion; }
|
||||
|
||||
@@ -44,6 +65,7 @@ index 4977ad741065e26bbfd35bc50e7558a033b13340..f55805ddc3f266415f7f8e81e5b8c318
|
||||
+
|
||||
public clearTexture(): void {
|
||||
- if (this._pages[0].currentRow.x === 0 && this._pages[0].currentRow.y === 0) {
|
||||
+ this._clearEmptyGlyphCache();
|
||||
+ // Guard on every page rather than pages[0]: a merged page is never written through
|
||||
+ // currentRow, so once one lands at index 0 the old check made every later clear a no-op.
|
||||
+ if (this._pages.every(page => page.glyphs.length === 0 && page.currentRow.x === 0 && page.currentRow.y === 0)) {
|
||||
@@ -68,7 +90,68 @@ index 4977ad741065e26bbfd35bc50e7558a033b13340..f55805ddc3f266415f7f8e81e5b8c318
|
||||
}
|
||||
|
||||
private _createNewPage(): AtlasPage {
|
||||
@@ -465,6 +468,36 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
@@ -273,17 +282,18 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
this._overflowSizePage = undefined;
|
||||
this._cacheMap.clear();
|
||||
this._cacheMapCombined.clear();
|
||||
+ this._clearEmptyGlyphCache();
|
||||
this._didWarmUp = false;
|
||||
this._pageLayoutVersion++;
|
||||
this._logService.debug(`Evicted ${pageCount} WebGL atlas pages in ${(performance.now() - startTime).toFixed(2)}ms`);
|
||||
}
|
||||
|
||||
public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
||||
- return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext, restrictToCellHeight, domContainer);
|
||||
+ return this._getFromCacheMap(this._cacheMapCombined, this._emptyCacheMapCombined, chars, bg, fg, ext, restrictToCellHeight, domContainer);
|
||||
}
|
||||
|
||||
public getRasterizedGlyph(code: number, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
||||
- return this._getFromCacheMap(this._cacheMap, code, bg, fg, ext, restrictToCellHeight, domContainer);
|
||||
+ return this._getFromCacheMap(this._cacheMap, this._emptyCacheMap, code, bg, fg, ext, restrictToCellHeight, domContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,6 +301,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
*/
|
||||
private _getFromCacheMap(
|
||||
cacheMap: FourKeyMap<string | number, number, number, number, IRasterizedGlyph>,
|
||||
+ emptyCacheMap: FourKeyMap<string | number, number, number, number, IRasterizedGlyph>,
|
||||
key: string | number,
|
||||
bg: number,
|
||||
fg: number,
|
||||
@@ -298,14 +309,29 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
restrictToCellHeight: boolean,
|
||||
domContainer: HTMLElement | undefined
|
||||
): IRasterizedGlyph {
|
||||
- $glyph = cacheMap.get(key, bg, fg, ext);
|
||||
+ $glyph = cacheMap.get(key, bg, fg, ext) ?? emptyCacheMap.get(key, bg, fg, ext);
|
||||
if (!$glyph) {
|
||||
$glyph = this._drawToCache(key, bg, fg, ext, restrictToCellHeight, domContainer);
|
||||
- cacheMap.set(key, bg, fg, ext, $glyph);
|
||||
+ if ($glyph === NULL_RASTERIZED_GLYPH) {
|
||||
+ // Empty glyphs consume no atlas pixels, so page eviction cannot bound their metadata.
|
||||
+ if (this._emptyGlyphCount >= Constants.EMPTY_GLYPH_CACHE_LIMIT) {
|
||||
+ this._clearEmptyGlyphCache();
|
||||
+ }
|
||||
+ emptyCacheMap.set(key, bg, fg, ext, $glyph);
|
||||
+ this._emptyGlyphCount++;
|
||||
+ } else {
|
||||
+ cacheMap.set(key, bg, fg, ext, $glyph);
|
||||
+ }
|
||||
}
|
||||
return $glyph;
|
||||
}
|
||||
|
||||
+ private _clearEmptyGlyphCache(): void {
|
||||
+ this._emptyCacheMap.clear();
|
||||
+ this._emptyCacheMapCombined.clear();
|
||||
+ this._emptyGlyphCount = 0;
|
||||
+ }
|
||||
+
|
||||
private _getColorFromAnsiIndex(idx: number): IColor {
|
||||
if (idx >= this._config.colors.ansi.length) {
|
||||
throw new Error('No color found for idx ' + idx);
|
||||
@@ -465,6 +491,36 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
return this._config.colors.contrastCache;
|
||||
}
|
||||
|
||||
@@ -105,7 +188,7 @@ index 4977ad741065e26bbfd35bc50e7558a033b13340..f55805ddc3f266415f7f8e81e5b8c318
|
||||
private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
||||
const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars;
|
||||
|
||||
@@ -536,6 +569,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
@@ -536,6 +592,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
const fontStyle = italic ? 'italic' : '';
|
||||
this._tmpCtx.font =
|
||||
`${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# WebGL invisible-glyph cache retention
|
||||
|
||||
The installed xterm WebGL addon caches every character/background/foreground/style
|
||||
variant. Invisible glyphs return a shared empty glyph and occupy no texture
|
||||
pixels, but still create cache entries. The texture-page eviction threshold can
|
||||
therefore never collect a stream of new invisible variants. Changing true-color
|
||||
foreground values while redrawing a space reproduces the growth; a space followed
|
||||
by a zero-width joiner exercises the separate combined-character cache.
|
||||
|
||||
The source patch keeps invisible entries in separate caches with a shared
|
||||
4,096-entry cap. Overflow clears only those entries. Visible glyphs, texture pages,
|
||||
and the atlas layout version stay intact, so a sibling terminal sharing the atlas
|
||||
does not need to rebuild its model. Explicit atlas clearing and page eviction
|
||||
also clear invisible entries. A cache miss after eviction rasterizes the invisible
|
||||
glyph again; recent repeated variants remain cache hits.
|
||||
|
||||
Both generated bundles and their source maps were regenerated using Orca's pinned
|
||||
xterm patch generator, the lockfile hashes were updated, and the dependency was
|
||||
reinstalled with the frozen lockfile. The generator's final `--check` passes.
|
||||
|
||||
## Reproduce
|
||||
|
||||
From the repository root, with Playwright's Chromium headless shell installed:
|
||||
|
||||
```sh
|
||||
ORCA_BACKGROUND_LAUNCH=1 node docs/audits/webgl-empty-glyph-retention/reproduce.mjs
|
||||
```
|
||||
|
||||
`ORCA_AUDIT_CHROMIUM` can select another Chromium executable. For a before/after
|
||||
comparison, set `ORCA_AUDIT_WEBGL_BASELINE` to the previous installed
|
||||
`lib/addon-webgl.js`. This audit reconstructed that baseline by reversing the new
|
||||
patch from a dependency copy and applying the previous checked-in patch; no
|
||||
application source or generated bundle was edited by hand.
|
||||
|
||||
The script runs the actual installed CJS and ESM bundles in headless Chromium
|
||||
with SwiftShader, feeds ordinary terminal output, and renders 100,000 redraws in
|
||||
two modes. It samples V8 heap after CDP collection and records bundle hashes in
|
||||
[results.json](./results.json). Two terminals share one atlas. Assertions cover:
|
||||
|
||||
- Invisible entries stay at or below 4,096; the baseline accumulates 100,000.
|
||||
- Visible glyph caches and the one texture page stay intact across overflow.
|
||||
- Rendered pixels for the unaffected first cell of both terminals stay identical.
|
||||
- The last 64 repeated variants cause no new rasterization.
|
||||
- Explicit clear drops invisible metadata even when the atlas has no drawn glyphs.
|
||||
|
||||
The baseline ends with 100,093 entries and about 13.6 MB of heap growth. The fixed
|
||||
run ends with 1,789 entries (93 visible and 1,696 invisible), with roughly 0.3 MB
|
||||
of heap growth. Exact heap samples vary; the bounded entry count is the invariant.
|
||||
No Orca window was launched, and no browser window was shown.
|
||||
|
||||
Validation also passed 86 tests across the patch generator/runtime contract and
|
||||
WebGL lifecycle/context/recovery suites, full typecheck, lint, and changed-code
|
||||
quality. Test commands used `ORCA_BACKGROUND_LAUNCH=1`.
|
||||
|
||||
The reported `v1.4.198` ships the same addon version and lacks this cap. This is a
|
||||
renderer retaining path compatible with app-scope memory growth, but #19831 does
|
||||
not establish a stream of distinct invisible color variants. It does not explain
|
||||
#19768's separately measured main PID. No incident attribution is claimed.
|
||||
@@ -0,0 +1,189 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { resolve } from 'node:path'
|
||||
import { chromium } from 'playwright'
|
||||
|
||||
if (process.env.ORCA_BACKGROUND_LAUNCH !== '1') {
|
||||
throw new Error('Run with ORCA_BACKGROUND_LAUNCH=1')
|
||||
}
|
||||
const installed = resolve('node_modules/@xterm/addon-webgl/lib/addon-webgl.js')
|
||||
const current = [
|
||||
['after', installed],
|
||||
['after', installed.replace(/\.js$/, '.mjs')]
|
||||
]
|
||||
const bundles = process.env.ORCA_AUDIT_WEBGL_BASELINE
|
||||
? [['before', resolve(process.env.ORCA_AUDIT_WEBGL_BASELINE)], ...current]
|
||||
: current
|
||||
const browser = await chromium.launch({
|
||||
executablePath: process.env.ORCA_AUDIT_CHROMIUM,
|
||||
headless: true,
|
||||
args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader']
|
||||
})
|
||||
const results = []
|
||||
try {
|
||||
for (const [phase, bundle] of bundles) {
|
||||
const sha256 = createHash('sha256')
|
||||
.update(await readFile(bundle))
|
||||
.digest('hex')
|
||||
for (const mode of ['space', 'space-joiner']) {
|
||||
const page = await browser.newPage()
|
||||
try {
|
||||
await page.setContent('<div id="first"></div><div id="second"></div>')
|
||||
await page.addStyleTag({ path: resolve('node_modules/@xterm/xterm/css/xterm.css') })
|
||||
await page.addScriptTag({ path: resolve('node_modules/@xterm/xterm/lib/xterm.js') })
|
||||
if (bundle.endsWith('.mjs')) {
|
||||
const source = await readFile(bundle, 'utf8')
|
||||
await page.evaluate(
|
||||
async (url) => {
|
||||
window.WebglAddon = await import(url)
|
||||
},
|
||||
`data:text/javascript;base64,${Buffer.from(source).toString('base64')}`
|
||||
)
|
||||
} else {
|
||||
await page.addScriptTag({ path: bundle })
|
||||
}
|
||||
await page.evaluate(async (mode) => {
|
||||
const create = (id, text) => {
|
||||
const terminal = new Terminal({
|
||||
cols: 4,
|
||||
rows: 1,
|
||||
scrollback: 0,
|
||||
allowProposedApi: true,
|
||||
logLevel: 'off'
|
||||
})
|
||||
terminal.open(document.getElementById(id))
|
||||
const addon = new WebglAddon.WebglAddon()
|
||||
terminal.loadAddon(addon)
|
||||
terminal._core.writeSync(text)
|
||||
addon._renderer.renderRows(0, 0)
|
||||
return { terminal, addon }
|
||||
}
|
||||
const first = create('first', 'A')
|
||||
const second = create('second', 'B')
|
||||
window.glyphAudit = { first, second, mode, index: 0 }
|
||||
await new Promise(requestAnimationFrame)
|
||||
await new Promise(requestIdleCallback)
|
||||
}, mode)
|
||||
const cdp = await page.context().newCDPSession(page)
|
||||
const samples = []
|
||||
for (const count of [0, 1000, 5000, 10000, 50000, 100000]) {
|
||||
const state = await page.evaluate((count) => {
|
||||
const { first, second, mode } = window.glyphAudit
|
||||
for (let index = window.glyphAudit.index; index < count; index++) {
|
||||
const color = index + 1
|
||||
first.terminal._core.writeSync(
|
||||
`\x1b[1;2H\x1b[38;2;${color >> 16};${(color >> 8) & 255};${color & 255}m ${mode === 'space-joiner' ? '\u200d' : ''}`
|
||||
)
|
||||
first.addon._renderer.renderRows(0, 0)
|
||||
}
|
||||
first.addon._renderer.renderRows(0, 0)
|
||||
second.addon._renderer.renderRows(0, 0)
|
||||
window.glyphAudit.index = count
|
||||
const atlas = first.addon._renderer._charAtlas
|
||||
const entries = (map) => {
|
||||
let result = 0
|
||||
for (const second of Object.values(map?._data._data ?? {})) {
|
||||
for (const inner of Object.values(second)) {
|
||||
for (const fourth of Object.values(inner._data)) {
|
||||
result += Object.keys(fourth).length
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
const pixels = ({ terminal, addon }) => {
|
||||
const gl = addon._renderer._gl
|
||||
const width = Math.floor(gl.drawingBufferWidth / terminal.cols)
|
||||
const height = gl.drawingBufferHeight
|
||||
const bytes = new Uint8Array(width * height * 4)
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, bytes)
|
||||
let hash = 2166136261
|
||||
for (const byte of bytes) {
|
||||
hash = Math.imul(hash ^ byte, 16777619)
|
||||
}
|
||||
return hash >>> 0
|
||||
}
|
||||
return {
|
||||
updates: count,
|
||||
firstCellPixels: pixels(first),
|
||||
secondCellPixels: pixels(second),
|
||||
regular: entries(atlas._cacheMap),
|
||||
combined: entries(atlas._cacheMapCombined),
|
||||
empty: entries(atlas._emptyCacheMap) + entries(atlas._emptyCacheMapCombined),
|
||||
pages: atlas.pages.length,
|
||||
glyphs: atlas.pages.reduce((n, page) => n + page.glyphs.length, 0),
|
||||
layoutVersion: atlas.pageLayoutVersion,
|
||||
shared: atlas === second.addon._renderer._charAtlas,
|
||||
preserved:
|
||||
first.terminal.buffer.active.getLine(0).getCell(0).getChars() === 'A' &&
|
||||
second.terminal.buffer.active.getLine(0).getCell(0).getChars() === 'B'
|
||||
}
|
||||
}, count)
|
||||
await cdp.send('HeapProfiler.collectGarbage')
|
||||
samples.push({ ...state, heap: (await cdp.send('Runtime.getHeapUsage')).usedSize })
|
||||
}
|
||||
const checks = await page.evaluate(() => {
|
||||
const { first, mode } = window.glyphAudit
|
||||
const atlas = first.addon._renderer._charAtlas
|
||||
let rasterizations = 0
|
||||
const draw = atlas._drawToCache
|
||||
atlas._drawToCache = function (...args) {
|
||||
rasterizations++
|
||||
return draw.apply(this, args)
|
||||
}
|
||||
for (let color = 99937; color <= 100000; color++) {
|
||||
first.terminal._core.writeSync(
|
||||
`\x1b[1;2H\x1b[38;2;${color >> 16};${(color >> 8) & 255};${color & 255}m ${mode === 'space-joiner' ? '\u200d' : ''}`
|
||||
)
|
||||
first.addon._renderer.renderRows(0, 0)
|
||||
}
|
||||
atlas._drawToCache = draw
|
||||
first.addon.clearTextureAtlas()
|
||||
// Exercise explicit clear with only invisible glyph metadata and no drawn atlas cells.
|
||||
atlas.getRasterizedGlyph(32, 0, 0x3000001, 0, false, first.terminal.element)
|
||||
first.addon.clearTextureAtlas()
|
||||
return { rasterizations, emptyAfterClear: atlas._emptyGlyphCount ?? null }
|
||||
})
|
||||
assert.ok(
|
||||
samples.every((sample) => sample.shared && sample.preserved && sample.pages === 1)
|
||||
)
|
||||
assert.equal(checks.rasterizations, 0)
|
||||
assert.notEqual(samples[0].firstCellPixels, samples[0].secondCellPixels)
|
||||
assert.ok(
|
||||
samples.every(
|
||||
(sample) =>
|
||||
sample.firstCellPixels === samples[0].firstCellPixels &&
|
||||
sample.secondCellPixels === samples[0].secondCellPixels
|
||||
)
|
||||
)
|
||||
if (phase === 'after') {
|
||||
assert.ok(
|
||||
samples.every(
|
||||
(sample) => sample.empty <= 4096 && sample.regular + sample.combined < 200
|
||||
)
|
||||
)
|
||||
assert.equal(checks.emptyAfterClear, 0)
|
||||
assert.equal(samples[0].layoutVersion, samples.at(-1).layoutVersion)
|
||||
} else {
|
||||
assert.ok(samples.at(-1).regular + samples.at(-1).combined >= 100000)
|
||||
}
|
||||
results.push({
|
||||
phase,
|
||||
format: bundle.endsWith('.mjs') ? 'esm' : 'cjs',
|
||||
mode,
|
||||
sha256,
|
||||
samples,
|
||||
checks
|
||||
})
|
||||
} finally {
|
||||
await page.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(
|
||||
JSON.stringify({ node: process.version, browser: browser.version(), results }, null, 2)
|
||||
)
|
||||
} finally {
|
||||
await browser.close()
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
{
|
||||
"node": "v26.6.0",
|
||||
"browser": "147.0.7727.15",
|
||||
"results": [
|
||||
{
|
||||
"phase": "before",
|
||||
"format": "cjs",
|
||||
"mode": "space",
|
||||
"sha256": "c4b646075065e9ed5f885880ff80e2edd54f481f982adaf193cc742de17e1a4f",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 3,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 3,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3224056
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 1004,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 4,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3920428
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 5093,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 4291832
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 10093,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 4912812
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 50093,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 10498896
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 100093,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 16964756
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"phase": "before",
|
||||
"format": "cjs",
|
||||
"mode": "space-joiner",
|
||||
"sha256": "c4b646075065e9ed5f885880ff80e2edd54f481f982adaf193cc742de17e1a4f",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 3,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 3,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3519884
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 1000,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3812016
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 5000,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 4305884
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 10000,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 4927728
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 50000,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 10510028
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 100000,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 16974812
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"phase": "after",
|
||||
"format": "cjs",
|
||||
"mode": "space",
|
||||
"sha256": "0667d4850345c52271515c6ffe434c40687c59db007ddd32aabc02f0118a1cad",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3334740
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1000,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3799504
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 904,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3792468
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1808,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3913748
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 848,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3833376
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1696,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3638720
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"phase": "after",
|
||||
"format": "cjs",
|
||||
"mode": "space-joiner",
|
||||
"sha256": "0667d4850345c52271515c6ffe434c40687c59db007ddd32aabc02f0118a1cad",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 3,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 3,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3451404
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1000,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3814924
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 904,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3809484
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1808,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3931512
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 848,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3849588
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1696,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3654196
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"phase": "after",
|
||||
"format": "esm",
|
||||
"mode": "space",
|
||||
"sha256": "1ff2a59921ed5d53c0958110dac290c8d9f8d4502ea631fac7fd8575227b30f0",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 3,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 3,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3476632
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1000,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3758644
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 904,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3752072
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1808,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3873504
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 848,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3794992
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1696,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3666356
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"phase": "after",
|
||||
"format": "esm",
|
||||
"mode": "space-joiner",
|
||||
"sha256": "1ff2a59921ed5d53c0958110dac290c8d9f8d4502ea631fac7fd8575227b30f0",
|
||||
"samples": [
|
||||
{
|
||||
"updates": 0,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 0,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3293684
|
||||
},
|
||||
{
|
||||
"updates": 1000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1000,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3736872
|
||||
},
|
||||
{
|
||||
"updates": 5000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 904,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3769340
|
||||
},
|
||||
{
|
||||
"updates": 10000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1808,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3891352
|
||||
},
|
||||
{
|
||||
"updates": 50000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 848,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3809472
|
||||
},
|
||||
{
|
||||
"updates": 100000,
|
||||
"firstCellPixels": 1033360771,
|
||||
"secondCellPixels": 395161943,
|
||||
"regular": 93,
|
||||
"combined": 0,
|
||||
"empty": 1696,
|
||||
"pages": 1,
|
||||
"glyphs": 93,
|
||||
"layoutVersion": 0,
|
||||
"shared": true,
|
||||
"preserved": true,
|
||||
"heap": 3680100
|
||||
}
|
||||
],
|
||||
"checks": {
|
||||
"rasterizations": 0,
|
||||
"emptyAfterClear": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+3
-3
@@ -113,7 +113,7 @@ patchedDependencies:
|
||||
'@xterm/addon-ligatures@0.11.0-beta.300': 47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920
|
||||
'@xterm/addon-search@0.17.0-beta.300': eee5338dd2621ece46e79c61ec06766cd7fadaf79ffdb24e2a8ab68e97ef31f0
|
||||
'@xterm/addon-serialize@0.15.0-beta.300': 851eac3d75e6d8c013b9f4c053e61d824b23965cb19ecc28e335e05059f3a294
|
||||
'@xterm/addon-webgl@0.20.0-beta.299': 94687e89a0115e6e6aa102837f986debdc029c091527ee5eb4a4e17ceaf9473e
|
||||
'@xterm/addon-webgl@0.20.0-beta.299': 023a26cbe215df764d841484cb7b0c81d97d9405587eec4b9446d9d06d4e762c
|
||||
'@xterm/xterm@6.1.0-beta.303': 1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4
|
||||
lint-staged@16.4.0: 7333b3837f80a7fbd045964db6d76ba4fc118e49134bdbabb00585b6b7b60673
|
||||
node-pty@1.1.0: 346cb29d33dd6eeb14910ff411c7584b0b2ff9a4b271c4b6d23c3b48e6548f74
|
||||
@@ -338,7 +338,7 @@ importers:
|
||||
version: 0.13.0-beta.300(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))
|
||||
'@xterm/addon-webgl':
|
||||
specifier: 0.20.0-beta.299
|
||||
version: 0.20.0-beta.299(patch_hash=94687e89a0115e6e6aa102837f986debdc029c091527ee5eb4a4e17ceaf9473e)(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))
|
||||
version: 0.20.0-beta.299(patch_hash=023a26cbe215df764d841484cb7b0c81d97d9405587eec4b9446d9d06d4e762c)(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))
|
||||
'@xterm/xterm':
|
||||
specifier: 6.1.0-beta.303
|
||||
version: 6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4)
|
||||
@@ -10459,7 +10459,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4)
|
||||
|
||||
'@xterm/addon-webgl@0.20.0-beta.299(patch_hash=94687e89a0115e6e6aa102837f986debdc029c091527ee5eb4a4e17ceaf9473e)(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))':
|
||||
'@xterm/addon-webgl@0.20.0-beta.299(patch_hash=023a26cbe215df764d841484cb7b0c81d97d9405587eec4b9446d9d06d4e762c)(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))':
|
||||
dependencies:
|
||||
'@xterm/xterm': 6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user