// 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< 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() }