The current verison of NodeJS hardcodes the path where perf data is written when the --perf-basic-prof
flag is used.
https://github.com/v8/v8/blob/061c2ab23a1d4cd192b935e7912e7dfb1fed845d/src/log.cc#L236
At Pinterest, /tmp
has limited capacity and so we weren't able to utilize perf data to troubleshoot NodeJS without filling the disk and crashing the running system.
First I'll copy the system node binary to my local directory so this set of actions isn't destructive to the running system:
$ cp $(which node) .
To demonstrate the behavior before patching, I'll run node with the --perf-basic-prof
flag:
$ ./node --perf-basic-prof
NodeJS is indeed writing perf files to /tmp/
:
$ ls -l /tmp/perf-*
-rw-r--r-- 1 root root 70363 Dec 7 17:37 /tmp/perf-33630.map
We'll search in the binary for the offset of the hardcoded value:
$ xxd ./node | grep -- '/tmp/perf-'
0b62ed0: 2f74 6d70 2f70 6572 662d 2564 2e6d 6170 /tmp/perf-%d.map
The string "tmp" that we want to patch starts at hex 0b62ed1
, decimal 11939537
. mnt
is conveniently three bytes and has a lot of space in our environment, so let's patch with that:
$ dd if=<(printf 'mnt') of=./node obs=1 seek=11939537 conv=notrunc
0+1 records in
3+0 records out
3 bytes (3 B) copied, 3.8673e-05 s, 77.6 kB/s
Now let's verify the patch was successful:
$ diff -u <(xxd $(which node)) <(xxd ./node)
--- /dev/fd/63 2016-12-07 17:38:00.364054335 +0000
+++ /dev/fd/62 2016-12-07 17:38:00.364054335 +0000
@@ -746219,7 +746219,7 @@
0b62ea0: 50cb af00 0000 0000 e088 6e00 0000 0000 P.........n.....
0b62eb0: e088 6e00 0000 0000 7379 6d62 6f6c 2868 ..n.....symbol(h
0b62ec0: 6173 6820 0000 0000 0000 0000 0000 0000 ash ............
-0b62ed0: 2f74 6d70 2f70 6572 662d 2564 2e6d 6170 /tmp/perf-%d.map
+0b62ed0: 2f6d 6e74 2f70 6572 662d 2564 2e6d 6170 /mnt/perf-%d.map
0b62ee0: 0000 0000 1000 0000 0000 0000 0000 0000 ................
0b62ef0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0b62f00: e07f af00 0000 0000 907f af00 0000 0000 ................
Looks good, let's test it out:
$ ./node --perf-basic-prof
Voila!
$ ls -l /mnt/perf-*
-rw-r--r-- 1 root root 70302 Dec 7 17:38 /mnt/perf-33979.map
In order to make this "production ready" you'll just need to perform this patch each time a new version of NodeJS is installed.
Q: I got the following error message, what did I do wrong?
#
# Fatal error in ../deps/v8/src/log.cc, line 272
# Check failed: (perf_output_handle_) != nullptr.
#
==== C stack trace ===============================
1: V8_Fatal
2: v8::internal::PerfBasicLogger::PerfBasicLogger()
3: v8::internal::Logger::SetUp(v8::internal::Isolate*)
4: v8::internal::Isolate::Init(v8::internal::Deserializer*)
5: v8::internal::Snapshot::Initialize(v8::internal::Isolate*)
6: v8::Isolate::New(v8::Isolate::CreateParams const&)
7: node::Start(int, char**)
8: __libc_start_main
9: 0x6e907d
Illegal instruction
A: The path that you patched in is not writable by the NodeJS process. Either escalate the privileges of the NodeJS process or chown
/chmod
the directory.
What NodeJS developers are saying:
This is the first application of hex outside of DOM colors I've seen!
— Jessica Chan
Impressive. 😮