fs: fix deoptimizing use of arguments#11678
Closed
vsemozhetbyt wants to merge 1 commit intonodejs:masterfrom
vsemozhetbyt:fix-fs-arguments-deopt
Closed
fs: fix deoptimizing use of arguments#11678vsemozhetbyt wants to merge 1 commit intonodejs:masterfrom vsemozhetbyt:fix-fs-arguments-deopt
arguments#11678vsemozhetbyt wants to merge 1 commit intonodejs:masterfrom
vsemozhetbyt:fix-fs-arguments-deopt
Conversation
Contributor
Author
|
FWIW, I've tried a benchmark without concurrent reads/writes, but it gives just more flaky results: Code (click me):'use strict';
const common = require('../common.js');
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'read-write-file-params.txt');
const data = Buffer.from('1');
const options = {};
const configs = {
n: [1e3],
methodName: ['readFile', 'writeFile'],
params: ['withOptions', 'withoutOptions'],
};
const bench = common.createBenchmark(main, configs);
function main(conf) {
const n = +conf.n;
const methodName = conf.methodName;
const params = conf.params;
let counter = n;
const callbacks = {
readFile: {
withOptions() {
if (counter--) fs.readFile(filePath, options, callback);
else bench.end(n);
},
withoutOptions() {
if (counter--) fs.readFile(filePath, callback);
else bench.end(n);
},
},
writeFile: {
withOptions() {
if (counter--) fs.writeFile(filePath, data, options, callback);
else bench.end(n);
},
withoutOptions() {
if (counter--) fs.writeFile(filePath, data, callback);
else bench.end(n);
},
},
};
const callback = callbacks[methodName][params];
bench.start();
callback();
}Examples of results (click me): |
Member
|
About the flakiness..you can try running it master against master to be more certain about it :) |
Contributor
Author
|
@joyeecheung Synk sycle (benchmark from the PR):Asynk sycle (benchmark from the comment above):While master against fix: async benchmark is flaky without any 'confidence', sync benchmark shows degradation of the |
Contributor
Author
|
To sum up the puzzles:
// cc @nodejs/v8 |
Contributor
Author
|
I will close it as the fixes do not give any performance gain anyway. Fixing the mentioned deopt in the |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
fs, benchmark
This is a twisted case that puzzles me for some time. I am not sure how it should proceed.
Prehistory / context
Thre are two deoptimization cases concerning
argumentsthat affectfsmodule. They have similar conditions and affect almost the samefsfunctions.I. 'Assignment to parameter in arguments object' in strict mode.
Previously this bailout was reported only for sloppy mode: see here and here. However, it seems there is some combination of circumstances for strict mode too.
There should be 3 conditions (which partly intersect with case II below):
argumentsmention (any:arguments,arguments[valid_index],arguments.length).How to check (run with
--trace_opt --trace_deoptand see the output):Versions impact:
v8 4.5.103.45 (Node.js 4.8.0) — affected (disabled optimization).
v8 5.1.281.93 (Node.js 6.10.0) — partly affected (deopt, then new optimization).
v8 5.5.372.41 (Node.js 7.7.1) — affected (disabled optimization).
v8 5.6.326.55 (Node.js 8.0.0-nightly / master) — partly affected, partly replaced by the case II (see below).
v8 5.8.202 (Node.js 8.0.0-pre vee-eight-lkgr) — partly affected, partly replaced by the case II (see below).
II. 'Bad value context for arguments value'.
This is a new deopt introduced by the v8 5.6 (see the upstream report; if I get this comment right, this will not be fixed till the new TurboFan pipeline hits the default use, i.e. till v8 5.9 (?)).
There should be 2 conditions (which partly intersect with case I):
arguments[valid_index](notargumentsorarguments.length).How to check (run with
--trace_opt --trace_deoptand see the output):Versions impact:
v8 5.6.326.55 (Node.js 8.0.0-nightly / master) — affected.
v8 5.8.202 (Node.js 8.0.0-pre vee-eight-lkgr) — affected.
Node.js libs impact
I've checked the libs for these two cases and have found out only 4 functions affected: 3 from
fs(this PR) and 1 from_http_agent(will address in another PR later on).fslib impactfs.readFile()has the conditions for the both cases I and II.fs.writeFile()has the conditions for the both cases I and II.writeAll()has the conditions for the case I only.I've tried to eliminate both the cases, so I had two variants of addressing: remove using of
argumentsor use intermediate variables for named parameters to transfer them into the lower scope. Both ways have the same benchmark results, so I've selected the first way (the second seems to be much more complicated and lumbering).For the
fs.readFile()andfs.writeFile()I've replacedargumentsby conditional using of named parameters.As to
writeAll(), I've noticed that the check in the first line is redundant:writeAll()is called only by thefs.writeFile()method (which has its own check that throws ifcallbackis not provided) and by thewriteAll()itself with already checkedcallback. So we can remove the check and the intermediate parameter.All tests are passed with the proposed changes (after this PR landed).
You can check deoptimization and fixes with these tests (run with
--trace_opt --trace_deoptand see the output):Performance puzzle
After running a newly created benchmark, I've found out that the optimized
fs.readFile()runs much slower than the unoptimized one on the master.fs.writeFile()has flaky results.Some examples:
Moreover, the
fs.readFile()tests show a very strange new deoptimization: it happens after all the cycle runs, so it hardly has any performance impact but can be an evidence of some murky processes. See more in this issue.I am not sure what to do with all this data. Maybe my benchmark is just wrong (I've gone over some alterations with no noticeable changes). So I just share it with the team by this PR to draw more thoughts. Sorry for any mess.