From f657ce685dddc1bf2d5b42f56d728df9176cceb9 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Wed, 21 Nov 2012 00:27:22 +0100 Subject: windows: add tracing with performance counters Patch by Henry Rawas and Scott Blomquist. --- src/node.cc | 7 + src/node_counters.cc | 149 ++++++++++++++++ src/node_counters.h | 53 ++++++ src/node_win32_perfctr_provider.cc | 338 +++++++++++++++++++++++++++++++++++++ src/node_win32_perfctr_provider.h | 55 ++++++ src/perfctr_macros.py | 9 + src/res/node_perfctr_provider.man | 97 +++++++++++ src/stream_wrap.cc | 19 +++ 8 files changed, 727 insertions(+) create mode 100644 src/node_counters.cc create mode 100644 src/node_counters.h create mode 100644 src/node_win32_perfctr_provider.cc create mode 100644 src/node_win32_perfctr_provider.h create mode 100644 src/perfctr_macros.py create mode 100644 src/res/node_perfctr_provider.man (limited to 'src') 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 #include @@ -2314,6 +2317,10 @@ void Load(Handle 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 + + +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::Cast(obj->Get(String::New(#member))); + + +Handle COUNTER_NET_SERVER_CONNECTION(const Arguments& args) { + NODE_COUNT_SERVER_CONN_OPEN(); + return Undefined(); +} + + +Handle COUNTER_NET_SERVER_CONNECTION_CLOSE(const Arguments& args) { + NODE_COUNT_SERVER_CONN_CLOSE(); + return Undefined(); +} + + +Handle COUNTER_HTTP_SERVER_REQUEST(const Arguments& args) { + NODE_COUNT_HTTP_SERVER_REQUEST(); + return Undefined(); +} + + +Handle COUNTER_HTTP_SERVER_RESPONSE(const Arguments& args) { + NODE_COUNT_HTTP_SERVER_RESPONSE(); + return Undefined(); +} + + +Handle COUNTER_HTTP_CLIENT_REQUEST(const Arguments& args) { + NODE_COUNT_HTTP_CLIENT_REQUEST(); + return Undefined(); +} + + +Handle 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((gcperiod * 100) / totalperiod); + + NODE_COUNT_GC_PERCENTTIME(percent); + counter_gc_end_time = endgc; + } + } + + return; +} + + +#define NODE_PROBE(name) #name, name + +void InitPerfCounters(Handle target) { + HandleScope scope; + + static struct { + const char* name; + Handle (*func)(const Arguments&); + Persistent 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::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 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 target); +void TermPerfCounters(v8::Handle 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 +#include "node_win32_perfctr_provider.h" + +#define __INIT_node_perfctr_provider_IMP +#include + +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(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(bytes)); + } +} + + +uint64_t NODE_COUNT_GET_GC_RAWTIME() { + LARGE_INTEGER timegc; + if (QueryPerformanceCounter(&timegc)) { + return timegc.QuadPart; + } else { + return static_cast(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(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(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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 // abort() #include // 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 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 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_); } } -- cgit v1.2.3