changeset 4305:c5c01d4cd7d9 hs24-b37

Merge
author amurillo
date Thu, 21 Mar 2013 11:12:14 -0700
parents 06db2de2922a 5bcfc2ed94a5
children 72e4bc0bcbd2
files
diffstat 30 files changed, 318 insertions(+), 209 deletions(-) [+]
line wrap: on
line diff
--- a/make/hotspot_version	Wed Mar 20 14:47:35 2013 -0700
+++ b/make/hotspot_version	Thu Mar 21 11:12:14 2013 -0700
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=24
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=36
+HS_BUILD_NUMBER=37
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=7
--- a/src/os/bsd/vm/os_bsd.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/os/bsd/vm/os_bsd.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -55,6 +55,7 @@
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
 #include "services/attachListener.hpp"
+#include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_bsd.inline.hpp"
 #include "utilities/decoder.hpp"
@@ -3315,13 +3316,25 @@
      return NULL;
   }
 
+  // The memory is committed
+  address pc = CALLER_PC;
+  MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc);
+  MemTracker::record_virtual_memory_commit((address)addr, bytes, pc);
+
   return addr;
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
   // detaching the SHM segment will also delete it, see reserve_memory_special()
   int rslt = shmdt(base);
-  return rslt == 0;
+  if (rslt == 0) {
+    MemTracker::record_virtual_memory_uncommit((address)base, bytes);
+    MemTracker::record_virtual_memory_release((address)base, bytes);
+    return true;
+  } else {
+    return false;
+  }
+
 }
 
 size_t os::large_page_size() {
--- a/src/os/linux/vm/os_linux.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/os/linux/vm/os_linux.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -55,6 +55,7 @@
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
 #include "services/attachListener.hpp"
+#include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_linux.inline.hpp"
 #include "utilities/decoder.hpp"
@@ -3116,13 +3117,24 @@
     numa_make_global(addr, bytes);
   }
 
+  // The memory is committed
+  address pc = CALLER_PC;
+  MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc);
+  MemTracker::record_virtual_memory_commit((address)addr, bytes, pc);
+
   return addr;
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
   // detaching the SHM segment will also delete it, see reserve_memory_special()
   int rslt = shmdt(base);
-  return rslt == 0;
+  if (rslt == 0) {
+    MemTracker::record_virtual_memory_uncommit((address)base, bytes);
+    MemTracker::record_virtual_memory_release((address)base, bytes);
+    return true;
+  } else {
+   return false;
+  }
 }
 
 size_t os::large_page_size() {
--- a/src/os/solaris/vm/os_solaris.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/os/solaris/vm/os_solaris.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -3426,13 +3426,25 @@
   if ((retAddr != NULL) && UseNUMAInterleaving) {
     numa_make_global(retAddr, size);
   }
+
+  // The memory is committed
+  address pc = CALLER_PC;
+  MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc);
+  MemTracker::record_virtual_memory_commit((address)retAddr, size, pc);
+
   return retAddr;
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
   // detaching the SHM segment will also delete it, see reserve_memory_special()
   int rslt = shmdt(base);
-  return rslt == 0;
+  if (rslt == 0) {
+    MemTracker::record_virtual_memory_uncommit((address)base, bytes);
+    MemTracker::record_virtual_memory_release((address)base, bytes);
+    return true;
+  } else {
+   return false;
+  }
 }
 
 size_t os::large_page_size() {
--- a/src/os/windows/vm/os_windows.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/os/windows/vm/os_windows.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -58,6 +58,7 @@
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
 #include "services/attachListener.hpp"
+#include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_windows.inline.hpp"
 #include "utilities/decoder.hpp"
@@ -2808,7 +2809,7 @@
                                 PAGE_READWRITE);
   // If reservation failed, return NULL
   if (p_buf == NULL) return NULL;
-
+  MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC);
   os::release_memory(p_buf, bytes + chunk_size);
 
   // we still need to round up to a page boundary (in case we are using large pages)
@@ -2870,6 +2871,11 @@
       if (next_alloc_addr > p_buf) {
         // Some memory was committed so release it.
         size_t bytes_to_release = bytes - bytes_remaining;
+        // NMT has yet to record any individual blocks, so it
+        // need to create a dummy 'reserve' record to match
+        // the release.
+        MemTracker::record_virtual_memory_reserve((address)p_buf,
+          bytes_to_release, CALLER_PC);
         os::release_memory(p_buf, bytes_to_release);
       }
 #ifdef ASSERT
@@ -2881,10 +2887,19 @@
 #endif
       return NULL;
     }
+
     bytes_remaining -= bytes_to_rq;
     next_alloc_addr += bytes_to_rq;
     count++;
   }
+  // Although the memory is allocated individually, it is returned as one.
+  // NMT records it as one block.
+  address pc = CALLER_PC;
+  MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc);
+  if ((flags & MEM_COMMIT) != 0) {
+    MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc);
+  }
+
   // made it this far, success
   return p_buf;
 }
@@ -3071,11 +3086,20 @@
     // normal policy just allocate it all at once
     DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
     char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot);
+    if (res != NULL) {
+      address pc = CALLER_PC;
+      MemTracker::record_virtual_memory_reserve((address)res, bytes, pc);
+      MemTracker::record_virtual_memory_commit((address)res, bytes, pc);
+    }
+
     return res;
   }
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
+  assert(base != NULL, "Sanity check");
+  // Memory allocated via reserve_memory_special() is committed
+  MemTracker::record_virtual_memory_uncommit((address)base, bytes);
   return release_memory(base, bytes);
 }
 
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -5903,6 +5903,8 @@
                                 &cmsKeepAliveClosure, false /* !preclean */);
   {
     GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm);
+
+    ReferenceProcessorStats stats;
     if (rp->processing_is_mt()) {
       // Set the degree of MT here.  If the discovery is done MT, there
       // may have been a different number of threads doing the discovery
@@ -5921,18 +5923,20 @@
       }
       rp->set_active_mt_degree(active_workers);
       CMSRefProcTaskExecutor task_executor(*this);
