Print this page
rev 2891 : 7120038: G1: ParallelGCThreads==0 is broken
Summary: Running G1 with ParallelGCThreads==0 results in various crashes and asserts. Most of these are caused by unguarded references to the worker threads array or an incorrect number of active workers.
Reviewed-by:

Split Close
Expand all
Collapse all
          --- old/src/share/vm/gc_implementation/g1/concurrentMark.cpp
          +++ new/src/share/vm/gc_implementation/g1/concurrentMark.cpp
↓ open down ↓ 1111 lines elided ↑ open up ↑
1112 1112                            ConcurrentMarkThread* cmt) :
1113 1113        AbstractGangTask("Concurrent Mark"), _cm(cm), _cmt(cmt) { }
1114 1114  
1115 1115    ~CMConcurrentMarkingTask() { }
1116 1116  };
1117 1117  
1118 1118  // Calculates the number of active workers for a concurrent
1119 1119  // phase.
1120 1120  int ConcurrentMark::calc_parallel_marking_threads() {
1121 1121  
1122      -  size_t n_conc_workers;
1123      -  if (!G1CollectedHeap::use_parallel_gc_threads()) {
1124      -    n_conc_workers = 1;
1125      -  } else {
     1122 +  size_t n_conc_workers = 0;
     1123 +  if (G1CollectedHeap::use_parallel_gc_threads()) {
1126 1124      if (!UseDynamicNumberOfGCThreads ||
1127 1125          (!FLAG_IS_DEFAULT(ConcGCThreads) &&
1128 1126           !ForceDynamicNumberOfGCThreads)) {
1129 1127        n_conc_workers = max_parallel_marking_threads();
1130 1128      } else {
1131 1129        n_conc_workers =
1132 1130          AdaptiveSizePolicy::calc_default_active_workers(
1133 1131                                       max_parallel_marking_threads(),
1134 1132                                       1, /* Minimum workers */
1135 1133                                       parallel_marking_threads(),
1136 1134                                       Threads::number_of_non_daemon_threads());
1137 1135        // Don't scale down "n_conc_workers" by scale_parallel_threads() because
1138 1136        // that scaling has already gone into "_max_parallel_marking_threads".
1139 1137      }
     1138 +    assert(n_conc_workers > 0, "Always need at least 1");
1140 1139    }
1141      -  assert(n_conc_workers > 0, "Always need at least 1");
1142      -  return (int) MAX2(n_conc_workers, (size_t) 1);
     1140 +  return (int) MAX2(n_conc_workers, max_parallel_marking_threads());
1143 1141  }
1144 1142  
1145 1143  void ConcurrentMark::markFromRoots() {
1146 1144    // we might be tempted to assert that:
1147 1145    // assert(asynch == !SafepointSynchronize::is_at_safepoint(),
1148 1146    //        "inconsistent argument?");
1149 1147    // However that wouldn't be right, because it's possible that
1150 1148    // a safepoint is indeed in progress as a younger generation
1151 1149    // stop-the-world GC happens even as we mark in this generation.
1152 1150  
1153 1151    _restart_for_overflow = false;
1154      -
1155      -  // Parallel task terminator is set in "set_phase()".
1156 1152    force_overflow_conc()->init();
1157 1153  
1158 1154    // _g1h has _n_par_threads
1159      -
1160 1155    _parallel_marking_threads = calc_parallel_marking_threads();
1161 1156    assert(parallel_marking_threads() <= max_parallel_marking_threads(),
1162 1157      "Maximum number of marking threads exceeded");
1163      -  _parallel_workers->set_active_workers((int)_parallel_marking_threads);
1164      -  // Don't set _n_par_threads because it affects MT in proceess_strong_roots()
1165      -  // and the decisions on that MT processing is made elsewhere.
1166 1158  
1167      -  assert( _parallel_workers->active_workers() > 0, "Should have been set");
1168      -  set_phase(_parallel_workers->active_workers(), true /* concurrent */);
     1159 +  size_t active_workers = MAX2((size_t) 1, parallel_marking_threads());
     1160 +
     1161 +  // Parallel task terminator is set in "set_phase()"
     1162 +  set_phase(active_workers, true /* concurrent */);
1169 1163  
1170 1164    CMConcurrentMarkingTask markingTask(this, cmThread());
1171 1165    if (parallel_marking_threads() > 0) {
     1166 +    _parallel_workers->set_active_workers((int)active_workers);
     1167 +    // Don't set _n_par_threads because it affects MT in proceess_strong_roots()
     1168 +    // and the decisions on that MT processing is made elsewhere.
     1169 +    assert(_parallel_workers->active_workers() > 0, "Should have been set");
1172 1170      _parallel_workers->run_task(&markingTask);
1173 1171    } else {
1174 1172      markingTask.work(0);
1175 1173    }
1176 1174    print_stats();
1177 1175  }
1178 1176  
1179 1177  void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
1180 1178    // world is stopped at this checkpoint
1181 1179    assert(SafepointSynchronize::is_at_safepoint(),
↓ open down ↓ 576 lines elided ↑ open up ↑
1758 1756                       /* option      */ VerifyOption_G1UsePrevMarking);
1759 1757    }
1760 1758  
1761 1759    G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy();
1762 1760    g1p->record_concurrent_mark_cleanup_start();
1763 1761  
1764 1762    double start = os::elapsedTime();
1765 1763  
1766 1764    HeapRegionRemSet::reset_for_cleanup_tasks();
1767 1765  
1768      -  g1h->set_par_threads();
1769      -  size_t n_workers = g1h->n_par_threads();
     1766 +  size_t n_workers;
     1767 +
