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 }