| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Page heap. |
| // |
| // See malloc.go for the general overview. |
| // |
| // Allocation policy is the subject of this file. All free spans live in |
| // a treap for most of their time being free. See |
| // https://en.wikipedia.org/wiki/Treap or |
| // https://faculty.washington.edu/aragon/pubs/rst89.pdf for an overview. |
| // sema.go also holds an implementation of a treap. |
| // |
| // Each treapNode holds a single span. The treap is sorted by base address |
| // and each span necessarily has a unique base address. |
| // Spans are returned based on a first-fit algorithm, acquiring the span |
| // with the lowest base address which still satisfies the request. |
| // |
| // The first-fit algorithm is possible due to an augmentation of each |
| // treapNode to maintain the size of the largest span in the subtree rooted |
| // at that treapNode. Below we refer to this invariant as the maxPages |
| // invariant. |
| // |
| // The primary routines are |
| // insert: adds a span to the treap |
| // remove: removes the span from that treap that best fits the required size |
| // removeSpan: which removes a specific span from the treap |
| // |
| // Whenever a pointer to a span which is owned by the treap is acquired, that |
| // span must not be mutated. To mutate a span in the treap, remove it first. |
| // |
| // mheap_.lock must be held when manipulating this data structure. |
| |
| package runtime |
| |
| import ( |
| "unsafe" |
| ) |
| |
| //go:notinheap |
| type mTreap struct { |
| treap *treapNode |
| unscavHugePages uintptr // number of unscavenged huge pages in the treap |
| } |
| |
| //go:notinheap |
| type treapNode struct { |
| right *treapNode // all treapNodes > this treap node |
| left *treapNode // all treapNodes < this treap node |
| parent *treapNode // direct parent of this node, nil if root |
| key uintptr // base address of the span, used as primary sort key |
| span *mspan // span at base address key |
| maxPages uintptr // the maximum size of any span in this subtree, including the root |
| priority uint32 // random number used by treap algorithm to keep tree probabilistically balanced |
| types treapIterFilter // the types of spans available in this subtree |
| } |
| |
| // updateInvariants is a helper method which has a node recompute its own |
| // maxPages and types values by looking at its own span as well as the |
| // values of its direct children. |
| // |
| // Returns true if anything changed. |
| func (t *treapNode) updateInvariants() bool { |
| m, i := t.maxPages, t.types |
| t.maxPages = t.span.npages |
| t.types = t.span.treapFilter() |
| if t.left != nil { |
| t.types |= t.left.types |
| if t.maxPages < t.left.maxPages { |
| t.maxPages = t.left.maxPages |
| } |
| } |
| if t.right != nil { |
| t.types |= t.right.types |
| if t.maxPages < t.right.maxPages { |
| t.maxPages = t.right.maxPages |
| } |
| } |
| return m != t.maxPages || i != t.types |
| } |
| |
| // findMinimal finds the minimal (lowest base addressed) node in the treap |
| // which matches the criteria set out by the filter f and returns nil if |
| // none exists. |
| // |
| // This algorithm is functionally the same as (*mTreap).find, so see that |
| // method for more details. |
| func (t *treapNode) findMinimal(f treapIterFilter) *treapNode { |
| if t == nil || !f.matches(t.types) { |
| return nil |
| } |
| for t != nil { |
| if t.left != nil && f.matches(t.left.types) { |
| t = t.left |
| } else if f.matches(t.span.treapFilter()) { |
| break |
| } else if t.right != nil && f.matches(t.right.types) { |
| t = t.right |
| } else { |
| println("runtime: f=", f) |
| throw("failed to find minimal node matching filter") |
| } |
| } |
| return t |
| } |
| |
| // findMaximal finds the maximal (highest base addressed) node in the treap |
| // which matches the criteria set out by the filter f and returns nil if |
| // none exists. |
| // |
| // This algorithm is the logical inversion of findMinimal and just changes |
| // the order of the left and right tests. |
| func (t *treapNode) findMaximal(f treapIterFilter) *treapNode { |
| if t == nil || !f.matches(t.types) { |
| return nil |
| } |
| for t != nil { |
| if t.right != nil && f.matches(t.right.types) { |
| t = t.right |
| } else if f.matches(t.span.treapFilter()) { |
| break |
| } else if t.left != nil && f.matches(t.left.types) { |
| t = t.left |
| } else { |
| println("runtime: f=", f) |
| throw("failed to find minimal node matching filter") |
| } |
| } |
| return t |
| } |
| |
| // pred returns the predecessor of t in the treap subject to the criteria |
| // specified by the filter f. Returns nil if no such predecessor exists. |
| func (t *treapNode) pred(f treapIterFilter) *treapNode { |
| if t.left != nil && f.matches(t.left.types) { |
| // The node has a left subtree which contains at least one matching |
| // node, find the maximal matching node in that subtree. |
| return t.left.findMaximal(f) |
| } |
| // Lacking a left subtree, look to the parents. |
| p := t // previous node |
| t = t.parent |
| for t != nil { |
| // Walk up the tree until we find a node that has a left subtree |
| // that we haven't already visited. |
| if t.right == p { |
| if f.matches(t.span.treapFilter()) { |
| // If this node matches, then it's guaranteed to be the |
| // predecessor since everything to its left is strictly |
| // greater. |
| return t |
| } else if t.left != nil && f.matches(t.left.types) { |
| // Failing the root of this subtree, if its left subtree has |
| // something, that's where we'll find our predecessor. |
| return t.left.findMaximal(f) |
| } |
| } |
| p = t |
| t = t.parent |
| } |
| // If the parent is nil, then we've hit the root without finding |
| // a suitable left subtree containing the node (and the predecessor |
| // wasn't on the path). Thus, there's no predecessor, so just return |
| // nil. |
| return nil |
| } |
| |
| // succ returns the successor of t in the treap subject to the criteria |
| // specified by the filter f. Returns nil if no such successor exists. |
| func (t *treapNode) succ(f treapIterFilter) *treapNode { |
| // See pred. This method is just the logical inversion of it. |
| if t.right != nil && f.matches(t.right.types) { |
| return t.right.findMinimal(f) |
| } |
| p := t |
| t = t.parent |
| for t != nil { |
| if t.left == p { |
| if f.matches(t.span.treapFilter()) { |
| return t |
| } else if t.right != nil && f.matches(t.right.types) { |
| return t.right.findMinimal(f) |
| } |
| } |
| p = t |
| t = t.parent |
| } |
| return nil |
| } |
| |
| // isSpanInTreap is handy for debugging. One should hold the heap lock, usually |
| // mheap_.lock(). |
| func (t *treapNode) isSpanInTreap(s *mspan) bool { |
| if t == nil { |
| return false |
| } |
| return t.span == s || t.left.isSpanInTreap(s) || t.right.isSpanInTreap(s) |
| } |
| |
| // walkTreap is handy for debugging and testing. |
| // Starting at some treapnode t, for example the root, do a depth first preorder walk of |
| // the tree executing fn at each treap node. One should hold the heap lock, usually |
| // mheap_.lock(). |
| func (t *treapNode) walkTreap(fn func(tn *treapNode)) { |
| if t == nil { |
| return |
| } |
| fn(t) |
| t.left.walkTreap(fn) |
| t.right.walkTreap(fn) |
| } |
| |
| // checkTreapNode when used in conjunction with walkTreap can usually detect a |
| // poorly formed treap. |
| func checkTreapNode(t *treapNode) { |
| if t == nil { |
| return |
| } |
| if t.span.next != nil || t.span.prev != nil || t.span.list != nil { |
| throw("span may be on an mSpanList while simultaneously in the treap") |
| } |
| if t.span.base() != t.key { |
| println("runtime: checkTreapNode treapNode t=", t, " t.key=", t.key, |
| "t.span.base()=", t.span.base()) |
| throw("why does span.base() and treap.key do not match?") |
| } |
| if t.left != nil && t.key < t.left.key { |
| throw("found out-of-order spans in treap (left child has greater base address)") |
| } |
| if t.right != nil && t.key > t.right.key { |
| throw("found out-of-order spans in treap (right child has lesser base address)") |
| } |
| } |
| |
| // validateInvariants is handy for debugging and testing. |
| // It ensures that the various invariants on each treap node are |
| // appropriately maintained throughout the treap by walking the |
| // treap in a post-order manner. |
| func (t *treapNode) validateInvariants() (uintptr, treapIterFilter) { |
| if t == nil { |
| return 0, 0 |
| } |
| leftMax, leftTypes := t.left.validateInvariants() |
| rightMax, rightTypes := t.right.validateInvariants() |
| max := t.span.npages |
| if leftMax > max { |
| max = leftMax |
| } |
| if rightMax > max { |
| max = rightMax |
| } |
| if max != t.maxPages { |
| println("runtime: t.maxPages=", t.maxPages, "want=", max) |
| throw("maxPages invariant violated in treap") |
| } |
| typ := t.span.treapFilter() | leftTypes | rightTypes |
| if typ != t.types { |
| println("runtime: t.types=", t.types, "want=", typ) |
| throw("types invariant violated in treap") |
| } |
| return max, typ |
| } |
| |
| // treapIterType represents the type of iteration to perform |
| // over the treap. Each different flag is represented by a bit |
| // in the type, and types may be combined together by a bitwise |
| // or operation. |
| // |
| // Note that only 5 bits are available for treapIterType, do not |
| // use the 3 higher-order bits. This constraint is to allow for |
| // expansion into a treapIterFilter, which is a uint32. |
| type treapIterType uint8 |
| |
| const ( |
| treapIterScav treapIterType = 1 << iota // scavenged spans |
| treapIterHuge // spans containing at least one huge page |
| treapIterBits = iota |
| ) |
| |
| // treapIterFilter is a bitwise filter of different spans by binary |
| // properties. Each bit of a treapIterFilter represents a unique |
| // combination of bits set in a treapIterType, in other words, it |
| // represents the power set of a treapIterType. |
| // |
| // The purpose of this representation is to allow the existence of |
| // a specific span type to bubble up in the treap (see the types |
| // field on treapNode). |
| // |
| // More specifically, any treapIterType may be transformed into a |
| // treapIterFilter for a specific combination of flags via the |
| // following operation: 1 << (0x1f&treapIterType). |
| type treapIterFilter uint32 |
| |
| // treapFilterAll represents the filter which allows all spans. |
| const treapFilterAll = ^treapIterFilter(0) |
| |
| // treapFilter creates a new treapIterFilter from two treapIterTypes. |
| // mask represents a bitmask for which flags we should check against |
| // and match for the expected result after applying the mask. |
| func treapFilter(mask, match treapIterType) treapIterFilter { |
| allow := treapIterFilter(0) |
| for i := treapIterType(0); i < 1<<treapIterBits; i++ { |
| if mask&i == match { |
| allow |= 1 << i |
| } |
| } |
| return allow |
| } |
| |
| // matches returns true if m and f intersect. |
| func (f treapIterFilter) matches(m treapIterFilter) bool { |
| return f&m != 0 |
| } |
| |
| // treapFilter returns the treapIterFilter exactly matching this span, |
| // i.e. popcount(result) == 1. |
| func (s *mspan) treapFilter() treapIterFilter { |
| have := treapIterType(0) |
| if s.scavenged { |
| have |= treapIterScav |
| } |
| if s.hugePages() > 0 { |
| have |= treapIterHuge |
| } |
| return treapIterFilter(uint32(1) << (0x1f & have)) |
| } |
| |
| // treapIter is a bidirectional iterator type which may be used to iterate over a |
| // an mTreap in-order forwards (increasing order) or backwards (decreasing order). |
| // Its purpose is to hide details about the treap from users when trying to iterate |
| // over it. |
| // |
| // To create iterators over the treap, call start or end on an mTreap. |
| type treapIter struct { |
| f treapIterFilter |
| t *treapNode |
| } |
| |
| // span returns the span at the current position in the treap. |
| // If the treap is not valid, span will panic. |
| func (i *treapIter) span() *mspan { |
| return i.t.span |
| } |
| |
| // valid returns whether the iterator represents a valid position |
| // in the mTreap. |
| func (i *treapIter) valid() bool { |
| return i.t != nil |
| } |
| |
| // next moves the iterator forward by one. Once the iterator |
| // ceases to be valid, calling next will panic. |
| func (i treapIter) next() treapIter { |
| i.t = i.t.succ(i.f) |
| return i |
| } |
| |
| // prev moves the iterator backwards by one. Once the iterator |
| // ceases to be valid, calling prev will panic. |
| func (i treapIter) prev() treapIter { |
| i.t = i.t.pred(i.f) |
| return i |
| } |
| |
| // start returns an iterator which points to the start of the treap (the |
| // left-most node in the treap) subject to mask and match constraints. |
| func (root *mTreap) start(mask, match treapIterType) treapIter { |
| f := treapFilter(mask, match) |
| return treapIter{f, root.treap.findMinimal(f)} |
| } |
| |
| // end returns an iterator which points to the end of the treap (the |
| // right-most node in the treap) subject to mask and match constraints. |
| func (root *mTreap) end(mask, match treapIterType) treapIter { |
| f := treapFilter(mask, match) |
| return treapIter{f, root.treap.findMaximal(f)} |
| } |
| |
| // mutate allows one to mutate the span without removing it from the treap via a |
| // callback. The span's base and size are allowed to change as long as the span |
| // remains in the same order relative to its predecessor and successor. |
| // |
| // Note however that any operation that causes a treap rebalancing inside of fn |
| // is strictly forbidden, as that may cause treap node metadata to go |
| // out-of-sync. |
| func (root *mTreap) mutate(i treapIter, fn func(span *mspan)) { |
| s := i.span() |
| // Save some state about the span for later inspection. |
| hpages := s.hugePages() |
| scavenged := s.scavenged |
| // Call the mutator. |
| fn(s) |
| // Update unscavHugePages appropriately. |
| if !scavenged { |
| mheap_.free.unscavHugePages -= hpages |
| } |
| if !s.scavenged { |
| mheap_.free.unscavHugePages += s.hugePages() |
| } |
| // Update the key in case the base changed. |
| i.t.key = s.base() |
| // Updating invariants up the tree needs to happen if |
| // anything changed at all, so just go ahead and do it |
| // unconditionally. |
| // |
| // If it turns out nothing changed, it'll exit quickly. |
| t := i.t |
| for t != nil && t.updateInvariants() { |
| t = t.parent |
| } |
| } |
| |
| // insert adds span to the large span treap. |
| func (root *mTreap) insert(span *mspan) { |
| if !span.scavenged { |
| root.unscavHugePages += span.hugePages() |
| } |
| base := span.base() |
| var last *treapNode |
| pt := &root.treap |
| for t := *pt; t != nil; t = *pt { |
| last = t |
| if t.key < base { |
| pt = &t.right |
| } else if t.key > base { |
| pt = &t.left |
| } else { |
| throw("inserting span already in treap") |
| } |
| } |
| |
| // Add t as new leaf in tree of span size and unique addrs. |
| // The balanced tree is a treap using priority as the random heap priority. |
| // That is, it is a binary tree ordered according to the key, |
| // but then among the space of possible binary trees respecting those |
| // keys, it is kept balanced on average by maintaining a heap ordering |
| // on the priority: s.priority <= both s.right.priority and s.right.priority. |
| // https://en.wikipedia.org/wiki/Treap |
| // https://faculty.washington.edu/aragon/pubs/rst89.pdf |
| |
| t := (*treapNode)(mheap_.treapalloc.alloc()) |
| t.key = span.base() |
| t.priority = fastrand() |
| t.span = span |
| t.maxPages = span.npages |
| t.types = span.treapFilter() |
| t.parent = last |
| *pt = t // t now at a leaf. |
| |
| // Update the tree to maintain the various invariants. |
| i := t |
| for i.parent != nil && i.parent.updateInvariants() { |
| i = i.parent |
| } |
| |
| // Rotate up into tree according to priority. |
| for t.parent != nil && t.parent.priority > t.priority { |
| if t != nil && t.span.base() != t.key { |
| println("runtime: insert t=", t, "t.key=", t.key) |
| println("runtime: t.span=", t.span, "t.span.base()=", t.span.base()) |
| throw("span and treap node base addresses do not match") |
| } |
| if t.parent.left == t { |
| root.rotateRight(t.parent) |
| } else { |
| if t.parent.right != t { |
| throw("treap insert finds a broken treap") |
| } |
| root.rotateLeft(t.parent) |
| } |
| } |
| } |
| |
| func (root *mTreap) removeNode(t *treapNode) { |
| if !t.span.scavenged { |
| root.unscavHugePages -= t.span.hugePages() |
| } |
| if t.span.base() != t.key { |
| throw("span and treap node base addresses do not match") |
| } |
| // Rotate t down to be leaf of tree for removal, respecting priorities. |
| for t.right != nil || t.left != nil { |
| if t.right == nil || t.left != nil && t.left.priority < t.right.priority { |
| root.rotateRight(t) |
| } else { |
| root.rotateLeft(t) |
| } |
| } |
| // Remove t, now a leaf. |
| if t.parent != nil { |
| p := t.parent |
| if p.left == t { |
| p.left = nil |
| } else { |
| p.right = nil |
| } |
| // Walk up the tree updating invariants until no updates occur. |
| for p != nil && p.updateInvariants() { |
| p = p.parent |
| } |
| } else { |
| root.treap = nil |
| } |
| // Return the found treapNode's span after freeing the treapNode. |
| mheap_.treapalloc.free(unsafe.Pointer(t)) |
| } |
| |
| // find searches for, finds, and returns the treap iterator over all spans |
| // representing the position of the span with the smallest base address which is |
| // at least npages in size. If no span has at least npages it returns an invalid |
| // iterator. |
| // |
| // This algorithm is as follows: |
| // * If there's a left child and its subtree can satisfy this allocation, |
| // continue down that subtree. |
| // * If there's no such left child, check if the root of this subtree can |
| // satisfy the allocation. If so, we're done. |
| // * If the root cannot satisfy the allocation either, continue down the |
| // right subtree if able. |
| // * Else, break and report that we cannot satisfy the allocation. |
| // |
| // The preference for left, then current, then right, results in us getting |
| // the left-most node which will contain the span with the lowest base |
| // address. |
| // |
| // Note that if a request cannot be satisfied the fourth case will be |
| // reached immediately at the root, since neither the left subtree nor |
| // the right subtree will have a sufficient maxPages, whilst the root |
| // node is also unable to satisfy it. |
| func (root *mTreap) find(npages uintptr) treapIter { |
| t := root.treap |
| for t != nil { |
| if t.span == nil { |
| throw("treap node with nil span found") |
| } |
| // Iterate over the treap trying to go as far left |
| // as possible while simultaneously ensuring that the |
| // subtrees we choose always have a span which can |
| // satisfy the allocation. |
| if t.left != nil && t.left.maxPages >= npages { |
| t = t.left |
| } else if t.span.npages >= npages { |
| // Before going right, if this span can satisfy the |
| // request, stop here. |
| break |
| } else if t.right != nil && t.right.maxPages >= npages { |
| t = t.right |
| } else { |
| t = nil |
| } |
| } |
| return treapIter{treapFilterAll, t} |
| } |
| |
| // removeSpan searches for, finds, deletes span along with |
| // the associated treap node. If the span is not in the treap |
| // then t will eventually be set to nil and the t.span |
| // will throw. |
| func (root *mTreap) removeSpan(span *mspan) { |
| base := span.base() |
| t := root.treap |
| for t.span != span { |
| if t.key < base { |
| t = t.right |
| } else if t.key > base { |
| t = t.left |
| } |
| } |
| root.removeNode(t) |
| } |
| |
| // erase removes the element referred to by the current position of the |
| // iterator. This operation consumes the given iterator, so it should no |
| // longer be used. It is up to the caller to get the next or previous |
| // iterator before calling erase, if need be. |
| func (root *mTreap) erase(i treapIter) { |
| root.removeNode(i.t) |
| } |
| |
| // rotateLeft rotates the tree rooted at node x. |
| // turning (x a (y b c)) into (y (x a b) c). |
| func (root *mTreap) rotateLeft(x *treapNode) { |
| // p -> (x a (y b c)) |
| p := x.parent |
| a, y := x.left, x.right |
| b, c := y.left, y.right |
| |
| y.left = x |
| x.parent = y |
| y.right = c |
| if c != nil { |
| c.parent = y |
| } |
| x.left = a |
| if a != nil { |
| a.parent = x |
| } |
| x.right = b |
| if b != nil { |
| b.parent = x |
| } |
| |
| y.parent = p |
| if p == nil { |
| root.treap = y |
| } else if p.left == x { |
| p.left = y |
| } else { |
| if p.right != x { |
| throw("large span treap rotateLeft") |
| } |
| p.right = y |
| } |
| |
| x.updateInvariants() |
| y.updateInvariants() |
| } |
| |
| // rotateRight rotates the tree rooted at node y. |
| // turning (y (x a b) c) into (x a (y b c)). |
| func (root *mTreap) rotateRight(y *treapNode) { |
| // p -> (y (x a b) c) |
| p := y.parent |
| x, c := y.left, y.right |
| a, b := x.left, x.right |
| |
| x.left = a |
| if a != nil { |
| a.parent = x |
| } |
| x.right = y |
| y.parent = x |
| y.left = b |
| if b != nil { |
| b.parent = y |
| } |
| y.right = c |
| if c != nil { |
| c.parent = y |
| } |
| |
| x.parent = p |
| if p == nil { |
| root.treap = x |
| } else if p.left == y { |
| p.left = x |
| } else { |
| if p.right != y { |
| throw("large span treap rotateRight") |
| } |
| p.right = x |
| } |
| |
| y.updateInvariants() |
| x.updateInvariants() |
| } |