Sat, 14 Aug 2010 00:47:52 -0700
Merge
1.1 --- a/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp Fri Aug 13 07:33:20 2010 -0700 1.2 +++ b/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp Sat Aug 14 00:47:52 2010 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -36,8 +36,8 @@ 1.11 } 1.12 1.13 inline void OrderAccess::release() { 1.14 - jint* dummy = (jint*)&dummy; 1.15 - __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory"); 1.16 + jint* local_dummy = (jint*)&local_dummy; 1.17 + __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory"); 1.18 } 1.19 1.20 inline void OrderAccess::fence() {
2.1 --- a/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Fri Aug 13 07:33:20 2010 -0700 2.2 +++ b/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Sat Aug 14 00:47:52 2010 -0700 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -30,16 +30,18 @@ 2.11 inline void OrderAccess::storeload() { fence(); } 2.12 2.13 inline void OrderAccess::acquire() { 2.14 - volatile intptr_t dummy; 2.15 + volatile intptr_t local_dummy; 2.16 #ifdef AMD64 2.17 - __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory"); 2.18 + __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory"); 2.19 #else 2.20 - __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory"); 2.21 + __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory"); 2.22 #endif // AMD64 2.23 } 2.24 2.25 inline void OrderAccess::release() { 2.26 - dummy = 0; 2.27 + // Avoid hitting the same cache-line from 2.28 + // different threads. 2.29 + volatile jint local_dummy = 0; 2.30 } 2.31 2.32 inline void OrderAccess::fence() {
3.1 --- a/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Fri Aug 13 07:33:20 2010 -0700 3.2 +++ b/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Sat Aug 14 00:47:52 2010 -0700 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -42,8 +42,8 @@ 3.11 } 3.12 3.13 inline void OrderAccess::release() { 3.14 - jint* dummy = (jint*)&dummy; 3.15 - __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory"); 3.16 + jint* local_dummy = (jint*)&local_dummy; 3.17 + __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory"); 3.18 } 3.19 3.20 inline void OrderAccess::fence() { 3.21 @@ -57,7 +57,9 @@ 3.22 } 3.23 3.24 inline void OrderAccess::release() { 3.25 - dummy = 0; 3.26 + // Avoid hitting the same cache-line from 3.27 + // different threads. 3.28 + volatile jint local_dummy = 0; 3.29 } 3.30 3.31 inline void OrderAccess::fence() {
4.1 --- a/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Fri Aug 13 07:33:20 2010 -0700 4.2 +++ b/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Sat Aug 14 00:47:52 2010 -0700 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 4.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 4.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.8 * 4.9 * This code is free software; you can redistribute it and/or modify it 4.10 @@ -40,7 +40,9 @@ 4.11 } 4.12 4.13 inline void OrderAccess::release() { 4.14 - dummy = 0; 4.15 + // Avoid hitting the same cache-line from 4.16 + // different threads. 4.17 + volatile jint local_dummy = 0; 4.18 } 4.19 4.20 inline void OrderAccess::fence() { 4.21 @@ -53,11 +55,11 @@ 4.22 4.23 extern "C" { 4.24 inline void _OrderAccess_acquire() { 4.25 - volatile intptr_t dummy; 4.26 + volatile intptr_t local_dummy; 4.27 #ifdef AMD64 4.28 - __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory"); 4.29 + __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory"); 4.30 #else 4.31 - __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory"); 4.32 + __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory"); 4.33 #endif // AMD64 4.34 } 4.35 inline void _OrderAccess_fence() {
5.1 --- a/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Fri Aug 13 07:33:20 2010 -0700 5.2 +++ b/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Sat Aug 14 00:47:52 2010 -0700 5.3 @@ -1,5 +1,5 @@ 5.4 /* 5.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 5.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 5.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.8 * 5.9 * This code is free software; you can redistribute it and/or modify it 5.10 @@ -41,7 +41,7 @@ 5.11 5.12 inline void OrderAccess::release() { 5.13 // A volatile store has release semantics. 5.14 - dummy = 0; 5.15 + volatile jint local_dummy = 0; 5.16 } 5.17 5.18 inline void OrderAccess::fence() {
6.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Aug 13 07:33:20 2010 -0700 6.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Sat Aug 14 00:47:52 2010 -0700 6.3 @@ -1965,6 +1965,9 @@ 6.4 _intra_sweep_estimate.padded_average()); 6.5 } 6.6 6.7 + { 6.8 + TraceCMSMemoryManagerStats(); 6.9 + } 6.10 GenMarkSweep::invoke_at_safepoint(_cmsGen->level(), 6.11 ref_processor(), clear_all_soft_refs); 6.12 #ifdef ASSERT 6.13 @@ -3415,6 +3418,7 @@ 6.14 void CMSCollector::checkpointRootsInitial(bool asynch) { 6.15 assert(_collectorState == InitialMarking, "Wrong collector state"); 6.16 check_correct_thread_executing(); 6.17 + TraceCMSMemoryManagerStats tms(_collectorState); 6.18 ReferenceProcessor* rp = ref_processor(); 6.19 SpecializationStats::clear(); 6.20 assert(_restart_addr == NULL, "Control point invariant"); 6.21 @@ -4748,6 +4752,7 @@ 6.22 // world is stopped at this checkpoint 6.23 assert(SafepointSynchronize::is_at_safepoint(), 6.24 "world should be stopped"); 6.25 + TraceCMSMemoryManagerStats tms(_collectorState); 6.26 verify_work_stacks_empty(); 6.27 verify_overflow_empty(); 6.28 6.29 @@ -5849,6 +5854,8 @@ 6.30 verify_work_stacks_empty(); 6.31 verify_overflow_empty(); 6.32 increment_sweep_count(); 6.33 + TraceCMSMemoryManagerStats tms(_collectorState); 6.34 + 6.35 _inter_sweep_timer.stop(); 6.36 _inter_sweep_estimate.sample(_inter_sweep_timer.seconds()); 6.37 size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free()); 6.38 @@ -9121,3 +9128,57 @@ 6.39 } 6.40 return res; 6.41 } 6.42 + 6.43 +TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase): TraceMemoryManagerStats() { 6.44 + 6.45 + switch (phase) { 6.46 + case CMSCollector::InitialMarking: 6.47 + initialize(true /* fullGC */ , 6.48 + true /* recordGCBeginTime */, 6.49 + true /* recordPreGCUsage */, 6.50 + false /* recordPeakUsage */, 6.51 + false /* recordPostGCusage */, 6.52 + true /* recordAccumulatedGCTime */, 6.53 + false /* recordGCEndTime */, 6.54 + false /* countCollection */ ); 6.55 + break; 6.56 + 6.57 + case CMSCollector::FinalMarking: 6.58 + initialize(true /* fullGC */ , 6.59 + false /* recordGCBeginTime */, 6.60 + false /* recordPreGCUsage */, 6.61 + false /* recordPeakUsage */, 6.62 + false /* recordPostGCusage */, 6.63 + true /* recordAccumulatedGCTime */, 6.64 + false /* recordGCEndTime */, 6.65 + false /* countCollection */ ); 6.66 + break; 6.67 + 6.68 + case CMSCollector::Sweeping: 6.69 + initialize(true /* fullGC */ , 6.70 + false /* recordGCBeginTime */, 6.71 + false /* recordPreGCUsage */, 6.72 + true /* recordPeakUsage */, 6.73 + true /* recordPostGCusage */, 6.74 + false /* recordAccumulatedGCTime */, 6.75 + true /* recordGCEndTime */, 6.76 + true /* countCollection */ ); 6.77 + break; 6.78 + 6.79 + default: 6.80 + ShouldNotReachHere(); 6.81 + } 6.82 +} 6.83 + 6.84 +// when bailing out of cms in concurrent mode failure 6.85 +TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(): TraceMemoryManagerStats() { 6.86 + initialize(true /* fullGC */ , 6.87 + true /* recordGCBeginTime */, 6.88 + true /* recordPreGCUsage */, 6.89 + true /* recordPeakUsage */, 6.90 + true /* recordPostGCusage */, 6.91 + true /* recordAccumulatedGCTime */, 6.92 + true /* recordGCEndTime */, 6.93 + true /* countCollection */ ); 6.94 +} 6.95 +
7.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Aug 13 07:33:20 2010 -0700 7.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Sat Aug 14 00:47:52 2010 -0700 7.3 @@ -507,6 +507,7 @@ 7.4 friend class VM_CMS_Operation; 7.5 friend class VM_CMS_Initial_Mark; 7.6 friend class VM_CMS_Final_Remark; 7.7 + friend class TraceCMSMemoryManagerStats; 7.8 7.9 private: 7.10 jlong _time_of_last_gc; 7.11 @@ -1858,3 +1859,11 @@ 7.12 _dead_bit_map(dead_bit_map) {} 7.13 size_t do_blk(HeapWord* addr); 7.14 }; 7.15 + 7.16 +class TraceCMSMemoryManagerStats : public TraceMemoryManagerStats { 7.17 + 7.18 + public: 7.19 + TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase); 7.20 + TraceCMSMemoryManagerStats(); 7.21 +}; 7.22 +
8.1 --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Fri Aug 13 07:33:20 2010 -0700 8.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Sat Aug 14 00:47:52 2010 -0700 8.3 @@ -339,7 +339,9 @@ 8.4 return res; 8.5 } 8.6 8.7 -void ConcurrentG1Refine::clean_up_cache(int worker_i, G1RemSet* g1rs) { 8.8 +void ConcurrentG1Refine::clean_up_cache(int worker_i, 8.9 + G1RemSet* g1rs, 8.10 + DirtyCardQueue* into_cset_dcq) { 8.11 assert(!use_cache(), "cache should be disabled"); 8.12 int start_idx; 8.13 8.14 @@ -353,7 +355,19 @@ 8.15 for (int i = start_idx; i < end_idx; i++) { 8.16 jbyte* entry = _hot_cache[i]; 8.17 if (entry != NULL) { 8.18 - g1rs->concurrentRefineOneCard(entry, worker_i); 8.19 + if (g1rs->concurrentRefineOneCard(entry, worker_i, true)) { 8.20 + // 'entry' contains references that point into the current 8.21 + // collection set. We need to record 'entry' in the DCQS 8.22 + // that's used for that purpose. 8.23 + // 8.24 + // The only time we care about recording cards that contain 8.25 + // references that point into the collection set is during 8.26 + // RSet updating while within an evacuation pause. 8.27 + // In this case worker_i should be the id of a GC worker thread 8.28 + assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); 8.29 + assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "incorrect worker id"); 8.30 + into_cset_dcq->enqueue(entry); 8.31 + } 8.32 } 8.33 } 8.34 }
9.1 --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Fri Aug 13 07:33:20 2010 -0700 9.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Sat Aug 14 00:47:52 2010 -0700 9.3 @@ -1,5 +1,5 @@ 9.4 /* 9.5 - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. 9.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 9.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.8 * 9.9 * This code is free software; you can redistribute it and/or modify it 9.10 @@ -184,7 +184,7 @@ 9.11 jbyte* cache_insert(jbyte* card_ptr, bool* defer); 9.12 9.13 // Process the cached entries. 9.14 - void clean_up_cache(int worker_i, G1RemSet* g1rs); 9.15 + void clean_up_cache(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq); 9.16 9.17 // Set up for parallel processing of the cards in the hot cache 9.18 void clear_hot_cache_claimed_index() {
10.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Fri Aug 13 07:33:20 2010 -0700 10.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Sat Aug 14 00:47:52 2010 -0700 10.3 @@ -1,5 +1,5 @@ 10.4 /* 10.5 - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. 10.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 10.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.8 * 10.9 * This code is free software; you can redistribute it and/or modify it 10.10 @@ -178,13 +178,14 @@ 10.11 } 10.12 10.13 bool DirtyCardQueueSet:: 10.14 -apply_closure_to_completed_buffer_helper(int worker_i, 10.15 +apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, 10.16 + int worker_i, 10.17 BufferNode* nd) { 10.18 if (nd != NULL) { 10.19 void **buf = BufferNode::make_buffer_from_node(nd); 10.20 size_t index = nd->index(); 10.21 bool b = 10.22 - DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 10.23 + DirtyCardQueue::apply_closure_to_buffer(cl, buf, 10.24 index, _sz, 10.25 true, worker_i); 10.26 if (b) { 10.27 @@ -199,15 +200,22 @@ 10.28 } 10.29 } 10.30 10.31 +bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, 10.32 + int worker_i, 10.33 + int stop_at, 10.34 + bool during_pause) { 10.35 + assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); 10.36 + BufferNode* nd = get_completed_buffer(stop_at); 10.37 + bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd); 10.38 + if (res) Atomic::inc(&_processed_buffers_rs_thread); 10.39 + return res; 10.40 +} 10.41 + 10.42 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, 10.43 int stop_at, 10.44 - bool during_pause) 10.45 -{ 10.46 - assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); 10.47 - BufferNode* nd = get_completed_buffer(stop_at); 10.48 - bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); 10.49 - if (res) Atomic::inc(&_processed_buffers_rs_thread); 10.50 - return res; 10.51 + bool during_pause) { 10.52 + return apply_closure_to_completed_buffer(_closure, worker_i, 10.53 + stop_at, during_pause); 10.54 } 10.55 10.56 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { 10.57 @@ -222,8 +230,8 @@ 10.58 } 10.59 } 10.60 10.61 -void DirtyCardQueueSet::abandon_logs() { 10.62 - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); 10.63 +// Deallocates any completed log buffers 10.64 +void DirtyCardQueueSet::clear() { 10.65 BufferNode* buffers_to_delete = NULL; 10.66 { 10.67 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); 10.68 @@ -242,6 +250,12 @@ 10.69 buffers_to_delete = nd->next(); 10.70 deallocate_buffer(BufferNode::make_buffer_from_node(nd)); 10.71 } 10.72 + 10.73 +} 10.74 + 10.75 +void DirtyCardQueueSet::abandon_logs() { 10.76 + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); 10.77 + clear(); 10.78 // Since abandon is done only at safepoints, we can safely manipulate 10.79 // these queues. 10.80 for (JavaThread* t = Threads::first(); t; t = t->next()) {
11.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Fri Aug 13 07:33:20 2010 -0700 11.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Sat Aug 14 00:47:52 2010 -0700 11.3 @@ -1,5 +1,5 @@ 11.4 /* 11.5 - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. 11.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 11.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.8 * 11.9 * This code is free software; you can redistribute it and/or modify it 11.10 @@ -123,7 +123,21 @@ 11.11 int stop_at = 0, 11.12 bool during_pause = false); 11.13 11.14 - bool apply_closure_to_completed_buffer_helper(int worker_i, 11.15 + // If there exists some completed buffer, pop it, then apply the 11.16 + // specified closure to all its elements, nulling out those elements 11.17 + // processed. If all elements are processed, returns "true". If no 11.18 + // completed buffers exist, returns false. If a completed buffer exists, 11.19 + // but is only partially completed before a "yield" happens, the 11.20 + // partially completed buffer (with its processed elements set to NULL) 11.21 + // is returned to the completed buffer set, and this call returns false. 11.22 + bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, 11.23 + int worker_i = 0, 11.24 + int stop_at = 0, 11.25 + bool during_pause = false); 11.26 + 11.27 + // Helper routine for the above. 11.28 + bool apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, 11.29 + int worker_i, 11.30 BufferNode* nd); 11.31 11.32 BufferNode* get_completed_buffer(int stop_at); 11.33 @@ -136,6 +150,9 @@ 11.34 return &_shared_dirty_card_queue; 11.35 } 11.36 11.37 + // Deallocate any completed log buffers 11.38 + void clear(); 11.39 + 11.40 // If a full collection is happening, reset partial logs, and ignore 11.41 // completed ones: the full collection will make them all irrelevant. 11.42 void abandon_logs();
12.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Aug 13 07:33:20 2010 -0700 12.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sat Aug 14 00:47:52 2010 -0700 12.3 @@ -56,7 +56,12 @@ 12.4 _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true) 12.5 {} 12.6 bool do_card_ptr(jbyte* card_ptr, int worker_i) { 12.7 - _g1rs->concurrentRefineOneCard(card_ptr, worker_i); 12.8 + bool oops_into_cset = _g1rs->concurrentRefineOneCard(card_ptr, worker_i, false); 12.9 + // This path is executed by the concurrent refine or mutator threads, 12.10 + // concurrently, and so we do not care if card_ptr contains references 12.11 + // that point into the collection set. 12.12 + assert(!oops_into_cset, "should be"); 12.13 + 12.14 if (_concurrent && _sts->should_yield()) { 12.15 // Caller will actually yield. 12.16 return false; 12.17 @@ -1322,6 +1327,7 @@ 12.18 SharedHeap(policy_), 12.19 _g1_policy(policy_), 12.20 _dirty_card_queue_set(false), 12.21 + _into_cset_dirty_card_queue_set(false), 12.22 _ref_processor(NULL), 12.23 _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), 12.24 _bot_shared(NULL), 12.25 @@ -1572,6 +1578,16 @@ 12.26 Shared_DirtyCardQ_lock, 12.27 &JavaThread::dirty_card_queue_set()); 12.28 } 12.29 + 12.30 + // Initialize the card queue set used to hold cards containing 12.31 + // references into the collection set. 12.32 + _into_cset_dirty_card_queue_set.initialize(DirtyCardQ_CBL_mon, 12.33 + DirtyCardQ_FL_lock, 12.34 + -1, // never trigger processing 12.35 + -1, // no limit on length 12.36 + Shared_DirtyCardQ_lock, 12.37 + &JavaThread::dirty_card_queue_set()); 12.38 + 12.39 // In case we're keeping closure specialization stats, initialize those 12.40 // counts and that mechanism. 12.41 SpecializationStats::clear(); 12.42 @@ -1603,14 +1619,16 @@ 12.43 return _g1_committed.byte_size(); 12.44 } 12.45 12.46 -void G1CollectedHeap::iterate_dirty_card_closure(bool concurrent, 12.47 +void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, 12.48 + DirtyCardQueue* into_cset_dcq, 12.49 + bool concurrent, 12.50 int worker_i) { 12.51 // Clean cards in the hot card cache 12.52 - concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set()); 12.53 + concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set(), into_cset_dcq); 12.54 12.55 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 12.56 int n_completed_buffers = 0; 12.57 - while (dcqs.apply_closure_to_completed_buffer(worker_i, 0, true)) { 12.58 + while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) { 12.59 n_completed_buffers++; 12.60 } 12.61 g1_policy()->record_update_rs_processed_buffers(worker_i, 12.62 @@ -2692,6 +2710,35 @@ 12.63 } 12.64 }; 12.65 12.66 +#if TASKQUEUE_STATS 12.67 +void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) { 12.68 + st->print_raw_cr("GC Task Stats"); 12.69 + st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); 12.70 + st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); 12.71 +} 12.72 + 12.73 +void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const { 12.74 + print_taskqueue_stats_hdr(st); 12.75 + 12.76 + TaskQueueStats totals; 12.77 + const int n = MAX2(workers()->total_workers(), 1); 12.78 + for (int i = 0; i < n; ++i) { 12.79 + st->print("%3d ", i); task_queue(i)->stats.print(st); st->cr(); 12.80 + totals += task_queue(i)->stats; 12.81 + } 12.82 + st->print_raw("tot "); totals.print(st); st->cr(); 12.83 + 12.84 + DEBUG_ONLY(totals.verify()); 12.85 +} 12.86 + 12.87 +void G1CollectedHeap::reset_taskqueue_stats() { 12.88 + const int n = MAX2(workers()->total_workers(), 1); 12.89 + for (int i = 0; i < n; ++i) { 12.90 + task_queue(i)->stats.reset(); 12.91 + } 12.92 +} 12.93 +#endif // TASKQUEUE_STATS 12.94 + 12.95 void 12.96 G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { 12.97 if (GC_locker::check_active_before_gc()) { 12.98 @@ -2825,93 +2872,57 @@ 12.99 g1_policy()->print_collection_set(g1_policy()->inc_cset_head(), gclog_or_tty); 12.100 #endif // YOUNG_LIST_VERBOSE 12.101 12.102 - // Now choose the CS. We may abandon a pause if we find no 12.103 - // region that will fit in the MMU pause. 12.104 - bool abandoned = g1_policy()->choose_collection_set(target_pause_time_ms); 12.105 + g1_policy()->choose_collection_set(target_pause_time_ms); 12.106 12.107 // Nothing to do if we were unable to choose a collection set. 12.108 - if (!abandoned) { 12.109 #if G1_REM_SET_LOGGING 12.110 - gclog_or_tty->print_cr("\nAfter pause, heap:"); 12.111 - print(); 12.112 + gclog_or_tty->print_cr("\nAfter pause, heap:"); 12.113 + print(); 12.114 #endif 12.115 - PrepareForRSScanningClosure prepare_for_rs_scan; 12.116 - collection_set_iterate(&prepare_for_rs_scan); 12.117 - 12.118 - setup_surviving_young_words(); 12.119 - 12.120 - // Set up the gc allocation regions. 12.121 - get_gc_alloc_regions(); 12.122 - 12.123 - // Actually do the work... 12.124 - evacuate_collection_set(); 12.125 - 12.126 - free_collection_set(g1_policy()->collection_set()); 12.127 - g1_policy()->clear_collection_set(); 12.128 - 12.129 - cleanup_surviving_young_words(); 12.130 - 12.131 - // Start a new incremental collection set for the next pause. 12.132 - g1_policy()->start_incremental_cset_building(); 12.133 - 12.134 - // Clear the _cset_fast_test bitmap in anticipation of adding 12.135 - // regions to the incremental collection set for the next 12.136 - // evacuation pause. 12.137 - clear_cset_fast_test(); 12.138 - 12.139 - if (g1_policy()->in_young_gc_mode()) { 12.140 - _young_list->reset_sampled_info(); 12.141 - 12.142 - // Don't check the whole heap at this point as the 12.143 - // GC alloc regions from this pause have been tagged 12.144 - // as survivors and moved on to the survivor list. 12.145 - // Survivor regions will fail the !is_young() check. 12.146 - assert(check_young_list_empty(false /* check_heap */), 12.147 - "young list should be empty"); 12.148 + PrepareForRSScanningClosure prepare_for_rs_scan; 12.149 + collection_set_iterate(&prepare_for_rs_scan); 12.150 + 12.151 + setup_surviving_young_words(); 12.152 + 12.153 + // Set up the gc allocation regions. 12.154 + get_gc_alloc_regions(); 12.155 + 12.156 + // Actually do the work... 12.157 + evacuate_collection_set(); 12.158 + 12.159 + free_collection_set(g1_policy()->collection_set()); 12.160 + g1_policy()->clear_collection_set(); 12.161 + 12.162 + cleanup_surviving_young_words(); 12.163 + 12.164 + // Start a new incremental collection set for the next pause. 12.165 + g1_policy()->start_incremental_cset_building(); 12.166 + 12.167 + // Clear the _cset_fast_test bitmap in anticipation of adding 12.168 + // regions to the incremental collection set for the next 12.169 + // evacuation pause. 12.170 + clear_cset_fast_test(); 12.171 + 12.172 + if (g1_policy()->in_young_gc_mode()) { 12.173 + _young_list->reset_sampled_info(); 12.174 + 12.175 + // Don't check the whole heap at this point as the 12.176 + // GC alloc regions from this pause have been tagged 12.177 + // as survivors and moved on to the survivor list. 12.178 + // Survivor regions will fail the !is_young() check. 12.179 + assert(check_young_list_empty(false /* check_heap */), 12.180 + "young list should be empty"); 12.181 12.182 #if YOUNG_LIST_VERBOSE 12.183 - gclog_or_tty->print_cr("Before recording survivors.\nYoung List:"); 12.184 - _young_list->print(); 12.185 + gclog_or_tty->print_cr("Before recording survivors.\nYoung List:"); 12.186 + _young_list->print(); 12.187 #endif // YOUNG_LIST_VERBOSE 12.188 12.189 - g1_policy()->record_survivor_regions(_young_list->survivor_length(), 12.190 + g1_policy()->record_survivor_regions(_young_list->survivor_length(), 12.191 _young_list->first_survivor_region(), 12.192 _young_list->last_survivor_region()); 12.193 12.194 - _young_list->reset_auxilary_lists(); 12.195 - } 12.196 - } else { 12.197 - // We have abandoned the current collection. This can only happen 12.198 - // if we're not doing young or partially young collections, and 12.199 - // we didn't find an old region that we're able to collect within 12.200 - // the allowed time. 12.201 - 12.202 - assert(g1_policy()->collection_set() == NULL, "should be"); 12.203 - assert(_young_list->length() == 0, "because it should be"); 12.204 - 12.205 - // This should be a no-op. 12.206 - abandon_collection_set(g1_policy()->inc_cset_head()); 12.207 - 12.208 - g1_policy()->clear_incremental_cset(); 12.209 - g1_policy()->stop_incremental_cset_building(); 12.210 - 12.211 - // Start a new incremental collection set for the next pause. 12.212 - g1_policy()->start_incremental_cset_building(); 12.213 - 12.214 - // Clear the _cset_fast_test bitmap in anticipation of adding 12.215 - // regions to the incremental collection set for the next 12.216 - // evacuation pause. 12.217 - clear_cset_fast_test(); 12.218 - 12.219 - // This looks confusing, because the DPT should really be empty 12.220 - // at this point -- since we have not done any collection work, 12.221 - // there should not be any derived pointers in the table to update; 12.222 - // however, there is some additional state in the DPT which is 12.223 - // reset at the end of the (null) "gc" here via the following call. 12.224 - // A better approach might be to split off that state resetting work 12.225 - // into a separate method that asserts that the DPT is empty and call 12.226 - // that here. That is deferred for now. 12.227 - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); 12.228 + _young_list->reset_auxilary_lists(); 12.229 } 12.230 12.231 if (evacuation_failed()) { 12.232 @@ -2945,7 +2956,7 @@ 12.233 double end_time_sec = os::elapsedTime(); 12.234 double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS; 12.235 g1_policy()->record_pause_time_ms(pause_time_ms); 12.236 - g1_policy()->record_collection_pause_end(abandoned); 12.237 + g1_policy()->record_collection_pause_end(); 12.238 12.239 assert(regions_accounted_for(), "Region leakage."); 12.240 12.241 @@ -2988,6 +2999,9 @@ 12.242 } 12.243 } 12.244 12.245 + TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats()); 12.246 + TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); 12.247 + 12.248 if (PrintHeapAtGC) { 12.249 Universe::print_heap_after_gc(); 12.250 } 12.251 @@ -3346,25 +3360,6 @@ 12.252 } 12.253 }; 12.254 12.255 -class UpdateRSetImmediate : public OopsInHeapRegionClosure { 12.256 -private: 12.257 - G1CollectedHeap* _g1; 12.258 - G1RemSet* _g1_rem_set; 12.259 -public: 12.260 - UpdateRSetImmediate(G1CollectedHeap* g1) : 12.261 - _g1(g1), _g1_rem_set(g1->g1_rem_set()) {} 12.262 - 12.263 - virtual void do_oop(narrowOop* p) { do_oop_work(p); } 12.264 - virtual void do_oop( oop* p) { do_oop_work(p); } 12.265 - template <class T> void do_oop_work(T* p) { 12.266 - assert(_from->is_in_reserved(p), "paranoia"); 12.267 - T heap_oop = oopDesc::load_heap_oop(p); 12.268 - if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) { 12.269 - _g1_rem_set->par_write_ref(_from, p, 0); 12.270 - } 12.271 - } 12.272 -}; 12.273 - 12.274 class UpdateRSetDeferred : public OopsInHeapRegionClosure { 12.275 private: 12.276 G1CollectedHeap* _g1; 12.277 @@ -3389,8 +3384,6 @@ 12.278 } 12.279 }; 12.280 12.281 - 12.282 - 12.283 class RemoveSelfPointerClosure: public ObjectClosure { 12.284 private: 12.285 G1CollectedHeap* _g1; 12.286 @@ -3453,7 +3446,7 @@ 12.287 }; 12.288 12.289 void G1CollectedHeap::remove_self_forwarding_pointers() { 12.290 - UpdateRSetImmediate immediate_update(_g1h); 12.291 + UpdateRSetImmediate immediate_update(_g1h->g1_rem_set()); 12.292 DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); 12.293 UpdateRSetDeferred deferred_update(_g1h, &dcq); 12.294 OopsInHeapRegionClosure *cl; 12.295 @@ -3754,10 +3747,6 @@ 12.296 _surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)), 12.297 _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)), 12.298 _age_table(false), 12.299 -#if G1_DETAILED_STATS 12.300 - _pushes(0), _pops(0), _steals(0), 12.301 - _steal_attempts(0), _overflow_pushes(0), 12.302 -#endif 12.303 _strong_roots_time(0), _term_time(0), 12.304 _alloc_buffer_waste(0), _undo_waste(0) 12.305 { 12.306 @@ -3777,14 +3766,41 @@ 12.307 _surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM; 12.308 memset(_surviving_young_words, 0, real_length * sizeof(size_t)); 12.309 12.310 - _overflowed_refs = new OverflowQueue(10); 12.311 - 12.312 _alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer; 12.313 _alloc_buffers[GCAllocForTenured] = &_tenured_alloc_buffer; 12.314 12.315 _start = os::elapsedTime(); 12.316 } 12.317 12.318 +void 12.319 +G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st) 12.320 +{ 12.321 + st->print_raw_cr("GC Termination Stats"); 12.322 + st->print_raw_cr(" elapsed --strong roots-- -------termination-------" 12.323 + " ------waste (KiB)------"); 12.324 + st->print_raw_cr("thr ms ms % ms % attempts" 12.325 + " total alloc undo"); 12.326 + st->print_raw_cr("--- --------- --------- ------ --------- ------ --------" 12.327 + " ------- ------- -------"); 12.328 +} 12.329 + 12.330 +void 12.331 +G1ParScanThreadState::print_termination_stats(int i, 12.332 + outputStream* const st) const 12.333 +{ 12.334 + const double elapsed_ms = elapsed_time() * 1000.0; 12.335 + const double s_roots_ms = strong_roots_time() * 1000.0; 12.336 + const double term_ms = term_time() * 1000.0; 12.337 + st->print_cr("%3d %9.2f %9.2f %6.2f " 12.338 + "%9.2f %6.2f " SIZE_FORMAT_W(8) " " 12.339 + SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7), 12.340 + i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms, 12.341 + term_ms, term_ms * 100 / elapsed_ms, term_attempts(), 12.342 + (alloc_buffer_waste() + undo_waste()) * HeapWordSize / K, 12.343 + alloc_buffer_waste() * HeapWordSize / K, 12.344 + undo_waste() * HeapWordSize / K); 12.345 +} 12.346 + 12.347 G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : 12.348 _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()), 12.349 _par_scan_state(par_scan_state) { } 12.350 @@ -3991,12 +4007,9 @@ 12.351 G1ParScanThreadState* pss = par_scan_state(); 12.352 while (true) { 12.353 pss->trim_queue(); 12.354 - IF_G1_DETAILED_STATS(pss->note_steal_attempt()); 12.355 12.356 StarTask stolen_task; 12.357 if (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) { 12.358 - IF_G1_DETAILED_STATS(pss->note_steal()); 12.359 - 12.360 // slightly paranoid tests; I'm trying to catch potential 12.361 // problems before we go into push_on_queue to know where the 12.362 // problem is coming from 12.363 @@ -4115,35 +4128,9 @@ 12.364 // Clean up any par-expanded rem sets. 12.365 HeapRegionRemSet::par_cleanup(); 12.366 12.367 - MutexLocker x(stats_lock()); 12.368 if (ParallelGCVerbose) { 12.369 - gclog_or_tty->print("Thread %d complete:\n", i); 12.370 -#if G1_DETAILED_STATS 12.371 - gclog_or_tty->print(" Pushes: %7d Pops: %7d Overflows: %7d Steals %7d (in %d attempts)\n", 12.372 - pss.pushes(), 12.373 - pss.pops(), 12.374 - pss.overflow_pushes(), 12.375 - pss.steals(), 12.376 - pss.steal_attempts()); 12.377 -#endif 12.378 - double elapsed = pss.elapsed(); 12.379 - double strong_roots = pss.strong_roots_time(); 12.380 - double term = pss.term_time(); 12.381 - gclog_or_tty->print(" Elapsed: %7.2f ms.\n" 12.382 - " Strong roots: %7.2f ms (%6.2f%%)\n" 12.383 - " Termination: %7.2f ms (%6.2f%%) " 12.384 - "(in "SIZE_FORMAT" entries)\n", 12.385 - elapsed * 1000.0, 12.386 - strong_roots * 1000.0, (strong_roots*100.0/elapsed), 12.387 - term * 1000.0, (term*100.0/elapsed), 12.388 - pss.term_attempts()); 12.389 - size_t total_waste = pss.alloc_buffer_waste() + pss.undo_waste(); 12.390 - gclog_or_tty->print(" Waste: %8dK\n" 12.391 - " Alloc Buffer: %8dK\n" 12.392 - " Undo: %8dK\n", 12.393 - (total_waste * HeapWordSize) / K, 12.394 - (pss.alloc_buffer_waste() * HeapWordSize) / K, 12.395 - (pss.undo_waste() * HeapWordSize) / K); 12.396 + MutexLocker x(stats_lock()); 12.397 + pss.print_termination_stats(i); 12.398 } 12.399 12.400 assert(pss.refs_to_scan() == 0, "Task queue should be empty"); 12.401 @@ -4260,6 +4247,7 @@ 12.402 if (ParallelGCThreads > 0) { 12.403 // The individual threads will set their evac-failure closures. 12.404 StrongRootsScope srs(this); 12.405 + if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr(); 12.406 workers()->run_task(&g1_par_task); 12.407 } else { 12.408 StrongRootsScope srs(this);
13.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Aug 13 07:33:20 2010 -0700 13.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Sat Aug 14 00:47:52 2010 -0700 13.3 @@ -46,17 +46,7 @@ 13.4 class ConcurrentG1Refine; 13.5 class ConcurrentZFThread; 13.6 13.7 -// If want to accumulate detailed statistics on work queues 13.8 -// turn this on. 13.9 -#define G1_DETAILED_STATS 0 13.10 - 13.11 -#if G1_DETAILED_STATS 13.12 -# define IF_G1_DETAILED_STATS(code) code 13.13 -#else 13.14 -# define IF_G1_DETAILED_STATS(code) 13.15 -#endif 13.16 - 13.17 -typedef GenericTaskQueue<StarTask> RefToScanQueue; 13.18 +typedef OverflowTaskQueue<StarTask> RefToScanQueue; 13.19 typedef GenericTaskQueueSet<RefToScanQueue> RefToScanQueueSet; 13.20 13.21 typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) 13.22 @@ -471,6 +461,12 @@ 13.23 virtual void shrink(size_t expand_bytes); 13.24 void shrink_helper(size_t expand_bytes); 13.25 13.26 + #if TASKQUEUE_STATS 13.27 + static void print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); 13.28 + void print_taskqueue_stats(outputStream* const st = gclog_or_tty) const; 13.29 + void reset_taskqueue_stats(); 13.30 + #endif // TASKQUEUE_STATS 13.31 + 13.32 // Do an incremental collection: identify a collection set, and evacuate 13.33 // its live objects elsewhere. 13.34 virtual void do_collection_pause(); 13.35 @@ -505,6 +501,12 @@ 13.36 // A function to check the consistency of dirty card logs. 13.37 void check_ct_logs_at_safepoint(); 13.38 13.39 + // A DirtyCardQueueSet that is used to hold cards that contain 13.40 + // references into the current collection set. This is used to 13.41 + // update the remembered sets of the regions in the collection 13.42 + // set in the event of an evacuation failure. 13.43 + DirtyCardQueueSet _into_cset_dirty_card_queue_set; 13.44 + 13.45 // After a collection pause, make the regions in the CS into free 13.46 // regions. 13.47 void free_collection_set(HeapRegion* cs_head); 13.48 @@ -656,11 +658,18 @@ 13.49 public: 13.50 void set_refine_cte_cl_concurrency(bool concurrent); 13.51 13.52 - RefToScanQueue *task_queue(int i); 13.53 + RefToScanQueue *task_queue(int i) const; 13.54 13.55 // A set of cards where updates happened during the GC 13.56 DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; } 13.57 13.58 + // A DirtyCardQueueSet that is used to hold cards that contain 13.59 + // references into the current collection set. This is used to 13.60 + // update the remembered sets of the regions in the collection 13.61 + // set in the event of an evacuation failure. 13.62 + DirtyCardQueueSet& into_cset_dirty_card_queue_set() 13.63 + { return _into_cset_dirty_card_queue_set; } 13.64 + 13.65 // Create a G1CollectedHeap with the specified policy. 13.66 // Must call the initialize method afterwards. 13.67 // May not return if something goes wrong. 13.68 @@ -715,7 +724,9 @@ 13.69 OrderAccess::fence(); 13.70 } 13.71 13.72 - void iterate_dirty_card_closure(bool concurrent, int worker_i); 13.73 + void iterate_dirty_card_closure(CardTableEntryClosure* cl, 13.74 + DirtyCardQueue* into_cset_dcq, 13.75 + bool concurrent, int worker_i); 13.76 13.77 // The shared block offset table array. 13.78 G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; } 13.79 @@ -1564,9 +1575,6 @@ 13.80 CardTableModRefBS* _ct_bs; 13.81 G1RemSet* _g1_rem; 13.82 13.83 - typedef GrowableArray<StarTask> OverflowQueue; 13.84 - OverflowQueue* _overflowed_refs; 13.85 - 13.86 G1ParGCAllocBuffer _surviving_alloc_buffer; 13.87 G1ParGCAllocBuffer _tenured_alloc_buffer; 13.88 G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount]; 13.89 @@ -1583,10 +1591,6 @@ 13.90 int _queue_num; 13.91 13.92 size_t _term_attempts; 13.93 -#if G1_DETAILED_STATS 13.94 - int _pushes, _pops, _steals, _steal_attempts; 13.95 - int _overflow_pushes; 13.96 -#endif 13.97 13.98 double _start; 13.99 double _start_strong_roots; 13.100 @@ -1600,7 +1604,7 @@ 13.101 // this points into the array, as we use the first few entries for padding 13.102 size_t* _surviving_young_words; 13.103 13.104 -#define PADDING_ELEM_NUM (64 / sizeof(size_t)) 13.105 +#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t)) 13.106 13.107 void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } 13.108 13.109 @@ -1635,15 +1639,14 @@ 13.110 } 13.111 13.112 RefToScanQueue* refs() { return _refs; } 13.113 - OverflowQueue* overflowed_refs() { return _overflowed_refs; } 13.114 ageTable* age_table() { return &_age_table; } 13.115 13.116 G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) { 13.117 return _alloc_buffers[purpose]; 13.118 } 13.119 13.120 - size_t alloc_buffer_waste() { return _alloc_buffer_waste; } 13.121 - size_t undo_waste() { return _undo_waste; } 13.122 + size_t alloc_buffer_waste() const { return _alloc_buffer_waste; } 13.123 + size_t undo_waste() const { return _undo_waste; } 13.124 13.125 template <class T> void push_on_queue(T* ref) { 13.126 assert(ref != NULL, "invariant"); 13.127 @@ -1656,12 +1659,7 @@ 13.128 assert(_g1h->obj_in_cs(p), "Should be in CS"); 13.129 } 13.130 #endif 13.131 - if (!refs()->push(ref)) { 13.132 - overflowed_refs()->push(ref); 13.133 - IF_G1_DETAILED_STATS(note_overflow_push()); 13.134 - } else { 13.135 - IF_G1_DETAILED_STATS(note_push()); 13.136 - } 13.137 + refs()->push(ref); 13.138 } 13.139 13.140 void pop_from_queue(StarTask& ref) { 13.141 @@ -1672,7 +1670,6 @@ 13.142 _g1h->is_in_g1_reserved(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref) 13.143 : oopDesc::load_decode_heap_oop((oop*)ref)), 13.144 "invariant"); 13.145 - IF_G1_DETAILED_STATS(note_pop()); 13.146 } else { 13.147 StarTask null_task; 13.148 ref = null_task; 13.149 @@ -1680,7 +1677,8 @@ 13.150 } 13.151 13.152 void pop_from_overflow_queue(StarTask& ref) { 13.153 - StarTask new_ref = overflowed_refs()->pop(); 13.154 + StarTask new_ref; 13.155 + refs()->pop_overflow(new_ref); 13.156 assert((oop*)new_ref != NULL, "pop() from a local non-empty stack"); 13.157 assert(UseCompressedOops || !new_ref.is_narrow(), "Error"); 13.158 assert(has_partial_array_mask((oop*)new_ref) || 13.159 @@ -1690,8 +1688,8 @@ 13.160 ref = new_ref; 13.161 } 13.162 13.163 - int refs_to_scan() { return refs()->size(); } 13.164 - int overflowed_refs_to_scan() { return overflowed_refs()->length(); } 13.165 + int refs_to_scan() { return refs()->size(); } 13.166 + int overflowed_refs_to_scan() { return refs()->overflow_stack()->length(); } 13.167 13.168 template <class T> void update_rs(HeapRegion* from, T* p, int tid) { 13.169 if (G1DeferredRSUpdate) { 13.170 @@ -1760,30 +1758,16 @@ 13.171 int* hash_seed() { return &_hash_seed; } 13.172 int queue_num() { return _queue_num; } 13.173 13.174 - size_t term_attempts() { return _term_attempts; } 13.175 + size_t term_attempts() const { return _term_attempts; } 13.176 void note_term_attempt() { _term_attempts++; } 13.177 13.178 -#if G1_DETAILED_STATS 13.179 - int pushes() { return _pushes; } 13.180 - int pops() { return _pops; } 13.181 - int steals() { return _steals; } 13.182 - int steal_attempts() { return _steal_attempts; } 13.183 - int overflow_pushes() { return _overflow_pushes; } 13.184 - 13.185 - void note_push() { _pushes++; } 13.186 - void note_pop() { _pops++; } 13.187 - void note_steal() { _steals++; } 13.188 - void note_steal_attempt() { _steal_attempts++; } 13.189 - void note_overflow_push() { _overflow_pushes++; } 13.190 -#endif 13.191 - 13.192 void start_strong_roots() { 13.193 _start_strong_roots = os::elapsedTime(); 13.194 } 13.195 void end_strong_roots() { 13.196 _strong_roots_time += (os::elapsedTime() - _start_strong_roots); 13.197 } 13.198 - double strong_roots_time() { return _strong_roots_time; } 13.199 + double strong_roots_time() const { return _strong_roots_time; } 13.200 13.201 void start_term_time() { 13.202 note_term_attempt(); 13.203 @@ -1792,12 +1776,17 @@ 13.204 void end_term_time() { 13.205 _term_time += (os::elapsedTime() - _start_term); 13.206 } 13.207 - double term_time() { return _term_time; } 13.208 + double term_time() const { return _term_time; } 13.209 13.210 - double elapsed() { 13.211 + double elapsed_time() const { 13.212 return os::elapsedTime() - _start; 13.213 } 13.214 13.215 + static void 13.216 + print_termination_stats_hdr(outputStream* const st = gclog_or_tty); 13.217 + void 13.218 + print_termination_stats(int i, outputStream* const st = gclog_or_tty) const; 13.219 + 13.220 size_t* surviving_young_words() { 13.221 // We add on to hide entry 0 which accumulates surviving words for 13.222 // age -1 regions (i.e. non-young ones)
14.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Aug 13 07:33:20 2010 -0700 14.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Sat Aug 14 00:47:52 2010 -0700 14.3 @@ -81,11 +81,10 @@ 14.4 return attempt_allocation_slow(word_size, permit_collection_pause); 14.5 } 14.6 14.7 -inline RefToScanQueue* G1CollectedHeap::task_queue(int i) { 14.8 +inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const { 14.9 return _task_queues->queue(i); 14.10 } 14.11 14.12 - 14.13 inline bool G1CollectedHeap::isMarkedPrev(oop obj) const { 14.14 return _cm->prevMarkBitMap()->isMarked((HeapWord *)obj); 14.15 }
15.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Aug 13 07:33:20 2010 -0700 15.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Sat Aug 14 00:47:52 2010 -0700 15.3 @@ -88,7 +88,6 @@ 15.4 _all_mod_union_times_ms(new NumberSeq()), 15.5 15.6 _summary(new Summary()), 15.7 - _abandoned_summary(new AbandonedSummary()), 15.8 15.9 #ifndef PRODUCT 15.10 _cur_clear_ct_time_ms(0.0), 15.11 @@ -238,7 +237,6 @@ 15.12 _par_last_update_rs_processed_buffers = new double[_parallel_gc_threads]; 15.13 15.14 _par_last_scan_rs_times_ms = new double[_parallel_gc_threads]; 15.15 - _par_last_scan_new_refs_times_ms = new double[_parallel_gc_threads]; 15.16 15.17 _par_last_obj_copy_times_ms = new double[_parallel_gc_threads]; 15.18 15.19 @@ -842,7 +840,6 @@ 15.20 _par_last_update_rs_times_ms[i] = -1234.0; 15.21 _par_last_update_rs_processed_buffers[i] = -1234.0; 15.22 _par_last_scan_rs_times_ms[i] = -1234.0; 15.23 - _par_last_scan_new_refs_times_ms[i] = -1234.0; 15.24 _par_last_obj_copy_times_ms[i] = -1234.0; 15.25 _par_last_termination_times_ms[i] = -1234.0; 15.26 _par_last_termination_attempts[i] = -1234.0; 15.27 @@ -1126,7 +1123,7 @@ 15.28 // Anything below that is considered to be zero 15.29 #define MIN_TIMER_GRANULARITY 0.0000001 15.30 15.31 -void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { 15.32 +void G1CollectorPolicy::record_collection_pause_end() { 15.33 double end_time_sec = os::elapsedTime(); 15.34 double elapsed_ms = _last_pause_time_ms; 15.35 bool parallel = ParallelGCThreads > 0; 15.36 @@ -1136,7 +1133,7 @@ 15.37 size_t cur_used_bytes = _g1->used(); 15.38 assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); 15.39 bool last_pause_included_initial_mark = false; 15.40 - bool update_stats = !abandoned && !_g1->evacuation_failed(); 15.41 + bool update_stats = !_g1->evacuation_failed(); 15.42 15.43 #ifndef PRODUCT 15.44 if (G1YoungSurvRateVerbose) { 15.45 @@ -1275,12 +1272,7 @@ 15.46 gclog_or_tty->print_cr(" Recording collection pause(%d)", _n_pauses); 15.47 } 15.48 15.49 - PauseSummary* summary; 15.50 - if (abandoned) { 15.51 - summary = _abandoned_summary; 15.52 - } else { 15.53 - summary = _summary; 15.54 - } 15.55 + PauseSummary* summary = _summary; 15.56 15.57 double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); 15.58 double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); 15.59 @@ -1348,61 +1340,58 @@ 15.60 15.61 double other_time_ms = elapsed_ms; 15.62 15.63 - if (!abandoned) { 15.64 - if (_satb_drain_time_set) 15.65 - other_time_ms -= _cur_satb_drain_time_ms; 15.66 - 15.67 - if (parallel) 15.68 - other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms; 15.69 - else 15.70 - other_time_ms -= 15.71 - update_rs_time + 15.72 - ext_root_scan_time + mark_stack_scan_time + 15.73 - scan_rs_time + obj_copy_time; 15.74 + if (_satb_drain_time_set) { 15.75 + other_time_ms -= _cur_satb_drain_time_ms; 15.76 } 15.77 15.78 + if (parallel) { 15.79 + other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms; 15.80 + } else { 15.81 + other_time_ms -= 15.82 + update_rs_time + 15.83 + ext_root_scan_time + mark_stack_scan_time + 15.84 + scan_rs_time + obj_copy_time; 15.85 + } 15.86 + 15.87 if (PrintGCDetails) { 15.88 - gclog_or_tty->print_cr("%s%s, %1.8lf secs]", 15.89 - abandoned ? " (abandoned)" : "", 15.90 + gclog_or_tty->print_cr("%s, %1.8lf secs]", 15.91 (last_pause_included_initial_mark) ? " (initial-mark)" : "", 15.92 elapsed_ms / 1000.0); 15.93 15.94 - if (!abandoned) { 15.95 - if (_satb_drain_time_set) { 15.96 - print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); 15.97 - } 15.98 - if (_last_satb_drain_processed_buffers >= 0) { 15.99 - print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); 15.100 - } 15.101 - if (parallel) { 15.102 - print_stats(1, "Parallel Time", _cur_collection_par_time_ms); 15.103 - print_par_stats(2, "GC Worker Start Time", 15.104 - _par_last_gc_worker_start_times_ms, false); 15.105 - print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); 15.106 - print_par_sizes(3, "Processed Buffers", 15.107 - _par_last_update_rs_processed_buffers, true); 15.108 - print_par_stats(2, "Ext Root Scanning", 15.109 - _par_last_ext_root_scan_times_ms); 15.110 - print_par_stats(2, "Mark Stack Scanning", 15.111 - _par_last_mark_stack_scan_times_ms); 15.112 - print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); 15.113 - print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); 15.114 - print_par_stats(2, "Termination", _par_last_termination_times_ms); 15.115 - print_par_sizes(3, "Termination Attempts", 15.116 - _par_last_termination_attempts, true); 15.117 - print_par_stats(2, "GC Worker End Time", 15.118 - _par_last_gc_worker_end_times_ms, false); 15.119 - print_stats(2, "Other", parallel_other_time); 15.120 - print_stats(1, "Clear CT", _cur_clear_ct_time_ms); 15.121 - } else { 15.122 - print_stats(1, "Update RS", update_rs_time); 15.123 - print_stats(2, "Processed Buffers", 15.124 - (int)update_rs_processed_buffers); 15.125 - print_stats(1, "Ext Root Scanning", ext_root_scan_time); 15.126 - print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); 15.127 - print_stats(1, "Scan RS", scan_rs_time); 15.128 - print_stats(1, "Object Copying", obj_copy_time); 15.129 - } 15.130 + if (_satb_drain_time_set) { 15.131 + print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); 15.132 + } 15.133 + if (_last_satb_drain_processed_buffers >= 0) { 15.134 + print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); 15.135 + } 15.136 + if (parallel) { 15.137 + print_stats(1, "Parallel Time", _cur_collection_par_time_ms); 15.138 + print_par_stats(2, "GC Worker Start Time", 15.139 + _par_last_gc_worker_start_times_ms, false); 15.140 + print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); 15.141 + print_par_sizes(3, "Processed Buffers", 15.142 + _par_last_update_rs_processed_buffers, true); 15.143 + print_par_stats(2, "Ext Root Scanning", 15.144 + _par_last_ext_root_scan_times_ms); 15.145 + print_par_stats(2, "Mark Stack Scanning", 15.146 + _par_last_mark_stack_scan_times_ms); 15.147 + print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); 15.148 + print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); 15.149 + print_par_stats(2, "Termination", _par_last_termination_times_ms); 15.150 + print_par_sizes(3, "Termination Attempts", 15.151 + _par_last_termination_attempts, true); 15.152 + print_par_stats(2, "GC Worker End Time", 15.153 + _par_last_gc_worker_end_times_ms, false); 15.154 + print_stats(2, "Other", parallel_other_time); 15.155 + print_stats(1, "Clear CT", _cur_clear_ct_time_ms); 15.156 + } else { 15.157 + print_stats(1, "Update RS", update_rs_time); 15.158 + print_stats(2, "Processed Buffers", 15.159 + (int)update_rs_processed_buffers); 15.160 + print_stats(1, "Ext Root Scanning", ext_root_scan_time); 15.161 + print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); 15.162 + print_stats(1, "Scan RS", scan_rs_time); 15.163 + print_stats(1, "Object Copying", obj_copy_time); 15.164 } 15.165 #ifndef PRODUCT 15.166 print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms); 15.167 @@ -2178,33 +2167,27 @@ 15.168 print_summary(1, "Other", summary->get_other_seq()); 15.169 { 15.170 NumberSeq calc_other_times_ms; 15.171 - if (body_summary != NULL) { 15.172 - // not abandoned 15.173 - if (parallel) { 15.174 - // parallel 15.175 - NumberSeq* other_parts[] = { 15.176 - body_summary->get_satb_drain_seq(), 15.177 - body_summary->get_parallel_seq(), 15.178 - body_summary->get_clear_ct_seq() 15.179 - }; 15.180 - calc_other_times_ms = NumberSeq(summary->get_total_seq(), 15.181 - 3, other_parts); 15.182 - } else { 15.183 - // serial 15.184 - NumberSeq* other_parts[] = { 15.185 - body_summary->get_satb_drain_seq(), 15.186 - body_summary->get_update_rs_seq(), 15.187 - body_summary->get_ext_root_scan_seq(), 15.188 - body_summary->get_mark_stack_scan_seq(), 15.189 - body_summary->get_scan_rs_seq(), 15.190 - body_summary->get_obj_copy_seq() 15.191 - }; 15.192 - calc_other_times_ms = NumberSeq(summary->get_total_seq(), 15.193 - 7, other_parts); 15.194 - } 15.195 + if (parallel) { 15.196 + // parallel 15.197 + NumberSeq* other_parts[] = { 15.198 + body_summary->get_satb_drain_seq(), 15.199 + body_summary->get_parallel_seq(), 15.200 + body_summary->get_clear_ct_seq() 15.201 + }; 15.202 + calc_other_times_ms = NumberSeq(summary->get_total_seq(), 15.203 + 3, other_parts); 15.204 } else { 15.205 - // abandoned 15.206 - calc_other_times_ms = NumberSeq(); 15.207 + // serial 15.208 + NumberSeq* other_parts[] = { 15.209 + body_summary->get_satb_drain_seq(), 15.210 + body_summary->get_update_rs_seq(), 15.211 + body_summary->get_ext_root_scan_seq(), 15.212 + body_summary->get_mark_stack_scan_seq(), 15.213 + body_summary->get_scan_rs_seq(), 15.214 + body_summary->get_obj_copy_seq() 15.215 + }; 15.216 + calc_other_times_ms = NumberSeq(summary->get_total_seq(), 15.217 + 7, other_parts); 15.218 } 15.219 check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); 15.220 } 15.221 @@ -2215,20 +2198,6 @@ 15.222 gclog_or_tty->print_cr(""); 15.223 } 15.224 15.225 -void 15.226 -G1CollectorPolicy::print_abandoned_summary(PauseSummary* summary) const { 15.227 - bool printed = false; 15.228 - if (summary->get_total_seq()->num() > 0) { 15.229 - printed = true; 15.230 - print_summary(summary); 15.231 - } 15.232 - if (!printed) { 15.233 - print_indent(0); 15.234 - gclog_or_tty->print_cr("none"); 15.235 - gclog_or_tty->print_cr(""); 15.236 - } 15.237 -} 15.238 - 15.239 void G1CollectorPolicy::print_tracing_info() const { 15.240 if (TraceGen0Time) { 15.241 gclog_or_tty->print_cr("ALL PAUSES"); 15.242 @@ -2242,9 +2211,6 @@ 15.243 gclog_or_tty->print_cr("EVACUATION PAUSES"); 15.244 print_summary(_summary); 15.245 15.246 - gclog_or_tty->print_cr("ABANDONED PAUSES"); 15.247 - print_abandoned_summary(_abandoned_summary); 15.248 - 15.249 gclog_or_tty->print_cr("MISC"); 15.250 print_summary_sd(0, "Stop World", _all_stop_world_times_ms); 15.251 print_summary_sd(0, "Yields", _all_yield_times_ms); 15.252 @@ -2870,19 +2836,12 @@ 15.253 } 15.254 #endif // !PRODUCT 15.255 15.256 -bool 15.257 +void 15.258 G1CollectorPolicy_BestRegionsFirst::choose_collection_set( 15.259 double target_pause_time_ms) { 15.260 // Set this here - in case we're not doing young collections. 15.261 double non_young_start_time_sec = os::elapsedTime(); 15.262 15.263 - // The result that this routine will return. This will be set to 15.264 - // false if: 15.265 - // * we're doing a young or partially young collection and we 15.266 - // have added the youg regions to collection set, or 15.267 - // * we add old regions to the collection set. 15.268 - bool abandon_collection = true; 15.269 - 15.270 start_recording_regions(); 15.271 15.272 guarantee(target_pause_time_ms > 0.0, 15.273 @@ -2986,10 +2945,6 @@ 15.274 } 15.275 15.276 assert(_inc_cset_size == _g1->young_list()->length(), "Invariant"); 15.277 - if (_inc_cset_size > 0) { 15.278 - assert(_collection_set != NULL, "Invariant"); 15.279 - abandon_collection = false; 15.280 - } 15.281 15.282 double young_end_time_sec = os::elapsedTime(); 15.283 _recorded_young_cset_choice_time_ms = 15.284 @@ -3011,10 +2966,6 @@ 15.285 NumberSeq seq; 15.286 double avg_prediction = 100000000000000000.0; // something very large 15.287 15.288 - // Save the current size of the collection set to detect 15.289 - // if we actually added any old regions. 15.290 - size_t n_young_regions = _collection_set_size; 15.291 - 15.292 do { 15.293 hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms, 15.294 avg_prediction); 15.295 @@ -3041,12 +2992,6 @@ 15.296 if (!adaptive_young_list_length() && 15.297 _collection_set_size < _young_list_fixed_length) 15.298 _should_revert_to_full_young_gcs = true; 15.299 - 15.300 - if (_collection_set_size > n_young_regions) { 15.301 - // We actually added old regions to the collection set 15.302 - // so we are not abandoning this collection. 15.303 - abandon_collection = false; 15.304 - } 15.305 } 15.306 15.307 choose_collection_set_end: 15.308 @@ -3059,19 +3004,6 @@ 15.309 double non_young_end_time_sec = os::elapsedTime(); 15.310 _recorded_non_young_cset_choice_time_ms = 15.311 (non_young_end_time_sec - non_young_start_time_sec) * 1000.0; 15.312 - 15.313 - // Here we are supposed to return whether the pause should be 15.314 - // abandoned or not (i.e., whether the collection set is empty or 15.315 - // not). However, this introduces a subtle issue when a pause is 15.316 - // initiated explicitly with System.gc() and 15.317 - // +ExplicitGCInvokesConcurrent (see Comment #2 in CR 6944166), it's 15.318 - // supposed to start a marking cycle, and it's abandoned. So, by 15.319 - // returning false here we are telling the caller never to consider 15.320 - // a pause to be abandoned. We'll actually remove all the code 15.321 - // associated with abandoned pauses as part of CR 6963209, but we are 15.322 - // just disabling them this way for the moment to avoid increasing 15.323 - // further the amount of changes for CR 6944166. 15.324 - return false; 15.325 } 15.326 15.327 void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() { 15.328 @@ -3086,7 +3018,7 @@ 15.329 } 15.330 15.331 void G1CollectorPolicy_BestRegionsFirst:: 15.332 -record_collection_pause_end(bool abandoned) { 15.333 - G1CollectorPolicy::record_collection_pause_end(abandoned); 15.334 +record_collection_pause_end() { 15.335 + G1CollectorPolicy::record_collection_pause_end(); 15.336 assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end."); 15.337 }
16.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Fri Aug 13 07:33:20 2010 -0700 16.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Sat Aug 14 00:47:52 2010 -0700 16.3 @@ -63,8 +63,6 @@ 16.4 define_num_seq(mark_stack_scan) 16.5 define_num_seq(update_rs) 16.6 define_num_seq(scan_rs) 16.7 - define_num_seq(scan_new_refs) // Only for temp use; added to 16.8 - // in parallel case. 16.9 define_num_seq(obj_copy) 16.10 define_num_seq(termination) // parallel only 16.11 define_num_seq(parallel_other) // parallel only 16.12 @@ -78,9 +76,6 @@ 16.13 virtual MainBodySummary* main_body_summary() { return this; } 16.14 }; 16.15 16.16 -class AbandonedSummary: public PauseSummary { 16.17 -}; 16.18 - 16.19 class G1CollectorPolicy: public CollectorPolicy { 16.20 protected: 16.21 // The number of pauses during the execution. 16.22 @@ -150,7 +145,6 @@ 16.23 TruncatedSeq* _concurrent_mark_cleanup_times_ms; 16.24 16.25 Summary* _summary; 16.26 - AbandonedSummary* _abandoned_summary; 16.27 16.28 NumberSeq* _all_pause_times_ms; 16.29 NumberSeq* _all_full_gc_times_ms; 16.30 @@ -177,7 +171,6 @@ 16.31 double* _par_last_update_rs_times_ms; 16.32 double* _par_last_update_rs_processed_buffers; 16.33 double* _par_last_scan_rs_times_ms; 16.34 - double* _par_last_scan_new_refs_times_ms; 16.35 double* _par_last_obj_copy_times_ms; 16.36 double* _par_last_termination_times_ms; 16.37 double* _par_last_termination_attempts; 16.38 @@ -576,7 +569,6 @@ 16.39 NumberSeq* calc_other_times_ms) const; 16.40 16.41 void print_summary (PauseSummary* stats) const; 16.42 - void print_abandoned_summary(PauseSummary* summary) const; 16.43 16.44 void print_summary (int level, const char* str, NumberSeq* seq) const; 16.45 void print_summary_sd (int level, const char* str, NumberSeq* seq) const; 16.46 @@ -889,7 +881,7 @@ 16.47 virtual void record_collection_pause_end_CH_strong_roots(); 16.48 virtual void record_collection_pause_end_G1_strong_roots(); 16.49 16.50 - virtual void record_collection_pause_end(bool abandoned); 16.51 + virtual void record_collection_pause_end(); 16.52 16.53 // Record the fact that a full collection occurred. 16.54 virtual void record_full_collection_start(); 16.55 @@ -933,14 +925,6 @@ 16.56 _par_last_scan_rs_times_ms[thread] = ms; 16.57 } 16.58 16.59 - void record_scan_new_refs_time(int thread, double ms) { 16.60 - _par_last_scan_new_refs_times_ms[thread] = ms; 16.61 - } 16.62 - 16.63 - double get_scan_new_refs_time(int thread) { 16.64 - return _par_last_scan_new_refs_times_ms[thread]; 16.65 - } 16.66 - 16.67 void reset_obj_copy_time(int thread) { 16.68 _par_last_obj_copy_times_ms[thread] = 0.0; 16.69 } 16.70 @@ -1010,7 +994,7 @@ 16.71 // Choose a new collection set. Marks the chosen regions as being 16.72 // "in_collection_set", and links them together. The head and number of 16.73 // the collection set are available via access methods. 16.74 - virtual bool choose_collection_set(double target_pause_time_ms) = 0; 16.75 + virtual void choose_collection_set(double target_pause_time_ms) = 0; 16.76 16.77 // The head of the list (via "next_in_collection_set()") representing the 16.78 // current collection set. 16.79 @@ -1267,7 +1251,7 @@ 16.80 // If the estimated is less then desirable, resize if possible. 16.81 void expand_if_possible(size_t numRegions); 16.82 16.83 - virtual bool choose_collection_set(double target_pause_time_ms); 16.84 + virtual void choose_collection_set(double target_pause_time_ms); 16.85 virtual void record_collection_pause_start(double start_time_sec, 16.86 size_t start_used); 16.87 virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, 16.88 @@ -1278,7 +1262,7 @@ 16.89 G1CollectorPolicy_BestRegionsFirst() { 16.90 _collectionSetChooser = new CollectionSetChooser(); 16.91 } 16.92 - void record_collection_pause_end(bool abandoned); 16.93 + void record_collection_pause_end(); 16.94 bool should_do_collection_pause(size_t word_size); 16.95 // This is not needed any more, after the CSet choosing code was 16.96 // changed to use the pause prediction work. But let's leave the
17.1 --- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Fri Aug 13 07:33:20 2010 -0700 17.2 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Sat Aug 14 00:47:52 2010 -0700 17.3 @@ -1,5 +1,5 @@ 17.4 /* 17.5 - * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved. 17.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 17.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.8 * 17.9 * This code is free software; you can redistribute it and/or modify it 17.10 @@ -37,7 +37,8 @@ 17.11 _g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) { 17.12 _oc->do_oop(p); 17.13 #if FILTERINTOCSCLOSURE_DOHISTOGRAMCOUNT 17.14 - _dcto_cl->incr_count(); 17.15 + if (_dcto_cl != NULL) 17.16 + _dcto_cl->incr_count(); 17.17 #endif 17.18 } 17.19 } 17.20 @@ -113,7 +114,10 @@ 17.21 if (_g1->in_cset_fast_test(obj)) { 17.22 Prefetch::write(obj->mark_addr(), 0); 17.23 Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); 17.24 + 17.25 + // Place on the references queue 17.26 _par_scan_state->push_on_queue(p); 17.27 } 17.28 } 17.29 } 17.30 +
18.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Aug 13 07:33:20 2010 -0700 18.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Sat Aug 14 00:47:52 2010 -0700 18.3 @@ -122,23 +122,24 @@ 18.4 HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs) 18.5 : G1RemSet(g1), _ct_bs(ct_bs), _g1p(_g1->g1_policy()), 18.6 _cg1r(g1->concurrent_g1_refine()), 18.7 - _par_traversal_in_progress(false), _new_refs(NULL), 18.8 + _traversal_in_progress(false), 18.9 + _cset_rs_update_cl(NULL), 18.10 _cards_scanned(NULL), _total_cards_scanned(0) 18.11 { 18.12 _seq_task = new SubTasksDone(NumSeqTasks); 18.13 guarantee(n_workers() > 0, "There should be some workers"); 18.14 - _new_refs = NEW_C_HEAP_ARRAY(GrowableArray<OopOrNarrowOopStar>*, n_workers()); 18.15 + _cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers()); 18.16 for (uint i = 0; i < n_workers(); i++) { 18.17 - _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<OopOrNarrowOopStar>(8192,true); 18.18 + _cset_rs_update_cl[i] = NULL; 18.19 } 18.20 } 18.21 18.22 HRInto_G1RemSet::~HRInto_G1RemSet() { 18.23 delete _seq_task; 18.24 for (uint i = 0; i < n_workers(); i++) { 18.25 - delete _new_refs[i]; 18.26 + assert(_cset_rs_update_cl[i] == NULL, "it should be"); 18.27 } 18.28 - FREE_C_HEAP_ARRAY(GrowableArray<OopOrNarrowOopStar>*, _new_refs); 18.29 + FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl); 18.30 } 18.31 18.32 void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { 18.33 @@ -306,12 +307,45 @@ 18.34 _g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); 18.35 } 18.36 18.37 -void HRInto_G1RemSet::updateRS(int worker_i) { 18.38 - ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine(); 18.39 +// Closure used for updating RSets and recording references that 18.40 +// point into the collection set. Only called during an 18.41 +// evacuation pause. 18.42 18.43 +class RefineRecordRefsIntoCSCardTableEntryClosure: public CardTableEntryClosure { 18.44 + G1RemSet* _g1rs; 18.45 + DirtyCardQueue* _into_cset_dcq; 18.46 +public: 18.47 + RefineRecordRefsIntoCSCardTableEntryClosure(G1CollectedHeap* g1h, 18.48 + DirtyCardQueue* into_cset_dcq) : 18.49 + _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq) 18.50 + {} 18.51 + bool do_card_ptr(jbyte* card_ptr, int worker_i) { 18.52 + // The only time we care about recording cards that 18.53 + // contain references that point into the collection set 18.54 + // is during RSet updating within an evacuation pause. 18.55 + // In this case worker_i should be the id of a GC worker thread. 18.56 + assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); 18.57 + assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "should be a GC worker"); 18.58 + 18.59 + if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) { 18.60 + // 'card_ptr' contains references that point into the collection 18.61 + // set. We need to record the card in the DCQS 18.62 + // (G1CollectedHeap::into_cset_dirty_card_queue_set()) 18.63 + // that's used for that purpose. 18.64 + // 18.65 + // Enqueue the card 18.66 + _into_cset_dcq->enqueue(card_ptr); 18.67 + } 18.68 + return true; 18.69 + } 18.70 +}; 18.71 + 18.72 +void HRInto_G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) { 18.73 double start = os::elapsedTime(); 18.74 - // Apply the appropriate closure to all remaining log entries. 18.75 - _g1->iterate_dirty_card_closure(false, worker_i); 18.76 + // Apply the given closure to all remaining log entries. 18.77 + RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); 18.78 + _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); 18.79 + 18.80 // Now there should be no dirty cards. 18.81 if (G1RSLogCheckCardTable) { 18.82 CountNonCleanMemRegionClosure cl(_g1); 18.83 @@ -405,33 +439,6 @@ 18.84 } 18.85 }; 18.86 18.87 -template <class T> void 18.88 -HRInto_G1RemSet::scanNewRefsRS_work(OopsInHeapRegionClosure* oc, 18.89 - int worker_i) { 18.90 - double scan_new_refs_start_sec = os::elapsedTime(); 18.91 - G1CollectedHeap* g1h = G1CollectedHeap::heap(); 18.92 - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); 18.93 - for (int i = 0; i < _new_refs[worker_i]->length(); i++) { 18.94 - T* p = (T*) _new_refs[worker_i]->at(i); 18.95 - oop obj = oopDesc::load_decode_heap_oop(p); 18.96 - // *p was in the collection set when p was pushed on "_new_refs", but 18.97 - // another thread may have processed this location from an RS, so it 18.98 - // might not point into the CS any longer. If so, it's obviously been 18.99 - // processed, and we don't need to do anything further. 18.100 - if (g1h->obj_in_cs(obj)) { 18.101 - HeapRegion* r = g1h->heap_region_containing(p); 18.102 - 18.103 - DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj)); 18.104 - oc->set_region(r); 18.105 - // If "p" has already been processed concurrently, this is 18.106 - // idempotent. 18.107 - oc->do_oop(p); 18.108 - } 18.109 - } 18.110 - double scan_new_refs_time_ms = (os::elapsedTime() - scan_new_refs_start_sec) * 1000.0; 18.111 - _g1p->record_scan_new_refs_time(worker_i, scan_new_refs_time_ms); 18.112 -} 18.113 - 18.114 void HRInto_G1RemSet::cleanupHRRS() { 18.115 HeapRegionRemSet::cleanup(); 18.116 } 18.117 @@ -457,32 +464,48 @@ 18.118 count_cl.print_histo(); 18.119 } 18.120 18.121 - if (ParallelGCThreads > 0) { 18.122 - // The two flags below were introduced temporarily to serialize 18.123 - // the updating and scanning of remembered sets. There are some 18.124 - // race conditions when these two operations are done in parallel 18.125 - // and they are causing failures. When we resolve said race 18.126 - // conditions, we'll revert back to parallel remembered set 18.127 - // updating and scanning. See CRs 6677707 and 6677708. 18.128 - if (G1UseParallelRSetUpdating || (worker_i == 0)) { 18.129 - updateRS(worker_i); 18.130 - scanNewRefsRS(oc, worker_i); 18.131 - } else { 18.132 - _g1p->record_update_rs_processed_buffers(worker_i, 0.0); 18.133 - _g1p->record_update_rs_time(worker_i, 0.0); 18.134 - _g1p->record_scan_new_refs_time(worker_i, 0.0); 18.135 - } 18.136 - if (G1UseParallelRSetScanning || (worker_i == 0)) { 18.137 - scanRS(oc, worker_i); 18.138 - } else { 18.139 - _g1p->record_scan_rs_time(worker_i, 0.0); 18.140 - } 18.141 + // We cache the value of 'oc' closure into the appropriate slot in the 18.142 + // _cset_rs_update_cl for this worker 18.143 + assert(worker_i < (int)n_workers(), "sanity"); 18.144 + _cset_rs_update_cl[worker_i] = oc; 18.145 + 18.146 + // A DirtyCardQueue that is used to hold cards containing references 18.147 + // that point into the collection set. This DCQ is associated with a 18.148 + // special DirtyCardQueueSet (see g1CollectedHeap.hpp). Under normal 18.149 + // circumstances (i.e. the pause successfully completes), these cards 18.150 + // are just discarded (there's no need to update the RSets of regions 18.151 + // that were in the collection set - after the pause these regions 18.152 + // are wholly 'free' of live objects. In the event of an evacuation 18.153 + // failure the cards/buffers in this queue set are: 18.154 + // * passed to the DirtyCardQueueSet that is used to manage deferred 18.155 + // RSet updates, or 18.156 + // * scanned for references that point into the collection set 18.157 + // and the RSet of the corresponding region in the collection set 18.158 + // is updated immediately. 18.159 + DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); 18.160 + 18.161 + assert((ParallelGCThreads > 0) || worker_i == 0, "invariant"); 18.162 + 18.163 + // The two flags below were introduced temporarily to serialize 18.164 + // the updating and scanning of remembered sets. There are some 18.165 + // race conditions when these two operations are done in parallel 18.166 + // and they are causing failures. When we resolve said race 18.167 + // conditions, we'll revert back to parallel remembered set 18.168 + // updating and scanning. See CRs 6677707 and 6677708. 18.169 + if (G1UseParallelRSetUpdating || (worker_i == 0)) { 18.170 + updateRS(&into_cset_dcq, worker_i); 18.171 } else { 18.172 - assert(worker_i == 0, "invariant"); 18.173 - updateRS(0); 18.174 - scanNewRefsRS(oc, 0); 18.175 - scanRS(oc, 0); 18.176 + _g1p->record_update_rs_processed_buffers(worker_i, 0.0); 18.177 + _g1p->record_update_rs_time(worker_i, 0.0); 18.178 } 18.179 + if (G1UseParallelRSetScanning || (worker_i == 0)) { 18.180 + scanRS(oc, worker_i); 18.181 + } else { 18.182 + _g1p->record_scan_rs_time(worker_i, 0.0); 18.183 + } 18.184 + 18.185 + // We now clear the cached values of _cset_rs_update_cl for this worker 18.186 + _cset_rs_update_cl[worker_i] = NULL; 18.187 } 18.188 18.189 void HRInto_G1RemSet:: 18.190 @@ -497,9 +520,9 @@ 18.191 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 18.192 dcqs.concatenate_logs(); 18.193 18.194 - assert(!_par_traversal_in_progress, "Invariant between iterations."); 18.195 + assert(!_traversal_in_progress, "Invariant between iterations."); 18.196 + set_traversal(true); 18.197 if (ParallelGCThreads > 0) { 18.198 - set_par_traversal(true); 18.199 _seq_task->set_par_threads((int)n_workers()); 18.200 } 18.201 guarantee( _cards_scanned == NULL, "invariant" ); 18.202 @@ -519,49 +542,65 @@ 18.203 } 18.204 }; 18.205 18.206 -class UpdateRSetOopsIntoCSImmediate : public OopClosure { 18.207 +// This closure, applied to a DirtyCardQueueSet, is used to immediately 18.208 +// update the RSets for the regions in the CSet. For each card it iterates 18.209 +// through the oops which coincide with that card. It scans the reference 18.210 +// fields in each oop; when it finds an oop that points into the collection 18.211 +// set, the RSet for the region containing the referenced object is updated. 18.212 +// Note: _par_traversal_in_progress in the G1RemSet must be FALSE; otherwise 18.213 +// the UpdateRSetImmediate closure will cause cards to be enqueued on to 18.214 +// the DCQS that we're iterating over, causing an infinite loop. 18.215 +class UpdateRSetCardTableEntryIntoCSetClosure: public CardTableEntryClosure { 18.216 G1CollectedHeap* _g1; 18.217 + CardTableModRefBS* _ct_bs; 18.218 public: 18.219 - UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { } 18.220 - virtual void do_oop(narrowOop* p) { do_oop_work(p); } 18.221 - virtual void do_oop( oop* p) { do_oop_work(p); } 18.222 - template <class T> void do_oop_work(T* p) { 18.223 - HeapRegion* to = _g1->heap_region_containing(oopDesc::load_decode_heap_oop(p)); 18.224 - if (to->in_collection_set()) { 18.225 - to->rem_set()->add_reference(p, 0); 18.226 - } 18.227 + UpdateRSetCardTableEntryIntoCSetClosure(G1CollectedHeap* g1, 18.228 + CardTableModRefBS* bs): 18.229 + _g1(g1), _ct_bs(bs) 18.230 + { } 18.231 + 18.232 + bool do_card_ptr(jbyte* card_ptr, int worker_i) { 18.233 + // Construct the region representing the card. 18.234 + HeapWord* start = _ct_bs->addr_for(card_ptr); 18.235 + // And find the region containing it. 18.236 + HeapRegion* r = _g1->heap_region_containing(start); 18.237 + assert(r != NULL, "unexpected null"); 18.238 + 18.239 + // Scan oops in the card looking for references into the collection set 18.240 + HeapWord* end = _ct_bs->addr_for(card_ptr + 1); 18.241 + MemRegion scanRegion(start, end); 18.242 + 18.243 + UpdateRSetImmediate update_rs_cl(_g1->g1_rem_set()); 18.244 + FilterIntoCSClosure update_rs_cset_oop_cl(NULL, _g1, &update_rs_cl); 18.245 + FilterOutOfRegionClosure filter_then_update_rs_cset_oop_cl(r, &update_rs_cset_oop_cl); 18.246 + 18.247 + // We can pass false as the "filter_young" parameter here as: 18.248 + // * we should be in a STW pause, 18.249 + // * the DCQS to which this closure is applied is used to hold 18.250 + // references that point into the collection set from the prior 18.251 + // RSet updating, 18.252 + // * the post-write barrier shouldn't be logging updates to young 18.253 + // regions (but there is a situation where this can happen - see 18.254 + // the comment in HRInto_G1RemSet::concurrentRefineOneCard below - 18.255 + // that should not be applicable here), and 18.256 + // * during actual RSet updating, the filtering of cards in young 18.257 + // regions in HeapRegion::oops_on_card_seq_iterate_careful is 18.258 + // employed. 18.259 + // As a result, when this closure is applied to "refs into cset" 18.260 + // DCQS, we shouldn't see any cards in young regions. 18.261 + update_rs_cl.set_region(r); 18.262 + HeapWord* stop_point = 18.263 + r->oops_on_card_seq_iterate_careful(scanRegion, 18.264 + &filter_then_update_rs_cset_oop_cl, 18.265 + false /* filter_young */); 18.266 + 18.267 + // Since this is performed in the event of an evacuation failure, we 18.268 + // we shouldn't see a non-null stop point 18.269 + assert(stop_point == NULL, "saw an unallocated region"); 18.270 + return true; 18.271 } 18.272 }; 18.273 18.274 -class UpdateRSetOopsIntoCSDeferred : public OopClosure { 18.275 - G1CollectedHeap* _g1; 18.276 - CardTableModRefBS* _ct_bs; 18.277 - DirtyCardQueue* _dcq; 18.278 -public: 18.279 - UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : 18.280 - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { } 18.281 - virtual void do_oop(narrowOop* p) { do_oop_work(p); } 18.282 - virtual void do_oop( oop* p) { do_oop_work(p); } 18.283 - template <class T> void do_oop_work(T* p) { 18.284 - oop obj = oopDesc::load_decode_heap_oop(p); 18.285 - if (_g1->obj_in_cs(obj)) { 18.286 - size_t card_index = _ct_bs->index_for(p); 18.287 - if (_ct_bs->mark_card_deferred(card_index)) { 18.288 - _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); 18.289 - } 18.290 - } 18.291 - } 18.292 -}; 18.293 - 18.294 -template <class T> void HRInto_G1RemSet::new_refs_iterate_work(OopClosure* cl) { 18.295 - for (size_t i = 0; i < n_workers(); i++) { 18.296 - for (int j = 0; j < _new_refs[i]->length(); j++) { 18.297 - T* p = (T*) _new_refs[i]->at(j); 18.298 - cl->do_oop(p); 18.299 - } 18.300 - } 18.301 -} 18.302 - 18.303 void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() { 18.304 guarantee( _cards_scanned != NULL, "invariant" ); 18.305 _total_cards_scanned = 0; 18.306 @@ -580,27 +619,42 @@ 18.307 // Set all cards back to clean. 18.308 _g1->cleanUpCardTable(); 18.309 18.310 - if (ParallelGCThreads > 0) { 18.311 - set_par_traversal(false); 18.312 + set_traversal(false); 18.313 + 18.314 + DirtyCardQueueSet& into_cset_dcqs = _g1->into_cset_dirty_card_queue_set(); 18.315 + int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); 18.316 + 18.317 + if (_g1->evacuation_failed()) { 18.318 + // Restore remembered sets for the regions pointing into the collection set. 18.319 + 18.320 + if (G1DeferredRSUpdate) { 18.321 + // If deferred RS updates are enabled then we just need to transfer 18.322 + // the completed buffers from (a) the DirtyCardQueueSet used to hold 18.323 + // cards that contain references that point into the collection set 18.324 + // to (b) the DCQS used to hold the deferred RS updates 18.325 + _g1->dirty_card_queue_set().merge_bufferlists(&into_cset_dcqs); 18.326 + } else { 18.327 + 18.328 + CardTableModRefBS* bs = (CardTableModRefBS*)_g1->barrier_set(); 18.329 + UpdateRSetCardTableEntryIntoCSetClosure update_rs_cset_immediate(_g1, bs); 18.330 + 18.331 + int n_completed_buffers = 0; 18.332 + while (into_cset_dcqs.apply_closure_to_completed_buffer(&update_rs_cset_immediate, 18.333 + 0, 0, true)) { 18.334 + n_completed_buffers++; 18.335 + } 18.336 + assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers"); 18.337 + } 18.338 } 18.339 18.340 - if (_g1->evacuation_failed()) { 18.341 - // Restore remembered sets for the regions pointing into 18.342 - // the collection set. 18.343 - if (G1DeferredRSUpdate) { 18.344 - DirtyCardQueue dcq(&_g1->dirty_card_queue_set()); 18.345 - UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq); 18.346 - new_refs_iterate(&deferred_update); 18.347 - } else { 18.348 - UpdateRSetOopsIntoCSImmediate immediate_update(_g1); 18.349 - new_refs_iterate(&immediate_update); 18.350 - } 18.351 - } 18.352 - for (uint i = 0; i < n_workers(); i++) { 18.353 - _new_refs[i]->clear(); 18.354 - } 18.355 + // Free any completed buffers in the DirtyCardQueueSet used to hold cards 18.356 + // which contain references that point into the collection. 18.357 + _g1->into_cset_dirty_card_queue_set().clear(); 18.358 + assert(_g1->into_cset_dirty_card_queue_set().completed_buffers_num() == 0, 18.359 + "all buffers should be freed"); 18.360 + _g1->into_cset_dirty_card_queue_set().clear_n_completed_buffers(); 18.361 18.362 - assert(!_par_traversal_in_progress, "Invariant between iterations."); 18.363 + assert(!_traversal_in_progress, "Invariant between iterations."); 18.364 } 18.365 18.366 class UpdateRSObjectClosure: public ObjectClosure { 18.367 @@ -652,7 +706,43 @@ 18.368 18.369 static IntHistogram out_of_histo(50, 50); 18.370 18.371 -void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) { 18.372 +class TriggerClosure : public OopClosure { 18.373 + bool _trigger; 18.374 +public: 18.375 + TriggerClosure() : _trigger(false) { } 18.376 + bool value() const { return _trigger; } 18.377 + template <class T> void do_oop_nv(T* p) { _trigger = true; } 18.378 + virtual void do_oop(oop* p) { do_oop_nv(p); } 18.379 + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } 18.380 +}; 18.381 + 18.382 +class InvokeIfNotTriggeredClosure: public OopClosure { 18.383 + TriggerClosure* _t; 18.384 + OopClosure* _oc; 18.385 +public: 18.386 + InvokeIfNotTriggeredClosure(TriggerClosure* t, OopClosure* oc): 18.387 + _t(t), _oc(oc) { } 18.388 + template <class T> void do_oop_nv(T* p) { 18.389 + if (!_t->value()) _oc->do_oop(p); 18.390 + } 18.391 + virtual void do_oop(oop* p) { do_oop_nv(p); } 18.392 + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } 18.393 +}; 18.394 + 18.395 +class Mux2Closure : public OopClosure { 18.396 + OopClosure* _c1; 18.397 + OopClosure* _c2; 18.398 +public: 18.399 + Mux2Closure(OopClosure *c1, OopClosure *c2) : _c1(c1), _c2(c2) { } 18.400 + template <class T> void do_oop_nv(T* p) { 18.401 + _c1->do_oop(p); _c2->do_oop(p); 18.402 + } 18.403 + virtual void do_oop(oop* p) { do_oop_nv(p); } 18.404 + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } 18.405 +}; 18.406 + 18.407 +bool HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, 18.408 + bool check_for_refs_into_cset) { 18.409 // Construct the region representing the card. 18.410 HeapWord* start = _ct_bs->addr_for(card_ptr); 18.411 // And find the region containing it. 18.412 @@ -669,7 +759,16 @@ 18.413 18.414 UpdateRSOopClosure update_rs_oop_cl(this, worker_i); 18.415 update_rs_oop_cl.set_from(r); 18.416 - FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); 18.417 + 18.418 + TriggerClosure trigger_cl; 18.419 + FilterIntoCSClosure into_cs_cl(NULL, _g1, &trigger_cl); 18.420 + InvokeIfNotTriggeredClosure invoke_cl(&trigger_cl, &into_cs_cl); 18.421 + Mux2Closure mux(&invoke_cl, &update_rs_oop_cl); 18.422 + 18.423 + FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, 18.424 + (check_for_refs_into_cset ? 18.425 + (OopClosure*)&mux : 18.426 + (OopClosure*)&update_rs_oop_cl)); 18.427 18.428 // Undirty the card. 18.429 *card_ptr = CardTableModRefBS::clean_card_val(); 18.430 @@ -717,11 +816,18 @@ 18.431 out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); 18.432 _conc_refine_cards++; 18.433 } 18.434 + 18.435 + return trigger_cl.value(); 18.436 } 18.437 18.438 -void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { 18.439 +bool HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i, 18.440 + bool check_for_refs_into_cset) { 18.441 // If the card is no longer dirty, nothing to do. 18.442 - if (*card_ptr != CardTableModRefBS::dirty_card_val()) return; 18.443 + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { 18.444 + // No need to return that this card contains refs that point 18.445 + // into the collection set. 18.446 + return false; 18.447 + } 18.448 18.449 // Construct the region representing the card. 18.450 HeapWord* start = _ct_bs->addr_for(card_ptr); 18.451 @@ -729,7 +835,9 @@ 18.452 HeapRegion* r = _g1->heap_region_containing(start); 18.453 if (r == NULL) { 18.454 guarantee(_g1->is_in_permanent(start), "Or else where?"); 18.455 - return; // Not in the G1 heap (might be in perm, for example.) 18.456 + // Again no need to return that this card contains refs that 18.457 + // point into the collection set. 18.458 + return false; // Not in the G1 heap (might be in perm, for example.) 18.459 } 18.460 // Why do we have to check here whether a card is on a young region, 18.461 // given that we dirty young regions and, as a result, the 18.462 @@ -743,7 +851,7 @@ 18.463 // and it doesn't happen often, but it can happen. So, the extra 18.464 // check below filters out those cards. 18.465 if (r->is_young()) { 18.466 - return; 18.467 + return false; 18.468 } 18.469 // While we are processing RSet buffers during the collection, we 18.470 // actually don't want to scan any cards on the collection set, 18.471 @@ -756,7 +864,7 @@ 18.472 // however, that if evacuation fails, we have to scan any objects 18.473 // that were not moved and create any missing entries. 18.474 if (r->in_collection_set()) { 18.475 - return; 18.476 + return false; 18.477 } 18.478 18.479 // Should we defer processing the card? 18.480 @@ -797,8 +905,14 @@ 18.481 // cache. 18.482 // Immediately process res; no need to process card_ptr. 18.483 18.484 + 18.485 jbyte* res = card_ptr; 18.486 bool defer = false; 18.487 + 18.488 + // This gets set to true if the card being refined has references 18.489 + // that point into the collection set. 18.490 + bool oops_into_cset = false; 18.491 + 18.492 if (_cg1r->use_cache()) { 18.493 jbyte* res = _cg1r->cache_insert(card_ptr, &defer); 18.494 if (res != NULL && (res != card_ptr || defer)) { 18.495 @@ -815,14 +929,31 @@ 18.496 // Process card pointer we get back from the hot card cache. This 18.497 // will check whether the region containing the card is young 18.498 // _after_ checking that the region has been allocated from. 18.499 - concurrentRefineOneCard_impl(res, worker_i); 18.500 + oops_into_cset = concurrentRefineOneCard_impl(res, worker_i, 18.501 + false /* check_for_refs_into_cset */); 18.502 + // The above call to concurrentRefineOneCard_impl is only 18.503 + // performed if the hot card cache is enabled. This cache is 18.504 + // disabled during an evacuation pause - which is the only 18.505 + // time when we need know if the card contains references 18.506 + // that point into the collection set. Also when the hot card 18.507 + // cache is enabled, this code is executed by the concurrent 18.508 + // refine threads - rather than the GC worker threads - and 18.509 + // concurrentRefineOneCard_impl will return false. 18.510 + assert(!oops_into_cset, "should not see true here"); 18.511 } 18.512 } 18.513 } 18.514 18.515 if (!defer) { 18.516 - concurrentRefineOneCard_impl(card_ptr, worker_i); 18.517 + oops_into_cset = 18.518 + concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset); 18.519 + // We should only be detecting that the card contains references 18.520 + // that point into the collection set if the current thread is 18.521 + // a GC worker thread. 18.522 + assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(), 18.523 + "invalid result at non safepoint"); 18.524 } 18.525 + return oops_into_cset; 18.526 } 18.527 18.528 class HRRSStatsIter: public HeapRegionClosure { 18.529 @@ -920,6 +1051,7 @@ 18.530 18.531 } 18.532 } 18.533 + 18.534 void HRInto_G1RemSet::prepare_for_verify() { 18.535 if (G1HRRSFlushLogBuffersOnVerify && 18.536 (VerifyBeforeGC || VerifyAfterGC) 18.537 @@ -932,7 +1064,9 @@ 18.538 } 18.539 bool cg1r_use_cache = _cg1r->use_cache(); 18.540 _cg1r->set_use_cache(false); 18.541 - updateRS(0); 18.542 + DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); 18.543 + updateRS(&into_cset_dcq, 0); 18.544 + _g1->into_cset_dirty_card_queue_set().clear(); 18.545 _cg1r->set_use_cache(cg1r_use_cache); 18.546 18.547 assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
19.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Fri Aug 13 07:33:20 2010 -0700 19.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Sat Aug 14 00:47:52 2010 -0700 19.3 @@ -1,5 +1,5 @@ 19.4 /* 19.5 - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. 19.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 19.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.8 * 19.9 * This code is free software; you can redistribute it and/or modify it 19.10 @@ -83,7 +83,13 @@ 19.11 // Refine the card corresponding to "card_ptr". If "sts" is non-NULL, 19.12 // join and leave around parts that must be atomic wrt GC. (NULL means 19.13 // being done at a safepoint.) 19.14 - virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {} 19.15 + // With some implementations of this routine, when check_for_refs_into_cset 19.16 + // is true, a true result may be returned if the given card contains oops 19.17 + // that have references into the current collection set. 19.18 + virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i, 19.19 + bool check_for_refs_into_cset) { 19.20 + return false; 19.21 + } 19.22 19.23 // Print any relevant summary info. 19.24 virtual void print_summary_info() {} 19.25 @@ -142,24 +148,22 @@ 19.26 size_t* _cards_scanned; 19.27 size_t _total_cards_scanned; 19.28 19.29 - // _par_traversal_in_progress is "true" iff a parallel traversal is in 19.30 - // progress. If so, then cards added to remembered sets should also have 19.31 - // their references into the collection summarized in "_new_refs". 19.32 - bool _par_traversal_in_progress; 19.33 - void set_par_traversal(bool b) { _par_traversal_in_progress = b; } 19.34 - GrowableArray<OopOrNarrowOopStar>** _new_refs; 19.35 - template <class T> void new_refs_iterate_work(OopClosure* cl); 19.36 - void new_refs_iterate(OopClosure* cl) { 19.37 - if (UseCompressedOops) { 19.38 - new_refs_iterate_work<narrowOop>(cl); 19.39 - } else { 19.40 - new_refs_iterate_work<oop>(cl); 19.41 - } 19.42 - } 19.43 + // _traversal_in_progress is "true" iff a traversal is in progress. 19.44 + 19.45 + bool _traversal_in_progress; 19.46 + void set_traversal(bool b) { _traversal_in_progress = b; } 19.47 + 19.48 + // Used for caching the closure that is responsible for scanning 19.49 + // references into the collection set. 19.50 + OopsInHeapRegionClosure** _cset_rs_update_cl; 19.51 19.52 // The routine that performs the actual work of refining a dirty 19.53 // card. 19.54 - void concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i); 19.55 + // If check_for_refs_into_refs is true then a true result is returned 19.56 + // if the card contains oops that have references into the current 19.57 + // collection set. 19.58 + bool concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, 19.59 + bool check_for_refs_into_cset); 19.60 19.61 protected: 19.62 template <class T> void write_ref_nv(HeapRegion* from, T* p); 19.63 @@ -188,7 +192,7 @@ 19.64 scanNewRefsRS_work<oop>(oc, worker_i); 19.65 } 19.66 } 19.67 - void updateRS(int worker_i); 19.68 + void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i); 19.69 HeapRegion* calculateStartRegion(int i); 19.70 19.71 HRInto_G1RemSet* as_HRInto_G1RemSet() { return this; } 19.72 @@ -219,7 +223,11 @@ 19.73 void scrub_par(BitMap* region_bm, BitMap* card_bm, 19.74 int worker_num, int claim_val); 19.75 19.76 - virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i); 19.77 + // If check_for_refs_into_cset is true then a true result is returned 19.78 + // if the card contains oops that have references into the current 19.79 + // collection set. 19.80 + virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i, 19.81 + bool check_for_refs_into_cset); 19.82 19.83 virtual void print_summary_info(); 19.84 virtual void prepare_for_verify(); 19.85 @@ -265,3 +273,16 @@ 19.86 // bool idempotent() { return true; } 19.87 bool apply_to_weak_ref_discovered_field() { return true; } 19.88 }; 19.89 + 19.90 +class UpdateRSetImmediate: public OopsInHeapRegionClosure { 19.91 +private: 19.92 + G1RemSet* _g1_rem_set; 19.93 + 19.94 + template <class T> void do_oop_work(T* p); 19.95 +public: 19.96 + UpdateRSetImmediate(G1RemSet* rs) : 19.97 + _g1_rem_set(rs) {} 19.98 + 19.99 + virtual void do_oop(narrowOop* p) { do_oop_work(p); } 19.100 + virtual void do_oop( oop* p) { do_oop_work(p); } 19.101 +};
20.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Fri Aug 13 07:33:20 2010 -0700 20.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Sat Aug 14 00:47:52 2010 -0700 20.3 @@ -1,5 +1,5 @@ 20.4 /* 20.5 - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. 20.6 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 20.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 20.8 * 20.9 * This code is free software; you can redistribute it and/or modify it 20.10 @@ -56,19 +56,25 @@ 20.11 assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); 20.12 } 20.13 #endif // ASSERT 20.14 - assert(from == NULL || from->is_in_reserved(p), 20.15 - "p is not in from"); 20.16 + 20.17 + assert(from == NULL || from->is_in_reserved(p), "p is not in from"); 20.18 + 20.19 HeapRegion* to = _g1->heap_region_containing(obj); 20.20 // The test below could be optimized by applying a bit op to to and from. 20.21 if (to != NULL && from != NULL && from != to) { 20.22 - // There is a tricky infinite loop if we keep pushing 20.23 - // self forwarding pointers onto our _new_refs list. 20.24 - // The _par_traversal_in_progress flag is true during the collection pause, 20.25 - // false during the evacuation failure handing. 20.26 - if (_par_traversal_in_progress && 20.27 + // The _traversal_in_progress flag is true during the collection pause, 20.28 + // false during the evacuation failure handling. This should avoid a 20.29 + // potential loop if we were to add the card containing 'p' to the DCQS 20.30 + // that's used to regenerate the remembered sets for the collection set, 20.31 + // in the event of an evacuation failure, here. The UpdateRSImmediate 20.32 + // closure will eventally call this routine. 20.33 + if (_traversal_in_progress && 20.34 to->in_collection_set() && !self_forwarded(obj)) { 20.35 - _new_refs[tid]->push((void*)p); 20.36 - // Deferred updates to the Cset are either discarded (in the normal case), 20.37 + 20.38 + assert(_cset_rs_update_cl[tid] != NULL, "should have been set already"); 20.39 + _cset_rs_update_cl[tid]->do_oop(p); 20.40 + 20.41 + // Deferred updates to the CSet are either discarded (in the normal case), 20.42 // or processed (if an evacuation failure occurs) at the end 20.43 // of the collection. 20.44 // See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do(). 20.45 @@ -89,3 +95,12 @@ 20.46 assert(_from != NULL, "from region must be non-NULL"); 20.47 _rs->par_write_ref(_from, p, _worker_i); 20.48 } 20.49 + 20.50 +template <class T> inline void UpdateRSetImmediate::do_oop_work(T* p) { 20.51 + assert(_from->is_in_reserved(p), "paranoia"); 20.52 + T heap_oop = oopDesc::load_heap_oop(p); 20.53 + if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) { 20.54 + _g1_rem_set->par_write_ref(_from, p, 0); 20.55 + } 20.56 +} 20.57 +
21.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Aug 13 07:33:20 2010 -0700 21.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Sat Aug 14 00:47:52 2010 -0700 21.3 @@ -683,6 +683,8 @@ 21.4 return NULL; 21.5 } 21.6 21.7 + assert(!is_young(), "check value of filter_young"); 21.8 + 21.9 // We used to use "block_start_careful" here. But we're actually happy 21.10 // to update the BOT while we do this... 21.11 HeapWord* cur = block_start(mr.start());
22.1 --- a/src/share/vm/gc_implementation/g1/sparsePRT.cpp Fri Aug 13 07:33:20 2010 -0700 22.2 +++ b/src/share/vm/gc_implementation/g1/sparsePRT.cpp Sat Aug 14 00:47:52 2010 -0700 22.3 @@ -424,7 +424,7 @@ 22.4 22.5 22.6 SparsePRT::SparsePRT(HeapRegion* hr) : 22.7 - _expanded(false), _next_expanded(NULL) 22.8 + _hr(hr), _expanded(false), _next_expanded(NULL) 22.9 { 22.10 _cur = new RSHashTable(InitialCapacity); 22.11 _next = _cur;
23.1 --- a/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Fri Aug 13 07:33:20 2010 -0700 23.2 +++ b/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Sat Aug 14 00:47:52 2010 -0700 23.3 @@ -149,6 +149,7 @@ 23.4 concurrentMarkSweepGeneration.cpp iterator.hpp 23.5 concurrentMarkSweepGeneration.cpp java.hpp 23.6 concurrentMarkSweepGeneration.cpp jvmtiExport.hpp 23.7 +concurrentMarkSweepGeneration.cpp memoryService.hpp 23.8 concurrentMarkSweepGeneration.cpp oop.inline.hpp 23.9 concurrentMarkSweepGeneration.cpp parNewGeneration.hpp 23.10 concurrentMarkSweepGeneration.cpp referencePolicy.hpp 23.11 @@ -165,6 +166,7 @@ 23.12 concurrentMarkSweepGeneration.hpp gcStats.hpp 23.13 concurrentMarkSweepGeneration.hpp generation.hpp 23.14 concurrentMarkSweepGeneration.hpp generationCounters.hpp 23.15 +concurrentMarkSweepGeneration.hpp memoryService.hpp 23.16 concurrentMarkSweepGeneration.hpp mutexLocker.hpp 23.17 concurrentMarkSweepGeneration.hpp taskqueue.hpp 23.18 concurrentMarkSweepGeneration.hpp virtualspace.hpp
24.1 --- a/src/share/vm/gc_implementation/includeDB_gc_g1 Fri Aug 13 07:33:20 2010 -0700 24.2 +++ b/src/share/vm/gc_implementation/includeDB_gc_g1 Sat Aug 14 00:47:52 2010 -0700 24.3 @@ -1,5 +1,5 @@ 24.4 // 24.5 -// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. 24.6 +// Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24.7 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 24.8 // 24.9 // This code is free software; you can redistribute it and/or modify it 24.10 @@ -241,6 +241,7 @@ 24.11 24.12 g1MMUTracker.hpp debug.hpp 24.13 g1MMUTracker.hpp allocation.hpp 24.14 + 24.15 g1RemSet.cpp bufferingOopClosure.hpp 24.16 g1RemSet.cpp concurrentG1Refine.hpp 24.17 g1RemSet.cpp concurrentG1RefineThread.hpp
25.1 --- a/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Fri Aug 13 07:33:20 2010 -0700 25.2 +++ b/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Sat Aug 14 00:47:52 2010 -0700 25.3 @@ -330,7 +330,6 @@ 25.4 psPromotionManager.cpp psScavenge.inline.hpp 25.5 25.6 psPromotionManager.hpp allocation.hpp 25.7 -psPromotionManager.hpp prefetchQueue.hpp 25.8 psPromotionManager.hpp psPromotionLAB.hpp 25.9 psPromotionManager.hpp taskqueue.hpp 25.10
26.1 --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Aug 13 07:33:20 2010 -0700 26.2 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Sat Aug 14 00:47:52 2010 -0700 26.3 @@ -51,9 +51,14 @@ 26.4 _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), 26.5 _keep_alive_closure(&_scan_weak_ref_closure), 26.6 _promotion_failure_size(0), 26.7 - _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0), 26.8 _strong_roots_time(0.0), _term_time(0.0) 26.9 { 26.10 + #if TASKQUEUE_STATS 26.11 + _term_attempts = 0; 26.12 + _overflow_refills = 0; 26.13 + _overflow_refill_objs = 0; 26.14 + #endif // TASKQUEUE_STATS 26.15 + 26.16 _survivor_chunk_array = 26.17 (ChunkArray*) old_gen()->get_data_recorder(thread_num()); 26.18 _hash_seed = 17; // Might want to take time-based random value. 26.19 @@ -100,7 +105,6 @@ 26.20 // Push remainder. 26.21 bool ok = work_queue()->push(old); 26.22 assert(ok, "just popped, push must be okay"); 26.23 - note_push(); 26.24 } else { 26.25 // Restore length so that it can be used if there 26.26 // is a promotion failure and forwarding pointers 26.27 @@ -126,7 +130,6 @@ 26.28 while (queue->size() > (juint)max_size) { 26.29 oop obj_to_scan; 26.30 if (queue->pop_local(obj_to_scan)) { 26.31 - note_pop(); 26.32 if ((HeapWord *)obj_to_scan < young_old_boundary()) { 26.33 if (obj_to_scan->is_objArray() && 26.34 obj_to_scan->is_forwarded() && 26.35 @@ -271,20 +274,28 @@ 26.36 GrowableArray<oop>** overflow_stacks_, 26.37 size_t desired_plab_sz, 26.38 ParallelTaskTerminator& term); 26.39 + 26.40 + ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); } 26.41 + 26.42 inline ParScanThreadState& thread_state(int i); 26.43 - int pushes() { return _pushes; } 26.44 - int pops() { return _pops; } 26.45 - int steals() { return _steals; } 26.46 + 26.47 void reset(bool promotion_failed); 26.48 void flush(); 26.49 + 26.50 + #if TASKQUEUE_STATS 26.51 + static void 26.52 + print_termination_stats_hdr(outputStream* const st = gclog_or_tty); 26.53 + void print_termination_stats(outputStream* const st = gclog_or_tty); 26.54 + static void 26.55 + print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); 26.56 + void print_taskqueue_stats(outputStream* const st = gclog_or_tty); 26.57 + void reset_stats(); 26.58 + #endif // TASKQUEUE_STATS 26.59 + 26.60 private: 26.61 ParallelTaskTerminator& _term; 26.62 ParNewGeneration& _gen; 26.63 Generation& _next_gen; 26.64 - // staticstics 26.65 - int _pushes; 26.66 - int _pops; 26.67 - int _steals; 26.68 }; 26.69 26.70 26.71 @@ -294,8 +305,7 @@ 26.72 GrowableArray<oop>** overflow_stack_set_, 26.73 size_t desired_plab_sz, ParallelTaskTerminator& term) 26.74 : ResourceArray(sizeof(ParScanThreadState), num_threads), 26.75 - _gen(gen), _next_gen(old_gen), _term(term), 26.76 - _pushes(0), _pops(0), _steals(0) 26.77 + _gen(gen), _next_gen(old_gen), _term(term) 26.78 { 26.79 assert(num_threads > 0, "sanity check!"); 26.80 // Initialize states. 26.81 @@ -323,6 +333,82 @@ 26.82 } 26.83 } 26.84 26.85 +#if TASKQUEUE_STATS 26.86 +void 26.87 +ParScanThreadState::reset_stats() 26.88 +{ 26.89 + taskqueue_stats().reset(); 26.90 + _term_attempts = 0; 26.91 + _overflow_refills = 0; 26.92 + _overflow_refill_objs = 0; 26.93 +} 26.94 + 26.95 +void ParScanThreadStateSet::reset_stats() 26.96 +{ 26.97 + for (int i = 0; i < length(); ++i) { 26.98 + thread_state(i).reset_stats(); 26.99 + } 26.100 +} 26.101 + 26.102 +void 26.103 +ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st) 26.104 +{ 26.105 + st->print_raw_cr("GC Termination Stats"); 26.106 + st->print_raw_cr(" elapsed --strong roots-- " 26.107 + "-------termination-------"); 26.108 + st->print_raw_cr("thr ms ms % " 26.109 + " ms % attempts"); 26.110 + st->print_raw_cr("--- --------- --------- ------ " 26.111 + "--------- ------ --------"); 26.112 +} 26.113 + 26.114 +void ParScanThreadStateSet::print_termination_stats(outputStream* const st) 26.115 +{ 26.116 + print_termination_stats_hdr(st); 26.117 + 26.118 + for (int i = 0; i < length(); ++i) { 26.119 + const ParScanThreadState & pss = thread_state(i); 26.120 + const double elapsed_ms = pss.elapsed_time() * 1000.0; 26.121 + const double s_roots_ms = pss.strong_roots_time() * 1000.0; 26.122 + const double term_ms = pss.term_time() * 1000.0; 26.123 + st->print_cr("%3d %9.2f %9.2f %6.2f " 26.124 + "%9.2f %6.2f " SIZE_FORMAT_W(8), 26.125 + i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms, 26.126 + term_ms, term_ms * 100 / elapsed_ms, pss.term_attempts()); 26.127 + } 26.128 +} 26.129 + 26.130 +// Print stats related to work queue activity. 26.131 +void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st) 26.132 +{ 26.133 + st->print_raw_cr("GC Task Stats"); 26.134 + st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); 26.135 + st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); 26.136 +} 26.137 + 26.138 +void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st) 26.139 +{ 26.140 + print_taskqueue_stats_hdr(st); 26.141 + 26.142 + TaskQueueStats totals; 26.143 + for (int i = 0; i < length(); ++i) { 26.144 + const ParScanThreadState & pss = thread_state(i); 26.145 + const TaskQueueStats & stats = pss.taskqueue_stats(); 26.146 + st->print("%3d ", i); stats.print(st); st->cr(); 26.147 + totals += stats; 26.148 + 26.149 + if (pss.overflow_refills() > 0) { 26.150 + st->print_cr(" " SIZE_FORMAT_W(10) " overflow refills " 26.151 + SIZE_FORMAT_W(10) " overflow objects", 26.152 + pss.overflow_refills(), pss.overflow_refill_objs()); 26.153 + } 26.154 + } 26.155 + st->print("tot "); totals.print(st); st->cr(); 26.156 + 26.157 + DEBUG_ONLY(totals.verify()); 26.158 +} 26.159 +#endif // TASKQUEUE_STATS 26.160 + 26.161 void ParScanThreadStateSet::flush() 26.162 { 26.163 // Work in this loop should be kept as lightweight as 26.164 @@ -346,42 +432,8 @@ 26.165 // Inform old gen that we're done. 26.166 _next_gen.par_promote_alloc_done(i); 26.167 _next_gen.par_oop_since_save_marks_iterate_done(i); 26.168 + } 26.169 26.170 - // Flush stats related to work queue activity (push/pop/steal) 26.171 - // This could conceivably become a bottleneck; if so, we'll put the 26.172 - // stat's gathering under the flag. 26.173 - if (PAR_STATS_ENABLED) { 26.174 - _pushes += par_scan_state.pushes(); 26.175 - _pops += par_scan_state.pops(); 26.176 - _steals += par_scan_state.steals(); 26.177 - if (ParallelGCVerbose) { 26.178 - gclog_or_tty->print("Thread %d complete:\n" 26.179 - " Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n", 26.180 - i, par_scan_state.pushes(), par_scan_state.pops(), 26.181 - par_scan_state.steals(), par_scan_state.steal_attempts()); 26.182 - if (par_scan_state.overflow_pushes() > 0 || 26.183 - par_scan_state.overflow_refills() > 0) { 26.184 - gclog_or_tty->print(" Overflow pushes: %7d " 26.185 - "Overflow refills: %7d for %d objs.\n", 26.186 - par_scan_state.overflow_pushes(), 26.187 - par_scan_state.overflow_refills(), 26.188 - par_scan_state.overflow_refill_objs()); 26.189 - } 26.190 - 26.191 - double elapsed = par_scan_state.elapsed(); 26.192 - double strong_roots = par_scan_state.strong_roots_time(); 26.193 - double term = par_scan_state.term_time(); 26.194 - gclog_or_tty->print( 26.195 - " Elapsed: %7.2f ms.\n" 26.196 - " Strong roots: %7.2f ms (%6.2f%%)\n" 26.197 - " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n", 26.198 - elapsed * 1000.0, 26.199 - strong_roots * 1000.0, (strong_roots*100.0/elapsed), 26.200 - term * 1000.0, (term*100.0/elapsed), 26.201 - par_scan_state.term_attempts()); 26.202 - } 26.203 - } 26.204 - } 26.205 if (UseConcMarkSweepGC && ParallelGCThreads > 0) { 26.206 // We need to call this even when ResizeOldPLAB is disabled 26.207 // so as to avoid breaking some asserts. While we may be able 26.208 @@ -456,15 +508,12 @@ 26.209 // We have no local work, attempt to steal from other threads. 26.210 26.211 // attempt to steal work from promoted. 26.212 - par_scan_state()->note_steal_attempt(); 26.213 if (task_queues()->steal(par_scan_state()->thread_num(), 26.214 par_scan_state()->hash_seed(), 26.215 obj_to_scan)) { 26.216 - par_scan_state()->note_steal(); 26.217 bool res = work_q->push(obj_to_scan); 26.218 assert(res, "Empty queue should have room for a push."); 26.219 26.220 - par_scan_state()->note_push(); 26.221 // if successful, goto Start. 26.222 continue; 26.223 26.224 @@ -842,17 +891,6 @@ 26.225 } 26.226 thread_state_set.reset(promotion_failed()); 26.227 26.228 - if (PAR_STATS_ENABLED && ParallelGCVerbose) { 26.229 - gclog_or_tty->print("Thread totals:\n" 26.230 - " Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n", 26.231 - thread_state_set.pushes(), thread_state_set.pops(), 26.232 - thread_state_set.steals(), 26.233 - thread_state_set.pops()+thread_state_set.steals()); 26.234 - } 26.235 - assert(thread_state_set.pushes() == thread_state_set.pops() 26.236 - + thread_state_set.steals(), 26.237 - "Or else the queues are leaky."); 26.238 - 26.239 // Process (weak) reference objects found during scavenge. 26.240 ReferenceProcessor* rp = ref_processor(); 26.241 IsAliveClosure is_alive(this); 26.242 @@ -932,6 +970,11 @@ 26.243 gch->print_heap_change(gch_prev_used); 26.244 } 26.245 26.246 + if (PrintGCDetails && ParallelGCVerbose) { 26.247 + TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats()); 26.248 + TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats()); 26.249 + } 26.250 + 26.251 if (UseAdaptiveSizePolicy) { 26.252 size_policy->minor_collection_end(gch->gc_cause()); 26.253 size_policy->avg_survived()->sample(from()->used()); 26.254 @@ -1104,9 +1147,8 @@ 26.255 gclog_or_tty->print("queue overflow!\n"); 26.256 } 26.257 push_on_overflow_list(old, par_scan_state); 26.258 - par_scan_state->note_overflow_push(); 26.259 + TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0)); 26.260 } 26.261 - par_scan_state->note_push(); 26.262 26.263 return new_obj; 26.264 } 26.265 @@ -1227,9 +1269,8 @@ 26.266 if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { 26.267 // Add stats for overflow pushes. 26.268 push_on_overflow_list(old, par_scan_state); 26.269 - par_scan_state->note_overflow_push(); 26.270 + TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0)); 26.271 } 26.272 - par_scan_state->note_push(); 26.273 26.274 return new_obj; 26.275 } 26.276 @@ -1466,7 +1507,7 @@ 26.277 cur = next; 26.278 n++; 26.279 } 26.280 - par_scan_state->note_overflow_refill(n); 26.281 + TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n)); 26.282 #ifndef PRODUCT 26.283 assert(_num_par_pushes >= n, "Too many pops?"); 26.284 Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes);
27.1 --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Fri Aug 13 07:33:20 2010 -0700 27.2 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Sat Aug 14 00:47:52 2010 -0700 27.3 @@ -36,9 +36,6 @@ 27.4 typedef Padded<OopTaskQueue> ObjToScanQueue; 27.5 typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet; 27.6 27.7 -// Enable this to get push/pop/steal stats. 27.8 -const int PAR_STATS_ENABLED = 0; 27.9 - 27.10 class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure { 27.11 private: 27.12 ParScanWeakRefClosure* _par_cl; 27.13 @@ -94,8 +91,11 @@ 27.14 27.15 bool _to_space_full; 27.16 27.17 - int _pushes, _pops, _steals, _steal_attempts, _term_attempts; 27.18 - int _overflow_pushes, _overflow_refills, _overflow_refill_objs; 27.19 +#if TASKQUEUE_STATS 27.20 + size_t _term_attempts; 27.21 + size_t _overflow_refills; 27.22 + size_t _overflow_refill_objs; 27.23 +#endif // TASKQUEUE_STATS 27.24 27.25 // Stats for promotion failure 27.26 size_t _promotion_failure_size; 27.27 @@ -181,45 +181,38 @@ 27.28 } 27.29 void print_and_clear_promotion_failure_size(); 27.30 27.31 - int pushes() { return _pushes; } 27.32 - int pops() { return _pops; } 27.33 - int steals() { return _steals; } 27.34 - int steal_attempts() { return _steal_attempts; } 27.35 - int term_attempts() { return _term_attempts; } 27.36 - int overflow_pushes() { return _overflow_pushes; } 27.37 - int overflow_refills() { return _overflow_refills; } 27.38 - int overflow_refill_objs() { return _overflow_refill_objs; } 27.39 +#if TASKQUEUE_STATS 27.40 + TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; } 27.41 27.42 - void note_push() { if (PAR_STATS_ENABLED) _pushes++; } 27.43 - void note_pop() { if (PAR_STATS_ENABLED) _pops++; } 27.44 - void note_steal() { if (PAR_STATS_ENABLED) _steals++; } 27.45 - void note_steal_attempt() { if (PAR_STATS_ENABLED) _steal_attempts++; } 27.46 - void note_term_attempt() { if (PAR_STATS_ENABLED) _term_attempts++; } 27.47 - void note_overflow_push() { if (PAR_STATS_ENABLED) _overflow_pushes++; } 27.48 - void note_overflow_refill(int objs) { 27.49 - if (PAR_STATS_ENABLED) { 27.50 - _overflow_refills++; 27.51 - _overflow_refill_objs += objs; 27.52 - } 27.53 + size_t term_attempts() const { return _term_attempts; } 27.54 + size_t overflow_refills() const { return _overflow_refills; } 27.55 + size_t overflow_refill_objs() const { return _overflow_refill_objs; } 27.56 + 27.57 + void note_term_attempt() { ++_term_attempts; } 27.58 + void note_overflow_refill(size_t objs) { 27.59 + ++_overflow_refills; _overflow_refill_objs += objs; 27.60 } 27.61 27.62 + void reset_stats(); 27.63 +#endif // TASKQUEUE_STATS 27.64 + 27.65 void start_strong_roots() { 27.66 _start_strong_roots = os::elapsedTime(); 27.67 } 27.68 void end_strong_roots() { 27.69 _strong_roots_time += (os::elapsedTime() - _start_strong_roots); 27.70 } 27.71 - double strong_roots_time() { return _strong_roots_time; } 27.72 + double strong_roots_time() const { return _strong_roots_time; } 27.73 void start_term_time() { 27.74 - note_term_attempt(); 27.75 + TASKQUEUE_STATS_ONLY(note_term_attempt()); 27.76 _start_term = os::elapsedTime(); 27.77 } 27.78 void end_term_time() { 27.79 _term_time += (os::elapsedTime() - _start_term); 27.80 } 27.81 - double term_time() { return _term_time; } 27.82 + double term_time() const { return _term_time; } 27.83 27.84 - double elapsed() { 27.85 + double elapsed_time() const { 27.86 return os::elapsedTime() - _start; 27.87 } 27.88 };
28.1 --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Fri Aug 13 07:33:20 2010 -0700 28.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Sat Aug 14 00:47:52 2010 -0700 28.3 @@ -123,7 +123,6 @@ 28.4 assert(start_array != NULL && sp != NULL && pm != NULL, "Sanity"); 28.5 assert(start_array->covered_region().contains(sp->used_region()), 28.6 "ObjectStartArray does not cover space"); 28.7 - bool depth_first = pm->depth_first(); 28.8 28.9 if (sp->not_empty()) { 28.10 oop* sp_top = (oop*)space_top; 28.11 @@ -201,21 +200,12 @@ 28.12 *first_nonclean_card++ = clean_card; 28.13 } 28.14 // scan oops in objects 28.15 - // hoisted the if (depth_first) check out of the loop 28.16 - if (depth_first){ 28.17 - do { 28.18 - oop(bottom_obj)->push_contents(pm); 28.19 - bottom_obj += oop(bottom_obj)->size(); 28.20 - assert(bottom_obj <= sp_top, "just checking"); 28.21 - } while (bottom_obj < top); 28.22 - pm->drain_stacks_cond_depth(); 28.23 - } else { 28.24 - do { 28.25 - oop(bottom_obj)->copy_contents(pm); 28.26 - bottom_obj += oop(bottom_obj)->size(); 28.27 - assert(bottom_obj <= sp_top, "just checking"); 28.28 - } while (bottom_obj < top); 28.29 - } 28.30 + do { 28.31 + oop(bottom_obj)->push_contents(pm); 28.32 + bottom_obj += oop(bottom_obj)->size(); 28.33 + assert(bottom_obj <= sp_top, "just checking"); 28.34 + } while (bottom_obj < top); 28.35 + pm->drain_stacks_cond_depth(); 28.36 // remember top oop* scanned 28.37 prev_top = top; 28.38 } 28.39 @@ -230,7 +220,6 @@ 28.40 uint stripe_number) { 28.41 int ssize = 128; // Naked constant! Work unit = 64k. 28.42 int dirty_card_count = 0; 28.43 - bool depth_first = pm->depth_first(); 28.44 28.45 oop* sp_top = (oop*)space_top; 28.46 jbyte* start_card = byte_for(sp->bottom()); 28.47 @@ -363,43 +352,22 @@ 28.48 const int interval = PrefetchScanIntervalInBytes; 28.49 // scan all objects in the range 28.50 if (interval != 0) { 28.51 - // hoisted the if (depth_first) check out of the loop 28.52 - if (depth_first) { 28.53 - while (p < to) { 28.54 - Prefetch::write(p, interval); 28.55 - oop m = oop(p); 28.56 - assert(m->is_oop_or_null(), "check for header"); 28.57 - m->push_contents(pm); 28.58 - p += m->size(); 28.59 - } 28.60 - pm->drain_stacks_cond_depth(); 28.61 - } else { 28.62 - while (p < to) { 28.63 - Prefetch::write(p, interval); 28.64 - oop m = oop(p); 28.65 - assert(m->is_oop_or_null(), "check for header"); 28.66 - m->copy_contents(pm); 28.67 - p += m->size(); 28.68 - } 28.69 + while (p < to) { 28.70 + Prefetch::write(p, interval); 28.71 + oop m = oop(p); 28.72 + assert(m->is_oop_or_null(), "check for header"); 28.73 + m->push_contents(pm); 28.74 + p += m->size(); 28.75 } 28.76 + pm->drain_stacks_cond_depth(); 28.77 } else { 28.78 - // hoisted the if (depth_first) check out of the loop 28.79 - if (depth_first) { 28.80 - while (p < to) { 28.81 - oop m = oop(p); 28.82 - assert(m->is_oop_or_null(), "check for header"); 28.83 - m->push_contents(pm); 28.84 - p += m->size(); 28.85 - } 28.86 - pm->drain_stacks_cond_depth(); 28.87 - } else { 28.88 - while (p < to) { 28.89 - oop m = oop(p); 28.90 - assert(m->is_oop_or_null(), "check for header"); 28.91 - m->copy_contents(pm); 28.92 - p += m->size(); 28.93 - } 28.94 + while (p < to) { 28.95 + oop m = oop(p); 28.96 + assert(m->is_oop_or_null(), "check for header"); 28.97 + m->push_contents(pm); 28.98 + p += m->size(); 28.99 } 28.100 + pm->drain_stacks_cond_depth(); 28.101 } 28.102 last_scanned = p; 28.103 }
29.1 --- a/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp Fri Aug 13 07:33:20 2010 -0700 29.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 29.3 @@ -1,68 +0,0 @@ 29.4 -/* 29.5 - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. 29.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 29.7 - * 29.8 - * This code is free software; you can redistribute it and/or modify it 29.9 - * under the terms of the GNU General Public License version 2 only, as 29.10 - * published by the Free Software Foundation. 29.11 - * 29.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 29.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 29.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29.15 - * version 2 for more details (a copy is included in the LICENSE file that 29.16 - * accompanied this code). 29.17 - * 29.18 - * You should have received a copy of the GNU General Public License version 29.19 - * 2 along with this work; if not, write to the Free Software Foundation, 29.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 29.21 - * 29.22 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 29.23 - * or visit www.oracle.com if you need additional information or have any 29.24 - * questions. 29.25 - * 29.26 - */ 29.27 - 29.28 -// 29.29 -// PrefetchQueue is a FIFO queue of variable length (currently 8). 29.30 -// 29.31 -// We need to examine the performance penalty of variable lengths. 29.32 -// We may also want to split this into cpu dependent bits. 29.33 -// 29.34 - 29.35 -const int PREFETCH_QUEUE_SIZE = 8; 29.36 - 29.37 -class PrefetchQueue : public CHeapObj { 29.38 - private: 29.39 - void* _prefetch_queue[PREFETCH_QUEUE_SIZE]; 29.40 - uint _prefetch_index; 29.41 - 29.42 - public: 29.43 - int length() { return PREFETCH_QUEUE_SIZE; } 29.44 - 29.45 - inline void clear() { 29.46 - for(int i=0; i<PREFETCH_QUEUE_SIZE; i++) { 29.47 - _prefetch_queue[i] = NULL; 29.48 - } 29.49 - _prefetch_index = 0; 29.50 - } 29.51 - 29.52 - template <class T> inline void* push_and_pop(T* p) { 29.53 - oop o = oopDesc::load_decode_heap_oop_not_null(p); 29.54 - Prefetch::write(o->mark_addr(), 0); 29.55 - // This prefetch is intended to make sure the size field of array 29.56 - // oops is in cache. It assumes the the object layout is 29.57 - // mark -> klass -> size, and that mark and klass are heapword 29.58 - // sized. If this should change, this prefetch will need updating! 29.59 - Prefetch::write(o->mark_addr() + (HeapWordSize*2), 0); 29.60 - _prefetch_queue[_prefetch_index++] = p; 29.61 - _prefetch_index &= (PREFETCH_QUEUE_SIZE-1); 29.62 - return _prefetch_queue[_prefetch_index]; 29.63 - } 29.64 - 29.65 - // Stores a NULL pointer in the pop'd location. 29.66 - inline void* pop() { 29.67 - _prefetch_queue[_prefetch_index++] = NULL; 29.68 - _prefetch_index &= (PREFETCH_QUEUE_SIZE-1); 29.69 - return _prefetch_queue[_prefetch_index]; 29.70 - } 29.71 -};
30.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Aug 13 07:33:20 2010 -0700 30.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Sat Aug 14 00:47:52 2010 -0700 30.3 @@ -27,7 +27,6 @@ 30.4 30.5 PSPromotionManager** PSPromotionManager::_manager_array = NULL; 30.6 OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL; 30.7 -OopTaskQueueSet* PSPromotionManager::_stack_array_breadth = NULL; 30.8 PSOldGen* PSPromotionManager::_old_gen = NULL; 30.9 MutableSpace* PSPromotionManager::_young_space = NULL; 30.10 30.11 @@ -42,23 +41,14 @@ 30.12 _manager_array = NEW_C_HEAP_ARRAY(PSPromotionManager*, ParallelGCThreads+1 ); 30.13 guarantee(_manager_array != NULL, "Could not initialize promotion manager"); 30.14 30.15 - if (UseDepthFirstScavengeOrder) { 30.16 - _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); 30.17 - guarantee(_stack_array_depth != NULL, "Count not initialize promotion manager"); 30.18 - } else { 30.19 - _stack_array_breadth = new OopTaskQueueSet(ParallelGCThreads); 30.20 - guarantee(_stack_array_breadth != NULL, "Count not initialize promotion manager"); 30.21 - } 30.22 + _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); 30.23 + guarantee(_stack_array_depth != NULL, "Cound not initialize promotion manager"); 30.24 30.25 // Create and register the PSPromotionManager(s) for the worker threads. 30.26 for(uint i=0; i<ParallelGCThreads; i++) { 30.27 _manager_array[i] = new PSPromotionManager(); 30.28 guarantee(_manager_array[i] != NULL, "Could not create PSPromotionManager"); 30.29 - if (UseDepthFirstScavengeOrder) { 30.30 - stack_array_depth()->register_queue(i, _manager_array[i]->claimed_stack_depth()); 30.31 - } else { 30.32 - stack_array_breadth()->register_queue(i, _manager_array[i]->claimed_stack_breadth()); 30.33 - } 30.34 + stack_array_depth()->register_queue(i, _manager_array[i]->claimed_stack_depth()); 30.35 } 30.36 30.37 // The VMThread gets its own PSPromotionManager, which is not available 30.38 @@ -93,11 +83,7 @@ 30.39 TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats()); 30.40 for (uint i = 0; i < ParallelGCThreads + 1; i++) { 30.41 PSPromotionManager* manager = manager_array(i); 30.42 - if (UseDepthFirstScavengeOrder) { 30.43 - assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); 30.44 - } else { 30.45 - assert(manager->claimed_stack_breadth()->is_empty(), "should be empty"); 30.46 - } 30.47 + assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); 30.48 manager->flush_labs(); 30.49 } 30.50 } 30.51 @@ -105,10 +91,8 @@ 30.52 #if TASKQUEUE_STATS 30.53 void 30.54 PSPromotionManager::print_taskqueue_stats(uint i) const { 30.55 - const TaskQueueStats& stats = depth_first() ? 30.56 - _claimed_stack_depth.stats : _claimed_stack_breadth.stats; 30.57 tty->print("%3u ", i); 30.58 - stats.print(); 30.59 + _claimed_stack_depth.stats.print(); 30.60 tty->cr(); 30.61 } 30.62 30.63 @@ -128,8 +112,7 @@ 30.64 30.65 void 30.66 PSPromotionManager::print_stats() { 30.67 - const bool df = UseDepthFirstScavengeOrder; 30.68 - tty->print_cr("== GC Task Stats (%s-First), GC %3d", df ? "Depth" : "Breadth", 30.69 + tty->print_cr("== GC Tasks Stats, GC %3d", 30.70 Universe::heap()->total_collections()); 30.71 30.72 tty->print("thr "); TaskQueueStats::print_header(1); tty->cr(); 30.73 @@ -147,9 +130,7 @@ 30.74 30.75 void 30.76 PSPromotionManager::reset_stats() { 30.77 - TaskQueueStats& stats = depth_first() ? 30.78 - claimed_stack_depth()->stats : claimed_stack_breadth()->stats; 30.79 - stats.reset(); 30.80 + claimed_stack_depth()->stats.reset(); 30.81 _masked_pushes = _masked_steals = 0; 30.82 _arrays_chunked = _array_chunks_processed = 0; 30.83 } 30.84 @@ -158,19 +139,13 @@ 30.85 PSPromotionManager::PSPromotionManager() { 30.86 ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); 30.87 assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); 30.88 - _depth_first = UseDepthFirstScavengeOrder; 30.89 30.90 // We set the old lab's start array. 30.91 _old_lab.set_start_array(old_gen()->start_array()); 30.92 30.93 uint queue_size; 30.94 - if (depth_first()) { 30.95 - claimed_stack_depth()->initialize(); 30.96 - queue_size = claimed_stack_depth()->max_elems(); 30.97 - } else { 30.98 - claimed_stack_breadth()->initialize(); 30.99 - queue_size = claimed_stack_breadth()->max_elems(); 30.100 - } 30.101 + claimed_stack_depth()->initialize(); 30.102 + queue_size = claimed_stack_depth()->max_elems(); 30.103 30.104 _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0); 30.105 if (_totally_drain) { 30.106 @@ -205,14 +180,11 @@ 30.107 _old_lab.initialize(MemRegion(lab_base, (size_t)0)); 30.108 _old_gen_is_full = false; 30.109 30.110 - _prefetch_queue.clear(); 30.111 - 30.112 TASKQUEUE_STATS_ONLY(reset_stats()); 30.113 } 30.114 30.115 30.116 void PSPromotionManager::drain_stacks_depth(bool totally_drain) { 30.117 - assert(depth_first(), "invariant"); 30.118 assert(claimed_stack_depth()->overflow_stack() != NULL, "invariant"); 30.119 totally_drain = totally_drain || _totally_drain; 30.120 30.121 @@ -250,50 +222,6 @@ 30.122 assert(tq->overflow_empty(), "Sanity"); 30.123 } 30.124 30.125 -void PSPromotionManager::drain_stacks_breadth(bool totally_drain) { 30.126 - assert(!depth_first(), "invariant"); 30.127 - assert(claimed_stack_breadth()->overflow_stack() != NULL, "invariant"); 30.128 - totally_drain = totally_drain || _totally_drain; 30.129 - 30.130 -#ifdef ASSERT 30.131 - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); 30.132 - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); 30.133 - MutableSpace* to_space = heap->young_gen()->to_space(); 30.134 - MutableSpace* old_space = heap->old_gen()->object_space(); 30.135 - MutableSpace* perm_space = heap->perm_gen()->object_space(); 30.136 -#endif /* ASSERT */ 30.137 - 30.138 - OverflowTaskQueue<oop>* const tq = claimed_stack_breadth(); 30.139 - do { 30.140 - oop obj; 30.141 - 30.142 - // Drain overflow stack first, so other threads can steal from 30.143 - // claimed stack while we work. 30.144 - while (tq->pop_overflow(obj)) { 30.145 - obj->copy_contents(this); 30.146 - } 30.147 - 30.148 - if (totally_drain) { 30.149 - while (tq->pop_local(obj)) { 30.150 - obj->copy_contents(this); 30.151 - } 30.152 - } else { 30.153 - while (tq->size() > _target_stack_size && tq->pop_local(obj)) { 30.154 - obj->copy_contents(this); 30.155 - } 30.156 - } 30.157 - 30.158 - // If we could not find any other work, flush the prefetch queue 30.159 - if (tq->is_empty()) { 30.160 - flush_prefetch_queue(); 30.161 - } 30.162 - } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty()); 30.163 - 30.164 - assert(!totally_drain || tq->taskqueue_empty(), "Sanity"); 30.165 - assert(totally_drain || tq->size() <= _target_stack_size, "Sanity"); 30.166 - assert(tq->overflow_empty(), "Sanity"); 30.167 -} 30.168 - 30.169 void PSPromotionManager::flush_labs() { 30.170 assert(stacks_empty(), "Attempt to flush lab with live stack"); 30.171 30.172 @@ -319,7 +247,7 @@ 30.173 // performance. 30.174 // 30.175 30.176 -oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) { 30.177 +oop PSPromotionManager::copy_to_survivor_space(oop o) { 30.178 assert(PSScavenge::should_scavenge(&o), "Sanity"); 30.179 30.180 oop new_obj = NULL; 30.181 @@ -423,24 +351,20 @@ 30.182 assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj"); 30.183 } 30.184 30.185 - if (depth_first) { 30.186 - // Do the size comparison first with new_obj_size, which we 30.187 - // already have. Hopefully, only a few objects are larger than 30.188 - // _min_array_size_for_chunking, and most of them will be arrays. 30.189 - // So, the is->objArray() test would be very infrequent. 30.190 - if (new_obj_size > _min_array_size_for_chunking && 30.191 - new_obj->is_objArray() && 30.192 - PSChunkLargeArrays) { 30.193 - // we'll chunk it 30.194 - oop* const masked_o = mask_chunked_array_oop(o); 30.195 - push_depth(masked_o); 30.196 - TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes); 30.197 - } else { 30.198 - // we'll just push its contents 30.199 - new_obj->push_contents(this); 30.200 - } 30.201 + // Do the size comparison first with new_obj_size, which we 30.202 + // already have. Hopefully, only a few objects are larger than 30.203 + // _min_array_size_for_chunking, and most of them will be arrays. 30.204 + // So, the is->objArray() test would be very infrequent. 30.205 + if (new_obj_size > _min_array_size_for_chunking && 30.206 + new_obj->is_objArray() && 30.207 + PSChunkLargeArrays) { 30.208 + // we'll chunk it 30.209 + oop* const masked_o = mask_chunked_array_oop(o); 30.210 + push_depth(masked_o); 30.211 + TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes); 30.212 } else { 30.213 - push_breadth(new_obj); 30.214 + // we'll just push its contents 30.215 + new_obj->push_contents(this); 30.216 } 30.217 } else { 30.218 // We lost, someone else "owns" this object 30.219 @@ -537,13 +461,7 @@ 30.220 // We won any races, we "own" this object. 30.221 assert(obj == obj->forwardee(), "Sanity"); 30.222 30.223 - if (depth_first()) { 30.224 - obj->push_contents(this); 30.225 - } else { 30.226 - // Don't bother incrementing the age, just push 30.227 - // onto the claimed_stack.. 30.228 - push_breadth(obj); 30.229 - } 30.230 + obj->push_contents(this); 30.231 30.232 // Save the mark if needed 30.233 PSScavenge::oop_promotion_failed(obj, obj_mark);
31.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Fri Aug 13 07:33:20 2010 -0700 31.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Sat Aug 14 00:47:52 2010 -0700 31.3 @@ -48,7 +48,6 @@ 31.4 private: 31.5 static PSPromotionManager** _manager_array; 31.6 static OopStarTaskQueueSet* _stack_array_depth; 31.7 - static OopTaskQueueSet* _stack_array_breadth; 31.8 static PSOldGen* _old_gen; 31.9 static MutableSpace* _young_space; 31.10 31.11 @@ -69,12 +68,10 @@ 31.12 PSOldPromotionLAB _old_lab; 31.13 bool _young_gen_is_full; 31.14 bool _old_gen_is_full; 31.15 - PrefetchQueue _prefetch_queue; 31.16 31.17 OopStarTaskQueue _claimed_stack_depth; 31.18 OverflowTaskQueue<oop> _claimed_stack_breadth; 31.19 31.20 - bool _depth_first; 31.21 bool _totally_drain; 31.22 uint _target_stack_size; 31.23 31.24 @@ -87,7 +84,6 @@ 31.25 31.26 inline static PSPromotionManager* manager_array(int index); 31.27 template <class T> inline void claim_or_forward_internal_depth(T* p); 31.28 - template <class T> inline void claim_or_forward_internal_breadth(T* p); 31.29 31.30 // On the task queues we push reference locations as well as 31.31 // partially-scanned arrays (in the latter case, we push an oop to 31.32 @@ -136,19 +132,11 @@ 31.33 void process_array_chunk(oop old); 31.34 31.35 template <class T> void push_depth(T* p) { 31.36 - assert(depth_first(), "pre-condition"); 31.37 claimed_stack_depth()->push(p); 31.38 } 31.39 31.40 - void push_breadth(oop o) { 31.41 - assert(!depth_first(), "pre-condition"); 31.42 - claimed_stack_breadth()->push(o); 31.43 - } 31.44 - 31.45 protected: 31.46 static OopStarTaskQueueSet* stack_array_depth() { return _stack_array_depth; } 31.47 - static OopTaskQueueSet* stack_array_breadth() { return _stack_array_breadth; } 31.48 - 31.49 public: 31.50 // Static 31.51 static void initialize(); 31.52 @@ -163,19 +151,12 @@ 31.53 return stack_array_depth()->steal(queue_num, seed, t); 31.54 } 31.55 31.56 - static bool steal_breadth(int queue_num, int* seed, oop& t) { 31.57 - return stack_array_breadth()->steal(queue_num, seed, t); 31.58 - } 31.59 - 31.60 PSPromotionManager(); 31.61 31.62 // Accessors 31.63 OopStarTaskQueue* claimed_stack_depth() { 31.64 return &_claimed_stack_depth; 31.65 } 31.66 - OverflowTaskQueue<oop>* claimed_stack_breadth() { 31.67 - return &_claimed_stack_breadth; 31.68 - } 31.69 31.70 bool young_gen_is_full() { return _young_gen_is_full; } 31.71 31.72 @@ -183,18 +164,14 @@ 31.73 void set_old_gen_is_full(bool state) { _old_gen_is_full = state; } 31.74 31.75 // Promotion methods 31.76 - oop copy_to_survivor_space(oop o, bool depth_first); 31.77 + oop copy_to_survivor_space(oop o); 31.78 oop oop_promotion_failed(oop obj, markOop obj_mark); 31.79 31.80 void reset(); 31.81 31.82 void flush_labs(); 31.83 void drain_stacks(bool totally_drain) { 31.84 - if (depth_first()) { 31.85 - drain_stacks_depth(totally_drain); 31.86 - } else { 31.87 - drain_stacks_breadth(totally_drain); 31.88 - } 31.89 + drain_stacks_depth(totally_drain); 31.90 } 31.91 public: 31.92 void drain_stacks_cond_depth() { 31.93 @@ -203,22 +180,14 @@ 31.94 } 31.95 } 31.96 void drain_stacks_depth(bool totally_drain); 31.97 - void drain_stacks_breadth(bool totally_drain); 31.98 31.99 - bool depth_first() const { 31.100 - return _depth_first; 31.101 - } 31.102 bool stacks_empty() { 31.103 - return depth_first() ? 31.104 - claimed_stack_depth()->is_empty() : 31.105 - claimed_stack_breadth()->is_empty(); 31.106 + return claimed_stack_depth()->is_empty(); 31.107 } 31.108 31.109 inline void process_popped_location_depth(StarTask p); 31.110 31.111 - inline void flush_prefetch_queue(); 31.112 template <class T> inline void claim_or_forward_depth(T* p); 31.113 - template <class T> inline void claim_or_forward_breadth(T* p); 31.114 31.115 TASKQUEUE_STATS_ONLY(inline void record_steal(StarTask& p);) 31.116 };
32.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Fri Aug 13 07:33:20 2010 -0700 32.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Sat Aug 14 00:47:52 2010 -0700 32.3 @@ -46,32 +46,7 @@ 32.4 } 32.5 32.6 template <class T> 32.7 -inline void PSPromotionManager::claim_or_forward_internal_breadth(T* p) { 32.8 - if (p != NULL) { // XXX: error if p != NULL here 32.9 - oop o = oopDesc::load_decode_heap_oop_not_null(p); 32.10 - if (o->is_forwarded()) { 32.11 - o = o->forwardee(); 32.12 - } else { 32.13 - o = copy_to_survivor_space(o, false); 32.14 - } 32.15 - // Card mark 32.16 - if (PSScavenge::is_obj_in_young((HeapWord*) o)) { 32.17 - PSScavenge::card_table()->inline_write_ref_field_gc(p, o); 32.18 - } 32.19 - oopDesc::encode_store_heap_oop_not_null(p, o); 32.20 - } 32.21 -} 32.22 - 32.23 -inline void PSPromotionManager::flush_prefetch_queue() { 32.24 - assert(!depth_first(), "invariant"); 32.25 - for (int i = 0; i < _prefetch_queue.length(); i++) { 32.26 - claim_or_forward_internal_breadth((oop*)_prefetch_queue.pop()); 32.27 - } 32.28 -} 32.29 - 32.30 -template <class T> 32.31 inline void PSPromotionManager::claim_or_forward_depth(T* p) { 32.32 - assert(depth_first(), "invariant"); 32.33 assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); 32.34 assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, 32.35 "Sanity"); 32.36 @@ -80,36 +55,6 @@ 32.37 claim_or_forward_internal_depth(p); 32.38 } 32.39 32.40 -template <class T> 32.41 -inline void PSPromotionManager::claim_or_forward_breadth(T* p) { 32.42 - assert(!depth_first(), "invariant"); 32.43 - assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); 32.44 - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, 32.45 - "Sanity"); 32.46 - assert(Universe::heap()->is_in(p), "pointer outside heap"); 32.47 - 32.48 - if (UsePrefetchQueue) { 32.49 - claim_or_forward_internal_breadth((T*)_prefetch_queue.push_and_pop(p)); 32.50 - } else { 32.51 - // This option is used for testing. The use of the prefetch 32.52 - // queue can delay the processing of the objects and thus 32.53 - // change the order of object scans. For example, remembered 32.54 - // set updates are typically the clearing of the remembered 32.55 - // set (the cards) followed by updates of the remembered set 32.56 - // for young-to-old pointers. In a situation where there 32.57 - // is an error in the sequence of clearing and updating 32.58 - // (e.g. clear card A, update card A, erroneously clear 32.59 - // card A again) the error can be obscured by a delay 32.60 - // in the update due to the use of the prefetch queue 32.61 - // (e.g., clear card A, erroneously clear card A again, 32.62 - // update card A that was pushed into the prefetch queue 32.63 - // and thus delayed until after the erronous clear). The 32.64 - // length of the delay is random depending on the objects 32.65 - // in the queue and the delay can be zero. 32.66 - claim_or_forward_internal_breadth(p); 32.67 - } 32.68 -} 32.69 - 32.70 inline void PSPromotionManager::process_popped_location_depth(StarTask p) { 32.71 if (is_oop_masked(p)) { 32.72 assert(PSChunkLargeArrays, "invariant");
33.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Aug 13 07:33:20 2010 -0700 33.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Sat Aug 14 00:47:52 2010 -0700 33.3 @@ -157,10 +157,8 @@ 33.4 q->enqueue(new PSRefProcTaskProxy(task, i)); 33.5 } 33.6 ParallelTaskTerminator terminator( 33.7 - ParallelScavengeHeap::gc_task_manager()->workers(), 33.8 - UseDepthFirstScavengeOrder ? 33.9 - (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth() 33.10 - : (TaskQueueSetSuper*) PSPromotionManager::stack_array_breadth()); 33.11 + ParallelScavengeHeap::gc_task_manager()->workers(), 33.12 + (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth()); 33.13 if (task.marks_oops_alive() && ParallelGCThreads > 1) { 33.14 for (uint j=0; j<ParallelGCThreads; j++) { 33.15 q->enqueue(new StealTask(&terminator)); 33.16 @@ -375,10 +373,8 @@ 33.17 q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); 33.18 33.19 ParallelTaskTerminator terminator( 33.20 - gc_task_manager()->workers(), 33.21 - promotion_manager->depth_first() ? 33.22 - (TaskQueueSetSuper*) promotion_manager->stack_array_depth() 33.23 - : (TaskQueueSetSuper*) promotion_manager->stack_array_breadth()); 33.24 + gc_task_manager()->workers(), 33.25 + (TaskQueueSetSuper*) promotion_manager->stack_array_depth()); 33.26 if (ParallelGCThreads>1) { 33.27 for (uint j=0; j<ParallelGCThreads; j++) { 33.28 q->enqueue(new StealTask(&terminator));
34.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Aug 13 07:33:20 2010 -0700 34.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Sat Aug 14 00:47:52 2010 -0700 34.3 @@ -65,7 +65,7 @@ 34.4 oop o = oopDesc::load_decode_heap_oop_not_null(p); 34.5 oop new_obj = o->is_forwarded() 34.6 ? o->forwardee() 34.7 - : pm->copy_to_survivor_space(o, pm->depth_first()); 34.8 + : pm->copy_to_survivor_space(o); 34.9 oopDesc::encode_store_heap_oop_not_null(p, new_obj); 34.10 34.11 // We cannot mark without test, as some code passes us pointers
35.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Aug 13 07:33:20 2010 -0700 35.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Sat Aug 14 00:47:52 2010 -0700 35.3 @@ -144,29 +144,15 @@ 35.4 "stacks should be empty at this point"); 35.5 35.6 int random_seed = 17; 35.7 - if (pm->depth_first()) { 35.8 - while(true) { 35.9 - StarTask p; 35.10 - if (PSPromotionManager::steal_depth(which, &random_seed, p)) { 35.11 - TASKQUEUE_STATS_ONLY(pm->record_steal(p)); 35.12 - pm->process_popped_location_depth(p); 35.13 - pm->drain_stacks_depth(true); 35.14 - } else { 35.15 - if (terminator()->offer_termination()) { 35.16 - break; 35.17 - } 35.18 - } 35.19 - } 35.20 - } else { 35.21 - while(true) { 35.22 - oop obj; 35.23 - if (PSPromotionManager::steal_breadth(which, &random_seed, obj)) { 35.24 - obj->copy_contents(pm); 35.25 - pm->drain_stacks_breadth(true); 35.26 - } else { 35.27 - if (terminator()->offer_termination()) { 35.28 - break; 35.29 - } 35.30 + while(true) { 35.31 + StarTask p; 35.32 + if (PSPromotionManager::steal_depth(which, &random_seed, p)) { 35.33 + TASKQUEUE_STATS_ONLY(pm->record_steal(p)); 35.34 + pm->process_popped_location_depth(p); 35.35 + pm->drain_stacks_depth(true); 35.36 + } else { 35.37 + if (terminator()->offer_termination()) { 35.38 + break; 35.39 } 35.40 } 35.41 }
36.1 --- a/src/share/vm/oops/arrayKlassKlass.cpp Fri Aug 13 07:33:20 2010 -0700 36.2 +++ b/src/share/vm/oops/arrayKlassKlass.cpp Sat Aug 14 00:47:52 2010 -0700 36.3 @@ -108,10 +108,6 @@ 36.4 } 36.5 36.6 #ifndef SERIALGC 36.7 -void arrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 36.8 - assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); 36.9 -} 36.10 - 36.11 void arrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 36.12 assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); 36.13 }
37.1 --- a/src/share/vm/oops/compiledICHolderKlass.cpp Fri Aug 13 07:33:20 2010 -0700 37.2 +++ b/src/share/vm/oops/compiledICHolderKlass.cpp Sat Aug 14 00:47:52 2010 -0700 37.3 @@ -120,10 +120,6 @@ 37.4 } 37.5 37.6 #ifndef SERIALGC 37.7 -void compiledICHolderKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 37.8 - assert(obj->is_compiledICHolder(), "must be compiledICHolder"); 37.9 -} 37.10 - 37.11 void compiledICHolderKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 37.12 assert(obj->is_compiledICHolder(), "must be compiledICHolder"); 37.13 }
38.1 --- a/src/share/vm/oops/constMethodKlass.cpp Fri Aug 13 07:33:20 2010 -0700 38.2 +++ b/src/share/vm/oops/constMethodKlass.cpp Sat Aug 14 00:47:52 2010 -0700 38.3 @@ -157,10 +157,6 @@ 38.4 } 38.5 38.6 #ifndef SERIALGC 38.7 -void constMethodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 38.8 - assert(obj->is_constMethod(), "should be constMethod"); 38.9 -} 38.10 - 38.11 void constMethodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 38.12 assert(obj->is_constMethod(), "should be constMethod"); 38.13 }
39.1 --- a/src/share/vm/oops/constantPoolKlass.cpp Fri Aug 13 07:33:20 2010 -0700 39.2 +++ b/src/share/vm/oops/constantPoolKlass.cpp Sat Aug 14 00:47:52 2010 -0700 39.3 @@ -268,21 +268,6 @@ 39.4 return cp->object_size(); 39.5 } 39.6 39.7 -void constantPoolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 39.8 - assert(obj->is_constantPool(), "should be constant pool"); 39.9 - constantPoolOop cp = (constantPoolOop) obj; 39.10 - if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) { 39.11 - oop* base = (oop*)cp->base(); 39.12 - for (int i = 0; i < cp->length(); ++i, ++base) { 39.13 - if (cp->tag_at(i).is_string()) { 39.14 - if (PSScavenge::should_scavenge(base)) { 39.15 - pm->claim_or_forward_breadth(base); 39.16 - } 39.17 - } 39.18 - } 39.19 - } 39.20 -} 39.21 - 39.22 void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 39.23 assert(obj->is_constantPool(), "should be constant pool"); 39.24 constantPoolOop cp = (constantPoolOop) obj;
40.1 --- a/src/share/vm/oops/cpCacheKlass.cpp Fri Aug 13 07:33:20 2010 -0700 40.2 +++ b/src/share/vm/oops/cpCacheKlass.cpp Sat Aug 14 00:47:52 2010 -0700 40.3 @@ -166,29 +166,6 @@ 40.4 } 40.5 40.6 #ifndef SERIALGC 40.7 -void constantPoolCacheKlass::oop_copy_contents(PSPromotionManager* pm, 40.8 - oop obj) { 40.9 - assert(obj->is_constantPoolCache(), "should be constant pool"); 40.10 - if (EnableInvokeDynamic) { 40.11 - constantPoolCacheOop cache = (constantPoolCacheOop)obj; 40.12 - // during a scavenge, it is safe to inspect my pool, since it is perm 40.13 - constantPoolOop pool = cache->constant_pool(); 40.14 - assert(pool->is_constantPool(), "should be constant pool"); 40.15 - if (pool->has_invokedynamic()) { 40.16 - for (int i = 0; i < cache->length(); i++) { 40.17 - ConstantPoolCacheEntry* e = cache->entry_at(i); 40.18 - oop* p = (oop*)&e->_f1; 40.19 - if (e->is_secondary_entry()) { 40.20 - if (PSScavenge::should_scavenge(p)) 40.21 - pm->claim_or_forward_breadth(p); 40.22 - assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), 40.23 - "no live oops here"); 40.24 - } 40.25 - } 40.26 - } 40.27 - } 40.28 -} 40.29 - 40.30 void constantPoolCacheKlass::oop_push_contents(PSPromotionManager* pm, 40.31 oop obj) { 40.32 assert(obj->is_constantPoolCache(), "should be constant pool");
41.1 --- a/src/share/vm/oops/instanceKlass.cpp Fri Aug 13 07:33:20 2010 -0700 41.2 +++ b/src/share/vm/oops/instanceKlass.cpp Sat Aug 14 00:47:52 2010 -0700 41.3 @@ -1809,18 +1809,7 @@ 41.4 } 41.5 41.6 #ifndef SERIALGC 41.7 -void instanceKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 41.8 - assert(!pm->depth_first(), "invariant"); 41.9 - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ 41.10 - obj, \ 41.11 - if (PSScavenge::should_scavenge(p)) { \ 41.12 - pm->claim_or_forward_breadth(p); \ 41.13 - }, \ 41.14 - assert_nothing ) 41.15 -} 41.16 - 41.17 void instanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 41.18 - assert(pm->depth_first(), "invariant"); 41.19 InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ 41.20 obj, \ 41.21 if (PSScavenge::should_scavenge(p)) { \ 41.22 @@ -1846,18 +1835,7 @@ 41.23 return size_helper(); 41.24 } 41.25 41.26 -void instanceKlass::copy_static_fields(PSPromotionManager* pm) { 41.27 - assert(!pm->depth_first(), "invariant"); 41.28 - InstanceKlass_OOP_ITERATE( \ 41.29 - start_of_static_fields(), static_oop_field_size(), \ 41.30 - if (PSScavenge::should_scavenge(p)) { \ 41.31 - pm->claim_or_forward_breadth(p); \ 41.32 - }, \ 41.33 - assert_nothing ) 41.34 -} 41.35 - 41.36 void instanceKlass::push_static_fields(PSPromotionManager* pm) { 41.37 - assert(pm->depth_first(), "invariant"); 41.38 InstanceKlass_OOP_ITERATE( \ 41.39 start_of_static_fields(), static_oop_field_size(), \ 41.40 if (PSScavenge::should_scavenge(p)) { \
42.1 --- a/src/share/vm/oops/instanceKlass.hpp Fri Aug 13 07:33:20 2010 -0700 42.2 +++ b/src/share/vm/oops/instanceKlass.hpp Sat Aug 14 00:47:52 2010 -0700 42.3 @@ -711,7 +711,6 @@ 42.4 42.5 #ifndef SERIALGC 42.6 // Parallel Scavenge 42.7 - void copy_static_fields(PSPromotionManager* pm); 42.8 void push_static_fields(PSPromotionManager* pm); 42.9 42.10 // Parallel Old
43.1 --- a/src/share/vm/oops/instanceKlassKlass.cpp Fri Aug 13 07:33:20 2010 -0700 43.2 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Sat Aug 14 00:47:52 2010 -0700 43.3 @@ -292,41 +292,7 @@ 43.4 } 43.5 43.6 #ifndef SERIALGC 43.7 -void instanceKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 43.8 - assert(!pm->depth_first(), "invariant"); 43.9 - instanceKlass* ik = instanceKlass::cast(klassOop(obj)); 43.10 - ik->copy_static_fields(pm); 43.11 - 43.12 - oop* loader_addr = ik->adr_class_loader(); 43.13 - if (PSScavenge::should_scavenge(loader_addr)) { 43.14 - pm->claim_or_forward_breadth(loader_addr); 43.15 - } 43.16 - 43.17 - oop* pd_addr = ik->adr_protection_domain(); 43.18 - if (PSScavenge::should_scavenge(pd_addr)) { 43.19 - pm->claim_or_forward_breadth(pd_addr); 43.20 - } 43.21 - 43.22 - oop* hk_addr = ik->adr_host_klass(); 43.23 - if (PSScavenge::should_scavenge(hk_addr)) { 43.24 - pm->claim_or_forward_breadth(hk_addr); 43.25 - } 43.26 - 43.27 - oop* sg_addr = ik->adr_signers(); 43.28 - if (PSScavenge::should_scavenge(sg_addr)) { 43.29 - pm->claim_or_forward_breadth(sg_addr); 43.30 - } 43.31 - 43.32 - oop* bsm_addr = ik->adr_bootstrap_method(); 43.33 - if (PSScavenge::should_scavenge(bsm_addr)) { 43.34 - pm->claim_or_forward_breadth(bsm_addr); 43.35 - } 43.36 - 43.37 - klassKlass::oop_copy_contents(pm, obj); 43.38 -} 43.39 - 43.40 void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 43.41 - assert(pm->depth_first(), "invariant"); 43.42 instanceKlass* ik = instanceKlass::cast(klassOop(obj)); 43.43 ik->push_static_fields(pm); 43.44 43.45 @@ -355,7 +321,7 @@ 43.46 pm->claim_or_forward_depth(bsm_addr); 43.47 } 43.48 43.49 - klassKlass::oop_copy_contents(pm, obj); 43.50 + klassKlass::oop_push_contents(pm, obj); 43.51 } 43.52 43.53 int instanceKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
44.1 --- a/src/share/vm/oops/instanceRefKlass.cpp Fri Aug 13 07:33:20 2010 -0700 44.2 +++ b/src/share/vm/oops/instanceRefKlass.cpp Sat Aug 14 00:47:52 2010 -0700 44.3 @@ -273,41 +273,8 @@ 44.4 44.5 #ifndef SERIALGC 44.6 template <class T> 44.7 -void specialized_oop_copy_contents(instanceRefKlass *ref, 44.8 - PSPromotionManager* pm, oop obj) { 44.9 - assert(!pm->depth_first(), "invariant"); 44.10 - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); 44.11 - if (PSScavenge::should_scavenge(referent_addr)) { 44.12 - ReferenceProcessor* rp = PSScavenge::reference_processor(); 44.13 - if (rp->discover_reference(obj, ref->reference_type())) { 44.14 - // reference already enqueued, referent and next will be traversed later 44.15 - ref->instanceKlass::oop_copy_contents(pm, obj); 44.16 - return; 44.17 - } else { 44.18 - // treat referent as normal oop 44.19 - pm->claim_or_forward_breadth(referent_addr); 44.20 - } 44.21 - } 44.22 - // treat next as normal oop 44.23 - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); 44.24 - if (PSScavenge::should_scavenge(next_addr)) { 44.25 - pm->claim_or_forward_breadth(next_addr); 44.26 - } 44.27 - ref->instanceKlass::oop_copy_contents(pm, obj); 44.28 -} 44.29 - 44.30 -void instanceRefKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 44.31 - if (UseCompressedOops) { 44.32 - specialized_oop_copy_contents<narrowOop>(this, pm, obj); 44.33 - } else { 44.34 - specialized_oop_copy_contents<oop>(this, pm, obj); 44.35 - } 44.36 -} 44.37 - 44.38 -template <class T> 44.39 void specialized_oop_push_contents(instanceRefKlass *ref, 44.40 PSPromotionManager* pm, oop obj) { 44.41 - assert(pm->depth_first(), "invariant"); 44.42 T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); 44.43 if (PSScavenge::should_scavenge(referent_addr)) { 44.44 ReferenceProcessor* rp = PSScavenge::reference_processor();
45.1 --- a/src/share/vm/oops/klassKlass.cpp Fri Aug 13 07:33:20 2010 -0700 45.2 +++ b/src/share/vm/oops/klassKlass.cpp Sat Aug 14 00:47:52 2010 -0700 45.3 @@ -161,9 +161,6 @@ 45.4 } 45.5 45.6 #ifndef SERIALGC 45.7 -void klassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 45.8 -} 45.9 - 45.10 void klassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 45.11 } 45.12
46.1 --- a/src/share/vm/oops/klassPS.hpp Fri Aug 13 07:33:20 2010 -0700 46.2 +++ b/src/share/vm/oops/klassPS.hpp Sat Aug 14 00:47:52 2010 -0700 46.3 @@ -28,7 +28,6 @@ 46.4 46.5 #ifndef SERIALGC 46.6 #define PARALLEL_GC_DECLS \ 46.7 - virtual void oop_copy_contents(PSPromotionManager* pm, oop obj); \ 46.8 virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ 46.9 /* Parallel Old GC support \ 46.10 \ 46.11 @@ -43,7 +42,6 @@ 46.12 46.13 // Pure virtual version for klass.hpp 46.14 #define PARALLEL_GC_DECLS_PV \ 46.15 - virtual void oop_copy_contents(PSPromotionManager* pm, oop obj) = 0; \ 46.16 virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ 46.17 virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ 46.18 virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; \
47.1 --- a/src/share/vm/oops/methodDataKlass.cpp Fri Aug 13 07:33:20 2010 -0700 47.2 +++ b/src/share/vm/oops/methodDataKlass.cpp Sat Aug 14 00:47:52 2010 -0700 47.3 @@ -154,13 +154,6 @@ 47.4 47.5 47.6 #ifndef SERIALGC 47.7 -void methodDataKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 47.8 - assert (obj->is_methodData(), "object must be method data"); 47.9 - methodDataOop m = methodDataOop(obj); 47.10 - // This should never point into the young gen. 47.11 - assert(!PSScavenge::should_scavenge(m->adr_method()), "Sanity"); 47.12 -} 47.13 - 47.14 void methodDataKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 47.15 assert (obj->is_methodData(), "object must be method data"); 47.16 methodDataOop m = methodDataOop(obj);
48.1 --- a/src/share/vm/oops/methodKlass.cpp Fri Aug 13 07:33:20 2010 -0700 48.2 +++ b/src/share/vm/oops/methodKlass.cpp Sat Aug 14 00:47:52 2010 -0700 48.3 @@ -184,10 +184,6 @@ 48.4 } 48.5 48.6 #ifndef SERIALGC 48.7 -void methodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 48.8 - assert(obj->is_method(), "should be method"); 48.9 -} 48.10 - 48.11 void methodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 48.12 assert(obj->is_method(), "should be method"); 48.13 }
49.1 --- a/src/share/vm/oops/objArrayKlass.cpp Fri Aug 13 07:33:20 2010 -0700 49.2 +++ b/src/share/vm/oops/objArrayKlass.cpp Sat Aug 14 00:47:52 2010 -0700 49.3 @@ -426,18 +426,7 @@ 49.4 } 49.5 49.6 #ifndef SERIALGC 49.7 -void objArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 49.8 - assert(!pm->depth_first(), "invariant"); 49.9 - assert(obj->is_objArray(), "obj must be obj array"); 49.10 - ObjArrayKlass_OOP_ITERATE( \ 49.11 - objArrayOop(obj), p, \ 49.12 - if (PSScavenge::should_scavenge(p)) { \ 49.13 - pm->claim_or_forward_breadth(p); \ 49.14 - }) 49.15 -} 49.16 - 49.17 void objArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 49.18 - assert(pm->depth_first(), "invariant"); 49.19 assert(obj->is_objArray(), "obj must be obj array"); 49.20 ObjArrayKlass_OOP_ITERATE( \ 49.21 objArrayOop(obj), p, \
50.1 --- a/src/share/vm/oops/objArrayKlassKlass.cpp Fri Aug 13 07:33:20 2010 -0700 50.2 +++ b/src/share/vm/oops/objArrayKlassKlass.cpp Sat Aug 14 00:47:52 2010 -0700 50.3 @@ -229,10 +229,6 @@ 50.4 } 50.5 50.6 #ifndef SERIALGC 50.7 -void objArrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 50.8 - assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); 50.9 -} 50.10 - 50.11 void objArrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 50.12 assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); 50.13 }
51.1 --- a/src/share/vm/oops/oop.hpp Fri Aug 13 07:33:20 2010 -0700 51.2 +++ b/src/share/vm/oops/oop.hpp Sat Aug 14 00:47:52 2010 -0700 51.3 @@ -306,7 +306,6 @@ 51.4 51.5 #ifndef SERIALGC 51.6 // Parallel Scavenge 51.7 - void copy_contents(PSPromotionManager* pm); 51.8 void push_contents(PSPromotionManager* pm); 51.9 51.10 // Parallel Old
52.1 --- a/src/share/vm/oops/oop.psgc.inline.hpp Fri Aug 13 07:33:20 2010 -0700 52.2 +++ b/src/share/vm/oops/oop.psgc.inline.hpp Sat Aug 14 00:47:52 2010 -0700 52.3 @@ -24,15 +24,6 @@ 52.4 52.5 // ParallelScavengeHeap methods 52.6 52.7 -inline void oopDesc::copy_contents(PSPromotionManager* pm) { 52.8 - Klass* klass = blueprint(); 52.9 - if (!klass->oop_is_typeArray()) { 52.10 - // It might contain oops beyond the header, so take the virtual call. 52.11 - klass->oop_copy_contents(pm, this); 52.12 - } 52.13 - // Else skip it. The typeArrayKlass in the header never needs scavenging. 52.14 -} 52.15 - 52.16 inline void oopDesc::push_contents(PSPromotionManager* pm) { 52.17 Klass* klass = blueprint(); 52.18 if (!klass->oop_is_typeArray()) {
53.1 --- a/src/share/vm/oops/symbolKlass.cpp Fri Aug 13 07:33:20 2010 -0700 53.2 +++ b/src/share/vm/oops/symbolKlass.cpp Sat Aug 14 00:47:52 2010 -0700 53.3 @@ -184,10 +184,6 @@ 53.4 53.5 53.6 #ifndef SERIALGC 53.7 -void symbolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 53.8 - assert(obj->is_symbol(), "should be symbol"); 53.9 -} 53.10 - 53.11 void symbolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 53.12 assert(obj->is_symbol(), "should be symbol"); 53.13 }
54.1 --- a/src/share/vm/oops/typeArrayKlass.cpp Fri Aug 13 07:33:20 2010 -0700 54.2 +++ b/src/share/vm/oops/typeArrayKlass.cpp Sat Aug 14 00:47:52 2010 -0700 54.3 @@ -228,10 +228,6 @@ 54.4 } 54.5 54.6 #ifndef SERIALGC 54.7 -void typeArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { 54.8 - assert(obj->is_typeArray(),"must be a type array"); 54.9 -} 54.10 - 54.11 void typeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { 54.12 assert(obj->is_typeArray(),"must be a type array"); 54.13 }
55.1 --- a/src/share/vm/runtime/arguments.cpp Fri Aug 13 07:33:20 2010 -0700 55.2 +++ b/src/share/vm/runtime/arguments.cpp Sat Aug 14 00:47:52 2010 -0700 55.3 @@ -184,6 +184,8 @@ 55.4 { "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, 55.5 { "DefaultInitialRAMFraction", 55.6 JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, 55.7 + { "UseDepthFirstScavengeOrder", 55.8 + JDK_Version::jdk_update(6,22), JDK_Version::jdk(7) }, 55.9 { NULL, JDK_Version(0), JDK_Version(0) } 55.10 }; 55.11
56.1 --- a/src/share/vm/runtime/globals.hpp Fri Aug 13 07:33:20 2010 -0700 56.2 +++ b/src/share/vm/runtime/globals.hpp Sat Aug 14 00:47:52 2010 -0700 56.3 @@ -3092,10 +3092,6 @@ 56.4 \ 56.5 product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ 56.6 \ 56.7 - product(bool, UseDepthFirstScavengeOrder, true, \ 56.8 - "true: the scavenge order will be depth-first, " \ 56.9 - "false: the scavenge order will be breadth-first") \ 56.10 - \ 56.11 product(bool, PSChunkLargeArrays, true, \ 56.12 "true: process large arrays in chunks") \ 56.13 \
57.1 --- a/src/share/vm/runtime/orderAccess.cpp Fri Aug 13 07:33:20 2010 -0700 57.2 +++ b/src/share/vm/runtime/orderAccess.cpp Sat Aug 14 00:47:52 2010 -0700 57.3 @@ -1,5 +1,5 @@ 57.4 /* 57.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 57.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 57.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 57.8 * 57.9 * This code is free software; you can redistribute it and/or modify it 57.10 @@ -25,8 +25,6 @@ 57.11 # include "incls/_precompiled.incl" 57.12 # include "incls/_orderAccess.cpp.incl" 57.13 57.14 -volatile intptr_t OrderAccess::dummy = 0; 57.15 - 57.16 void OrderAccess::StubRoutines_fence() { 57.17 // Use a stub if it exists. It may not exist during bootstrap so do 57.18 // nothing in that case but assert if no fence code exists after threads have been created
58.1 --- a/src/share/vm/runtime/orderAccess.hpp Fri Aug 13 07:33:20 2010 -0700 58.2 +++ b/src/share/vm/runtime/orderAccess.hpp Sat Aug 14 00:47:52 2010 -0700 58.3 @@ -1,5 +1,5 @@ 58.4 /* 58.5 - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 58.6 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 58.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 58.8 * 58.9 * This code is free software; you can redistribute it and/or modify it 58.10 @@ -166,6 +166,12 @@ 58.11 // and release must include a sequence point, usually via a volatile memory 58.12 // access. Other ways to guarantee a sequence point are, e.g., use of 58.13 // indirect calls and linux's __asm__ volatile. 58.14 +// Note: as of 6973570, we have replaced the originally static "dummy" field 58.15 +// (see above) by a volatile store to the stack. All of the versions of the 58.16 +// compilers that we currently use (SunStudio, gcc and VC++) respect the 58.17 +// semantics of volatile here. If you build HotSpot using other 58.18 +// compilers, you may need to verify that no compiler reordering occurs 58.19 +// across the sequence point respresented by the volatile access. 58.20 // 58.21 // 58.22 // os::is_MP Considered Redundant 58.23 @@ -297,10 +303,6 @@ 58.24 static void release_store_ptr_fence(volatile intptr_t* p, intptr_t v); 58.25 static void release_store_ptr_fence(volatile void* p, void* v); 58.26 58.27 - // In order to force a memory access, implementations may 58.28 - // need a volatile externally visible dummy variable. 58.29 - static volatile intptr_t dummy; 58.30 - 58.31 private: 58.32 // This is a helper that invokes the StubRoutines::fence_entry() 58.33 // routine if it exists, It should only be used by platforms that
59.1 --- a/src/share/vm/services/management.cpp Fri Aug 13 07:33:20 2010 -0700 59.2 +++ b/src/share/vm/services/management.cpp Sat Aug 14 00:47:52 2010 -0700 59.3 @@ -1900,16 +1900,15 @@ 59.4 59.5 // Get the GCMemoryManager 59.6 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK); 59.7 - if (mgr->last_gc_stat() == NULL) { 59.8 - gc_stat->gc_index = 0; 59.9 - return; 59.10 - } 59.11 59.12 // Make a copy of the last GC statistics 59.13 // GC may occur while constructing the last GC information 59.14 int num_pools = MemoryService::num_memory_pools(); 59.15 GCStatInfo* stat = new GCStatInfo(num_pools); 59.16 - stat->copy_stat(mgr->last_gc_stat()); 59.17 + if (mgr->get_last_gc_stat(stat) == 0) { 59.18 + gc_stat->gc_index = 0; 59.19 + return; 59.20 + } 59.21 59.22 gc_stat->gc_index = stat->gc_index(); 59.23 gc_stat->start_time = Management::ticks_to_ms(stat->start_time());
60.1 --- a/src/share/vm/services/memoryManager.cpp Fri Aug 13 07:33:20 2010 -0700 60.2 +++ b/src/share/vm/services/memoryManager.cpp Sat Aug 14 00:47:52 2010 -0700 60.3 @@ -166,17 +166,6 @@ 60.4 FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); 60.5 } 60.6 60.7 -void GCStatInfo::copy_stat(GCStatInfo* stat) { 60.8 - set_index(stat->gc_index()); 60.9 - set_start_time(stat->start_time()); 60.10 - set_end_time(stat->end_time()); 60.11 - assert(_usage_array_size == stat->usage_array_size(), "Must have same array size"); 60.12 - for (int i = 0; i < _usage_array_size; i++) { 60.13 - set_before_gc_usage(i, stat->before_gc_usage_for_pool(i)); 60.14 - set_after_gc_usage(i, stat->after_gc_usage_for_pool(i)); 60.15 - } 60.16 -} 60.17 - 60.18 void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { 60.19 MemoryUsage* gc_usage_array; 60.20 if (before_gc) { 60.21 @@ -187,67 +176,129 @@ 60.22 gc_usage_array[pool_index] = usage; 60.23 } 60.24 60.25 +void GCStatInfo::clear() { 60.26 + _index = 0; 60.27 + _start_time = 0L; 60.28 + _end_time = 0L; 60.29 + size_t len = _usage_array_size * sizeof(MemoryUsage); 60.30 + memset(_before_gc_usage_array, 0, len); 60.31 + memset(_after_gc_usage_array, 0, len); 60.32 +} 60.33 + 60.34 + 60.35 GCMemoryManager::GCMemoryManager() : MemoryManager() { 60.36 _num_collections = 0; 60.37 _last_gc_stat = NULL; 60.38 + _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", true); 60.39 + _current_gc_stat = NULL; 60.40 _num_gc_threads = 1; 60.41 } 60.42 60.43 GCMemoryManager::~GCMemoryManager() { 60.44 delete _last_gc_stat; 60.45 + delete _last_gc_lock; 60.46 + delete _current_gc_stat; 60.47 } 60.48 60.49 void GCMemoryManager::initialize_gc_stat_info() { 60.50 assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools"); 60.51 _last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); 60.52 + _current_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); 60.53 + // tracking concurrent collections we need two objects: one to update, and one to 60.54 + // hold the publicly available "last (completed) gc" information. 60.55 } 60.56 60.57 -void GCMemoryManager::gc_begin() { 60.58 - assert(_last_gc_stat != NULL, "Just checking"); 60.59 - _accumulated_timer.start(); 60.60 - _num_collections++; 60.61 - _last_gc_stat->set_index(_num_collections); 60.62 - _last_gc_stat->set_start_time(Management::timestamp()); 60.63 +void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, 60.64 + bool recordAccumulatedGCTime) { 60.65 + assert(_last_gc_stat != NULL && _current_gc_stat != NULL, "Just checking"); 60.66 + if (recordAccumulatedGCTime) { 60.67 + _accumulated_timer.start(); 60.68 + } 60.69 + // _num_collections now increases in gc_end, to count completed collections 60.70 + if (recordGCBeginTime) { 60.71 + _current_gc_stat->set_index(_num_collections+1); 60.72 + _current_gc_stat->set_start_time(Management::timestamp()); 60.73 + } 60.74 60.75 - // Keep memory usage of all memory pools 60.76 - for (int i = 0; i < MemoryService::num_memory_pools(); i++) { 60.77 - MemoryPool* pool = MemoryService::get_memory_pool(i); 60.78 - MemoryUsage usage = pool->get_memory_usage(); 60.79 - _last_gc_stat->set_before_gc_usage(i, usage); 60.80 - HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, 60.81 - name(), strlen(name()), 60.82 - pool->name(), strlen(pool->name()), 60.83 - usage.init_size(), usage.used(), 60.84 - usage.committed(), usage.max_size()); 60.85 + if (recordPreGCUsage) { 60.86 + // Keep memory usage of all memory pools 60.87 + for (int i = 0; i < MemoryService::num_memory_pools(); i++) { 60.88 + MemoryPool* pool = MemoryService::get_memory_pool(i); 60.89 + MemoryUsage usage = pool->get_memory_usage(); 60.90 + _current_gc_stat->set_before_gc_usage(i, usage); 60.91 + HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, 60.92 + name(), strlen(name()), 60.93 + pool->name(), strlen(pool->name()), 60.94 + usage.init_size(), usage.used(), 60.95 + usage.committed(), usage.max_size()); 60.96 + } 60.97 } 60.98 } 60.99 60.100 -void GCMemoryManager::gc_end() { 60.101 - _accumulated_timer.stop(); 60.102 - _last_gc_stat->set_end_time(Management::timestamp()); 60.103 - 60.104 - int i; 60.105 - // keep the last gc statistics for all memory pools 60.106 - for (i = 0; i < MemoryService::num_memory_pools(); i++) { 60.107 - MemoryPool* pool = MemoryService::get_memory_pool(i); 60.108 - MemoryUsage usage = pool->get_memory_usage(); 60.109 - 60.110 - HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, 60.111 - name(), strlen(name()), 60.112 - pool->name(), strlen(pool->name()), 60.113 - usage.init_size(), usage.used(), 60.114 - usage.committed(), usage.max_size()); 60.115 - 60.116 - _last_gc_stat->set_after_gc_usage(i, usage); 60.117 +// A collector MUST, even if it does not complete for some reason, 60.118 +// make a TraceMemoryManagerStats object where countCollection is true, 60.119 +// to ensure the current gc stat is placed in _last_gc_stat. 60.120 +void GCMemoryManager::gc_end(bool recordPostGCUsage, 60.121 + bool recordAccumulatedGCTime, 60.122 + bool recordGCEndTime, bool countCollection) { 60.123 + if (recordAccumulatedGCTime) { 60.124 + _accumulated_timer.stop(); 60.125 + } 60.126 + if (recordGCEndTime) { 60.127 + _current_gc_stat->set_end_time(Management::timestamp()); 60.128 } 60.129 60.130 - // Set last collection usage of the memory pools managed by this collector 60.131 - for (i = 0; i < num_memory_pools(); i++) { 60.132 - MemoryPool* pool = get_memory_pool(i); 60.133 - MemoryUsage usage = pool->get_memory_usage(); 60.134 + if (recordPostGCUsage) { 60.135 + int i; 60.136 + // keep the last gc statistics for all memory pools 60.137 + for (i = 0; i < MemoryService::num_memory_pools(); i++) { 60.138 + MemoryPool* pool = MemoryService::get_memory_pool(i); 60.139 + MemoryUsage usage = pool->get_memory_usage(); 60.140 60.141 - // Compare with GC usage threshold 60.142 - pool->set_last_collection_usage(usage); 60.143 - LowMemoryDetector::detect_after_gc_memory(pool); 60.144 + HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, 60.145 + name(), strlen(name()), 60.146 + pool->name(), strlen(pool->name()), 60.147 + usage.init_size(), usage.used(), 60.148 + usage.committed(), usage.max_size()); 60.149 + 60.150 + _current_gc_stat->set_after_gc_usage(i, usage); 60.151 + } 60.152 + 60.153 + // Set last collection usage of the memory pools managed by this collector 60.154 + for (i = 0; i < num_memory_pools(); i++) { 60.155 + MemoryPool* pool = get_memory_pool(i); 60.156 + MemoryUsage usage = pool->get_memory_usage(); 60.157 + 60.158 + // Compare with GC usage threshold 60.159 + pool->set_last_collection_usage(usage); 60.160 + LowMemoryDetector::detect_after_gc_memory(pool); 60.161 + } 60.162 + } 60.163 + if (countCollection) { 60.164 + _num_collections++; 60.165 + // alternately update two objects making one public when complete 60.166 + { 60.167 + MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); 60.168 + GCStatInfo *tmp = _last_gc_stat; 60.169 + _last_gc_stat = _current_gc_stat; 60.170 + _current_gc_stat = tmp; 60.171 + // reset the current stat for diagnosability purposes 60.172 + _current_gc_stat->clear(); 60.173 + } 60.174 } 60.175 } 60.176 + 60.177 +size_t GCMemoryManager::get_last_gc_stat(GCStatInfo* dest) { 60.178 + MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); 60.179 + if (_last_gc_stat->gc_index() != 0) { 60.180 + dest->set_index(_last_gc_stat->gc_index()); 60.181 + dest->set_start_time(_last_gc_stat->start_time()); 60.182 + dest->set_end_time(_last_gc_stat->end_time()); 60.183 + assert(dest->usage_array_size() == _last_gc_stat->usage_array_size(), 60.184 + "Must have same array size"); 60.185 + size_t len = dest->usage_array_size() * sizeof(MemoryUsage); 60.186 + memcpy(dest->before_gc_usage_array(), _last_gc_stat->before_gc_usage_array(), len); 60.187 + memcpy(dest->after_gc_usage_array(), _last_gc_stat->after_gc_usage_array(), len); 60.188 + } 60.189 + return _last_gc_stat->gc_index(); 60.190 +}
61.1 --- a/src/share/vm/services/memoryManager.hpp Fri Aug 13 07:33:20 2010 -0700 61.2 +++ b/src/share/vm/services/memoryManager.hpp Sat Aug 14 00:47:52 2010 -0700 61.3 @@ -131,6 +131,9 @@ 61.4 return _after_gc_usage_array[pool_index]; 61.5 } 61.6 61.7 + MemoryUsage* before_gc_usage_array() { return _before_gc_usage_array; } 61.8 + MemoryUsage* after_gc_usage_array() { return _after_gc_usage_array; } 61.9 + 61.10 void set_index(size_t index) { _index = index; } 61.11 void set_start_time(jlong time) { _start_time = time; } 61.12 void set_end_time(jlong time) { _end_time = time; } 61.13 @@ -143,7 +146,7 @@ 61.14 set_gc_usage(pool_index, usage, false /* after gc */); 61.15 } 61.16 61.17 - void copy_stat(GCStatInfo* stat); 61.18 + void clear(); 61.19 }; 61.20 61.21 class GCMemoryManager : public MemoryManager { 61.22 @@ -153,6 +156,8 @@ 61.23 elapsedTimer _accumulated_timer; 61.24 elapsedTimer _gc_timer; // for measuring every GC duration 61.25 GCStatInfo* _last_gc_stat; 61.26 + Mutex* _last_gc_lock; 61.27 + GCStatInfo* _current_gc_stat; 61.28 int _num_gc_threads; 61.29 public: 61.30 GCMemoryManager(); 61.31 @@ -166,11 +171,16 @@ 61.32 int num_gc_threads() { return _num_gc_threads; } 61.33 void set_num_gc_threads(int count) { _num_gc_threads = count; } 61.34 61.35 - void gc_begin(); 61.36 - void gc_end(); 61.37 + void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, 61.38 + bool recordAccumulatedGCTime); 61.39 + void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime, 61.40 + bool recordGCEndTime, bool countCollection); 61.41 61.42 void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); } 61.43 - GCStatInfo* last_gc_stat() { return _last_gc_stat; } 61.44 + 61.45 + // Copy out _last_gc_stat to the given destination, returning 61.46 + // the collection count. Zero signifies no gc has taken place. 61.47 + size_t get_last_gc_stat(GCStatInfo* dest); 61.48 61.49 virtual MemoryManager::Name kind() = 0; 61.50 };
62.1 --- a/src/share/vm/services/memoryService.cpp Fri Aug 13 07:33:20 2010 -0700 62.2 +++ b/src/share/vm/services/memoryService.cpp Sat Aug 14 00:47:52 2010 -0700 62.3 @@ -509,7 +509,10 @@ 62.4 } 62.5 } 62.6 62.7 -void MemoryService::gc_begin(bool fullGC) { 62.8 +void MemoryService::gc_begin(bool fullGC, bool recordGCBeginTime, 62.9 + bool recordAccumulatedGCTime, 62.10 + bool recordPreGCUsage, bool recordPeakUsage) { 62.11 + 62.12 GCMemoryManager* mgr; 62.13 if (fullGC) { 62.14 mgr = _major_gc_manager; 62.15 @@ -517,16 +520,21 @@ 62.16 mgr = _minor_gc_manager; 62.17 } 62.18 assert(mgr->is_gc_memory_manager(), "Sanity check"); 62.19 - mgr->gc_begin(); 62.20 + mgr->gc_begin(recordGCBeginTime, recordPreGCUsage, recordAccumulatedGCTime); 62.21 62.22 // Track the peak memory usage when GC begins 62.23 - for (int i = 0; i < _pools_list->length(); i++) { 62.24 - MemoryPool* pool = _pools_list->at(i); 62.25 - pool->record_peak_memory_usage(); 62.26 + if (recordPeakUsage) { 62.27 + for (int i = 0; i < _pools_list->length(); i++) { 62.28 + MemoryPool* pool = _pools_list->at(i); 62.29 + pool->record_peak_memory_usage(); 62.30 + } 62.31 } 62.32 } 62.33 62.34 -void MemoryService::gc_end(bool fullGC) { 62.35 +void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage, 62.36 + bool recordAccumulatedGCTime, 62.37 + bool recordGCEndTime, bool countCollection) { 62.38 + 62.39 GCMemoryManager* mgr; 62.40 if (fullGC) { 62.41 mgr = (GCMemoryManager*) _major_gc_manager; 62.42 @@ -536,7 +544,8 @@ 62.43 assert(mgr->is_gc_memory_manager(), "Sanity check"); 62.44 62.45 // register the GC end statistics and memory usage 62.46 - mgr->gc_end(); 62.47 + mgr->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, 62.48 + countCollection); 62.49 } 62.50 62.51 void MemoryService::oops_do(OopClosure* f) { 62.52 @@ -585,12 +594,12 @@ 62.53 return obj; 62.54 } 62.55 // 62.56 -// GC manager type depends on the type of Generation. Depending the space 62.57 -// availablity and vm option the gc uses major gc manager or minor gc 62.58 +// GC manager type depends on the type of Generation. Depending on the space 62.59 +// availablity and vm options the gc uses major gc manager or minor gc 62.60 // manager or both. The type of gc manager depends on the generation kind. 62.61 -// For DefNew, ParNew and ASParNew generation doing scavange gc uses minor 62.62 -// gc manager (so _fullGC is set to false ) and for other generation kind 62.63 -// DOing mark-sweep-compact uses major gc manager (so _fullGC is set 62.64 +// For DefNew, ParNew and ASParNew generation doing scavenge gc uses minor 62.65 +// gc manager (so _fullGC is set to false ) and for other generation kinds 62.66 +// doing mark-sweep-compact uses major gc manager (so _fullGC is set 62.67 // to true). 62.68 TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind) { 62.69 switch (kind) { 62.70 @@ -611,13 +620,48 @@ 62.71 default: 62.72 assert(false, "Unrecognized gc generation kind."); 62.73 } 62.74 - MemoryService::gc_begin(_fullGC); 62.75 + // this has to be called in a stop the world pause and represent 62.76 + // an entire gc pause, start to finish: 62.77 + initialize(_fullGC, true, true, true, true, true, true, true); 62.78 } 62.79 -TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC) { 62.80 +TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC, 62.81 + bool recordGCBeginTime, 62.82 + bool recordPreGCUsage, 62.83 + bool recordPeakUsage, 62.84 + bool recordPostGCUsage, 62.85 + bool recordAccumulatedGCTime, 62.86 + bool recordGCEndTime, 62.87 + bool countCollection) { 62.88 + initialize(fullGC, recordGCBeginTime, recordPreGCUsage, recordPeakUsage, 62.89 + recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, 62.90 + countCollection); 62.91 +} 62.92 + 62.93 +// for a subclass to create then initialize an instance before invoking 62.94 +// the MemoryService 62.95 +void TraceMemoryManagerStats::initialize(bool fullGC, 62.96 + bool recordGCBeginTime, 62.97 + bool recordPreGCUsage, 62.98 + bool recordPeakUsage, 62.99 + bool recordPostGCUsage, 62.100 + bool recordAccumulatedGCTime, 62.101 + bool recordGCEndTime, 62.102 + bool countCollection) { 62.103 _fullGC = fullGC; 62.104 - MemoryService::gc_begin(_fullGC); 62.105 + _recordGCBeginTime = recordGCBeginTime; 62.106 + _recordPreGCUsage = recordPreGCUsage; 62.107 + _recordPeakUsage = recordPeakUsage; 62.108 + _recordPostGCUsage = recordPostGCUsage; 62.109 + _recordAccumulatedGCTime = recordAccumulatedGCTime; 62.110 + _recordGCEndTime = recordGCEndTime; 62.111 + _countCollection = countCollection; 62.112 + 62.113 + MemoryService::gc_begin(_fullGC, _recordGCBeginTime, _recordAccumulatedGCTime, 62.114 + _recordPreGCUsage, _recordPeakUsage); 62.115 } 62.116 62.117 TraceMemoryManagerStats::~TraceMemoryManagerStats() { 62.118 - MemoryService::gc_end(_fullGC); 62.119 + MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime, 62.120 + _recordGCEndTime, _countCollection); 62.121 } 62.122 +
63.1 --- a/src/share/vm/services/memoryService.hpp Fri Aug 13 07:33:20 2010 -0700 63.2 +++ b/src/share/vm/services/memoryService.hpp Sat Aug 14 00:47:52 2010 -0700 63.3 @@ -149,8 +149,13 @@ 63.4 } 63.5 static void track_memory_pool_usage(MemoryPool* pool); 63.6 63.7 - static void gc_begin(bool fullGC); 63.8 - static void gc_end(bool fullGC); 63.9 + static void gc_begin(bool fullGC, bool recordGCBeginTime, 63.10 + bool recordAccumulatedGCTime, 63.11 + bool recordPreGCUsage, bool recordPeakUsage); 63.12 + static void gc_end(bool fullGC, bool recordPostGCUsage, 63.13 + bool recordAccumulatedGCTime, 63.14 + bool recordGCEndTime, bool countCollection); 63.15 + 63.16 63.17 static void oops_do(OopClosure* f); 63.18 63.19 @@ -164,8 +169,34 @@ 63.20 class TraceMemoryManagerStats : public StackObj { 63.21 private: 63.22 bool _fullGC; 63.23 + bool _recordGCBeginTime; 63.24 + bool _recordPreGCUsage; 63.25 + bool _recordPeakUsage; 63.26 + bool _recordPostGCUsage; 63.27 + bool _recordAccumulatedGCTime; 63.28 + bool _recordGCEndTime; 63.29 + bool _countCollection; 63.30 + 63.31 public: 63.32 - TraceMemoryManagerStats(bool fullGC); 63.33 + TraceMemoryManagerStats() {} 63.34 + TraceMemoryManagerStats(bool fullGC, 63.35 + bool recordGCBeginTime = true, 63.36 + bool recordPreGCUsage = true, 63.37 + bool recordPeakUsage = true, 63.38 + bool recordPostGCUsage = true, 63.39 + bool recordAccumulatedGCTime = true, 63.40 + bool recordGCEndTime = true, 63.41 + bool countCollection = true); 63.42 + 63.43 + void initialize(bool fullGC, 63.44 + bool recordGCBeginTime, 63.45 + bool recordPreGCUsage, 63.46 + bool recordPeakUsage, 63.47 + bool recordPostGCUsage, 63.48 + bool recordAccumulatedGCTime, 63.49 + bool recordGCEndTime, 63.50 + bool countCollection); 63.51 + 63.52 TraceMemoryManagerStats(Generation::Name kind); 63.53 ~TraceMemoryManagerStats(); 63.54 };
64.1 --- a/src/share/vm/utilities/taskqueue.cpp Fri Aug 13 07:33:20 2010 -0700 64.2 +++ b/src/share/vm/utilities/taskqueue.cpp Sat Aug 14 00:47:52 2010 -0700 64.3 @@ -36,6 +36,14 @@ 64.4 "qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax" 64.5 }; 64.6 64.7 +TaskQueueStats & TaskQueueStats::operator +=(const TaskQueueStats & addend) 64.8 +{ 64.9 + for (unsigned int i = 0; i < last_stat_id; ++i) { 64.10 + _stats[i] += addend._stats[i]; 64.11 + } 64.12 + return *this; 64.13 +} 64.14 + 64.15 void TaskQueueStats::print_header(unsigned int line, outputStream* const stream, 64.16 unsigned int width) 64.17 { 64.18 @@ -71,6 +79,29 @@ 64.19 } 64.20 #undef FMT 64.21 } 64.22 + 64.23 +#ifdef ASSERT 64.24 +// Invariants which should hold after a TaskQueue has been emptied and is 64.25 +// quiescent; they do not hold at arbitrary times. 64.26 +void TaskQueueStats::verify() const 64.27 +{ 64.28 + assert(get(push) == get(pop) + get(steal), 64.29 + err_msg("push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT, 64.30 + get(push), get(pop), get(steal))); 64.31 + assert(get(pop_slow) <= get(pop), 64.32 + err_msg("pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT, 64.33 + get(pop_slow), get(pop))); 64.34 + assert(get(steal) <= get(steal_attempt), 64.35 + err_msg("steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT, 64.36 + get(steal), get(steal_attempt))); 64.37 + assert(get(overflow) == 0 || get(push) != 0, 64.38 + err_msg("overflow=" SIZE_FORMAT " push=" SIZE_FORMAT, 64.39 + get(overflow), get(push))); 64.40 + assert(get(overflow_max_len) == 0 || get(overflow) != 0, 64.41 + err_msg("overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, 64.42 + get(overflow_max_len), get(overflow))); 64.43 +} 64.44 +#endif // ASSERT 64.45 #endif // TASKQUEUE_STATS 64.46 64.47 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
65.1 --- a/src/share/vm/utilities/taskqueue.hpp Fri Aug 13 07:33:20 2010 -0700 65.2 +++ b/src/share/vm/utilities/taskqueue.hpp Sat Aug 14 00:47:52 2010 -0700 65.3 @@ -59,15 +59,21 @@ 65.4 inline void record_steal(bool success); 65.5 inline void record_overflow(size_t new_length); 65.6 65.7 + TaskQueueStats & operator +=(const TaskQueueStats & addend); 65.8 + 65.9 inline size_t get(StatId id) const { return _stats[id]; } 65.10 inline const size_t* get() const { return _stats; } 65.11 65.12 inline void reset(); 65.13 65.14 + // Print the specified line of the header (does not include a line separator). 65.15 static void print_header(unsigned int line, outputStream* const stream = tty, 65.16 unsigned int width = 10); 65.17 + // Print the statistics (does not include a line separator). 65.18 void print(outputStream* const stream = tty, unsigned int width = 10) const; 65.19 65.20 + DEBUG_ONLY(void verify() const;) 65.21 + 65.22 private: 65.23 size_t _stats[last_stat_id]; 65.24 static const char * const _names[last_stat_id];
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 66.2 +++ b/test/gc/6581734/Test6581734.java Sat Aug 14 00:47:52 2010 -0700 66.3 @@ -0,0 +1,149 @@ 66.4 +/* 66.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 66.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 66.7 + * 66.8 + * This code is free software; you can redistribute it and/or modify it 66.9 + * under the terms of the GNU General Public License version 2 only, as 66.10 + * published by the Free Software Foundation. 66.11 + * 66.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 66.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 66.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 66.15 + * version 2 for more details (a copy is included in the LICENSE file that 66.16 + * accompanied this code). 66.17 + * 66.18 + * You should have received a copy of the GNU General Public License version 66.19 + * 2 along with this work; if not, write to the Free Software Foundation, 66.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 66.21 + * 66.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 66.23 + * or visit www.oracle.com if you need additional information or have any 66.24 + * questions. 66.25 + */ 66.26 + 66.27 +/* 66.28 + * @test Test6581734.java 66.29 + * @bug 6581734 66.30 + * @summary CMS Old Gen's collection usage is zero after GC which is incorrect 66.31 + * @run main/othervm -Xmx512m -verbose:gc -XX:+UseConcMarkSweepGC Test6581734 66.32 + * 66.33 + */ 66.34 +import java.util.*; 66.35 +import java.lang.management.*; 66.36 + 66.37 +// 6581734 states that memory pool usage via the mbean is wrong 66.38 +// for CMS (zero, even after a collection). 66.39 +// 66.40 +// 6580448 states that the collection count similarly is wrong 66.41 +// (stays at zero for CMS collections) 66.42 +// -- closed as dup of 6581734 as the same fix resolves both. 66.43 + 66.44 + 66.45 +public class Test6581734 { 66.46 + 66.47 + private String poolName = "CMS"; 66.48 + private String collectorName = "ConcurrentMarkSweep"; 66.49 + 66.50 + public static void main(String [] args) { 66.51 + 66.52 + Test6581734 t = null; 66.53 + if (args.length==2) { 66.54 + t = new Test6581734(args[0], args[1]); 66.55 + } else { 66.56 + System.out.println("Defaulting to monitor CMS pool and collector."); 66.57 + t = new Test6581734(); 66.58 + } 66.59 + t.run(); 66.60 + } 66.61 + 66.62 + public Test6581734(String pool, String collector) { 66.63 + poolName = pool; 66.64 + collectorName = collector; 66.65 + } 66.66 + 66.67 + public Test6581734() { 66.68 + } 66.69 + 66.70 + public void run() { 66.71 + // Use some memory, enough that we expect collections should 66.72 + // have happened. 66.73 + // Must run with options to ensure no stop the world full GC, 66.74 + // but e.g. at least one CMS cycle. 66.75 + allocationWork(300*1024*1024); 66.76 + System.out.println("Done allocationWork"); 66.77 + 66.78 + // Verify some non-zero results are stored. 66.79 + List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); 66.80 + int poolsFound = 0; 66.81 + int poolsWithStats = 0; 66.82 + for (int i=0; i<pools.size(); i++) { 66.83 + MemoryPoolMXBean pool = pools.get(i); 66.84 + String name = pool.getName(); 66.85 + System.out.println("found pool: " + name); 66.86 + 66.87 + if (name.contains(poolName)) { 66.88 + long usage = pool.getCollectionUsage().getUsed(); 66.89 + System.out.println(name + ": usage after GC = " + usage); 66.90 + poolsFound++; 66.91 + if (usage > 0) { 66.92 + poolsWithStats++; 66.93 + } 66.94 + } 66.95 + } 66.96 + if (poolsFound == 0) { 66.97 + throw new RuntimeException("No matching memory pools found: test with -XX:+UseConcMarkSweepGC"); 66.98 + } 66.99 + 66.100 + List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans(); 66.101 + int collectorsFound = 0; 66.102 + int collectorsWithTime= 0; 66.103 + for (int i=0; i<collectors.size(); i++) { 66.104 + GarbageCollectorMXBean collector = collectors.get(i); 66.105 + String name = collector.getName(); 66.106 + System.out.println("found collector: " + name); 66.107 + if (name.contains(collectorName)) { 66.108 + collectorsFound++; 66.109 + System.out.println(name + ": collection count = " 66.110 + + collector.getCollectionCount()); 66.111 + System.out.println(name + ": collection time = " 66.112 + + collector.getCollectionTime()); 66.113 + if (collector.getCollectionCount() <= 0) { 66.114 + throw new RuntimeException("collection count <= 0"); 66.115 + } 66.116 + if (collector.getCollectionTime() > 0) { 66.117 + collectorsWithTime++; 66.118 + } 66.119 + } 66.120 + } 66.121 + // verify: 66.122 + if (poolsWithStats < poolsFound) { 66.123 + throw new RuntimeException("pools found with zero stats"); 66.124 + } 66.125 + 66.126 + if (collectorsWithTime<collectorsFound) { 66.127 + throw new RuntimeException("collectors found with zero time"; 66.128 + } 66.129 + System.out.println("Test passed."); 66.130 + } 66.131 + 66.132 + public void allocationWork(long target) { 66.133 + 66.134 + long sizeAllocated = 0; 66.135 + List list = new LinkedList(); 66.136 + long delay = 50; 66.137 + long count = 0; 66.138 + 66.139 + while (sizeAllocated < target) { 66.140 + int size = 1024*1024; 66.141 + byte [] alloc = new byte[size]; 66.142 + if (count % 2 == 0) { 66.143 + list.add(alloc); 66.144 + sizeAllocated+=size; 66.145 + System.out.print("."); 66.146 + } 66.147 + try { Thread.sleep(delay); } catch (InterruptedException ie) { } 66.148 + count++; 66.149 + } 66.150 + } 66.151 + 66.152 +}