[libc-commits] [libc] [libc] Use best-fit binary trie to make malloc logarithmic (PR #106259)
Daniel Thornburgh via libc-commits
libc-commits at lists.llvm.org
Thu Nov 14 11:57:57 PST 2024
================
@@ -0,0 +1,237 @@
+//===-- Interface for freetrie --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
+#define LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
+
+#include "freelist.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+/// A trie of free lists.
+///
+/// This is an unusual little data structure originally from Doug Lea's malloc.
+/// Finding the best fit from a set of differently-sized free list typically
+/// required some kind of ordered map, and these are typically implemented using
+/// a self-balancing binary search tree. Those are notorious for having a
+/// relatively large number of special cases, while this trie has relatively
+/// few, which helps with code size.
+///
+/// Operations on the trie are logarithmic not on the number of nodes within it,
+/// but rather the fixed range of possible sizes that the trie can contain. This
+/// means that the data structure would likely actually perform worse than an
+/// e.g. red-black tree, but its implementation is still much simpler.
+///
+/// Each trie node's children subdivide the range of possible sizes into two
+/// halves: a lower and an upper. The node itself holds a free list of some size
+/// within its range. This makes it possible to summarily replace any node with
+/// any leaf within its subtrie, which makes it very straightforward to remove a
+/// node. Insertion is also simple; the only real complexity lies with finding
+/// the best fit. This can still be done in logarithmic time with only a few
+/// cases to consider.
+///
+/// The trie refers to, but does not own, the Nodes that comprise it.
+class FreeTrie {
+public:
+ /// A trie node that is also a free list. Only the head node of each list is
+ /// actually part of the trie. The subtrie contains a continous SizeRange of
+ /// free lists. The lower and upper subtrie's contain the lower and upper half
+ /// of the subtries range. There is no direct relationship between the size of
+ /// this node's free list and the contents of the lower and upper subtries.
+ class Node : public FreeList::Node {
+ /// The child subtrie covering the lower half of this subtrie's size range.
+ /// Undefined if this is not the head of the list.
+ Node *lower;
+ /// The child subtrie covering the upper half of this subtrie's size range.
+ /// Undefined if this is not the head of the list.
+ Node *upper;
+ /// The parent subtrie. nullptr if this is the root or not the head of the
+ /// list.
+ Node *parent;
+
+ friend class FreeTrie;
+ };
+
+ /// Power-of-two range of sizes covered by a subtrie.
+ struct SizeRange {
+ size_t min;
+ size_t width;
+
+ LIBC_INLINE constexpr SizeRange(size_t min, size_t width)
+ : min(min), width(width) {
+ LIBC_ASSERT(!(width & (width - 1)) && "width must be a power of two");
+ }
+
+ /// @returns The lower half of the size range.
+ LIBC_INLINE SizeRange lower() const { return {min, width / 2}; }
+
+ /// @returns The lower half of the size range.
----------------
mysterymath wrote:
Done, thanks.
https://github.com/llvm/llvm-project/pull/106259
More information about the libc-commits
mailing list