-      rp->process_discovered_references(&_is_alive_closure,
+      stats = rp->process_discovered_references(&_is_alive_closure,
                                         &cmsKeepAliveClosure,
                                         &cmsDrainMarkingStackClosure,
                                         &task_executor,
                                         _gc_timer_cm);
     } else {
-      rp->process_discovered_references(&_is_alive_closure,
+      stats = rp->process_discovered_references(&_is_alive_closure,
                                         &cmsKeepAliveClosure,
                                         &cmsDrainMarkingStackClosure,
                                         NULL,
                                         _gc_timer_cm);
     }
+    _gc_tracer_cm->report_gc_reference_stats(stats);
+
     verify_work_stacks_empty();
   }
 
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -37,6 +37,7 @@
 #include "gc_implementation/g1/heapRegionSeq.inline.hpp"
 #include "gc_implementation/shared/vmGCOperations.hpp"
 #include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/gcTraceTime.hpp"
 #include "memory/genOopClosures.inline.hpp"
 #include "memory/referencePolicy.hpp"
@@ -2325,6 +2326,7 @@
     G1CMRefProcTaskExecutor par_task_executor(g1h, this,
                                               g1h->workers(), active_workers);
 
+    ReferenceProcessorStats stats;
     if (rp->processing_is_mt()) {
       // Set the degree of MT here.  If the discovery is done MT, there
       // may have been a different number of threads doing the discovery
@@ -2333,7 +2335,7 @@
       // balance_all_queues() and balance_queues()).
       rp->set_active_mt_degree(active_workers);
 
-      rp->process_discovered_references(&g1_is_alive,
+      stats = rp->process_discovered_references(&g1_is_alive,
                                       &g1_keep_alive,
                                       &g1_drain_mark_stack,
                                       &par_task_executor,
@@ -2343,13 +2345,15 @@
       // will set the has_overflown flag if we overflow the global marking
       // stack.
     } else {
-      rp->process_discovered_references(&g1_is_alive,
+      stats = rp->process_discovered_references(&g1_is_alive,
                                         &g1_keep_alive,
                                         &g1_drain_mark_stack,
                                         NULL,
                                         g1h->gc_timer_cm());
     }
 
+    g1h->gc_tracer_cm()->report_gc_reference_stats(stats);
+
     assert(_markStack.overflow() || _markStack.isEmpty(),
             "mark stack should be empty (unless it overflowed)");
     if (_markStack.overflow()) {
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -5584,22 +5584,28 @@
   // Setup the soft refs policy...
   rp->setup_policy(false);
 
+  ReferenceProcessorStats stats;
   if (!rp->processing_is_mt()) {
     // Serial reference processing...
-    rp->process_discovered_references(&is_alive,
-                                      &keep_alive,
-                                      &drain_queue,
-                                      NULL,
-                                      _gc_timer_stw);
+    stats = rp->process_discovered_references(&is_alive,
+                                              &keep_alive,
+                                              &drain_queue,
+                                              NULL,
+                                              _gc_timer_stw);
   } else {
     // Parallel reference processing
     assert(rp->num_q() == no_of_gc_workers, "sanity");
     assert(no_of_gc_workers <= rp->max_num_q(), "sanity");
 
     G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers);
-    rp->process_discovered_references(&is_alive, &keep_alive, &drain_queue, &par_task_executor, _gc_timer_stw);
-  }
-
+    stats = rp->process_discovered_references(&is_alive,
+                                              &keep_alive,
+                                              &drain_queue,
+                                              &par_task_executor,
+                                              _gc_timer_stw);
+  }
+
+  _gc_tracer_stw->report_gc_reference_stats(stats);
   // We have completed copying any necessary live referent objects
   // (that were not copied during the actual pause) so we can
   // retire any active alloc buffers
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -1178,6 +1178,7 @@
   ReferenceProcessor* ref_processor_cm() const { return _ref_processor_cm; }
 
   ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; }
+  G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; }
 
   virtual size_t capacity() const;
   virtual size_t used() const;
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -148,11 +148,13 @@
   assert(rp == G1CollectedHeap::heap()->ref_processor_stw(), "Sanity");
 
   rp->setup_policy(clear_all_softrefs);
-  rp->process_discovered_references(&GenMarkSweep::is_alive,
-                                    &GenMarkSweep::keep_alive,
-                                    &GenMarkSweep::follow_stack_closure,
-                                    NULL,
-                                    gc_timer());
+  const ReferenceProcessorStats& stats =
+    rp->process_discovered_references(&GenMarkSweep::is_alive,
+                                      &GenMarkSweep::keep_alive,
+                                      &GenMarkSweep::follow_stack_closure,
+                                      NULL,
+                                      gc_timer());
+  gc_tracer()->report_gc_reference_stats(stats);
 
   // Follow system dictionary roots and unload classes
   bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -33,6 +33,7 @@
 #include "gc_implementation/shared/gcTimer.hpp"
 #include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "gc_implementation/shared/spaceDecorator.hpp"
 #include "memory/defNewGeneration.inline.hpp"
 #include "memory/genCollectedHeap.hpp"
@@ -79,7 +80,6 @@
                       work_queue_set_, &term_),
   _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
   _keep_alive_closure(&_scan_weak_ref_closure),
-  _promotion_failure_size(0),
   _strong_roots_time(0.0), _term_time(0.0)
 {
   #if TASKQUEUE_STATS
@@ -283,13 +283,10 @@
   }
 }
 
-void ParScanThreadState::print_and_clear_promotion_failure_size() {
-  if (_promotion_failure_size != 0) {
-    if (PrintPromotionFailure) {
-      gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
-        _thread_num, _promotion_failure_size);
-    }
-    _promotion_failure_size = 0;
+void ParScanThreadState::print_promotion_failure_size() {
+  if (_promotion_failed_info.promotion_failed() && PrintPromotionFailure) {
+    gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
+                        _thread_num, _promotion_failed_info.first_size());
   }
 }
 
@@ -309,6 +306,7 @@
 
   inline ParScanThreadState& thread_state(int i);
 
