File tree Expand file tree Collapse file tree 6 files changed +74
-16
lines changed
Expand file tree Collapse file tree 6 files changed +74
-16
lines changed Original file line number Diff line number Diff line change @@ -53,12 +53,12 @@ await bench.run();
5353console .table (bench .table ());
5454
5555// Output:
56- // ┌─────────┬───────────────┬──────────┬────────────────────┬ ───────────┬─────────┐
57- // │ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
58- // ├─────────┼───────────────┼──────────┼────────────────────┼ ───────────┼─────────┤
59- // │ 0 │ 'faster task' │ '41,621 ' │ 24025.791819761525 │ '±20.50 %' │ 4257 │
60- // │ 1 │ 'slower task' │ '828 ' │ 1207382.7838323202 │ '±7.07 %' │ 83 │
61- // └─────────┴───────────────┴──────────┴────────────────────┴ ───────────┴─────────┘
56+ // ┌─────────┬───────────────┬──────────┬──────────────────────┬──────────┬─────────────────────── ───────────┬─────────┐
57+ // │ (index) │ Task name │ ops/sec │ Average time/op (ns) │ Margin │ Median time/op (ns) │ Samples │
58+ // ├─────────┼───────────────┼──────────┼──────────────────────┼──────────┼─────────────────────── ───────────┼─────────┤
59+ // │ 0 │ 'faster task' │ '38,832 ' │ 25751.297631307978 │ '±3.48 %' │ '22016.49999997812±5.5000000145' │ 3884 │
60+ // │ 1 │ 'slower task' │ '669 ' │ 1493338.567164177 │ '±5.98 %' │ '1445076.0000000286' │ 67 │
61+ // └─────────┴───────────────┴──────────┴──────────────────────┴──────────┴─────────────────────── ───────────┴─────────┘
6262
6363console .table (bench .table ((task ) => ({ ' Task name' : task .name })));
6464
@@ -282,6 +282,16 @@ export type TaskResult = {
282282 */
283283 rme: number ;
284284
285+ /**
286+ * median absolute deviation
287+ */
288+ mad: number ;
289+
290+ /**
291+ * p50/median percentile
292+ */
293+ p50: number ;
294+
285295 /**
286296 * p75 percentile
287297 */
Original file line number Diff line number Diff line change @@ -18,12 +18,12 @@ await bench.run();
1818console . table ( bench . table ( ) ) ;
1919
2020// Output:
21- // ┌─────────┬───────────────┬──────────┬────────────────────┬ ───────────┬─────────┐
22- // │ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
23- // ├─────────┼───────────────┼──────────┼────────────────────┼ ───────────┼─────────┤
24- // │ 0 │ 'faster task' │ '41,621 ' │ 24025.791819761525 │ '±20.50 %' │ 4257 │
25- // │ 1 │ 'slower task' │ '828 ' │ 1207382.7838323202 │ '±7.07 %' │ 83 │
26- // └─────────┴───────────────┴──────────┴────────────────────┴ ───────────┴─────────┘
21+ // ┌─────────┬───────────────┬──────────┬──────────────────────┬──────────┬─────────────────────── ───────────┬─────────┐
22+ // │ (index) │ Task name │ ops/sec │ Average time/op (ns) │ Margin │ Median time/op (ns) │ Samples │
23+ // ├─────────┼───────────────┼──────────┼──────────────────────┼──────────┼─────────────────────── ───────────┼─────────┤
24+ // │ 0 │ 'faster task' │ '38,832 ' │ 25751.297631307978 │ '±3.48 %' │ '22016.49999997812±5.5000000145' │ 3884 │
25+ // │ 1 │ 'slower task' │ '669 ' │ 1493338.567164177 │ '±5.98 %' │ '1445076.0000000286' │ 67 │
26+ // └─────────┴───────────────┴──────────┴──────────────────────┴──────────┴─────────────────────── ───────────┴─────────┘
2727
2828console . table (
2929 bench . todos . map ( ( { name } ) => ( {
Original file line number Diff line number Diff line change @@ -242,10 +242,11 @@ export default class Bench extends EventTarget {
242242 throw task . result . error ;
243243 }
244244 return convert ?.( task ) || {
245- 'Task Name ' : task . name ,
245+ 'Task name ' : task . name ,
246246 'ops/sec' : task . result . error ? 'NaN' : parseInt ( task . result . hz . toString ( ) , 10 ) . toLocaleString ( ) ,
247- 'Average Time (ns)' : task . result . error ? 'NaN' : task . result . mean * 1000 * 1000 ,
247+ 'Average time/op (ns)' : task . result . error ? 'NaN' : task . result . mean * 1e6 ,
248248 Margin : task . result . error ? 'NaN' : `\xb1${ task . result . rme . toFixed ( 2 ) } %` ,
249+ 'Median time/op (ns)' : task . result . error ? 'NaN' : `${ task . result . p50 * 1e6 } ${ task . result . mad * 1e6 > 0 ? `\xb1${ ( task . result . mad * 1e6 ) . toFixed ( 10 ) } ` : '' } ` ,
249250 Samples : task . result . error ? 'NaN' : task . result . samples . length ,
250251 } ;
251252 }
Original file line number Diff line number Diff line change @@ -10,7 +10,13 @@ import Bench from './bench';
1010import tTable from './constants' ;
1111import { createBenchEvent } from './event' ;
1212import { AddEventListenerOptionsArgument , RemoveEventListenerOptionsArgument } from './types' ;
13- import { getVariance , isAsyncTask , quantileSorted } from './utils' ;
13+ import {
14+ absoluteDeviation ,
15+ getVariance ,
16+ isAsyncTask ,
17+ medianSorted ,
18+ quantileSorted ,
19+ } from './utils' ;
1420
1521/**
1622 * A class that represents each benchmark task in Tinybench. It keeps track of the
@@ -152,6 +158,9 @@ export default class Task extends EventTarget {
152158 const moe = sem * critical ;
153159 const rme = ( moe / mean ) * 100 ;
154160
161+ const mad = absoluteDeviation ( samples , medianSorted ) ;
162+
163+ const p50 = medianSorted ( samples ) ;
155164 const p75 = quantileSorted ( samples , 0.75 ) ;
156165 const p99 = quantileSorted ( samples , 0.99 ) ;
157166 const p995 = quantileSorted ( samples , 0.995 ) ;
@@ -176,6 +185,8 @@ export default class Task extends EventTarget {
176185 critical,
177186 moe,
178187 rme,
188+ mad,
189+ p50,
179190 p75,
180191 p99,
181192 p995,
Original file line number Diff line number Diff line change @@ -105,6 +105,16 @@ export type TaskResult = {
105105 */
106106 rme : number ;
107107
108+ /**
109+ * median absolute deviation
110+ */
111+ mad : number ;
112+
113+ /**
114+ * p50/median percentile
115+ */
116+ p50 : number ;
117+
108118 /**
109119 * p75 percentile
110120 */
Original file line number Diff line number Diff line change @@ -19,7 +19,7 @@ function isPromiseLike<T>(maybePromiseLike: any): maybePromiseLike is PromiseLik
1919const AsyncFunctionConstructor = ( async ( ) => { } ) . constructor ;
2020
2121/**
22- * an async function check method only consider runtime support async syntax
22+ * An async function check method only consider runtime support async syntax
2323 */
2424export const isAsyncFunction = ( fn : Fn ) => fn . constructor === AsyncFunctionConstructor ;
2525
@@ -113,3 +113,29 @@ export const quantileSorted = (samples: number[], q: number) => {
113113 }
114114 return samples [ baseIndex ] ;
115115} ;
116+
117+ /**
118+ * Computes the median of a sorted sample.
119+ *
120+ * @param samples the sorted sample
121+ * @returns the median of the sample
122+ */
123+ export const medianSorted = ( samples : number [ ] ) => quantileSorted ( samples , 0.5 ) ;
124+
125+ /**
126+ * Computes the absolute deviation of a sample given an aggregation.
127+ *
128+ * @param samples the sample
129+ * @param aggFn the aggregation function to use
130+ * @returns the absolute deviation of the sample given the aggregation
131+ */
132+ export const absoluteDeviation = ( samples : number [ ] , aggFn : ( arr : number [ ] ) => number | undefined ) => {
133+ const value = aggFn ( samples ) ;
134+ const absoluteDeviations : number [ ] = [ ] ;
135+
136+ for ( const sample of samples ) {
137+ absoluteDeviations . push ( Math . abs ( sample - value ! ) ) ;
138+ }
139+
140+ return aggFn ( absoluteDeviations ) ;
141+ } ;
You can’t perform that action at this time.
0 commit comments