Skip to content

Instantly share code, notes, and snippets.

@diegovgsilva95
Created February 2, 2025 10:53
Show Gist options
  • Select an option

  • Save diegovgsilva95/80347347758341032662dd6c1528dd0a to your computer and use it in GitHub Desktop.

Select an option

Save diegovgsilva95/80347347758341032662dd6c1528dd0a to your computer and use it in GitHub Desktop.
Node.js - Fair performance testing between two or more algorithms, or simply spawning isolated JS functions/code

Use cases

  • Spawning an isolated Node.js environment for running a given code
  • Accurately timing the execution of a given code (bypassing JIT optimizations which would lead to a biased timing)
  • Accurately comparing the timing between two or more algorithms (also, bypassing JIT optimizations which would lead to a biased timing)
import { spawn } from "child_process"
import { log } from "console"
process.stdout.write("\x1b[H\x1b[2J\x1b[3J")
const funToSrc = function(fn){
if(typeof fn !== "function")
throw new TypeError("fn should be a function")
let fns = fn.toString()
return fns.slice(fns.indexOf("{")+1, fns.lastIndexOf("}"))
}
// console.log(`[Main] Main PID = ${process.pid}`)
const termFn = _ => {var __INIT_TIME = performance.now();process.on("beforeExit", _ => {process.send(performance.now()-__INIT_TIME)})}
const runFun = (fn, timeout = 5000) =>
new Promise((res) => {
let start = 0
let reportedDelay = null
let offspring = spawn("node",["--input-type=module", "-"], {
stdio: ["pipe", "inherit", "inherit", "ipc"],
})
let silverBullet = setTimeout(() => {
// log("[Main] Offspring timeout")
offspring.kill()
silverBullet = null
res({error:"TIMEOUT"})
}, timeout)
offspring.on("exit", function(code){
if(silverBullet){
let outerDelay = performance.now()-start
// log("[Main] Offspring is done")
clearTimeout(silverBullet)
res(code!=0?{error:code}:{reportedDelay, outerDelay})
}
}).on("message", function(data){
if(typeof data === "number")
reportedDelay = data
})
let sourceCode = ""
sourceCode+=funToSrc(termFn) + ";\n"
sourceCode+=funToSrc(fn)
sourceCode=sourceCode.trim();
// log(`[Main] Source:\n${sourceCode}\n---`)
offspring.stdin.write(sourceCode)
offspring.stdin.end(_ => start = performance.now())
}
)
// Example: comparing log2 v. clz32 for determining how many bits a number has
log(`[Main] log2 approach:`, await runFun(async function(){
let dummyVar = null
for(let k = 0; k < 1E8; k++){
dummyVar = Math.ceil(Math.log2((k||1)+1))
}
}))
log(`[Main] clz32 approach:`, await runFun(async function(){
let dummyVar = null
for(let k = 0; k < 1E8; k++){
dummyVar = 32-Math.clz32(k||1)
}
}))
// Expected output be like:
//[Main] log2 approach: { reportedDelay: 1558.801457002759, outerDelay: 1597.571946002543 }
//[Main] clz32 approach: { reportedDelay: 132.8723310008645, outerDelay: 168.81133100390434 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment