From c4def505cb333d96915fa234b296327ae3a274c6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 28 Oct 2013 20:18:59 +0100 Subject: [PATCH] build: use zero overhead systemtap probes Profiling suggested that on Linux sometimes over 10% of CPU time was being spent inside the systemtap probe entry points in the binding layer, even when the process was not actively being traced with the `stap` tool. That's why this commit makes it possible to use the *_ENABLED() macros and bail out early when we're not being traced, reducing the overhead of unused probes to (almost) zero. Said macros were already being generated by `dtrace -h` but were not usable because they rely on external definitions. To remedy that, we now generate the accompanying object files with `dtrace -G`. This commit includes a change to libuv that has been landed upstream in commit joyent/libuv@3c172ea. --- configure | 21 ++++++-------- deps/uv/uv.gyp | 25 ++++++++++++++--- node.gyp | 68 +++++++++++++++++++++++++++++----------------- src/node.cc | 8 ++---- src/node_dtrace.cc | 27 ++---------------- 5 files changed, 77 insertions(+), 72 deletions(-) diff --git a/configure b/configure index 9c8343428e38..b3a8b46ad647 100755 --- a/configure +++ b/configure @@ -459,24 +459,21 @@ def configure_node(o): if not is_clang and cc_version < (4,0,0): o['variables']['visibility'] = '' - # By default, enable DTrace on SunOS systems. Don't allow it on other - # systems, since it won't work. (The MacOS build process is different than - # SunOS, and we haven't implemented it.) - if flavor in ('solaris', 'mac'): - o['variables']['node_use_dtrace'] = b(not options.without_dtrace) - o['variables']['uv_use_dtrace'] = o['variables']['node_use_dtrace'] + if flavor in ('solaris', 'mac', 'linux'): + use_dtrace = not options.without_dtrace + # Don't enable by default on linux, it needs the sdt-devel package. + if flavor == 'linux': + if options.systemtap_includes: + o['include_dirs'] += [options.systemtap_includes] + use_dtrace = options.with_dtrace + o['variables']['node_use_dtrace'] = b(use_dtrace) + o['variables']['uv_use_dtrace'] = b(use_dtrace) o['variables']['uv_parent_path'] = '/deps/uv/' - elif flavor == 'linux': - o['variables']['node_use_dtrace'] = 'false' - o['variables']['node_use_systemtap'] = b(options.with_dtrace) - if options.systemtap_includes: - o['include_dirs'] += [options.systemtap_includes] elif options.with_dtrace: raise Exception( 'DTrace is currently only supported on SunOS, MacOS or Linux systems.') else: o['variables']['node_use_dtrace'] = 'false' - o['variables']['node_use_systemtap'] = 'false' # if we're on illumos based systems wrap the helper library into the # executable diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 74768a094a05..950956429917 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -268,13 +268,17 @@ ['library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], + # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. ['uv_use_dtrace=="true"', { 'defines': [ 'HAVE_DTRACE=1' ], 'dependencies': [ 'uv_dtrace_header' ], 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], 'conditions': [ - ['OS != "mac"', { - 'sources': ['src/unix/dtrace.c' ], + [ 'OS not in "mac linux"', { + 'sources': [ 'src/unix/dtrace.c' ], + }], + [ 'OS=="linux"', { + 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ] }], ], }], @@ -480,11 +484,12 @@ ], }, + # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. { 'target_name': 'uv_dtrace_provider', 'type': 'none', 'conditions': [ - [ 'uv_use_dtrace=="true" and OS!="mac"', { + [ 'uv_use_dtrace=="true" and OS not in "mac linux"', { 'actions': [ { 'action_name': 'uv_dtrace_o', @@ -499,7 +504,19 @@ '-o', '<@(_outputs)' ] } ] - } ] + }], + [ 'uv_use_dtrace=="true" and OS=="linux"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_o', + 'inputs': [ 'src/unix/uv-dtrace.d' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ], + 'action': [ + 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' + ], + } + ] + }], ] }, diff --git a/node.gyp b/node.gyp index 7947a237df4a..50c1394719e1 100644 --- a/node.gyp +++ b/node.gyp @@ -14,7 +14,6 @@ 'node_shared_cares%': 'false', 'node_shared_libuv%': 'false', 'node_use_openssl%': 'true', - 'node_use_systemtap%': 'false', 'node_shared_openssl%': 'false', 'node_use_mdb%': 'false', 'library_files': [ @@ -186,12 +185,12 @@ 'dependencies': [ 'node_dtrace_header' ], 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], # - # DTrace is supported on solaris, mac, and bsd. There are three - # object files associated with DTrace support, but they're not all - # used all the time: + # DTrace is supported on linux, solaris, mac, and bsd. There are + # three object files associated with DTrace support, but they're + # not all used all the time: # # node_dtrace.o all configurations - # node_dtrace_ustack.o not supported on OS X + # node_dtrace_ustack.o not supported on mac and linux # node_dtrace_provider.o All except OS X. "dtrace -G" is not # used on OS X. # @@ -202,11 +201,15 @@ # below, and the GYP-generated Makefiles will properly build them when # needed. # - 'sources': [ - 'src/node_dtrace.cc', - ], - 'conditions': [ [ - 'OS!="mac"', { + 'sources': [ 'src/node_dtrace.cc' ], + 'conditions': [ + [ 'OS=="linux"', { + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/node_dtrace_provider.o', + '<(SHARED_INTERMEDIATE_DIR)/libuv_dtrace_provider.o', + ], + }], + [ 'OS!="mac" and OS!="linux"', { 'sources': [ 'src/node_dtrace_ustack.cc', 'src/node_dtrace_provider.cc', @@ -221,12 +224,6 @@ 'src/node_mdb.cc', ], } ], - [ 'node_use_systemtap=="true"', { - 'defines': [ 'HAVE_SYSTEMTAP=1', 'STAP_SDT_V1=1' ], - 'sources': [ - 'src/node_dtrace.cc', - ], - } ], [ 'node_use_etw=="true"', { 'defines': [ 'HAVE_ETW=1' ], 'dependencies': [ 'node_etw' ], @@ -387,11 +384,8 @@ '<(SHARED_INTERMEDIATE_DIR)/node_natives.h', ], 'conditions': [ - [ 'node_use_dtrace=="false"' - ' and node_use_etw=="false"' - ' and node_use_systemtap=="false"', - { - 'inputs': ['src/notrace_macros.py'] + [ 'node_use_dtrace=="false" and node_use_etw=="false"', { + 'inputs': [ 'src/notrace_macros.py' ] }], [ 'node_use_perfctr=="false"', { 'inputs': [ 'src/perfctr_macros.py' ] @@ -410,7 +404,7 @@ 'target_name': 'node_dtrace_header', 'type': 'none', 'conditions': [ - [ 'node_use_dtrace=="true" or node_use_systemtap=="true"', { + [ 'node_use_dtrace=="true"', { 'actions': [ { 'action_name': 'node_dtrace_header', @@ -453,7 +447,7 @@ 'target_name': 'node_dtrace_provider', 'type': 'none', 'conditions': [ - [ 'node_use_dtrace=="true" and OS!="mac"', { + [ 'node_use_dtrace=="true" and OS!="mac" and OS!="linux"', { 'actions': [ { 'action_name': 'node_dtrace_provider_o', @@ -469,14 +463,38 @@ '-o', '<@(_outputs)' ] } ] - } ] + }], + [ 'node_use_dtrace=="true" and OS=="linux"', { + 'actions': [ + { + 'action_name': 'node_dtrace_provider_o', + 'inputs': [ 'src/node_provider.d' ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/node_dtrace_provider.o' + ], + 'action': [ + 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' + ], + }, + { + 'action_name': 'libuv_dtrace_provider_o', + 'inputs': [ 'deps/uv/src/unix/uv-dtrace.d' ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/libuv_dtrace_provider.o' + ], + 'action': [ + 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' + ], + }, + ], + }], ] }, { 'target_name': 'node_dtrace_ustack', 'type': 'none', 'conditions': [ - [ 'node_use_dtrace=="true" and OS!="mac"', { + [ 'node_use_dtrace=="true" and OS!="mac" and OS!="linux"', { 'actions': [ { 'action_name': 'node_dtrace_ustack_constants', diff --git a/src/node.cc b/src/node.cc index b6bd8b70f888..4e30269e0d78 100644 --- a/src/node.cc +++ b/src/node.cc @@ -35,14 +35,10 @@ #include "node_crypto.h" #endif -#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP +#if defined HAVE_DTRACE || defined HAVE_ETW #include "node_dtrace.h" #endif -#if HAVE_SYSTEMTAP -#include "node_provider.h" -#endif - #include "ares.h" #include "env.h" #include "env-inl.h" @@ -2656,7 +2652,7 @@ void Load(Environment* env) { // Add a reference to the global object Local global = env->context()->Global(); -#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP +#if defined HAVE_DTRACE || defined HAVE_ETW InitDTrace(global); #endif diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index de2fceaf4387..e259cfbd06a4 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -22,20 +22,13 @@ #ifdef HAVE_DTRACE #include "node_dtrace.h" -#include #include "node_provider.h" +#include #elif HAVE_ETW #include "node_dtrace.h" #include #include "node_win32_etw_provider.h" #include "node_win32_etw_provider-inl.h" -#elif HAVE_SYSTEMTAP -#include -#include -#include -#include -#include "node_provider.h" -#include "node_dtrace.h" #else #define NODE_HTTP_SERVER_REQUEST(arg0, arg1) #define NODE_HTTP_SERVER_REQUEST_ENABLED() (0) @@ -143,10 +136,8 @@ using v8::Value; void DTRACE_NET_SERVER_CONNECTION(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_NET_SERVER_CONNECTION_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION(args[0], conn); NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port, conn.fd); @@ -154,10 +145,8 @@ void DTRACE_NET_SERVER_CONNECTION(const FunctionCallbackInfo& args) { void DTRACE_NET_STREAM_END(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_NET_STREAM_END_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION(args[0], conn); NODE_NET_STREAM_END(&conn, conn.remote, conn.port, conn.fd); @@ -165,10 +154,8 @@ void DTRACE_NET_STREAM_END(const FunctionCallbackInfo& args) { void DTRACE_NET_SOCKET_READ(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_NET_SOCKET_READ_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION(args[0], conn); @@ -182,10 +169,8 @@ void DTRACE_NET_SOCKET_READ(const FunctionCallbackInfo& args) { void DTRACE_NET_SOCKET_WRITE(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_NET_SOCKET_WRITE_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION(args[0], conn); @@ -201,10 +186,8 @@ void DTRACE_NET_SOCKET_WRITE(const FunctionCallbackInfo& args) { void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { node_dtrace_http_server_request_t req; -#ifndef HAVE_SYSTEMTAP if (!NODE_HTTP_SERVER_REQUEST_ENABLED()) return; -#endif HandleScope scope(node_isolate); Local arg0 = Local::Cast(args[0]); @@ -234,10 +217,8 @@ void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { void DTRACE_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_HTTP_SERVER_RESPONSE_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION(args[0], conn); NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port, conn.fd); @@ -248,10 +229,8 @@ void DTRACE_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo& args) { node_dtrace_http_client_request_t req; char *header; -#ifndef HAVE_SYSTEMTAP if (!NODE_HTTP_CLIENT_REQUEST_ENABLED()) return; -#endif HandleScope scope(node_isolate); @@ -286,10 +265,8 @@ void DTRACE_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo& args) { void DTRACE_HTTP_CLIENT_RESPONSE(const FunctionCallbackInfo& args) { -#ifndef HAVE_SYSTEMTAP if (!NODE_HTTP_CLIENT_RESPONSE_ENABLED()) return; -#endif HandleScope scope(node_isolate); SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(args[0], args[1], conn); NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port, conn.fd); @@ -341,7 +318,7 @@ void InitDTrace(Handle target) { init_etw(); #endif -#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP +#if defined HAVE_DTRACE || defined HAVE_ETW v8::V8::AddGCPrologueCallback((GCPrologueCallback)dtrace_gc_start); v8::V8::AddGCEpilogueCallback((GCEpilogueCallback)dtrace_gc_done); #endif