test: Fix and update recursive-delete benchmarks (#84875)

PR created with claude code, with some manual review.

- Update benchmark scripts to work, given my recent code changes
- Include a native nodejs benchmark
- Use rimraf's `manual` implementation (tries to use node's native version)
- Tried to clean up the code a bit
- Use a trap to always clean up
- Use getopt and add an `--iterations` option
- `set -euo pipefail` to avoid swallowing errors

Example output:

```
pnpm bench

> bench-recursive-delete@ bench /home/bgw.linux/next.js/bench/recursive-delete
> bash run.sh

-----------
rimraf (async) 1
62.443657
rimraf (async) 2
52.953482
rimraf (async) 3
52.029235
rimraf (async) 4
50.709822
rimraf (async) 5
54.204893
-----------
rimraf (sync) 1
35.034669
rimraf (sync) 2
35.663417
rimraf (sync) 3
46.360754
rimraf (sync) 4
36.859329
rimraf (sync) 5
34.368796
-----------
recursive delete 1
37.851534
recursive delete 2
35.98904
recursive delete 3
36.620913
recursive delete 4
38.059992
recursive delete 5
43.880346
-----------
nodejs rm (promises) 1
71.301125
nodejs rm (promises) 2
89.78331
nodejs rm (promises) 3
68.073553
nodejs rm (promises) 4
70.787543
nodejs rm (promises) 5
73.727616
-----------
nodejs rm (callback) 1
92.698258
nodejs rm (callback) 2
73.043993
nodejs rm (callback) 3
70.869584
nodejs rm (callback) 4
69.196757
nodejs rm (callback) 5
75.715526
-----------
nodejs rm (sync) 1
41.71002
nodejs rm (sync) 2
41.742395
nodejs rm (sync) 3
38.894571
nodejs rm (sync) 4
41.326271
nodejs rm (sync) 5
48.152122
```
This commit is contained in:
Benjamin Woodruff
2025-10-20 17:52:34 -07:00
committed by GitHub
parent 3cd8a23446
commit b3959cdcbf
8 changed files with 126 additions and 77 deletions
+7
View File
@@ -0,0 +1,7 @@
# Recursive Delete Benchmark
```bash
pnpm bench
```
Run `pnpm bench --help` for options.
+27
View File
@@ -0,0 +1,27 @@
import { rm as rmPromises } from 'fs/promises'
import { rm as rmCallback, rmSync } from 'fs'
import { promisify } from 'util'
const rmCallbackPromise = promisify(rmCallback)
const targetDir = process.argv[2]
const method = process.argv[3] // 'promises', 'callback', or 'sync'
async function test() {
const time = process.hrtime()
if (method === 'promises') {
await rmPromises(targetDir, { recursive: true, force: true })
} else if (method === 'callback') {
await rmCallbackPromise(targetDir, { recursive: true, force: true })
} else if (method === 'sync') {
rmSync(targetDir, { recursive: true, force: true })
}
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
const milliseconds = nanoseconds / 1e6
console.log(milliseconds)
}
test()
View File
+12
View File
@@ -0,0 +1,12 @@
{
"name": "bench-recursive-delete",
"type": "module",
"scripts": {
"bench": "bash run.sh"
},
"devDependencies": {
"fuzzponent": "workspace:*",
"next": "workspace:*",
"rimraf": "6.0.1"
}
}
+4 -4
View File
@@ -1,10 +1,10 @@
import { join } from 'path'
import { recursiveDelete } from 'next/dist/lib/recursive-delete'
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`)
import { recursiveDeleteSyncWithAsyncRetries } from 'next/dist/lib/recursive-delete.js'
const targetDir = process.argv[2]
async function test() {
const time = process.hrtime()
await recursiveDelete(resolveDataDir)
await recursiveDeleteSyncWithAsyncRetries(targetDir)
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
+9 -6
View File
@@ -1,13 +1,16 @@
import { join } from 'path'
import { promisify } from 'util'
import rimrafMod from 'rimraf'
import { manual, manualSync } from 'rimraf'
const rimraf = promisify(rimrafMod)
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`, '**/*')
const targetDir = process.argv[2]
const method = process.argv[3]
async function test() {
const time = process.hrtime()
await rimraf(resolveDataDir)
if (method === 'sync') {
manualSync(targetDir)
} else {
await manual(targetDir)
}
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
+54 -60
View File
@@ -1,69 +1,63 @@
# Uses https://github.com/divmain/fuzzponent
mkdir fixtures-1
cd fixtures-1
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 1"
node rimraf.js 1
#!/usr/bin/env bash
set -euo pipefail
mkdir fixtures-2
cd fixtures-2
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 2"
node rimraf.js 2
ITERATIONS=5
mkdir fixtures-3
cd fixtures-3
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 3"
node rimraf.js 3
show_help() {
echo "Usage: $(basename "$0") [-i|--iterations N] [-h|--help]"
exit "${1:-0}"
}
mkdir fixtures-4
cd fixtures-4
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 4"
node rimraf.js 4
if ! OPTS=$(getopt -o i:h --long iterations:,help -n "$(basename "$0")" -- "$@"); then
show_help 1
fi
eval set -- "$OPTS"
mkdir fixtures-5
cd fixtures-5
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 5"
node rimraf.js 5
while true; do
case "$1" in
-i|--iterations)
ITERATIONS="$2"
shift 2
;;
-h|--help)
show_help
;;
*)
break
;;
esac
done
echo "-----------"
cleanup() {
for i in $(seq 1 "$ITERATIONS"); do
rm -rf "fixtures-$i"
done
}
cd fixtures-1
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 1"
node recursive-delete.js 1
trap cleanup EXIT
cleanup
cd fixtures-2
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 2"
node recursive-delete.js 2
run_benchmark() {
local name=$1
local script=$2
shift 2
cd fixtures-3
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 3"
node recursive-delete.js 3
echo "-----------"
for i in $(seq 1 "$ITERATIONS"); do
local fixture="fixtures-$i"
mkdir "$fixture"
cd "fixtures-$i"
fuzzponent -d 2 -s 20
cd ..
echo "$name $i"
node "$script" "$fixture" "$@"
if [[ -d "$fixture" ]]; then rmdir "$fixture"; fi
done
}
cd fixtures-4
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 4"
node recursive-delete.js 4
cd fixtures-5
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 5"
node recursive-delete.js 5
rm -r fixtures-1 fixtures-2 fixtures-3 fixtures-4 fixtures-5
run_benchmark "rimraf (async)" "rimraf.js" "async"
run_benchmark "rimraf (sync)" "rimraf.js" "sync"
run_benchmark "recursive delete" "recursive-delete.js"
run_benchmark "nodejs rm (promises)" "nodejs-rm.js" "promises"
run_benchmark "nodejs rm (callback)" "nodejs-rm.js" "callback"
run_benchmark "nodejs rm (sync)" "nodejs-rm.js" "sync"
+13 -7
View File
@@ -794,6 +794,18 @@ importers:
specifier: workspace:*
version: link:../../packages/next
bench/recursive-delete:
devDependencies:
fuzzponent:
specifier: workspace:*
version: link:../fuzzponent
next:
specifier: workspace:*
version: link:../../packages/next
rimraf:
specifier: 6.0.1
version: 6.0.1
bench/rendering:
dependencies:
fs-extra:
@@ -12222,10 +12234,6 @@ packages:
[email protected]:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
[email protected]:
resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
engines: {node: 20 || >=22}
[email protected]:
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
engines: {node: 20 || >=22}
@@ -30683,8 +30691,6 @@ snapshots:
[email protected]: {}
[email protected]: {}
[email protected]: {}
[email protected]:
@@ -32938,7 +32944,7 @@ snapshots:
[email protected]:
dependencies:
lru-cache: 11.1.0
lru-cache: 11.2.1
minipass: 7.1.2
[email protected]: {}