Skip to content

Instantly share code, notes, and snippets.

@billywhizz
Last active June 17, 2024 02:46
Show Gist options
  • Save billywhizz/b0b43f83c673f964628097f339c10f78 to your computer and use it in GitHub Desktop.
Save billywhizz/b0b43f83c673f964628097f339c10f78 to your computer and use it in GitHub Desktop.
file reading benchmark for JS runtimes
openssl-3.0.12

setup

docker build -t bench .
docker run -it --rm --privileged -v $(pwd):/bench bench /bin/bash

versions

root@8f04c899517e:/bench# node --version
v22.2.0
root@8f04c899517e:/bench# deno --version | head -n 1
deno 1.44.1 (release, x86_64-unknown-linux-gnu)
root@8f04c899517e:/bench# bun --version
1.1.12
root@8f04c899517e:/bench# 

read file results

root@8f04c899517e:/bench# node read_as_text.mjs 
readFileSync 1336    time     1916 rate     156514 rate/core     156264 ns/iter      6389.18 rss    56088 usr  44.34 sys  55.82 tot 100.16
readFileSync 1336    time     1976 rate     151817 rate/core     154663 ns/iter      6586.84 rss    57752 usr  45.03 sys  53.13 tot  98.16
readFileSync 1336    time     1944 rate     154252 rate/core     157916 ns/iter      6482.88 rss    57752 usr  40.10 sys  57.58 tot  97.68
readFileSync 1336    time     1930 rate     155399 rate/core     159597 ns/iter      6435.02 rss    57752 usr  45.06 sys  52.31 tot  97.37
readFileSync 1336    time     1947 rate     154020 rate/core     157921 ns/iter      6492.66 rss    57752 usr  40.55 sys  56.98 tot  97.53
readFileSync 1336    time     1923 rate     155948 rate/core     159587 ns/iter      6412.36 rss    57752 usr  45.74 sys  51.98 tot  97.72
readFileSync 1336    time     1939 rate     154646 rate/core     157899 ns/iter      6466.35 rss    57752 usr  38.66 sys  59.28 tot  97.94
readFileSync 1336    time     1930 rate     155410 rate/core     159592 ns/iter      6434.55 rss    57752 usr  40.92 sys  56.46 tot  97.38
readFileSync 1336    time     1922 rate     156083 rate/core     160431 ns/iter      6406.81 rss    57752 usr  40.58 sys  56.71 tot  97.29
readFileSync 1336    time     1952 rate     153632 rate/core     156274 ns/iter      6509.04 rss    57880 usr  40.96 sys  57.35 tot  98.31
root@8f04c899517e:/bench# bun read_as_text.mjs 
readFileSync 1336    time     2066 rate     145183 rate/core     146354 ns/iter      6887.85 rss    88784 usr  37.74 sys  61.46 tot  99.20
readFileSync 1336    time     2066 rate     145189 rate/core     147806 ns/iter      6887.55 rss    91440 usr  38.71 sys  59.52 tot  98.23
readFileSync 1336    time     2053 rate     146108 rate/core     150009 ns/iter      6844.23 rss    91420 usr  36.04 sys  61.36 tot  97.40
readFileSync 1336    time     2051 rate     146255 rate/core     148528 ns/iter      6837.33 rss    93804 usr  37.05 sys  61.42 tot  98.47
readFileSync 1336    time     2057 rate     145820 rate/core     148539 ns/iter      6857.73 rss    94108 usr  35.96 sys  62.21 tot  98.17
readFileSync 1336    time     2072 rate     144761 rate/core     147791 ns/iter      6907.92 rss    93124 usr  41.98 sys  55.97 tot  97.95
readFileSync 1336    time     2075 rate     144510 rate/core     147084 ns/iter      6919.89 rss    93176 usr  39.49 sys  58.76 tot  98.25
readFileSync 1336    time     2070 rate     144892 rate/core     148532 ns/iter      6901.67 rss    91872 usr  42.50 sys  55.05 tot  97.55
readFileSync 1336    time     2065 rate     145274 rate/core     148542 ns/iter      6883.53 rss    92000 usr  38.73 sys  59.07 tot  97.80
readFileSync 1336    time     2062 rate     145460 rate/core     147796 ns/iter      6874.71 rss    92060 usr  38.30 sys  60.12 tot  98.42
root@8f04c899517e:/bench# deno run -A read_as_text.mjs 
readFileSync 1336    time     4021 rate      74604 rate/core      72999 ns/iter     13404.09 rss    59732 usr  55.70 sys  46.50 tot 102.20
readFileSync 1336    time     3981 rate      75356 rate/core      74448 ns/iter     13270.24 rss    59328 usr  55.76 sys  45.46 tot 101.22
readFileSync 1336    time     3974 rate      75478 rate/core      74444 ns/iter     13248.72 rss    59328 usr  53.59 sys  47.80 tot 101.39
readFileSync 1336    time     3982 rate      75327 rate/core      74449 ns/iter     13275.45 rss    59328 usr  55.49 sys  45.69 tot 101.18
readFileSync 1336    time     3977 rate      75424 rate/core      74449 ns/iter     13258.31 rss    59456 usr  52.04 sys  49.27 tot 101.31
readFileSync 1336    time     4017 rate      74682 rate/core      73717 ns/iter     13390.07 rss    59584 usr  50.53 sys  50.78 tot 101.31
readFileSync 1336    time     3995 rate      75079 rate/core      73897 ns/iter     13319.26 rss    59712 usr  52.55 sys  49.05 tot 101.60
readFileSync 1336    time     4005 rate      74900 rate/core      74086 ns/iter     13350.97 rss    59712 usr  54.17 sys  46.93 tot 101.10
readFileSync 1336    time     3998 rate      75027 rate/core      73723 ns/iter     13328.46 rss    59840 usr  54.26 sys  47.51 tot 101.77
readFileSync 1336    time     4005 rate      74905 rate/core      74083 ns/iter     13350.18 rss    59840 usr  53.18 sys  47.93 tot 101.11
root@8f04c899517e:/bench# node read_as_text_async.mjs 
readFile 1336        time     2252 rate      13315 rate/core      10381 ns/iter     75098.85 rss    59616 usr  81.67 sys  46.60 tot 128.27
readFile 1336        time     2213 rate      13554 rate/core      10832 ns/iter     73776.81 rss    59744 usr  79.06 sys  46.08 tot 125.14
readFile 1336        time     1929 rate      15546 rate/core      12554 ns/iter     64324.27 rss    59744 usr  80.32 sys  43.52 tot 123.84
readFile 1336        time     1940 rate      15457 rate/core      12449 ns/iter     64694.63 rss    59744 usr  79.86 sys  44.31 tot 124.17
readFile 1336        time     2248 rate      13339 rate/core      10715 ns/iter     74966.56 rss    59744 usr  80.92 sys  43.57 tot 124.49
readFile 1336        time     2254 rate      13306 rate/core      10716 ns/iter     75149.36 rss    63456 usr  82.05 sys  42.13 tot 124.18
readFile 1336        time     1949 rate      15387 rate/core      12348 ns/iter     64988.71 rss    63456 usr  75.39 sys  49.23 tot 124.62
readFile 1336        time     2103 rate      14263 rate/core      11539 ns/iter     70110.79 rss    63456 usr  79.87 sys  43.74 tot 123.61
readFile 1336        time     2061 rate      14550 rate/core      11719 ns/iter     68727.72 rss    63456 usr  82.45 sys  41.71 tot 124.16
readFile 1336        time     2136 rate      14039 rate/core      11279 ns/iter     71228.57 rss    63456 usr  80.96 sys  43.52 tot 124.48
root@8f04c899517e:/bench# bun read_as_text_async.mjs 
readFile 1336        time      620 rate      48347 rate/core      35295 ns/iter     20683.52 rss    59136 usr  61.24 sys  75.74 tot 136.98
readFile 1336        time      643 rate      46617 rate/core      37978 ns/iter     21451.34 rss    59772 usr  66.81 sys  55.94 tot 122.75
readFile 1336        time      635 rate      47174 rate/core      38463 ns/iter     21197.96 rss    59772 usr  64.47 sys  58.18 tot 122.65
readFile 1336        time      628 rate      47751 rate/core      38463 ns/iter     20941.78 rss    60284 usr  65.26 sys  58.89 tot 124.15
readFile 1336        time      633 rate      47323 rate/core      38966 ns/iter     21131.11 rss    60284 usr  52.05 sys  69.40 tot 121.45
readFile 1336        time      616 rate      48691 rate/core      39474 ns/iter     20537.34 rss    58496 usr  58.43 sys  64.92 tot 123.35
readFile 1336        time      642 rate      46726 rate/core      38464 ns/iter     21400.96 rss    58496 usr  56.07 sys  65.41 tot 121.48
readFile 1336        time      623 rate      48089 rate/core      38964 ns/iter     20794.51 rss    58624 usr  57.70 sys  65.72 tot 123.42
readFile 1336        time      619 rate      48405 rate/core      39476 ns/iter     20658.66 rss    58624 usr  58.08 sys  64.54 tot 122.62
readFile 1336        time      602 rate      49771 rate/core      40544 ns/iter     20091.75 rss    58624 usr  59.72 sys  63.04 tot 122.76
root@8f04c899517e:/bench# deno run -A read_as_text_async.mjs 
readFile 1336        time      948 rate      31636 rate/core      24796 ns/iter     31609.22 rss    62596 usr  79.09 sys  48.50 tot 127.59
readFile 1336        time     1038 rate      28889 rate/core      24196 ns/iter     34614.83 rss    62596 usr  80.89 sys  38.51 tot 119.40
readFile 1336        time     1070 rate      28020 rate/core      23257 ns/iter     35687.75 rss    62852 usr  74.72 sys  45.76 tot 120.48
readFile 1336        time      999 rate      30001 rate/core      24795 ns/iter     33331.87 rss    62852 usr  79.00 sys  42.00 tot 121.00
readFile 1336        time      979 rate      30625 rate/core      25643 ns/iter     32652.21 rss    62980 usr  77.58 sys  41.85 tot 119.43
readFile 1336        time     1020 rate      29394 rate/core      24392 ns/iter     34019.46 rss    62980 usr  74.46 sys  46.05 tot 120.51
readFile 1336        time      881 rate      34049 rate/core      28848 ns/iter     29369.27 rss    62980 usr  71.50 sys  46.53 tot 118.03
readFile 1336        time      936 rate      32017 rate/core      27030 ns/iter     31232.68 rss    62980 usr  70.43 sys  48.02 tot 118.45
readFile 1336        time     1033 rate      29031 rate/core      25001 ns/iter     34445.16 rss    62980 usr  74.51 sys  41.61 tot 116.12
readFile 1336        time      970 rate      30922 rate/core      26088 ns/iter     32339.41 rss    62980 usr  73.18 sys  45.35 tot 118.53

