summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian White <mscdex@mscdex.net>2017-02-23 12:45:10 -0500
committerBrian White <mscdex@mscdex.net>2017-02-25 20:58:42 -0500
commit22abb39b2cfc8a462caddf0abe6a096b8562380f (patch)
treecf48a7036b5e988c8d4a93c909bab03e9c9f5388
parentefdc571a5804c8fd962e50edc0beb176f95cc092 (diff)
downloadandroid-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.js32
-rw-r--r--lib/fs.js26
-rw-r--r--src/node_file.cc72
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);
}
diff --git a/lib/fs.js b/lib/fs.js
index d45bd82df7..3f2a3cc1ac 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -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)
}
}