summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2013-02-03 12:53:33 -0800
committerisaacs <i@izs.me>2013-02-15 18:48:43 -0800
commit8476aefc8e21fb8db597937c7e8fbc3490a72f39 (patch)
tree8ed881bd065658a72437d86436aece25f66653f7
parent9299168f2a2ea231f63731894bc93e3807d1065a (diff)
downloadnode-8476aefc8e21fb8db597937c7e8fbc3490a72f39.tar.gz
fs: Change default WriteStream config, increase perf
This increases fs.WriteStream throughput dramatically by removing the "higher default water marks" for fs.WriteStream. Also includes a benchmark. Current performance is significantly higher than v0.8 for strings at all tested levels except size=1. Buffer performance is still lackluster. Further improvement in the stream.Writable base class is required, but this is a start.
-rw-r--r--benchmark/fs-write-stream-throughput.js96
-rw-r--r--lib/fs.js6
2 files changed, 97 insertions, 5 deletions
diff --git a/benchmark/fs-write-stream-throughput.js b/benchmark/fs-write-stream-throughput.js
new file mode 100644
index 000000000..b131d5b73
--- /dev/null
+++ b/benchmark/fs-write-stream-throughput.js
@@ -0,0 +1,96 @@
+
+// If there are no args, then this is the root. Run all the benchmarks!
+if (!process.argv[2])
+ parent();
+else
+ runTest(+process.argv[2], +process.argv[3], process.argv[4]);
+
+function parent() {
+ var types = [ 'string', 'buffer' ];
+ var durs = [ 1, 5 ];
+ var sizes = [ 1, 10, 100, 2048, 10240 ];
+ var queue = [];
+ types.forEach(function(t) {
+ durs.forEach(function(d) {
+ sizes.forEach(function(s) {
+ queue.push([__filename, d, s, t]);
+ });
+ });
+ });
+
+ var spawn = require('child_process').spawn;
+ var node = process.execPath;
+
+ run();
+
+ function run() {
+ var args = queue.shift();
+ if (!args)
+ return;
+ var child = spawn(node, args, { stdio: 'inherit' });
+ child.on('close', function(code, signal) {
+ if (code)
+ throw new Error('Benchmark failed: ' + args.slice(1));
+ run();
+ });
+ }
+}
+
+function runTest(dur, size, type) {
+ if (type !== 'string')
+ type = 'buffer';
+ switch (type) {
+ case 'string':
+ var chunk = new Array(size + 1).join('a');
+ break;
+ case 'buffer':
+ var chunk = new Buffer(size);
+ chunk.fill('a');
+ break;
+ }
+
+ var writes = 0;
+ var fs = require('fs');
+ try { fs.unlinkSync('write_stream_throughput'); } catch (e) {}
+
+ var start
+ var end;
+ function done() {
+ var time = end[0] + end[1]/1E9;
+ var written = fs.statSync('write_stream_throughput').size / 1024;
+ var rate = (written / time).toFixed(2);
+ console.log('fs_write_stream_dur_%d_size_%d_type_%s: %d',
+ dur, size, type, rate);
+
+ try { fs.unlinkSync('write_stream_throughput'); } catch (e) {}
+ }
+
+ var f = require('fs').createWriteStream('write_stream_throughput');
+ f.on('drain', write);
+ f.on('open', write);
+ f.on('close', done);
+
+ // streams2 fs.WriteStreams will let you send a lot of writes into the
+ // buffer before returning false, so capture the *actual* end time when
+ // all the bytes have been written to the disk, indicated by 'finish'
+ f.on('finish', function() {
+ end = process.hrtime(start);
+ });
+
+ var ending = false;
+ function write() {
+ // don't try to write after we end, even if a 'drain' event comes.
+ // v0.8 streams are so sloppy!
+ if (ending)
+ return;
+
+ start = start || process.hrtime();
+ while (false !== f.write(chunk));
+ end = process.hrtime(start);
+
+ if (end[0] >= dur) {
+ ending = true;
+ f.end();
+ }
+ }
+}
diff --git a/lib/fs.js b/lib/fs.js
index 5cbc43b5e..7209d2a30 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -1559,11 +1559,7 @@ function WriteStream(path, options) {
if (!(this instanceof WriteStream))
return new WriteStream(path, options);
- // a little bit bigger buffer and water marks by default
- options = util._extend({
- lowWaterMark: 16 * 1024,
- highWaterMark: 64 * 1024
- }, options || {});
+ options = options || {};
Writable.call(this, options);