1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #ifndef SHARE_MEMORY_METASPACE_BLOCKTREE_HPP 27 #define SHARE_MEMORY_METASPACE_BLOCKTREE_HPP 28 29 #include "memory/allocation.hpp" 30 #include "memory/metaspace/chunklevel.hpp" 31 #include "memory/metaspace/counters.hpp" 32 #include "utilities/debug.hpp" 33 #include "utilities/globalDefinitions.hpp" 34 35 namespace metaspace { 36 37 // BlockTree is a rather simple binary search tree. It is used to 38 // manage small to medium free memory blocks (see class FreeBlocks). 39 // 40 // There is no separation between payload (managed blocks) and nodes: the 41 // memory blocks themselves are the nodes, with the block size being the key. 42 // 43 // We store node pointer information in these blocks when storing them. That 44 // imposes a minimum size to the managed memory blocks. 45 // See get_raw_word_size_for_requested_word_size() (msCommon.hpp). 46 // 47 // We want to manage many memory blocks of the same size, but we want 48 // to prevent the tree from blowing up and degenerating into a list. Therefore 49 // there is only one node for each unique block size; subsequent blocks of the 50 // same size are stacked below that first node: 51 // 52 // +-----+ 53 // | 100 | 54 // +-----+ 55 // / \ 56 // +-----+ 57 // | 80 | 58 // +-----+ 59 // / | \ 60 // / +-----+ \ 61 // +-----+ | 80 | +-----+ 62 // | 70 | +-----+ | 85 | 63 // +-----+ | +-----+ 64 // +-----+ 65 // | 80 | 66 // +-----+ 67 // 68 // 69 // Todo: This tree is unbalanced. It would be a good fit for a red-black tree. 70 // In order to make this a red-black tree, we need an algorithm which can deal 71 // with nodes which are their own payload (most red-black tree implementations 72 // swap payloads of their nodes at some point, see e.g. j.u.TreeSet). 73 // A good example is the Linux kernel rbtree, which is a clean, easy-to-read 74 // implementation. 75 76 class BlockTree: public CHeapObj<mtMetaspace> { 77 78 struct Node { 79 80 static const intptr_t _canary_value = 81 NOT_LP64(0x4e4f4445) LP64_ONLY(0x4e4f44454e4f4445ULL); // "NODE" resp "NODENODE" 82 83 // Note: we afford us the luxury of an always-there canary value. 84 // The space for that is there (these nodes are only used to manage larger blocks, 85 // see FreeBlocks::MaxSmallBlocksWordSize). 86 // It is initialized in debug and release, but only automatically tested 87 // in debug. 88 const intptr_t _canary; 89 90 // Normal tree node stuff... 91 // (Note: all null if this is a stacked node) 92 Node* _parent; 93 Node* _left; 94 Node* _right; 95 96 // Blocks with the same size are put in a list with this node as head. 97 Node* _next; 98 99 // Word size of node. Note that size cannot be larger than max metaspace size, 100 // so this could be very well a 32bit value (in case we ever make this a balancing 101 // tree and need additional space for weighting information). 102 const size_t _word_size; 103 104 Node(size_t word_size) : 105 _canary(_canary_value), 106 _parent(nullptr), 107 _left(nullptr), 108 _right(nullptr), 109 _next(nullptr), 110 _word_size(word_size) 111 {} 112 113 #ifdef ASSERT 114 bool valid() const { 115 return _canary == _canary_value && 116 _word_size >= sizeof(Node) && 117 _word_size < chunklevel::MAX_CHUNK_WORD_SIZE; 118 } 119 #endif 120 }; 121 122 // Needed for verify() and print_tree() 123 struct walkinfo; 124 125 #ifdef ASSERT 126 // Run a quick check on a node; upon suspicion dive into a full tree check. 127 void check_node(const Node* n) const { if (!n->valid()) verify(); } 128 #endif 129 130 public: 131 132 // Minimum word size a block has to be to be added to this structure (note ceil division). 133 const static size_t MinWordSize = 134 (sizeof(Node) + sizeof(MetaWord) - 1) / sizeof(MetaWord); 135 136 private: 137 138 Node* _root; 139 140 MemRangeCounter _counter; 141 142 // Given a node n, add it to the list starting at head 143 static void add_to_list(Node* n, Node* head) { 144 assert(head->_word_size == n->_word_size, "sanity"); 145 n->_next = head->_next; 146 head->_next = n; 147 DEBUG_ONLY(n->_left = n->_right = n->_parent = nullptr;) 148 } 149 150 // Given a node list starting at head, remove one of the follow up nodes from 151 // that list and return it. The head node gets not modified and remains in the 152 // tree. 153 // List must contain at least one other node. 154 static Node* remove_from_list(Node* head) { 155 assert(head->_next != nullptr, "sanity"); 156 Node* n = head->_next; 157 head->_next = n->_next; 158 return n; 159 } 160 161 // Given a node c and a node p, wire up c as left child of p. 162 static void set_left_child(Node* p, Node* c) { 163 p->_left = c; 164 if (c != nullptr) { 165 assert(c->_word_size < p->_word_size, "sanity"); 166 c->_parent = p; 167 } 168 } 169 170 // Given a node c and a node p, wire up c as right child of p. 171 static void set_right_child(Node* p, Node* c) { 172 p->_right = c; 173 if (c != nullptr) { 174 assert(c->_word_size > p->_word_size, "sanity"); 175 c->_parent = p; 176 } 177 } 178 179 // Given a node n, return its successor in the tree 180 // (node with the next-larger size). 181 static Node* successor(Node* n) { 182 Node* succ = nullptr; 183 if (n->_right != nullptr) { 184 // If there is a right child, search the left-most 185 // child of that child. 186 succ = n->_right; 187 while (succ->_left != nullptr) { 188 succ = succ->_left; 189 } 190 } else { 191 succ = n->_parent; 192 Node* n2 = n; 193 // As long as I am the right child of my parent, search upward 194 while (succ != nullptr && n2 == succ->_right) { 195 n2 = succ; 196 succ = succ->_parent; 197 } 198 } 199 return succ; 200 } 201 202 // Given a node, replace it with a replacement node as a child for its parent. 203 // If the node is root and has no parent, sets it as root. 204 void replace_node_in_parent(Node* child, Node* replace) { 205 Node* parent = child->_parent; 206 if (parent != nullptr) { 207 if (parent->_left == child) { // Child is left child 208 set_left_child(parent, replace); 209 } else { 210 set_right_child(parent, replace); 211 } 212 } else { 213 assert(child == _root, "must be root"); 214 _root = replace; 215 if (replace != nullptr) { 216 replace->_parent = nullptr; 217 } 218 } 219 return; 220 } 221 222 // Given a node n and an insertion point, insert n under insertion point. 223 void insert(Node* insertion_point, Node* n) { 224 assert(n->_parent == nullptr, "Sanity"); 225 for (;;) { 226 DEBUG_ONLY(check_node(insertion_point);) 227 if (n->_word_size == insertion_point->_word_size) { 228 add_to_list(n, insertion_point); // parent stays null in this case. 229 break; 230 } else if (n->_word_size > insertion_point->_word_size) { 231 if (insertion_point->_right == nullptr) { 232 set_right_child(insertion_point, n); 233 break; 234 } else { 235 insertion_point = insertion_point->_right; 236 } 237 } else { 238 if (insertion_point->_left == nullptr) { 239 set_left_child(insertion_point, n); 240 break; 241 } else { 242 insertion_point = insertion_point->_left; 243 } 244 } 245 } 246 } 247 248 // Given a node and a wish size, search this node and all children for 249 // the node closest (equal or larger sized) to the size s. 250 Node* find_closest_fit(Node* n, size_t s) { 251 Node* best_match = nullptr; 252 while (n != nullptr) { 253 DEBUG_ONLY(check_node(n);) 254 if (n->_word_size >= s) { 255 best_match = n; 256 if (n->_word_size == s) { 257 break; // perfect match or max depth reached 258 } 259 n = n->_left; 260 } else { 261 n = n->_right; 262 } 263 } 264 return best_match; 265 } 266 267 // Given a wish size, search the whole tree for a 268 // node closest (equal or larger sized) to the size s. 269 Node* find_closest_fit(size_t s) { 270 if (_root != nullptr) { 271 return find_closest_fit(_root, s); 272 } 273 return nullptr; 274 } 275 276 // Given a node n, remove it from the tree and repair tree. 277 void remove_node_from_tree(Node* n) { 278 assert(n->_next == nullptr, "do not delete a node which has a non-empty list"); 279 280 if (n->_left == nullptr && n->_right == nullptr) { 281 replace_node_in_parent(n, nullptr); 282 283 } else if (n->_left == nullptr && n->_right != nullptr) { 284 replace_node_in_parent(n, n->_right); 285 286 } else if (n->_left != nullptr && n->_right == nullptr) { 287 replace_node_in_parent(n, n->_left); 288 289 } else { 290 // Node has two children. 291 292 // 1) Find direct successor (the next larger node). 293 Node* succ = successor(n); 294 295 // There has to be a successor since n->right was != null... 296 assert(succ != nullptr, "must be"); 297 298 // ... and it should not have a left child since successor 299 // is supposed to be the next larger node, so it must be the mostleft node 300 // in the sub tree rooted at n->right 301 assert(succ->_left == nullptr, "must be"); 302 assert(succ->_word_size > n->_word_size, "sanity"); 303 304 Node* successor_parent = succ->_parent; 305 Node* successor_right_child = succ->_right; 306 307 // Remove successor from its parent. 308 if (successor_parent == n) { 309 310 // special case: successor is a direct child of n. Has to be the right child then. 311 assert(n->_right == succ, "sanity"); 312 313 // Just replace n with this successor. 314 replace_node_in_parent(n, succ); 315 316 // Take over n's old left child, too. 317 // We keep the successor's right child. 318 set_left_child(succ, n->_left); 319 } else { 320 // If the successors parent is not n, we are deeper in the tree, 321 // the successor has to be the left child of its parent. 322 assert(successor_parent->_left == succ, "sanity"); 323 324 // The right child of the successor (if there was one) replaces 325 // the successor at its parent's left child. 326 set_left_child(successor_parent, succ->_right); 327 328 // and the successor replaces n at its parent 329 replace_node_in_parent(n, succ); 330 331 // and takes over n's old children 332 set_left_child(succ, n->_left); 333 set_right_child(succ, n->_right); 334 } 335 } 336 } 337 338 #ifdef ASSERT 339 void zap_range(MetaWord* p, size_t word_size); 340 // Helper for verify() 341 void verify_node_pointer(const Node* n) const; 342 #endif // ASSERT 343 344 public: 345 346 BlockTree() : _root(nullptr) {} 347 348 // Add a memory block to the tree. Its content will be overwritten. 349 void add_block(MetaWord* p, size_t word_size) { 350 DEBUG_ONLY(zap_range(p, word_size)); 351 assert(word_size >= MinWordSize, "invalid block size " SIZE_FORMAT, word_size); 352 Node* n = new(p) Node(word_size); 353 if (_root == nullptr) { 354 _root = n; 355 } else { 356 insert(_root, n); 357 } 358 _counter.add(word_size); 359 } 360 361 // Given a word_size, search and return the smallest block that is equal or 362 // larger than that size. Upon return, *p_real_word_size contains the actual 363 // block size. 364 MetaWord* remove_block(size_t word_size, size_t* p_real_word_size) { 365 assert(word_size > 0, "invalid block size " SIZE_FORMAT, word_size); 366 367 Node* n = find_closest_fit(word_size); 368 369 if (n != nullptr) { 370 DEBUG_ONLY(check_node(n);) 371 assert(n->_word_size >= word_size, "sanity"); 372 373 if (n->_next != nullptr) { 374 // If the node is head of a chain of same sized nodes, we leave it alone 375 // and instead remove one of the follow up nodes (which is simpler than 376 // removing the chain head node and then having to graft the follow up 377 // node into its place in the tree). 378 n = remove_from_list(n); 379 } else { 380 remove_node_from_tree(n); 381 } 382 383 MetaWord* p = (MetaWord*)n; 384 *p_real_word_size = n->_word_size; 385 386 _counter.sub(n->_word_size); 387 388 DEBUG_ONLY(zap_range(p, n->_word_size)); 389 return p; 390 } 391 return nullptr; 392 } 393 394 // Returns number of blocks in this structure 395 unsigned count() const { return _counter.count(); } 396 397 // Returns total size, in words, of all elements. 398 size_t total_size() const { return _counter.total_size(); } 399 400 bool is_empty() const { return _root == nullptr; } 401 402 DEBUG_ONLY(void print_tree(outputStream* st) const;) 403 DEBUG_ONLY(void verify() const;) 404 }; 405 406 } // namespace metaspace 407 408 #endif // SHARE_MEMORY_METASPACE_BLOCKTREE_HPP