From bd9fa2e8419dda3ecff55ca7d801af3db4aeb5b2 Mon Sep 17 00:00:00 2001 From: mrb Date: Wed, 11 Jan 2012 23:42:24 -0500 Subject: [PATCH] dgram: use slab memory allocator Change udp memory allocation scheme from uv_buf_init to slab allocation. Takes slab allocation scheme from stream_wrap. --- src/udp_wrap.cc | 68 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 741e4ed46..aa5160ceb 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -59,10 +59,14 @@ namespace node { return scope.Close(Integer::New(-1)); \ } +#define SLAB_SIZE (1024 * 1024) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + // TODO share with tcp_wrap.cc Persistent address_symbol; Persistent port_symbol; Persistent buffer_sym; +static Persistent udp_slab_sym; void AddressToJS(Handle info, const sockaddr* addr, @@ -70,6 +74,12 @@ void AddressToJS(Handle info, typedef ReqWrap SendWrap; + +static size_t slab_used; +size_t slab_offset_; +static uv_handle_t* handle_that_last_alloced; + + class UDPWrap: public HandleWrap { public: static void Initialize(Handle target); @@ -83,6 +93,8 @@ public: static Handle GetSockName(const Arguments& args); private: + static inline char* NewSlab(v8::Handle global, v8::Handle wrap_obj); + UDPWrap(Handle object); virtual ~UDPWrap(); @@ -118,6 +130,7 @@ void UDPWrap::Initialize(Handle target) { HandleScope scope; + udp_slab_sym = Persistent::New(String::NewSymbol("udpslab")); buffer_sym = NODE_PSYMBOL("buffer"); port_symbol = NODE_PSYMBOL("port"); address_symbol = NODE_PSYMBOL("address"); @@ -149,7 +162,6 @@ Handle UDPWrap::New(const Arguments& args) { return scope.Close(args.This()); } - Handle UDPWrap::DoBind(const Arguments& args, int family) { HandleScope scope; int r; @@ -332,13 +344,44 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) { uv_buf_t UDPWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) { - // FIXME switch to slab allocation, share with stream_wrap.cc - return uv_buf_init(new char[suggested_size], suggested_size); -} + HandleScope scope; + UDPWrap* wrap = static_cast(handle->data); + + char* slab = NULL; + + Handle global = Context::GetCurrent()->Global(); + Local slab_v = global->GetHiddenValue(udp_slab_sym); + + if (slab_v.IsEmpty()) { + // No slab currently. Create a new one. + slab = NewSlab(global, wrap->object_); + } else { + // Use existing slab. + Local slab_obj = slab_v->ToObject(); + slab = Buffer::Data(slab_obj); + assert(Buffer::Length(slab_obj) == SLAB_SIZE); + assert(SLAB_SIZE >= slab_used); + + // If less than 64kb is remaining on the slab allocate a new one. + if (SLAB_SIZE - slab_used < 64 * 1024) { + slab = NewSlab(global, wrap->object_); + } else { + wrap->object_->SetHiddenValue(udp_slab_sym, slab_obj); + } + } + + uv_buf_t buf; + buf.base = slab + slab_used; + buf.len = MIN(SLAB_SIZE - slab_used, suggested_size); + + slab_offset_ = slab_used; + slab_used += buf.len; + + handle_that_last_alloced = reinterpret_cast(handle); + + return buf; -static void ReleaseMemory(char* data, void* arg) { - delete[] data; // data == buf.base } @@ -348,7 +391,6 @@ void UDPWrap::OnRecv(uv_udp_t* handle, struct sockaddr* addr, unsigned flags) { if (nread == 0) { - ReleaseMemory(buf.base, NULL); return; } @@ -365,18 +407,26 @@ void UDPWrap::OnRecv(uv_udp_t* handle, if (nread == -1) { SetErrno(uv_last_error(uv_default_loop())); - ReleaseMemory(buf.base, NULL); } else { Local rinfo = Object::New(); AddressToJS(rinfo, addr, sizeof *addr); - argv[2] = Buffer::New(buf.base, nread, ReleaseMemory, NULL)->handle_; + argv[2] = Buffer::New(buf.base, nread, NULL, NULL)->handle_; argv[3] = rinfo; } MakeCallback(wrap->object_, "onmessage", ARRAY_SIZE(argv), argv); } +inline char* UDPWrap::NewSlab(Handle global, + Handle wrap_obj) { + Buffer* b = Buffer::New(SLAB_SIZE); + global->SetHiddenValue(udp_slab_sym, b->handle_); + assert(Buffer::Length(b) == SLAB_SIZE); + slab_used = 0; + wrap_obj->SetHiddenValue(udp_slab_sym, b->handle_); + return Buffer::Data(b); +} void AddressToJS(Handle info, const sockaddr* addr,