From ca57f88d68b3411dd9dddb1ae5484ba8585b8696 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Thu, 23 Oct 2025 13:55:21 +0200 Subject: [PATCH 1/3] fix --- JetStreamDriver.js | 11 +++- generators/async-file-system.js | 106 ++++++++++++++++++++++++++++---- generators/sync-file-system.js | 104 +++++++++++++++++++++++++++---- 3 files changed, 197 insertions(+), 24 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index 94ff6e80..3eea9bfd 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -842,8 +842,9 @@ class Benchmark { get prerunCode() { return null; } + get preIterationCode() { - let code = `benchmark.prepareForNextIteration?.();`; + let code = this.prepareForNextIterationCode ; if (this.plan.deterministicRandom) code += `Math.random.__resetSeed();`; @@ -853,6 +854,10 @@ class Benchmark { return code; } + get prepareForNextIterationCode() { + return "benchmark.prepareForNextIteration?.();" + } + get postIterationCode() { let code = ""; @@ -1517,6 +1522,10 @@ class AsyncBenchmark extends DefaultBenchmark { return str; } + get prepareForNextIterationCode() { + return "await benchmark.prepareForNextIteration?.();" + } + get runnerCode() { return ` async function doRun() { diff --git a/generators/async-file-system.js b/generators/async-file-system.js index 9f85daf0..0b01dcb0 100644 --- a/generators/async-file-system.js +++ b/generators/async-file-system.js @@ -37,7 +37,7 @@ const isLittleEndian = computeIsLittleEndian(); let globalCounter = 0; function randomFileContents() { - const numBytes = (globalCounter % 128) + 2056; + const numBytes = ((globalCounter * 1234.213784) % 2056); globalCounter++; let result = new ArrayBuffer(numBytes); let view = new Uint8Array(result); @@ -55,6 +55,8 @@ class File { set data(dataView) { this._data = dataView; } + get byteLength() { return this._data.byteLength; } + swapByteOrder() { let hash = 0x1a2b3c4d; for (let i = 0; i < Math.floor(this.data.byteLength / 8) * 8; i += 8) { @@ -144,9 +146,28 @@ class Directory { return count; } + async totalFileSize() { + let size = 0; + for await (const {entry: file} of this.forEachFileRecursively()) { + size += file.byteLength; + } + return size; + } + async rm(name) { return this.structure.delete(name); } + + async visit(visitor) { + visitor.visitDir(undefined, this); + for await (const {name, entry, isDirectory} of this.ls()) { + if (isDirectory) + await entry.visit(visitor); + else + visitor.visitFile(name, entry); + } + } + } async function setupDirectory() { @@ -154,8 +175,8 @@ async function setupDirectory() { let dirs = [fs]; let counter = 0; for (let dir of dirs) { - for (let i = 0; i < 10; ++i) { - if (dirs.length < 400 && (counter % 3) <= 1) { + for (let i = 0; i < 15; ++i) { + if (dirs.length <= 3000) { dirs.push(await dir.addDirectory(`dir-${i}`)); } counter++; @@ -163,8 +184,8 @@ async function setupDirectory() { } for (let dir of dirs) { - for (let i = 0; i < 5; ++i) { - if ((counter % 3) === 0) { + for (let i = 0; i < 3; ++i) { + if ((counter % 13) === 0) { await dir.addFile(`file-${i}`, new File(randomFileContents())); } counter++; @@ -174,32 +195,93 @@ async function setupDirectory() { return fs; } +class FSVisitor { + visitFile(name, file) { + } + + visitDir(name, dir) { + } +} + +class CountVisitor extends FSVisitor { + fileCount = 0; + dirCount = 0; + + visitFile() { + this.fileCount++; + } + + visitDir() { + this.dirCount++; + } +} + +class CountDracula extends FSVisitor { + bytes = 0; + visitFile(name, file) { + this.bytes += file.byteLength; + } +} + + class Benchmark { - EXPECTED_FILE_COUNT = 666; + EXPECTED_FILE_COUNT = 693; totalFileCount = 0; + totalDirCount = 0; lastFileHash = undefined; + fs; - async runIteration() { - const fs = await setupDirectory(); + async prepareForNextIteration() { + this.fs = await setupDirectory(); + } - for await (let { entry: file } of fs.forEachFileRecursively()) { + async runIteration() { + for await (let { entry: file } of this.fs.forEachFileRecursively()) { this.lastFileHash = file.swapByteOrder(); } - for await (let { name, entry: dir } of fs.forEachDirectoryRecursively()) { + let bytesDeleted = 0; + for await (let { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { + const oldTotalSize = dir.totalFileSize(); if ((await dir.fileCount()) > 3) { for await (let { name } of dir.forEachFile()) { let result = await dir.rm(name); if (!result) throw new Error("rm should have returned true"); } + const totalReducedSize = oldTotalSize - dir.totalFileSize(); + bytesDeleted += totalReducedSize; } } - for await (let _ of fs.forEachFileRecursively()) { - this.totalFileCount++; + const countVisitor = new CountVisitor(); + await this.fs.visit(countVisitor); + + const countDracula = new CountDracula(); + await this.fs.visit(countDracula); + + let fileCount = 0; + let fileBytes = 0; + for await (const {entry: file} of this.fs.forEachFileRecursively()) { + fileCount++ + fileBytes += file.byteLength; + } + this.totalFileCount += fileCount; + + let dirCount = 1; + for await (let _ of this.fs.forEachDirectoryRecursively()) { + dirCount++; } + this.totalDirCount += dirCount; + + if (countVisitor.fileCount !== fileCount) + throw new Error(`Invalid total file count ${countVisitor.fileCount}, expected ${fileCount}.`); + if (countDracula.bytes !== fileBytes) + throw new Error(`Invalid total file bytes ${countDracula.bytes}, expected ${fileBytes}.`); + if (countVisitor.dirCount !== dirCount) + throw new Error(`Invalid total dir count ${countVisitor.dirCount}, expected ${dirCount}.`); + } validate(iterations) { diff --git a/generators/sync-file-system.js b/generators/sync-file-system.js index 6b3a8b42..e54d3100 100644 --- a/generators/sync-file-system.js +++ b/generators/sync-file-system.js @@ -37,7 +37,7 @@ const isLittleEndian = computeIsLittleEndian(); let globalCounter = 0; function randomFileContents() { - const numBytes = (globalCounter % 128) + 2056; + const numBytes = ((globalCounter * 1234.213784) % 2056); globalCounter++; let result = new ArrayBuffer(numBytes); let view = new Uint8Array(result); @@ -56,6 +56,8 @@ class File { set data(dataView) { this._data = dataView; } + get byteLength() { return this._data.byteLength; } + swapByteOrder() { let hash = 0x1a2b3c4d; for (let i = 0; i < Math.floor(this.data.byteLength / 8) * 8; i += 8) { @@ -141,9 +143,28 @@ class Directory { return count; } + totalFileSize() { + let size = 0; + for (const file of this.forEachFileRecursively()) { + size += file.byteLength; + } + return size; + } + rm(name) { return this.structure.delete(name); } + + visit(visitor) { + visitor.visitDir(undefined, this); + for (const {name, entry, isDirectory} of this.ls()) { + if (isDirectory) + entry.visit(visitor); + else + visitor.visitFile(name, entry); + } + } + } function setupDirectory() { @@ -151,8 +172,8 @@ function setupDirectory() { let dirs = [fs]; let counter = 0; for (let dir of dirs) { - for (let i = 0; i < 10; ++i) { - if (dirs.length < 400 && (counter % 3) <= 1) { + for (let i = 0; i < 15; ++i) { + if (dirs.length <= 5000) { dirs.push(dir.addDirectory(`dir-${i}`)); } counter++; @@ -160,8 +181,8 @@ function setupDirectory() { } for (let dir of dirs) { - for (let i = 0; i < 5; ++i) { - if ((counter % 3) === 0) { + for (let i = 0; i < 3; ++i) { + if ((counter % 13) === 0) { dir.addFile(`file-${i}`, new File(randomFileContents())); } counter++; @@ -171,20 +192,55 @@ function setupDirectory() { return fs; } +class FSVisitor { + visitFile(name, file) { + } + + visitDir(name, dir) { + } +} + +class CountVisitor extends FSVisitor { + fileCount = 0; + dirCount = 0; + + visitFile() { + this.fileCount++; + } + + visitDir() { + this.dirCount++; + } +} + +class CountDracula extends FSVisitor { + bytes = 0; + visitFile(name, file) { + this.bytes += file.byteLength; + } +} + class Benchmark { - EXPECTED_FILE_COUNT = 666; + EXPECTED_FILE_COUNT = 1154; totalFileCount = 0; + totalDirCount = 0; lastFileHash = undefined; + fs; + + prepareForNextIteration() { + } runIteration() { - const fs = setupDirectory(); + this.fs = setupDirectory(); - for (let { entry: file } of fs.forEachFileRecursively()) { + for (let { entry: file } of this.fs.forEachFileRecursively()) { this.lastFileHash = file.swapByteOrder(); } - for (let { name, entry: dir } of fs.forEachDirectoryRecursively()) { + let bytesDeleted = 0; + for (let { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { + const oldTotalSize = dir.totalFileSize(); if (dir.fileCount() > 3) { for (let { name } of dir.forEachFile()) { let result = dir.rm(name); @@ -193,11 +249,37 @@ class Benchmark { } } + const totalReducedSize = oldTotalSize - dir.totalFileSize(); + bytesDeleted += totalReducedSize; } - for (let _ of fs.forEachFileRecursively()) { - this.totalFileCount++; + const countVisitor = new CountVisitor(); + this.fs.visit(countVisitor); + + const countDracula = new CountDracula(); + this.fs.visit(countDracula); + + let fileCount = 0; + let fileBytes = 0; + for (const {entry: file} of this.fs.forEachFileRecursively()) { + fileCount++ + fileBytes += file.byteLength; } + this.totalFileCount += fileCount; + + let dirCount = 1; + for (let _ of this.fs.forEachDirectoryRecursively()) { + dirCount++; + } + this.totalDirCount += dirCount; + + if (countVisitor.fileCount !== fileCount) + throw new Error(`Invalid total file count ${countVisitor.fileCount}, expected ${fileCount}.`); + if (countDracula.bytes !== fileBytes) + throw new Error(`Invalid total file bytes ${countDracula.bytes}, expected ${fileBytes}.`); + if (countVisitor.dirCount !== dirCount) + throw new Error(`Invalid total dir count ${countVisitor.dirCount}, expected ${dirCount}.`); + } validate(iterations) { From 7e276f5118f5104219827b083cba5ce71a652c2c Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Thu, 23 Oct 2025 14:01:28 +0200 Subject: [PATCH 2/3] fixes --- generators/async-file-system.js | 25 +++++++++++++++---------- generators/sync-file-system.js | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/generators/async-file-system.js b/generators/async-file-system.js index 0b01dcb0..3bed23e8 100644 --- a/generators/async-file-system.js +++ b/generators/async-file-system.js @@ -36,15 +36,19 @@ function computeIsLittleEndian() { const isLittleEndian = computeIsLittleEndian(); let globalCounter = 0; -function randomFileContents() { - const numBytes = ((globalCounter * 1234.213784) % 2056); - globalCounter++; - let result = new ArrayBuffer(numBytes); - let view = new Uint8Array(result); - for (let i = 0; i < numBytes; ++i) - view[i] = (i + globalCounter) % 255; - return new DataView(result); -} +const randomFileContentsGen = (function *randomFileContents() { + let counter = 1; + while(true) { + const numBytes = ((counter * 1192.18851371) % 2056); + counter++; + let result = new ArrayBuffer(numBytes); + let view = new Uint8Array(result); + for (let i = 0; i < numBytes; ++i) + view[i] = (i + counter) % 255; + yield new DataView(result); + } +})(); + class File { constructor(dataView, permissions) { @@ -186,7 +190,8 @@ async function setupDirectory() { for (let dir of dirs) { for (let i = 0; i < 3; ++i) { if ((counter % 13) === 0) { - await dir.addFile(`file-${i}`, new File(randomFileContents())); + const fileContents = randomFileContentsGen.next().value; + await dir.addFile(`file-${i}`, new File(fileContents)); } counter++; } diff --git a/generators/sync-file-system.js b/generators/sync-file-system.js index e54d3100..32cc1737 100644 --- a/generators/sync-file-system.js +++ b/generators/sync-file-system.js @@ -34,17 +34,19 @@ function computeIsLittleEndian() { } const isLittleEndian = computeIsLittleEndian(); -let globalCounter = 0; - -function randomFileContents() { - const numBytes = ((globalCounter * 1234.213784) % 2056); - globalCounter++; - let result = new ArrayBuffer(numBytes); - let view = new Uint8Array(result); - for (let i = 0; i < numBytes; ++i) - view[i] = (i + globalCounter) % 255; - return new DataView(result); -} + +const randomFileContentsGen = (function *randomFileContents() { + let counter = 1; + while(true) { + const numBytes = ((counter * 1192.18851371) % 2056); + counter++; + let result = new ArrayBuffer(numBytes); + let view = new Uint8Array(result); + for (let i = 0; i < numBytes; ++i) + view[i] = (i + counter) % 255; + yield new DataView(result); + } +})(); class File { @@ -183,7 +185,8 @@ function setupDirectory() { for (let dir of dirs) { for (let i = 0; i < 3; ++i) { if ((counter % 13) === 0) { - dir.addFile(`file-${i}`, new File(randomFileContents())); + const fileContents = randomFileContentsGen.next().value; + dir.addFile(`file-${i}`, new File(fileContents)); } counter++; } From 277ac4c21d1502e9e0bd15e8acc309907404fed3 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Thu, 23 Oct 2025 15:53:53 +0200 Subject: [PATCH 3/3] async file content creation --- generators/async-file-system.js | 54 ++++++++++++++++++-------------- generators/sync-file-system.js | 55 ++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/generators/async-file-system.js b/generators/async-file-system.js index 3bed23e8..03e146eb 100644 --- a/generators/async-file-system.js +++ b/generators/async-file-system.js @@ -34,9 +34,8 @@ function computeIsLittleEndian() { } const isLittleEndian = computeIsLittleEndian(); -let globalCounter = 0; -const randomFileContentsGen = (function *randomFileContents() { +async function *randomFileContents() { let counter = 1; while(true) { const numBytes = ((counter * 1192.18851371) % 2056); @@ -47,7 +46,7 @@ const randomFileContentsGen = (function *randomFileContents() { view[i] = (i + counter) % 255; yield new DataView(result); } -})(); +} class File { @@ -174,27 +173,30 @@ class Directory { } +const MAX_DIR_COUNT = 2500; +const MAX_FILE_COUNT = 800; + async function setupDirectory() { const fs = new Directory; let dirs = [fs]; let counter = 0; for (let dir of dirs) { for (let i = 0; i < 15; ++i) { - if (dirs.length <= 3000) { + if (dirs.length <= MAX_DIR_COUNT) { dirs.push(await dir.addDirectory(`dir-${i}`)); } counter++; } } - for (let dir of dirs) { - for (let i = 0; i < 3; ++i) { - if ((counter % 13) === 0) { - const fileContents = randomFileContentsGen.next().value; - await dir.addFile(`file-${i}`, new File(fileContents)); - } - counter++; - } + let fileCounter = 0; + for await (const fileContents of randomFileContents()) { + const dirIndex = fileCounter * 107; + const dir = dirs[dirIndex % dirs.length]; + await dir.addFile(`file-${fileCounter}`, new File(fileContents)); + fileCounter++ + if (fileCounter >= MAX_FILE_COUNT) + break; } return fs; @@ -230,7 +232,7 @@ class CountDracula extends FSVisitor { class Benchmark { - EXPECTED_FILE_COUNT = 693; + EXPECTED_FILE_COUNT = 739; totalFileCount = 0; totalDirCount = 0; @@ -247,18 +249,24 @@ class Benchmark { } let bytesDeleted = 0; - for await (let { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { - const oldTotalSize = dir.totalFileSize(); - if ((await dir.fileCount()) > 3) { - for await (let { name } of dir.forEachFile()) { - let result = await dir.rm(name); - if (!result) - throw new Error("rm should have returned true"); - } - const totalReducedSize = oldTotalSize - dir.totalFileSize(); - bytesDeleted += totalReducedSize; + let counter = 0; + for await (const { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { + const oldTotalSize = await dir.totalFileSize(); + if (await dir.fileCount() === 0) + continue; + counter++; + if (counter % 13 !== 0) + continue; + for await (const { name } of dir.forEachFile()) { + const result = await dir.rm(name); + if (!result) + throw new Error("rm should have returned true"); } + const totalReducedSize = oldTotalSize - dir.totalFileSize(); + bytesDeleted += totalReducedSize; } + if (bytesDeleted === 0) + throw new Error("Did not delete any files"); const countVisitor = new CountVisitor(); await this.fs.visit(countVisitor); diff --git a/generators/sync-file-system.js b/generators/sync-file-system.js index 32cc1737..af65d587 100644 --- a/generators/sync-file-system.js +++ b/generators/sync-file-system.js @@ -35,7 +35,7 @@ function computeIsLittleEndian() { const isLittleEndian = computeIsLittleEndian(); -const randomFileContentsGen = (function *randomFileContents() { +function *randomFileContents() { let counter = 1; while(true) { const numBytes = ((counter * 1192.18851371) % 2056); @@ -46,7 +46,7 @@ const randomFileContentsGen = (function *randomFileContents() { view[i] = (i + counter) % 255; yield new DataView(result); } -})(); +}; class File { @@ -147,7 +147,7 @@ class Directory { totalFileSize() { let size = 0; - for (const file of this.forEachFileRecursively()) { + for (const { entry:file } of this.forEachFileRecursively()) { size += file.byteLength; } return size; @@ -169,29 +169,29 @@ class Directory { } +const MAX_DIR_COUNT = 5000; +const MAX_FILE_COUNT = 1200; + function setupDirectory() { const fs = new Directory; let dirs = [fs]; - let counter = 0; for (let dir of dirs) { for (let i = 0; i < 15; ++i) { - if (dirs.length <= 5000) { - dirs.push(dir.addDirectory(`dir-${i}`)); + if (dirs.length < MAX_DIR_COUNT) { + dirs.push(dir.addDirectory(`dir-${dirs.length}`)); } - counter++; } } - for (let dir of dirs) { - for (let i = 0; i < 3; ++i) { - if ((counter % 13) === 0) { - const fileContents = randomFileContentsGen.next().value; - dir.addFile(`file-${i}`, new File(fileContents)); - } - counter++; - } + let fileCounter = 0; + for (const fileContents of randomFileContents()) { + const dirIndex = fileCounter * 107; + const dir = dirs[dirIndex % dirs.length]; + dir.addFile(`file-${fileCounter}`, new File(fileContents)); + fileCounter++ + if (fileCounter >= MAX_FILE_COUNT) + break; } - return fs; } @@ -224,7 +224,7 @@ class CountDracula extends FSVisitor { } class Benchmark { - EXPECTED_FILE_COUNT = 1154; + EXPECTED_FILE_COUNT = 1108; totalFileCount = 0; totalDirCount = 0; @@ -242,19 +242,24 @@ class Benchmark { } let bytesDeleted = 0; - for (let { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { + let counter = 0; + for (const { name, entry: dir } of this.fs.forEachDirectoryRecursively()) { const oldTotalSize = dir.totalFileSize(); - if (dir.fileCount() > 3) { - for (let { name } of dir.forEachFile()) { - let result = dir.rm(name); - if (!result) - throw new Error("rm should have returned true"); - - } + if (dir.fileCount() === 0) + continue; + counter++; + if (counter % 13 !== 0) + continue; + for (const { name } of dir.forEachFile()) { + const result = dir.rm(name); + if (!result) + throw new Error("rm should have returned true"); } const totalReducedSize = oldTotalSize - dir.totalFileSize(); bytesDeleted += totalReducedSize; } + if (bytesDeleted === 0) + throw new Error("Did not delete any files"); const countVisitor = new CountVisitor(); this.fs.visit(countVisitor);