[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [UNIKRAFT PATCH 1/2] lib/ukallocregion: add region-based allocator



Hi Hugo,

thanks a lot for your work. I have few comments inline. If you address them I am happy to take the allocator upstream. Really useful...

Thanks,

Simon

On 27.07.20 16:21, Hugo Lefeuvre wrote:
Hi Simon,

it looks like region.c is missing an #include (inline).

I think the problem should be actually fixed within page.h header. I sent out a patch for this. The page.h header should not use undefined things and should actually be self-contained and include its dependencies.


We might want to fix this with a v2 after your review (or while
upstreaming).

regards,
Hugo

On Mon, 2020-06-22 at 16:23 +0200, Hugo Lefeuvre wrote:
Add ukallocregion, a minimalist region-based allocator.

Note that deallocation is not supported. This makes sense because
regions
only allow for deallocation at region-granularity. In our case, this
would
imply the freeing of the entire heap, which is generally not
possible.

Obviously, the lack of deallocation support makes ukallocregion a
fairly
bad general-purpose allocator. This allocator is interesting in that
it
offers maximum speed allocation and deallocation (bounded O(1), no
bookkeeping). It can be used as a baseline for measurements (e.g.,
boot
time) or as a first-level allocator in a nested context.

Refer to Gay & Aiken, `Memory management with explicit regions'
(PLDI'98)
for an introduction to region-based memory management.

Signed-off-by: Hugo Lefeuvre <hugo.lefeuvre@xxxxxxxxx>
---
  lib/Makefile.uk                            |   1 +
  lib/ukallocregion/Config.uk                |  13 +++
  lib/ukallocregion/Makefile.uk              |   6 +
  lib/ukallocregion/exportsyms.uk            |   1 +
  lib/ukallocregion/include/uk/allocregion.h |  49 +++++++++
  lib/ukallocregion/region.c                 | 169
+++++++++++++++++++++++++++++
  6 files changed, 239 insertions(+)
  create mode 100644 lib/ukallocregion/Config.uk
  create mode 100644 lib/ukallocregion/Makefile.uk
  create mode 100644 lib/ukallocregion/exportsyms.uk
  create mode 100644 lib/ukallocregion/include/uk/allocregion.h
  create mode 100644 lib/ukallocregion/region.c

diff --git a/lib/Makefile.uk b/lib/Makefile.uk
index aa7e730..1f223d2 100644
--- a/lib/Makefile.uk
+++ b/lib/Makefile.uk
@@ -14,6 +14,7 @@ $(eval $(call
_import_lib,$(CONFIG_UK_BASE)/lib/uktimeconv))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/nolibc))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukalloc))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukallocbbuddy))
+$(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukallocregion))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uksched))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukschedcoop))
  $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/fdt))
diff --git a/lib/ukallocregion/Config.uk
b/lib/ukallocregion/Config.uk
new file mode 100644
index 0000000..0bbc69f
--- /dev/null
+++ b/lib/ukallocregion/Config.uk
@@ -0,0 +1,13 @@
+config LIBUKALLOCREGION
+       bool "ukallocregion - Region-based allocator"

Use a ":" instead of a "-". This is to make it inline with the other menu items. I am going to do it while upstreaming.

+       default n
+       select LIBNOLIBC if !HAVE_LIBC
+       select LIBUKDEBUG
+       select LIBUKALLOC
+       help
+         Satisfy allocations as fast as possible, without
bookkeeping. No
+         support for free(): when the end of the allocation pool is
reached,
+         the allocator runs out-of-memory. This allocator is useful
for
+         experimentation, as baseline, or as first-level allocator
in a nested
+         context. Note that this allocator does not provide optimal
locality of
+         reference.

I think the last sentence can be removed. It probably confused more than it helps. bbuddy is also not considering locality and it somehow also depends how you allocator is initialized.

diff --git a/lib/ukallocregion/Makefile.uk
b/lib/ukallocregion/Makefile.uk
new file mode 100644
index 0000000..05a3d67
--- /dev/null
+++ b/lib/ukallocregion/Makefile.uk
@@ -0,0 +1,6 @@
+$(eval $(call addlib_s,libukallocregion,$(CONFIG_LIBUKALLOCREGION)))
+
+CINCLUDES-$(CONFIG_LIBUKALLOCREGION)   +=
-I$(LIBUKALLOCREGION_BASE)/include
+CXXINCLUDES-$(CONFIG_LIBUKALLOCREGION) +=
-I$(LIBUKALLOCREGION_BASE)/include
+
+LIBUKALLOCREGION_SRCS-y += $(LIBUKALLOCREGION_BASE)/region.c
diff --git a/lib/ukallocregion/exportsyms.uk
b/lib/ukallocregion/exportsyms.uk
new file mode 100644
index 0000000..481bc10
--- /dev/null
+++ b/lib/ukallocregion/exportsyms.uk
@@ -0,0 +1 @@
+uk_allocregion_init
diff --git a/lib/ukallocregion/include/uk/allocregion.h
b/lib/ukallocregion/include/uk/allocregion.h
new file mode 100644
index 0000000..1fc12db
--- /dev/null
+++ b/lib/ukallocregion/include/uk/allocregion.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Hugo Lefeuvre <hugo.lefeuvre@xxxxxxxxx>
+ *
+ * Copyright (c) 2020, NEC Europe Ltd., NEC Corporation. All rights
reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
without
+ * modification, are permitted provided that the following
conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
copyright
+ *    notice, this list of conditions and the following disclaimer
in the
+ *    documentation and/or other materials provided with the
distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products
derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LIBUKALLOCREGION_H__
+#define __LIBUKALLOCREGION_H__
+
+#include <uk/alloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* allocator initialization */
+struct uk_alloc *uk_allocregion_init(void *base, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBUKALLOCREGION_H__ */
diff --git a/lib/ukallocregion/region.c b/lib/ukallocregion/region.c
new file mode 100644
index 0000000..6760b4c
--- /dev/null
+++ b/lib/ukallocregion/region.c
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Hugo Lefeuvre <hugo.lefeuvre@xxxxxxxxx>
+ *
+ * Copyright (c) 2020, NEC Europe Ltd., NEC Corporation. All rights
reserved.

Oh... this is an old header. It should say "NEC Laboratories Europe GmbH" instead of "NEC Europe Ltd.". Please check all your headers.

+ *
+ * Redistribution and use in source and binary forms, with or
without
+ * modification, are permitted provided that the following
conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
copyright
+ *    notice, this list of conditions and the following disclaimer
in the
+ *    documentation and/or other materials provided with the
distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products
derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ukallocregion is a minimalist region implementation.
+ *
+ * Note that deallocation is not supported. This makes sense because
regions
+ * only allow for deallocation at region-granularity. In our case,
this would
+ * imply the freeing of the entire heap, which is generally not
possible.
+ *
+ * Obviously, the lack of deallocation support makes ukallocregion a
fairly bad
+ * general-purpose allocator. This allocator is interesting in that
it offers
+ * maximum speed allocation and deallocation (no bookkeeping). It
can be used as
+ * a baseline for measurements (e.g., boot time) or as a first-level
allocator
+ * in a nested context.
+ *
+ * Refer to Gay & Aiken, `Memory management with explicit regions'
(PLDI'98) for
+ * an introduction to region-based memory management.
+ */
+
+#include <uk/allocregion.h>
+#include <uk/alloc_impl.h>
+#include <uk/page.h>     // round_pgup()

checkpatch did not complain because of "//" comments? ;-)


#include <limits.h> is needed for __PAGE_SIZE.

+
+struct uk_allocregion {
+       void *heap_top;
+       void *heap_base;
+};
+
+void *uk_allocregion_malloc(struct uk_alloc *a, size_t size)
+{
+       struct uk_allocregion *b;
+       void *newbase, *prevbase;
+
+       UK_ASSERT(a != NULL);
+
+       b = (struct uk_allocregion *)&a->priv;
+
+       /* return aligned pointers: this is a requirement for some
+        * embedded systems archs, and more generally good for
performance
+        */
+       newbase  = (void *) ALIGN_UP(((uintptr_t) b->heap_base +
size),
+                                       (uintptr_t) sizeof(void *));
+       prevbase = b->heap_base;

Hum, I was thinking a while how to solve the problem that prevbase can be unaligned (e.g., first malloc call or malloc call after posix_memalign). First I thought, posix_memalign and allocregion_init need to be adopted to leave heap_base always aligned. But actually, the easier way is to align prevbase instead of newbase (similar to posix_memalign). This way all three behave the same: They will leave b->heap_base (not unaligned. What do you think?

+
+       UK_ASSERT(newbase >= b->heap_base);
+       UK_ASSERT(newbase <= b->heap_top);
+
+       b->heap_base = newbase;
+
+       return prevbase;
+}
+
+int uk_allocregion_posix_memalign(struct uk_alloc *a, void **memptr,
+                                       size_t align, size_t size)
+{
+       struct uk_allocregion *b;
+       uintptr_t intptr;
+
+       UK_ASSERT(a != NULL);
+
+       b = (struct uk_allocregion *)&a->priv;
+
+       /* align must be a power of two */
+       UK_ASSERT(((align - 1) & align) == 0);
+
+       /* align must be larger than pointer size */
+       UK_ASSERT((align % sizeof(void *)) == 0);
+
+       if (!size) {
+               *memptr = NULL;
+               return EINVAL;
+       }
+
+       intptr = ALIGN_UP((uintptr_t) b->heap_base, (uintptr_t)
align);
+
+       if (intptr > (uintptr_t) b->heap_top)
+               return ENOMEM; /* out-of-memory */
+
+       *memptr = (void *)intptr;
+       b->heap_base = (void *)(intptr + size);
+
+       return 0;
+}
+
+void uk_allocregion_free(struct uk_alloc *a __unused, void *ptr
__unused)
+{
+       uk_pr_debug("%p: Releasing of memory is not supported by "
+                       "ukallocregion\n", a);
+}
+
+int uk_allocregion_addmem(struct uk_alloc *a __unused, void *base
__unused,
+                               size_t size __unused)
+{
+       /* TODO: support multiple regions */
+       uk_pr_debug("%p: ukallocregion does not support multiple
memory "
+                       "regions\n", a);
+       return 0;
+}
+
+struct uk_alloc *uk_allocregion_init(void *base, size_t len)
+{
+       struct uk_alloc *a;
+       struct uk_allocregion *b;
+       size_t metalen = sizeof(*a) + sizeof(*b);
+
+       /* TODO: ukallocregion does not support multiple memory
regions yet.
+        * Because of the multiboot layout, the first region might
be a single
+        * page, so we simply ignore it.
+        */
+       if (len <= __PAGE_SIZE)
+               return NULL;
+
+       /* enough space for allocator available? */
+       if (metalen > len) {
+               uk_pr_err("Not enough space for allocator: %"__PRIsz
+                         " B required but only %"__PRIuptr" B
usable\n",
+                         metalen, len);
+               return NULL;
+       }
+
+       /* store allocator metadata on the heap, just before the
memory pool */
+       a = (struct uk_alloc *)base;
+       b = (struct uk_allocregion *)&a->priv;
+
+       uk_pr_info("Initialize allocregion allocator @ 0x%"
+                  __PRIuptr ", len %"__PRIsz"\n", (uintptr_t)a,
len);
+
+       b->heap_top  = (void *)((uintptr_t) base + len);
+       b->heap_base = (void *)((uintptr_t) base + metalen);
+
+       /* use exclusively "compat" wrappers for calloc, realloc,
memalign,
+        * palloc and pfree as those do not add additional metadata.
+        */
+       uk_alloc_init_malloc(a, uk_allocregion_malloc,
uk_calloc_compat,
+                               uk_realloc_compat,
uk_allocregion_free,
+                               uk_allocregion_posix_memalign,
+                               uk_memalign_compat, NULL);
+
+       return a;
+}



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.