build: use zero overhead systemtap probes
authorBen Noordhuis <info@bnoordhuis.nl>
Mon, 28 Oct 2013 19:18:59 +0000 (20:18 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Tue, 29 Oct 2013 20:55:48 +0000 (21:55 +0100)
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
deps/uv/uv.gyp
node.gyp
src/node.cc
src/node_dtrace.cc

index 9c83434..b3a8b46 100755 (executable)
--- 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
index 74768a0..9509564 100644 (file)
         ['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' ]
             }],
           ],
         }],
       ],
     },
 
+    # 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',
                 '-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)'
+              ],
+            }
+          ]
+        }],
       ]
     },
 
index 7947a23..50c1394 100644 (file)
--- 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': [
           '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.
           #
           # 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',
             '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' ],
             '<(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' ]
       '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',
       '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',
                 '-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',
index b6bd8b7..4e30269 100644 (file)
 #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<Object> global = env->context()->Global();
 
-#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
+#if defined HAVE_DTRACE || defined HAVE_ETW
   InitDTrace(global);
 #endif
 
index de2fcea..e259cfb 100644 (file)
 
 #ifdef HAVE_DTRACE
 #include "node_dtrace.h"
-#include <string.h>
 #include "node_provider.h"
+#include <string.h>
 #elif HAVE_ETW
 #include "node_dtrace.h"
 #include <string.h>
 #include "node_win32_etw_provider.h"
 #include "node_win32_etw_provider-inl.h"
-#elif HAVE_SYSTEMTAP
-#include <string.h>
-#include <node.h>
-#include <v8.h>
-#include <sys/sdt.h>
-#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<Value>& 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<Value>& args) {
 
 
 void DTRACE_NET_STREAM_END(const FunctionCallbackInfo<Value>& 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<Value>& args) {
 
 
 void DTRACE_NET_SOCKET_READ(const FunctionCallbackInfo<Value>& 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<Value>& args) {
 
 
 void DTRACE_NET_SOCKET_WRITE(const FunctionCallbackInfo<Value>& 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<Value>& args) {
 void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo<Value>& args) {
   node_dtrace_http_server_request_t req;
 
-#ifndef HAVE_SYSTEMTAP
   if (!NODE_HTTP_SERVER_REQUEST_ENABLED())
     return;
-#endif
 
   HandleScope scope(node_isolate);
   Local<Object> arg0 = Local<Object>::Cast(args[0]);
@@ -234,10 +217,8 @@ void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo<Value>& args) {
 
 
 void DTRACE_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo<Value>& 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<Value>& 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<Value>& args) {
 
 
 void DTRACE_HTTP_CLIENT_RESPONSE(const FunctionCallbackInfo<Value>& 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<Object> 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