diff options
author | Trevor Norris <trev.norris@gmail.com> | 2013-06-19 11:20:45 -0700 |
---|---|---|
committer | Trevor Norris <trev.norris@gmail.com> | 2013-07-03 14:56:27 -0700 |
commit | ec90e6e80adbb9c6f31158c319eba4e35edda845 (patch) | |
tree | b6fe6d19a44b22677b421c6f32f4fbc11ad2e8e5 /src | |
parent | c1db1ecd15fd796b68311c67288b395e7784defd (diff) | |
download | node-ec90e6e80adbb9c6f31158c319eba4e35edda845.tar.gz |
slab_allocator: remove SlabAllocator
Now that Buffer instantiation has improved, the SlabAllocator is an
unnecessary layer of complexity preventing further performance
optimizations.
Currently there is a small performance loss with very small stream
requests, but this will soon be addressed.
Diffstat (limited to 'src')
-rw-r--r-- | src/slab_allocator.cc | 127 | ||||
-rw-r--r-- | src/slab_allocator.h | 49 | ||||
-rw-r--r-- | src/stream_wrap.cc | 37 | ||||
-rw-r--r-- | src/stream_wrap.h | 3 | ||||
-rw-r--r-- | src/udp_wrap.cc | 39 |
5 files changed, 30 insertions, 225 deletions
diff --git a/src/slab_allocator.cc b/src/slab_allocator.cc deleted file mode 100644 index 1a98c8ecd..000000000 --- a/src/slab_allocator.cc +++ /dev/null @@ -1,127 +0,0 @@ -// 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 "v8.h" -#include "node.h" -#include "node_buffer.h" -#include "slab_allocator.h" -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - - -using v8::Handle; -using v8::HandleScope; -using v8::Integer; -using v8::Local; -using v8::Null; -using v8::Object; -using v8::Persistent; -using v8::String; -using v8::V8; -using v8::Value; - - -namespace node { - -SlabAllocator::SlabAllocator(unsigned int size) { - size_ = ROUND_UP(size ? size : 1, 8192); - initialized_ = false; -} - - -SlabAllocator::~SlabAllocator() { - if (!initialized_) return; - if (V8::IsDead()) return; - slab_sym_.Dispose(node_isolate); - slab_sym_.Clear(); - slab_.Dispose(node_isolate); - slab_.Clear(); -} - - -void SlabAllocator::Initialize() { - HandleScope scope(node_isolate); - char sym[256]; - snprintf(sym, sizeof(sym), "slab_%p", this); // namespace object key - offset_ = 0; - last_ptr_ = NULL; - initialized_ = true; - slab_sym_ = Persistent<String>::New(node_isolate, String::New(sym)); -} - - -static Local<Object> NewSlab(unsigned int size) { - HandleScope scope(node_isolate); - Local<Object> buf = Buffer::New(ROUND_UP(size, 16)); - return scope.Close(buf); -} - - -char* SlabAllocator::Allocate(Handle<Object> obj, unsigned int size) { - HandleScope scope(node_isolate); - - assert(!obj.IsEmpty()); - - if (size == 0) return NULL; - if (!initialized_) Initialize(); - - if (size > size_) { - Local<Object> buf = NewSlab(size); - obj->SetHiddenValue(slab_sym_, buf); - return Buffer::Data(buf); - } - - if (slab_.IsEmpty() || offset_ + size > size_) { - slab_.Dispose(node_isolate); - slab_.Clear(); - slab_ = Persistent<Object>::New(node_isolate, NewSlab(size_)); - offset_ = 0; - last_ptr_ = NULL; - } - - obj->SetHiddenValue(slab_sym_, slab_); - last_ptr_ = Buffer::Data(slab_) + offset_; - offset_ += size; - - return last_ptr_; -} - - -Local<Object> SlabAllocator::Shrink(Handle<Object> obj, - char* ptr, - unsigned int size) { - HandleScope scope(node_isolate); - Local<Value> slab_v = obj->GetHiddenValue(slab_sym_); - obj->SetHiddenValue(slab_sym_, Null(node_isolate)); - assert(!slab_v.IsEmpty()); - assert(slab_v->IsObject()); - Local<Object> slab = slab_v->ToObject(); - assert(ptr != NULL); - if (ptr == last_ptr_) { - last_ptr_ = NULL; - offset_ = ptr - Buffer::Data(slab) + ROUND_UP(size, 16); - } - return scope.Close(slab); -} - - -} // namespace node diff --git a/src/slab_allocator.h b/src/slab_allocator.h deleted file mode 100644 index 6440bd4a0..000000000 --- a/src/slab_allocator.h +++ /dev/null @@ -1,49 +0,0 @@ -// 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 "v8.h" - -namespace node { - -class SlabAllocator { -public: - SlabAllocator(unsigned int size = 10485760); // default to 10M - ~SlabAllocator(); - - // allocate memory from slab, attaches the slice to `obj` - char* Allocate(v8::Handle<v8::Object> obj, unsigned int size); - - // return excess memory to the slab, returns a handle to the parent buffer - v8::Local<v8::Object> Shrink(v8::Handle<v8::Object> obj, - char* ptr, - unsigned int size); - -private: - void Initialize(); - bool initialized_; - v8::Persistent<v8::Object> slab_; - v8::Persistent<v8::String> slab_sym_; - unsigned int offset_; - unsigned int size_; - char* last_ptr_; -}; - -} // namespace node diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index 886cf648e..9b33d62b5 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -22,7 +22,6 @@ #include "node.h" #include "node_buffer.h" #include "handle_wrap.h" -#include "slab_allocator.h" #include "stream_wrap.h" #include "pipe_wrap.h" #include "tcp_wrap.h" @@ -33,8 +32,6 @@ #include <stdlib.h> // abort() #include <limits.h> // INT_MAX -#define SLAB_SIZE (1024 * 1024) - namespace node { @@ -49,6 +46,7 @@ using v8::Number; using v8::Object; using v8::Persistent; using v8::String; +using v8::Uint32; using v8::Value; @@ -58,23 +56,13 @@ static Persistent<String> write_queue_size_sym; static Persistent<String> onread_sym; static Persistent<String> oncomplete_sym; static Persistent<String> handle_sym; -static SlabAllocator* slab_allocator; static bool initialized; -static void DeleteSlabAllocator(void*) { - delete slab_allocator; - slab_allocator = NULL; -} - - void StreamWrap::Initialize(Handle<Object> target) { if (initialized) return; initialized = true; - slab_allocator = new SlabAllocator(SLAB_SIZE); - AtExit(DeleteSlabAllocator, NULL); - HandleScope scope(node_isolate); HandleWrap::Initialize(target); @@ -592,8 +580,7 @@ void StreamWrapCallbacks::AfterWrite(WriteWrap* w) { uv_buf_t StreamWrapCallbacks::DoAlloc(uv_handle_t* handle, size_t suggested_size) { - char* buf = slab_allocator->Allocate(wrap_->object_, suggested_size); - return uv_buf_init(buf, suggested_size); + return uv_buf_init(new char[suggested_size], suggested_size); } @@ -604,26 +591,30 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle, HandleScope scope(node_isolate); if (nread < 0) { - // If libuv reports an error or EOF it *may* give us a buffer back. In that - // case, return the space to the slab. if (buf.base != NULL) - slab_allocator->Shrink(Self(), buf.base, 0); + delete[] buf.base; SetErrno(uv_last_error(uv_default_loop())); MakeCallback(Self(), onread_sym, 0, NULL); return; } - Local<Object> slab = slab_allocator->Shrink(wrap_->object_, buf.base, nread); + if (nread == 0) { + if (buf.base != NULL) + delete[] buf.base; + return; + } + + // TODO(trevnorris): not kosher to use new/delete w/ realloc + buf.base = static_cast<char*>(realloc(buf.base, nread)); - if (nread == 0) return; assert(static_cast<size_t>(nread) <= buf.len); int argc = 3; Local<Value> argv[4] = { - slab, - Integer::NewFromUnsigned(buf.base - Buffer::Data(slab), node_isolate), - Integer::NewFromUnsigned(nread, node_isolate) + Buffer::Use(buf.base, nread), + Uint32::New(0, node_isolate), + Uint32::New(nread, node_isolate) }; Local<Object> pending_obj; diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 6b73efd68..5ac725b4c 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -135,8 +135,6 @@ class StreamWrap : public HandleWrap { void UpdateWriteQueueSize(); private: - static inline char* NewSlab(v8::Handle<v8::Object> global, v8::Handle<v8::Object> wrap_obj); - // Callbacks for libuv static void AfterWrite(uv_write_t* req, int status); static uv_buf_t OnAlloc(uv_handle_t* handle, size_t suggested_size); @@ -151,7 +149,6 @@ class StreamWrap : public HandleWrap { template <enum encoding encoding> static v8::Handle<v8::Value> WriteStringImpl(const v8::Arguments& args); - size_t slab_offset_; uv_stream_t* stream_; StreamWrapCallbacks default_callbacks_; diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index b463a75c8..db759e6ed 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -21,15 +21,12 @@ #include "node.h" #include "node_buffer.h" -#include "slab_allocator.h" #include "req_wrap.h" #include "handle_wrap.h" #include "udp_wrap.h" #include <stdlib.h> -#define SLAB_SIZE (1024 * 1024) - namespace node { @@ -45,6 +42,7 @@ using v8::Object; using v8::Persistent; using v8::PropertyAttribute; using v8::String; +using v8::Uint32; using v8::Value; typedef ReqWrap<uv_udp_send_t> SendWrap; @@ -56,13 +54,6 @@ static Persistent<Function> constructor; static Persistent<String> buffer_sym; static Persistent<String> oncomplete_sym; static Persistent<String> onmessage_sym; -static SlabAllocator* slab_allocator; - - -static void DeleteSlabAllocator(void*) { - delete slab_allocator; - slab_allocator = NULL; -} UDPWrap::UDPWrap(Handle<Object> object) @@ -79,9 +70,6 @@ UDPWrap::~UDPWrap() { void UDPWrap::Initialize(Handle<Object> target) { HandleWrap::Initialize(target); - slab_allocator = new SlabAllocator(SLAB_SIZE); - AtExit(DeleteSlabAllocator, NULL); - HandleScope scope(node_isolate); buffer_sym = NODE_PSYMBOL("buffer"); @@ -383,9 +371,7 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) { uv_buf_t UDPWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) { - UDPWrap* wrap = static_cast<UDPWrap*>(handle->data); - char* buf = slab_allocator->Allocate(wrap->object_, suggested_size); - return uv_buf_init(buf, suggested_size); + return uv_buf_init(new char[suggested_size], suggested_size); } @@ -397,23 +383,30 @@ void UDPWrap::OnRecv(uv_udp_t* handle, HandleScope scope(node_isolate); UDPWrap* wrap = reinterpret_cast<UDPWrap*>(handle->data); - Local<Object> slab = slab_allocator->Shrink(wrap->object_, - buf.base, - nread < 0 ? 0 : nread); - if (nread == 0) return; if (nread < 0) { + if (buf.base != NULL) + delete[] buf.base; Local<Value> argv[] = { Local<Object>::New(node_isolate, wrap->object_) }; SetErrno(uv_last_error(uv_default_loop())); MakeCallback(wrap->object_, onmessage_sym, ARRAY_SIZE(argv), argv); return; } + if (nread == 0) { + if (buf.base != NULL) + delete[] buf.base; + return; + } + + // TODO(trevnorris): not kosher to use new/delete w/ realloc + buf.base = static_cast<char*>(realloc(buf.base, nread)); + Local<Value> argv[] = { Local<Object>::New(node_isolate, wrap->object_), - slab, - Integer::NewFromUnsigned(buf.base - Buffer::Data(slab), node_isolate), - Integer::NewFromUnsigned(nread, node_isolate), + Buffer::Use(buf.base, nread), + Uint32::New(0, node_isolate), + Uint32::New(nread, node_isolate), AddressToJS(addr) }; MakeCallback(wrap->object_, onmessage_sym, ARRAY_SIZE(argv), argv); |