You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2018/03/08 19:44:48 UTC

[trafficserver] branch master updated: jemalloc no dump allocator

This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 284fb4d  jemalloc no dump allocator
284fb4d is described below

commit 284fb4d56a1251cbec4a755472d2f1a9f4ac3ffe
Author: Fei Deng <du...@gmail.com>
AuthorDate: Wed Mar 7 13:38:06 2018 -0600

    jemalloc no dump allocator
---
 NOTICE                |   7 ++-
 lib/ts/JeAllocator.cc | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ts/JeAllocator.h  |  88 +++++++++++++++++++++++++++++
 lib/ts/Makefile.am    |   2 +
 lib/ts/ink_queue.cc   |  12 ++--
 5 files changed, 251 insertions(+), 7 deletions(-)

diff --git a/NOTICE b/NOTICE
index b08a298..60834a9 100644
--- a/NOTICE
+++ b/NOTICE
@@ -98,6 +98,11 @@ Copyright (c) <2008>, Sun Microsystems, Inc.  All rights reserved.
 
 ~~
 
-Reusable Gold Testing System  
+Reusable Gold Testing System
 https://bitbucket.org/dragon512/reusable-gold-testing-system
 Copyright (c) 2015-2016 Jason Kenny All Rights Reserved.
+
+~~
+
+Folly: Facebook Open-source Library
+https://github.com/facebook/folly
diff --git a/lib/ts/JeAllocator.cc b/lib/ts/JeAllocator.cc
new file mode 100644
index 0000000..3d60c8c
--- /dev/null
+++ b/lib/ts/JeAllocator.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <cstring>
+#include <cstdlib>
+#include <iostream>
+#include "ts/ink_memory.h"
+#include "ts/ink_error.h"
+#include "ts/ink_assert.h"
+#include "ts/ink_align.h"
+#include "ts/JeAllocator.h"
+
+namespace jearena
+{
+JemallocNodumpAllocator::JemallocNodumpAllocator()
+{
+  extend_and_setup_arena();
+}
+
+#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
+
+extent_hooks_t JemallocNodumpAllocator::extent_hooks_;
+extent_alloc_t *JemallocNodumpAllocator::original_alloc_ = nullptr;
+
+void *
+JemallocNodumpAllocator::alloc(extent_hooks_t *extent, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit,
+                               unsigned arena_ind)
+{
+  void *result = original_alloc_(extent, new_addr, size, alignment, zero, commit, arena_ind);
+
+  if (result != nullptr) {
+    // Seems like we don't really care if the advice went through
+    // in the original code, so just keeping it the same here.
+    ats_madvise((caddr_t)result, size, MADV_DONTDUMP);
+  }
+
+  return result;
+}
+
+#endif /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
+
+bool
+JemallocNodumpAllocator::extend_and_setup_arena()
+{
+#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
+  size_t arena_index_len_ = sizeof(arena_index_);
+  if (auto ret = mallctl("arenas.create", &arena_index_, &arena_index_len_, nullptr, 0)) {
+    ink_abort("Unable to extend arena: %s", std::strerror(ret));
+  }
+  flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE;
+
+  // Read the existing hooks
+  const auto key = "arena." + std::to_string(arena_index_) + ".extent_hooks";
+  extent_hooks_t *hooks;
+  size_t hooks_len = sizeof(hooks);
+  if (auto ret = mallctl(key.c_str(), &hooks, &hooks_len, nullptr, 0)) {
+    ink_abort("Unable to get the hooks: %s", std::strerror(ret));
+  }
+  if (original_alloc_ == nullptr) {
+    original_alloc_ = hooks->alloc;
+  } else {
+    ink_release_assert(original_alloc_ == hooks->alloc);
+  }
+
+  // Set the custom hook
+  extent_hooks_             = *hooks;
+  extent_hooks_.alloc       = &JemallocNodumpAllocator::alloc;
+  extent_hooks_t *new_hooks = &extent_hooks_;
+  if (auto ret = mallctl(key.c_str(), nullptr, nullptr, &new_hooks, sizeof(new_hooks))) {
+    ink_abort("Unable to set the hooks: %s", std::strerror(ret));
+  }
+
+  return true;
+#else  /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
+  return false;
+#endif /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
+}
+
+/**
+ * This will retain the orignal functionality if
+ * !defined(JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED)
+ */
+void *
+JemallocNodumpAllocator::allocate(InkFreeList *f)
+{
+  void *newp = nullptr;
+
+  if (f->advice) {
+#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
+    if (likely(f->type_size > 0)) {
+      int flags = flags_ | MALLOCX_ALIGN(f->alignment);
+      if (unlikely((newp = mallocx(f->type_size, flags)) == nullptr)) {
+        ink_abort("couldn't allocate %u bytes", f->type_size);
+      }
+    }
+#else
+    newp = ats_memalign(f->alignment, f->type_size);
+    if (INK_ALIGN((uint64_t)newp, ats_pagesize()) == (uint64_t)newp) {
+      ats_madvise((caddr_t)newp, INK_ALIGN(f->type_size, f->alignment), f->advice);
+    }
+#endif
+  } else {
+    newp = ats_memalign(f->alignment, f->type_size);
+  }
+  return newp;
+}
+
+/**
+ * This will retain the orignal functionality if
+ * !defined(JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED)
+ */
+void
+JemallocNodumpAllocator::deallocate(InkFreeList *f, void *ptr)
+{
+  if (f->advice) {
+#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
+    if (likely(ptr)) {
+      dallocx(ptr, flags_);
+    }
+#else
+    ats_memalign_free(ptr);
+#endif
+  } else {
+    ats_memalign_free(ptr);
+  }
+}
+
+JemallocNodumpAllocator &
+globalJemallocNodumpAllocator()
+{
+  static auto instance = new JemallocNodumpAllocator();
+  return *instance;
+}
+}
diff --git a/lib/ts/JeAllocator.h b/lib/ts/JeAllocator.h
new file mode 100644
index 0000000..d3539e8
--- /dev/null
+++ b/lib/ts/JeAllocator.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// https://github.com/jemalloc/jemalloc/releases
+// Requires jemalloc 5.0.0 or above.
+
+#ifndef _jeallocator_h_
+#define _jeallocator_h_
+
+#include "ts/ink_config.h"
+#include "ts/ink_queue.h"
+#include <sys/mman.h>
+#include <cstddef>
+
+#if TS_HAS_JEMALLOC
+#include <jemalloc/jemalloc.h>
+#if (JEMALLOC_VERSION_MAJOR == 5) && defined(MADV_DONTDUMP)
+#define JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED 1
+#endif /* MADV_DONTDUMP */
+#endif /* TS_HAS_JEMALLOC */
+
+namespace jearena
+{
+/**
+ * An allocator which uses Jemalloc to create an dedicated arena to allocate
+ * memory from. The only special property set on the allocated memory is that
+ * the memory is not dump-able.
+ *
+ * This is done by setting MADV_DONTDUMP using the `madvise` system call. A
+ * custom hook installed which is called when allocating a new chunk / extent of
+ * memory.  All it does is call the original jemalloc hook to allocate the
+ * memory and then set the advise on it before returning the pointer to the
+ * allocated memory. Jemalloc does not use allocated chunks / extents across
+ * different arenas, without `munmap`-ing them first, and the advises are not
+ * sticky i.e. they are unset if `munmap` is done. Also this arena can't be used
+ * by any other part of the code by just calling `malloc`.
+ *
+ * If target system doesn't support MADV_DONTDUMP or jemalloc doesn't support
+ * custom arena hook, JemallocNodumpAllocator would fall back to using malloc /
+ * free. Such behavior can be identified by using
+ * !defined(JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED).
+ *
+ * Similarly, if binary isn't linked with jemalloc, the logic would fall back to
+ * malloc / free.
+ */
+class JemallocNodumpAllocator
+{
+public:
+  explicit JemallocNodumpAllocator();
+
+  void *allocate(InkFreeList *f);
+  void deallocate(InkFreeList *f, void *ptr);
+
+private:
+#if JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
+  static extent_hooks_t extent_hooks_;
+  static extent_alloc_t *original_alloc_;
+  static void *alloc(extent_hooks_t *extent, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit,
+                     unsigned arena_ind);
+
+  unsigned arena_index_{0};
+  int flags_{0};
+#endif /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
+
+  bool extend_and_setup_arena();
+};
+
+/**
+ * JemallocNodumpAllocator singleton.
+ */
+JemallocNodumpAllocator &globalJemallocNodumpAllocator();
+
+} /* namespace jearena */
+
+#endif /* _jeallocator_h_ */
diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index 6faa377..7175ac8 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -161,6 +161,8 @@ libtsutil_la_SOURCES = \
   IpMapConf.h \
   IpMap.h \
   I_Version.h \