+  void trace_promotion_failed(YoungGCTracer& gc_tracer);
   void reset(int active_workers, bool promotion_failed);
   void flush();
 
@@ -357,13 +355,21 @@
   return ((ParScanThreadState*)_data)[i];
 }
 
+void ParScanThreadStateSet::trace_promotion_failed(YoungGCTracer& gc_tracer) {
+  for (int i = 0; i < length(); ++i) {
+    if (thread_state(i).promotion_failed()) {
+      gc_tracer.report_promotion_failed(thread_state(i).promotion_failed_info());
+      thread_state(i).promotion_failed_info().reset();
+    }
+  }
+}
 
 void ParScanThreadStateSet::reset(int active_threads, bool promotion_failed)
 {
   _term.reset_for_reuse(active_threads);
   if (promotion_failed) {
     for (int i = 0; i < length(); ++i) {
-      thread_state(i).print_and_clear_promotion_failure_size();
+      thread_state(i).print_promotion_failure_size();
     }
   }
 }
@@ -874,6 +880,8 @@
 }
 
 
+// A Generation that does parallel young-gen collection.
+
 bool ParNewGeneration::_avoid_promotion_undo = false;
 
 void ParNewGeneration::adjust_desired_tenuring_threshold() {
@@ -882,7 +890,30 @@
     age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize);
 }
 
-// A Generation that does parallel young-gen collection.
+void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer) {
+  assert(_promo_failure_scan_stack.is_empty(), "post condition");
+  _promo_failure_scan_stack.clear(true); // Clear cached segments.
+
+  remove_forwarding_pointers();
+  if (PrintGCDetails) {
+    gclog_or_tty->print(" (promotion failed)");
+  }
+  // All the spaces are in play for mark-sweep.
+  swap_spaces();  // Make life simpler for CMS || rescan; see 6483690.
+  from()->set_next_compaction_space(to());
+  gch->set_incremental_collection_failed();
+  // Inform the next generation that a promotion failure occurred.
+  _next_gen->promotion_failure_occurred();
+
+  // Trace promotion failure in the parallel GC threads
+  thread_state_set.trace_promotion_failed(gc_tracer);
+  // Single threaded code may have reported promotion failure to the global state
+  if (_promotion_failed_info.promotion_failed()) {
+    gc_tracer.report_promotion_failed(_promotion_failed_info);
+  }
+  // Reset the PromotionFailureALot counters.
+  NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
+}
 
 void ParNewGeneration::collect(bool   full,
                                bool   clear_all_soft_refs,
@@ -914,7 +945,7 @@
     set_avoid_promotion_undo(true);
   }
 
-  // If the next generation is too full to accomodate worst-case promotion
+  // If the next generation is too full to accommodate worst-case promotion
   // from this generation, pass on collection; let the next generation
   // do it.
   if (!collection_attempt_is_safe()) {
@@ -987,19 +1018,21 @@
   rp->setup_policy(clear_all_soft_refs);
   // Can  the mt_degree be set later (at run_task() time would be best)?
   rp->set_active_mt_degree(active_workers);
+  ReferenceProcessorStats stats;
   if (rp->processing_is_mt()) {
     ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
-    rp->process_discovered_references(&is_alive, &keep_alive,
-                                      &evacuate_followers, &task_executor,
-                                      _gc_timer);
+    stats = rp->process_discovered_references(&is_alive, &keep_alive,
+                                              &evacuate_followers, &task_executor,
+                                              _gc_timer);
   } else {
     thread_state_set.flush();
     gch->set_par_threads(0);  // 0 ==> non-parallel.
     gch->save_marks();
-    rp->process_discovered_references(&is_alive, &keep_alive,
-                                      &evacuate_followers, NULL,
-                                      _gc_timer);
+    stats = rp->process_discovered_references(&is_alive, &keep_alive,
+                                              &evacuate_followers, NULL,
+                                              _gc_timer);
   }
+  gc_tracer.report_gc_reference_stats(stats);
   if (!promotion_failed()) {
     // Swap the survivor spaces.
     eden()->clear(SpaceDecorator::Mangle);
@@ -1022,22 +1055,7 @@
 
     assert(to()->is_empty(), "to space should be empty now");
   } else {
-    assert(_promo_failure_scan_stack.is_empty(), "post condition");
-    _promo_failure_scan_stack.clear(true); // Clear cached segments.
-
-    remove_forwarding_pointers();
-    if (PrintGCDetails) {
-      gclog_or_tty->print(" (promotion failed)");
-    }
-    // All the spaces are in play for mark-sweep.
-    swap_spaces();  // Make life simpler for CMS || rescan; see 6483690.
-    from()->set_next_compaction_space(to());
-    gch->set_incremental_collection_failed();
-    // Inform the next generation that a promotion failure occurred.
-    _next_gen->promotion_failure_occurred();
-
-    // Reset the PromotionFailureALot counters.
-    NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
+    handle_promotion_failed(gch, thread_state_set, gc_tracer);
   }
   // set new iteration safe limit for the survivor spaces
   from()->set_concurrent_iteration_safe_limit(from()->top());
@@ -1193,8 +1211,7 @@
       new_obj = old;
 
       preserve_mark_if_necessary(old, m);
-      // Log the size of the maiden promotion failure
-      par_scan_state->log_promotion_failure(sz);
+      par_scan_state->register_promotion_failure(sz);
     }
 
     old->forward_to(new_obj);
@@ -1309,8 +1326,7 @@
       failed_to_promote = true;
 
       preserve_mark_if_necessary(old, m);
-      // Log the size of the maiden promotion failure
-      par_scan_state->log_promotion_failure(sz);
+      par_scan_state->register_promotion_failure(sz);
     }
   } else {
     // Is in to-space; do copying ourselves.
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -25,7 +25,9 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP
 
+#include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/parGCAllocBuffer.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/defNewGeneration.hpp"
 #include "utilities/taskqueue.hpp"
 
@@ -105,7 +107,7 @@
 #endif // TASKQUEUE_STATS
 
   // Stats for promotion failure
-  size_t _promotion_failure_size;
+  PromotionFailedInfo _promotion_failed_info;
 
   // Timing numbers.
   double _start;
@@ -180,13 +182,16 @@
   void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz);
 
   // Promotion failure stats
