8149343: assert(rp->num_q() == no_of_gc_workers) failed: sanity
authorjmasa
Mon, 07 Mar 2016 11:28:06 -0800
changeset 37165 ed7da23aaa16
parent 37164 24bc914cc980
child 37167 53914a6631b5
child 37168 088adaf734f4
8149343: assert(rp->num_q() == no_of_gc_workers) failed: sanity Reviewed-by: tschatzl, kbarrett
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
hotspot/src/share/vm/gc/shared/referenceProcessor.cpp
hotspot/src/share/vm/gc/shared/referenceProcessor.hpp
hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Mon Mar 21 12:52:24 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Mon Mar 07 11:28:06 2016 -0800
@@ -4247,7 +4247,7 @@
     _workers(workers),
     _active_workers(n_workers)
   {
-    assert(n_workers > 0, "shouldn't call this otherwise");
+    g1h->ref_processor_stw()->set_active_mt_degree(n_workers);
   }
 
   // Executes the given task using concurrent marking worker threads.
@@ -4368,7 +4368,9 @@
     _queues(task_queues),
     _terminator(workers, _queues),
     _n_workers(workers)
-  { }
+  {
+    g1h->ref_processor_cm()->set_active_mt_degree(workers);
+  }
 
   void work(uint worker_id) {
     G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id);
@@ -4511,8 +4513,9 @@
     uint no_of_gc_workers = workers()->active_workers();
 
     // Parallel reference processing
-    assert(rp->num_q() == no_of_gc_workers, "sanity");
-    assert(no_of_gc_workers <= rp->max_num_q(), "sanity");
+    assert(no_of_gc_workers <= rp->max_num_q(),
+           "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
+           no_of_gc_workers,  rp->max_num_q());
 
     G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, no_of_gc_workers);
     stats = rp->process_discovered_references(&is_alive,
@@ -4548,8 +4551,9 @@
 
     uint n_workers = workers()->active_workers();
 
-    assert(rp->num_q() == n_workers, "sanity");
-    assert(n_workers <= rp->max_num_q(), "sanity");
+    assert(n_workers <= rp->max_num_q(),
+           "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
+           n_workers,  rp->max_num_q());
 
     G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, n_workers);
     rp->enqueue_discovered_references(&par_task_executor);
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp	Mon Mar 21 12:52:24 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp	Mon Mar 07 11:28:06 2016 -0800
@@ -134,7 +134,7 @@
   guarantee(!_discovering_refs, "Discovering refs?");
   for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
     guarantee(_discovered_refs[i].is_empty(),
-              "Found non-empty discovered list");
+              "Found non-empty discovered list at %u", i);
   }
 }
 #endif
@@ -683,19 +683,30 @@
 };
 
 #ifndef PRODUCT
-void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) {
+void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_refs) {
   if (!log_is_enabled(Trace, gc, ref)) {
     return;
   }
 
   stringStream st;
-  for (uint i = 0; i < _max_num_q; ++i) {
+  for (uint i = 0; i < active_length; ++i) {
     st.print(SIZE_FORMAT " ", ref_lists[i].length());
   }
   log_develop_trace(gc, ref)("%s= " SIZE_FORMAT, st.as_string(), total_refs);
+#ifdef ASSERT
+  for (uint i = active_length; i < _max_num_q; i++) {
+    assert(ref_lists[i].length() == 0, SIZE_FORMAT " unexpected References in %u",
+           ref_lists[i].length(), i);
+  }
+#endif
 }
 #endif
 
+void ReferenceProcessor::set_active_mt_degree(uint v) {
+  _num_q = v;
+  _next_id = 0;
+}
+
 // Balances reference queues.
 // Move entries from all queues[0, 1, ..., _max_num_q-1] to
 // queues[0, 1, ..., _num_q-1] because only the first _num_q
@@ -708,8 +719,8 @@
 
   for (uint i = 0; i < _max_num_q; ++i) {
     total_refs += ref_lists[i].length();
-    }
-  log_reflist_counts(ref_lists, total_refs);
+  }
+  log_reflist_counts(ref_lists, _max_num_q, total_refs);
   size_t avg_refs = total_refs / _num_q + 1;
   uint to_idx = 0;
   for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) {
@@ -771,10 +782,10 @@
   }
 #ifdef ASSERT
   size_t balanced_total_refs = 0;
-  for (uint i = 0; i < _max_num_q; ++i) {
+  for (uint i = 0; i < _num_q; ++i) {
     balanced_total_refs += ref_lists[i].length();
-    }
-  log_reflist_counts(ref_lists, balanced_total_refs);
+  }
+  log_reflist_counts(ref_lists, _num_q, balanced_total_refs);
   assert(total_refs == balanced_total_refs, "Balancing was incomplete");
 #endif
 }
@@ -868,7 +879,7 @@
       id = next_id();
     }
   }
-  assert(id < _max_num_q, "Id is out-of-bounds (call Freud?)");
+  assert(id < _max_num_q, "Id is out-of-bounds id %u and max id %u)", id, _max_num_q);
 
   // Get the discovered queue to which we will add
   DiscoveredList* list = NULL;
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp	Mon Mar 21 12:52:24 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp	Mon Mar 07 11:28:06 2016 -0800
@@ -225,7 +225,7 @@
 
   uint num_q()                             { return _num_q; }
   uint max_num_q()                         { return _max_num_q; }
-  void set_active_mt_degree(uint v)        { _num_q = v; }
+  void set_active_mt_degree(uint v);
 
   DiscoveredList* discovered_refs()        { return _discovered_refs; }
 
@@ -326,9 +326,11 @@
   // round-robin mod _num_q (not: _not_ mode _max_num_q)
   uint next_id() {
     uint id = _next_id;
+    assert(!_discovery_is_mt, "Round robin should only be used in serial discovery");
     if (++_next_id == _num_q) {
       _next_id = 0;
     }
+    assert(_next_id < _num_q, "_next_id %u _num_q %u _max_num_q %u", _next_id, _num_q, _max_num_q);
     return id;
   }
   DiscoveredList* get_discovered_list(ReferenceType rt);
@@ -340,7 +342,7 @@
   // Calculate the number of jni handles.
   size_t count_jni_refs();
 
-  void log_reflist_counts(DiscoveredList ref_lists[], size_t total_count) PRODUCT_RETURN;
+  void log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_count) PRODUCT_RETURN;
 
   // Balances reference queues.
   void balance_queues(DiscoveredList ref_lists[]);
--- a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java	Mon Mar 21 12:52:24 2016 +0100
+++ b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java	Mon Mar 07 11:28:06 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,6 +63,14 @@
     System.arraycopy(baseArgs,  0, finalArgs, extraArgs.length, baseArgs.length);
     pb_enabled = ProcessTools.createJavaProcessBuilder(finalArgs);
     verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()));
+
+    // Turn on parallel reference processing
+    String[] parRefProcArg = {"-XX:+ParallelRefProcEnabled", "-XX:-ShowMessageBoxOnError"};
+    String[] parRefArgs = new String[baseArgs.length + parRefProcArg.length];
+    System.arraycopy(parRefProcArg, 0, parRefArgs, 0,                parRefProcArg.length);
+    System.arraycopy(baseArgs,  0, parRefArgs, parRefProcArg.length, baseArgs.length);
+    pb_enabled = ProcessTools.createJavaProcessBuilder(parRefArgs);
+    verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()));
   }
 
   static class GCTest {