fs.realpath 70x slower than native
repost of nodejs/node-v0.x-archive#7902 to ensure it is not lost, as per @jasnell suggestion.
credit goes to @joliss I am merely transplanting the issue.
The fs.realpath function is 70x slower than native C realpath. On my system, fs.realpath takes 32 µs, while C realpath takes 0.45 µs.
This is a real problem in the Broccoli build tool, where we need to resolve symlinks in hot code paths. Resolving 1000 symlinked files - not an unusual case - would take 45 ms, slowing down the build considerably. [1]
As for a solution: I haven't looked at the fs.js source in detail, but it seems we might be able to call the realpath function in the C standard library, where available, instead of using our own implementation.
Benchmark code for Node:
var fs = require('fs') var start = Date.now() var n = 10000 for (var i = 0; i < n; i++) { if (fs.realpathSync('.') === 'dummy') throw new Error('never happens') } console.log(((Date.now() - start) * 1000 / n) + ' us') // => 32 us on Node 0.11.13
Benchmark code for C:
#include <limits.h> /* PATH_MAX */ #include <stdio.h> #include <stdlib.h> // Adapted from http://stackoverflow.com/a/1563237/525872 int main(void) { char buf[PATH_MAX + 1]; /* not sure about the "+ 1" */ int i; for (i = 0; i < 1000000; i++) { char *res = realpath(".", buf); if (res) { // printf("This source is at %s.\n", buf); } else { perror("realpath"); exit(EXIT_FAILURE); } } return 0; }
Run with gcc -std=gnu99 realpath-benchmark.c -o realpath-benchmark && time ./realpath-benchmark. This yields 0.45 µs per iteration on my Linux system.
[1] We cannot work around this by using naïve string concatenation, because path_resolution(7) requires that we resolve symlinks in all path components. Here is a gist to show why this matters.