-  size_t promotion_failure_size() { return promotion_failure_size(); }
-  void log_promotion_failure(size_t sz) {
-    if (_promotion_failure_size == 0) {
-      _promotion_failure_size = sz;
-    }
+  void register_promotion_failure(size_t sz) {
+    _promotion_failed_info.register_promotion_failed(sz);
   }
-  void print_and_clear_promotion_failure_size();
+  PromotionFailedInfo& promotion_failed_info() {
+    return _promotion_failed_info;
+  }
+  bool promotion_failed() {
+    return _promotion_failed_info.promotion_failed();
+  }
+  void print_promotion_failure_size();
 
 #if TASKQUEUE_STATS
   TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; }
@@ -337,6 +342,8 @@
   // word being overwritten with a self-forwarding-pointer.
   void preserve_mark_if_necessary(oop obj, markOop m);
 
+  void handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer);
+
  protected:
 
   bool _survivor_overflow;
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -538,8 +538,10 @@
   // Process reference objects found during marking
   {
     ref_processor()->setup_policy(clear_all_softrefs);
-    ref_processor()->process_discovered_references(
-      is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer);
+    const ReferenceProcessorStats& stats =
+      ref_processor()->process_discovered_references(
+        is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer);
+    gc_tracer()->report_gc_reference_stats(stats);
   }
 
   // Follow system dictionary roots and unload classes
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -2086,7 +2086,7 @@
     bool marked_for_unloading = false;
 
     marking_start.update();
-    marking_phase(vmthread_cm, maximum_heap_compaction, &_gc_tracer);
+    marking_phase(vmthread_cm, maximum_heap_compaction);
 
 #ifndef PRODUCT
     if (TraceParallelOldGCMarkingPhase) {
@@ -2361,9 +2361,7 @@
   return ParallelScavengeHeap::gc_task_manager();
 }
 
-void PSParallelCompact::marking_phase(ParCompactionManager* cm,
-                                      bool maximum_heap_compaction,
-                                      ParallelOldTracer *gc_tracer) {
+void PSParallelCompact::marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction) {
   // Recursively traverse all live objects and mark them
   GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer);
 
@@ -2407,18 +2405,19 @@
   {
     GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer);
 
+    ReferenceProcessorStats stats;
     if (ref_processor()->processing_is_mt()) {
       RefProcTaskExecutor task_executor;
-      ref_processor()->process_discovered_references(
+      stats = ref_processor()->process_discovered_references(
         is_alive_closure(), &mark_and_push_closure, &follow_stack_closure,
         &task_executor, &_gc_timer);
     } else {
-      ref_processor()->process_discovered_references(
+      stats = ref_processor()->process_discovered_references(
         is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL,
         &_gc_timer);
     }
 
-    gc_tracer->report_gc_reference_processing(ref_processor()->collect_statistics());
+    _gc_tracer.report_gc_reference_stats(stats);
   }
 
   GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer);
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -890,9 +890,7 @@
   static void post_compact();
 
   // Mark live objects
-  static void marking_phase(ParCompactionManager* cm,
-                            bool maximum_heap_compaction,
-                            ParallelOldTracer *gc_tracer);
+  static void marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction);
   static void follow_weak_klass_links();
   static void follow_mdo_weak_refs();
 
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -27,8 +27,8 @@
 #include "gc_implementation/parallelScavenge/psOldGen.hpp"
 #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
 #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/mutableSpace.hpp"
-#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/memRegion.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oop.psgc.inline.hpp"
@@ -87,24 +87,20 @@
   }
 }
 
-PromotionFailedInfo PSPromotionManager::post_scavenge() {
-  size_t promotion_failed_size = 0;
-  uint   promotion_failed_count = 0;
-  PromotionFailedInfo pfi;
+bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
+  bool promotion_failure_occurred = false;
 
   TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());
   for (uint i = 0; i < ParallelGCThreads + 1; i++) {
     PSPromotionManager* manager = manager_array(i);
     assert(manager->claimed_stack_depth()->is_empty(), "should be empty");
     if (manager->_promotion_failed_info.promotion_failed()) {
-        promotion_failed_size += manager->_promotion_failed_info.promotion_failed_size();
-        promotion_failed_count += manager->_promotion_failed_info.promotion_failed_count();
+      gc_tracer.report_promotion_failed(manager->_promotion_failed_info);
+      promotion_failure_occurred = true;
     }
     manager->flush_labs();
   }
-
-  pfi.set_promotion_failed(promotion_failed_size, promotion_failed_count);
-  return pfi;
+  return promotion_failure_occurred;
 }
 
 #if TASKQUEUE_STATS
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_HPP
 
 #include "gc_implementation/parallelScavenge/psPromotionLAB.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/allocation.hpp"
 #include "utilities/taskqueue.hpp"
@@ -152,7 +153,7 @@
   static void initialize();
 
   static void pre_scavenge();
