hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp
changeset 41176 ff9f64534cff
parent 41081 286019ba662d
child 41186 767efcf17936
equal deleted inserted replaced
41175:68d3c7c39153 41176:ff9f64534cff
   131   _bm.at_put_range(heapWordToOffset(mr.start()),
   131   _bm.at_put_range(heapWordToOffset(mr.start()),
   132                    heapWordToOffset(mr.end()), false);
   132                    heapWordToOffset(mr.end()), false);
   133 }
   133 }
   134 
   134 
   135 G1CMMarkStack::G1CMMarkStack() :
   135 G1CMMarkStack::G1CMMarkStack() :
   136   _reserved_space(),
   136   _max_chunk_capacity(0),
   137   _base(NULL),
   137   _base(NULL),
   138   _capacity(0),
   138   _chunk_capacity(0),
   139   _saved_index((size_t)AllBits),
   139   _out_of_memory(false),
   140   _should_expand(false) {
   140   _should_expand(false) {
   141   set_empty();
   141   set_empty();
   142 }
   142 }
   143 
   143 
   144 bool G1CMMarkStack::resize(size_t new_capacity) {
   144 bool G1CMMarkStack::resize(size_t new_capacity) {
   145   assert(is_empty(), "Only resize when stack is empty.");
   145   assert(is_empty(), "Only resize when stack is empty.");
   146   assert(new_capacity <= MarkStackSizeMax,
   146   assert(new_capacity <= _max_chunk_capacity,
   147          "Trying to resize stack to " SIZE_FORMAT " elements when the maximum is " SIZE_FORMAT, new_capacity, MarkStackSizeMax);
   147          "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity);
   148 
   148 
   149   size_t reservation_size = ReservedSpace::allocation_align_size_up(new_capacity * sizeof(oop));
   149   OopChunk* new_base = MmapArrayAllocator<OopChunk, mtGC>::allocate_or_null(new_capacity);
   150 
   150 
   151   ReservedSpace rs(reservation_size);
   151   if (new_base == NULL) {
   152   if (!rs.is_reserved()) {
   152     log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(OopChunk));
   153     log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " elements and size " SIZE_FORMAT "B.", new_capacity, reservation_size);
       
   154     return false;
   153     return false;
   155   }
   154   }
   156 
       
   157   VirtualSpace vs;
       
   158 
       
   159   if (!vs.initialize(rs, rs.size())) {
       
   160     rs.release();
       
   161     log_warning(gc)("Failed to commit memory for new overflow mark stack of size " SIZE_FORMAT "B.", rs.size());
       
   162     return false;
       
   163   }
       
   164 
       
   165   assert(vs.committed_size() == rs.size(), "Failed to commit all of the mark stack.");
       
   166 
       
   167   // Release old mapping.
   155   // Release old mapping.
   168   _reserved_space.release();
   156   if (_base != NULL) {
   169 
   157     MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
   170   // Save new mapping for future unmapping.
   158   }
   171   _reserved_space = rs;
   159 
   172 
   160   _base = new_base;
   173   MemTracker::record_virtual_memory_type((address)_reserved_space.base(), mtGC);
   161   _chunk_capacity = new_capacity;
   174 
       
   175   _base = (oop*) vs.low();
       
   176   _capacity = new_capacity;
       
   177   set_empty();
   162   set_empty();
   178   _should_expand = false;
   163   _should_expand = false;
   179 
   164 
   180   return true;
   165   return true;
   181 }
   166 }
   182 
   167 
   183 bool G1CMMarkStack::allocate(size_t capacity) {
   168 size_t G1CMMarkStack::capacity_alignment() {
   184   return resize(capacity);
   169   return (size_t)lcm(os::vm_allocation_granularity(), sizeof(OopChunk)) / sizeof(void*);
       
   170 }
       
   171 
       
   172 bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) {
       
   173   guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized.");
       
   174 
       
   175   size_t const OopChunkSizeInVoidStar = sizeof(OopChunk) / sizeof(void*);
       
   176 
       
   177   _max_chunk_capacity = (size_t)align_size_up(max_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
       
   178   size_t initial_chunk_capacity = (size_t)align_size_up(initial_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
       
   179 
       
   180   guarantee(initial_chunk_capacity <= _max_chunk_capacity,
       
   181             "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT,
       
   182             _max_chunk_capacity,
       
   183             initial_chunk_capacity);
       
   184 
       
   185   log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
       
   186                 initial_chunk_capacity, _max_chunk_capacity);
       
   187 
       
   188   return resize(initial_chunk_capacity);
   185 }
   189 }
   186 
   190 
   187 void G1CMMarkStack::expand() {
   191 void G1CMMarkStack::expand() {
   188   // Clear expansion flag
   192   // Clear expansion flag
   189   _should_expand = false;
   193   _should_expand = false;
   190 
   194 
   191   if (_capacity == MarkStackSizeMax) {
   195   if (_chunk_capacity == _max_chunk_capacity) {
   192     log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " elements.", _capacity);
   196     log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity);
   193     return;
   197     return;
   194   }
   198   }
   195   size_t old_capacity = _capacity;
   199   size_t old_capacity = _chunk_capacity;
   196   // Double capacity if possible
   200   // Double capacity if possible
   197   size_t new_capacity = MIN2(old_capacity * 2, MarkStackSizeMax);
   201   size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity);
   198 
   202 
   199   if (resize(new_capacity)) {
   203   if (resize(new_capacity)) {
   200     log_debug(gc)("Expanded marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
   204     log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
   201                   old_capacity, new_capacity);
   205                   old_capacity, new_capacity);
   202   } else {
   206   } else {
   203     log_warning(gc)("Failed to expand marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
   207     log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
   204                     old_capacity, new_capacity);
   208                     old_capacity, new_capacity);
   205   }
   209   }
   206 }
   210 }
   207 
   211 
   208 G1CMMarkStack::~G1CMMarkStack() {
   212 G1CMMarkStack::~G1CMMarkStack() {
   209   if (_base != NULL) {
   213   if (_base != NULL) {
   210     _base = NULL;
   214     MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
   211     _reserved_space.release();
   215   }
   212   }
   216 }
   213 }
   217 
   214 
   218 void G1CMMarkStack::add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem) {
   215 void G1CMMarkStack::par_push_arr(oop* buffer, size_t n) {
   219   elem->next = *list;
   216   MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
   220   *list = elem;
   217   size_t start = _index;
   221 }
   218   size_t next_index = start + n;
   222 
   219   if (next_index > _capacity) {
   223 void G1CMMarkStack::add_chunk_to_chunk_list(OopChunk* elem) {
   220     _overflow = true;
   224   MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
   221     return;
   225   add_chunk_to_list(&_chunk_list, elem);
   222   }
   226   _chunks_in_chunk_list++;
   223   // Otherwise.
   227 }
   224   _index = next_index;
   228 
   225   for (size_t i = 0; i < n; i++) {
   229 void G1CMMarkStack::add_chunk_to_free_list(OopChunk* elem) {
   226     size_t ind = start + i;
   230   MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
   227     assert(ind < _capacity, "By overflow test above.");
   231   add_chunk_to_list(&_free_list, elem);
   228     _base[ind] = buffer[i];
   232 }
   229   }
   233 
   230 }
   234 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_list(OopChunk* volatile* list) {
   231 
   235   OopChunk* result = *list;
   232 bool G1CMMarkStack::par_pop_arr(oop* buffer, size_t max, size_t* n) {
   236   if (result != NULL) {
   233   MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
   237     *list = (*list)->next;
   234   size_t index = _index;
   238   }
   235   if (index == 0) {
   239   return result;
   236     *n = 0;
   240 }
       
   241 
       
   242 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_chunk_list() {
       
   243   MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
       
   244   OopChunk* result = remove_chunk_from_list(&_chunk_list);
       
   245   if (result != NULL) {
       
   246     _chunks_in_chunk_list--;
       
   247   }
       
   248   return result;
       
   249 }
       
   250 
       
   251 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_free_list() {
       
   252   MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
       
   253   return remove_chunk_from_list(&_free_list);
       
   254 }
       
   255 
       
   256 G1CMMarkStack::OopChunk* G1CMMarkStack::allocate_new_chunk() {
       
   257   // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code.
       
   258   // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding
       
   259   // wraparound of _hwm.
       
   260   if (_hwm >= _chunk_capacity) {
       
   261     return NULL;
       
   262   }
       
   263 
       
   264   size_t cur_idx = Atomic::add(1, &_hwm) - 1;
       
   265   if (cur_idx >= _chunk_capacity) {
       
   266     return NULL;
       
   267   }
       
   268 
       
   269   OopChunk* result = ::new (&_base[cur_idx]) OopChunk;
       
   270   result->next = NULL;
       
   271   return result;
       
   272 }
       
   273 
       
   274 bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) {
       
   275   // Get a new chunk.
       
   276   OopChunk* new_chunk = remove_chunk_from_free_list();
       
   277 
       
   278   if (new_chunk == NULL) {
       
   279     // Did not get a chunk from the free list. Allocate from backing memory.
       
   280     new_chunk = allocate_new_chunk();
       
   281   }
       
   282 
       
   283   if (new_chunk == NULL) {
       
   284     _out_of_memory = true;
   237     return false;
   285     return false;
   238   } else {
   286   }
   239     size_t k = MIN2(max, index);
   287 
   240     size_t new_ind = index - k;
   288   Copy::conjoint_oops_atomic(ptr_arr, new_chunk->data, OopsPerChunk);
   241     for (size_t j = 0; j < k; j++) {
   289 
   242       buffer[j] = _base[new_ind + j];
   290   add_chunk_to_chunk_list(new_chunk);
   243     }
   291 
   244     _index = new_ind;
   292   return true;
   245     *n = k;
   293 }
   246     return true;
   294 
   247   }
   295 bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) {
   248 }
   296   OopChunk* cur = remove_chunk_from_chunk_list();
   249 
   297 
   250 void G1CMMarkStack::note_start_of_gc() {
   298   if (cur == NULL) {
   251   assert(_saved_index == (size_t)AllBits, "note_start_of_gc()/end_of_gc() calls bracketed incorrectly");
   299     return false;
   252   _saved_index = _index;
   300   }
   253 }
   301 
   254 
   302   Copy::conjoint_oops_atomic(cur->data, ptr_arr, OopsPerChunk);
   255 void G1CMMarkStack::note_end_of_gc() {
   303 
   256   guarantee(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index);
   304   add_chunk_to_free_list(cur);
   257 
   305   return true;
   258   _saved_index = (size_t)AllBits;
   306 }
       
   307 
       
   308 void G1CMMarkStack::set_empty() {
       
   309   _chunks_in_chunk_list = 0;
       
   310   _hwm = 0;
       
   311   clear_out_of_memory();
       
   312   _chunk_list = NULL;
       
   313   _free_list = NULL;
   259 }
   314 }
   260 
   315 
   261 G1CMRootRegions::G1CMRootRegions() :
   316 G1CMRootRegions::G1CMRootRegions() :
   262   _cm(NULL), _scan_in_progress(false),
   317   _cm(NULL), _scan_in_progress(false),
   263   _should_abort(false), _claimed_survivor_index(0) { }
   318   _should_abort(false), _claimed_survivor_index(0) { }
   481         }
   536         }
   482       }
   537       }
   483     }
   538     }
   484   }
   539   }
   485 
   540 
   486   if (!_global_mark_stack.allocate(MarkStackSize)) {
   541   if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) {
   487     vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
   542     vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
   488     return;
       
   489   }
   543   }
   490 
   544 
   491   _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
   545   _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
   492   _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
   546   _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
   493 
   547 
  1693 
  1747 
  1694     // The do_oop work routines of the keep_alive and drain_marking_stack
  1748     // The do_oop work routines of the keep_alive and drain_marking_stack
  1695     // oop closures will set the has_overflown flag if we overflow the
  1749     // oop closures will set the has_overflown flag if we overflow the
  1696     // global marking stack.
  1750     // global marking stack.
  1697 
  1751 
  1698     assert(_global_mark_stack.overflow() || _global_mark_stack.is_empty(),
  1752     assert(_global_mark_stack.is_out_of_memory() || _global_mark_stack.is_empty(),
  1699             "mark stack should be empty (unless it overflowed)");
  1753             "Mark stack should be empty (unless it is out of memory)");
  1700 
  1754 
  1701     if (_global_mark_stack.overflow()) {
  1755     if (_global_mark_stack.is_out_of_memory()) {
  1702       // This should have been done already when we tried to push an
  1756       // This should have been done already when we tried to push an
  1703       // entry on to the global mark stack. But let's do it again.
  1757       // entry on to the global mark stack. But let's do it again.
  1704       set_has_overflown();
  1758       set_has_overflown();
  1705     }
  1759     }
  1706 
  1760 
  2341   _refs_reached_limit  = _real_refs_reached_limit -
  2395   _refs_reached_limit  = _real_refs_reached_limit -
  2342     3 * refs_reached_period / 4;
  2396     3 * refs_reached_period / 4;
  2343 }
  2397 }
  2344 
  2398 
  2345 void G1CMTask::move_entries_to_global_stack() {
  2399 void G1CMTask::move_entries_to_global_stack() {
  2346   // local array where we'll store the entries that will be popped
  2400   // Local array where we'll store the entries that will be popped
  2347   // from the local queue
  2401   // from the local queue.
  2348   oop buffer[global_stack_transfer_size];
  2402   oop buffer[G1CMMarkStack::OopsPerChunk];
  2349 
  2403 
  2350   int n = 0;
  2404   size_t n = 0;
  2351   oop obj;
  2405   oop obj;
  2352   while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) {
  2406   while (n < G1CMMarkStack::OopsPerChunk && _task_queue->pop_local(obj)) {
  2353     buffer[n] = obj;
  2407     buffer[n] = obj;
  2354     ++n;
  2408     ++n;
  2355   }
  2409   }
       
  2410   if (n < G1CMMarkStack::OopsPerChunk) {
       
  2411     buffer[n] = NULL;
       
  2412   }
  2356 
  2413 
  2357   if (n > 0) {
  2414   if (n > 0) {
  2358     // we popped at least one entry from the local queue
  2415     if (!_cm->mark_stack_push(buffer)) {
  2359 
       
  2360     if (!_cm->mark_stack_push(buffer, n)) {
       
  2361       set_has_aborted();
  2416       set_has_aborted();
  2362     }
  2417     }
  2363   }
  2418   }
  2364 
  2419 
  2365   // this operation was quite expensive, so decrease the limits
  2420   // This operation was quite expensive, so decrease the limits.
  2366   decrease_limits();
  2421   decrease_limits();
  2367 }
  2422 }
  2368 
  2423 
  2369 void G1CMTask::get_entries_from_global_stack() {
  2424 bool G1CMTask::get_entries_from_global_stack() {
  2370   // local array where we'll store the entries that will be popped
  2425   // Local array where we'll store the entries that will be popped
  2371   // from the global stack.
  2426   // from the global stack.
  2372   oop buffer[global_stack_transfer_size];
  2427   oop buffer[G1CMMarkStack::OopsPerChunk];
  2373   size_t n;
  2428 
  2374   _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n);
  2429   if (!_cm->mark_stack_pop(buffer)) {
  2375   assert(n <= global_stack_transfer_size,
  2430     return false;
  2376          "we should not pop more than the given limit");
  2431   }
  2377   if (n > 0) {
  2432 
  2378     // yes, we did actually pop at least one entry
  2433   // We did actually pop at least one entry.
  2379     for (size_t i = 0; i < n; ++i) {
  2434   for (size_t i = 0; i < G1CMMarkStack::OopsPerChunk; ++i) {
  2380       bool success = _task_queue->push(buffer[i]);
  2435     oop elem = buffer[i];
  2381       // We only call this when the local queue is empty or under a
  2436     if (elem == NULL) {
  2382       // given target limit. So, we do not expect this push to fail.
  2437       break;
  2383       assert(success, "invariant");
  2438     }
  2384     }
  2439     bool success = _task_queue->push(elem);
  2385   }
  2440     // We only call this when the local queue is empty or under a
  2386 
  2441     // given target limit. So, we do not expect this push to fail.
  2387   // this operation was quite expensive, so decrease the limits
  2442     assert(success, "invariant");
       
  2443   }
       
  2444 
       
  2445   // This operation was quite expensive, so decrease the limits
  2388   decrease_limits();
  2446   decrease_limits();
       
  2447   return true;
  2389 }
  2448 }
  2390 
  2449 
  2391 void G1CMTask::drain_local_queue(bool partially) {
  2450 void G1CMTask::drain_local_queue(bool partially) {
  2392   if (has_aborted()) return;
  2451   if (has_aborted()) return;
  2393 
  2452 
  2427   // drain the global stack.
  2486   // drain the global stack.
  2428   assert(partially || _task_queue->size() == 0, "invariant");
  2487   assert(partially || _task_queue->size() == 0, "invariant");
  2429 
  2488 
  2430   // Decide what the target size is, depending whether we're going to
  2489   // Decide what the target size is, depending whether we're going to
  2431   // drain it partially (so that other tasks can steal if they run out
  2490   // drain it partially (so that other tasks can steal if they run out
  2432   // of things to do) or totally (at the very end).  Notice that,
  2491   // of things to do) or totally (at the very end).
  2433   // because we move entries from the global stack in chunks or
  2492   // Notice that when draining the global mark stack partially, due to the racyness
  2434   // because another task might be doing the same, we might in fact
  2493   // of the mark stack size update we might in fact drop below the target. But,
  2435   // drop below the target. But, this is not a problem.
  2494   // this is not a problem.
  2436   size_t target_size;
  2495   // In case of total draining, we simply process until the global mark stack is
       
  2496   // totally empty, disregarding the size counter.
  2437   if (partially) {
  2497   if (partially) {
  2438     target_size = _cm->partial_mark_stack_size_target();
  2498     size_t const target_size = _cm->partial_mark_stack_size_target();
       
  2499     while (!has_aborted() && _cm->mark_stack_size() > target_size) {
       
  2500       if (get_entries_from_global_stack()) {
       
  2501         drain_local_queue(partially);
       
  2502       }
       
  2503     }
  2439   } else {
  2504   } else {
  2440     target_size = 0;
  2505     while (!has_aborted() && get_entries_from_global_stack()) {
  2441   }
       
  2442 
       
  2443   if (_cm->mark_stack_size() > target_size) {
       
  2444     while (!has_aborted() && _cm->mark_stack_size() > target_size) {
       
  2445       get_entries_from_global_stack();
       
  2446       drain_local_queue(partially);
  2506       drain_local_queue(partially);
  2447     }
  2507     }
  2448   }
  2508   }
  2449 }
  2509 }
  2450 
  2510