-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(base64): Improve benchmark script (merge #1986)
- Loading branch information
Showing
3 changed files
with
90 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,94 @@ | ||
/* eslint-disable no-restricted-globals */ | ||
/* global print */ | ||
|
||
// This is a quick and dirty benchmark to encode and decode base64, intended to | ||
// be run manually to measure performance progress or regressions. | ||
// This is a hand-rolled benchmark that attempts as much as possible to avoid | ||
// incorporating the noise of function calls and the underlying Date.now() | ||
// syscall, by exponentially probing for the number of operations that can be | ||
// executed within each benchmark's deadline. | ||
// incorporating the noise of function calls and the underlying | ||
// performance.now()/Date.now() syscall, by exponentially probing for the number | ||
// of operations that can be executed within each benchmark's deadline. | ||
|
||
import { encodeBase64, decodeBase64 } from '../index.js'; | ||
import { jsEncodeBase64 } from '../src/encode.js'; | ||
import { jsDecodeBase64 } from '../src/decode.js'; | ||
|
||
async function main() { | ||
const log = (typeof console !== 'undefined' && console.log) || print; | ||
/** @type {typeof Date.now} */ | ||
const now = await (async () => { | ||
try { | ||
const { performance } = await import('perf_hooks'); | ||
if (performance.now) { | ||
return performance.now.bind(performance); | ||
} | ||
} catch (_err) { | ||
// eslint-disable-next-line no-empty | ||
} | ||
return Date.now; | ||
})(); | ||
|
||
const timeout = 1000; // ms | ||
|
||
const shortString = | ||
'there once a rich man from nottingham who tried to cross the river. what a dope, he tripped on a rope. now look at him shiver.'; | ||
const string = new Array(10000).fill(shortString).join(' '); | ||
const shortData = encodeBase64(shortString); | ||
const data = encodeBase64(string); | ||
|
||
const timeout = 1000; // ms | ||
|
||
const string = new Array(10000) | ||
.fill( | ||
'there once a rich man from nottingham who tried to cross the river. what a dope, he tripped on a rope. now look at him shiver.', | ||
) | ||
.join(' '); | ||
const data = encodeBase64(string); | ||
|
||
{ | ||
const start = Date.now(); | ||
const deadline = start + timeout / 2; | ||
let operations = 0; | ||
for (let n = 1; Date.now() < deadline; n *= 2) { | ||
for (let i = 0; i < n; i += 1) { | ||
encodeBase64(string); | ||
/** @type {string} */ | ||
let result; | ||
|
||
for (const [label, fn, input] of [ | ||
['encodes', encodeBase64, string], | ||
['JS short-string encodes', jsEncodeBase64, shortString], | ||
]) { | ||
for (const pass of [1, 2]) { | ||
const start = now(); | ||
const deadline = start + timeout / 2; | ||
let operations = 0; | ||
for (let n = 1; now() < deadline; n *= 2) { | ||
for (let i = 0; i < n; i += 1) { | ||
result = fn(input); | ||
} | ||
operations += n; | ||
} | ||
const end = now(); | ||
const duration = end - start; | ||
log( | ||
`[pass ${pass}] ${label}`, | ||
(operations * input.length) / duration, | ||
'characters per millisecond', | ||
); | ||
} | ||
operations += n; | ||
} | ||
const end = Date.now(); | ||
const duration = end - start; | ||
console.log( | ||
'encodes', | ||
(operations * string.length) / duration, | ||
'characters per millisecond', | ||
); | ||
} | ||
|
||
{ | ||
const start = Date.now(); | ||
const deadline = start + timeout / 2; | ||
let operations = 0; | ||
for (let n = 1; Date.now() < deadline; n *= 2) { | ||
for (let i = 0; i < n; i += 1) { | ||
decodeBase64(data); | ||
if (result.length < 100) throw Error(`unexpected result: ${result}`); | ||
|
||
for (const [label, fn, input] of [ | ||
['decodes', decodeBase64, data], | ||
['JS short-string decodes', jsDecodeBase64, shortData], | ||
]) { | ||
for (const pass of [1, 2]) { | ||
const start = now(); | ||
const deadline = start + timeout / 2; | ||
let operations = 0; | ||
for (let n = 1; now() < deadline; n *= 2) { | ||
for (let i = 0; i < n; i += 1) { | ||
result = fn(input); | ||
} | ||
operations += n; | ||
} | ||
const end = now(); | ||
const duration = end - start; | ||
log( | ||
`[pass ${pass}] ${label}`, | ||
(operations * input.length) / duration, | ||
'bytes per millisecond', | ||
); | ||
} | ||
operations += n; | ||
} | ||
const end = Date.now(); | ||
const duration = end - start; | ||
console.log( | ||
'decodes', | ||
(operations * data.length) / duration, | ||
'bytes per millisecond', | ||
); | ||
|
||
if (result.length < 100) throw Error(`unexpected result: ${result}`); | ||
} | ||
|
||
main(); |