4
4
5
5
// ignore_for_file: avoid_function_literals_in_foreach_calls
6
6
7
- import 'dart:math' show pow;
8
-
9
7
import 'package:benchmark_harness/benchmark_harness.dart' ;
10
8
import 'package:fixnum/fixnum.dart' ;
11
9
@@ -33,29 +31,43 @@ void check(bool sink2isEven) {
33
31
// integers.
34
32
const requiredDigits = 11106 ;
35
33
36
- class ParseBigIntBenchmark extends BenchmarkBase {
37
- final int bits;
38
- final BigInt seed;
39
- final List <String > strings = [];
40
-
41
- ParseBigIntBenchmark (String name, this .bits)
42
- : seed = (BigInt .one << bits) - BigInt .one,
34
+ class Benchmark extends BenchmarkBase {
35
+ final List <String > strings;
36
+ Benchmark (String name, int bits, {bool forInt: false })
37
+ : strings = generateStrings (bits, forInt),
43
38
super (name);
44
39
45
- @override
46
- void setup () {
40
+ static List <String > generateStrings (int bits, bool forInt) {
41
+ List <String > strings = [];
42
+ BigInt seed = (BigInt .one << bits) - BigInt .one;
47
43
var b = seed;
44
+ var restartDelta = BigInt .zero;
48
45
var totalLength = 0 ;
49
46
while (totalLength < requiredDigits) {
50
47
if (b.bitLength < bits) {
51
- b = seed;
48
+ restartDelta += seed >> 20 ;
49
+ restartDelta += BigInt .one;
50
+ // Restart from a slighly reduced seed to generate different numbers.
51
+ b = seed - restartDelta;
52
52
}
53
- final string = b.toString ();
53
+ var string = b.toString ();
54
+
55
+ // Web integers lose precision due to rounding for larger values. Make
56
+ // sure the string will round-trip correctly.
57
+ if (forInt) string = int .parse (string).toString ();
58
+
54
59
strings.add (string);
55
60
totalLength += string.length;
56
- b = b - (b >> 8 );
61
+ var delta = b >> 8 ;
62
+ if (delta == BigInt .zero) delta = BigInt .one;
63
+ b = b - delta;
57
64
}
65
+ return strings;
58
66
}
67
+ }
68
+
69
+ class ParseBigIntBenchmark extends Benchmark {
70
+ ParseBigIntBenchmark (String name, int bits) : super (name, bits);
59
71
60
72
@override
61
73
void run () {
@@ -68,31 +80,8 @@ class ParseBigIntBenchmark extends BenchmarkBase {
68
80
}
69
81
}
70
82
71
- int int64UnsignedBitLength (Int64 i) => i.isNegative ? 64 : i.bitLength;
72
-
73
- class ParseInt64Benchmark extends BenchmarkBase {
74
- final int bits;
75
- final Int64 seed;
76
- final List <String > strings = [];
77
-
78
- ParseInt64Benchmark (String name, this .bits)
79
- : seed = (Int64 .ONE << bits) - Int64 .ONE ,
80
- super (name);
81
-
82
- @override
83
- void setup () {
84
- var b = seed;
85
- var totalLength = 0 ;
86
- while (totalLength < requiredDigits) {
87
- if (int64UnsignedBitLength (b) < bits) {
88
- b = seed;
89
- }
90
- final string = b.toStringUnsigned ();
91
- strings.add (string);
92
- totalLength += string.length;
93
- b = b - b.shiftRightUnsigned (8 );
94
- }
95
- }
83
+ class ParseInt64Benchmark extends Benchmark {
84
+ ParseInt64Benchmark (String name, int bits) : super (name, bits);
96
85
97
86
@override
98
87
void run () {
@@ -105,29 +94,8 @@ class ParseInt64Benchmark extends BenchmarkBase {
105
94
}
106
95
}
107
96
108
- class ParseIntBenchmark extends BenchmarkBase {
109
- final int bits;
110
- final int seed;
111
- final List <String > strings = [];
112
-
113
- ParseIntBenchmark (String name, this .bits)
114
- : seed = (pow (2 , bits) as int ) - 1 ,
115
- super (name);
116
-
117
- @override
118
- void setup () {
119
- var b = seed;
120
- var totalLength = 0 ;
121
- while (totalLength < requiredDigits) {
122
- if (b.bitLength < bits) {
123
- b = seed;
124
- }
125
- final string = b.toString ();
126
- strings.add (string);
127
- totalLength += string.length;
128
- b = b - b ~ / 256 ;
129
- }
130
- }
97
+ class ParseIntBenchmark extends Benchmark {
98
+ ParseIntBenchmark (String name, int bits) : super (name, bits, forInt: true );
131
99
132
100
@override
133
101
void run () {
@@ -140,33 +108,8 @@ class ParseIntBenchmark extends BenchmarkBase {
140
108
}
141
109
}
142
110
143
- class ParseJsBigIntBenchmark extends BenchmarkBase {
144
- final int bits;
145
- final Object seed;
146
- final List <String > strings = [];
147
-
148
- ParseJsBigIntBenchmark (String name, this .bits)
149
- : seed = nativeBigInt.subtract (
150
- nativeBigInt.shiftLeft (
151
- nativeBigInt.one, nativeBigInt.fromInt (bits)),
152
- nativeBigInt.one),
153
- super (name);
154
-
155
- @override
156
- void setup () {
157
- var b = seed;
158
- var totalLength = 0 ;
159
- while (totalLength < requiredDigits) {
160
- if (nativeBigInt.bitLength (b) < bits) {
161
- b = seed;
162
- }
163
- final string = nativeBigInt.toStringMethod (b);
164
- strings.add (string);
165
- totalLength += string.length;
166
- b = nativeBigInt.subtract (
167
- b, nativeBigInt.shiftRight (b, nativeBigInt.eight));
168
- }
169
- }
111
+ class ParseJsBigIntBenchmark extends Benchmark {
112
+ ParseJsBigIntBenchmark (String name, int bits) : super (name, bits);
170
113
171
114
@override
172
115
void run () {
@@ -179,27 +122,16 @@ class ParseJsBigIntBenchmark extends BenchmarkBase {
179
122
}
180
123
}
181
124
182
- class FormatBigIntBenchmark extends BenchmarkBase {
183
- final int bits;
184
- final BigInt seed;
125
+ class FormatBigIntBenchmark extends Benchmark {
185
126
final List <BigInt > values = [];
186
127
187
- FormatBigIntBenchmark (String name, this .bits)
188
- : seed = (BigInt .one << bits) - BigInt .one,
189
- super (name);
128
+ FormatBigIntBenchmark (String name, int bits) : super (name, bits);
190
129
191
130
@override
192
131
void setup () {
193
- var b = seed;
194
- var totalLength = 0 ;
195
- while (totalLength < requiredDigits) {
196
- if (b.bitLength < bits) {
197
- b = seed;
198
- }
199
- final string = b.toString ();
132
+ for (String s in strings) {
133
+ BigInt b = BigInt .parse (s);
200
134
values.add (b - BigInt .one); // We add 'one' back later.
201
- totalLength += string.length;
202
- b = b - (b >> 8 );
203
135
}
204
136
}
205
137
@@ -218,36 +150,26 @@ class FormatBigIntBenchmark extends BenchmarkBase {
218
150
}
219
151
}
220
152
221
- class FormatIntBenchmark extends BenchmarkBase {
222
- final int bits;
223
- final int seed;
153
+ class FormatIntBenchmark extends Benchmark {
224
154
final List <int > values = [];
225
155
226
- FormatIntBenchmark (String name, this .bits)
227
- : seed = (pow (2 , bits) as int ) - 1 ,
228
- super (name);
156
+ FormatIntBenchmark (String name, int bits) : super (name, bits, forInt: true );
229
157
230
158
@override
231
159
void setup () {
232
- var b = seed;
233
- var totalLength = 0 ;
234
- int kk = b ~ / 100000 ;
235
- while (totalLength < requiredDigits) {
236
- if (b.bitLength < bits) {
237
- b = seed - ++ kk;
238
- }
239
- final string = b.toString ();
240
- values.add (b - 4096 ); // We add 'one' back later.
241
- totalLength += string.length;
242
- b = b - (b ~ / 256 );
160
+ for (String s in strings) {
161
+ int b = int .parse (s);
162
+ values.add (b - 4096 ); // We add this back later.
243
163
}
244
164
}
245
165
246
166
@override
247
167
void run () {
248
168
for (final b0 in values) {
249
169
// Instances might cache `toString()`, so use arithmetic to create a new
250
- // instance to try to protect against measuring a cached string.
170
+ // instance to try to protect against measuring a cached string. We use
171
+ // 4096 to avoid the arithmetic being a no-op due to rounding on web
172
+ // integers (i.e. doubles).
251
173
final b = b0 + 4096 ;
252
174
final s = b.toString ();
253
175
sink1 = s;
@@ -257,27 +179,16 @@ class FormatIntBenchmark extends BenchmarkBase {
257
179
}
258
180
}
259
181
260
- class FormatInt64Benchmark extends BenchmarkBase {
261
- final int bits;
262
- final Int64 seed;
182
+ class FormatInt64Benchmark extends Benchmark {
263
183
final List <Int64 > values = [];
264
184
265
- FormatInt64Benchmark (String name, this .bits)
266
- : seed = (Int64 .ONE << bits) - Int64 .ONE ,
267
- super (name);
185
+ FormatInt64Benchmark (String name, int bits) : super (name, bits);
268
186
269
187
@override
270
188
void setup () {
271
- var b = seed;
272
- var totalLength = 0 ;
273
- while (totalLength < requiredDigits) {
274
- if (int64UnsignedBitLength (b) < bits) {
275
- b = seed;
276
- }
277
- final string = b.toStringUnsigned ();
278
- values.add (b - Int64 .ONE );
279
- totalLength += string.length;
280
- b = b - b.shiftRightUnsigned (8 );
189
+ for (String s in strings) {
190
+ final b = Int64 .parseInt (s);
191
+ values.add (b - Int64 .ONE ); // We add this back later.
281
192
}
282
193
}
283
194
@@ -296,32 +207,17 @@ class FormatInt64Benchmark extends BenchmarkBase {
296
207
}
297
208
}
298
209
299
- class FormatJsBigIntBenchmark extends BenchmarkBase {
300
- final int bits;
301
- final Object seed;
210
+ class FormatJsBigIntBenchmark extends Benchmark {
302
211
final List <Object > values = [];
303
212
304
- FormatJsBigIntBenchmark (String name, this .bits)
305
- : seed = nativeBigInt.subtract (
306
- nativeBigInt.shiftLeft (
307
- nativeBigInt.one, nativeBigInt.fromInt (bits)),
308
- nativeBigInt.one),
309
- super (name);
213
+ FormatJsBigIntBenchmark (String name, int bits) : super (name, bits);
310
214
311
215
@override
312
216
void setup () {
313
217
final one = nativeBigInt.one;
314
- var b = seed;
315
- var totalLength = 0 ;
316
- while (totalLength < requiredDigits) {
317
- if (nativeBigInt.bitLength (b) < bits) {
318
- b = seed;
319
- }
320
- final string = nativeBigInt.toStringMethod (b);
321
- values.add (nativeBigInt.subtract (b, one)); // We add 'one' back later.
322
- totalLength += string.length;
323
- b = nativeBigInt.subtract (
324
- b, nativeBigInt.shiftRight (b, nativeBigInt.eight));
218
+ for (String s in strings) {
219
+ final b = nativeBigInt.parse (s);
220
+ values.add (nativeBigInt.subtract (b, one)); // We add this back later.
325
221
}
326
222
}
327
223
@@ -371,6 +267,9 @@ void main() {
371
267
final benchmarks = [
372
268
() => ParseIntBenchmark ('Int.parse.0009.bits' , 9 ),
373
269
() => ParseIntBenchmark ('Int.parse.0032.bits' , 32 ),
270
+ // Use '63' bits to avoid 64-bit arithmetic overflowing to negative. Keep
271
+ // the name as '64' to help comparisons. The effect of an incorrect number
272
+ // is reduced since benchmark results are normalized to a 'per digit' score
374
273
() => ParseIntBenchmark ('Int.parse.0064.bits' , 63 ),
375
274
() => ParseInt64Benchmark ('Int64.parse.0009.bits' , 9 ),
376
275
() => ParseInt64Benchmark ('Int64.parse.0032.bits' , 32 ),
@@ -389,7 +288,7 @@ void main() {
389
288
selectParseNativeBigIntBenchmark ('JsBigInt.parse.4096.bits' , 4096 ),
390
289
() => FormatIntBenchmark ('Int.toString.0009.bits' , 9 ),
391
290
() => FormatIntBenchmark ('Int.toString.0032.bits' , 32 ),
392
- () => FormatIntBenchmark ('Int.toString.0064.bits' , 63 ),
291
+ () => FormatIntBenchmark ('Int.toString.0064.bits' , 63 ), // '63': See above.
393
292
() => FormatInt64Benchmark ('Int64.toString.0009.bits' , 9 ),
394
293
() => FormatInt64Benchmark ('Int64.toString.0032.bits' , 32 ),
395
294
() => FormatInt64Benchmark ('Int64.toString.0064.bits' , 64 ),
0 commit comments