-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fs: improve error performance for readSync
#50033
Changes from 2 commits
4e9ea4b
da75cb5
ca4a904
37329e1
e75131a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict'; | ||
|
||
const common = require('../common'); | ||
const fs = require('fs'); | ||
const tmpdir = require('../../test/common/tmpdir'); | ||
tmpdir.refresh(); | ||
|
||
const tmpfile = tmpdir.resolve(`.existing-file-${process.pid}`); | ||
fs.writeFileSync(tmpfile, 'this-is-for-a-benchmark', 'utf8'); | ||
|
||
const bench = common.createBenchmark(main, { | ||
type: ['existing', 'non-existing'], | ||
paramType: ['offset-and-length', 'no-offset-and-length'], | ||
n: [1e4], | ||
}); | ||
|
||
function main({ n, type, paramType }) { | ||
let fd; | ||
|
||
switch (type) { | ||
case 'existing': | ||
fd = fs.openSync(tmpfile, 'r', 0o666); | ||
break; | ||
case 'non-existing': | ||
fd = 1 << 30; | ||
break; | ||
default: | ||
new Error('Invalid type'); | ||
} | ||
|
||
bench.start(); | ||
switch (paramType) { | ||
case 'offset-and-length': | ||
for (let i = 0; i < n; i++) { | ||
try { | ||
fs.readSync(fd, Buffer.alloc(1), 0, 1, 0); | ||
} catch { | ||
// Continue regardless of error. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this fail if type is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do you mean you only run this benchmark with For now it seems the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Benchmark is performed on |
||
} | ||
} | ||
break; | ||
case 'no-offset-and-length': | ||
for (let i = 0; i < n; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think here either n needs to be equal or less than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks to you, it helped me a lot in understanding the API. :) |
||
try { | ||
fs.readSync(fd, Buffer.alloc(1)); | ||
} catch { | ||
// Continue regardless of error. | ||
} | ||
} | ||
break; | ||
default: | ||
new Error('Invalid type'); | ||
} | ||
bench.end(n); | ||
|
||
if (type === 'existing') fs.closeSync(fd); | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -157,6 +157,7 @@ declare namespace InternalFSBinding { | |||
function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, req: FSReqCallback<number>): void; | ||||
function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, req: undefined, ctx: FSSyncContext): number; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, usePromises: typeof kUsePromises): Promise<number>; | ||||
function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number): number; | ||||
|
||||
function readBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: FSReqCallback<number>): void; | ||||
function readBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: undefined, ctx: FSSyncContext): number; | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the buffer should be reused, as what's normally done in the wild. Also "reading a file from offset 1 many many times, one character at a time" do not seem to be a very typical use case. It would be better to tweak the benchmark so that it reads a big file in a reused buffer (with a length of
fs.statSync(file).blksize
) and then read without offset until the file ends, which is the most common way to use this API. We probably do not need an additional case for the offset as reading a file repeatedly from the same offset is probably not common enough in the wild to optimize for.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your good comments.
I tried modifying it, but I'm not sure if it worked as you said.
Would it be better to remove
paramType
and test it by passing only buffer?