readdir setup

wget https://www.openssl.org/source/openssl-3.0.12.tar.gz
tar -xvf openssl-3.0.12.tar.gz

readdir run

root@b1847c7942ea:/bench# node readdir.mjs 
readdirSync          time     3136 rate        191 rate/core        189 ns/iter   5227845.44 rss    71184 usr  43.67 sys  57.70 tot 101.37
readdirSync          time     3157 rate        190 rate/core        192 ns/iter   5261768.56 rss    87568 usr  43.39 sys  56.06 tot  99.45
readdirSync          time     3120 rate        192 rate/core        194 ns/iter   5200281.65 rss    87568 usr  42.30 sys  57.04 tot  99.34
readdirSync          time     3121 rate        192 rate/core        193 ns/iter   5203181.83 rss    87568 usr  42.60 sys  57.01 tot  99.61
readdirSync          time     3121 rate        192 rate/core        194 ns/iter   5203190.68 rss    87568 usr  41.00 sys  58.29 tot  99.29
readdirSync          time     3116 rate        192 rate/core        194 ns/iter   5193774.58 rss    87568 usr  44.60 sys  54.55 tot  99.15
readdirSync          time     3164 rate        189 rate/core        190 ns/iter   5273977.51 rss    87568 usr  40.13 sys  59.41 tot  99.54
readdirSync          time     3123 rate        192 rate/core        194 ns/iter   5205329.63 rss    87568 usr  42.58 sys  56.67 tot  99.25
readdirSync          time     3123 rate        192 rate/core        192 ns/iter   5206163.86 rss    87628 usr  40.01 sys  60.18 tot 100.19
readdirSync          time     3104 rate        193 rate/core        194 ns/iter   5174705.63 rss    88008 usr  38.64 sys  60.87 tot  99.51
root@b1847c7942ea:/bench# bun readdir.mjs 
readdirSync          time     2923 rate        205 rate/core        203 ns/iter   4872872.21 rss   322500 usr  38.99 sys  62.24 tot 101.23
readdirSync          time     2896 rate        207 rate/core        207 ns/iter   4827375.33 rss   519608 usr  37.97 sys  62.14 tot 100.11
readdirSync          time     2910 rate        206 rate/core        207 ns/iter   4850817.14 rss   717404 usr  39.16 sys  60.81 tot  99.97
readdirSync          time     2900 rate        206 rate/core        205 ns/iter   4833975.85 rss   914676 usr  39.99 sys  60.68 tot 100.67
readdirSync          time     2901 rate        206 rate/core        205 ns/iter   4835062.86 rss  1109668 usr  38.95 sys  61.70 tot 100.65
readdirSync          time     2907 rate        206 rate/core        204 ns/iter   4845513.94 rss  1306916 usr  41.27 sys  59.84 tot 101.11
readdirSync          time     2904 rate        206 rate/core        205 ns/iter   4840913.15 rss  1503744 usr  39.24 sys  61.62 tot 100.86
readdirSync          time     2913 rate        205 rate/core        203 ns/iter   4855396.75 rss  1700668 usr  39.13 sys  62.13 tot 101.26
readdirSync          time     2916 rate        205 rate/core        202 ns/iter   4860366.63 rss  1895152 usr  40.12 sys  61.38 tot 101.50
readdirSync          time     2912 rate        205 rate/core        202 ns/iter   4854814.63 rss  2092684 usr  40.16 sys  61.45 tot 101.61
root@b1847c7942ea:/bench# node readdir_async.mjs 
readdir (async)      time     6745 rate         88 rate/core         86 ns/iter  11242754.00 rss    83836 usr  54.99 sys  48.32 tot 103.31
readdir (async)      time     6809 rate         88 rate/core         87 ns/iter  11349926.67 rss    84092 usr  53.15 sys  48.31 tot 101.46
readdir (async)      time     6559 rate         91 rate/core         89 ns/iter  10932207.83 rss    84092 usr  56.40 sys  46.95 tot 103.35
readdir (async)      time     6692 rate         89 rate/core         88 ns/iter  11154978.83 rss    84092 usr  54.98 sys  47.06 tot 102.04
readdir (async)      time     6805 rate         88 rate/core         87 ns/iter  11341976.98 rss    84092 usr  58.19 sys  43.05 tot 101.24
readdir (async)      time     6749 rate         88 rate/core         87 ns/iter  11249886.93 rss    84092 usr  56.59 sys  45.63 tot 102.22
readdir (async)      time     6758 rate         88 rate/core         87 ns/iter  11264053.11 rss    84092 usr  57.26 sys  44.98 tot 102.24
readdir (async)      time     6670 rate         89 rate/core         87 ns/iter  11116963.93 rss    84220 usr  57.56 sys  44.97 tot 102.53
readdir (async)      time     6797 rate         88 rate/core         86 ns/iter  11328988.68 rss    84220 usr  56.63 sys  46.63 tot 103.26
readdir (async)      time     6544 rate         91 rate/core         90 ns/iter  10907676.36 rss    84500 usr  56.84 sys  44.92 tot 101.76
root@b1847c7942ea:/bench# bun readdir_async.mjs 
readdir (async)      time      982 rate        610 rate/core        118 ns/iter   1637018.12 rss   336112 usr 241.29 sys 279.98 tot 521.27
readdir (async)      time      963 rate        623 rate/core        119 ns/iter   1605124.75 rss   565784 usr 244.01 sys 280.35 tot 524.36
readdir (async)      time      960 rate        624 rate/core        119 ns/iter   1601039.25 rss   768740 usr 242.55 sys 285.23 tot 527.78
readdir (async)      time      967 rate        619 rate/core        118 ns/iter   1613063.82 rss   976400 usr 247.97 sys 278.97 tot 526.94
readdir (async)      time      977 rate        613 rate/core        118 ns/iter   1628949.56 rss  1181584 usr 247.60 sys 275.22 tot 522.82
readdir (async)      time      983 rate        610 rate/core        117 ns/iter   1638423.51 rss  1382360 usr 244.13 sys 278.72 tot 522.85
readdir (async)      time      979 rate        612 rate/core        116 ns/iter   1632312.49 rss  1584780 usr 261.38 sys 266.49 tot 527.87
readdir (async)      time      980 rate        612 rate/core        116 ns/iter   1633956.65 rss  1790856 usr 234.60 sys 293.76 tot 528.36
readdir (async)      time      980 rate        612 rate/core        116 ns/iter   1633807.56 rss  1993436 usr 241.76 sys 289.71 tot 531.47
readdir (async)      time     1100 rate        545 rate/core        103 ns/iter   1834554.38 rss  2196984 usr 261.64 sys 272.54 tot 534.18
function is_a_tty (fd = 1) {
if (globalThis.Deno) return Deno.isatty(fd)
if (globalThis.lo) return lo.core.isatty(fd)
if (fd === 1) return process.stdout.isTTY
if (fd === 2) return process.stderr.isTTY
return process.stdin.isTTY
}
const isatty = is_a_tty()
const AD = isatty ? '\u001b[0m' : '' // ANSI Default
const A0 = isatty ? '\u001b[30m' : '' // ANSI Black
const AR = isatty ? '\u001b[31m' : '' // ANSI Red
const AG = isatty ? '\u001b[32m' : '' // ANSI Green
const AY = isatty ? '\u001b[33m' : '' // ANSI Yellow
const AB = isatty ? '\u001b[34m' : '' // ANSI Blue
const AM = isatty ? '\u001b[35m' : '' // ANSI Magenta
const AC = isatty ? '\u001b[36m' : '' // ANSI Cyan
const AW = isatty ? '\u001b[37m' : '' // ANSI White
const colors = { AD, AG, AY, AM, AD, AR, AB, AC, AW, A0 }
class Stats {
recv = 0
send = 0
conn = 0
rps = 0
log () {
const { send, recv, conn, rps } = this
const [ usr, , sys ] = cputime()
console.log(`${AC}send${AD} ${to_size_string(send)} ${AC}recv${AD} ${to_size_string(recv)} ${AC}rps${AD} ${rps} ${AC}rss${AD} ${mem()} ${AC}con${AD} ${conn} ${AY}usr${AD} ${usr.toString().padStart(3, ' ')} ${AY}sys${AD} ${sys.toString().padStart(3, ' ')} ${AY}tot${AD} ${(usr + sys).toString().padStart(3, ' ')}`)
this.send = this.recv = this.rps = 0
}
get runtime () {
return lo.hrtime() - lo.start
}
}
function pad (v, size, precision = 0) {
return v.toFixed(precision).padStart(size, ' ')
}
function memory_usage (buf) {
return Math.floor((Number(decoder.decode(buf).split(' ')[23]) * 4096) / (1024))
}
let lastusr = 0
let lastsys = 0
function cpu_usage (bytes) {
const str = decoder.decode(bytes)
const parts = str.split(' ')
const usr = Number(parts[13])
const sys = Number(parts[14])
const res = [(usr - lastusr) / 100, (sys - lastsys) / 100]
lastusr = usr
lastsys = sys
return res
}
async function wrap_mem_usage () {
if (globalThis.Deno) {
if (Deno.build.os !== 'linux') return () => 0
const mem = () => memory_usage(Deno.readFileSync('/proc/self/stat'))
const cputime = () => cpu_usage(Deno.readFileSync('/proc/self/stat'))
return { mem, cputime }
}
if (globalThis.Bun) {
if (require('node:os').platform() !== 'linux') return () => 0
const fs = require('node:fs')
const mem = () => memory_usage(fs.readFileSync('/proc/self/stat'))
const cputime = () => cpu_usage(fs.readFileSync('/proc/self/stat'))
return { mem, cputime }
}
if (globalThis.process) {
const os = await import('os')
if (os.platform() !== 'linux') return () => 0
const fs = await import('fs')
const mem = () => memory_usage(fs.readFileSync('/proc/self/stat'))
const cputime = () => cpu_usage(fs.readFileSync('/proc/self/stat'))
return { mem, cputime }
}
if (globalThis.lo) {
const mem = () => memory_usage(lo.core.read_file('/proc/self/stat', lo.core.READ_ONLY, 65536))
const cputime = () => cpu_usage(lo.core.read_file('/proc/self/stat', lo.core.READ_ONLY, 65536))
return { mem, cputime }
}
}
function to_size_string (bytes) {
if (bytes < 1000) {
return `${bytes.toFixed(2)} Bps`
} else if (bytes < 1000 * 1000) {
return `${(Math.floor((bytes / 1000) * 100) / 100).toFixed(2)} KBps`
} else if (bytes < 1000 * 1000 * 1000) {
return `${(Math.floor((bytes / (1000 * 1000)) * 100) / 100).toFixed(2)} MBps`
}
return `${(Math.floor((bytes / (1000 * 1000 * 1000)) * 100) / 100).toFixed(2)} GBps`
}
function formatNanos (nanos) {
if (nanos >= 1000000000) return `${AY}sec/iter${AD} ${pad((nanos / 1000000000), 10, 2)}`
if (nanos >= 1000000) return `${AY}ms/iter${AD} ${pad((nanos / 1000000), 10, 2)}`
if (nanos >= 1000) return `${AY}μs/iter${AD} ${pad((nanos / 1000), 10, 2)}`
return `${AY}ns/iter${AD} ${pad(nanos, 10, 2)}`
}
function bench (name, fn, count, after = noop) {
const start = performance.now()
for (let i = 0; i < count; i++) fn()
const elapsed = (performance.now() - start)
const rate = Math.floor(count / (elapsed / 1000))
const nanos = 1000000000 / rate
const rss = mem()
console.log(`${name.slice(0, 32).padEnd(17, ' ')} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`)
after()
return { name, count, elapsed, rate, nanos, rss, runtime }
}
async function benchAsync (name, fn, count, after = noop) {
const start = performance.now()
for (let i = 0; i < count; i++) await fn()
const elapsed = (performance.now() - start)
const rate = Math.floor((count / (elapsed / 1000)) * 100) / 100
const nanos = 1000000000 / rate
const rss = mem()
console.log(`${name.slice(0, 32).padEnd(17, ' ')} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`)
after()
return { name, count, elapsed, rate, nanos, rss, runtime }
}
const runAsync = async (name, fn, count, repeat = 10, after = () => {}) => {
const runs = []
for (let i = 0; i < repeat; i++) {
runs.push(await benchAsync(name, fn, count, after))
}
return runs
}
const run = (name, fn, count, repeat = 10, after = () => {}) => {
const runs = []
for (let i = 0; i < repeat; i++) {
runs.push(bench(name, fn, count, after))
}
return runs
}
function arrayEquals (a, b) {
return Array.isArray(a) &&
Array.isArray(b) &&
a.length === b.length &&
a.every((val, index) => val === b[index])
}
class Bench {
#start = 0
#end = 0
#name = 'bench'
#display = true
#name_width = 20
constructor (display = true) {
this.#display = display
}
set name_width (len) {
this.#name_width = len
}
start (name = 'bench') {
this.#name = name.slice(0, 32).padEnd(32, ' ')
this.#start = performance.now()
}
end (count = 0, size = 0) {
this.#end = performance.now()
const elapsed = this.#end - this.#start
const nanos = Math.floor(elapsed * 1000000)
const seconds = nanos / 1000000000
const rate = Math.floor(count / seconds)
const rss = mem()
const cpu = cputime()
const usr = Math.floor((cpu[0] / seconds) * 10000) / 100
const sys = Math.floor((cpu[1] / seconds) * 10000) / 100
//const total = Math.floor(((cpu[0] + cpu[1]) / seconds) * 100 )
const total = usr + sys
const rate_pc = Math.ceil(rate / (total / 100))
const ns_iter = Math.floor((nanos / count) * 100) / 100
if (this.#display) {
if (size) {
console.log(`${AM}${this.#name.trim().padEnd(this.#name_width, ' ')}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, ' ')} ${AY}rate${AD} ${rate.toString().padStart(10, ' ')} ${AM}rate/core${AD} ${rate_pc.toString().padStart(10, ' ')} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, ' ')} ${AG}rss${AD} ${rss.toString().padStart(8, ' ')} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, ' ')} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, ' ')} ${AY}tot${AD} ${total.toFixed(2).padStart(6, ' ')} ${AG}thru${AD} ${to_size_string(rate_pc * size).padStart(12, ' ')}`)
} else {
console.log(`${AM}${this.#name.trim().padEnd(this.#name_width, ' ')}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, ' ')} ${AY}rate${AD} ${rate.toString().padStart(10, ' ')} ${AM}rate/core${AD} ${rate_pc.toString().padStart(10, ' ')} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, ' ')} ${AG}rss${AD} ${rss.toString().padStart(8, ' ')} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, ' ')} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, ' ')} ${AY}tot${AD} ${total.toFixed(2).padStart(6, ' ')}`)
}
}
return { name: this.#name.trim(), count, elapsed, rate, nanos, rss, runtime, usr, sys, rate_pc, ns_iter, seconds }
}
}
const runtime = { name: '', version: '' }
if (globalThis.Deno) {
globalThis.args = Deno.args
runtime.name = 'deno'
runtime.version = Deno.version.deno
runtime.v8 = Deno.version.v8
globalThis.readFileAsText = async fn => decoder.decode(Deno.readFileSync(fn))
globalThis.readFileAsBytes = async fn => Deno.readFileSync(fn)
globalThis.writeFileAsText = async (fn, str) => Deno.writeFileSync(fn, encoder.encode(str))
globalThis.writeFileAsBytes = async (fn, u8) => Deno.writeFileSync(fn, u8)
const fs = await import('node:fs')
globalThis.openSync = fs.openSync
globalThis.readSync = fs.readSync
globalThis.closeSync = fs.closeSync
globalThis.readFileSync = fs.readFileSync
} else if (globalThis.lo) {
globalThis.performance = { now: () => lo.hrtime() / 1000000 }
globalThis.assert = lo.assert
globalThis.args = lo.args.slice(2)
runtime.name = 'lo'
runtime.version = lo.version.lo
runtime.v8 = lo.version.v8
const { readFile, writeFile } = lo.core
const { close, open, read, O_RDONLY } = lo.core
globalThis.readFileAsText = async fn => decoder.decode(readFile(fn))
globalThis.readFileAsBytes = async fn => readFile(fn)
globalThis.writeFileAsText = async (fn, str) => writeFile(fn, encoder.encode(str))
globalThis.writeFileAsBytes = async (fn, u8) => writeFile(fn, u8)
globalThis.openSync = file_name => open(file_name, O_RDONLY)
globalThis.readSync = (fd, buf) => read(fd, buf, buf.length)
globalThis.closeSync = fd => close(fd)
globalThis.readFileSync = readFile
} else if (globalThis.Bun) {
globalThis.args = Bun.argv.slice(2)
runtime.name = 'bun'
runtime.version = Bun.version
globalThis.readFileAsText = async fn => (await Bun.file(fn).text())
globalThis.readFileAsBytes = async fn => (await Bun.file(fn).bytes())
globalThis.writeFileAsText = async (fn, str) => Bun.write(fn, str)
globalThis.writeFileAsBytes = async (fn, u8) => Bun.write(fn, u8)
const fs = await import('node:fs')
globalThis.openSync = fs.openSync
globalThis.readSync = fs.readSync
globalThis.closeSync = fs.closeSync
globalThis.readFileSync = fs.readFileSync
} else if (globalThis.process) {
globalThis.args = process.argv.slice(2)
runtime.name = 'node'
runtime.version = process.version
runtime.v8 = process.versions.v8
const fs = await import('fs')
globalThis.readFileAsText = async fn => decoder.decode(fs.readFileSync(fn))
globalThis.readFileAsBytes = async fn => fs.readFileSync(fn)
globalThis.writeFileAsText = async (fn, str) => fs.writeFileSync(fn, encoder.encode(str))
globalThis.writeFileAsBytes = async (fn, u8) => fs.writeFileSync(fn, u8)
globalThis.openSync = fs.openSync
globalThis.readSync = fs.readSync
globalThis.closeSync = fs.closeSync
globalThis.readFileSync = fs.readFileSync
}
globalThis.colors = colors
globalThis.arrayEquals = arrayEquals
const noop = () => {}
const { mem, cputime } = await wrap_mem_usage()
const decoder = new TextDecoder()
const encoder = new TextEncoder()
if (!globalThis.assert) {
function assert (condition, message, ErrorType = Error) {
if (!condition) {
throw new ErrorType(message || "Assertion failed")
}
}
globalThis.assert = assert
}
const measure = {
start: () => {
cputime()
measure._start = performance.now()
},
end: () => {
const nanos = Math.floor((performance.now() - measure._start) * 1000000)
const seconds = nanos / 1000000000
const cpu = cputime()
const usr = Math.floor((cpu[0] / seconds) * 100) / 100
const sys = Math.floor((cpu[1] / seconds) * 100) / 100
const total = Math.floor(((cpu[0] + cpu[1]) / seconds) * 100 ) / 100
const rss = mem()
const cpu_time = Math.floor(nanos * total)
return { rss, usr, sys, total, nanos, cpu_time }
},
log: () => {
const { rss, nanos, usr, sys, total, cpu_time } = measure.end()
console.log(`${AY}time${AD} ${nanos} ns ${AY}cputime${AD} ${cpu_time} ns ${AG}rss${AD} ${rss} KB ${AM}cpu${AD} ${usr} / ${sys} (${total})`)
}
}
export {
pad, formatNanos, colors, run, runAsync, Bench, mem, runtime, to_size_string,
Stats, cputime, measure, is_a_tty, cpu_usage, memory_usage
}
FROM debian:bookworm-slim
RUN apt-get update -y --fix-missing
RUN apt-get install -y curl make g++ autoconf libtool unzip xz-utils golang dmidecode python3
WORKDIR /bench
# hyperfine
ARG HYPERFINE_VERSION=1.18.0
RUN curl -L -o hyperfine_${HYPERFINE_VERSION}_amd64.deb https://github.com/sharkdp/hyperfine/releases/download/v${HYPERFINE_VERSION}/hyperfine_${HYPERFINE_VERSION}_amd64.deb
RUN dpkg -i hyperfine_${HYPERFINE_VERSION}_amd64.deb
RUN rm hyperfine_${HYPERFINE_VERSION}_amd64.deb
# poop
ARG POOP_VERSION=0.4.0
RUN curl -L -o poop https://github.com/andrewrk/poop/releases/download/${POOP_VERSION}/x86_64-linux-poop
RUN mv poop /usr/local/bin/
# node.js
ARG NODE_VERSION=22.2.0
RUN curl -L -o nodejs.tar.xz https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz
RUN tar -xvf nodejs.tar.xz
RUN mv node-v${NODE_VERSION}-linux-x64 /root/.node
ENV NODE_ENV=production
RUN rm nodejs.tar.xz
# bun
RUN /bin/bash -o pipefail -c "$(curl -fsSL https://bun.sh/install)"
# deno
RUN /bin/bash -o pipefail -c "$(curl -fsSL https://deno.land/install.sh)"
# lo
ARG LO_VERSION=0.0.16-pre
RUN curl -L -o ${LO_VERSION}.tar.gz https://github.com/just-js/lo/archive/refs/tags/${LO_VERSION}.tar.gz
RUN tar -xf ${LO_VERSION}.tar.gz
RUN mv lo-${LO_VERSION} /root/.lo
RUN rm ${LO_VERSION}.tar.gz
RUN curl -L -o lo-linux-x64.gz https://github.com/just-js/lo/releases/download/${LO_VERSION}/lo-linux-x64.gz
RUN gunzip lo-linux-x64.gz
RUN chmod +x lo-linux-x64
RUN ./lo-linux-x64 install
RUN rm lo-linux-x64
# fix permissions for root
RUN chown -R root:root /root/.deno/
RUN chown -R root:root /root/.node/
RUN chown -R root:root /root/.bun/
RUN chmod +x /usr/local/bin/poop
# add paths to installed apps
ENV LO_HOME="/root/.lo"
ENV PATH="/root/.node/bin:/root/.bun/bin:/root/.lo/bin:/root/.deno/bin:$PATH"
RUN npm install -g node-gyp
RUN apt install -y cmake
# for sbffi
RUN npm install -g prebuild node-addon-api cmake-js
#RUN go install "github.com/prometheus/procfs@latest"
#RUN go mod init github.com/billywhizz/linecount
#RUN go get github.com/prometheus/procfs
#RUN go get gopkg.ilharper.com/x/isatty
CMD ["/bin/bash"]
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
import { Bench } from './bench.mjs'
import { readFileSync } from 'node:fs'
const bench = new Bench()
const file_name = './lipsum.txt'
const encoding = { encoding: 'utf-8' }
const expected = readFileSync(file_name, encoding).length
let iter = 10
let runs = 300000
for (let i = 0; i < iter; i++) {
bench.start(`readFileSync ${expected}`)
for (let j = 0; j < runs; j++) {
assert(expected === readFileSync(file_name, encoding).length)
}
bench.end(runs)
}
import { Bench } from './bench.mjs'
import { promises } from 'node:fs'
const { readFile } = promises
const bench = new Bench()
const file_name = './lipsum.txt'
const encoding = { encoding: 'utf-8' }
const expected = (await readFile(file_name, encoding)).length
let iter = 10
let runs = 30000
for (let i = 0; i < iter; i++) {
bench.start(`readFile ${expected}`)
for (let j = 0; j < runs; j++) {
assert(expected === (await readFile(file_name, encoding)).length)
}
bench.end(runs)
}
import { Bench } from './bench.mjs'
const { core, utf8_decode, ptr } = lo
const { read_file } = core
const { open, close, read2, O_RDONLY } = core
const decoder = new TextDecoder()
const MAX_SIZE = 1337
const u8 = ptr(new Uint8Array(MAX_SIZE))
function read_as_text (path) {
const fd = open(path, O_RDONLY)
assert(fd > 0)
let off = 0
let len = 0
while ((len = read2(fd, u8.ptr + off, Math.max(65536, MAX_SIZE - off))) > 0) off += len
close(fd)
return utf8_decode(u8.ptr, off)
}
const bench = new Bench()
let iter = 10
let runs = 300000
const file_name = './lipsum.txt'
const expected = decoder.decode(read_file(file_name)).length
const size = expected
for (let i = 0; i < iter; i++) {
bench.start(`read_as_text ${size}`)
for (let j = 0; j < runs; j++) {
assert(expected === read_as_text(file_name).length)
}
bench.end(runs)
}
import { Bench } from './bench.mjs'
import { readdirSync } from "node:fs";
import { argv } from 'node:process'
const dir = argv.length > 2 ? argv[2] : 'openssl-3.0.12'
const opts = { recursive: true, withFileTypes: true }
const entries = readdirSync(dir, opts)
assert(entries.length === 4847)
const bench = new Bench()
const iter = 10
const runs = 600
for (let i = 0; i < iter; i++) {
bench.start(`readdirSync`)
for (let j = 0; j < runs; j++) {
assert(readdirSync(dir, opts).length === 4847)
}
bench.end(runs)
}
import { Bench } from './bench.mjs'
import { readdir } from 'node:fs/promises'
import { argv } from 'node:process'
const dir = argv.length > 2 ? argv[2] : 'openssl-3.0.12'
const opts = { recursive: true, withFileTypes: true }
const entries = await readdir(dir, opts)
assert(entries.length === 4847)
const bench = new Bench()
const iter = 10
const runs = 600
for (let i = 0; i < iter; i++) {
bench.start(`readdir (async)`)
for (let j = 0; j < runs; j++) {
assert((await readdir(dir, opts)).length === 4847)
}
bench.end(runs)
}
import { Bench } from './bench.mjs'
const { assert, core, ptr, latin1Decode } = lo
const {
open, close, getdents, strnlen, O_RDONLY, O_DIRECTORY
} = core
const default_options = { withFileTypes: false }
let depth = 0
const records = (new Array(64)).fill(0).map(v => {
const dir = ptr(new Uint8Array(65536))
const view = new DataView(dir.buffer)
return { view, dir, dir_len: dir.length, dir_ptr: dir.ptr }
})
function readdir (path, options = default_options, entries = []) {
const fd = open(path, O_RDONLY | O_DIRECTORY)
assert(fd > 2)
const { view, dir, dir_len, dir_ptr } = records[depth]
dir.fill(0)
assert(getdents(fd, dir_ptr, dir_len) > 0)
let off = 0
let d_ino = view.getUint32(off, true)
depth++
while (d_ino > 0) {
const d_reclen = view.getUint16(off + 16, true)
const d_type = dir[off + 18]
const name = latin1Decode(dir_ptr + off + 19, strnlen(dir_ptr + off + 19, 1024))
if (!(name === '..' || name === '.')) {
const entry_path = `${path}/${name}`
if (d_type === 4) {
entries.push({ path, name: entry_path, type: d_type })
readdir(entry_path, options, entries)
} else if (d_type === 8) {
entries.push({ path, name, type: d_type })
}
}
off += d_reclen
d_ino = view.getUint32(off, true)
}
depth--
close(fd)
}
const dir = lo.args[2] || 'openssl-3.0.12'
const entries = []
const opts = { recursive: true, withFileTypes: true }
readdir(dir, opts, entries);
assert(entries.length === 4847)
/*
for (const entry of entries) {
console.log(`path ${entry.path} name ${entry.name} directory ${entry.type === 4} file ${entry.type === 8}`)
}
*/
const bench = new Bench()
const iter = 10
const runs = 600
for (let i = 0; i < iter; i++) {
bench.start(`readdir`)
for (let j = 0; j < runs; j++) {
readdir(dir, opts, []);
}
bench.end(runs)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment