summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorScott Blomquist <sblom@microsoft.com>2012-11-21 00:27:22 +0100
committerBert Belder <bertbelder@gmail.com>2012-11-21 01:21:53 +0100
commitf657ce685dddc1bf2d5b42f56d728df9176cceb9 (patch)
treeff03ca0dcd8c3260257c9b8c9e842829e7372db8 /src
parentbc9388342f59ed5c69d69c7095e5a17fcbd80ba8 (diff)
downloadandroid-node-v8-f657ce685dddc1bf2d5b42f56d728df9176cceb9.tar.gz
android-node-v8-f657ce685dddc1bf2d5b42f56d728df9176cceb9.tar.bz2
android-node-v8-f657ce685dddc1bf2d5b42f56d728df9176cceb9.zip
windows: add tracing with performance counters
Patch by Henry Rawas and Scott Blomquist.
Diffstat (limited to 'src')
-rw-r--r--src/node.cc7
-rw-r--r--src/node_counters.cc149
-rw-r--r--src/node_counters.h53
-rw-r--r--src/node_win32_perfctr_provider.cc338
-rw-r--r--src/node_win32_perfctr_provider.h55
-rw-r--r--src/perfctr_macros.py9
-rw-r--r--src/res/node_perfctr_provider.man97
-rw-r--r--src/stream_wrap.cc19
8 files changed, 727 insertions, 0 deletions
diff --git a/src/node.cc b/src/node.cc
index 60cc19c4eb..c56e1494a8 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -30,6 +30,9 @@
#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
# include "node_dtrace.h"
#endif
+#if defined HAVE_PERFCTR
+# include "node_counters.h"
+#endif
#include <locale.h>
#include <signal.h>
@@ -2314,6 +2317,10 @@ void Load(Handle<Object> process_l) {
InitDTrace(global);
#endif
+#if defined HAVE_PERFCTR
+ InitPerfCounters(global);
+#endif
+
f->Call(global, 1, args);
if (try_catch.HasCaught()) {
diff --git a/src/node_counters.cc b/src/node_counters.cc
new file mode 100644
index 0000000000..3c8d49c00b
--- /dev/null
+++ b/src/node_counters.cc
@@ -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();
+}
+
+}
diff --git a/src/node_counters.h b/src/node_counters.h
new file mode 100644
index 0000000000..c55d99b909
--- /dev/null
+++ b/src/node_counters.h
@@ -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
diff --git a/src/node_win32_perfctr_provider.cc b/src/node_win32_perfctr_provider.cc
new file mode 100644
index 0000000000..8135726852
--- /dev/null
+++ b/src/node_win32_perfctr_provider.cc
@@ -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));
+ }
+}
+
+
+}
diff --git a/src/node_win32_perfctr_provider.h b/src/node_win32_perfctr_provider.h
new file mode 100644
index 0000000000..1b16a3fec8
--- /dev/null
+++ b/src/node_win32_perfctr_provider.h
@@ -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
+
diff --git a/src/perfctr_macros.py b/src/perfctr_macros.py
new file mode 100644
index 0000000000..2f7e3cbf82
--- /dev/null
+++ b/src/perfctr_macros.py
@@ -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) = ;
diff --git a/src/res/node_perfctr_provider.man b/src/res/node_perfctr_provider.man
new file mode 100644
index 0000000000..cd945ee5fb
--- /dev/null
+++ b/src/res/node_perfctr_provider.man
@@ -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>
diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc
index e79d212c43..825b65aa99 100644
--- a/src/stream_wrap.cc
+++ b/src/stream_wrap.cc
@@ -27,6 +27,7 @@
#include "pipe_wrap.h"
#include "tcp_wrap.h"
#include "req_wrap.h"
+#include "node_counters.h"
#include <stdlib.h> // abort()
#include <limits.h> // INT_MAX
@@ -226,6 +227,12 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
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);
}
@@ -285,6 +292,12 @@ Handle<Value> StreamWrap::WriteBuffer(const Arguments& args) {
delete[] storage;
return scope.Close(v8::Null());
} 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_);
}
}
@@ -418,6 +431,12 @@ Handle<Value> StreamWrap::WriteStringImpl(const Arguments& args) {
delete[] storage;
return scope.Close(v8::Null());
} 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_);
}
}