File size: 6,288 Bytes
6655e35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

import * as benchmark from 'benchmark';

import {toBigIntBE, toBigIntLE, toBufferBE, toBufferLE} from './index';

const BN = require('bn.js');


// This file contains the benchmark test suite. It includes the benchmark and
// some lightweight boilerplate code for running benchmark.js. To
// run the benchmarks, execute `npm run benchmark` from the package directory.
const suite = new benchmark.Suite();

interface BenchmarkRun {
  name: string;
  hz: number;
  stats: benchmark.Stats;
}

// Tests the performance of a no-op.
suite.add('no-op', () => {});

// Test small strings (unaligned)
const smallHex = 'deadbeef';
const smallString = `0x${smallHex}`;
const smallBuf: Buffer = Buffer.from(smallHex, 'hex');
suite.add('bigint from hex string (small)', () => {
  return BigInt(smallString);
});
suite.add('bigint from hex string from buffer (small)', () => {
  return BigInt(`0x${smallBuf.toString('hex')}`);
});
suite.add('BN from hex string from buffer (small)', () => {
  return new BN(smallBuf.toString('hex'), 16);
});
suite.add('LE bigint-buffer ToBigInt (small)', () => {
  return toBigIntLE(smallBuf);
});
suite.add('BE bigint-buffer ToBigInt (small)', () => {
  return toBigIntBE(smallBuf);
});

// Test mid strings (aligned)
const midHex = 'badc0ffee0ddf00d';
const midString = `0x${midHex}`;
const midBuf: Buffer = Buffer.from(midHex, 'hex');
suite.add('bigint from hex string (mid, aligned)', () => {
  return BigInt(midString);
});
suite.add('bigint from hex string from buffer (mid, aligned)', () => {
  return BigInt(`0x${midBuf.toString('hex')}`);
});
suite.add('BN from hex string from buffer (mid, aligned)', () => {
  return new BN(midBuf.toString('hex'), 16);
});
suite.add('LE bigint-buffer ToBigInt (mid, aligned)', () => {
  return toBigIntLE(midBuf);
});
suite.add('BE bigint-buffer ToBigInt (mid, aligned)', () => {
  return toBigIntBE(midBuf);
});

// Test huge strings
const hugeHex =
    'badc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00d';
const hugeString = `0x${hugeHex}`;
const hugeBuf: Buffer = Buffer.from(hugeHex, 'hex');
suite.add('bigint from hex string (huge)', () => {
  return BigInt(hugeString);
});
suite.add('bigint from hex string from buffer (huge)', () => {
  return BigInt(`0x${hugeBuf.toString('hex')}`);
});
suite.add('BN from hex string from buffer (huge)', () => {
  return new BN(hugeBuf.toString('hex'), 16);
});
suite.add('LE bigint-buffer ToBigInt (huge)', () => {
  return toBigIntLE(hugeBuf);
});
suite.add('BE bigint-buffer ToBigInt (huge)', () => {
  return toBigIntBE(hugeBuf);
});

const bigIntToBufferWithStringBE = (int: bigint, width: number): Buffer => {
  const hex = int.toString(16);
  return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
};

const bigIntToBufferWithStringLE = (int: bigint, width: number): Buffer => {
  const hex = int.toString(16);
  const buffer =
      Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
  buffer.reverse();
  return buffer;
};

// Test small toBuffer
const smallValue = 12345678n;
suite.add('LE bigint to hex string to buffer (small)', () => {
  return bigIntToBufferWithStringLE(smallValue, 8);
});

suite.add('BE bigint to hex string to buffer (small)', () => {
  return bigIntToBufferWithStringBE(smallValue, 8);
});

const bnSmallValue = new BN('12345678', 10);
suite.add('BN to buffer (small)', () => {
  return bnSmallValue.toBuffer(8);
});

suite.add('LE bigint-buffer to buffer (small)', () => {
  return toBufferLE(smallValue, 8);
});

suite.add('BE bigint-buffer to buffer (small)', () => {
  return toBufferBE(smallValue, 8);
});


// Test large toBuffer
const largeValue =
    0xbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dn;
suite.add('LE bigint to hex string to buffer (large)', () => {
  return bigIntToBufferWithStringLE(largeValue, 24);
});

suite.add('BE bigint to hex string to buffer (large)', () => {
  return bigIntToBufferWithStringBE(largeValue, 24);
});

const bnLargeValue = new BN(
    'badc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00d',
    16);
suite.add('BN to buffer (large)', () => {
  return bnLargeValue.toBuffer(24);
});

suite.add('LE bigint-buffer to buffer (large)', () => {
  return toBufferLE(largeValue, 24);
});

suite.add('BE bigint-buffer to buffer (large)', () => {
  return toBufferBE(largeValue, 24);
});

suite.add('LE bigint to hex string to buffer (large)', () => {
  return bigIntToBufferWithStringLE(largeValue, 8);
});

suite.add('BE bigint to hex string to buffer (large)', () => {
  return bigIntToBufferWithStringBE(largeValue, 8);
});

suite.add('LE bigint-buffer to buffer (large, truncated)', () => {
  return toBufferLE(largeValue, 8);
});

suite.add('BE bigint-buffer to buffer (large, truncated)', () => {
  return toBufferBE(largeValue, 8);
});

const b1 = Buffer.from('0123456789ABCDEF0123456789ABCDEF', 'hex');
const b2 = Buffer.from('0123456789ABCDEF0123456789ABCDEF', 'hex');
const bn1 = new BN('0123456789ABCDEF0123456789ABCDEF', 'hex');
const bn2 = new BN('0123456789ABCDEF0123456789ABCDEF', 'hex');
const n1 = 0x0123456789ABCDEF0123456789ABCDEFn;
const n2 = 0x0123456789ABCDEF0123456789ABCDEFn;
suite.add('Buffer equality comparison', () => {
  return b1.compare(b2) === 0;
});

suite.add('BN equality comparison', () => {
  return bn1.eq(bn2);
});

suite.add('bigint equality comparison', () => {
  return n1 === n2;
});

suite.add('BN multiply', () => {
  return bn1.mul(bn2);
});

suite.add('bigint multiply', () => {
  return n1 * n2;
});

//#endregion


// Reporter for each benchmark
suite.on('cycle', (event: benchmark.Event) => {
  const benchmarkRun: BenchmarkRun = event.target as BenchmarkRun;
  const stats = benchmarkRun.stats as benchmark.Stats;
  const meanInNanos = (stats.mean * 1000000000).toFixed(2);
  const stdDevInNanos = (stats.deviation * 1000000000).toFixed(3);
  const runs = stats.sample.length;
  const ops = benchmarkRun.hz.toFixed(benchmarkRun.hz < 100 ? 2 : 0);
  const err = stats.rme.toFixed(2);

  console.log(`${benchmarkRun.name}: ${ops}±${err}% ops/s ${meanInNanos}±${
      stdDevInNanos} ns/op (${runs} run${runs === 0 ? '' : 's'})`);
});

// Runs the test suite
suite.run();