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.