/
result.ts
186 lines (167 loc) · 4.28 KB
/
result.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import AssertRule from './assertion';
/**
* The result of benchmark.
*
* This value will included outlier. Please use {@link Result.dropOutlier} if you want drop they.
*/
export default class Result {
/**
* Name of this test.
*/
readonly name: string;
/**
* Times of benchmark result in milliseconds.
*/
readonly msecs: number[];
/**
* @param name Name of benchmark.
* @param msecs Times of benchmark result.
*/
constructor(name: string, msecs: number[]) {
this.name = name;
this.msecs = msecs;
}
/**
* Total milliseconds of this benchmark.
*/
get total(): number {
return this.msecs.reduce((x, y) => x + y);
}
/**
* The time of fastest test in milliseconds.
*/
get fastest(): number {
return Math.min(...this.msecs);
}
/**
* The time of slowest test in milliseconds.
*/
get slowest(): number {
return Math.max(...this.msecs);
}
/**
* Average time of this benchmark in milliseconds.
*/
get average(): number {
return this.total / this.msecs.length;
}
/**
* Time unbiased sample variance of times.
*/
get variance(): number {
const avg = this.average;
return this.msecs.reduce((total, x) => total + (x - avg) ** 2, 0) / (this.msecs.length - 1);
}
/**
* Standard division of times.
*/
get std(): number {
return Math.sqrt(this.variance);
}
/**
* Standard error of the mean of times.
*/
get sem(): number {
return this.std / Math.sqrt(this.msecs.length);
}
/**
* Guessed error range of this benchmark.
*/
get errorRange(): number {
return this.sem * 1.96;
}
/**
* Error range per average time.
*/
get errorRate(): number {
return this.errorRange / this.average;
}
/**
* Operations per seconds.
*/
get opsPerSec(): number {
return 1000 / this.average;
}
/**
* Make new Result that droped outlier.
*
* @param threshold The threshold of outlier testing.
*
* @return New {@link Result} instance.
*/
dropOutlier(threshold = 2): Result {
const { average, std } = this;
return new Result(
this.name,
this.msecs.filter((x) => Math.abs((x - average) / std) <= threshold),
);
}
/**
* Convert to string for printing.
*
* @return Human redable string
*/
toString(): string {
const avg = Math.round(this.average * 10000) / 10000;
const ops = Math.round(this.opsPerSec * 1000) / 1000;
const range = Math.round(this.errorRange * 10000) / 10000;
const rate = Math.round(this.errorRate * 10000) / 100;
return `${this.name}:\t${ops}ops/sec\t${avg}msec/op\t+-${range}msec/op (${rate}%)\t${this.msecs.length} times tried`;
}
/**
* Assertion if it taked more (or less) time than expected.
*
* Expected rule format is `{operator}{number}{unit}`; use like `<=10msec`.
* Operator and unit are can omit. If omitted, uses `<=` and `msec`.
*
* This function will throw {@link AsyncMarkAssertionError} if result is unaccepcable.
*
* @param expected Expected time in milliseconds number or string value.
* e.g. `<10ms` or `>=20s`.
*
* @return
*
* ## Supported operators
* |example |means |
* |--------------|-------------------|
* |"<42" |faster than 42 msec|
* |"<=42" or omit|42 msec or faster |
* |">42" |slower than 42 msec|
* |">=42" |42 msec or slower |
*
* ## Supported units
* |example |means |
* |------------------|------------|
* |"42s" or "42sec" |seconds |
* |"42ms" or "42msec"|milliseconds|
* |"42us" or "42usec"|microseconds|
* |"42ns" or "42nsec"|nanoseconds |
*
* ## Examples
* ### Simple usage
*
* ``` typescript
* const result = await Benchmark(function() {
* # do something that expect done in least 100msec
* }).run();
*
* result.assert(100);
* ```
*
* ### Combination rule
*
* ``` typescript
* const result = await Benchmark(async function() {
* await sleep_function(100);
* }).run();
*
* result.assert('>90ms', '<110ms');
* ```
*
* @since 0.3.0
*/
assert(...expected: (number | string)[]): void {
const rules = expected.map((x) => new AssertRule(x));
rules.forEach((rule) => rule.assert(this, this.assert));
}
}