use IdleTaskQueue & Date.now; some testcases
This commit is contained in:
@@ -9,6 +9,7 @@ import { CircularList } from 'common/CircularList';
|
||||
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
|
||||
import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { ExtendedAttrs } from 'common/buffer/AttributeData';
|
||||
|
||||
const INIT_COLS = 80;
|
||||
const INIT_ROWS = 24;
|
||||
@@ -1177,4 +1178,33 @@ describe('Buffer', () => {
|
||||
assert.equal(str3, '😁a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('memory cleanup after shrinking', () => {
|
||||
it('should realign memory from idle task execution', async () => {
|
||||
buffer.fillViewportRows();
|
||||
|
||||
// shrink more than 2 times to trigger lazy memory cleanup
|
||||
buffer.resize(INIT_COLS / 2 - 1, INIT_ROWS);
|
||||
|
||||
// sync
|
||||
for (let i = 0; i < INIT_ROWS; i++) {
|
||||
const line = buffer.lines.get(i)!;
|
||||
// line memory is still at old size from initialization
|
||||
assert.equal((line as any)._data.buffer.byteLength, INIT_COLS * 3 * 4);
|
||||
// array.length and .length get immediately adjusted
|
||||
assert.equal((line as any)._data.length, (INIT_COLS / 2 - 1) * 3);
|
||||
assert.equal(line.length, INIT_COLS / 2 - 1);
|
||||
}
|
||||
|
||||
// wait for a bit to give IdleTaskQueue a chance to kick in
|
||||
// and finish memory cleaning
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
|
||||
// cleanup should have realigned memory with exact bytelength
|
||||
for (let i = 0; i < INIT_ROWS; i++) {
|
||||
const line = buffer.lines.get(i)!;
|
||||
assert.equal((line as any)._data.buffer.byteLength, (INIT_COLS / 2 - 1) * 3 * 4);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+22
-15
@@ -14,7 +14,7 @@ import { Marker } from 'common/buffer/Marker';
|
||||
import { IOptionsService, IBufferService } from 'common/services/Services';
|
||||
import { DEFAULT_CHARSET } from 'common/data/Charsets';
|
||||
import { ExtendedAttrs } from 'common/buffer/AttributeData';
|
||||
import { DebouncedIdleTask } from 'common/TaskQueue';
|
||||
import { DebouncedIdleTask, IdleTaskQueue } from 'common/TaskQueue';
|
||||
|
||||
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
||||
|
||||
@@ -151,8 +151,8 @@ export class Buffer implements IBuffer {
|
||||
// store reference to null cell with default attrs
|
||||
const nullCell = this.getNullCell(DEFAULT_ATTR_DATA);
|
||||
|
||||
// defer memory cleanup of bufferlines
|
||||
let needsCleanup = 0;
|
||||
// count bufferlines with overly big memory to be cleaned afterwards
|
||||
let dirtyMemoryLines = 0;
|
||||
|
||||
// Increase max length if needed before adjustments to allow space to fill
|
||||
// as required.
|
||||
@@ -168,7 +168,7 @@ export class Buffer implements IBuffer {
|
||||
if (this._cols < newCols) {
|
||||
for (let i = 0; i < this.lines.length; i++) {
|
||||
// +boolean for fast 0 or 1 conversion
|
||||
needsCleanup |= +this.lines.get(i)!.resize(newCols, nullCell);
|
||||
dirtyMemoryLines += +this.lines.get(i)!.resize(newCols, nullCell);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ export class Buffer implements IBuffer {
|
||||
if (this._cols > newCols) {
|
||||
for (let i = 0; i < this.lines.length; i++) {
|
||||
// +boolean for fast 0 or 1 conversion
|
||||
needsCleanup |= +this.lines.get(i)!.resize(newCols, nullCell);
|
||||
dirtyMemoryLines += +this.lines.get(i)!.resize(newCols, nullCell);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,26 +256,33 @@ export class Buffer implements IBuffer {
|
||||
this._cols = newCols;
|
||||
this._rows = newRows;
|
||||
|
||||
if (needsCleanup) {
|
||||
this._memoryCleanupTask.set(() => this._cleanupMemory());
|
||||
} else {
|
||||
// FIXME: DebouncedIdleTask has no clear method?
|
||||
this._memoryCleanupTask.set(() => {});
|
||||
this._memoryCleanupQueue.clear();
|
||||
// schedule memory cleanup only, if more than 10% of the lines are affected
|
||||
if (dirtyMemoryLines > 0.1 * this.lines.length) {
|
||||
this._memoryCleanupQueue.enqueue(() => this._batchedMemoryCleanup());
|
||||
}
|
||||
}
|
||||
|
||||
private _memoryCleanupTask: DebouncedIdleTask = new DebouncedIdleTask();
|
||||
private _memoryCleanupQueue = new IdleTaskQueue();
|
||||
|
||||
private _cleanupMemory(): void {
|
||||
private _batchedMemoryCleanup(): boolean {
|
||||
let counted = 0;
|
||||
for (let i = 0; i < this.lines.length; i++) {
|
||||
counted += this.lines.get(i)!.cleanupMemory();
|
||||
// throttle to 5k lines
|
||||
// throttle to 5k lines at once and
|
||||
// return true to indicate, that the task is not finished yet
|
||||
if (counted > 5000) {
|
||||
this._memoryCleanupTask.set(() => this._cleanupMemory());
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private _forceMemoryCleanup(): void {
|
||||
this._memoryCleanupQueue.clear();
|
||||
for (let i = 0; i < this.lines.length; i++) {
|
||||
this.lines.get(i)!.cleanupMemory();
|
||||
}
|
||||
}
|
||||
|
||||
private get _isReflowEnabled(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user