1770 1768  
1771 1769    // Do counting once more with the world stopped for good measure.
1772 1770    G1ParFinalCountTask g1_par_count_task(g1h, nextMarkBitMap(),
1773 1771                                          &_region_bm, &_card_bm);
1774 1772    if (G1CollectedHeap::use_parallel_gc_threads()) {
1775 1773      assert(g1h->check_heap_region_claim_values(
1776 1774                                                 HeapRegion::InitialClaimValue),
1777 1775             "sanity check");
1778      -
     1776 +    
     1777 +    g1h->set_par_threads();
     1778 +    n_workers = g1h->n_par_threads();
1779 1779      assert(g1h->n_par_threads() == (int) n_workers,
1780      -      "Should not have been reset");
     1780 +           "Should not have been reset");
1781 1781      g1h->workers()->run_task(&g1_par_count_task);
1782 1782      // Done with the parallel phase so reset to 0.
1783 1783      g1h->set_par_threads(0);
1784 1784  
1785 1785      assert(g1h->check_heap_region_claim_values(
1786 1786                                               HeapRegion::FinalCountClaimValue),
1787 1787             "sanity check");
1788 1788    } else {
     1789 +    n_workers = 1;
1789 1790      g1_par_count_task.work(0);
1790 1791    }
1791 1792  
1792 1793    size_t known_garbage_bytes =
1793 1794      g1_par_count_task.used_bytes() - g1_par_count_task.live_bytes();
1794 1795    g1p->set_known_garbage_bytes(known_garbage_bytes);
1795 1796  
1796 1797    size_t start_used_bytes = g1h->used();
1797 1798    _at_least_one_mark_complete = true;
1798 1799    g1h->set_marking_complete();
↓ open down ↓ 45 lines elided ↑ open up ↑
1844 1845      // concurrently. Notify anyone else that might be wanting free
1845 1846      // regions that there will be more free regions coming soon.
1846 1847      g1h->set_free_regions_coming();
1847 1848    }
1848 1849    double note_end_end = os::elapsedTime();
1849 1850    if (G1PrintParCleanupStats) {
1850 1851      gclog_or_tty->print_cr("  note end of marking: %8.3f ms.",
1851 1852                             (note_end_end - note_end_start)*1000.0);
1852 1853    }
1853 1854  
1854      -
1855 1855    // call below, since it affects the metric by which we sort the heap
1856 1856    // regions.
1857 1857    if (G1ScrubRemSets) {
1858 1858      double rs_scrub_start = os::elapsedTime();
1859 1859      G1ParScrubRemSetTask g1_par_scrub_rs_task(g1h, &_region_bm, &_card_bm);
1860 1860      if (G1CollectedHeap::use_parallel_gc_threads()) {
1861 1861        g1h->set_par_threads((int)n_workers);
1862 1862        g1h->workers()->run_task(&g1_par_scrub_rs_task);
1863 1863        g1h->set_par_threads(0);
1864 1864  
↓ open down ↓ 457 lines elided ↑ open up ↑
2322 2322          task->do_marking_step(1000000000.0 /* something very large */,
2323 2323                                true /* do_stealing    */,
2324 2324                                true /* do_termination */);
2325 2325        } while (task->has_aborted() && !_cm->has_overflown());
2326 2326        // If we overflow, then we do not want to restart. We instead
2327 2327        // want to abort remark and do concurrent marking again.
2328 2328        task->record_end_time();
2329 2329      }
2330 2330    }
2331 2331  
2332      -  CMRemarkTask(ConcurrentMark* cm) :
     2332 +  CMRemarkTask(ConcurrentMark* cm, int active_workers) :