+  JeAllocator.h \
+  JeAllocator.cc \
   Layout.cc \
   List.h \
   llqueue.cc \
diff --git a/lib/ts/ink_queue.cc b/lib/ts/ink_queue.cc
index b6606ec..88a8240 100644
--- a/lib/ts/ink_queue.cc
+++ b/lib/ts/ink_queue.cc
@@ -51,6 +51,7 @@
 #include "ts/ink_align.h"
 #include "ts/hugepages.h"
 #include "ts/Diags.h"
+#include "ts/JeAllocator.h"
 
 #define DEBUG_TAG "freelist"
 
@@ -65,6 +66,8 @@
 #define DEADBEEF
 #endif
 
+static auto jna = jearena::globalJemallocNodumpAllocator();
+
 struct ink_freelist_ops {
   void *(*fl_new)(InkFreeList *);
   void (*fl_free)(InkFreeList *, void *);
@@ -258,10 +261,7 @@ malloc_new(InkFreeList *f)
   void *newp = nullptr;
 
   if (f->alignment) {
-    newp = ats_memalign(f->alignment, f->type_size);
-    if (f->advice && (INK_ALIGN((uint64_t)newp, ats_pagesize()) == (uint64_t)newp)) {
-      ats_madvise((caddr_t)newp, INK_ALIGN(f->type_size, f->alignment), f->advice);
-    }
+    newp = jna.allocate(f);
   } else {
     newp = ats_malloc(f->type_size);
   }
@@ -320,7 +320,7 @@ static void
 malloc_free(InkFreeList *f, void *item)
 {
   if (f->alignment) {
-    ats_memalign_free(item);
+    jna.deallocate(f, item);
   } else {
     ats_free(item);
   }
@@ -389,7 +389,7 @@ malloc_bulkfree(InkFreeList *f, void *head, void *tail, size_t num_item)
   if (f->alignment) {
     for (size_t i = 0; i < num_item && item; ++i, item = next) {
       next = *(void **)item; // find next item before freeing current item
-      ats_memalign_free(item);
+      jna.deallocate(f, item);
     }
   } else {
     for (size_t i = 0; i < num_item && item; ++i, item = next) {

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.