WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions packages/ag-charts-community/benchmarks/highFrequencyDataBar.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { describe as jestDescribe } from '@jest/globals';

import type { AgCartesianChartOptions } from 'ag-charts-types';

import { benchmark, setupBenchmark } from './benchmark';
import { isAtOrAfterVersion } from './compatibility';

const describeWhenSupported = isAtOrAfterVersion(12, 3, 0) ? jestDescribe : jestDescribe.skip;

describeWhenSupported('high-frequency data bar benchmark', () => {
const ctx = setupBenchmark<AgCartesianChartOptions>('high-freq-bar');

type Datum = {
timestamp: number;
price: number;
volume: number;
};

const INITIAL_POINTS = 100_000;
const BATCH_SIZE = 100;
const DATA_INTERVAL_MS = 250;
const START_TIMESTAMP = Date.UTC(2024, 0, 1, 0, 0, 0);
const BASE_PRICE = 100;

class HighFrequencyBarDataGenerator {
private index = 0;
private price = BASE_PRICE;

reset() {
this.index = 0;
this.price = BASE_PRICE;
}

take(count: number): Datum[] {
const batch: Datum[] = [];
for (let i = 0; i < count; i++) {
batch.push(this.next());
}
return batch;
}

private next(): Datum {
const index = this.index++;
const timestamp = START_TIMESTAMP + index * DATA_INTERVAL_MS;
const drift = Math.sin(index / 12) * 0.7 + Math.cos(index / 24) * 0.4;
this.price = Number((this.price + drift).toFixed(2));
return {
timestamp,
price: this.price,
volume: 600 + Math.round((Math.sin(index / 8) + 1) * 220),
};
}
}

const barDataGenerator = new HighFrequencyBarDataGenerator();

let data: Datum[] = [];

function createSeedData(count: number): Datum[] {
barDataGenerator.reset();
return barDataGenerator.take(count);
}

function createBatch(count: number): Datum[] {
return barDataGenerator.take(count);
}

beforeEach(() => {
data = createSeedData(INITIAL_POINTS);
});

describe('applyTransaction updates', () => {
beforeEach(async () => {
ctx.options.data = data;
await ctx.create();
});

benchmark(
'1x append batch (100 points)',
ctx,
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const append = createBatch(BATCH_SIZE);
data = data.concat(append);
await (ctx.chart as any).applyTransaction({ append });
},
15_000
);

benchmark(
'10x append batch (1k points total)',
ctx.repeatCount(10),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const append = createBatch(BATCH_SIZE);
data = data.concat(append);
await (ctx.chart as any).applyTransaction({ append });
},
30_000
);

benchmark(
'1x remove batch (100 points)',
ctx.repeatCount(1),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
data = data.slice(BATCH_SIZE);
await (ctx.chart as any).applyTransaction({ remove });
},
15_000
);

benchmark(
'1x rolling window update (append + remove)',
ctx.repeatCount(1),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
const append = createBatch(BATCH_SIZE);
data = data.slice(BATCH_SIZE).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
15_000
);

benchmark(
'10x rolling window update (append + remove)',
ctx.repeatCount(10),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
const append = createBatch(BATCH_SIZE);
data = data.slice(BATCH_SIZE).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
30_000
);

benchmark(
'50x rolling window update (append + remove)',
ctx.repeatCount(50),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
const append = createBatch(BATCH_SIZE);
data = data.slice(BATCH_SIZE).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
60_000
);
});

