Skip to content
Permalink
Browse files

[release-branch.go1.12] runtime: make mTreap.find actually find the b…

…est fit

This change modifies the implementation of mTreap.find to find the
best-fit span with the lowest possible base address.

Fixes #31677.

Change-Id: Ib4bda0f85d7d0590326f939a243a6e4665f37d3f
Reviewed-on: https://go-review.googlesource.com/c/go/+/173479
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
(cherry picked from commit 8c05d67)
Reviewed-on: https://go-review.googlesource.com/c/go/+/173939
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information...
mknyszek authored and bradfitz committed Apr 23, 2019
1 parent a1a9d8a commit 438b1a5dae01812a2b91b648c762414d4854ccd7
Showing with 19 additions and 15 deletions.
  1. +14 −8 src/runtime/mgclarge.go
  2. +5 −7 src/runtime/treap_test.go
@@ -301,24 +301,30 @@ func (root *mTreap) removeNode(t *treapNode) {
// find searches for, finds, and returns the treap node containing the
// smallest span that can hold npages. If no span has at least npages
// it returns nil.
// This is slightly more complicated than a simple binary tree search
// since if an exact match is not found the next larger node is
// returned.
// This is a simple binary tree search that tracks the best-fit node found
// so far. The best-fit node is guaranteed to be on the path to a
// (maybe non-existent) lowest-base exact match.
func (root *mTreap) find(npages uintptr) *treapNode {
var best *treapNode
t := root.treap
for t != nil {
if t.spanKey == nil {
throw("treap node with nil spanKey found")
}
if t.npagesKey < npages {
t = t.right
} else if t.left != nil && t.left.npagesKey >= npages {
// If we found an exact match, try to go left anyway. There could be
// a span there with a lower base address.
//
// Don't bother checking nil-ness of left and right here; even if t
// becomes nil, we already know the other path had nothing better for
// us anyway.
if t.npagesKey >= npages {
best = t
t = t.left
} else {
return t
t = t.right
}
}
return nil
return best
}

// removeSpan searches for, finds, deletes span along with
@@ -58,11 +58,7 @@ func TestTreap(t *testing.T) {
}
tr.RemoveSpan(spans[0])
})
t.Run("Find", func(t *testing.T) {
// Note that Find doesn't actually find the best-fit
// element, so just make sure it always returns an element
// that is at least large enough to satisfy the request.
//
t.Run("FindBestFit", func(t *testing.T) {
// Run this 10 times, recreating the treap each time.
// Because of the non-deterministic structure of a treap,
// we'll be able to test different structures this way.
@@ -72,8 +68,10 @@ func TestTreap(t *testing.T) {
tr.Insert(s)
}
i := tr.Find(5)
if i.Span().Pages() < 5 {
t.Fatalf("expected span of size at least 5, got size %d", i.Span().Pages())
if i.Span().Pages() != 5 {
t.Fatalf("expected span of size 5, got span of size %d", i.Span().Pages())
} else if i.Span().Base() != 0xc0040000 {
t.Fatalf("expected span to have the lowest base address, instead got base %x", i.Span().Base())
}
for _, s := range spans {
tr.RemoveSpan(s)

0 comments on commit 438b1a5

Please sign in to comment.
You can’t perform that action at this time.