-  static PromotionFailedInfo post_scavenge();
+  static bool post_scavenge(YoungGCTracer& gc_tracer);
 
   static PSPromotionManager* gc_thread_promotion_manager(int index);
   static PSPromotionManager* vm_thread_promotion_manager();
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -332,7 +332,6 @@
   {
     ResourceMark rm;
     HandleMark hm;
-    PromotionFailedInfo promotion_failed_info;
 
     gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
     TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
@@ -449,17 +448,18 @@
       reference_processor()->set_active_mt_degree(active_workers);
       PSKeepAliveClosure keep_alive(promotion_manager);
       PSEvacuateFollowersClosure evac_followers(promotion_manager);
+      ReferenceProcessorStats stats;
       if (reference_processor()->processing_is_mt()) {
         PSRefProcTaskExecutor task_executor;
-        reference_processor()->process_discovered_references(
+        stats = reference_processor()->process_discovered_references(
           &_is_alive_closure, &keep_alive, &evac_followers, &task_executor,
           &_gc_timer);
       } else {
-        reference_processor()->process_discovered_references(
+        stats = reference_processor()->process_discovered_references(
           &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer);
       }
 
-      _gc_tracer.report_gc_reference_processing(reference_processor()->collect_statistics());
+      _gc_tracer.report_gc_reference_stats(stats);
 
       // Enqueue reference objects discovered during scavenge.
       if (reference_processor()->processing_is_mt()) {
@@ -480,12 +480,8 @@
     }
 
     // Finally, flush the promotion_manager's labs, and deallocate its stacks.
-    promotion_failed_info = PSPromotionManager::post_scavenge();
-
-    promotion_failure_occurred = promotion_failed_info.promotion_failed();
+    promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer);
     if (promotion_failure_occurred) {
-      _gc_tracer.report_promotion_failed(promotion_failed_info.promotion_failed_size(),
-                                         promotion_failed_info.promotion_failed_count());
       clean_up_failed_promotion();
       if (PrintGC) {
         gclog_or_tty->print("--");
@@ -499,8 +495,6 @@
 
     if (!promotion_failure_occurred) {
       // Swap the survivor spaces.
-
-
       young_gen->eden_space()->clear(SpaceDecorator::Mangle);
       young_gen->from_space()->clear(SpaceDecorator::Mangle);
       young_gen->swap_spaces();
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -26,6 +26,7 @@
 #include "gc_implementation/shared/gcHeapSummary.hpp"
 #include "gc_implementation/shared/gcTimer.hpp"
 #include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/referenceProcessorStats.hpp"
 #include "utilities/globalDefinitions.hpp"
 
@@ -75,13 +76,13 @@
   _shared_gc_info.set_id(SharedGCInfo::UNSET_GCID);
 }
 
-void GCTracer::report_gc_reference_processing(const ReferenceProcessorStats& rps) const {
+void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) const {
   assert_set_gc_id();
 
-  send_reference_processing_event(REF_SOFT, rps.soft_count());
-  send_reference_processing_event(REF_WEAK, rps.weak_count());
-  send_reference_processing_event(REF_FINAL, rps.final_count());
-  send_reference_processing_event(REF_PHANTOM, rps.phantom_count());
+  send_reference_stats_event(REF_SOFT, rps.soft_count());
+  send_reference_stats_event(REF_WEAK, rps.weak_count());
+  send_reference_stats_event(REF_FINAL, rps.final_count());
+  send_reference_stats_event(REF_PHANTOM, rps.phantom_count());
 }
 
 void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const PermGenSummary& perm_gen_summary) const {
@@ -98,11 +99,10 @@
   send_young_gc_event();
 }
 
-void YoungGCTracer::report_promotion_failed(size_t size, uint count) {
+void YoungGCTracer::report_promotion_failed(const PromotionFailedInfo& pf_info) {
   assert_set_gc_id();
 
-  young_gc_info().register_promotion_failed();
-  send_promotion_failed_event(size, count);
+  send_promotion_failed_event(pf_info);
 }
 
 
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -28,6 +28,7 @@
 #include "gc_interface/gcCause.hpp"
 #include "gc_interface/gcName.hpp"
 #include "gc_implementation/shared/gcWhen.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/allocation.hpp"
 #include "memory/referenceType.hpp"
 #ifndef SERIALGC
@@ -93,16 +94,6 @@
   void* dense_prefix() const { return _dense_prefix; }
 };
 
-class YoungGCInfo VALUE_OBJ_CLASS_SPEC {
-  bool _promotion_failed;
- public:
-  YoungGCInfo() : _promotion_failed(false) {}
-  void register_promotion_failed() {
-    _promotion_failed = true;
-  }
-  bool promotion_failed() const { return _promotion_failed; }
-};
-
 #ifndef SERIALGC
 
 class G1YoungGCInfo VALUE_OBJ_CLASS_SPEC {
@@ -125,7 +116,7 @@
   void report_gc_start(GCCause::Cause cause, jlong timestamp);
   void report_gc_end(jlong timestamp, TimePartitions* time_partitions);
   void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const PermGenSummary& perm_gen_summary) const;
-  void report_gc_reference_processing(const ReferenceProcessorStats& rp) const;
+  void report_gc_reference_stats(const ReferenceProcessorStats& rp) const;
 
   bool has_reported_gc_start() const;
 
@@ -138,26 +129,23 @@
   void send_garbage_collection_event() const;
   void send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const;
   void send_perm_gen_summary_event(GCWhen::Type when, const PermGenSummary& perm_gen_summary) const;
-  void send_reference_processing_event(ReferenceType type, size_t count) const;
+  void send_reference_stats_event(ReferenceType type, size_t count) const;
   void send_phase_events(TimePartitions* time_partitions) const;
 };
 
 class YoungGCTracer : public GCTracer {
-  YoungGCInfo _young_gc_info;
-
  protected:
   YoungGCTracer(GCName name) : GCTracer(name) {}
-  virtual YoungGCInfo& young_gc_info() { return _young_gc_info; }
 
  public:
-  virtual void report_promotion_failed(size_t size, uint count);
+  virtual void report_promotion_failed(const PromotionFailedInfo& pf_info);
 
  protected:
   virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
 
  private:
   void send_young_gc_event() const;
-  void send_promotion_failed_event(size_t size, uint count) const;
+  void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const;
 };
 
 class OldGCTracer : public GCTracer {
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -27,6 +27,7 @@
 #include "gc_implementation/shared/gcTimer.hpp"
 #include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/gcWhen.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "trace/tracing.hpp"
 #ifndef SERIALGC
 #include "gc_implementation/g1/g1YCTypes.hpp"
@@ -50,8 +51,8 @@
   }
 }
 
-void GCTracer::send_reference_processing_event(ReferenceType type, size_t count) const {
-  EventGCReferenceProcessing e;
+void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const {
+  EventGCReferenceStatistics e;
   if (e.should_commit()) {
       e.set_gcId(_shared_gc_info.id());
       e.set_type((u1)type);
@@ -75,7 +76,6 @@
   EventGCYoungGarbageCollection e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
-    e.set_promotionFailed(_young_gc_info.promotion_failed());
     e.set_starttime(_shared_gc_info.start_timestamp());
     e.set_endtime(_shared_gc_info.end_timestamp());
     e.commit();
@@ -92,12 +92,15 @@
   }
 }
 
-void YoungGCTracer::send_promotion_failed_event(size_t size, uint count) const {
+void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const {
   EventPromotionFailed e;
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
-    e.set_objectCount(count);
-    e.set_totalSize(size);
+    e.set_objectCount(pf_info.promotion_failed_count());
+    e.set_firstSize(pf_info.first_size());
+    e.set_smallestSize(pf_info.smallest_size());
+    e.set_totalSize(pf_info.total_size());
+    e.set_thread(pf_info.thread()->thread_id());
     e.commit();
   }
 }
--- a/src/share/vm/gc_implementation/shared/promotionFailedInfo.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/promotionFailedInfo.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -25,34 +25,46 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_PROMOTIONFAILEDINFO_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_SHARED_PROMOTIONFAILEDINFO_HPP
 
+#include "runtime/thread.hpp"
 #include "utilities/globalDefinitions.hpp"
 
 class PromotionFailedInfo VALUE_OBJ_CLASS_SPEC {
-  uint   _promotion_failed_count;
-  size_t _promotion_failed_size;
+  size_t    _first_size;
+  size_t    _smallest_size;
+  size_t    _total_size;
+  uint      _count;
+  OSThread* _thread;
+
  public:
-  PromotionFailedInfo() : _promotion_failed_count(0), _promotion_failed_size(0) {}
+  PromotionFailedInfo() : _first_size(0), _smallest_size(0), _total_size(0), _count(0), _thread(NULL) {}
 
   void register_promotion_failed(size_t size) {
-    _promotion_failed_size += size;
-    _promotion_failed_count++;
-  }
-
-  void set_promotion_failed(size_t size, uint count) {
-    _promotion_failed_size = size;
-    _promotion_failed_count = count;
+    if (_first_size == 0) {
+      _first_size = size;
+      _smallest_size = size;
+      _thread = Thread::current()->osthread();
+    } else if (size < _smallest_size) {
+      _smallest_size = size;
+    }
+    _total_size += size;
+    _count++;
+    assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local.");
   }
 
   void reset() {
-    _promotion_failed_size = 0;
-    _promotion_failed_count = 0;
+    _first_size = 0;
+    _smallest_size = 0;
+    _total_size = 0;
+    _count = 0;
+    _thread = NULL;
   }
 
-  bool promotion_failed() const { return _promotion_failed_size > 0; }
-  size_t promotion_failed_size() const { return _promotion_failed_size; }
-  uint promotion_failed_count() const { return _promotion_failed_count; }
+  bool promotion_failed() const { return _count != 0; }
+  size_t first_size() const { return _first_size; }
+  size_t smallest_size() const { return _smallest_size; }
+  size_t total_size() const { return _total_size; }
+  uint promotion_failed_count() const { return _count; }
+  OSThread* thread() const { return _thread; }
 };
 
-
 #endif /* SHARE_VM_GC_IMPLEMENTATION_SHARED_PROMOTIONFAILEDINFO_HPP */
-
--- a/src/share/vm/memory/defNewGeneration.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/defNewGeneration.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -546,7 +546,7 @@
   assert(_next_gen != NULL,
     "This must be the youngest gen, and not the only gen");
 
-  // If the next generation is too full to accomodate promotion
+  // If the next generation is too full to accommodate promotion
   // from this generation, pass on collection; let the next generation
   // do it.
   if (!collection_attempt_is_safe()) {
@@ -610,9 +610,11 @@
   FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
   ReferenceProcessor* rp = ref_processor();
   rp->setup_policy(clear_all_soft_refs);
-  rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
-                                    NULL, _gc_timer);
-  if (!promotion_failed()) {
+  const ReferenceProcessorStats& stats =
+    rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
+                                      NULL, _gc_timer);
+  gc_tracer.report_gc_reference_stats(stats);
+  if (!_promotion_failed) {
     // Swap the survivor spaces.
     eden()->clear(SpaceDecorator::Mangle);
     from()->clear(SpaceDecorator::Mangle);
@@ -661,6 +663,7 @@
 
     // Inform the next generation that a promotion failure occurred.
     _next_gen->promotion_failure_occurred();
+    gc_tracer.report_promotion_failed(_promotion_failed_info);
 
     // Reset the PromotionFailureALot counters.
     NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
@@ -670,7 +673,7 @@
   to()->set_concurrent_iteration_safe_limit(to()->top());
   SpecializationStats::print();
 
-  // We need to use a monotonically non-deccreasing time in ms
+  // We need to use a monotonically non-decreasing time in ms
   // or we will see time-warp warnings and os::javaTimeMillis()
   // does not guarantee monotonicity.
   jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
@@ -692,6 +695,7 @@
 
 void DefNewGeneration::init_assuming_no_promotion_failure() {
   _promotion_failed = false;
+  _promotion_failed_info.reset();
   from()->set_next_compaction_space(NULL);
 }
 
@@ -713,7 +717,7 @@
 }
 
 void DefNewGeneration::preserve_mark(oop obj, markOop m) {
-  assert(promotion_failed() && m->must_be_preserved_for_promotion_failure(obj),
+  assert(_promotion_failed && m->must_be_preserved_for_promotion_failure(obj),
          "Oversaving!");
   _objs_with_preserved_marks.push(obj);
   _preserved_marks_of_objs.push(m);
@@ -731,6 +735,7 @@
                         old->size());
   }
   _promotion_failed = true;
+  _promotion_failed_info.register_promotion_failed(old->size());
   preserve_mark_if_necessary(old, old->mark());
   // forward to self
   old->forward_to(old);
--- a/src/share/vm/memory/defNewGeneration.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/defNewGeneration.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -28,6 +28,7 @@
 #include "gc_implementation/shared/ageTable.hpp"
 #include "gc_implementation/shared/cSpaceCounters.hpp"
 #include "gc_implementation/shared/generationCounters.hpp"
+#include "gc_implementation/shared/promotionFailedInfo.hpp"
 #include "memory/generation.inline.hpp"
 #include "utilities/stack.hpp"
 
@@ -47,15 +48,17 @@
   int         _tenuring_threshold;   // Tenuring threshold for next collection.
   ageTable    _age_table;
   // Size of object to pretenure in words; command line provides bytes
-  size_t        _pretenure_size_threshold_words;
+  size_t      _pretenure_size_threshold_words;
 
   ageTable*   age_table() { return &_age_table; }
+
   // Initialize state to optimistically assume no promotion failure will
   // happen.
   void   init_assuming_no_promotion_failure();
   // True iff a promotion has failed in the current collection.
   bool   _promotion_failed;
   bool   promotion_failed() { return _promotion_failed; }
+  PromotionFailedInfo _promotion_failed_info;
 
   // Handling promotion failure.  A young generation collection
   // can fail if a live object cannot be copied out of its
--- a/src/share/vm/memory/genMarkSweep.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/genMarkSweep.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -291,8 +291,10 @@
   // Process reference objects found during marking
   {
     ref_processor()->setup_policy(clear_all_softrefs);
-    ref_processor()->process_discovered_references(
-      &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer);
+    const ReferenceProcessorStats& stats =
+      ref_processor()->process_discovered_references(
+        &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer);
+    gc_tracer()->report_gc_reference_stats(stats);
   }
 
   // Follow system dictionary roots and unload classes
--- a/src/share/vm/memory/referenceProcessor.cpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/referenceProcessor.cpp	Thu Mar 21 11:12:14 2013 -0700
@@ -102,8 +102,7 @@
   _discovered_list_needs_barrier(discovered_list_needs_barrier),
   _bs(NULL),
   _processing_is_mt(mt_processing),
-  _next_id(0),
-  _stats()
+  _next_id(0)
 {
   _span = span;
   _discovery_is_atomic = atomic_discovery;
@@ -191,14 +190,7 @@
   return total;
 }
 
-void ReferenceProcessor::save_discovered_list_stats() {
-  _stats._soft_count = total_count(_discoveredSoftRefs);
-  _stats._weak_count = total_count(_discoveredWeakRefs);
-  _stats._final_count = total_count(_discoveredFinalRefs);
-  _stats._phantom_count = total_count(_discoveredPhantomRefs);
-}
-
-void ReferenceProcessor::process_discovered_references(
+ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
   BoolObjectClosure*           is_alive,
   OopClosure*                  keep_alive,
   VoidClosure*                 complete_gc,
@@ -220,37 +212,44 @@
 
   _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
 
-  save_discovered_list_stats();
+  bool trace_time = PrintGCDetails && PrintReferenceGC;
 
-  bool trace_time = PrintGCDetails && PrintReferenceGC;
   // Soft references
+  size_t soft_count = 0;
   {
     GCTraceTime tt("SoftReference", trace_time, false, gc_timer);
-    process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
-                               is_alive, keep_alive, complete_gc, task_executor);
+    soft_count =
+      process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
+                                 is_alive, keep_alive, complete_gc, task_executor);
   }
 
   update_soft_ref_master_clock();
 
   // Weak references
+  size_t weak_count = 0;
   {
     GCTraceTime tt("WeakReference", trace_time, false, gc_timer);
-    process_discovered_reflist(_discoveredWeakRefs, NULL, true,
-                               is_alive, keep_alive, complete_gc, task_executor);
+    weak_count =
+      process_discovered_reflist(_discoveredWeakRefs, NULL, true,
+                                 is_alive, keep_alive, complete_gc, task_executor);
   }
 
   // Final references
+  size_t final_count = 0;
   {
     GCTraceTime tt("FinalReference", trace_time, false, gc_timer);
-    process_discovered_reflist(_discoveredFinalRefs, NULL, false,
-                               is_alive, keep_alive, complete_gc, task_executor);
+    final_count =
+      process_discovered_reflist(_discoveredFinalRefs, NULL, false,
+                                 is_alive, keep_alive, complete_gc, task_executor);
   }
 
   // Phantom references
+  size_t phantom_count = 0;
   {
     GCTraceTime tt("PhantomReference", trace_time, false, gc_timer);
-    process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
-                               is_alive, keep_alive, complete_gc, task_executor);
+    phantom_count =
+      process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
+                                 is_alive, keep_alive, complete_gc, task_executor);
   }
 
   // Weak global JNI references. It would make more sense (semantically) to
