dgram: use slab memory allocator
authormrb <michaelrbernstein@gmail.com>
Thu, 12 Jan 2012 04:42:24 +0000 (23:42 -0500)
committerBen Noordhuis <info@bnoordhuis.nl>
Thu, 12 Jan 2012 16:34:15 +0000 (17:34 +0100)
Change udp memory allocation scheme from uv_buf_init to slab allocation. Takes
slab allocation scheme from stream_wrap.

src/udp_wrap.cc

index 741e4ed..aa5160c 100644 (file)
@@ -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<String> address_symbol;
 Persistent<String> port_symbol;
 Persistent<String> buffer_sym;
+static Persistent<String> udp_slab_sym;
 
 void AddressToJS(Handle<Object> info,
                  const sockaddr* addr,
@@ -70,6 +74,12 @@ void AddressToJS(Handle<Object> info,
 
 typedef ReqWrap<uv_udp_send_t> 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<Object> target);
@@ -83,6 +93,8 @@ public:
   static Handle<Value> GetSockName(const Arguments& args);
 
 private:
+  static inline char* NewSlab(v8::Handle<v8::Object> global, v8::Handle<v8::Object> wrap_obj);
+
   UDPWrap(Handle<Object> object);
   virtual ~UDPWrap();
 
@@ -118,6 +130,7 @@ void UDPWrap::Initialize(Handle<Object> target) {
 
   HandleScope scope;
 
+  udp_slab_sym = Persistent<String>::New(String::NewSymbol("udpslab"));
   buffer_sym = NODE_PSYMBOL("buffer");
   port_symbol = NODE_PSYMBOL("port");
   address_symbol = NODE_PSYMBOL("address");
@@ -149,7 +162,6 @@ Handle<Value> UDPWrap::New(const Arguments& args) {
   return scope.Close(args.This());
 }
 
-
 Handle<Value> 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<UDPWrap*>(handle->data);
+
+  char* slab = NULL;
+
+  Handle<Object> global = Context::GetCurrent()->Global();
+  Local<Value> 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<Object> 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<uv_handle_t*>(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<Object> 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<Object> global,
+                                        Handle<Object> 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<Object> info,
                  const sockaddr* addr,