diff options
author | Brian White <mscdex@mscdex.net> | 2017-02-23 12:45:10 -0500 |
---|---|---|
committer | Brian White <mscdex@mscdex.net> | 2017-02-25 20:58:42 -0500 |
commit | 22abb39b2cfc8a462caddf0abe6a096b8562380f (patch) | |
tree | cf48a7036b5e988c8d4a93c909bab03e9c9f5388 | |
parent | efdc571a5804c8fd962e50edc0beb176f95cc092 (diff) | |
download | android-node-v8-22abb39b2cfc8a462caddf0abe6a096b8562380f.tar.gz android-node-v8-22abb39b2cfc8a462caddf0abe6a096b8562380f.tar.bz2 android-node-v8-22abb39b2cfc8a462caddf0abe6a096b8562380f.zip |
fs: improve performance for sync stat() functions
PR-URL: https://github.com/nodejs/node/pull/11522
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
-rw-r--r-- | benchmark/fs/bench-statSync.js | 32 | ||||
-rw-r--r-- | lib/fs.js | 26 | ||||
-rw-r--r-- | src/node_file.cc | 72 |
3 files changed, 102 insertions, 28 deletions
diff --git a/benchmark/fs/bench-statSync.js b/benchmark/fs/bench-statSync.js index ba1e8168b4..4bc2ecd65a 100644 --- a/benchmark/fs/bench-statSync.js +++ b/benchmark/fs/bench-statSync.js @@ -5,17 +5,35 @@ const fs = require('fs'); const bench = common.createBenchmark(main, { n: [1e4], - kind: ['lstatSync', 'statSync'] + kind: ['fstatSync', 'lstatSync', 'statSync'] }); function main(conf) { const n = conf.n >>> 0; - const fn = fs[conf.kind]; - - bench.start(); - for (var i = 0; i < n; i++) { - fn(__filename); + var fn; + var i; + switch (conf.kind) { + case 'statSync': + case 'lstatSync': + fn = fs[conf.kind]; + bench.start(); + for (i = 0; i < n; i++) { + fn(__filename); + } + bench.end(n); + break; + case 'fstatSync': + fn = fs.fstatSync; + const fd = fs.openSync(__filename, 'r'); + bench.start(); + for (i = 0; i < n; i++) { + fn(fd); + } + bench.end(n); + fs.closeSync(fd); + break; + default: + throw new Error('Invalid kind argument'); } - bench.end(n); } @@ -131,7 +131,7 @@ function isFd(path) { } // Static method to set the stats properties on a Stats object. -fs.Stats = function( +function Stats( dev, mode, nlink, @@ -160,7 +160,8 @@ fs.Stats = function( this.mtime = new Date(mtim_msec); this.ctime = new Date(ctim_msec); this.birthtime = new Date(birthtim_msec); -}; +} +fs.Stats = Stats; // Create a C++ binding to the function which creates a Stats object. binding.FSInitialize(fs.Stats); @@ -262,7 +263,7 @@ fs.existsSync = function(path) { try { handleError((path = getPathFromURL(path))); nullCheck(path); - binding.stat(pathModule._makeLong(path)); + binding.stat(pathModule._makeLong(path), statValues); return true; } catch (e) { return false; @@ -856,20 +857,33 @@ fs.stat = function(path, callback) { binding.stat(pathModule._makeLong(path), req); }; +const statValues = new Float64Array(14); +function statsFromValues() { + return new Stats(statValues[0], statValues[1], statValues[2], statValues[3], + statValues[4], statValues[5], + statValues[6] < 0 ? undefined : statValues[6], statValues[7], + statValues[8], statValues[9] < 0 ? undefined : statValues[9], + statValues[10], statValues[11], statValues[12], + statValues[13]); +} + fs.fstatSync = function(fd) { - return binding.fstat(fd); + binding.fstat(fd, statValues); + return statsFromValues(); }; fs.lstatSync = function(path) { handleError((path = getPathFromURL(path))); nullCheck(path); - return binding.lstat(pathModule._makeLong(path)); + binding.lstat(pathModule._makeLong(path), statValues); + return statsFromValues(); }; fs.statSync = function(path) { handleError((path = getPathFromURL(path))); nullCheck(path); - return binding.stat(pathModule._makeLong(path)); + binding.stat(pathModule._makeLong(path), statValues); + return statsFromValues(); }; fs.readlink = function(path, options, callback) { diff --git a/src/node_file.cc b/src/node_file.cc index 0abb880887..99048b2234 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -27,8 +27,10 @@ namespace node { using v8::Array; +using v8::ArrayBuffer; using v8::Context; using v8::EscapableHandleScope; +using v8::Float64Array; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -528,6 +530,37 @@ Local<Value> BuildStatsObject(Environment* env, const uv_stat_t* s) { return handle_scope.Escape(stats); } +void FillStatsArray(double* fields, const uv_stat_t* s) { + fields[0] = s->st_dev; + fields[1] = s->st_mode; + fields[2] = s->st_nlink; + fields[3] = s->st_uid; + fields[4] = s->st_gid; + fields[5] = s->st_rdev; +#if defined(__POSIX__) + fields[6] = s->st_blksize; +#else + fields[6] = -1; +#endif + fields[7] = s->st_ino; + fields[8] = s->st_size; +#if defined(__POSIX__) + fields[9] = s->st_blocks; +#else + fields[9] = -1; +#endif + // Dates. +#define X(idx, name) \ + fields[idx] = (static_cast<double>(s->st_##name.tv_sec) * 1000) + \ + (static_cast<double>(s->st_##name.tv_nsec / 1000000)); \ + + X(10, atim) + X(11, mtim) + X(12, ctim) + X(13, birthtim) +#undef X +} + // Used to speed up module loading. Returns the contents of the file as // a string or undefined when the file cannot be opened. The speedup // comes from not creating Error objects on failure. @@ -612,12 +645,15 @@ static void Stat(const FunctionCallbackInfo<Value>& args) { BufferValue path(env->isolate(), args[0]); ASSERT_PATH(path) - if (args[1]->IsObject()) { - ASYNC_CALL(stat, args[1], UTF8, *path) - } else { + if (args[1]->IsFloat64Array()) { + Local<Float64Array> array = args[1].As<Float64Array>(); + CHECK_EQ(array->Length(), 14); + Local<ArrayBuffer> ab = array->Buffer(); + double* fields = static_cast<double*>(ab->GetContents().Data()); SYNC_CALL(stat, *path, *path) - args.GetReturnValue().Set( - BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr))); + FillStatsArray(fields, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)); + } else if (args[1]->IsObject()) { + ASYNC_CALL(stat, args[1], UTF8, *path) } } @@ -630,12 +666,15 @@ static void LStat(const FunctionCallbackInfo<Value>& args) { BufferValue path(env->isolate(), args[0]); ASSERT_PATH(path) - if (args[1]->IsObject()) { - ASYNC_CALL(lstat, args[1], UTF8, *path) - } else { + if (args[1]->IsFloat64Array()) { + Local<Float64Array> array = args[1].As<Float64Array>(); + CHECK_EQ(array->Length(), 14); + Local<ArrayBuffer> ab = array->Buffer(); + double* fields = static_cast<double*>(ab->GetContents().Data()); SYNC_CALL(lstat, *path, *path) - args.GetReturnValue().Set( - BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr))); + FillStatsArray(fields, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)); + } else if (args[1]->IsObject()) { + ASYNC_CALL(lstat, args[1], UTF8, *path) } } @@ -649,12 +688,15 @@ static void FStat(const FunctionCallbackInfo<Value>& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsObject()) { - ASYNC_CALL(fstat, args[1], UTF8, fd) - } else { + if (args[1]->IsFloat64Array()) { + Local<Float64Array> array = args[1].As<Float64Array>(); + CHECK_EQ(array->Length(), 14); + Local<ArrayBuffer> ab = array->Buffer(); + double* fields = static_cast<double*>(ab->GetContents().Data()); SYNC_CALL(fstat, 0, fd) - args.GetReturnValue().Set( - BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr))); + FillStatsArray(fields, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)); + } else if (args[1]->IsObject()) { + ASYNC_CALL(fstat, args[1], UTF8, fd) } } |