@@ -265,6 +264,8 @@
     }
     process_phaseJNI(is_alive, keep_alive, complete_gc);
   }
+
+  return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count);
 }
 
 #ifndef PRODUCT
@@ -900,7 +901,7 @@
   balance_queues(_discoveredPhantomRefs);
 }
 
-void
+size_t
 ReferenceProcessor::process_discovered_reflist(
   DiscoveredList               refs_lists[],
   ReferencePolicy*             policy,
@@ -923,8 +924,11 @@
       must_balance) {
     balance_queues(refs_lists);
   }
+
+  size_t total_list_count = total_count(refs_lists);
+
   if (PrintReferenceGC && PrintGCDetails) {
-    gclog_or_tty->print(", %u refs", total_count(refs_lists));
+    gclog_or_tty->print(", %u refs", total_list_count);
   }
 
   // Phase 1 (soft refs only):
@@ -969,6 +973,8 @@
                      is_alive, keep_alive, complete_gc);
     }
   }
+
+  return total_list_count;
 }
 
 void ReferenceProcessor::clean_up_discovered_references() {
--- a/src/share/vm/memory/referenceProcessor.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/referenceProcessor.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -210,10 +210,7 @@
 class ReferenceProcessor : public CHeapObj<mtGC> {
 
  private:
-  ReferenceProcessorStats _stats;
-
   size_t total_count(DiscoveredList lists[]);
-  void save_discovered_list_stats();
 
  protected:
   // Compatibility with pre-4965777 JDK's
@@ -293,13 +290,13 @@
   }
 
   // Process references with a certain reachability level.
-  void process_discovered_reflist(DiscoveredList               refs_lists[],
-                                  ReferencePolicy*             policy,
-                                  bool                         clear_referent,
-                                  BoolObjectClosure*           is_alive,
-                                  OopClosure*                  keep_alive,
-                                  VoidClosure*                 complete_gc,
-                                  AbstractRefProcTaskExecutor* task_executor);
+  size_t process_discovered_reflist(DiscoveredList               refs_lists[],
+                                    ReferencePolicy*             policy,
+                                    bool                         clear_referent,
+                                    BoolObjectClosure*           is_alive,
+                                    OopClosure*                  keep_alive,
+                                    VoidClosure*                 complete_gc,
+                                    AbstractRefProcTaskExecutor* task_executor);
 
   void process_phaseJNI(BoolObjectClosure* is_alive,
                         OopClosure*        keep_alive,
@@ -384,12 +381,6 @@
 
   void enqueue_discovered_reflists(HeapWord* pending_list_addr, AbstractRefProcTaskExecutor* task_executor);
 
-  // Returns statistics from the last time the reference where processed via
-  // an invocation of process_discovered_references.
-  const ReferenceProcessorStats& collect_statistics() const {
-    return _stats;
-  }
-
  protected:
   // Set the 'discovered' field of the given reference to
   // the given value - emitting barriers depending upon
@@ -447,8 +438,7 @@
     _num_q(0),
     _max_num_q(0),
     _processing_is_mt(false),
-    _next_id(0),
-    _stats()
+    _next_id(0)
   { }
 
   // Default parameters give you a vanilla reference processor.
@@ -520,11 +510,12 @@
   bool discover_reference(oop obj, ReferenceType rt);
 
   // Process references found during GC (called by the garbage collector)
-  void process_discovered_references(BoolObjectClosure*           is_alive,
-                                     OopClosure*                  keep_alive,
-                                     VoidClosure*                 complete_gc,
-                                     AbstractRefProcTaskExecutor* task_executor,
-                                     GCTimer *gc_timer);
+  ReferenceProcessorStats
+  process_discovered_references(BoolObjectClosure*           is_alive,
+                                OopClosure*                  keep_alive,
+                                VoidClosure*                 complete_gc,
+                                AbstractRefProcTaskExecutor* task_executor,
+                                GCTimer *gc_timer);
 
   // Enqueue references at end of GC (called by the garbage collector)
   bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL);
--- a/src/share/vm/memory/referenceProcessorStats.hpp	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/memory/referenceProcessorStats.hpp	Thu Mar 21 11:12:14 2013 -0700
@@ -32,9 +32,6 @@
 // ReferenceProcessorStats contains statistics about how many references that
 // have been traversed when processing references during garbage collection.
 class ReferenceProcessorStats {
-  friend class ReferenceProcessor;
-
- private:
   size_t _soft_count;
   size_t _weak_count;
   size_t _final_count;
@@ -47,6 +44,16 @@
     _final_count(0),
     _phantom_count(0) {}
 
+  ReferenceProcessorStats(size_t soft_count,
+                          size_t weak_count,
+                          size_t final_count,
+                          size_t phantom_count) :
+    _soft_count(soft_count),
+    _weak_count(weak_count),
+    _final_count(final_count),
+    _phantom_count(phantom_count)
+  {}
+
   size_t soft_count() const {
     return _soft_count;
   }
--- a/src/share/vm/trace/trace.xml	Wed Mar 20 14:47:35 2013 -0700
+++ b/src/share/vm/trace/trace.xml	Thu Mar 21 11:12:14 2013 -0700
@@ -168,8 +168,6 @@
     <event id="GCYoungGarbageCollection" path="vm/gc/collector/young_garbage_collection" label="Young Garbage Collection"
            description="Extra information specific to Young Garbage Collections">
       <value type="ULONG" field="gcId"  label="GC ID" relation="GC_ID" />
-      <!-- This information can also be found by looking for PromotionFailed events. It's here for convenience. -->
-      <value type="BOOLEAN" field="promotionFailed" label="Promotion Failed" description="Tells if we failed to promote some objects to the old gen" />
     </event>
 
     <event id="GCOldGarbageCollection" path="vm/gc/collector/old_garbage_collection" label="Old Garbage Collection"
@@ -183,7 +181,7 @@
       <value type="G1YCTYPE" field="type" label="Type" />
     </event>
 
-    <event id="GCReferenceProcessing" path="vm/gc/reference/statistics"
+    <event id="GCReferenceStatistics" path="vm/gc/reference/statistics"
            label="GC Reference Processing" is_instant="true"
            description="Total count of processed references during GC">
       <value type="ULONG" field="gcId" label="GC ID" relation="GC_ID"/>
@@ -195,7 +193,10 @@
            description="Promotion of an object failed">
       <value type="ULONG" field="gcId" label="GC ID" relation="GC_ID"/>
       <value type="BYTES64" field="objectCount" label="Object Count"/>
+      <value type="BYTES64" field="firstSize" label="First Failed Object Size"/>
+      <value type="BYTES64" field="smallestSize" label="Smallest Failed Object Size"/>
       <value type="BYTES64" field="totalSize" label="Total Object Size"/>
+      <value type="OSTHREAD" field="thread" label="Running thread"/>
     </event>
 
     <event id="GCPhasePause" path="vm/gc/phases/pause" label="GC Phase Pause">
--- a/test/runtime/NMT/BaselineWithParameter.java	Wed Mar 20 14:47:35 2013 -0700
+++ b/test/runtime/NMT/BaselineWithParameter.java	Thu Mar 21 11:12:14 2013 -0700
@@ -43,7 +43,7 @@
 
     // Run 'jcmd <pid> VM.native_memory baseline=false'
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=false"});
-    pb.start();
+    pb.start().waitFor();
 
     // Run 'jcmd <pid> VM.native_memory summary=false'
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary=false"});