Skip to content

Commit 72db1dd

Browse files
committed
chore: simple benchmark run
1 parent 09d0a98 commit 72db1dd

File tree

1 file changed

+91
-190
lines changed

1 file changed

+91
-190
lines changed

benchmark/benchmark.js

Lines changed: 91 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,8 @@
1-
import { SparseMatrix } from '../src/index.js';
1+
import Benchmark from 'benchmark';
22
import { Matrix } from 'ml-matrix';
33
import { SparseMatrix as SparseMatrixOld } from './class/SparseMatrixOld.js';
4-
// import { SparseMatrix as SparseMatrixOld } from '../src/Elements.js';
5-
import fs from 'fs';
6-
7-
function randomSparseMatrix(rows, cols, density = 0.01) {
8-
const total = rows * cols;
9-
const cardinality = Math.round(total * density);
10-
const positions = new Set();
11-
12-
// Generate unique random positions
13-
while (positions.size < cardinality) {
14-
positions.add(Math.floor(Math.random() * total));
15-
}
16-
17-
// Build the matrix with zeros
18-
const matrix = Array.from({ length: rows }, () => new Float64Array(cols));
19-
20-
// Assign random values to the selected positions
21-
for (const pos of positions) {
22-
const i = Math.floor(pos / cols);
23-
const j = pos % cols;
24-
matrix[i][j] = Math.random() * 10;
25-
}
26-
27-
return new SparseMatrix(matrix);
28-
}
29-
30-
function benchmark(fn, label, iterations = 5, logIt = false) {
31-
const times = [];
32-
for (let i = 0; i < iterations; i++) {
33-
const t0 = performance.now();
34-
fn();
35-
const t1 = performance.now();
36-
times.push(t1 - t0);
37-
}
38-
const avg = times.reduce((a, b) => a + b, 0) / times.length;
39-
if (logIt) {
40-
console.log(`${label}: avg ${avg.toFixed(2)} ms over ${iterations} runs`);
41-
}
42-
return avg;
43-
}
44-
45-
function printWinner(label1, avg1, label2, avg2) {
46-
let winner, loser, win, lose;
47-
if (avg1 < avg2) {
48-
winner = label1;
49-
win = avg1;
50-
loser = label2;
51-
lose = avg2;
52-
} else {
53-
winner = label2;
54-
win = avg2;
55-
loser = label1;
56-
lose = avg1;
57-
}
58-
59-
const percent = ((lose - win) / lose) * 100;
60-
console.log(
61-
` -> ${winner} was ${(lose / win).toFixed(2)}x faster (${percent.toFixed(
62-
1,
63-
)}% faster) than ${loser}\n`,
64-
);
65-
}
4+
import { randomSparseMatrix } from './utils/randomSparseMatrix.js';
5+
import { printWinner } from './utils/printWinner.js';
666

