1+ // https://gist.github.com/evanwashere/7ee592870e46f80405b9776dcd56e1e8#file-bench-js
2+
3+ const now = performance . now . bind ( performance ) ;
4+
5+ function sort ( a , b ) {
6+ if ( a > b ) return 1 ;
7+ if ( a < b ) return - 1 ;
8+
9+ return 0 ;
10+ } ;
11+
12+ function stats ( n , avg , min , max , jit , all ) {
13+ return {
14+ min : Math . ceil ( min * 1e6 ) ,
15+ max : Math . ceil ( max * 1e6 ) ,
16+ avg : Math . ceil ( avg / n * 1e6 ) ,
17+ jit : jit . map ( x => Math . ceil ( x * 1e6 ) ) ,
18+ '50th' : Math . ceil ( 1e6 * all [ Math . ceil ( n * ( 50 / 100 ) ) - 1 ] ) ,
19+ '75th' : Math . ceil ( 1e6 * all [ Math . ceil ( n * ( 75 / 100 ) ) - 1 ] ) ,
20+ '99th' : Math . ceil ( 1e6 * all [ Math . ceil ( n * ( 99 / 100 ) ) - 1 ] ) ,
21+ '99.5th' : Math . ceil ( 1e6 * all [ Math . ceil ( n * ( 99.5 / 100 ) ) - 1 ] ) ,
22+ '99.9th' : Math . ceil ( 1e6 * all [ Math . ceil ( n * ( 99.9 / 100 ) ) - 1 ] ) ,
23+ } ;
24+ }
25+
26+ export function sync ( n , fn ) {
27+ let avg = 0 ;
28+ let min = Infinity ;
29+ let max = - Infinity ;
30+ const all = new Array ( n ) ;
31+ const jit = new Array ( 10 ) ;
32+
33+ warmup: {
34+ let offset = 0 ;
35+ let iterations = 10 ;
36+ while ( iterations -- ) {
37+ const t1 = now ( ) ;
38+
39+ fn ( ) ;
40+ jit [ offset ++ ] = now ( ) - t1 ;
41+ }
42+
43+ iterations = 1e3 - 10 ;
44+ while ( iterations -- ) fn ( ) ;
45+ }
46+
47+ measure: {
48+ let offset = 0 ;
49+ let iterations = n ;
50+ while ( iterations -- ) {
51+ const t1 = now ( ) ;
52+
53+ fn ( ) ;
54+ const t2 = now ( ) - t1 ;
55+ if ( t2 < min ) min = t2 ;
56+ if ( t2 > max ) max = t2 ;
57+ avg += ( all [ offset ++ ] = t2 ) ;
58+ }
59+ }
60+
61+ all . sort ( sort ) ;
62+ return stats ( n , avg , min , max , jit , all ) ;
63+ }
64+
65+ export async function async ( n , fn ) {
66+ let avg = 0 ;
67+ let min = Infinity ;
68+ let max = - Infinity ;
69+ const all = new Array ( n ) ;
70+ const jit = new Array ( 10 ) ;
71+
72+ warmup: {
73+ let offset = 0 ;
74+ let iterations = 10 ;
75+ while ( iterations -- ) {
76+ const t1 = now ( ) ;
77+
78+ await fn ( ) ;
79+ jit [ offset ++ ] = now ( ) - t1 ;
80+ }
81+
82+ iterations = 1e3 - 10 ;
83+ while ( iterations -- ) await fn ( ) ;
84+ }
85+
86+ measure: {
87+ let offset = 0 ;
88+ let iterations = n ;
89+ while ( iterations -- ) {
90+ const t1 = now ( ) ;
91+
92+ await fn ( ) ;
93+ const t2 = now ( ) - t1 ;
94+ if ( t2 < min ) min = t2 ;
95+ if ( t2 > max ) max = t2 ;
96+ avg += ( all [ offset ++ ] = t2 ) ;
97+ }
98+ }
99+
100+ all . sort ( sort ) ;
101+ return stats ( n , avg , min , max , jit , all ) ;
102+ }
103+
104+ export function format ( { results, title = '' , unit = 'ns' , percentiles = true } ) {
105+ const h = '─' ;
106+ const v = '│' ;
107+
108+ let s = '' ;
109+ unit = `${ unit } /iter` ;
110+ const rk = Object . keys ( results ) ;
111+ const rv = Object . values ( results ) ;
112+ const ra = rv . map ( x => x . avg . toLocaleString ( 'en-us' ) ) ;
113+ const r50 = rv . map ( x => x [ '50th' ] . toLocaleString ( 'en-us' ) ) ;
114+ const r75 = rv . map ( x => x [ '75th' ] . toLocaleString ( 'en-us' ) ) ;
115+ const r99 = rv . map ( x => x [ '99th' ] . toLocaleString ( 'en-us' ) ) ;
116+ const r995 = rv . map ( x => x [ '99.5th' ] . toLocaleString ( 'en-us' ) ) ;
117+ const r999 = rv . map ( x => x [ '99.9th' ] . toLocaleString ( 'en-us' ) ) ;
118+ const rmm = rv . map ( x => [ x . min . toLocaleString ( 'en-us' ) , x . max . toLocaleString ( 'en-us' ) ] ) ;
119+
120+ const us = unit . length ;
121+ const rks = Math . max ( ...rk . map ( x => x . length ) ) ;
122+ const ras = Math . max ( ...ra . map ( x => x . length ) ) ;
123+ const r50s = Math . max ( ...r50 . map ( x => x . length ) ) ;
124+ const r75s = Math . max ( ...r75 . map ( x => x . length ) ) ;
125+ const r99s = Math . max ( ...r99 . map ( x => x . length ) ) ;
126+ const r995s = Math . max ( ...r995 . map ( x => x . length ) ) ;
127+ const r999s = Math . max ( ...r999 . map ( x => x . length ) ) ;
128+ const rmns = Math . max ( ...rmm . map ( x => x [ 0 ] . length ) ) ;
129+ const rmxs = Math . max ( ...rmm . map ( x => x [ 1 ] . length ) ) ;
130+
131+ const bks = 1 + rks + 1 ;
132+ const b50s = 1 + r50s + 1 + us + 1 ;
133+ const b75s = 1 + r75s + 1 + us + 1 ;
134+ const b99s = 1 + r99s + 1 + us + 1 ;
135+ const b995s = 1 + r995s + 1 + us + 1 ;
136+ const b999s = 1 + r999s + 1 + us + 1 ;
137+ const bimms = 1 + rmns + 2 + rmxs + 1 + us + 1 ;
138+ const bas = 1 + ( ras + 1 + us ) + 1 + bimms + 1 ;
139+ const ls = 1 + bks + 1 + bas + 1 + b50s + 1 + b75s + 1 + b99s + 1 + b995s + 1 + b999s + 1 ;
140+
141+ if ( ! percentiles ) s += title ? ` ${ title } ` : '' ;
142+
143+ else {
144+ s += ' ' . repeat ( 3 + bks + bas ) ;
145+ s += '┌' + h . repeat ( ls - 4 - bks - bas ) + '┐' ;
146+ s += '\n' + ` ${ title . padEnd ( 2 + bks + bas , ' ' ) } ` ;
147+ }
148+
149+ if ( percentiles ) s += v
150+ + '50th' . padEnd ( ( b50s + 4 ) / 2 , ' ' ) . padStart ( b50s , ' ' ) + v
151+ + '75th' . padEnd ( ( b75s + 4 ) / 2 , ' ' ) . padStart ( b75s , ' ' ) + v
152+ + '99th' . padEnd ( ( b99s + 4 ) / 2 , ' ' ) . padStart ( b99s , ' ' ) + v
153+ + '99.5th' . padEnd ( ( b995s + 6 ) / 2 , ' ' ) . padStart ( b995s , ' ' ) + v
154+ + '99.9th' . padEnd ( ( b999s + 6 ) / 2 , ' ' ) . padStart ( b999s , ' ' ) + v ;
155+
156+ s += ( title || percentiles ? '\n' : '' ) + '┌' + h . repeat ( 1 + bks + bas ) + '┐' + ( percentiles ? '├' + h . repeat ( ls - 4 - bks - bas ) + '┤' : '' ) ;
157+
158+ for ( let i = 0 ; i < rk . length ; i ++ ) {
159+ s += '\n' + v + ` ${ rk [ i ] . padEnd ( rks , ' ' ) } ` + v + ` ${ ra [ i ] . padStart ( ras , ' ' ) } ${ unit } ${ `(${ rmm [ i ] [ 0 ] } ..${ rmm [ i ] [ 1 ] } ${ unit } )` . padStart ( bimms , ' ' ) } ` + v
160+ if ( percentiles ) s += v + ` ${ r50 [ i ] . padStart ( r50s , ' ' ) } ${ unit } ` + v + ` ${ r75 [ i ] . padStart ( r75s , ' ' ) } ${ unit } ` + v + ` ${ r99 [ i ] . padStart ( r99s , ' ' ) } ${ unit } ` + v + ` ${ r995 [ i ] . padStart ( r995s , ' ' ) } ${ unit } ` + v + ` ${ r999 [ i ] . padStart ( r999s , ' ' ) } ${ unit } ` + v ;
161+ }
162+
163+ s += '\n' + '└' + h . repeat ( 1 + bks + bas ) + '┘' + ( percentiles ? '└' + h . repeat ( ls - 4 - bks - bas ) + '┘' : '' ) ;
164+
165+ return s ;
166+ }
0 commit comments