github.com/zxy12/golang_with_comment@v0.0.0-20190701084843-0e6b2aff5ef3/runtime/mgclarge.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Page heap.
     6  //
     7  // See malloc.go for the general overview.
     8  //
     9  // Large spans are the subject of this file. Spans consisting of less than
    10  // _MaxMHeapLists are held in lists of like sized spans. Larger spans
    11  // are held in a treap. See https://en.wikipedia.org/wiki/Treap or
    12  // http://faculty.washington.edu/aragon/pubs/rst89.pdf for an overview.
    13  // sema.go also holds an implementation of a treap.
    14  //
    15  // Each treapNode holds a single span. The treap is sorted by page size
    16  // and for spans of the same size a secondary sort based on start address
    17  // is done.
    18  // Spans are returned based on a best fit algorithm and for spans of the same
    19  // size the one at the lowest address is selected.
    20  //
    21  // The primary routines are
    22  // insert: adds a span to the treap
    23  // remove: removes the span from that treap that best fits the required size
    24  // removeSpan: which removes a specific span from the treap
    25  //
    26  // _mheap.lock must be held when manipulating this data structure.
    27  
    28  package runtime
    29  
    30  import (
    31  	"unsafe"
    32  )
    33  
    34  //go:notinheap
    35  type mTreap struct {
    36  	treap   *treapNode
    37  	nodenum int
    38  }
    39  
    40  //go:notinheap
    41  type treapNode struct {
    42  	right     *treapNode // all treapNodes > this treap node
    43  	left      *treapNode // all treapNodes < this treap node
    44  	parent    *treapNode // direct parent of this node, nil if root
    45  	npagesKey uintptr    // number of pages in spanKey, used as primary sort key
    46  	spanKey   *mspan     // span of size npagesKey, used as secondary sort key
    47  	priority  uint32     // random number used by treap algorithm keep tree probablistically balanced
    48  }
    49  
    50  func (t *treapNode) init() {
    51  	t.right = nil
    52  	t.left = nil
    53  	t.parent = nil
    54  	t.spanKey = nil
    55  	t.npagesKey = 0
    56  	t.priority = 0
    57  }
    58  
    59  // isSpanInTreap is handy for debugging. One should hold the heap lock, usually
    60  // mheap_.lock().
    61  func (t *treapNode) isSpanInTreap(s *mspan) bool {
    62  	if t == nil {
    63  		return false
    64  	}
    65  	return t.spanKey == s || t.left.isSpanInTreap(s) || t.right.isSpanInTreap(s)
    66  }
    67  
    68  // walkTreap is handy for debugging.
    69  // Starting at some treapnode t, for example the root, do a depth first preorder walk of
    70  // the tree executing fn at each treap node. One should hold the heap lock, usually
    71  // mheap_.lock().
    72  func (t *treapNode) walkTreap(fn func(tn *treapNode)) {
    73  	if t == nil {
    74  		return
    75  	}
    76  	fn(t)
    77  	t.left.walkTreap(fn)
    78  	t.right.walkTreap(fn)
    79  }
    80  
    81  // checkTreapNode when used in conjunction with walkTreap can usually detect a
    82  // poorly formed treap.
    83  func checkTreapNode(t *treapNode) {
    84  	// lessThan is used to order the treap.
    85  	// npagesKey and npages are the primary keys.
    86  	// spanKey and span are the secondary keys.
    87  	// span == nil (0) will always be lessThan all
    88  	// spans of the same size.
    89  	lessThan := func(npages uintptr, s *mspan) bool {
    90  		if t.npagesKey != npages {
    91  			return t.npagesKey < npages
    92  		}
    93  		// t.npagesKey == npages
    94  		return uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(s))
    95  	}
    96  
    97  	if t == nil {
    98  		return
    99  	}
   100  	if t.spanKey.npages != t.npagesKey || t.spanKey.next != nil {
   101  		//println("runtime: checkTreapNode treapNode t=", t, "     t.npagesKey=", t.npagesKey,
   102  		//	"t.spanKey.npages=", t.spanKey.npages)
   103  		throw("why does span.npages and treap.ngagesKey do not match?")
   104  	}
   105  	if t.left != nil && lessThan(t.left.npagesKey, t.left.spanKey) {
   106  		throw("t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
   107  	}
   108  	if t.right != nil && !lessThan(t.right.npagesKey, t.right.spanKey) {
   109  		throw("!t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
   110  	}
   111  }
   112  
   113  // insert adds span to the large span treap.
   114  func (root *mTreap) insert(span *mspan) {
   115  	npages := span.npages
   116  	root.nodenum++
   117  	//println("mtreap insert a span:", npages)
   118  	var last *treapNode
   119  	pt := &root.treap
   120  	for t := *pt; t != nil; t = *pt {
   121  		last = t
   122  		if t.npagesKey < npages {
   123  			pt = &t.right
   124  		} else if t.npagesKey > npages {
   125  			pt = &t.left
   126  		} else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
   127  			// t.npagesKey == npages, so sort on span addresses.
   128  			pt = &t.right
   129  		} else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
   130  			pt = &t.left
   131  		} else {
   132  			throw("inserting span already in treap")
   133  		}
   134  	}
   135  
   136  	// Add t as new leaf in tree of span size and unique addrs.
   137  	// The balanced tree is a treap using priority as the random heap priority.
   138  	// That is, it is a binary tree ordered according to the npagesKey,
   139  	// but then among the space of possible binary trees respecting those
   140  	// npagesKeys, it is kept balanced on average by maintaining a heap ordering
   141  	// on the priority: s.priority <= both s.right.priority and s.right.priority.
   142  	// https://en.wikipedia.org/wiki/Treap
   143  	// http://faculty.washington.edu/aragon/pubs/rst89.pdf
   144  
   145  	t := (*treapNode)(mheap_.treapalloc.alloc())
   146  	t.init()
   147  	t.npagesKey = span.npages
   148  	t.priority = fastrand()
   149  	t.spanKey = span
   150  	t.parent = last
   151  	*pt = t // t now at a leaf.
   152  	// Rotate up into tree according to priority.
   153  	for t.parent != nil && t.parent.priority > t.priority {
   154  		if t != nil && t.spanKey.npages != t.npagesKey {
   155  			//println("runtime: insert t=", t, "t.npagesKey=", t.npagesKey)
   156  			//println("runtime:      t.spanKey=", t.spanKey, "t.spanKey.npages=", t.spanKey.npages)
   157  			throw("span and treap sizes do not match?")
   158  		}
   159  		if t.parent.left == t {
   160  			root.rotateRight(t.parent)
   161  		} else {
   162  			if t.parent.right != t {
   163  				throw("treap insert finds a broken treap")
   164  			}
   165  			root.rotateLeft(t.parent)
   166  		}
   167  	}
   168  }
   169  
   170  func (root *mTreap) removeNode(t *treapNode) *mspan {
   171  	if t.spanKey.npages != t.npagesKey {
   172  		throw("span and treap node npages do not match")
   173  	}
   174  	result := t.spanKey
   175  
   176  	// Rotate t down to be leaf of tree for removal, respecting priorities.
   177  	for t.right != nil || t.left != nil {
   178  		if t.right == nil || t.left != nil && t.left.priority < t.right.priority {
   179  			root.rotateRight(t)
   180  		} else {
   181  			root.rotateLeft(t)
   182  		}
   183  	}
   184  	// Remove t, now a leaf.
   185  	if t.parent != nil {
   186  		if t.parent.left == t {
   187  			t.parent.left = nil
   188  		} else {
   189  			t.parent.right = nil
   190  		}
   191  	} else {
   192  		root.treap = nil
   193  	}
   194  	// Return the found treapNode's span after freeing the treapNode.
   195  	t.spanKey = nil
   196  	t.npagesKey = 0
   197  	mheap_.treapalloc.free(unsafe.Pointer(t))
   198  	return result
   199  }
   200  
   201  // remove searches for, finds, removes from the treap, and returns the smallest
   202  // span that can hold npages. If no span has at least npages return nil.
   203  // This is slightly more complicated than a simple binary tree search
   204  // since if an exact match is not found the next larger node is
   205  // returned.
   206  // If the last node inspected > npagesKey not holding
   207  // a left node (a smaller npages) is the "best fit" node.
   208  func (root *mTreap) remove(npages uintptr) *mspan {
   209  
   210  	t := root.treap
   211  	for t != nil {
   212  		if t.spanKey == nil {
   213  			throw("treap node with nil spanKey found")
   214  		}
   215  		if t.npagesKey < npages {
   216  			t = t.right
   217  		} else if t.left != nil && t.left.npagesKey >= npages {
   218  			t = t.left
   219  		} else {
   220  			result := t.spanKey
   221  			root.removeNode(t)
   222  			root.nodenum--
   223  			////println("mtreap remove a span:", t.npagesKey, ",need:", npages)
   224  			return result
   225  		}
   226  	}
   227  	return nil
   228  }
   229  
   230  // removeSpan searches for, finds, deletes span along with
   231  // the associated treap node. If the span is not in the treap
   232  // then t will eventually be set to nil and the t.spanKey
   233  // will throw.
   234  func (root *mTreap) removeSpan(span *mspan) {
   235  	npages := span.npages
   236  	t := root.treap
   237  	for t.spanKey != span {
   238  		if t.npagesKey < npages {
   239  			t = t.right
   240  		} else if t.npagesKey > npages {
   241  			t = t.left
   242  		} else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
   243  			t = t.right
   244  		} else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
   245  			t = t.left
   246  		}
   247  	}
   248  	root.removeNode(t)
   249  }
   250  
   251  // scavengetreap visits each node in the treap and scavenges the
   252  // treapNode's span.
   253  func scavengetreap(treap *treapNode, now, limit uint64) uintptr {
   254  	if treap == nil {
   255  		return 0
   256  	}
   257  	return scavengeTreapNode(treap, now, limit) +
   258  		scavengetreap(treap.left, now, limit) +
   259  		scavengetreap(treap.right, now, limit)
   260  }
   261  
   262  // rotateLeft rotates the tree rooted at node x.
   263  // turning (x a (y b c)) into (y (x a b) c).
   264  func (root *mTreap) rotateLeft(x *treapNode) {
   265  	// p -> (x a (y b c))
   266  	p := x.parent
   267  	a, y := x.left, x.right
   268  	b, c := y.left, y.right
   269  
   270  	y.left = x
   271  	x.parent = y
   272  	y.right = c
   273  	if c != nil {
   274  		c.parent = y
   275  	}
   276  	x.left = a
   277  	if a != nil {
   278  		a.parent = x
   279  	}
   280  	x.right = b
   281  	if b != nil {
   282  		b.parent = x
   283  	}
   284  
   285  	y.parent = p
   286  	if p == nil {
   287  		root.treap = y
   288  	} else if p.left == x {
   289  		p.left = y
   290  	} else {
   291  		if p.right != x {
   292  			throw("large span treap rotateLeft")
   293  		}
   294  		p.right = y
   295  	}
   296  }
   297  
   298  // rotateRight rotates the tree rooted at node y.
   299  // turning (y (x a b) c) into (x a (y b c)).
   300  func (root *mTreap) rotateRight(y *treapNode) {
   301  	// p -> (y (x a b) c)
   302  	p := y.parent
   303  	x, c := y.left, y.right
   304  	a, b := x.left, x.right
   305  
   306  	x.left = a
   307  	if a != nil {
   308  		a.parent = x
   309  	}
   310  	x.right = y
   311  	y.parent = x
   312  	y.left = b
   313  	if b != nil {
   314  		b.parent = y
   315  	}
   316  	y.right = c
   317  	if c != nil {
   318  		c.parent = y
   319  	}
   320  
   321  	x.parent = p
   322  	if p == nil {
   323  		root.treap = x
   324  	} else if p.left == y {
   325  		p.left = x
   326  	} else {
   327  		if p.right != y {
   328  			throw("large span treap rotateRight")
   329  		}
   330  		p.right = x
   331  	}
   332  }