677
function runBenchmarks() {
688
const m = 256;
@@ -71,7 +11,6 @@ function runBenchmarks() {
7111
const densityA = 0.01;
7212
const densityB = 0.01;
7313

74-
const nbIterations = 3;
7514
const A = randomSparseMatrix(m, n, densityA);
7615
const B = randomSparseMatrix(n, p, densityB);
7716

@@ -84,141 +23,103 @@ function runBenchmarks() {
8423
denseA = new Matrix(denseA);
8524
denseB = new Matrix(denseB);
8625

87-
denseA.mmul(denseB);
88-
// 1. add vs addNew
89-
// const addAvg = benchmark(() => {
90-
// const a = AOld.clone();
91-
// a.add(BOld);
92-
// }, 'add');
93-
94-
// const addNewAvg = benchmark(() => {
95-
// const a = A.clone();
96-
// a.add(B);
97-
// }, 'addNew');
26+
const results = [];
9827

99-
// printWinner('add', addAvg, 'addNew', addNewAvg);
28+
// 1. add vs addNew
29+
const addSuite = new Benchmark.Suite('add');
30+
addSuite
31+
.add('add', function () {
32+
const a = AOld.clone();
33+
a.add(BOld);
34+
})
35+
.add('addNew', function () {
36+
const a = A.clone();
37+
a.add(B);
38+
})
39+
.add('addDense', function () {
40+
const a = denseA.clone();
41+
a.add(denseB);
42+
})
43+
.on('cycle', function (event) {
44+
console.log(String(event.target));
45+
})
46+
.on('complete', function () {
47+
const fastest = this.filter('fastest').map('name');
48+
this.forEach((bench) => {
49+
results.push({ label: bench.name, avg: 1000 / bench.hz });
50+
});
51+
printWinner(results);
52+
})
53+
.run({ async: false });
10054

10155
// 2. mmul vs mmulNew
102-
103-
const mmulNewAvg = benchmark(
104-
() => {
56+
const mmulSuite = new Benchmark.Suite('mmul');
57+
mmulSuite
58+
.add('mmulNew', function () {
10559
A.mmul(B);
106-
},
107-
'mmulNew',
108-
nbIterations,
109-
);
110-
111-
const mmulAvg = benchmark(
112-
() => {
60+
})
61+
.add('mmul', function () {
11362
AOld.mmul(BOld);
114-
},
115-
'mmul',
116-
nbIterations,
117-
);
118-
119-
const denseAvg = benchmark(
120-
() => {
63+
})
64+
.add('denseMatrix', function () {
12165
denseA.mmul(denseB);
122-
},
123-
'denseMatrix',
124-
nbIterations,
125-
);
126-
127-
printWinner('mmul', mmulAvg, 'mmulNew', mmulNewAvg);
66+
})
67+
.on('cycle', function (event) {
68+
console.log(String(event.target));
69+
})
70+
.on('complete', function () {
71+
const mmulResults = [];
72+
this.forEach((bench) => {
73+
mmulResults.push({ label: bench.name, avg: 1000 / bench.hz });
74+
});
75+
printWinner(mmulResults);
76+
})
77+
.run({ async: false });
12878

12979
// 3. kroneckerProduct vs kroneckerProductNew
130-
// const kronNewAvg = benchmark(() => {
131-
// A.kroneckerProduct(B);
132-
// }, 'kroneckerProductNew');
133-
// const kronAvg = benchmark(() => {
134-
// AOld.kroneckerProduct(BOld);
135-
// }, 'kroneckerProduct');
136-
137-
// printWinner('kroneckerProduct', kronAvg, 'kroneckerProductNew', kronNewAvg);
80+
const kronSuite = new Benchmark.Suite('kroneckerProduct');
81+
kronSuite
82+
.add('kroneckerProductNew', function () {
83+
A.kroneckerProduct(B);
84+
})
85+
.add('kroneckerProduct', function () {
86+
AOld.kroneckerProduct(BOld);
87+
})
88+
.add('kroneckerProductDense', function () {
89+
denseA.kroneckerProduct(denseB);
90+
})
91+
.on('cycle', function (event) {
92+
console.log(String(event.target));
93+
})
94+
.on('complete', function () {
95+
const kronResults = [];
96+
this.forEach((bench) => {
97+
kronResults.push({ label: bench.name, avg: 1000 / bench.hz });
98+
});
99+
printWinner(kronResults);
100+
})
101+
.run({ async: false });
138102

139103
// 4. matrix multiplication
140-
// const mulAvg = benchmark(() => {
141-
// A.mul(5);
142-
// }, 'mul');
143-
144-
// const mulNewAvg = benchmark(() => {
145-
// AOld.mul(5);
146-
// }, 'mulNew');
147-
148-
// printWinner('mul', mulAvg, 'mulNew', mulNewAvg);
149-
}
150-
151-
function runSizeSweepBenchmark() {
152-
const nbIterations = 3;
153-
const sizes = [32, 64, 128, 256];
154-
const densities = [0.01, 0.015, 0.02, 0.025, 0.03];
155-
const results = [];
156-
157-
for (const densityA of densities) {
158-
for (const densityB of densities) {
159-
for (const m of sizes) {
160-
for (const n of sizes) {
161-
for (const p of sizes) {
162-
// A: m x n, B: n x p
163-
164-
const A = randomSparseMatrix(m, n, densityA);
165-
const B = randomSparseMatrix(n, p, densityB);
166-
167-
let denseA = A.to2DArray();
168-
let denseB = B.to2DArray();
169-
170-
const AOld = new SparseMatrixOld(denseA);
171-
const BOld = new SparseMatrixOld(denseB);
172-
173-
denseA = new Matrix(denseA);
174-
denseB = new Matrix(denseB);
175-
176-
const mmulNewAvg = benchmark(
177-
() => {
178-
A.mmul(B);
179-
},
180-
'mmulNew',
181-
nbIterations,
182-
);
183-
184-
const mmulAvg = benchmark(
185-
() => {
186-
AOld.mmul(BOld);
187-
},
188-
'mmul',
189-
nbIterations,
190-
);
191-
192-
const denseAvg = benchmark(
193-
() => {
194-
denseA.mmul(denseB);
195-
},
196-
'denseMatrix',
197-
nbIterations,
198-
);
199-
200-
results.push({
201-
densityA,
202-
densityB,
203-
A_shape: [m, n],
204-
B_shape: [n, p],
205-
dense: denseAvg,
206-
new: mmulNewAvg,
207-
old: mmulAvg,
208-
});
209-
}
210-
}
211-
}
212-
}
213-
}
214-
215-
fs.writeFileSync(
216-
'./benchmark/size_sweep_results-dense.json',
217-
JSON.stringify(results, null, 2),
218-
);
219-
console.log('Size sweep benchmark results saved to size_sweep_results.json');
104+
const mulSuite = new Benchmark.Suite('mul');
105+
mulSuite
106+
.add('mul', function () {
107+
A.mul(5);
108+
})
109+
.add('mulNew', function () {
110+
AOld.mul(5);
111+
})
112+
.on('cycle', function (event) {
113+
console.log(String(event.target));
114+
})
115+
.on('complete', function () {
116+
const mulResults = [];
117+
this.forEach((bench) => {
118+
mulResults.push({ label: bench.name, avg: 1000 / bench.hz });
119+
});
120+
printWinner(mulResults);
121+
})
122+
.run({ async: false });
220123
}
221124

222-
// runBenchmarks();
223-
// Uncomment to run the size sweep benchmark
224-
runSizeSweepBenchmark();
125+
runBenchmarks();

0 commit comments

Comments
 (0)