From f9b6f313c616fe8b95e9e1056911f543a0c8ac1a Mon Sep 17 00:00:00 2001 From: Revone Date: Thu, 16 Nov 2023 21:07:00 +0800 Subject: [PATCH] feat: The performance report generator supports parameter filtering commands, which can be used to run specific tests individually. It generates individual performance comparison reports. Enrich the COMMANDS.md document. --- CHANGELOG.md | 2 +- COMMANDS.md | 7 +- README.md | 33 ++-- package.json | 2 +- src/data-structures/heap/heap.ts | 148 ++++++++++++++++-- .../binary-tree/rb-tree.test.ts | 6 +- .../data-structures/comparation.test.ts | 142 +++++++++++++++++ .../data-structures/hash/hash-map.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../priority-queue/priority-queue.test.ts | 2 +- .../data-structures/queue/deque.test.ts | 2 +- .../data-structures/queue/queue.test.ts | 2 +- .../data-structures/stack/stack.test.ts | 4 +- test/performance/reportor.ts | 42 ++++- test/unit/data-structures/heap/heap.test.ts | 42 ++++- test/utils/index.ts | 1 + test/utils/performanc.ts | 7 + 17 files changed, 397 insertions(+), 51 deletions(-) create mode 100644 test/performance/data-structures/comparation.test.ts create mode 100644 test/utils/performanc.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1593cfd..d72fd98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file. - [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - [`auto-changelog`](https://github.com/CookPete/auto-changelog) -## [v1.45.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.45.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/COMMANDS.md b/COMMANDS.md index b1aedba..9a745a4 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -5,12 +5,17 @@ Overview of the commands to test, run and build this project as well as those th ## Most important commands for development - `npm install` Installs all dependencies and creates the folder `node_modules`, that is needed for all following commands. +- `npm run lint` Lint src/ and test/ codebase (using ESLint) +- `npm run format` Pretty src/ and test/ codebase (using Prettier) +- `npm run inspect` Check src/ and test/ codebase (using TSC and ESLint) - `npm run changelog` Update CHANGELOG.md - `npm login` + `npm publish` To publish a new release. Be sure to run npm run package first. ## Commands to test, run and build the project -- `npm test` Run all unit tests (using Jest) with reporting coverage +- `npm test` or `npm run test:unit` Run all unit tests (using Jest) with reporting coverage +- `npm test:perf` Run all performance tests (using Benchmark.js) with reporting results +- `npm run test:perf -- priority-queue.test` Run specific performance test [//]: # (- `npm run coverage-badge` Updates code coverage badge inside `README.md`) - `npm run build:docs` Generates JSDoc Documentation in folder "docs" diff --git a/README.md b/README.md index 1993ffe..bac0803 100644 --- a/README.md +++ b/README.md @@ -734,50 +734,53 @@ optimal approach to data structure design. [//]: # (No deletion!!! Start of Replace Section)
+
comparation
+
test nametime taken (ms)executions per secsample deviation
SRC 10,000 add0.591701.783.28e-5
CJS 10,000 add0.611648.706.98e-5
MJS 10,000 add0.591691.862.44e-5
SRC PQ 10,000 add & pop4.97201.191.37e-4
CJS PQ 10,000 add & pop4.93202.705.60e-5
MJS PQ 10,000 add & pop4.98200.744.39e-4
+
avl-tree
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly33.3429.990.00
10,000 add & delete randomly72.3013.830.00
10,000 addMany49.5020.200.00
10,000 get27.2336.737.19e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly32.2730.990.00
10,000 add & delete randomly73.6713.570.00
10,000 addMany41.8123.920.00
10,000 get29.2134.240.00
binary-tree
-
test nametime taken (ms)executions per secsample deviation
1,000 add randomly12.2081.978.36e-5
1,000 add & delete randomly15.9362.772.09e-4
1,000 addMany10.3696.562.01e-4
1,000 get18.4354.264.67e-4
1,000 dfs154.616.470.00
1,000 bfs57.7317.320.01
1,000 morris258.473.870.00
+
test nametime taken (ms)executions per secsample deviation
1,000 add randomly13.8272.380.00
1,000 add & delete randomly16.0162.455.80e-4
1,000 addMany12.3081.330.01
1,000 get19.7550.630.01
1,000 dfs157.126.360.00
1,000 bfs56.7217.634.27e-4
1,000 morris334.972.990.03
bst
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly29.4433.963.99e-4
10,000 add & delete randomly72.3513.820.00
10,000 addMany29.7633.600.00
10,000 get28.5335.055.76e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly28.3035.340.00
10,000 add & delete randomly67.4714.820.00
10,000 addMany29.2534.180.00
10,000 get30.5332.750.01
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add90.4211.060.01
100,000 add & delete randomly223.524.470.02
100,000 getNode38.6725.860.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add96.6710.340.01
100,000 add & delete randomly224.854.450.01
100,000 getNode40.8324.492.73e-4
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.119499.565.09e-6
1,000 addEdge6.37157.048.13e-4
1,000 getVertex0.052.15e+41.20e-6
1,000 getEdge22.4444.560.00
tarjan213.534.680.01
tarjan all215.754.630.00
topologicalSort175.515.700.01
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.119364.631.25e-5
1,000 addEdge6.18161.781.26e-4
1,000 getVertex0.052.12e+44.19e-6
1,000 getEdge25.9838.500.01
tarjan240.234.160.02
tarjan all227.364.400.00
topologicalSort185.855.380.00
hash-map
-
test nametime taken (ms)executions per secsample deviation
10,000 set0.761308.631.65e-5
10,000 set & get1.03966.592.21e-5
+
test nametime taken (ms)executions per secsample deviation
10,000 set1.001001.311.82e-5
10,000 set & get1.54650.144.87e-5
heap
-
test nametime taken (ms)executions per secsample deviation
10,000 add & pop4.65214.921.18e-4
10,000 fib add & pop367.352.720.01
+
test nametime taken (ms)executions per secsample deviation
10,000 add & pop6.97143.495.27e-4
10,000 fib add & pop378.402.640.05
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift222.804.490.06
1,000,000 unshift & shift174.605.730.04
1,000,000 insertBefore309.213.230.07
+
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift224.554.450.07
1,000,000 unshift & shift182.175.490.06
1,000,000 insertBefore342.632.920.08
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
10,000 push & pop214.754.660.01
10,000 insertBefore250.453.990.01
+
test nametime taken (ms)executions per secsample deviation
10,000 push & pop222.424.500.01
10,000 insertBefore248.394.030.00
max-priority-queue
-
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.4487.431.80e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.8384.551.45e-4
priority-queue
-
test nametime taken (ms)executions per secsample deviation
10,000 add & pop12.4180.571.56e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add & pop10.7992.722.01e-4
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push219.154.560.04
1,000,000 shift26.7637.370.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push231.334.320.06
1,000,000 shift27.6436.170.01
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push45.1722.140.01
1,000,000 push & shift80.4112.440.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push46.1621.660.01
1,000,000 push & shift82.1812.170.00
stack
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push43.6722.900.01
1,000,000 push & pop48.1820.760.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push45.4522.000.01
1,000,000 push & pop50.1019.960.01
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push60.4616.540.00
100,000 getWords83.1312.030.00
+
test nametime taken (ms)executions per secsample deviation
100,000 push46.2521.620.00
100,000 getWords65.1715.340.00
[//]: # (No deletion!!! End of Replace Section) \ No newline at end of file diff --git a/package.json b/package.json index 2c3bacf..d49f2b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.45.0", + "version": "1.45.2", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 5850ba7..0bc2df6 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -305,18 +305,28 @@ export class Heap { * @param index - The index of the newly added element. */ protected bubbleUp(index: number): void { - const element = this.nodes[index]; + // const element = this.nodes[index]; + // while (index > 0) { + // const parentIndex = (index - 1) >> 1; + // const parent = this.nodes[parentIndex]; + // if (this.comparator(element, parent) < 0) { + // this.nodes[index] = parent; + // this.nodes[parentIndex] = element; + // index = parentIndex; + // } else { + // break; + // } + // } + + const item = this.nodes[index]; while (index > 0) { - const parentIndex = Math.floor((index - 1) / 2); - const parent = this.nodes[parentIndex]; - if (this.comparator(element, parent) < 0) { - this.nodes[index] = parent; - this.nodes[parentIndex] = element; - index = parentIndex; - } else { - break; - } + const parent = (index - 1) >> 1; + const parentItem = this.nodes[parent]; + if (this.comparator(parentItem, item) <= 0) break; + this.nodes[index] = parentItem; + index = parent; } + this.nodes[index] = item; } /** @@ -332,8 +342,8 @@ export class Heap { * @param index - The index from which to start sinking. */ protected sinkDown(index: number): void { - const leftChildIndex = 2 * index + 1; - const rightChildIndex = 2 * index + 2; + const leftChildIndex = index << 1 | 1; + const rightChildIndex = leftChildIndex + 1; const length = this.nodes.length; let targetIndex = index; @@ -774,3 +784,117 @@ export class FibonacciHeap { } } } + + +export class CHeap { + + protected _length = 0; + private readonly _priorityQueue: T[] = []; + private readonly _cmp: (x: T, y: T) => number; + + constructor( + cmp: (x: T, y: T) => number = + function (x: T, y: T) { + if (x > y) return -1; + if (x < y) return 1; + return 0; + }, + copy = true + ) { + + this._cmp = cmp; + + } + + clear() { + this._length = 0; + this._priorityQueue.length = 0; + } + + push(item: T) { + this._priorityQueue.push(item); + this._pushUp(this._length); + this._length += 1; + } + + pop() { + if (this._length === 0) return; + const value = this._priorityQueue[0]; + const last = this._priorityQueue.pop()!; + this._length -= 1; + if (this._length) { + this._priorityQueue[0] = last; + this._pushDown(0, this._length >> 1); + } + return value; + } + + top(): T | undefined { + return this._priorityQueue[0]; + } + + find(item: T) { + return this._priorityQueue.indexOf(item) >= 0; + } + + remove(item: T) { + const index = this._priorityQueue.indexOf(item); + if (index < 0) return false; + if (index === 0) { + this.pop(); + } else if (index === this._length - 1) { + this._priorityQueue.pop(); + this._length -= 1; + } else { + this._priorityQueue.splice(index, 1, this._priorityQueue.pop()!); + this._length -= 1; + this._pushUp(index); + this._pushDown(index, this._length >> 1); + } + return true; + } + + updateItem(item: T) { + const index = this._priorityQueue.indexOf(item); + if (index < 0) return false; + this._pushUp(index); + this._pushDown(index, this._length >> 1); + return true; + } + + toArray() { + return [...this._priorityQueue]; + } + + private _pushUp(pos: number) { + const item = this._priorityQueue[pos]; + while (pos > 0) { + const parent = (pos - 1) >> 1; + const parentItem = this._priorityQueue[parent]; + if (this._cmp(parentItem, item) <= 0) break; + this._priorityQueue[pos] = parentItem; + pos = parent; + } + this._priorityQueue[pos] = item; + } + + private _pushDown(pos: number, halfLength: number) { + const item = this._priorityQueue[pos]; + while (pos < halfLength) { + let left = pos << 1 | 1; + const right = left + 1; + let minItem = this._priorityQueue[left]; + if ( + right < this._length && + this._cmp(minItem, this._priorityQueue[right]) > 0 + ) { + left = right; + minItem = this._priorityQueue[right]; + } + if (this._cmp(minItem, item) >= 0) break; + this._priorityQueue[pos] = minItem; + pos = left; + } + this._priorityQueue[pos] = item; + } +} diff --git a/test/performance/data-structures/binary-tree/rb-tree.test.ts b/test/performance/data-structures/binary-tree/rb-tree.test.ts index 40af7ed..ca0dfcc 100644 --- a/test/performance/data-structures/binary-tree/rb-tree.test.ts +++ b/test/performance/data-structures/binary-tree/rb-tree.test.ts @@ -8,7 +8,7 @@ const suite = new Benchmark.Suite(); const rbTree = new RedBlackTree(); const { HUNDRED_THOUSAND } = magnitude; const arr = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND, true); -const competitor = new OrderedMap(); +const cOrderedMap = new OrderedMap(); suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => { rbTree.clear(); @@ -18,9 +18,9 @@ suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => { }); if (isCompetitor) { - suite.add(`${HUNDRED_THOUSAND.toLocaleString()} competitor add`, () => { + suite.add(`${HUNDRED_THOUSAND.toLocaleString()} CPT add`, () => { for (let i = 0; i < arr.length; i++) { - competitor.setElement(arr[i], arr[i]); + cOrderedMap.setElement(arr[i], arr[i]); } }); } diff --git a/test/performance/data-structures/comparation.test.ts b/test/performance/data-structures/comparation.test.ts new file mode 100644 index 0000000..ae7ff99 --- /dev/null +++ b/test/performance/data-structures/comparation.test.ts @@ -0,0 +1,142 @@ +import { PriorityQueue as MJSPriorityQueue } from '../../../dist/cjs'; +import { PriorityQueue as SRCPriorityQueue } from '../../../src'; +import { PriorityQueue as CJSPriorityQueue } from '../../../dist/mjs'; +import { + Deque as CDeque, + HashMap as CHashMap, + LinkList as CLinkedList, + OrderedMap, + PriorityQueue as CPriorityQueue, + Queue as CQueue, + Stack as CStack +} from 'js-sdsl'; + +import * as Benchmark from 'benchmark'; +import { getRandomIntArray, magnitude } from '../../utils'; +import { isCompetitor } from '../../config'; + +const suite = new Benchmark.Suite(); +const { TEN_THOUSAND, HUNDRED_THOUSAND, LINEAR } = magnitude; +const cOrderedMap = new OrderedMap(); +const arrHundredThousand = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND, true); + +suite.add(`SRC ${TEN_THOUSAND.toLocaleString()} add`, () => { + + const pq = new SRCPriorityQueue({ comparator: (a, b) => b - a }); + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); +}).add(`CJS ${TEN_THOUSAND.toLocaleString()} add`, () => { + + const pq = new CJSPriorityQueue({ comparator: (a, b) => b - a }); + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); +}).add(`MJS ${TEN_THOUSAND.toLocaleString()} add`, () => { + + const pq = new MJSPriorityQueue({ comparator: (a, b) => b - a }); + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); +}); + +if (isCompetitor) { + suite.add(`CPT PQ ${TEN_THOUSAND.toLocaleString()} add`, () => { + + const pq = new CPriorityQueue(); + for (let i = 0; i < TEN_THOUSAND; i++) pq.push(i); + }); +} + +suite.add(`SRC PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + const pq = new SRCPriorityQueue({ comparator: (a, b) => b - a }); + + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); + for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); +}).add(`CJS PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + const pq = new CJSPriorityQueue({ comparator: (a, b) => b - a }); + + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); + for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); +}).add(`MJS PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + const pq = new MJSPriorityQueue({ comparator: (a, b) => b - a }); + + for (let i = 0; i < TEN_THOUSAND; i++) pq.add(i); + for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); +}); + + +if (isCompetitor) { + suite.add(`CPT PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + const pq = new CPriorityQueue(); + + for (let i = 0; i < TEN_THOUSAND; i++) pq.push(i); + for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); + }) + .add(`CPT OM ${HUNDRED_THOUSAND.toLocaleString()} add`, () => { + for (let i = 0; i < arrHundredThousand.length; i++) { + cOrderedMap.setElement(arrHundredThousand[i], arrHundredThousand[i]); + } + }) + .add(`CPT HM ${TEN_THOUSAND.toLocaleString()} set`, () => { + const hm = new CHashMap(); + + for (let i = 0; i < TEN_THOUSAND; i++) { + hm.setElement(i, i); + } + }) + .add(`CPT HM ${TEN_THOUSAND.toLocaleString()} set & get`, () => { + const hm = new CHashMap(); + + for (let i = 0; i < TEN_THOUSAND; i++) { + hm.setElement(i, i); + } + for (let i = 0; i < TEN_THOUSAND; i++) { + hm.getElementByKey(i); + } + }) + .add(`CPT LL ${LINEAR.toLocaleString()} unshift`, () => { + const list = new CLinkedList(); + + for (let i = 0; i < LINEAR; i++) { + list.pushFront(i); + } + }) + .add(`CPT PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + const pq = new CPriorityQueue(); + + for (let i = 0; i < TEN_THOUSAND; i++) { + pq.push(i); + } + + for (let i = 0; i < TEN_THOUSAND; i++) { + pq.pop(); + } + }) + .add(`CPT DQ ${LINEAR.toLocaleString()} push`, () => { + const deque = new CDeque(); + for (let i = 0; i < LINEAR; i++) { + deque.pushBack(i); + } + }) + .add(`CPT Q ${LINEAR.toLocaleString()} push`, () => { + const queue = new CQueue(); + + for (let i = 0; i < LINEAR; i++) { + queue.push(i); + } + }) + .add(`CPT ST ${LINEAR.toLocaleString()} push`, () => { + const queue = new CStack(); + + for (let i = 0; i < LINEAR; i++) { + queue.push(i); + } + }) + .add(`CPT ST ${LINEAR.toLocaleString()} push & pop`, () => { + const queue = new CStack(); + + for (let i = 0; i < LINEAR; i++) { + queue.push(i); + } + for (let i = 0; i < LINEAR; i++) { + queue.pop(); + } + }); +} + +export { suite }; diff --git a/test/performance/data-structures/hash/hash-map.test.ts b/test/performance/data-structures/hash/hash-map.test.ts index f8adfde..b98890f 100644 --- a/test/performance/data-structures/hash/hash-map.test.ts +++ b/test/performance/data-structures/hash/hash-map.test.ts @@ -15,7 +15,7 @@ suite.add(`${TEN_THOUSAND.toLocaleString()} set`, () => { } }); if (isCompetitor) { - suite.add(`${TEN_THOUSAND.toLocaleString()} competitor set`, () => { + suite.add(`${TEN_THOUSAND.toLocaleString()} CPT set`, () => { const hm = new CHashMap(); for (let i = 0; i < TEN_THOUSAND; i++) { @@ -34,7 +34,7 @@ suite.add(`${TEN_THOUSAND.toLocaleString()} set & get`, () => { } }); if (isCompetitor) { - suite.add(`${TEN_THOUSAND.toLocaleString()} competitor set & get`, () => { + suite.add(`${TEN_THOUSAND.toLocaleString()} CPT set & get`, () => { const hm = new CHashMap(); for (let i = 0; i < TEN_THOUSAND; i++) { diff --git a/test/performance/data-structures/linked-list/doubly-linked-list.test.ts b/test/performance/data-structures/linked-list/doubly-linked-list.test.ts index 2289343..b52fc6d 100644 --- a/test/performance/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/performance/data-structures/linked-list/doubly-linked-list.test.ts @@ -15,7 +15,7 @@ suite.add(`${LINEAR.toLocaleString()} unshift`, () => { } }); if (isCompetitor) { - suite.add(`${LINEAR.toLocaleString()} competitor unshift`, () => { + suite.add(`${LINEAR.toLocaleString()} CPT unshift`, () => { const list = new CLinkedList(); for (let i = 0; i < LINEAR; i++) { diff --git a/test/performance/data-structures/priority-queue/priority-queue.test.ts b/test/performance/data-structures/priority-queue/priority-queue.test.ts index cd54e4b..84c58b5 100644 --- a/test/performance/data-structures/priority-queue/priority-queue.test.ts +++ b/test/performance/data-structures/priority-queue/priority-queue.test.ts @@ -19,7 +19,7 @@ suite.add(`${TEN_THOUSAND.toLocaleString()} add & pop`, () => { } }); if (isCompetitor) { - suite.add(`${TEN_THOUSAND.toLocaleString()} competitor add & pop`, () => { + suite.add(`${TEN_THOUSAND.toLocaleString()} CPT add & pop`, () => { const pq = new CPriorityQueue(); for (let i = 0; i < TEN_THOUSAND; i++) { diff --git a/test/performance/data-structures/queue/deque.test.ts b/test/performance/data-structures/queue/deque.test.ts index 526174a..dddad4e 100644 --- a/test/performance/data-structures/queue/deque.test.ts +++ b/test/performance/data-structures/queue/deque.test.ts @@ -14,7 +14,7 @@ suite.add(`${LINEAR.toLocaleString()} push`, () => { } }); if (isCompetitor) { - suite.add(`${LINEAR.toLocaleString()} competitor push`, () => { + suite.add(`${LINEAR.toLocaleString()} CPT push`, () => { const deque = new CDeque(); for (let i = 0; i < LINEAR; i++) { deque.pushBack(i); diff --git a/test/performance/data-structures/queue/queue.test.ts b/test/performance/data-structures/queue/queue.test.ts index f2a2165..f1545b6 100644 --- a/test/performance/data-structures/queue/queue.test.ts +++ b/test/performance/data-structures/queue/queue.test.ts @@ -15,7 +15,7 @@ suite.add(`${LINEAR.toLocaleString()} push`, () => { } }); if (isCompetitor) { - suite.add(`${LINEAR.toLocaleString()} competitor push`, () => { + suite.add(`${LINEAR.toLocaleString()} CPT push`, () => { const queue = new CQueue(); for (let i = 0; i < LINEAR; i++) { diff --git a/test/performance/data-structures/stack/stack.test.ts b/test/performance/data-structures/stack/stack.test.ts index d1aac39..e4a2742 100644 --- a/test/performance/data-structures/stack/stack.test.ts +++ b/test/performance/data-structures/stack/stack.test.ts @@ -15,7 +15,7 @@ suite.add(`${LINEAR.toLocaleString()} push`, () => { } }); if (isCompetitor) { - suite.add(`${LINEAR.toLocaleString()} competitor push`, () => { + suite.add(`${LINEAR.toLocaleString()} CPT push`, () => { const queue = new CStack(); for (let i = 0; i < LINEAR; i++) { @@ -34,7 +34,7 @@ suite.add(`${LINEAR.toLocaleString()} push & pop`, () => { } }); if (isCompetitor) { - suite.add(`${LINEAR.toLocaleString()} competitor push & pop`, () => { + suite.add(`${LINEAR.toLocaleString()} CPT push & pop`, () => { const queue = new CStack(); for (let i = 0; i < LINEAR; i++) { diff --git a/test/performance/reportor.ts b/test/performance/reportor.ts index 1013406..447fa87 100644 --- a/test/performance/reportor.ts +++ b/test/performance/reportor.ts @@ -5,18 +5,46 @@ import * as fastGlob from 'fast-glob'; import { Color, numberFix, render } from '../utils'; import { PerformanceTest } from './types'; + +const args = process.argv.slice(2); + +const { GREEN, BOLD, END, YELLOW, GRAY, CYAN, BG_YELLOW } = Color; + +const getRelativePath = (file: string) => { + return path.relative(__dirname, file); +} +const coloredLabeled = (label: string, file: string) => { + const relativeFilePath = getRelativePath(file); + const directory = path.dirname(relativeFilePath); + const fileName = path.basename(relativeFilePath); + return `${BG_YELLOW} ${label} ${END} ${GRAY}${directory}/${END}${CYAN}${fileName}${END}`; +} + const parentDirectory = path.resolve(__dirname, '../..'); const reportDistPath = path.join(parentDirectory, 'benchmark'); const testDir = path.join(__dirname, 'data-structures'); -const testFiles = fastGlob.sync(path.join(testDir, '**', '*.test.ts')); +const allFiles = fastGlob.sync(path.join(testDir, '**', '*.test.ts')); +let testFiles: string[] = []; +if (args.length > 0) { + console.log(`arguments: ${args.join(' ')}`) + + testFiles = allFiles.filter(file => + args.every(word => file.includes(word)) + ); + + console.log(`${testFiles.map(file => coloredLabeled('Matched', file)).join(` +`)}`); +} else { + testFiles = allFiles; +} + const report: { [key: string]: any } = {}; let completedCount = 0; const performanceTests: PerformanceTest[] = []; -const { GREEN, BOLD, END, YELLOW, GRAY, CYAN, BG_YELLOW } = Color; testFiles.forEach((file: string) => { const testName = path.basename(file, '.test.ts'); @@ -107,7 +135,7 @@ const composeReport = () => { htmlTables // New content to be inserted ); fs.writeFileSync(htmlFilePath, html); - console.log(`Performance ${BOLD}${GREEN}report${END} file generated in ${BOLD}${GREEN}${reportDistPath}${END}`); + console.log(`Performance ${BOLD}${GREEN}report${END} file generated in file://${BOLD}${GREEN}${htmlFilePath}${END}`); }; function replaceMarkdownContent(startMarker: string, endMarker: string, newText: string) { @@ -135,7 +163,7 @@ function replaceMarkdownContent(startMarker: string, endMarker: string, newText: if (err) { console.error(`Unable to write to ${filePath}:`, err); } else { - console.log(`The content has been successfully replaced in ${BOLD}${GREEN}${filePath}!${END}`); + console.log(`The content has been successfully replaced in file://${BOLD}${GREEN}${filePath}${END}`); } }); }); @@ -143,10 +171,8 @@ function replaceMarkdownContent(startMarker: string, endMarker: string, newText: performanceTests.forEach(item => { const { suite, testName, file } = item; - const relativeFilePath = path.relative(__dirname, file); - const directory = path.dirname(relativeFilePath); - const fileName = path.basename(relativeFilePath); - console.log(`${BG_YELLOW} Running ${END} ${GRAY}${directory}/${END}${CYAN}${fileName}${END}`); + + console.log(coloredLabeled('Running', file)); if (suite) { let runTime = 0; diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index accab1c..8e625f2 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -1,5 +1,5 @@ -import { FibonacciHeap, MaxHeap, MinHeap } from '../../../../src'; -import { logBigOMetricsWrap } from '../../../utils'; +import { CHeap, FibonacciHeap, MaxHeap, MinHeap } from '../../../../src'; +import { calcRunTime, logBigOMetricsWrap } from '../../../utils'; describe('Heap Operation Test', () => { it('should numeric heap work well', function () { @@ -257,3 +257,41 @@ describe('FibonacciHeap Stress Test', () => { ); }); }); + +// describe('Competitor performance compare', () => { +// const minHeap = new MinHeap(); +// const cHeap = new CHeap(); +// const cPQ = new PriorityQueue(undefined, (a, b) => a - b); +// const n = 10000; +// +// it('should add performance well', () => { +// const heapCost = calcRunTime(() => { +// for (let i = 0; i < n; i++) { +// minHeap.add(i); +// } +// }) +// +// console.log(`heapCost: ${heapCost}`) +// }); +// +// it('should add performance well', () => { +// +// const cHeapCost = calcRunTime(() => { +// for (let i = 0; i < n; i++) { +// cHeap.push(i); +// } +// }) +// +// console.log(`cHeapCost: ${cHeapCost}`) +// }); +// +// it('should add performance well', () => { +// +// const cPQCost = calcRunTime(() => { +// for (let i = 0; i < n; i++) { +// cPQ.push(i); +// } +// }) +// console.log(`cPQCost: ${cPQCost}`) +// }); +// }); diff --git a/test/utils/index.ts b/test/utils/index.ts index 97be71e..6f522c4 100644 --- a/test/utils/index.ts +++ b/test/utils/index.ts @@ -5,3 +5,4 @@ export * from './json2html'; export * from './is'; export * from './console'; export * from './string'; +export * from './performanc'; diff --git a/test/utils/performanc.ts b/test/utils/performanc.ts new file mode 100644 index 0000000..ea74095 --- /dev/null +++ b/test/utils/performanc.ts @@ -0,0 +1,7 @@ +import { performance } from 'perf_hooks'; + +export const calcRunTime = (callback: (...args: any[]) => any) => { + const startTime = performance.now(); + callback(); + return performance.now() - startTime; +} \ No newline at end of file