Skip to content

Commit

Permalink
build: use zero overhead systemtap probes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bnoordhuis committed Oct 29, 2013
1 parent ba7c9ce commit c4def50
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 72 deletions.
21 changes: 9 additions & 12 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 21 additions & 4 deletions deps/uv/uv.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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' ]
}],
],
}],
Expand Down Expand Up @@ -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',
Expand All @@ -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)'
],
}
]
}],
]
},

Expand Down
68 changes: 43 additions & 25 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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': [
Expand Down Expand Up @@ -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.
#
Expand All @@ -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',
Expand All @@ -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' ],
Expand Down Expand Up @@ -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' ]
Expand All @@ -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',
Expand Down Expand Up @@ -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',
Expand All @@ -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',
Expand Down
8 changes: 2 additions & 6 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down
27 changes: 2 additions & 25 deletions src/node_dtrace.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,13 @@

#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)
Expand Down Expand Up @@ -143,32 +136,26 @@ 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);
}


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);
}


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);

Expand All @@ -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);

Expand All @@ -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]);
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c4def50

Please sign in to comment.