Skip to content

Commit 6215add

Browse files
authored
sync-fs and async-fs improvements (#217)
- Try to bump min measured iteration duration to ~10ms - Use generator for randomFileContents - Only measure setupDirectory in the faster sync-fs - Increase NOF files and folders - Add FSVisitor to get some more generator action going
1 parent 5e8fe96 commit 6215add

File tree

3 files changed

+264
-70
lines changed

3 files changed

+264
-70
lines changed

JetStreamDriver.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,8 +842,9 @@ class Benchmark {
842842

843843
get prerunCode() { return null; }
844844

845+
845846
get preIterationCode() {
846-
let code = `benchmark.prepareForNextIteration?.();`;
847+
let code = this.prepareForNextIterationCode ;
847848
if (this.plan.deterministicRandom)
848849
code += `Math.random.__resetSeed();`;
849850

@@ -853,6 +854,10 @@ class Benchmark {
853854
return code;
854855
}
855856

857+
get prepareForNextIterationCode() {
858+
return "benchmark.prepareForNextIteration?.();"
859+
}
860+
856861
get postIterationCode() {
857862
let code = "";
858863

@@ -1519,6 +1524,10 @@ class AsyncBenchmark extends DefaultBenchmark {
15191524
return str;
15201525
}
15211526

1527+
get prepareForNextIterationCode() {
1528+
return "await benchmark.prepareForNextIteration?.();"
1529+
}
1530+
15221531
get runnerCode() {
15231532
return `
15241533
async function doRun() {

generators/async-file-system.js

Lines changed: 127 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@ function computeIsLittleEndian() {
3434
}
3535

3636
const isLittleEndian = computeIsLittleEndian();
37-
let globalCounter = 0;
38-
39-
function randomFileContents() {
40-
const numBytes = (globalCounter % 128) + 2056;
41-
globalCounter++;
42-
let result = new ArrayBuffer(numBytes);
43-
let view = new Uint8Array(result);
44-
for (let i = 0; i < numBytes; ++i)
45-
view[i] = (i + globalCounter) % 255;
46-
return new DataView(result);
37+
38+
async function *randomFileContents() {
39+
let counter = 1;
40+
while(true) {
41+
const numBytes = ((counter * 1192.18851371) % 2056);
42+
counter++;
43+
let result = new ArrayBuffer(numBytes);
44+
let view = new Uint8Array(result);
45+
for (let i = 0; i < numBytes; ++i)
46+
view[i] = (i + counter) % 255;
47+
yield new DataView(result);
48+
}
4749
}
4850

51+
4952
class File {
5053
constructor(dataView, permissions) {
5154
this._data = dataView;
@@ -55,6 +58,8 @@ class File {
5558

5659
set data(dataView) { this._data = dataView; }
5760

61+
get byteLength() { return this._data.byteLength; }
62+
5863
swapByteOrder() {
5964
let hash = 0x1a2b3c4d;
6065
for (let i = 0; i < Math.floor(this.data.byteLength / 8) * 8; i += 8) {
@@ -144,62 +149,152 @@ class Directory {
144149
return count;
145150
}
146151

152+
async totalFileSize() {
153+
let size = 0;
154+
for await (const {entry: file} of this.forEachFileRecursively()) {
155+
size += file.byteLength;
156+
}
157+
return size;
158+
}
159+
147160
async rm(name) {
148161
return this.structure.delete(name);
149162
}
163+
164+
async visit(visitor) {
165+
visitor.visitDir(undefined, this);
166+
for await (const {name, entry, isDirectory} of this.ls()) {
167+
if (isDirectory)
168+
await entry.visit(visitor);
169+
else
170+
visitor.visitFile(name, entry);
171+
}
172+
}
173+
150174
}
151175

176+
const MAX_DIR_COUNT = 2500;
177+
const MAX_FILE_COUNT = 800;
178+
152179
async function setupDirectory() {
153180
const fs = new Directory;
154181
let dirs = [fs];
155182
let counter = 0;
156183
for (let dir of dirs) {
157-
for (let i = 0; i < 10; ++i) {
158-
if (dirs.length < 400 && (counter % 3) <= 1) {
184+
for (let i = 0; i < 15; ++i) {
185+
if (dirs.length <= MAX_DIR_COUNT) {
159186
dirs.push(await dir.addDirectory(`dir-${i}`));
160187
}
161188
counter++;
162189
}
163190
}
164191

165-
for (let dir of dirs) {
166-
for (let i = 0; i < 5; ++i) {
167-
if ((counter % 3) === 0) {
168-
await dir.addFile(`file-${i}`, new File(randomFileContents()));
169-
}
170-
counter++;
171-
}
192+
let fileCounter = 0;
193+
for await (const fileContents of randomFileContents()) {
194+
const dirIndex = fileCounter * 107;
195+
const dir = dirs[dirIndex % dirs.length];
196+
await dir.addFile(`file-${fileCounter}`, new File(fileContents));
197+
fileCounter++
198+
if (fileCounter >= MAX_FILE_COUNT)
199+
break;
172200
}
173201

174202
return fs;
175203
}
176204

205+
class FSVisitor {
206+
visitFile(name, file) {
207+
}
208+
209+
visitDir(name, dir) {
210+
}
211+
}
212+
213+
class CountVisitor extends FSVisitor {
214+
fileCount = 0;
215+
dirCount = 0;
216+
217+
visitFile() {
218+
this.fileCount++;
219+
}
220+
221+
visitDir() {
222+
this.dirCount++;
223+
}
224+
}
225+
226+
class CountDracula extends FSVisitor {
227+
bytes = 0;
228+
visitFile(name, file) {
229+
this.bytes += file.byteLength;
230+
}
231+
}
232+
233+
177234
class Benchmark {
178-
EXPECTED_FILE_COUNT = 666;
235+
EXPECTED_FILE_COUNT = 739;
179236

180237
totalFileCount = 0;
238+
totalDirCount = 0;
181239
lastFileHash = undefined;
240+
fs;
182241

183-
async runIteration() {
184-
const fs = await setupDirectory();
242+
async prepareForNextIteration() {
243+
this.fs = await setupDirectory();
244+
}
185245

186-
for await (let { entry: file } of fs.forEachFileRecursively()) {
246+
async runIteration() {
247+
for await (let { entry: file } of this.fs.forEachFileRecursively()) {
187248
this.lastFileHash = file.swapByteOrder();
188249
}
189250

190-
for await (let { name, entry: dir } of fs.forEachDirectoryRecursively()) {
191-
if ((await dir.fileCount()) > 3) {
192-
for await (let { name } of dir.forEachFile()) {
193-
let result = await dir.rm(name);
194-
if (!result)
195-
throw new Error("rm should have returned true");
196-
}
251+
let bytesDeleted = 0;
252+
let counter = 0;
253+
for await (const { name, entry: dir } of this.fs.forEachDirectoryRecursively()) {
254+
const oldTotalSize = await dir.totalFileSize();
255+
if (await dir.fileCount() === 0)
256+
continue;
257+
counter++;
258+
if (counter % 13 !== 0)
259+
continue;
260+
for await (const { name } of dir.forEachFile()) {
261+
const result = await dir.rm(name);
262+
if (!result)
263+
throw new Error("rm should have returned true");
197264
}
265+
const totalReducedSize = oldTotalSize - dir.totalFileSize();
266+
bytesDeleted += totalReducedSize;
267+
}
268+
if (bytesDeleted === 0)
269+
throw new Error("Did not delete any files");
270+
271+
const countVisitor = new CountVisitor();
272+
await this.fs.visit(countVisitor);
273+
274+
const countDracula = new CountDracula();
275+
await this.fs.visit(countDracula);
276+
277+
let fileCount = 0;
278+
let fileBytes = 0;
279+
for await (const {entry: file} of this.fs.forEachFileRecursively()) {
280+
fileCount++
281+
fileBytes += file.byteLength;
198282
}
283+
this.totalFileCount += fileCount;
199284

200-
for await (let _ of fs.forEachFileRecursively()) {
201-
this.totalFileCount++;
285+
let dirCount = 1;
286+
for await (let _ of this.fs.forEachDirectoryRecursively()) {
287+
dirCount++;
202288
}
289+
this.totalDirCount += dirCount;
290+
291+
if (countVisitor.fileCount !== fileCount)
292+
throw new Error(`Invalid total file count ${countVisitor.fileCount}, expected ${fileCount}.`);
293+
if (countDracula.bytes !== fileBytes)
294+
throw new Error(`Invalid total file bytes ${countDracula.bytes}, expected ${fileBytes}.`);
295+
if (countVisitor.dirCount !== dirCount)
296+
throw new Error(`Invalid total dir count ${countVisitor.dirCount}, expected ${dirCount}.`);
297+
203298
}
204299

205300
validate(iterations) {

0 commit comments

Comments
 (0)