From 0cd1f28c613a876bfedd3b70b987e37f91888ed0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 24 May 2024 21:39:51 +0200 Subject: [PATCH] perf: optimize circular buffer for numbers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/circular-buffer.ts | 36 ++++++++++++++++------------------ src/pools/worker-node.ts | 16 +++++++-------- src/pools/worker.ts | 2 +- tests/circular-buffer.test.mjs | 18 +++++++++-------- tests/pools/utils.test.mjs | 34 +++++++++++++------------------- 5 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/circular-buffer.ts b/src/circular-buffer.ts index 2975ef77..a56cd09d 100644 --- a/src/circular-buffer.ts +++ b/src/circular-buffer.ts @@ -4,17 +4,15 @@ export const defaultBufferSize = 2048 /** - * Circular buffer. + * Circular buffer designed for positive numbers. * - * @typeParam T - Type of buffer data. * @internal */ -export class CircularBuffer { +export class CircularBuffer { private readIdx: number private writeIdx: number - private items: Array + private items: Float32Array private readonly maxArrayIdx: number - /* Buffer number of elements */ public size: number /** @@ -27,7 +25,7 @@ export class CircularBuffer { this.writeIdx = 0 this.maxArrayIdx = size - 1 this.size = 0 - this.items = new Array(size) + this.items = new Float32Array(size).fill(-1) } /** @@ -49,12 +47,12 @@ export class CircularBuffer { } /** - * Puts data into buffer. + * Puts number into buffer. * - * @param data - Data to put into buffer. + * @param number - Number to put into buffer. */ - public put (data: T): void { - this.items[this.writeIdx] = data + public put (number: number): void { + this.items[this.writeIdx] = number this.writeIdx = this.writeIdx === this.maxArrayIdx ? 0 : this.writeIdx + 1 if (this.size < this.items.length) { ++this.size @@ -62,28 +60,28 @@ export class CircularBuffer { } /** - * Gets data from buffer. + * Gets number from buffer. * - * @returns Data from buffer. + * @returns Number from buffer. */ - public get (): T | undefined { + public get (): number | undefined { const data = this.items[this.readIdx] - if (data == null) { + if (data === -1) { return } - this.items[this.readIdx] = undefined + this.items[this.readIdx] = -1 this.readIdx = this.readIdx === this.maxArrayIdx ? 0 : this.readIdx + 1 --this.size return data } /** - * Returns buffer as array. + * Returns buffer as numbers' array. * - * @returns Array of buffer data. + * @returns Numbers' array. */ - public toArray (): T[] { - return this.items.filter(item => item != null) as T[] + public toArray (): number[] { + return Array.from(this.items.filter(item => item !== -1)) } private checkSize (size: number): void { diff --git a/src/pools/worker-node.ts b/src/pools/worker-node.ts index d87a79c0..07955701 100644 --- a/src/pools/worker-node.ts +++ b/src/pools/worker-node.ts @@ -240,17 +240,17 @@ export class WorkerNode failed: 0 }, runTime: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, waitTime: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, elu: { idle: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, active: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) } } } @@ -283,17 +283,17 @@ export class WorkerNode failed: 0 }, runTime: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, waitTime: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, elu: { idle: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) }, active: { - history: new CircularBuffer(MeasurementHistorySize) + history: new CircularBuffer(MeasurementHistorySize) } } } diff --git a/src/pools/worker.ts b/src/pools/worker.ts index 7d9f3de9..b2e6ba80 100644 --- a/src/pools/worker.ts +++ b/src/pools/worker.ts @@ -86,7 +86,7 @@ export interface MeasurementStatistics { /** * Measurement history. */ - readonly history: CircularBuffer + readonly history: CircularBuffer } /** diff --git a/tests/circular-buffer.test.mjs b/tests/circular-buffer.test.mjs index c6351eb7..2d275237 100644 --- a/tests/circular-buffer.test.mjs +++ b/tests/circular-buffer.test.mjs @@ -10,7 +10,7 @@ describe('Circular buffer test suite', t => { expect(circularBuffer.writeIdx).toBe(0) expect(circularBuffer.maxArrayIdx).toBe(defaultBufferSize - 1) expect(circularBuffer.size).toBe(0) - expect(circularBuffer.items).toBeInstanceOf(Array) + expect(circularBuffer.items).toBeInstanceOf(Float32Array) expect(circularBuffer.items.length).toBe(defaultBufferSize) }) @@ -18,7 +18,7 @@ describe('Circular buffer test suite', t => { const size = 1000 const circularBuffer = new CircularBuffer(size) expect(circularBuffer.maxArrayIdx).toBe(size - 1) - expect(circularBuffer.items).toBeInstanceOf(Array) + expect(circularBuffer.items).toBeInstanceOf(Float32Array) expect(circularBuffer.items.length).toBe(size) }) @@ -41,27 +41,29 @@ describe('Circular buffer test suite', t => { it('Verify that circular buffer put() works as intended', () => { const circularBuffer = new CircularBuffer(4) circularBuffer.put(1) - expect(circularBuffer.items).toMatchObject([1]) + expect(circularBuffer.items).toStrictEqual( + new Float32Array([1, -1, -1, -1]) + ) expect(circularBuffer.writeIdx).toBe(1) expect(circularBuffer.size).toBe(1) circularBuffer.put(2) - expect(circularBuffer.items).toMatchObject([1, 2]) + expect(circularBuffer.items).toStrictEqual(new Float32Array([1, 2, -1, -1])) expect(circularBuffer.writeIdx).toBe(2) expect(circularBuffer.size).toBe(2) circularBuffer.put(3) - expect(circularBuffer.items).toMatchObject([1, 2, 3]) + expect(circularBuffer.items).toStrictEqual(new Float32Array([1, 2, 3, -1])) expect(circularBuffer.writeIdx).toBe(3) expect(circularBuffer.size).toBe(3) circularBuffer.put(4) - expect(circularBuffer.items).toMatchObject([1, 2, 3, 4]) + expect(circularBuffer.items).toStrictEqual(new Float32Array([1, 2, 3, 4])) expect(circularBuffer.writeIdx).toBe(0) expect(circularBuffer.size).toBe(4) circularBuffer.put(5) - expect(circularBuffer.items).toMatchObject([5, 2, 3, 4]) + expect(circularBuffer.items).toStrictEqual(new Float32Array([5, 2, 3, 4])) expect(circularBuffer.writeIdx).toBe(1) expect(circularBuffer.size).toBe(4) circularBuffer.put(6) - expect(circularBuffer.items).toMatchObject([5, 6, 3, 4]) + expect(circularBuffer.items).toStrictEqual(new Float32Array([5, 6, 3, 4])) expect(circularBuffer.writeIdx).toBe(2) expect(circularBuffer.size).toBe(4) }) diff --git a/tests/pools/utils.test.mjs b/tests/pools/utils.test.mjs index 3d9634ff..85a00fba 100644 --- a/tests/pools/utils.test.mjs +++ b/tests/pools/utils.test.mjs @@ -36,79 +36,73 @@ describe('Pool utils test suite', () => { }) it('Verify updateMeasurementStatistics() behavior', () => { - const circularBuffer = new CircularBuffer(MeasurementHistorySize) + // const circularBuffer = new CircularBuffer(MeasurementHistorySize) const measurementStatistics = { - history: circularBuffer + history: new CircularBuffer(MeasurementHistorySize) } updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: false, median: false }, 0.01 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.01, maximum: 0.01, - minimum: 0.01, - history: circularBuffer + minimum: 0.01 }) updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: false, median: false }, 0.02 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.03, maximum: 0.02, - minimum: 0.01, - history: circularBuffer + minimum: 0.01 }) updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: true, median: false }, 0.001 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.031, maximum: 0.02, minimum: 0.001, - average: 0.001, - history: circularBuffer + average: 0.0010000000474974513 }) updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: true, median: false }, 0.003 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.034, maximum: 0.02, minimum: 0.001, - average: 0.002, - history: circularBuffer + average: 0.0020000000367872417 }) updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: false, median: true }, 0.006 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.04, maximum: 0.02, minimum: 0.001, - median: 0.003, - history: circularBuffer + median: 0.003000000026077032 }) updateMeasurementStatistics( measurementStatistics, { aggregate: true, average: true, median: false }, 0.01 ) - expect(measurementStatistics).toStrictEqual({ + expect(measurementStatistics).toMatchObject({ aggregate: 0.05, maximum: 0.02, minimum: 0.001, - average: 0.005, - history: circularBuffer + average: 0.004999999975552782 }) }) -- 2.34.1