1
- import fs from 'node:fs' ;
2
-
1
+ /* eslint-disable no-invalid-this */
2
+ import Benchmark from 'benchmark' ;
3
3
import { Matrix } from 'ml-matrix' ;
4
4
5
- import { SparseMatrix } from '../src/index.js' ;
6
-
7
5
import { SparseMatrix as SparseMatrixOld } from './class/SparseMatrixOld.js' ;
8
-
9
- function randomSparseMatrix ( rows , cols , density = 0.01 ) {
10
- const matrix = [ ] ;
11
- for ( let i = 0 ; i < rows ; i ++ ) {
12
- const row = new Array ( cols ) . fill ( 0 ) ;
13
- for ( let j = 0 ; j < cols ; j ++ ) {
14
- if ( Math . random ( ) < density ) {
15
- row [ j ] = Math . random ( ) * 10 ;
16
- }
17
- }
18
- matrix . push ( row ) ;
19
- }
20
- return new SparseMatrix ( matrix ) ;
21
- }
22
-
23
- function benchmark ( fn , label , iterations = 5 ) {
24
- const times = [ ] ;
25
- for ( let i = 0 ; i < iterations ; i ++ ) {
26
- const t0 = performance . now ( ) ;
27
- fn ( ) ;
28
- const t1 = performance . now ( ) ;
29
- times . push ( t1 - t0 ) ;
30
- }
31
- const avg = times . reduce ( ( a , b ) => a + b , 0 ) / times . length ;
32
- console . log ( `${ label } : avg ${ avg . toFixed ( 2 ) } ms over ${ iterations } runs` ) ;
33
- return avg ;
34
- }
35
-
36
- function printWinner ( label1 , avg1 , label2 , avg2 ) {
37
- let winner , loser , win , lose ;
38
- if ( avg1 < avg2 ) {
39
- winner = label1 ;
40
- win = avg1 ;
41
- loser = label2 ;
42
- lose = avg2 ;
43
- } else {
44
- winner = label2 ;
45
- win = avg2 ;
46
- loser = label1 ;
47
- lose = avg1 ;
48
- }
49
-
50
- const percent = ( ( lose - win ) / lose ) * 100 ;
51
- console . log (
52
- ` -> ${ winner } was ${ ( lose / win ) . toFixed ( 2 ) } x faster (${ percent . toFixed (
53
- 1 ,
54
- ) } % faster) than ${ loser } \n`,
55
- ) ;
56
- }
6
+ import { printWinner } from './utils/printWinner.js' ;
7
+ import { randomSparseMatrix } from './utils/randomSparseMatrix.js' ;
57
8
58
9
function runBenchmarks ( ) {
59
- const m = 128 ;
60
- const n = 128 ;
61
- const p = 128 ;
10
+ const m = 256 ;
11
+ const n = 256 ;
12
+ const p = 256 ;
62
13
const densityA = 0.01 ;
63
14
const densityB = 0.01 ;
64
15
65
- const nbIterations = 3 ;
66
16
const A = randomSparseMatrix ( m , n , densityA ) ;
67
17
const B = randomSparseMatrix ( n , p , densityB ) ;
68
18
@@ -75,138 +25,103 @@ function runBenchmarks() {
75
25
denseA = new Matrix ( denseA ) ;
76
26
denseB = new Matrix ( denseB ) ;
77
27
78
- denseA . mmul ( denseB ) ;
79
- // 1. add vs addNew
80
- // const addAvg = benchmark(() => {
81
- // const a = AOld.clone();
82
- // a.add(BOld);
83
- // }, 'add');
84
-
85
- // const addNewAvg = benchmark(() => {
86
- // const a = A.clone();
87
- // a.add(B);
88
- // }, 'addNew');
28
+ const results = [ ] ;
89
29
90
- // printWinner('add', addAvg, 'addNew', addNewAvg);
30
+ // 1. add vs addNew
31
+ const addSuite = new Benchmark . Suite ( 'add' ) ;
32
+ addSuite
33
+ . add ( 'add' , ( ) => {
34
+ const a = AOld . clone ( ) ;
35
+ a . add ( BOld ) ;
36
+ } )
37
+ . add ( 'addNew' , ( ) => {
38
+ const a = A . clone ( ) ;
39
+ a . add ( B ) ;
40
+ } )
41
+ . add ( 'addDense' , ( ) => {
42
+ const a = denseA . clone ( ) ;
43
+ a . add ( denseB ) ;
44
+ } )
45
+ . on ( 'cycle' , ( event ) => {
46
+ console . log ( String ( event . target ) ) ;
47
+ } )
48
+ . on ( 'complete' , function onComplete ( ) {
49
+ const fastest = this . filter ( 'fastest' ) . map ( 'name' ) ;
50
+ this . forEach ( ( bench ) => {
51
+ results . push ( { label : bench . name , avg : 1000 / bench . hz } ) ;
52
+ } ) ;
53
+ printWinner ( results ) ;
54
+ } )
55
+ . run ( { async : false } ) ;
91
56
92
57
// 2. mmul vs mmulNew
93
-
94
- const mmulNewAvg = benchmark (
95
- ( ) => {
58
+ const mmulSuite = new Benchmark . Suite ( 'mmul' ) ;
59
+ mmulSuite
60
+ . add ( 'mmulNew' , ( ) => {
96
61
A . mmul ( B ) ;
97
- } ,
98
- 'mmulNew' ,
99
- nbIterations ,
100
- ) ;
101
-
102
- const mmulAvg = benchmark (
103
- ( ) => {
62
+ } )
63
+ . add ( 'mmul' , ( ) => {
104
64
AOld . mmul ( BOld ) ;
105
- } ,
106
- 'mmul' ,
107
- nbIterations ,
108
- ) ;
109
-
110
- const denseAvg = benchmark (
111
- ( ) => {
65
+ } )
66
+ . add ( 'denseMatrix' , ( ) => {
112
67
denseA . mmul ( denseB ) ;
113
- } ,
114
- 'denseMatrix' ,
115
- nbIterations ,
116
- ) ;
117
-
118
- printWinner ( 'mmul' , mmulAvg , 'mmulNew' , mmulNewAvg ) ;
68
+ } )
69
+ . on ( 'cycle' , ( event ) => {
70
+ console . log ( String ( event . target ) ) ;
71
+ } )
72
+ . on ( 'complete' , function onComplete ( ) {
73
+ const mmulResults = [ ] ;
74
+ this . forEach ( ( bench ) => {
75
+ mmulResults . push ( { label : bench . name , avg : 1000 / bench . hz } ) ;
76
+ } ) ;
77
+ printWinner ( mmulResults ) ;
78
+ } )
79
+ . run ( { async : false } ) ;
119
80
120
81
// 3. kroneckerProduct vs kroneckerProductNew
121
- // const kronNewAvg = benchmark(() => {
122
- // A.kroneckerProduct(B);
123
- // }, 'kroneckerProductNew');
124
- // const kronAvg = benchmark(() => {
125
- // AOld.kroneckerProduct(BOld);
126
- // }, 'kroneckerProduct');
127
-
128
- // printWinner('kroneckerProduct', kronAvg, 'kroneckerProductNew', kronNewAvg);
82
+ const kronSuite = new Benchmark . Suite ( 'kroneckerProduct' ) ;
83
+ kronSuite
84
+ . add ( 'kroneckerProductNew' , ( ) => {
85
+ A . kroneckerProduct ( B ) ;
86
+ } )
87
+ . add ( 'kroneckerProduct' , ( ) => {
88
+ AOld . kroneckerProduct ( BOld ) ;
89
+ } )
90
+ . add ( 'kroneckerProductDense' , ( ) => {
91
+ denseA . kroneckerProduct ( denseB ) ;
92
+ } )
93
+ . on ( 'cycle' , ( event ) => {
94
+ console . log ( String ( event . target ) ) ;
95
+ } )
96
+ . on ( 'complete' , function onComplete ( ) {
97
+ const kronResults = [ ] ;
98
+ this . forEach ( ( bench ) => {
99
+ kronResults . push ( { label : bench . name , avg : 1000 / bench . hz } ) ;
100
+ } ) ;
101
+ printWinner ( kronResults ) ;
102
+ } )
103
+ . run ( { async : false } ) ;
129
104
130
105
// 4. matrix multiplication
131
- // const mulAvg = benchmark(() => {
132
- // A.mul(5);
133
- // }, 'mul');
134
-
135
- // const mulNewAvg = benchmark(() => {
136
- // AOld.mul(5);
137
- // }, 'mulNew');
138
-
139
- // printWinner('mul', mulAvg, 'mulNew', mulNewAvg);
140
- }
141
-
142
- function runSizeSweepBenchmark ( ) {
143
- const sizes = [ 8 , 16 , 32 , 64 , 128 ] ;
144
- const densities = [ 0.01 , 0.015 , 0.02 , 0.025 , 0.03 , 0.35 ] ;
145
- const results = [ ] ;
146
-
147
- for ( const densityA of densities ) {
148
- for ( const densityB of densities ) {
149
- for ( const m of sizes ) {
150
- for ( const n of sizes ) {
151
- for ( const p of sizes ) {
152
- // A: m x n, B: n x p
153
-
154
- const A = randomSparseMatrix ( m , n , densityA ) ;
155
- const B = randomSparseMatrix ( n , p , densityB ) ;
156
-
157
- let denseA = A . to2DArray ( ) ;
158
- let denseB = B . to2DArray ( ) ;
159
-
160
- const AOld = new SparseMatrixOld ( denseA ) ;
161
- const BOld = new SparseMatrixOld ( denseB ) ;
162
-
163
- denseA = new Matrix ( denseA ) ;
164
- denseB = new Matrix ( denseB ) ;
165
-
166
- const mmulNewAvg = benchmark (
167
- ( ) => {
168
- A . mmul ( B ) ;
169
- } ,
170
- 'mmulNew' ,
171
- 3 ,
172
- ) ;
173
-
174
- const mmulAvg = benchmark (
175
- ( ) => {
176
- AOld . mmul ( BOld ) ;
177
- } ,
178
- 'mmul' ,
179
- 3 ,
180
- ) ;
181
-
182
- const denseAvg = benchmark (
183
- ( ) => denseA . mmul ( denseB ) ,
184
- 'denseMatrix' ,
185
- 3 ,
186
- ) ;
187
-
188
- results . push ( {
189
- densityA,
190
- densityB,
191
- aShape : [ m , n ] ,
192
- bShape : [ n , p ] ,
193
- dense : denseAvg ,
194
- mmulNew : mmulNewAvg ,
195
- mmul : mmulAvg ,
196
- } ) ;
197
- }
198
- }
199
- }
200
- }
201
- }
202
-
203
- fs . writeFileSync (
204
- './benchmark/size_sweep_results-dense.json' ,
205
- JSON . stringify ( results , null , 2 ) ,
206
- ) ;
207
- console . log ( 'Size sweep benchmark results saved to size_sweep_results.json' ) ;
106
+ const mulSuite = new Benchmark . Suite ( 'mul' ) ;
107
+ mulSuite
108
+ . add ( 'mul' , ( ) => {
109
+ A . mul ( 5 ) ;
110
+ } )
111
+ . add ( 'mulNew' , ( ) => {
112
+ AOld . mul ( 5 ) ;
113
+ } )
114
+ . on ( 'cycle' , ( event ) => {
115
+ console . log ( String ( event . target ) ) ;
116
+ } )
117
+ . on ( 'complete' , function onComplete ( ) {
118
+ const mulResults = [ ] ;
119
+ this . forEach ( ( bench ) => {
120
+ mulResults . push ( { label : bench . name , avg : 1000 / bench . hz } ) ;
121
+ } ) ;
122
+ printWinner ( mulResults ) ;
123
+ } )
124
+ . run ( { async : false } ) ;
208
125
}
209
126
210
127
runBenchmarks ( ) ;
211
- // Uncomment to run the size sweep benchmark
212
- // runSizeSweepBenchmark();
0 commit comments