Improve copyFrom for empty and sparse sparse-map paths
Use shared empty-map sentinels with copy-on-write for scroll recycling, and an inlined _data flag scan for populated sparse maps (faster than per-cell function calls on master). Avoid slow Object.assign map copies. Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
This commit is contained in:
co-authored by
Daniel Imms
parent
9872be0c29
commit
b44d036524
@@ -4,26 +4,54 @@
|
||||
*/
|
||||
|
||||
import { perfContext, before, RuntimeCase } from 'xterm-benchmark';
|
||||
import { BufferLine } from 'common/buffer/BufferLine';
|
||||
import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
||||
import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache';
|
||||
import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from 'common/buffer/Constants';
|
||||
import { BgFlags, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants';
|
||||
|
||||
const ITERATIONS = 500_000;
|
||||
const stringCache = new BufferLineStringCache();
|
||||
const nullCell = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||
const yCell = CellData.fromCharData([0, 'y', 1, 'y'.charCodeAt(0)]);
|
||||
|
||||
function setupScrollRecyclePair(cols: number): { recycled: BufferLine; blank: BufferLine } {
|
||||
function fillPlainY(line: BufferLine, cols: number): void {
|
||||
for (let i = 0; i < cols; i++) {
|
||||
line.setCellFromCodepoint(i, 'y'.charCodeAt(0), 1, DEFAULT_ATTR_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
function setupScrollRecyclePair(cols: number): { recycled: BufferLine, blank: BufferLine } {
|
||||
const blank = new BufferLine(stringCache, cols, nullCell, false);
|
||||
const recycled = new BufferLine(stringCache, cols, yCell, false);
|
||||
for (let i = 0; i < cols; i++) {
|
||||
recycled.setCellFromCodepoint(i, 'y'.charCodeAt(0), 1, DEFAULT_ATTR_DATA);
|
||||
}
|
||||
fillPlainY(recycled, cols);
|
||||
return { recycled, blank };
|
||||
}
|
||||
|
||||
/** Source line with combining chars and extended attrs spread across columns. */
|
||||
function buildSparseSourceLine(cols: number): BufferLine {
|
||||
const line = new BufferLine(stringCache, cols, nullCell, false);
|
||||
for (let i = 0; i < cols; i++) {
|
||||
if (i % 10 === 0) {
|
||||
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
|
||||
cell.extended.underlineStyle = UnderlineStyle.CURLY;
|
||||
cell.bg |= BgFlags.HAS_EXTENDED;
|
||||
line.setCell(i, cell);
|
||||
} else if (i % 17 === 0) {
|
||||
line.setCell(i, CellData.fromCharData([1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]));
|
||||
} else {
|
||||
line.setCellFromCodepoint(i, 'y'.charCodeAt(0), 1, DEFAULT_ATTR_DATA);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
function setupCopyFromSparsePair(cols: number): { dest: BufferLine, src: BufferLine } {
|
||||
const src = buildSparseSourceLine(cols);
|
||||
const dest = new BufferLine(stringCache, cols, yCell, false);
|
||||
fillPlainY(dest, cols);
|
||||
return { dest, src };
|
||||
}
|
||||
|
||||
perfContext('BufferLine.copyFrom (scroll recycle)', () => {
|
||||
perfContext('cols=80', () => {
|
||||
let recycled: BufferLine;
|
||||
@@ -53,3 +81,33 @@ perfContext('BufferLine.copyFrom (scroll recycle)', () => {
|
||||
}, { fork: false }).showAverageRuntime();
|
||||
});
|
||||
});
|
||||
|
||||
perfContext('BufferLine.copyFrom (sparse source: combined + extended attrs)', () => {
|
||||
perfContext('cols=80', () => {
|
||||
let dest: BufferLine;
|
||||
let src: BufferLine;
|
||||
before(() => {
|
||||
({ dest, src } = setupCopyFromSparsePair(80));
|
||||
});
|
||||
new RuntimeCase('', () => {
|
||||
for (let i = 0; i < ITERATIONS; i++) {
|
||||
dest.copyFrom(src);
|
||||
}
|
||||
return { payloadSize: ITERATIONS };
|
||||
}, { fork: false }).showAverageRuntime();
|
||||
});
|
||||
|
||||
perfContext('cols=279', () => {
|
||||
let dest: BufferLine;
|
||||
let src: BufferLine;
|
||||
before(() => {
|
||||
({ dest, src } = setupCopyFromSparsePair(279));
|
||||
});
|
||||
new RuntimeCase('', () => {
|
||||
for (let i = 0; i < ITERATIONS; i++) {
|
||||
dest.copyFrom(src);
|
||||
}
|
||||
return { payloadSize: ITERATIONS };
|
||||
}, { fork: false }).showAverageRuntime();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user