1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include "precompiled.hpp" 25 #include "gc/z/zErrno.hpp" 26 #include "gc/z/zFlags.hpp" 27 #include "gc/z/zGlobals.hpp" 28 #include "gc/z/zLock.inline.hpp" 29 #include "gc/z/zMarkStack.inline.hpp" 30 #include "logging/log.hpp" 31 #include "runtime/atomic.hpp" 32 #include "utilities/debug.hpp" 33 34 #include <sys/mman.h> 35 #include <sys/types.h> 36 37 ZMarkStackSpace::ZMarkStackSpace() : 38 _expand_lock(), 39 _top(0), 40 _end(0) { 41 assert(ZMarkStacksMax >= ZMarkStackSpaceExpandSize, "ZMarkStacksMax too small"); 42 assert(ZMarkStacksMax <= ZMarkStackSpaceSize, "ZMarkStacksMax too large"); 43 44 // Reserve address space 45 const void* res = mmap((void*)ZMarkStackSpaceStart, ZMarkStackSpaceSize, 46 PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); 47 if (res != (void*)ZMarkStackSpaceStart) { 48 log_error(gc, marking)("Failed to reserve address space for marking stacks"); 49 return; 50 } 51 52 // Successfully initialized 53 _top = _end = ZMarkStackSpaceStart; 54 } 55 56 bool ZMarkStackSpace::is_initialized() const { 57 return _top != 0; 58 } 59 60 bool ZMarkStackSpace::expand() { 61 const size_t max = ZMarkStackSpaceStart + ZMarkStacksMax; 62 if (_end + ZMarkStackSpaceExpandSize > max) { 63 // Expansion limit reached 64 return false; 65 } 66 67 void* const res = mmap((void*)_end, ZMarkStackSpaceExpandSize, 68 PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0); 69 if (res == MAP_FAILED) { 70 ZErrno err; 71 log_error(gc, marking)("Failed to map memory for marking stacks (%s)", err.to_string()); 72 return false; 73 } 74 75 return true; 76 } 77 78 uintptr_t ZMarkStackSpace::alloc_space(size_t size) { 79 uintptr_t top = _top; 80 81 for (;;) { 82 const uintptr_t new_top = top + size; 83 if (new_top > _end) { 84 // Not enough space left 85 return 0; 86 } 87 88 const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, top); 89 if (prev_top == top) { 90 // Success 91 return top; 92 } 93 94 // Retry 95 top = prev_top; 96 } 97 } 98 99 uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) { 100 ZLocker locker(&_expand_lock); 101 102 // Retry allocation before expanding 103 uintptr_t addr = alloc_space(size); 104 if (addr != 0) { 105 return addr; 106 } 107 108 // Expand stack space 109 if (!expand()) { 110 // We currently can't handle the situation where we 111 // are running out of mark stack space. 112 fatal("Mark stack overflow (allocated " SIZE_FORMAT "M, size " SIZE_FORMAT "M, max " SIZE_FORMAT "M)," 113 " use -XX:ZMarkStacksMax=? to increase this limit", 114 (_end - ZMarkStackSpaceStart) / M, size / M, ZMarkStacksMax / M); 115 return 0; 116 } 117 118 log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M", 119 (_end - ZMarkStackSpaceStart) / M, 120 (_end - ZMarkStackSpaceStart + ZMarkStackSpaceExpandSize) / M); 121 122 // Increment top before end to make sure another 123 // thread can't steal out newly expanded space. 124 addr = Atomic::add(size, &_top) - size; 125 _end += ZMarkStackSpaceExpandSize; 126 127 return addr; 128 } 129 130 uintptr_t ZMarkStackSpace::alloc(size_t size) { 131 const uintptr_t addr = alloc_space(size); 132 if (addr != 0) { 133 return addr; 134 } 135 136 return expand_and_alloc_space(size); 137 } 138 139 ZMarkStackAllocator::ZMarkStackAllocator() : 140 _freelist(), 141 _space() { 142 guarantee(sizeof(ZMarkStack) == ZMarkStackSize, "Size mismatch"); 143 guarantee(sizeof(ZMarkStackMagazine) <= ZMarkStackSize, "Size mismatch"); 144 145 // Prime free list to avoid an immediate space 146 // expansion when marking starts. 147 if (_space.is_initialized()) { 148 prime_freelist(); 149 } 150 } 151 152 bool ZMarkStackAllocator::is_initialized() const { 153 return _space.is_initialized(); 154 } 155 156 void ZMarkStackAllocator::prime_freelist() { 157 for (size_t size = 0; size < ZMarkStackSpaceExpandSize; size += ZMarkStackMagazineSize) { 158 const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); 159 ZMarkStackMagazine* const magazine = create_magazine_from_space(addr, ZMarkStackMagazineSize); 160 free_magazine(magazine); 161 } 162 } 163 164 ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) { 165 assert(is_aligned(size, ZMarkStackSize), "Invalid size"); 166 167 // Use first stack as magazine 168 ZMarkStackMagazine* const magazine = new ((void*)addr) ZMarkStackMagazine(); 169 for (size_t i = ZMarkStackSize; i < size; i += ZMarkStackSize) { 170 ZMarkStack* const stack = new ((void*)(addr + i)) ZMarkStack(); 171 const bool success = magazine->push(stack); 172 assert(success, "Magazine should never get full"); 173 } 174 175 return magazine; 176 } 177 178 ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { 179 // Try allocating from the free list first 180 ZMarkStackMagazine* const magazine = _freelist.pop_atomic(); 181 if (magazine != NULL) { 182 return magazine; 183 } 184 185 // Allocate new magazine 186 const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); 187 if (addr == 0) { 188 return NULL; 189 } 190 191 return create_magazine_from_space(addr, ZMarkStackMagazineSize); 192 } 193 194 void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) { 195 _freelist.push_atomic(magazine); 196 } 197 198 ZMarkStripe::ZMarkStripe() : 199 _published(), 200 _overflowed() {} 201 202 ZMarkStripeSet::ZMarkStripeSet() : 203 _nstripes(0), 204 _nstripes_mask(0), 205 _stripes() {} 206 207 void ZMarkStripeSet::set_nstripes(size_t nstripes) { 208 assert(is_power_of_2(nstripes), "Must be a power of two"); 209 assert(is_power_of_2(ZMarkStripesMax), "Must be a power of two"); 210 assert(nstripes >= 1, "Invalid number of stripes"); 211 assert(nstripes <= ZMarkStripesMax, "Invalid number of stripes"); 212 213 _nstripes = nstripes; 214 _nstripes_mask = nstripes - 1; 215 216 log_debug(gc, marking)("Using " SIZE_FORMAT " mark stripes", _nstripes); 217 } 218 219 bool ZMarkStripeSet::is_empty() const { 220 for (size_t i = 0; i < _nstripes; i++) { 221 if (!_stripes[i].is_empty()) { 222 return false; 223 } 224 } 225 226 return true; 227 } 228 229 ZMarkStripe* ZMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) { 230 const size_t spillover_limit = (nworkers / _nstripes) * _nstripes; 231 size_t index; 232 233 if (worker_id < spillover_limit) { 234 // Not a spillover worker, use natural stripe 235 index = worker_id & _nstripes_mask; 236 } else { 237 // Distribute spillover workers evenly across stripes 238 const size_t spillover_nworkers = nworkers - spillover_limit; 239 const size_t spillover_worker_id = worker_id - spillover_limit; 240 const double spillover_chunk = (double)_nstripes / (double)spillover_nworkers; 241 index = spillover_worker_id * spillover_chunk; 242 } 243 244 assert(index < _nstripes, "Invalid index"); 245 return &_stripes[index]; 246 } 247 248 ZMarkThreadLocalStacks::ZMarkThreadLocalStacks() : 249 _magazine(NULL) { 250 for (size_t i = 0; i < ZMarkStripesMax; i++) { 251 _stacks[i] = NULL; 252 } 253 } 254 255 bool ZMarkThreadLocalStacks::is_empty(const ZMarkStripeSet* stripes) const { 256 for (size_t i = 0; i < stripes->nstripes(); i++) { 257 ZMarkStack* const stack = _stacks[i]; 258 if (stack != NULL) { 259 return false; 260 } 261 } 262 263 return true; 264 } 265 266 ZMarkStack* ZMarkThreadLocalStacks::allocate_stack(ZMarkStackAllocator* allocator) { 267 if (_magazine == NULL) { 268 // Allocate new magazine 269 _magazine = allocator->alloc_magazine(); 270 if (_magazine == NULL) { 271 return NULL; 272 } 273 } 274 275 ZMarkStack* stack = NULL; 276 277 if (!_magazine->pop(stack)) { 278 // Magazine is empty, convert magazine into a new stack 279 _magazine->~ZMarkStackMagazine(); 280 stack = new ((void*)_magazine) ZMarkStack(); 281 _magazine = NULL; 282 } 283 284 return stack; 285 } 286 287 void ZMarkThreadLocalStacks::free_stack(ZMarkStackAllocator* allocator, ZMarkStack* stack) { 288 for (;;) { 289 if (_magazine == NULL) { 290 // Convert stack into a new magazine 291 stack->~ZMarkStack(); 292 _magazine = new ((void*)stack) ZMarkStackMagazine(); 293 return; 294 } 295 296 if (_magazine->push(stack)) { 297 // Success 298 return; 299 } 300 301 // Free and uninstall full magazine 302 allocator->free_magazine(_magazine); 303 _magazine = NULL; 304 } 305 } 306 307 bool ZMarkThreadLocalStacks::push_slow(ZMarkStackAllocator* allocator, 308 ZMarkStripe* stripe, 309 ZMarkStack** stackp, 310 ZMarkStackEntry entry, 311 bool publish) { 312 ZMarkStack* stack = *stackp; 313 314 for (;;) { 315 if (stack == NULL) { 316 // Allocate and install new stack 317 *stackp = stack = allocate_stack(allocator); 318 if (stack == NULL) { 319 // Out of mark stack memory 320 return false; 321 } 322 } 323 324 if (stack->push(entry)) { 325 // Success 326 return true; 327 } 328 329 // Publish/Overflow and uninstall stack 330 stripe->publish_stack(stack, publish); 331 *stackp = stack = NULL; 332 } 333 } 334 335 bool ZMarkThreadLocalStacks::pop_slow(ZMarkStackAllocator* allocator, 336 ZMarkStripe* stripe, 337 ZMarkStack** stackp, 338 ZMarkStackEntry& entry) { 339 ZMarkStack* stack = *stackp; 340 341 for (;;) { 342 if (stack == NULL) { 343 // Try steal and install stack 344 *stackp = stack = stripe->steal_stack(); 345 if (stack == NULL) { 346 // Nothing to steal 347 return false; 348 } 349 } 350 351 if (stack->pop(entry)) { 352 // Success 353 return true; 354 } 355 356 // Free and uninstall stack 357 free_stack(allocator, stack); 358 *stackp = stack = NULL; 359 } 360 } 361 362 bool ZMarkThreadLocalStacks::flush(ZMarkStackAllocator* allocator, ZMarkStripeSet* stripes) { 363 bool flushed = false; 364 365 // Flush all stacks 366 for (size_t i = 0; i < stripes->nstripes(); i++) { 367 ZMarkStripe* const stripe = stripes->stripe_at(i); 368 ZMarkStack** const stackp = &_stacks[i]; 369 ZMarkStack* const stack = *stackp; 370 if (stack == NULL) { 371 continue; 372 } 373 374 // Free/Publish and uninstall stack 375 if (stack->is_empty()) { 376 free_stack(allocator, stack); 377 } else { 378 stripe->publish_stack(stack); 379 flushed = true; 380 } 381 *stackp = NULL; 382 } 383 384 return flushed; 385 } 386 387 void ZMarkThreadLocalStacks::free(ZMarkStackAllocator* allocator) { 388 // Free and uninstall magazine 389 if (_magazine != NULL) { 390 allocator->free_magazine(_magazine); 391 _magazine = NULL; 392 } 393 }