github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/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) { 168 if t.spanKey.npages != t.npagesKey { 169 throw("span and treap node npages do not match") 170 } 171 172 // Rotate t down to be leaf of tree for removal, respecting priorities. 173 for t.right != nil || t.left != nil { 174 if t.right == nil || t.left != nil && t.left.priority < t.right.priority { 175 root.rotateRight(t) 176 } else { 177 root.rotateLeft(t) 178 } 179 } 180 // Remove t, now a leaf. 181 if t.parent != nil { 182 if t.parent.left == t { 183 t.parent.left = nil 184 } else { 185 t.parent.right = nil 186 } 187 } else { 188 root.treap = nil 189 } 190 // Return the found treapNode's span after freeing the treapNode. 191 t.spanKey = nil 192 t.npagesKey = 0 193 mheap_.treapalloc.free(unsafe.Pointer(t)) 194 } 195 196 // remove searches for, finds, removes from the treap, and returns the smallest 197 // span that can hold npages. If no span has at least npages return nil. 198 // This is slightly more complicated than a simple binary tree search 199 // since if an exact match is not found the next larger node is 200 // returned. 201 // If the last node inspected > npagesKey not holding 202 // a left node (a smaller npages) is the "best fit" node. 203 func (root *mTreap) remove(npages uintptr) *mspan { 204 t := root.treap 205 for t != nil { 206 if t.spanKey == nil { 207 throw("treap node with nil spanKey found") 208 } 209 if t.npagesKey < npages { 210 t = t.right 211 } else if t.left != nil && t.left.npagesKey >= npages { 212 t = t.left 213 } else { 214 result := t.spanKey 215 root.removeNode(t) 216 return result 217 } 218 } 219 return nil 220 } 221 222 // removeSpan searches for, finds, deletes span along with 223 // the associated treap node. If the span is not in the treap 224 // then t will eventually be set to nil and the t.spanKey 225 // will throw. 226 func (root *mTreap) removeSpan(span *mspan) { 227 npages := span.npages 228 t := root.treap 229 for t.spanKey != span { 230 if t.npagesKey < npages { 231 t = t.right 232 } else if t.npagesKey > npages { 233 t = t.left 234 } else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) { 235 t = t.right 236 } else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) { 237 t = t.left 238 } 239 } 240 root.removeNode(t) 241 } 242 243 // scavengetreap visits each node in the treap and scavenges the 244 // treapNode's span. 245 func scavengetreap(treap *treapNode, now, limit uint64) uintptr { 246 if treap == nil { 247 return 0 248 } 249 return scavengeTreapNode(treap, now, limit) + 250 scavengetreap(treap.left, now, limit) + 251 scavengetreap(treap.right, now, limit) 252 } 253 254 // rotateLeft rotates the tree rooted at node x. 255 // turning (x a (y b c)) into (y (x a b) c). 256 func (root *mTreap) rotateLeft(x *treapNode) { 257 // p -> (x a (y b c)) 258 p := x.parent 259 a, y := x.left, x.right 260 b, c := y.left, y.right 261 262 y.left = x 263 x.parent = y 264 y.right = c 265 if c != nil { 266 c.parent = y 267 } 268 x.left = a 269 if a != nil { 270 a.parent = x 271 } 272 x.right = b 273 if b != nil { 274 b.parent = x 275 } 276 277 y.parent = p 278 if p == nil { 279 root.treap = y 280 } else if p.left == x { 281 p.left = y 282 } else { 283 if p.right != x { 284 throw("large span treap rotateLeft") 285 } 286 p.right = y 287 } 288 } 289 290 // rotateRight rotates the tree rooted at node y. 291 // turning (y (x a b) c) into (x a (y b c)). 292 func (root *mTreap) rotateRight(y *treapNode) { 293 // p -> (y (x a b) c) 294 p := y.parent 295 x, c := y.left, y.right 296 a, b := x.left, x.right 297 298 x.left = a 299 if a != nil { 300 a.parent = x 301 } 302 x.right = y 303 y.parent = x 304 y.left = b 305 if b != nil { 306 b.parent = y 307 } 308 y.right = c 309 if c != nil { 310 c.parent = y 311 } 312 313 x.parent = p 314 if p == nil { 315 root.treap = x 316 } else if p.left == y { 317 p.left = x 318 } else { 319 if p.right != y { 320 throw("large span treap rotateRight") 321 } 322 p.right = x 323 } 324 }