describe('different batch sizes', () => {
beforeEach(async () => {
ctx.options.data = data;
await ctx.create();
});

benchmark(
'applyTransaction - 10 points rolling window',
ctx.repeatCount(10),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const batchSize = 10;
const remove = data.slice(0, batchSize);
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
30_000
);

benchmark(
'applyTransaction - 500 points rolling window',
ctx.repeatCount(10),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const batchSize = 500;
const remove = data.slice(0, batchSize);
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
30_000
);

benchmark(
'applyTransaction - 1000 points rolling window',
ctx.repeatCount(10),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const batchSize = 1000;
const remove = data.slice(0, batchSize);
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
30_000
);
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { beforeEach, describe } from '@jest/globals';
import { describe as jestDescribe } from '@jest/globals';

import { AgCartesianChartOptions } from 'ag-charts-types';
import type { AgCartesianChartOptions } from 'ag-charts-types';

import { benchmark, setupBenchmark } from './benchmark';
import { isAtOrAfterVersion } from './compatibility';

describe('high-frequency data benchmark', () => {
const ctx = setupBenchmark<AgCartesianChartOptions>('high-freq-high-volume');
const describeWhenSupported = isAtOrAfterVersion(12, 3, 0) ? jestDescribe : jestDescribe.skip;

describeWhenSupported('high-frequency data line benchmark', () => {
const ctx = setupBenchmark<AgCartesianChartOptions>('high-freq-line');

type Datum = {
timestamp: number;
Expand All @@ -17,39 +20,50 @@ describe('high-frequency data benchmark', () => {
const DATA_INTERVAL_MS = 250;
const START_TIMESTAMP = Date.UTC(2024, 0, 1, 0, 0, 0);

let data: Datum[] = [];
let nextIndex = 0;

function generateDatum(index: number): Datum {
const timestamp = START_TIMESTAMP + index * DATA_INTERVAL_MS;
const trend = Math.sin(index / 240) * 40 + Math.cos(index / 80) * 25;
const volatility = Math.sin(index / 15) * 5;
const baseline = 1_000 + index * 0.02;
return {
timestamp,
value: Number((baseline + trend + volatility).toFixed(2)),
};
class HighFrequencyLineDataGenerator {
private index = 0;

reset() {
this.index = 0;
}

take(count: number): Datum[] {
const batch: Datum[] = [];
for (let i = 0; i < count; i++) {
batch.push(this.next());
}
return batch;
}

private next(): Datum {
const index = this.index++;
const timestamp = START_TIMESTAMP + index * DATA_INTERVAL_MS;
const trend = Math.sin(index / 240) * 40 + Math.cos(index / 80) * 25;
const volatility = Math.sin(index / 15) * 5;
const baseline = 1_000 + index * 0.02;

return {
timestamp,
value: Number((baseline + trend + volatility).toFixed(2)),
};
}
}

const lineDataGenerator = new HighFrequencyLineDataGenerator();

let data: Datum[] = [];

function createSeedData(count: number): Datum[] {
const result: Datum[] = [];
for (let i = 0; i < count; i++) {
result.push(generateDatum(i));
}
return result;
lineDataGenerator.reset();
return lineDataGenerator.take(count);
}

function createBatch(count: number): Datum[] {
const batch: Datum[] = [];
for (let i = 0; i < count; i++) {
batch.push(generateDatum(nextIndex++));
}
return batch;
return lineDataGenerator.take(count);
}

beforeEach(() => {
data = createSeedData(INITIAL_POINTS);
nextIndex = data.length;
});

describe('applyTransaction updates', () => {
Expand Down Expand Up @@ -84,7 +98,7 @@ describe('high-frequency data benchmark', () => {

benchmark(
'1x remove batch (100 points)',
ctx,
ctx.repeatCount(1),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
Expand All @@ -96,7 +110,7 @@ describe('high-frequency data benchmark', () => {

benchmark(
'1x rolling window update (append + remove)',
ctx,
ctx.repeatCount(1),
{ expectedRelativeMB: 0.5, expectedCanvasCount: 2, autoSnapshot: false },
async () => {
const remove = data.slice(0, BATCH_SIZE);
Expand Down Expand Up @@ -147,10 +161,7 @@ describe('high-frequency data benchmark', () => {
async () => {
const batchSize = 10;
const remove = data.slice(0, batchSize);
const append: Datum[] = [];
for (let i = 0; i < batchSize; i++) {
append.push(generateDatum(nextIndex++));
}
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
Expand All @@ -164,10 +175,7 @@ describe('high-frequency data benchmark', () => {
async () => {
const batchSize = 500;
const remove = data.slice(0, batchSize);
const append: Datum[] = [];
for (let i = 0; i < batchSize; i++) {
append.push(generateDatum(nextIndex++));
}
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
Expand All @@ -181,10 +189,7 @@ describe('high-frequency data benchmark', () => {
async () => {
const batchSize = 1000;
const remove = data.slice(0, batchSize);
const append: Datum[] = [];
for (let i = 0; i < batchSize; i++) {
append.push(generateDatum(nextIndex++));
}
const append = createBatch(batchSize);
data = data.slice(batchSize).concat(append);
await (ctx.chart as any).applyTransaction({ append, remove });
},
Expand Down
3 changes: 2 additions & 1 deletion packages/ag-charts-community/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@
"ag-charts-website-benchmarks_large-scale-multi-series_main.ts:generate-example",
"ag-charts-website-benchmarks_multi-series_main.ts:generate-example",
"ag-charts-website-benchmarks_resize_main.ts:generate-example",
"ag-charts-website-benchmarks_high-freq-high-volume_main.ts:generate-example"
"ag-charts-website-benchmarks_high-freq-line_main.ts:generate-example",
"ag-charts-website-benchmarks_high-freq-bar_main.ts:generate-example"
]
},
"pack": {
Expand Down
Loading
Loading