windows: add tracing with performance counters
Patch by Henry Rawas and Scott Blomquist.
This commit is contained in:
parent
bc9388342f
commit
f657ce685d
22
configure
vendored
22
configure
vendored
@ -211,6 +211,16 @@ parser.add_option("--without-etw",
|
|||||||
dest="without_etw",
|
dest="without_etw",
|
||||||
help="Build without ETW")
|
help="Build without ETW")
|
||||||
|
|
||||||
|
parser.add_option("--with-perfctr",
|
||||||
|
action="store_true",
|
||||||
|
dest="with_perfctr",
|
||||||
|
help="Build with performance counters (default is true on Windows)")
|
||||||
|
|
||||||
|
parser.add_option("--without-perfctr",
|
||||||
|
action="store_true",
|
||||||
|
dest="without_perfctr",
|
||||||
|
help="Build without performance counters")
|
||||||
|
|
||||||
# CHECKME does this still work with recent releases of V8?
|
# CHECKME does this still work with recent releases of V8?
|
||||||
parser.add_option("--gdb",
|
parser.add_option("--gdb",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@ -454,7 +464,7 @@ def configure_node(o):
|
|||||||
o['variables']['node_use_systemtap'] = b(options.with_dtrace)
|
o['variables']['node_use_systemtap'] = b(options.with_dtrace)
|
||||||
if options.systemtap_includes:
|
if options.systemtap_includes:
|
||||||
o['include_dirs'] += [options.systemtap_includes]
|
o['include_dirs'] += [options.systemtap_includes]
|
||||||
elif b(options.with_dtrace) == 'true':
|
elif options.with_dtrace:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
'DTrace is currently only supported on SunOS or Linux systems.')
|
'DTrace is currently only supported on SunOS or Linux systems.')
|
||||||
else:
|
else:
|
||||||
@ -467,11 +477,19 @@ def configure_node(o):
|
|||||||
# By default, enable ETW on Windows.
|
# By default, enable ETW on Windows.
|
||||||
if sys.platform.startswith('win32'):
|
if sys.platform.startswith('win32'):
|
||||||
o['variables']['node_use_etw'] = b(not options.without_etw);
|
o['variables']['node_use_etw'] = b(not options.without_etw);
|
||||||
elif b(options.with_etw) == 'true':
|
elif options.with_etw:
|
||||||
raise Exception('ETW is only supported on Windows.')
|
raise Exception('ETW is only supported on Windows.')
|
||||||
else:
|
else:
|
||||||
o['variables']['node_use_etw'] = 'false'
|
o['variables']['node_use_etw'] = 'false'
|
||||||
|
|
||||||
|
# By default, enable Performance counters on Windows.
|
||||||
|
if sys.platform.startswith('win32'):
|
||||||
|
o['variables']['node_use_perfctr'] = b(not options.without_perfctr);
|
||||||
|
elif options.with_perfctr:
|
||||||
|
raise Exception('Performance counter is only supported on Windows.')
|
||||||
|
else:
|
||||||
|
o['variables']['node_use_perfctr'] = 'false'
|
||||||
|
|
||||||
|
|
||||||
def configure_libz(o):
|
def configure_libz(o):
|
||||||
o['variables']['node_shared_zlib'] = b(options.shared_zlib)
|
o['variables']['node_shared_zlib'] = b(options.shared_zlib)
|
||||||
|
@ -841,9 +841,11 @@ OutgoingMessage.prototype._finish = function() {
|
|||||||
assert(this.connection);
|
assert(this.connection);
|
||||||
if (this instanceof ServerResponse) {
|
if (this instanceof ServerResponse) {
|
||||||
DTRACE_HTTP_SERVER_RESPONSE(this.connection);
|
DTRACE_HTTP_SERVER_RESPONSE(this.connection);
|
||||||
|
COUNTER_HTTP_SERVER_RESPONSE();
|
||||||
} else {
|
} else {
|
||||||
assert(this instanceof ClientRequest);
|
assert(this instanceof ClientRequest);
|
||||||
DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
|
DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
|
||||||
|
COUNTER_HTTP_CLIENT_REQUEST();
|
||||||
}
|
}
|
||||||
this.emit('finish');
|
this.emit('finish');
|
||||||
};
|
};
|
||||||
@ -1472,6 +1474,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
|
|||||||
|
|
||||||
|
|
||||||
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
|
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
|
||||||
|
COUNTER_HTTP_CLIENT_RESPONSE();
|
||||||
req.emit('response', res);
|
req.emit('response', res);
|
||||||
req.res = res;
|
req.res = res;
|
||||||
res.req = req;
|
res.req = req;
|
||||||
@ -1779,6 +1782,7 @@ function connectionListener(socket) {
|
|||||||
debug('server response shouldKeepAlive: ' + shouldKeepAlive);
|
debug('server response shouldKeepAlive: ' + shouldKeepAlive);
|
||||||
res.shouldKeepAlive = shouldKeepAlive;
|
res.shouldKeepAlive = shouldKeepAlive;
|
||||||
DTRACE_HTTP_SERVER_REQUEST(req, socket);
|
DTRACE_HTTP_SERVER_REQUEST(req, socket);
|
||||||
|
COUNTER_HTTP_SERVER_REQUEST();
|
||||||
|
|
||||||
if (socket._httpMessage) {
|
if (socket._httpMessage) {
|
||||||
// There are already pending outgoing res, append.
|
// There are already pending outgoing res, append.
|
||||||
|
@ -361,6 +361,7 @@ Socket.prototype._destroy = function(exception, cb) {
|
|||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
|
|
||||||
if (this.server) {
|
if (this.server) {
|
||||||
|
COUNTER_NET_SERVER_CONNECTION_CLOSE(this);
|
||||||
this.server._connections--;
|
this.server._connections--;
|
||||||
if (this.server._emitCloseIfDrained) {
|
if (this.server._emitCloseIfDrained) {
|
||||||
this.server._emitCloseIfDrained();
|
this.server._emitCloseIfDrained();
|
||||||
@ -1054,6 +1055,7 @@ function onconnection(clientHandle) {
|
|||||||
socket.server = self;
|
socket.server = self;
|
||||||
|
|
||||||
DTRACE_NET_SERVER_CONNECTION(socket);
|
DTRACE_NET_SERVER_CONNECTION(socket);
|
||||||
|
COUNTER_NET_SERVER_CONNECTION(socket);
|
||||||
self.emit('connection', socket);
|
self.emit('connection', socket);
|
||||||
socket.emit('connect');
|
socket.emit('connect');
|
||||||
}
|
}
|
||||||
|
72
node.gyp
72
node.gyp
@ -6,6 +6,7 @@
|
|||||||
'werror': '',
|
'werror': '',
|
||||||
'node_use_dtrace%': 'false',
|
'node_use_dtrace%': 'false',
|
||||||
'node_use_etw%': 'false',
|
'node_use_etw%': 'false',
|
||||||
|
'node_use_perfctr%': 'false',
|
||||||
'node_shared_v8%': 'false',
|
'node_shared_v8%': 'false',
|
||||||
'node_shared_zlib%': 'false',
|
'node_shared_zlib%': 'false',
|
||||||
'node_shared_http_parser%': 'false',
|
'node_shared_http_parser%': 'false',
|
||||||
@ -189,6 +190,17 @@
|
|||||||
'<(SHARED_INTERMEDIATE_DIR)/node_etw_provider.rc',
|
'<(SHARED_INTERMEDIATE_DIR)/node_etw_provider.rc',
|
||||||
]
|
]
|
||||||
} ],
|
} ],
|
||||||
|
[ 'node_use_perfctr=="true"', {
|
||||||
|
'defines': [ 'HAVE_PERFCTR=1' ],
|
||||||
|
'dependencies': [ 'node_perfctr' ],
|
||||||
|
'sources': [
|
||||||
|
'src/node_win32_perfctr_provider.h',
|
||||||
|
'src/node_win32_perfctr_provider.cc',
|
||||||
|
'src/node_counters.cc',
|
||||||
|
'src/node_counters.h',
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/node_perfctr_provider.rc',
|
||||||
|
]
|
||||||
|
} ],
|
||||||
[ 'node_shared_v8=="false"', {
|
[ 'node_shared_v8=="false"', {
|
||||||
'sources': [
|
'sources': [
|
||||||
'deps/v8/include/v8.h',
|
'deps/v8/include/v8.h',
|
||||||
@ -287,6 +299,29 @@
|
|||||||
} ]
|
} ]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
# generate perf counter header and resource files
|
||||||
|
{
|
||||||
|
'target_name': 'node_perfctr',
|
||||||
|
'type': 'none',
|
||||||
|
'conditions': [
|
||||||
|
[ 'node_use_perfctr=="true"', {
|
||||||
|
'actions': [
|
||||||
|
{
|
||||||
|
'action_name': 'node_perfctr_man',
|
||||||
|
'inputs': [ 'src/res/node_perfctr_provider.man' ],
|
||||||
|
'outputs': [
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/node_perfctr_provider.h',
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/node_perfctr_provider.rc',
|
||||||
|
],
|
||||||
|
'action': [ 'ctrpp <@(_inputs) '
|
||||||
|
'-o <(SHARED_INTERMEDIATE_DIR)/node_perfctr_provider.h '
|
||||||
|
'-rc <(SHARED_INTERMEDIATE_DIR)/node_perfctr_provider.rc'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} ]
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'target_name': 'node_js2c',
|
'target_name': 'node_js2c',
|
||||||
'type': 'none',
|
'type': 'none',
|
||||||
@ -294,41 +329,31 @@
|
|||||||
'actions': [
|
'actions': [
|
||||||
{
|
{
|
||||||
'action_name': 'node_js2c',
|
'action_name': 'node_js2c',
|
||||||
|
|
||||||
'inputs': [
|
'inputs': [
|
||||||
'<@(library_files)',
|
'<@(library_files)',
|
||||||
'./config.gypi',
|
'./config.gypi',
|
||||||
],
|
],
|
||||||
|
|
||||||
'outputs': [
|
'outputs': [
|
||||||
'<(SHARED_INTERMEDIATE_DIR)/node_natives.h',
|
'<(SHARED_INTERMEDIATE_DIR)/node_natives.h',
|
||||||
],
|
],
|
||||||
|
|
||||||
# FIXME can the following conditions be shorted by just setting
|
|
||||||
# macros.py into some variable which then gets included in the
|
|
||||||
# action?
|
|
||||||
|
|
||||||
'conditions': [
|
'conditions': [
|
||||||
[ 'node_use_dtrace=="true"'
|
[ 'node_use_dtrace=="false"'
|
||||||
' or node_use_etw=="true"'
|
' and node_use_etw=="false"'
|
||||||
' or node_use_systemtap=="true"',
|
' and node_use_systemtap=="false"',
|
||||||
{
|
{
|
||||||
'action': [
|
'inputs': ['src/macros.py']
|
||||||
'<(python)',
|
}
|
||||||
'tools/js2c.py',
|
|
||||||
'<@(_outputs)',
|
|
||||||
'<@(_inputs)',
|
|
||||||
],
|
|
||||||
}, { # No Dtrace
|
|
||||||
'action': [
|
|
||||||
'<(python)',
|
|
||||||
'tools/js2c.py',
|
|
||||||
'<@(_outputs)',
|
|
||||||
'<@(_inputs)',
|
|
||||||
'src/macros.py'
|
|
||||||
],
|
],
|
||||||
|
[ 'node_use_perfctr=="false"', {
|
||||||
|
'inputs': [ 'src/perfctr_macros.py' ]
|
||||||
}]
|
}]
|
||||||
],
|
],
|
||||||
|
'action': [
|
||||||
|
'<(python)',
|
||||||
|
'tools/js2c.py',
|
||||||
|
'<@(_outputs)',
|
||||||
|
'<@(_inputs)',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}, # end node_js2c
|
}, # end node_js2c
|
||||||
@ -428,4 +453,3 @@
|
|||||||
}
|
}
|
||||||
] # end targets
|
] # end targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
|
#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
|
||||||
# include "node_dtrace.h"
|
# include "node_dtrace.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined HAVE_PERFCTR
|
||||||
|
# include "node_counters.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -2314,6 +2317,10 @@ void Load(Handle<Object> process_l) {
|
|||||||
InitDTrace(global);
|
InitDTrace(global);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined HAVE_PERFCTR
|
||||||
|
InitPerfCounters(global);
|
||||||
|
#endif
|
||||||
|
|
||||||
f->Call(global, 1, args);
|
f->Call(global, 1, args);
|
||||||
|
|
||||||
if (try_catch.HasCaught()) {
|
if (try_catch.HasCaught()) {
|
||||||
|
149
src/node_counters.cc
Normal file
149
src/node_counters.cc
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "node_counters.h"
|
||||||
|
|
||||||
|
#include "uv.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
using namespace v8;
|
||||||
|
|
||||||
|
|
||||||
|
static uint64_t counter_gc_start_time;
|
||||||
|
static uint64_t counter_gc_end_time;
|
||||||
|
|
||||||
|
#define SLURP_OBJECT(obj, member, valp) \
|
||||||
|
if (!(obj)->IsObject()) { \
|
||||||
|
return (ThrowException(Exception::Error(String::New("expected " \
|
||||||
|
"object for " #obj " to contain object member " #member)))); \
|
||||||
|
} \
|
||||||
|
*valp = Local<Object>::Cast(obj->Get(String::New(#member)));
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_NET_SERVER_CONNECTION(const Arguments& args) {
|
||||||
|
NODE_COUNT_SERVER_CONN_OPEN();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_NET_SERVER_CONNECTION_CLOSE(const Arguments& args) {
|
||||||
|
NODE_COUNT_SERVER_CONN_CLOSE();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_HTTP_SERVER_REQUEST(const Arguments& args) {
|
||||||
|
NODE_COUNT_HTTP_SERVER_REQUEST();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_HTTP_SERVER_RESPONSE(const Arguments& args) {
|
||||||
|
NODE_COUNT_HTTP_SERVER_RESPONSE();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_HTTP_CLIENT_REQUEST(const Arguments& args) {
|
||||||
|
NODE_COUNT_HTTP_CLIENT_REQUEST();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> COUNTER_HTTP_CLIENT_RESPONSE(const Arguments& args) {
|
||||||
|
NODE_COUNT_HTTP_CLIENT_RESPONSE();
|
||||||
|
return Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void counter_gc_start(GCType type, GCCallbackFlags flags) {
|
||||||
|
counter_gc_start_time = NODE_COUNT_GET_GC_RAWTIME();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void counter_gc_done(GCType type, GCCallbackFlags flags) {
|
||||||
|
uint64_t endgc = NODE_COUNT_GET_GC_RAWTIME();
|
||||||
|
if (endgc != 0) {
|
||||||
|
uint64_t totalperiod = endgc - counter_gc_end_time;
|
||||||
|
uint64_t gcperiod = endgc - counter_gc_start_time;
|
||||||
|
|
||||||
|
if (totalperiod > 0) {
|
||||||
|
unsigned int percent = static_cast<unsigned int>((gcperiod * 100) / totalperiod);
|
||||||
|
|
||||||
|
NODE_COUNT_GC_PERCENTTIME(percent);
|
||||||
|
counter_gc_end_time = endgc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define NODE_PROBE(name) #name, name
|
||||||
|
|
||||||
|
void InitPerfCounters(Handle<Object> target) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char* name;
|
||||||
|
Handle<Value> (*func)(const Arguments&);
|
||||||
|
Persistent<FunctionTemplate> templ;
|
||||||
|
} tab[] = {
|
||||||
|
{ NODE_PROBE(COUNTER_NET_SERVER_CONNECTION) },
|
||||||
|
{ NODE_PROBE(COUNTER_NET_SERVER_CONNECTION_CLOSE) },
|
||||||
|
{ NODE_PROBE(COUNTER_HTTP_SERVER_REQUEST) },
|
||||||
|
{ NODE_PROBE(COUNTER_HTTP_SERVER_RESPONSE) },
|
||||||
|
{ NODE_PROBE(COUNTER_HTTP_CLIENT_REQUEST) },
|
||||||
|
{ NODE_PROBE(COUNTER_HTTP_CLIENT_RESPONSE) }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(tab); i++) {
|
||||||
|
tab[i].templ = Persistent<FunctionTemplate>::New(
|
||||||
|
FunctionTemplate::New(tab[i].func));
|
||||||
|
target->Set(String::NewSymbol(tab[i].name), tab[i].templ->GetFunction());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only Windows performance counters supported
|
||||||
|
// To enable other OS, use conditional compilation here
|
||||||
|
InitPerfCountersWin32();
|
||||||
|
|
||||||
|
// init times for GC percent calculation and hook callbacks
|
||||||
|
counter_gc_start_time = NODE_COUNT_GET_GC_RAWTIME();
|
||||||
|
counter_gc_end_time = counter_gc_start_time;
|
||||||
|
|
||||||
|
v8::V8::AddGCPrologueCallback(counter_gc_start);
|
||||||
|
v8::V8::AddGCEpilogueCallback(counter_gc_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TermPerfCounters(Handle<Object> target) {
|
||||||
|
// Only Windows performance counters supported
|
||||||
|
// To enable other OS, use conditional compilation here
|
||||||
|
TermPerfCountersWin32();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
src/node_counters.h
Normal file
53
src/node_counters.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef NODE_COUNTERS_H_
|
||||||
|
#define NODE_COUNTERS_H_
|
||||||
|
|
||||||
|
#include "node.h"
|
||||||
|
#include "v8.h"
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
void InitPerfCounters(v8::Handle<v8::Object> target);
|
||||||
|
void TermPerfCounters(v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_PERFCTR
|
||||||
|
#include "node_win32_perfctr_provider.h"
|
||||||
|
#else
|
||||||
|
#define NODE_COUNTER_ENABLED() (false)
|
||||||
|
#define NODE_COUNT_HTTP_SERVER_REQUEST()
|
||||||
|
#define NODE_COUNT_HTTP_SERVER_RESPONSE()
|
||||||
|
#define NODE_COUNT_HTTP_CLIENT_REQUEST()
|
||||||
|
#define NODE_COUNT_HTTP_CLIENT_RESPONSE()
|
||||||
|
#define NODE_COUNT_SERVER_CONN_OPEN()
|
||||||
|
#define NODE_COUNT_SERVER_CONN_CLOSE()
|
||||||
|
#define NODE_COUNT_NET_BYTES_SENT(bytes)
|
||||||
|
#define NODE_COUNT_NET_BYTES_RECV(bytes)
|
||||||
|
#define NODE_COUNT_GET_GC_RAWTIME()
|
||||||
|
#define NODE_COUNT_GC_PERCENTTIME()
|
||||||
|
#define NODE_COUNT_PIPE_BYTES_SENT(bytes)
|
||||||
|
#define NODE_COUNT_PIPE_BYTES_RECV(bytes)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
338
src/node_win32_perfctr_provider.cc
Normal file
338
src/node_win32_perfctr_provider.cc
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "node_counters.h"
|
||||||
|
#include <perflib.h>
|
||||||
|
#include "node_win32_perfctr_provider.h"
|
||||||
|
|
||||||
|
#define __INIT_node_perfctr_provider_IMP
|
||||||
|
#include <node_perfctr_provider.h>
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfStartProviderExFunc)(
|
||||||
|
__in LPGUID ProviderGuid,
|
||||||
|
__in_opt PPERF_PROVIDER_CONTEXT ProviderContext,
|
||||||
|
__out PHANDLE Provider
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfStopProviderFunc)(
|
||||||
|
__in HANDLE ProviderHandle
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfSetCounterSetInfoFunc)(
|
||||||
|
__in HANDLE ProviderHandle,
|
||||||
|
__inout_bcount(TemplateSize) PPERF_COUNTERSET_INFO Template,
|
||||||
|
__in ULONG TemplateSize
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef PPERF_COUNTERSET_INSTANCE (WINAPI *PerfCreateInstanceFunc)(
|
||||||
|
__in HANDLE ProviderHandle,
|
||||||
|
__in LPCGUID CounterSetGuid,
|
||||||
|
__in PCWSTR Name,
|
||||||
|
__in ULONG Id
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfDeleteInstanceFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__in PPERF_COUNTERSET_INSTANCE InstanceBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfSetULongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfSetULongLongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONGLONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfIncrementULongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfIncrementULongLongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONGLONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfDecrementULongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ULONG (WINAPI *PerfDecrementULongLongCounterValueFunc)(
|
||||||
|
__in HANDLE Provider,
|
||||||
|
__inout PPERF_COUNTERSET_INSTANCE Instance,
|
||||||
|
__in ULONG CounterId,
|
||||||
|
__in ULONGLONG Value
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
HMODULE advapimod;
|
||||||
|
PerfStartProviderExFunc perfctr_startProvider;
|
||||||
|
PerfStopProviderFunc perfctr_stopProvider;
|
||||||
|
PerfSetCounterSetInfoFunc perfctr_setCounterSetInfo;
|
||||||
|
PerfCreateInstanceFunc perfctr_createInstance;
|
||||||
|
PerfDeleteInstanceFunc perfctr_deleteInstance;
|
||||||
|
PerfSetULongCounterValueFunc perfctr_setULongValue;
|
||||||
|
PerfSetULongLongCounterValueFunc perfctr_setULongLongValue;
|
||||||
|
PerfIncrementULongCounterValueFunc perfctr_incrementULongValue;
|
||||||
|
PerfIncrementULongLongCounterValueFunc perfctr_incrementULongLongValue;
|
||||||
|
PerfDecrementULongCounterValueFunc perfctr_decrementULongValue;
|
||||||
|
PerfDecrementULongLongCounterValueFunc perfctr_decrementULongLongValue;
|
||||||
|
|
||||||
|
PPERF_COUNTERSET_INSTANCE perfctr_instance;
|
||||||
|
|
||||||
|
|
||||||
|
#define NODE_COUNTER_HTTP_SERVER_REQUEST 1
|
||||||
|
#define NODE_COUNTER_HTTP_SERVER_RESPONSE 2
|
||||||
|
#define NODE_COUNTER_HTTP_CLIENT_REQUEST 3
|
||||||
|
#define NODE_COUNTER_HTTP_CLIENT_RESPONSE 4
|
||||||
|
#define NODE_COUNTER_SERVER_CONNS 5
|
||||||
|
#define NODE_COUNTER_NET_BYTES_SENT 6
|
||||||
|
#define NODE_COUNTER_NET_BYTES_RECV 7
|
||||||
|
#define NODE_COUNTER_GC_PERCENTTIME 8
|
||||||
|
#define NODE_COUNTER_PIPE_BYTES_SENT 9
|
||||||
|
#define NODE_COUNTER_PIPE_BYTES_RECV 10
|
||||||
|
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_C DECLSPEC_SELECTANY HANDLE NodeCounterProvider = NULL;
|
||||||
|
|
||||||
|
void InitPerfCountersWin32() {
|
||||||
|
ULONG status;
|
||||||
|
PERF_PROVIDER_CONTEXT providerContext;
|
||||||
|
|
||||||
|
// create instance name using pid
|
||||||
|
#define INST_MAX_LEN 32
|
||||||
|
#define INST_PREFIX_LEN 5
|
||||||
|
#define INST_PREFIX L"node_"
|
||||||
|
|
||||||
|
wchar_t Inst[INST_MAX_LEN];
|
||||||
|
DWORD pid = GetCurrentProcessId();
|
||||||
|
wcscpy_s(Inst, INST_MAX_LEN, INST_PREFIX);
|
||||||
|
_itow_s(pid, Inst + INST_PREFIX_LEN, INST_MAX_LEN - INST_PREFIX_LEN, 10);
|
||||||
|
|
||||||
|
advapimod = LoadLibrary("advapi32.dll");
|
||||||
|
if (advapimod) {
|
||||||
|
perfctr_startProvider = (PerfStartProviderExFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfStartProviderEx");
|
||||||
|
perfctr_stopProvider = (PerfStopProviderFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfStopProvider");
|
||||||
|
perfctr_setCounterSetInfo = (PerfSetCounterSetInfoFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfSetCounterSetInfo");
|
||||||
|
perfctr_createInstance = (PerfCreateInstanceFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfCreateInstance");
|
||||||
|
perfctr_deleteInstance = (PerfDeleteInstanceFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfDeleteInstance");
|
||||||
|
perfctr_setULongValue = (PerfSetULongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfSetULongCounterValue");
|
||||||
|
perfctr_setULongLongValue = (PerfSetULongLongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfSetULongLongCounterValue");
|
||||||
|
perfctr_incrementULongValue = (PerfIncrementULongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfIncrementULongCounterValue");
|
||||||
|
perfctr_incrementULongLongValue = (PerfIncrementULongLongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfIncrementULongLongCounterValue");
|
||||||
|
perfctr_decrementULongValue = (PerfDecrementULongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfDecrementULongCounterValue");
|
||||||
|
perfctr_decrementULongLongValue = (PerfDecrementULongLongCounterValueFunc)
|
||||||
|
GetProcAddress(advapimod, "PerfDecrementULongLongCounterValue");
|
||||||
|
|
||||||
|
ZeroMemory(&providerContext, sizeof(providerContext));
|
||||||
|
providerContext.ContextSize = sizeof(providerContext);
|
||||||
|
|
||||||
|
status = perfctr_startProvider(&NodeCounterSetGuid,
|
||||||
|
&providerContext,
|
||||||
|
&NodeCounterProvider);
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
NodeCounterProvider = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = perfctr_setCounterSetInfo(NodeCounterProvider,
|
||||||
|
&NodeCounterSetInfo.CounterSet,
|
||||||
|
sizeof(NodeCounterSetInfo));
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
perfctr_stopProvider(NodeCounterProvider);
|
||||||
|
NodeCounterProvider = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
perfctr_instance = perfctr_createInstance(NodeCounterProvider,
|
||||||
|
&NodeCounterSetGuid,
|
||||||
|
Inst,
|
||||||
|
1);
|
||||||
|
if (perfctr_instance == NULL) {
|
||||||
|
perfctr_stopProvider(NodeCounterProvider);
|
||||||
|
NodeCounterProvider = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TermPerfCountersWin32() {
|
||||||
|
if (NodeCounterProvider != NULL &&
|
||||||
|
perfctr_stopProvider != NULL) {
|
||||||
|
perfctr_stopProvider(NodeCounterProvider);
|
||||||
|
NodeCounterProvider = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advapimod) {
|
||||||
|
FreeLibrary(advapimod);
|
||||||
|
advapimod = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_HTTP_SERVER_REQUEST() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongValue != NULL) {
|
||||||
|
perfctr_incrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_HTTP_SERVER_REQUEST,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_HTTP_SERVER_RESPONSE() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongValue != NULL) {
|
||||||
|
perfctr_incrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_HTTP_SERVER_RESPONSE,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_HTTP_CLIENT_REQUEST() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongValue != NULL) {
|
||||||
|
perfctr_incrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_HTTP_CLIENT_REQUEST,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_HTTP_CLIENT_RESPONSE() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongValue != NULL) {
|
||||||
|
perfctr_incrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_HTTP_CLIENT_RESPONSE,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_SERVER_CONN_OPEN() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongValue != NULL) {
|
||||||
|
perfctr_incrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_SERVER_CONNS,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_SERVER_CONN_CLOSE() {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_decrementULongValue != NULL) {
|
||||||
|
perfctr_decrementULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_SERVER_CONNS,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_NET_BYTES_SENT(int bytes) {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongLongValue != NULL) {
|
||||||
|
perfctr_incrementULongLongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_NET_BYTES_SENT,
|
||||||
|
static_cast<ULONGLONG>(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_NET_BYTES_RECV(int bytes) {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongLongValue != NULL) {
|
||||||
|
perfctr_incrementULongLongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_NET_BYTES_RECV,
|
||||||
|
static_cast<ULONGLONG>(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t NODE_COUNT_GET_GC_RAWTIME() {
|
||||||
|
LARGE_INTEGER timegc;
|
||||||
|
if (QueryPerformanceCounter(&timegc)) {
|
||||||
|
return timegc.QuadPart;
|
||||||
|
} else {
|
||||||
|
return static_cast<uint64_t>(GetTickCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_GC_PERCENTTIME(unsigned int percent) {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_setULongValue != NULL) {
|
||||||
|
perfctr_setULongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_GC_PERCENTTIME,
|
||||||
|
percent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_PIPE_BYTES_SENT(int bytes) {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongLongValue != NULL) {
|
||||||
|
perfctr_incrementULongLongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_PIPE_BYTES_SENT,
|
||||||
|
static_cast<ULONGLONG>(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NODE_COUNT_PIPE_BYTES_RECV(int bytes) {
|
||||||
|
if (NodeCounterProvider != NULL && perfctr_incrementULongLongValue != NULL) {
|
||||||
|
perfctr_incrementULongLongValue(NodeCounterProvider,
|
||||||
|
perfctr_instance,
|
||||||
|
NODE_COUNTER_PIPE_BYTES_RECV,
|
||||||
|
static_cast<ULONGLONG>(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
55
src/node_win32_perfctr_provider.h
Normal file
55
src/node_win32_perfctr_provider.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef SRC_WINPERFCTRS_H_
|
||||||
|
#define SRC_WINPERFCTRS_H_
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define INLINE __forceinline
|
||||||
|
#else
|
||||||
|
# define INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
extern HANDLE NodeCounterProvider;
|
||||||
|
|
||||||
|
INLINE bool NODE_COUNTER_ENABLED() { return NodeCounterProvider != NULL; }
|
||||||
|
void NODE_COUNT_HTTP_SERVER_REQUEST();
|
||||||
|
void NODE_COUNT_HTTP_SERVER_RESPONSE();
|
||||||
|
void NODE_COUNT_HTTP_CLIENT_REQUEST();
|
||||||
|
void NODE_COUNT_HTTP_CLIENT_RESPONSE();
|
||||||
|
void NODE_COUNT_SERVER_CONN_OPEN();
|
||||||
|
void NODE_COUNT_SERVER_CONN_CLOSE();
|
||||||
|
void NODE_COUNT_NET_BYTES_SENT(int bytes);
|
||||||
|
void NODE_COUNT_NET_BYTES_RECV(int bytes);
|
||||||
|
uint64_t NODE_COUNT_GET_GC_RAWTIME();
|
||||||
|
void NODE_COUNT_GC_PERCENTTIME(unsigned int percent);
|
||||||
|
void NODE_COUNT_PIPE_BYTES_SENT(int bytes);
|
||||||
|
void NODE_COUNT_PIPE_BYTES_RECV(int bytes);
|
||||||
|
|
||||||
|
void InitPerfCountersWin32();
|
||||||
|
void TermPerfCountersWin32();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
9
src/perfctr_macros.py
Normal file
9
src/perfctr_macros.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# This file is used by tools/js2c.py to preprocess out the performance counters
|
||||||
|
# symbols in builds that don't support counters. This is not used in builds
|
||||||
|
# that support performance counters.
|
||||||
|
macro COUNTER_NET_SERVER_CONNECTION(x) = ;
|
||||||
|
macro COUNTER_NET_SERVER_CONNECTION_CLOSE(x) = ;
|
||||||
|
macro COUNTER_HTTP_SERVER_REQUEST(x) = ;
|
||||||
|
macro COUNTER_HTTP_SERVER_RESPONSE(x) = ;
|
||||||
|
macro COUNTER_HTTP_CLIENT_REQUEST(x) = ;
|
||||||
|
macro COUNTER_HTTP_CLIENT_RESPONSE(x) = ;
|
97
src/res/node_perfctr_provider.man
Normal file
97
src/res/node_perfctr_provider.man
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<instrumentationManifest
|
||||||
|
xmlns="http://schemas.microsoft.com/win/2004/08/events"
|
||||||
|
xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<instrumentation>
|
||||||
|
<counters xmlns="http://schemas.microsoft.com/win/2005/12/counters"
|
||||||
|
schemaVersion="1.1">
|
||||||
|
<provider symbol="NodeCounterProvider"
|
||||||
|
applicationIdentity="node.exe"
|
||||||
|
providerType="userMode"
|
||||||
|
providerGuid="{1E2E15D7-3760-470E-8699-B9DB5248EDD5}">
|
||||||
|
<counterSet symbol="NodeCounterSet"
|
||||||
|
guid="{3A22A8EC-297C-48AC-AB15-33EC93033FD8}"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet"
|
||||||
|
name="Node.js"
|
||||||
|
description="Node.js performance counters"
|
||||||
|
instances="multiple">
|
||||||
|
|
||||||
|
<counter id="1"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.httpsrvreq"
|
||||||
|
name="HTTP server requests"
|
||||||
|
description="Number of HTTP server requests"
|
||||||
|
type="perf_counter_counter"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="2"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.httpsrvrsp"
|
||||||
|
name="HTTP server responses"
|
||||||
|
description="Number of HTTP server responses"
|
||||||
|
type="perf_counter_counter"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="3"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.httpclireq"
|
||||||
|
name="HTTP client requests"
|
||||||
|
description="Number of HTTP client requests"
|
||||||
|
type="perf_counter_counter"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="4"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.httpclirsp"
|
||||||
|
name="HTTP client responses"
|
||||||
|
description="Number of HTTP client responses"
|
||||||
|
type="perf_counter_counter"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="5"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.netsrvconn"
|
||||||
|
name="Active server connections"
|
||||||
|
description="Number of server connections"
|
||||||
|
type="perf_counter_rawcount"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="6"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.netbytesent"
|
||||||
|
name="Network bytes sent"
|
||||||
|
description="Number of bytes sent using TCP"
|
||||||
|
type="perf_counter_bulk_count"
|
||||||
|
detailLevel="standard"
|
||||||
|
defaultScale="-3" />
|
||||||
|
|
||||||
|
<counter id="7"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.netbyterecv"
|
||||||
|
name="Network bytes received"
|
||||||
|
description="Number of bytes received using TCP"
|
||||||
|
type="perf_counter_bulk_count"
|
||||||
|
detailLevel="standard"
|
||||||
|
defaultScale="-3" />
|
||||||
|
|
||||||
|
<counter id="8"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.gctime"
|
||||||
|
name="%Time in GC"
|
||||||
|
description="Percent of time for last GC"
|
||||||
|
type="perf_counter_rawcount"
|
||||||
|
detailLevel="standard" />
|
||||||
|
|
||||||
|
<counter id="9"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.pipebytesent"
|
||||||
|
name="Pipe bytes sent"
|
||||||
|
description="Number of bytes sent using pipe"
|
||||||
|
type="perf_counter_bulk_count"
|
||||||
|
detailLevel="standard"
|
||||||
|
defaultScale="-3" />
|
||||||
|
|
||||||
|
<counter id="10"
|
||||||
|
uri="Microsoft.Windows.System.PerfCounters.NodeCounterSet.pipebyterecv"
|
||||||
|
name="Pipe bytes received"
|
||||||
|
description="Number of bytes received using pipe"
|
||||||
|
type="perf_counter_bulk_count"
|
||||||
|
detailLevel="standard"
|
||||||
|
defaultScale="-3" />
|
||||||
|
|
||||||
|
</counterSet>
|
||||||
|
</provider>
|
||||||
|
</counters>
|
||||||
|
</instrumentation>
|
||||||
|
</instrumentationManifest>
|
@ -27,6 +27,7 @@
|
|||||||
#include "pipe_wrap.h"
|
#include "pipe_wrap.h"
|
||||||
#include "tcp_wrap.h"
|
#include "tcp_wrap.h"
|
||||||
#include "req_wrap.h"
|
#include "req_wrap.h"
|
||||||
|
#include "node_counters.h"
|
||||||
|
|
||||||
#include <stdlib.h> // abort()
|
#include <stdlib.h> // abort()
|
||||||
#include <limits.h> // INT_MAX
|
#include <limits.h> // INT_MAX
|
||||||
@ -226,6 +227,12 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
|
|||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wrap->stream_->type == UV_TCP) {
|
||||||
|
NODE_COUNT_NET_BYTES_RECV(nread);
|
||||||
|
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
||||||
|
NODE_COUNT_PIPE_BYTES_RECV(nread);
|
||||||
|
}
|
||||||
|
|
||||||
MakeCallback(wrap->object_, onread_sym, argc, argv);
|
MakeCallback(wrap->object_, onread_sym, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +292,12 @@ Handle<Value> StreamWrap::WriteBuffer(const Arguments& args) {
|
|||||||
delete[] storage;
|
delete[] storage;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
|
if (wrap->stream_->type == UV_TCP) {
|
||||||
|
NODE_COUNT_NET_BYTES_SENT(length);
|
||||||
|
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
||||||
|
NODE_COUNT_PIPE_BYTES_SENT(length);
|
||||||
|
}
|
||||||
|
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,6 +431,12 @@ Handle<Value> StreamWrap::WriteStringImpl(const Arguments& args) {
|
|||||||
delete[] storage;
|
delete[] storage;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
|
if (wrap->stream_->type == UV_TCP) {
|
||||||
|
NODE_COUNT_NET_BYTES_SENT(buf.len);
|
||||||
|
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
||||||
|
NODE_COUNT_PIPE_BYTES_SENT(buf.len);
|
||||||
|
}
|
||||||
|
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,14 @@ process.on('exit', function() {
|
|||||||
knownGlobals.push(DTRACE_NET_SOCKET_READ);
|
knownGlobals.push(DTRACE_NET_SOCKET_READ);
|
||||||
knownGlobals.push(DTRACE_NET_SOCKET_WRITE);
|
knownGlobals.push(DTRACE_NET_SOCKET_WRITE);
|
||||||
}
|
}
|
||||||
|
if (global.COUNTER_NET_SERVER_CONNECTION) {
|
||||||
|
knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
|
||||||
|
knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
|
||||||
|
knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
|
||||||
|
knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
|
||||||
|
knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
|
||||||
|
knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
if (global.ArrayBuffer) {
|
if (global.ArrayBuffer) {
|
||||||
knownGlobals.push(ArrayBuffer);
|
knownGlobals.push(ArrayBuffer);
|
||||||
|
@ -266,13 +266,17 @@ def JS2C(source, target):
|
|||||||
# Locate the macros file name.
|
# Locate the macros file name.
|
||||||
consts = {}
|
consts = {}
|
||||||
macros = {}
|
macros = {}
|
||||||
|
macro_lines = []
|
||||||
|
|
||||||
for s in source:
|
for s in source:
|
||||||
if 'macros.py' == (os.path.split(str(s))[1]):
|
if (os.path.split(str(s))[1]).endswith('macros.py'):
|
||||||
(consts, macros) = ReadMacros(ReadLines(str(s)))
|
macro_lines.extend(ReadLines(str(s)))
|
||||||
else:
|
else:
|
||||||
modules.append(s)
|
modules.append(s)
|
||||||
|
|
||||||
|
# Process input from all *macro.py files
|
||||||
|
(consts, macros) = ReadMacros(macro_lines)
|
||||||
|
|
||||||
# Build source code lines
|
# Build source code lines
|
||||||
source_lines = [ ]
|
source_lines = [ ]
|
||||||
source_lines_empty = []
|
source_lines_empty = []
|
||||||
|
@ -16,22 +16,22 @@
|
|||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFilesFolder</DefineConstants>
|
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NoPerfCtr=$(NoPerfCtr);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFilesFolder</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFilesFolder</DefineConstants>
|
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NoPerfCtr=$(NoPerfCtr);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFilesFolder</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||||
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFiles64Folder</DefineConstants>
|
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NoPerfCtr=$(NoPerfCtr);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFiles64Folder</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||||
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
<OutputPath>..\..\..\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFiles64Folder</DefineConstants>
|
<DefineConstants>Debug;ProductVersion=$(NodeVersion);NoETW=$(NoETW);NoPerfCtr=$(NoPerfCtr);NPMSourceDir=..\..\..\deps\npm\;ProgramFilesFolderId=ProgramFiles64Folder</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="product.wxs" />
|
<Compile Include="product.wxs" />
|
||||||
|
@ -48,6 +48,11 @@
|
|||||||
<util:EventManifest MessageFile="[APPLICATIONROOTDIRECTORY]node.exe" ResourceFile="[APPLICATIONROOTDIRECTORY]node.exe"/>
|
<util:EventManifest MessageFile="[APPLICATIONROOTDIRECTORY]node.exe" ResourceFile="[APPLICATIONROOTDIRECTORY]node.exe"/>
|
||||||
</File>
|
</File>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
<?if $(var.NoPerfCtr) != 1 ?>
|
||||||
|
<File Id="node_perfctr_provider_man" Name="node_perfctr_provider.man" Source="$(var.RepoDir)\src\res\node_perfctr_provider.man" >
|
||||||
|
<util:PerfCounterManifest ResourceFileDirectory="[APPLICATIONROOTDIRECTORY]"/>
|
||||||
|
</File>
|
||||||
|
<?endif?>
|
||||||
<Environment Id="npm_env"
|
<Environment Id="npm_env"
|
||||||
Action="set"
|
Action="set"
|
||||||
Name="PATH"
|
Name="PATH"
|
||||||
|
@ -32,6 +32,9 @@ set buildnodeweak=
|
|||||||
set noetw=
|
set noetw=
|
||||||
set noetw_arg=
|
set noetw_arg=
|
||||||
set noetw_msi_arg=
|
set noetw_msi_arg=
|
||||||
|
set noperfctr=
|
||||||
|
set noperfctr_arg=
|
||||||
|
set noperfctr_msi_arg=
|
||||||
|
|
||||||
:next-arg
|
:next-arg
|
||||||
if "%1"=="" goto args-done
|
if "%1"=="" goto args-done
|
||||||
@ -46,6 +49,7 @@ if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
|
|||||||
if /i "%1"=="nosign" set nosign=1&goto arg-ok
|
if /i "%1"=="nosign" set nosign=1&goto arg-ok
|
||||||
if /i "%1"=="nosnapshot" set nosnapshot=1&goto arg-ok
|
if /i "%1"=="nosnapshot" set nosnapshot=1&goto arg-ok
|
||||||
if /i "%1"=="noetw" set noetw=1&goto arg-ok
|
if /i "%1"=="noetw" set noetw=1&goto arg-ok
|
||||||
|
if /i "%1"=="noperfctr" set noperfctr=1&goto arg-ok
|
||||||
if /i "%1"=="licensertf" set licensertf=1&goto arg-ok
|
if /i "%1"=="licensertf" set licensertf=1&goto arg-ok
|
||||||
if /i "%1"=="test-uv" set test=test-uv&goto arg-ok
|
if /i "%1"=="test-uv" set test=test-uv&goto arg-ok
|
||||||
if /i "%1"=="test-internet" set test=test-internet&goto arg-ok
|
if /i "%1"=="test-internet" set test=test-internet&goto arg-ok
|
||||||
@ -74,13 +78,14 @@ if "%config%"=="Debug" set debug_arg=--debug
|
|||||||
if "%target_arch%"=="x64" set msiplatform=x64
|
if "%target_arch%"=="x64" set msiplatform=x64
|
||||||
if defined nosnapshot set nosnapshot_arg=--without-snapshot
|
if defined nosnapshot set nosnapshot_arg=--without-snapshot
|
||||||
if defined noetw set noetw_arg=--without-etw& set noetw_msi_arg=/p:NoETW=1
|
if defined noetw set noetw_arg=--without-etw& set noetw_msi_arg=/p:NoETW=1
|
||||||
|
if defined noperfctr set noperfctr_arg=--without-perfctr& set noperfctr_msi_arg=/p:NoPerfCtr=1
|
||||||
|
|
||||||
:project-gen
|
:project-gen
|
||||||
@rem Skip project generation if requested.
|
@rem Skip project generation if requested.
|
||||||
if defined noprojgen goto msbuild
|
if defined noprojgen goto msbuild
|
||||||
|
|
||||||
@rem Generate the VS project.
|
@rem Generate the VS project.
|
||||||
python configure %debug_arg% %nosnapshot_arg% %noetw_arg% --dest-cpu=%target_arch%
|
python configure %debug_arg% %nosnapshot_arg% %noetw_arg% %noperfctr_arg% --dest-cpu=%target_arch%
|
||||||
if errorlevel 1 goto create-msvs-files-failed
|
if errorlevel 1 goto create-msvs-files-failed
|
||||||
if not exist node.sln goto create-msvs-files-failed
|
if not exist node.sln goto create-msvs-files-failed
|
||||||
echo Project files generated.
|
echo Project files generated.
|
||||||
@ -125,7 +130,7 @@ if not defined msi goto run
|
|||||||
python "%~dp0tools\getnodeversion.py" > "%temp%\node_version.txt"
|
python "%~dp0tools\getnodeversion.py" > "%temp%\node_version.txt"
|
||||||
if not errorlevel 0 echo Cannot determine current version of node.js & goto exit
|
if not errorlevel 0 echo Cannot determine current version of node.js & goto exit
|
||||||
for /F "tokens=*" %%i in (%temp%\node_version.txt) do set NODE_VERSION=%%i
|
for /F "tokens=*" %%i in (%temp%\node_version.txt) do set NODE_VERSION=%%i
|
||||||
msbuild "%~dp0tools\msvs\msi\nodemsi.sln" /m /t:Clean,Build /p:Configuration=%config% /p:Platform=%msiplatform% /p:NodeVersion=%NODE_VERSION% %noetw_msi_arg% /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo
|
msbuild "%~dp0tools\msvs\msi\nodemsi.sln" /m /t:Clean,Build /p:Configuration=%config% /p:Platform=%msiplatform% /p:NodeVersion=%NODE_VERSION% %noetw_msi_arg% %noperfctr_msi_arg% /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo
|
||||||
if errorlevel 1 goto exit
|
if errorlevel 1 goto exit
|
||||||
|
|
||||||
if defined nosign goto run
|
if defined nosign goto run
|
||||||
|
Loading…
x
Reference in New Issue
Block a user