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