99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
|
|
/**
|
||
|
|
* Performance Benchmark: SpatialIndex with 50,000 elements
|
||
|
|
* Verifies that the R-Tree spatial index can handle large datasets efficiently.
|
||
|
|
*/
|
||
|
|
import { describe, it, expect, beforeAll } from 'vitest';
|
||
|
|
import { SpatialIndex } from '../src/canvas/SpatialIndex';
|
||
|
|
import type { CADElement } from '../src/types/cad.types';
|
||
|
|
|
||
|
|
const N = 50_000;
|
||
|
|
|
||
|
|
describe('Performance Benchmark: 50.000 Elemente', () => {
|
||
|
|
let spatialIndex: SpatialIndex;
|
||
|
|
let elements: CADElement[];
|
||
|
|
|
||
|
|
beforeAll(() => {
|
||
|
|
spatialIndex = new SpatialIndex();
|
||
|
|
elements = [];
|
||
|
|
|
||
|
|
// Generate 50k elements in a grid pattern
|
||
|
|
for (let i = 0; i < N; i++) {
|
||
|
|
const col = i % 200;
|
||
|
|
const row = Math.floor(i / 200);
|
||
|
|
elements.push({
|
||
|
|
id: `perf-el-${i}`,
|
||
|
|
type: 'rect',
|
||
|
|
layerId: 'layer-perf',
|
||
|
|
x: col * 10,
|
||
|
|
y: row * 10,
|
||
|
|
width: 8,
|
||
|
|
height: 8,
|
||
|
|
properties: { stroke: '#000', fill: '#ccc' },
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should bulk-insert 50k elements in under 2s', () => {
|
||
|
|
const start = performance.now();
|
||
|
|
spatialIndex.bulkInsert(elements);
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`Bulk insert ${N} elements: ${elapsed.toFixed(1)}ms`);
|
||
|
|
expect(elapsed).toBeLessThan(2000);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should search viewport with ~100 visible elements in under 10ms', () => {
|
||
|
|
// Query a small viewport that contains ~100 elements
|
||
|
|
const start = performance.now();
|
||
|
|
const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 1000, maxY: 100 });
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`Viewport search (~100 elements): ${elapsed.toFixed(2)}ms, found=${results.length}`);
|
||
|
|
expect(results.length).toBeGreaterThan(50);
|
||
|
|
expect(results.length).toBeLessThan(2000);
|
||
|
|
expect(elapsed).toBeLessThan(10);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should search large viewport (all elements) in under 100ms', () => {
|
||
|
|
const start = performance.now();
|
||
|
|
const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 });
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`Full viewport search: ${elapsed.toFixed(2)}ms, found=${results.length}`);
|
||
|
|
expect(results.length).toBe(N);
|
||
|
|
expect(elapsed).toBeLessThan(100);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle 100 sequential viewport searches in under 500ms', () => {
|
||
|
|
const start = performance.now();
|
||
|
|
for (let i = 0; i < 100; i++) {
|
||
|
|
const x = (i * 20) % 2000;
|
||
|
|
const y = (i * 5) % 500;
|
||
|
|
spatialIndex.search({ minX: x, minY: y, maxX: x + 200, maxY: y + 100 });
|
||
|
|
}
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`100 sequential searches: ${elapsed.toFixed(2)}ms`);
|
||
|
|
expect(elapsed).toBeLessThan(500);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should remove 1000 elements in under 200ms', () => {
|
||
|
|
const start = performance.now();
|
||
|
|
for (let i = 0; i < 1000; i++) {
|
||
|
|
spatialIndex.remove(elements[i]);
|
||
|
|
}
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`Remove 1000 elements: ${elapsed.toFixed(2)}ms`);
|
||
|
|
expect(elapsed).toBeLessThan(200);
|
||
|
|
|
||
|
|
// Verify count
|
||
|
|
const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 });
|
||
|
|
expect(results.length).toBe(N - 1000);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should clear all elements in under 50ms', () => {
|
||
|
|
const start = performance.now();
|
||
|
|
spatialIndex.clear();
|
||
|
|
const elapsed = performance.now() - start;
|
||
|
|
console.log(`Clear all: ${elapsed.toFixed(2)}ms`);
|
||
|
|
expect(elapsed).toBeLessThan(50);
|
||
|
|
expect(spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 }).length).toBe(0);
|
||
|
|
});
|
||
|
|
});
|