2333 2333      AbstractGangTask("Par Remark"), _cm(cm) {
2334      -    _cm->terminator()->reset_for_reuse(cm->_g1h->workers()->active_workers());
     2334 +    _cm->terminator()->reset_for_reuse(active_workers);
2335 2335    }
2336 2336  };
2337 2337  
2338 2338  void ConcurrentMark::checkpointRootsFinalWork() {
2339 2339    ResourceMark rm;
2340 2340    HandleMark   hm;
2341 2341    G1CollectedHeap* g1h = G1CollectedHeap::heap();
2342 2342  
2343 2343    g1h->ensure_parsability(false);
2344 2344  
↓ open down ↓ 5 lines elided ↑ open up ↑
2350 2350        assert(active_workers > 0, "Should have been set earlier");
2351 2351        active_workers = ParallelGCThreads;
2352 2352        g1h->workers()->set_active_workers(active_workers);
2353 2353      }
2354 2354      set_phase(active_workers, false /* concurrent */);
2355 2355      // Leave _parallel_marking_threads at it's
2356 2356      // value originally calculated in the ConcurrentMark
2357 2357      // constructor and pass values of the active workers
2358 2358      // through the gang in the task.
2359 2359  
2360      -    CMRemarkTask remarkTask(this);
     2360 +    CMRemarkTask remarkTask(this, active_workers);
2361 2361      g1h->set_par_threads(active_workers);
2362 2362      g1h->workers()->run_task(&remarkTask);
2363 2363      g1h->set_par_threads(0);
2364 2364    } else {
2365 2365      G1CollectedHeap::StrongRootsScope srs(g1h);
2366 2366      // this is remark, so we'll use up all available threads
2367 2367      int active_workers = 1;
2368 2368      set_phase(active_workers, false /* concurrent */);
2369 2369  
2370      -    CMRemarkTask remarkTask(this);
     2370 +    CMRemarkTask remarkTask(this, active_workers);
2371 2371      // We will start all available threads, even if we decide that the
2372 2372      // active_workers will be fewer. The extra ones will just bail out
2373 2373      // immediately.
2374 2374      remarkTask.work(0);
2375 2375    }
2376 2376    SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
2377 2377    guarantee(satb_mq_set.completed_buffers_num() == 0, "invariant");
2378 2378  
2379 2379    print_stats();
2380 2380  
↓ open down ↓ 735 lines elided ↑ open up ↑
3116 3116  
3117 3117  void ConcurrentMark::complete_marking_in_collection_set() {
3118 3118    G1CollectedHeap* g1h =  G1CollectedHeap::heap();
3119 3119  
3120 3120    if (!g1h->mark_in_progress()) {
3121 3121      g1h->g1_policy()->record_mark_closure_time(0.0);
3122 3122      return;
3123 3123    }
3124 3124  
3125 3125    double start = os::elapsedTime();
3126      -  int n_workers = g1h->workers()->total_workers();
3127      -
3128 3126    G1ParCompleteMarkInCSetTask complete_mark_task(g1h, this);
3129 3127  
3130 3128    assert(g1h->check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity");
3131 3129  
3132 3130    if (G1CollectedHeap::use_parallel_gc_threads()) {
     3131 +    int n_workers = g1h->workers()->active_workers();
3133 3132      g1h->set_par_threads(n_workers);
3134 3133      g1h->workers()->run_task(&complete_mark_task);
3135 3134      g1h->set_par_threads(0);
3136 3135    } else {
3137 3136      complete_mark_task.work(0);
3138 3137    }
3139 3138  
3140 3139    assert(g1h->check_cset_heap_region_claim_values(HeapRegion::CompleteMarkCSetClaimValue), "sanity");
3141 3140  
3142 3141    // Now reset the claim values in the regions in the collection set.
↓ open down ↓ 1645 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX