Mon, 24 Mar 2014 14:23:02 -0700
Merge
src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/make/excludeSrc.make Fri Feb 28 15:27:09 2014 +0100 1.2 +++ b/make/excludeSrc.make Mon Mar 24 14:23:02 2014 -0700 1.3 @@ -87,7 +87,8 @@ 1.4 g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \ 1.5 g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \ 1.6 g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \ 1.7 - g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ 1.8 + g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1StringDedup.cpp g1StringDedupStat.cpp \ 1.9 + g1StringDedupTable.cpp g1StringDedupThread.cpp g1StringDedupQueue.cpp g1_globals.cpp heapRegion.cpp \ 1.10 g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ 1.11 ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \ 1.12 adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \
2.1 --- a/src/share/vm/classfile/javaClasses.hpp Fri Feb 28 15:27:09 2014 +0100 2.2 +++ b/src/share/vm/classfile/javaClasses.hpp Mon Mar 24 14:23:02 2014 -0700 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 1997, 2014, 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 @@ -61,10 +61,6 @@ 2.11 2.12 static Handle basic_create(int length, TRAPS); 2.13 2.14 - static void set_value( oop string, typeArrayOop buffer) { 2.15 - assert(initialized, "Must be initialized"); 2.16 - string->obj_field_put(value_offset, (oop)buffer); 2.17 - } 2.18 static void set_offset(oop string, int offset) { 2.19 assert(initialized, "Must be initialized"); 2.20 if (offset_offset > 0) { 2.21 @@ -122,12 +118,26 @@ 2.22 return hash_offset; 2.23 } 2.24 2.25 + static void set_value(oop string, typeArrayOop buffer) { 2.26 + assert(initialized && (value_offset > 0), "Must be initialized"); 2.27 + string->obj_field_put(value_offset, (oop)buffer); 2.28 + } 2.29 + static void set_hash(oop string, unsigned int hash) { 2.30 + assert(initialized && (hash_offset > 0), "Must be initialized"); 2.31 + string->int_field_put(hash_offset, hash); 2.32 + } 2.33 + 2.34 // Accessors 2.35 static typeArrayOop value(oop java_string) { 2.36 assert(initialized && (value_offset > 0), "Must be initialized"); 2.37 assert(is_instance(java_string), "must be java_string"); 2.38 return (typeArrayOop) java_string->obj_field(value_offset); 2.39 } 2.40 + static unsigned int hash(oop java_string) { 2.41 + assert(initialized && (hash_offset > 0), "Must be initialized"); 2.42 + assert(is_instance(java_string), "must be java_string"); 2.43 + return java_string->int_field(hash_offset); 2.44 + } 2.45 static int offset(oop java_string) { 2.46 assert(initialized, "Must be initialized"); 2.47 assert(is_instance(java_string), "must be java_string");
3.1 --- a/src/share/vm/classfile/symbolTable.cpp Fri Feb 28 15:27:09 2014 +0100 3.2 +++ b/src/share/vm/classfile/symbolTable.cpp Mon Mar 24 14:23:02 2014 -0700 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 1997, 2014, 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 @@ -35,6 +35,9 @@ 3.11 #include "oops/oop.inline2.hpp" 3.12 #include "runtime/mutexLocker.hpp" 3.13 #include "utilities/hashtable.inline.hpp" 3.14 +#if INCLUDE_ALL_GCS 3.15 +#include "gc_implementation/g1/g1StringDedup.hpp" 3.16 +#endif 3.17 3.18 // -------------------------------------------------------------------------- 3.19 3.20 @@ -728,6 +731,15 @@ 3.21 string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); 3.22 } 3.23 3.24 +#if INCLUDE_ALL_GCS 3.25 + if (G1StringDedup::is_enabled()) { 3.26 + // Deduplicate the string before it is interned. Note that we should never 3.27 + // deduplicate a string after it has been interned. Doing so will counteract 3.28 + // compiler optimizations done on e.g. interned string literals. 3.29 + G1StringDedup::deduplicate(string()); 3.30 + } 3.31 +#endif 3.32 + 3.33 // Grab the StringTable_lock before getting the_table() because it could 3.34 // change at safepoint. 3.35 MutexLocker ml(StringTable_lock, THREAD);
4.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Feb 28 15:27:09 2014 +0100 4.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Mar 24 14:23:02 2014 -0700 4.3 @@ -39,6 +39,7 @@ 4.4 #include "gc_implementation/g1/g1MarkSweep.hpp" 4.5 #include "gc_implementation/g1/g1OopClosures.inline.hpp" 4.6 #include "gc_implementation/g1/g1RemSet.inline.hpp" 4.7 +#include "gc_implementation/g1/g1StringDedup.hpp" 4.8 #include "gc_implementation/g1/g1YCTypes.hpp" 4.9 #include "gc_implementation/g1/heapRegion.inline.hpp" 4.10 #include "gc_implementation/g1/heapRegionRemSet.hpp" 4.11 @@ -2172,6 +2173,8 @@ 4.12 // values in the heap have been properly initialized. 4.13 _g1mm = new G1MonitoringSupport(this); 4.14 4.15 + G1StringDedup::initialize(); 4.16 + 4.17 return JNI_OK; 4.18 } 4.19 4.20 @@ -3474,6 +3477,11 @@ 4.21 if (!silent) gclog_or_tty->print("RemSet "); 4.22 rem_set()->verify(); 4.23 4.24 + if (G1StringDedup::is_enabled()) { 4.25 + if (!silent) gclog_or_tty->print("StrDedup "); 4.26 + G1StringDedup::verify(); 4.27 + } 4.28 + 4.29 if (failures) { 4.30 gclog_or_tty->print_cr("Heap:"); 4.31 // It helps to have the per-region information in the output to 4.32 @@ -3491,8 +3499,13 @@ 4.33 } 4.34 guarantee(!failures, "there should not have been any failures"); 4.35 } else { 4.36 - if (!silent) 4.37 - gclog_or_tty->print("(SKIPPING roots, heapRegionSets, heapRegions, remset) "); 4.38 + if (!silent) { 4.39 + gclog_or_tty->print("(SKIPPING Roots, HeapRegionSets, HeapRegions, RemSet"); 4.40 + if (G1StringDedup::is_enabled()) { 4.41 + gclog_or_tty->print(", StrDedup"); 4.42 + } 4.43 + gclog_or_tty->print(") "); 4.44 + } 4.45 } 4.46 } 4.47 4.48 @@ -3585,6 +3598,9 @@ 4.49 st->cr(); 4.50 _cm->print_worker_threads_on(st); 4.51 _cg1r->print_worker_threads_on(st); 4.52 + if (G1StringDedup::is_enabled()) { 4.53 + G1StringDedup::print_worker_threads_on(st); 4.54 + } 4.55 } 4.56 4.57 void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { 4.58 @@ -3593,6 +3609,9 @@ 4.59 } 4.60 tc->do_thread(_cmThread); 4.61 _cg1r->threads_do(tc); 4.62 + if (G1StringDedup::is_enabled()) { 4.63 + G1StringDedup::threads_do(tc); 4.64 + } 4.65 } 4.66 4.67 void G1CollectedHeap::print_tracing_info() const { 4.68 @@ -4773,6 +4792,13 @@ 4.69 obj->set_mark(m); 4.70 } 4.71 4.72 + if (G1StringDedup::is_enabled()) { 4.73 + G1StringDedup::enqueue_from_evacuation(from_region->is_young(), 4.74 + to_region->is_young(), 4.75 + queue_num(), 4.76 + obj); 4.77 + } 4.78 + 4.79 size_t* surv_young_words = surviving_young_words(); 4.80 surv_young_words[young_index] += word_sz; 4.81 4.82 @@ -5248,6 +5274,10 @@ 4.83 g1_unlink_task.strings_processed(), g1_unlink_task.strings_removed(), 4.84 g1_unlink_task.symbols_processed(), g1_unlink_task.symbols_removed()); 4.85 } 4.86 + 4.87 + if (G1StringDedup::is_enabled()) { 4.88 + G1StringDedup::unlink(is_alive); 4.89 + } 4.90 } 4.91 4.92 class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { 4.93 @@ -5871,6 +5901,9 @@ 4.94 G1STWIsAliveClosure is_alive(this); 4.95 G1KeepAliveClosure keep_alive(this); 4.96 JNIHandles::weak_oops_do(&is_alive, &keep_alive); 4.97 + if (G1StringDedup::is_enabled()) { 4.98 + G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive); 4.99 + } 4.100 } 4.101 4.102 release_gc_alloc_regions(n_workers, evacuation_info); 4.103 @@ -6351,9 +6384,10 @@ 4.104 TearDownRegionSetsClosure cl(&_old_set); 4.105 heap_region_iterate(&cl); 4.106 4.107 - // Need to do this after the heap iteration to be able to 4.108 - // recognize the young regions and ignore them during the iteration. 4.109 - _young_list->empty_list(); 4.110 + // Note that emptying the _young_list is postponed and instead done as 4.111 + // the first step when rebuilding the regions sets again. The reason for 4.112 + // this is that during a full GC string deduplication needs to know if 4.113 + // a collected region was young or old when the full GC was initiated. 4.114 } 4.115 _free_list.remove_all(); 4.116 } 4.117 @@ -6407,6 +6441,10 @@ 4.118 void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { 4.119 assert_at_safepoint(true /* should_be_vm_thread */); 4.120 4.121 + if (!free_list_only) { 4.122 + _young_list->empty_list(); 4.123 + } 4.124 + 4.125 RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list); 4.126 heap_region_iterate(&cl); 4.127
5.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Fri Feb 28 15:27:09 2014 +0100 5.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Mon Mar 24 14:23:02 2014 -0700 5.3 @@ -27,6 +27,7 @@ 5.4 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 5.5 #include "gc_implementation/g1/g1GCPhaseTimes.hpp" 5.6 #include "gc_implementation/g1/g1Log.hpp" 5.7 +#include "gc_implementation/g1/g1StringDedup.hpp" 5.8 5.9 // Helper class for avoiding interleaved logging 5.10 class LineBuffer: public StackObj { 5.11 @@ -168,7 +169,9 @@ 5.12 _last_termination_attempts(_max_gc_threads, SIZE_FORMAT), 5.13 _last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false), 5.14 _last_gc_worker_times_ms(_max_gc_threads, "%.1lf"), 5.15 - _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf") 5.16 + _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"), 5.17 + _cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"), 5.18 + _cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf") 5.19 { 5.20 assert(max_gc_threads > 0, "Must have some GC threads"); 5.21 } 5.22 @@ -229,6 +232,16 @@ 5.23 _last_gc_worker_other_times_ms.verify(); 5.24 } 5.25 5.26 +void G1GCPhaseTimes::note_string_dedup_fixup_start() { 5.27 + _cur_string_dedup_queue_fixup_worker_times_ms.reset(); 5.28 + _cur_string_dedup_table_fixup_worker_times_ms.reset(); 5.29 +} 5.30 + 5.31 +void G1GCPhaseTimes::note_string_dedup_fixup_end() { 5.32 + _cur_string_dedup_queue_fixup_worker_times_ms.verify(); 5.33 + _cur_string_dedup_table_fixup_worker_times_ms.verify(); 5.34 +} 5.35 + 5.36 void G1GCPhaseTimes::print_stats(int level, const char* str, double value) { 5.37 LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value); 5.38 } 5.39 @@ -253,6 +266,11 @@ 5.40 // Strong code root purge time 5.41 misc_time_ms += _cur_strong_code_root_purge_time_ms; 5.42 5.43 + if (G1StringDedup::is_enabled()) { 5.44 + // String dedup fixup time 5.45 + misc_time_ms += _cur_string_dedup_fixup_time_ms; 5.46 + } 5.47 + 5.48 // Subtract the time taken to clean the card table from the 5.49 // current value of "other time" 5.50 misc_time_ms += _cur_clear_ct_time_ms; 5.51 @@ -303,6 +321,11 @@ 5.52 print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); 5.53 print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); 5.54 print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); 5.55 + if (G1StringDedup::is_enabled()) { 5.56 + print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); 5.57 + _cur_string_dedup_queue_fixup_worker_times_ms.print(2, "Queue Fixup (ms)"); 5.58 + _cur_string_dedup_table_fixup_worker_times_ms.print(2, "Table Fixup (ms)"); 5.59 + } 5.60 print_stats(1, "Clear CT", _cur_clear_ct_time_ms); 5.61 double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); 5.62 print_stats(1, "Other", misc_time_ms);
6.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Feb 28 15:27:09 2014 +0100 6.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Mon Mar 24 14:23:02 2014 -0700 6.3 @@ -137,6 +137,10 @@ 6.4 double _cur_evac_fail_restore_remsets; 6.5 double _cur_evac_fail_remove_self_forwards; 6.6 6.7 + double _cur_string_dedup_fixup_time_ms; 6.8 + WorkerDataArray<double> _cur_string_dedup_queue_fixup_worker_times_ms; 6.9 + WorkerDataArray<double> _cur_string_dedup_table_fixup_worker_times_ms; 6.10 + 6.11 double _cur_clear_ct_time_ms; 6.12 double _cur_ref_proc_time_ms; 6.13 double _cur_ref_enq_time_ms; 6.14 @@ -246,6 +250,21 @@ 6.15 _cur_evac_fail_remove_self_forwards = ms; 6.16 } 6.17 6.18 + void note_string_dedup_fixup_start(); 6.19 + void note_string_dedup_fixup_end(); 6.20 + 6.21 + void record_string_dedup_fixup_time(double ms) { 6.22 + _cur_string_dedup_fixup_time_ms = ms; 6.23 + } 6.24 + 6.25 + void record_string_dedup_queue_fixup_worker_time(uint worker_id, double ms) { 6.26 + _cur_string_dedup_queue_fixup_worker_times_ms.set(worker_id, ms); 6.27 + } 6.28 + 6.29 + void record_string_dedup_table_fixup_worker_time(uint worker_id, double ms) { 6.30 + _cur_string_dedup_table_fixup_worker_times_ms.set(worker_id, ms); 6.31 + } 6.32 + 6.33 void record_ref_proc_time(double ms) { 6.34 _cur_ref_proc_time_ms = ms; 6.35 }
7.1 --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Feb 28 15:27:09 2014 +0100 7.2 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Mar 24 14:23:02 2014 -0700 7.3 @@ -1,5 +1,5 @@ 7.4 /* 7.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. 7.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. 7.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.8 * 7.9 * This code is free software; you can redistribute it and/or modify it 7.10 @@ -31,6 +31,7 @@ 7.11 #include "code/icBuffer.hpp" 7.12 #include "gc_implementation/g1/g1Log.hpp" 7.13 #include "gc_implementation/g1/g1MarkSweep.hpp" 7.14 +#include "gc_implementation/g1/g1StringDedup.hpp" 7.15 #include "gc_implementation/shared/gcHeapSummary.hpp" 7.16 #include "gc_implementation/shared/gcTimer.hpp" 7.17 #include "gc_implementation/shared/gcTrace.hpp" 7.18 @@ -320,6 +321,10 @@ 7.19 // have been cleared if they pointed to non-surviving objects.) 7.20 g1h->g1_process_weak_roots(&GenMarkSweep::adjust_pointer_closure); 7.21 7.22 + if (G1StringDedup::is_enabled()) { 7.23 + G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); 7.24 + } 7.25 + 7.26 GenMarkSweep::adjust_marks(); 7.27 7.28 G1AdjustPointersClosure blk;
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Mon Mar 24 14:23:02 2014 -0700 8.3 @@ -0,0 +1,208 @@ 8.4 +/* 8.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. 8.11 + * 8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.15 + * version 2 for more details (a copy is included in the LICENSE file that 8.16 + * accompanied this code). 8.17 + * 8.18 + * You should have received a copy of the GNU General Public License version 8.19 + * 2 along with this work; if not, write to the Free Software Foundation, 8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.21 + * 8.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.23 + * or visit www.oracle.com if you need additional information or have any 8.24 + * questions. 8.25 + * 8.26 + */ 8.27 + 8.28 +#include "precompiled.hpp" 8.29 +#include "classfile/javaClasses.hpp" 8.30 +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 8.31 +#include "gc_implementation/g1/g1GCPhaseTimes.hpp" 8.32 +#include "gc_implementation/g1/g1StringDedup.hpp" 8.33 +#include "gc_implementation/g1/g1StringDedupQueue.hpp" 8.34 +#include "gc_implementation/g1/g1StringDedupStat.hpp" 8.35 +#include "gc_implementation/g1/g1StringDedupTable.hpp" 8.36 +#include "gc_implementation/g1/g1StringDedupThread.hpp" 8.37 + 8.38 +bool G1StringDedup::_enabled = false; 8.39 + 8.40 +void G1StringDedup::initialize() { 8.41 + assert(UseG1GC, "String deduplication only available with G1"); 8.42 + if (UseStringDeduplication) { 8.43 + _enabled = true; 8.44 + G1StringDedupQueue::create(); 8.45 + G1StringDedupTable::create(); 8.46 + G1StringDedupThread::create(); 8.47 + } 8.48 +} 8.49 + 8.50 +bool G1StringDedup::is_candidate_from_mark(oop obj) { 8.51 + if (java_lang_String::is_instance(obj)) { 8.52 + bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young(); 8.53 + if (from_young && obj->age() < StringDeduplicationAgeThreshold) { 8.54 + // Candidate found. String is being evacuated from young to old but has not 8.55 + // reached the deduplication age threshold, i.e. has not previously been a 8.56 + // candidate during its life in the young generation. 8.57 + return true; 8.58 + } 8.59 + } 8.60 + 8.61 + // Not a candidate 8.62 + return false; 8.63 +} 8.64 + 8.65 +void G1StringDedup::enqueue_from_mark(oop java_string) { 8.66 + assert(is_enabled(), "String deduplication not enabled"); 8.67 + if (is_candidate_from_mark(java_string)) { 8.68 + G1StringDedupQueue::push(0 /* worker_id */, java_string); 8.69 + } 8.70 +} 8.71 + 8.72 +bool G1StringDedup::is_candidate_from_evacuation(bool from_young, bool to_young, oop obj) { 8.73 + if (from_young && java_lang_String::is_instance(obj)) { 8.74 + if (to_young && obj->age() == StringDeduplicationAgeThreshold) { 8.75 + // Candidate found. String is being evacuated from young to young and just 8.76 + // reached the deduplication age threshold. 8.77 + return true; 8.78 + } 8.79 + if (!to_young && obj->age() < StringDeduplicationAgeThreshold) { 8.80 + // Candidate found. String is being evacuated from young to old but has not 8.81 + // reached the deduplication age threshold, i.e. has not previously been a 8.82 + // candidate during its life in the young generation. 8.83 + return true; 8.84 + } 8.85 + } 8.86 + 8.87 + // Not a candidate 8.88 + return false; 8.89 +} 8.90 + 8.91 +void G1StringDedup::enqueue_from_evacuation(bool from_young, bool to_young, uint worker_id, oop java_string) { 8.92 + assert(is_enabled(), "String deduplication not enabled"); 8.93 + if (is_candidate_from_evacuation(from_young, to_young, java_string)) { 8.94 + G1StringDedupQueue::push(worker_id, java_string); 8.95 + } 8.96 +} 8.97 + 8.98 +void G1StringDedup::deduplicate(oop java_string) { 8.99 + assert(is_enabled(), "String deduplication not enabled"); 8.100 + G1StringDedupStat dummy; // Statistics from this path is never used 8.101 + G1StringDedupTable::deduplicate(java_string, dummy); 8.102 +} 8.103 + 8.104 +void G1StringDedup::oops_do(OopClosure* keep_alive) { 8.105 + assert(is_enabled(), "String deduplication not enabled"); 8.106 + unlink_or_oops_do(NULL, keep_alive); 8.107 +} 8.108 + 8.109 +void G1StringDedup::unlink(BoolObjectClosure* is_alive) { 8.110 + assert(is_enabled(), "String deduplication not enabled"); 8.111 + // Don't allow a potential resize or rehash during unlink, as the unlink 8.112 + // operation itself might remove enough entries to invalidate such a decision. 8.113 + unlink_or_oops_do(is_alive, NULL, false /* allow_resize_and_rehash */); 8.114 +} 8.115 + 8.116 +// 8.117 +// Task for parallel unlink_or_oops_do() operation on the deduplication queue 8.118 +// and table. 8.119 +// 8.120 +class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask { 8.121 +private: 8.122 + G1StringDedupUnlinkOrOopsDoClosure _cl; 8.123 + 8.124 +public: 8.125 + G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive, 8.126 + OopClosure* keep_alive, 8.127 + bool allow_resize_and_rehash) : 8.128 + AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"), 8.129 + _cl(is_alive, keep_alive, allow_resize_and_rehash) { 8.130 + } 8.131 + 8.132 + virtual void work(uint worker_id) { 8.133 + double queue_fixup_start = os::elapsedTime(); 8.134 + G1StringDedupQueue::unlink_or_oops_do(&_cl); 8.135 + 8.136 + double table_fixup_start = os::elapsedTime(); 8.137 + G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id); 8.138 + 8.139 + double queue_fixup_time_ms = (table_fixup_start - queue_fixup_start) * 1000.0; 8.140 + double table_fixup_time_ms = (os::elapsedTime() - table_fixup_start) * 1000.0; 8.141 + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); 8.142 + g1p->phase_times()->record_string_dedup_queue_fixup_worker_time(worker_id, queue_fixup_time_ms); 8.143 + g1p->phase_times()->record_string_dedup_table_fixup_worker_time(worker_id, table_fixup_time_ms); 8.144 + } 8.145 +}; 8.146 + 8.147 +void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool allow_resize_and_rehash) { 8.148 + assert(is_enabled(), "String deduplication not enabled"); 8.149 + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); 8.150 + g1p->phase_times()->note_string_dedup_fixup_start(); 8.151 + double fixup_start = os::elapsedTime(); 8.152 + 8.153 + G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash); 8.154 + if (G1CollectedHeap::use_parallel_gc_threads()) { 8.155 + G1CollectedHeap* g1h = G1CollectedHeap::heap(); 8.156 + g1h->set_par_threads(); 8.157 + g1h->workers()->run_task(&task); 8.158 + g1h->set_par_threads(0); 8.159 + } else { 8.160 + task.work(0); 8.161 + } 8.162 + 8.163 + double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; 8.164 + g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms); 8.165 + g1p->phase_times()->note_string_dedup_fixup_end(); 8.166 +} 8.167 + 8.168 +void G1StringDedup::threads_do(ThreadClosure* tc) { 8.169 + assert(is_enabled(), "String deduplication not enabled"); 8.170 + tc->do_thread(G1StringDedupThread::thread()); 8.171 +} 8.172 + 8.173 +void G1StringDedup::print_worker_threads_on(outputStream* st) { 8.174 + assert(is_enabled(), "String deduplication not enabled"); 8.175 + G1StringDedupThread::thread()->print_on(st); 8.176 + st->cr(); 8.177 +} 8.178 + 8.179 +void G1StringDedup::verify() { 8.180 + assert(is_enabled(), "String deduplication not enabled"); 8.181 + G1StringDedupQueue::verify(); 8.182 + G1StringDedupTable::verify(); 8.183 +} 8.184 + 8.185 +G1StringDedupUnlinkOrOopsDoClosure::G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, 8.186 + OopClosure* keep_alive, 8.187 + bool allow_resize_and_rehash) : 8.188 + _is_alive(is_alive), 8.189 + _keep_alive(keep_alive), 8.190 + _resized_table(NULL), 8.191 + _rehashed_table(NULL), 8.192 + _next_queue(0), 8.193 + _next_bucket(0) { 8.194 + if (allow_resize_and_rehash) { 8.195 + // If both resize and rehash is needed, only do resize. Rehash of 8.196 + // the table will eventually happen if the situation persists. 8.197 + _resized_table = G1StringDedupTable::prepare_resize(); 8.198 + if (!is_resizing()) { 8.199 + _rehashed_table = G1StringDedupTable::prepare_rehash(); 8.200 + } 8.201 + } 8.202 +} 8.203 + 8.204 +G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() { 8.205 + assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash"); 8.206 + if (is_resizing()) { 8.207 + G1StringDedupTable::finish_resize(_resized_table); 8.208 + } else if (is_rehashing()) { 8.209 + G1StringDedupTable::finish_rehash(_rehashed_table); 8.210 + } 8.211 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.hpp Mon Mar 24 14:23:02 2014 -0700 9.3 @@ -0,0 +1,202 @@ 9.4 +/* 9.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 + * 9.8 + * This code is free software; you can redistribute it and/or modify it 9.9 + * under the terms of the GNU General Public License version 2 only, as 9.10 + * published by the Free Software Foundation. 9.11 + * 9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.15 + * version 2 for more details (a copy is included in the LICENSE file that 9.16 + * accompanied this code). 9.17 + * 9.18 + * You should have received a copy of the GNU General Public License version 9.19 + * 2 along with this work; if not, write to the Free Software Foundation, 9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.21 + * 9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.23 + * or visit www.oracle.com if you need additional information or have any 9.24 + * questions. 9.25 + * 9.26 + */ 9.27 + 9.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP 9.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP 9.30 + 9.31 +// 9.32 +// String Deduplication 9.33 +// 9.34 +// String deduplication aims to reduce the heap live-set by deduplicating identical 9.35 +// instances of String so that they share the same backing character array. 9.36 +// 9.37 +// The deduplication process is divided in two main parts, 1) finding the objects to 9.38 +// deduplicate, and 2) deduplicating those objects. The first part is done as part of 9.39 +// a normal GC cycle when objects are marked or evacuated. At this time a check is 9.40 +// applied on each object to check if it is a candidate for deduplication. If so, the 9.41 +// object is placed on the deduplication queue for later processing. The second part, 9.42 +// processing the objects on the deduplication queue, is a concurrent phase which 9.43 +// starts right after the stop-the-wold marking/evacuation phase. This phase is 9.44 +// executed by the deduplication thread, which pulls deduplication candidates of the 9.45 +// deduplication queue and tries to deduplicate them. 9.46 +// 9.47 +// A deduplication hashtable is used to keep track of all unique character arrays 9.48 +// used by String objects. When deduplicating, a lookup is made in this table to see 9.49 +// if there is already an identical character array somewhere on the heap. If so, the 9.50 +// String object is adjusted to point to that character array, releasing the reference 9.51 +// to the original array allowing it to eventually be garbage collected. If the lookup 9.52 +// fails the character array is instead inserted into the hashtable so that this array 9.53 +// can be shared at some point in the future. 9.54 +// 9.55 +// Candidate selection 9.56 +// 9.57 +// An object is considered a deduplication candidate if all of the following 9.58 +// statements are true: 9.59 +// 9.60 +// - The object is an instance of java.lang.String 9.61 +// 9.62 +// - The object is being evacuated from a young heap region 9.63 +// 9.64 +// - The object is being evacuated to a young/survivor heap region and the 9.65 +// object's age is equal to the deduplication age threshold 9.66 +// 9.67 +// or 9.68 +// 9.69 +// The object is being evacuated to an old heap region and the object's age is 9.70 +// less than the deduplication age threshold 9.71 +// 9.72 +// Once an string object has been promoted to an old region, or its age is higher 9.73 +// than the deduplication age threshold, is will never become a candidate again. 9.74 +// This approach avoids making the same object a candidate more than once. 9.75 +// 9.76 +// Interned strings are a bit special. They are explicitly deduplicated just before 9.77 +// being inserted into the StringTable (to avoid counteracting C2 optimizations done 9.78 +// on string literals), then they also become deduplication candidates if they reach 9.79 +// the deduplication age threshold or are evacuated to an old heap region. The second 9.80 +// attempt to deduplicate such strings will be in vain, but we have no fast way of 9.81 +// filtering them out. This has not shown to be a problem, as the number of interned 9.82 +// strings is usually dwarfed by the number of normal (non-interned) strings. 9.83 +// 9.84 +// For additional information on string deduplication, please see JEP 192, 9.85 +// http://openjdk.java.net/jeps/192 9.86 +// 9.87 + 9.88 +#include "memory/allocation.hpp" 9.89 +#include "oops/oop.hpp" 9.90 + 9.91 +class OopClosure; 9.92 +class BoolObjectClosure; 9.93 +class ThreadClosure; 9.94 +class outputStream; 9.95 +class G1StringDedupTable; 9.96 + 9.97 +// 9.98 +// Main interface for interacting with string deduplication. 9.99 +// 9.100 +class G1StringDedup : public AllStatic { 9.101 +private: 9.102 + // Single state for checking if both G1 and string deduplication is enabled. 9.103 + static bool _enabled; 9.104 + 9.105 + // Candidate selection policies, returns true if the given object is 9.106 + // candidate for string deduplication. 9.107 + static bool is_candidate_from_mark(oop obj); 9.108 + static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj); 9.109 + 9.110 +public: 9.111 + // Returns true if both G1 and string deduplication is enabled. 9.112 + static bool is_enabled() { 9.113 + return _enabled; 9.114 + } 9.115 + 9.116 + static void initialize(); 9.117 + 9.118 + // Immediately deduplicates the given String object, bypassing the 9.119 + // the deduplication queue. 9.120 + static void deduplicate(oop java_string); 9.121 + 9.122 + // Enqueues a deduplication candidate for later processing by the deduplication 9.123 + // thread. Before enqueuing, these functions apply the appropriate candidate 9.124 + // selection policy to filters out non-candidates. 9.125 + static void enqueue_from_mark(oop java_string); 9.126 + static void enqueue_from_evacuation(bool from_young, bool to_young, 9.127 + unsigned int queue, oop java_string); 9.128 + 9.129 + static void oops_do(OopClosure* keep_alive); 9.130 + static void unlink(BoolObjectClosure* is_alive); 9.131 + static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, 9.132 + bool allow_resize_and_rehash = true); 9.133 + 9.134 + static void threads_do(ThreadClosure* tc); 9.135 + static void print_worker_threads_on(outputStream* st); 9.136 + static void verify(); 9.137 +}; 9.138 + 9.139 +// 9.140 +// This closure encapsulates the state and the closures needed when scanning 9.141 +// the deduplication queue and table during the unlink_or_oops_do() operation. 9.142 +// A single instance of this closure is created and then shared by all worker 9.143 +// threads participating in the scan. The _next_queue and _next_bucket fields 9.144 +// provide a simple mechanism for GC workers to claim exclusive access to a 9.145 +// queue or a table partition. 9.146 +// 9.147 +class G1StringDedupUnlinkOrOopsDoClosure : public StackObj { 9.148 +private: 9.149 + BoolObjectClosure* _is_alive; 9.150 + OopClosure* _keep_alive; 9.151 + G1StringDedupTable* _resized_table; 9.152 + G1StringDedupTable* _rehashed_table; 9.153 + size_t _next_queue; 9.154 + size_t _next_bucket; 9.155 + 9.156 +public: 9.157 + G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, 9.158 + OopClosure* keep_alive, 9.159 + bool allow_resize_and_rehash); 9.160 + ~G1StringDedupUnlinkOrOopsDoClosure(); 9.161 + 9.162 + bool is_resizing() { 9.163 + return _resized_table != NULL; 9.164 + } 9.165 + 9.166 + G1StringDedupTable* resized_table() { 9.167 + return _resized_table; 9.168 + } 9.169 + 9.170 + bool is_rehashing() { 9.171 + return _rehashed_table != NULL; 9.172 + } 9.173 + 9.174 + // Atomically claims the next available queue for exclusive access by 9.175 + // the current thread. Returns the queue number of the claimed queue. 9.176 + size_t claim_queue() { 9.177 + return (size_t)Atomic::add_ptr(1, &_next_queue) - 1; 9.178 + } 9.179 + 9.180 + // Atomically claims the next available table partition for exclusive 9.181 + // access by the current thread. Returns the table bucket number where 9.182 + // the claimed partition starts. 9.183 + size_t claim_table_partition(size_t partition_size) { 9.184 + return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size; 9.185 + } 9.186 + 9.187 + // Applies and returns the result from the is_alive closure, or 9.188 + // returns true if no such closure was provided. 9.189 + bool is_alive(oop o) { 9.190 + if (_is_alive != NULL) { 9.191 + return _is_alive->do_object_b(o); 9.192 + } 9.193 + return true; 9.194 + } 9.195 + 9.196 + // Applies the keep_alive closure, or does nothing if no such 9.197 + // closure was provided. 9.198 + void keep_alive(oop* p) { 9.199 + if (_keep_alive != NULL) { 9.200 + _keep_alive->do_oop(p); 9.201 + } 9.202 + } 9.203 +}; 9.204 + 9.205 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Mon Mar 24 14:23:02 2014 -0700 10.3 @@ -0,0 +1,162 @@ 10.4 +/* 10.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.7 + * 10.8 + * This code is free software; you can redistribute it and/or modify it 10.9 + * under the terms of the GNU General Public License version 2 only, as 10.10 + * published by the Free Software Foundation. 10.11 + * 10.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 10.15 + * version 2 for more details (a copy is included in the LICENSE file that 10.16 + * accompanied this code). 10.17 + * 10.18 + * You should have received a copy of the GNU General Public License version 10.19 + * 2 along with this work; if not, write to the Free Software Foundation, 10.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 10.21 + * 10.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 10.23 + * or visit www.oracle.com if you need additional information or have any 10.24 + * questions. 10.25 + * 10.26 + */ 10.27 + 10.28 +#include "precompiled.hpp" 10.29 +#include "classfile/javaClasses.hpp" 10.30 +#include "gc_implementation/g1/g1StringDedupQueue.hpp" 10.31 +#include "memory/gcLocker.hpp" 10.32 +#include "runtime/mutexLocker.hpp" 10.33 +#include "utilities/stack.inline.hpp" 10.34 + 10.35 +G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; 10.36 +const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue 10.37 +const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue 10.38 + 10.39 +G1StringDedupQueue::G1StringDedupQueue() : 10.40 + _cursor(0), 10.41 + _empty(true), 10.42 + _dropped(0) { 10.43 + _nqueues = MAX2(ParallelGCThreads, (size_t)1); 10.44 + _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); 10.45 + for (size_t i = 0; i < _nqueues; i++) { 10.46 + new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); 10.47 + } 10.48 +} 10.49 + 10.50 +G1StringDedupQueue::~G1StringDedupQueue() { 10.51 + ShouldNotReachHere(); 10.52 +} 10.53 + 10.54 +void G1StringDedupQueue::create() { 10.55 + assert(_queue == NULL, "One string deduplication queue allowed"); 10.56 + _queue = new G1StringDedupQueue(); 10.57 +} 10.58 + 10.59 +void G1StringDedupQueue::wait() { 10.60 + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); 10.61 + while (_queue->_empty) { 10.62 + ml.wait(Mutex::_no_safepoint_check_flag); 10.63 + } 10.64 +} 10.65 + 10.66 +void G1StringDedupQueue::push(uint worker_id, oop java_string) { 10.67 + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); 10.68 + assert(worker_id < _queue->_nqueues, "Invalid queue"); 10.69 + 10.70 + // Push and notify waiter 10.71 + G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; 10.72 + if (!worker_queue.is_full()) { 10.73 + worker_queue.push(java_string); 10.74 + if (_queue->_empty) { 10.75 + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); 10.76 + if (_queue->_empty) { 10.77 + // Mark non-empty and notify waiter 10.78 + _queue->_empty = false; 10.79 + ml.notify(); 10.80 + } 10.81 + } 10.82 + } else { 10.83 + // Queue is full, drop the string and update the statistics 10.84 + Atomic::inc_ptr(&_queue->_dropped); 10.85 + } 10.86 +} 10.87 + 10.88 +oop G1StringDedupQueue::pop() { 10.89 + assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); 10.90 + No_Safepoint_Verifier nsv; 10.91 + 10.92 + // Try all queues before giving up 10.93 + for (size_t tries = 0; tries < _queue->_nqueues; tries++) { 10.94 + // The cursor indicates where we left of last time 10.95 + G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; 10.96 + while (!queue->is_empty()) { 10.97 + oop obj = queue->pop(); 10.98 + // The oop we pop can be NULL if it was marked 10.99 + // dead. Just ignore those and pop the next oop. 10.100 + if (obj != NULL) { 10.101 + return obj; 10.102 + } 10.103 + } 10.104 + 10.105 + // Try next queue 10.106 + _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; 10.107 + } 10.108 + 10.109 + // Mark empty 10.110 + _queue->_empty = true; 10.111 + 10.112 + return NULL; 10.113 +} 10.114 + 10.115 +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { 10.116 + // A worker thread first claims a queue, which ensures exclusive 10.117 + // access to that queue, then continues to process it. 10.118 + for (;;) { 10.119 + // Grab next queue to scan 10.120 + size_t queue = cl->claim_queue(); 10.121 + if (queue >= _queue->_nqueues) { 10.122 + // End of queues 10.123 + break; 10.124 + } 10.125 + 10.126 + // Scan the queue 10.127 + unlink_or_oops_do(cl, queue); 10.128 + } 10.129 +} 10.130 + 10.131 +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { 10.132 + assert(queue < _queue->_nqueues, "Invalid queue"); 10.133 + StackIterator<oop, mtGC> iter(_queue->_queues[queue]); 10.134 + while (!iter.is_empty()) { 10.135 + oop* p = iter.next_addr(); 10.136 + if (*p != NULL) { 10.137 + if (cl->is_alive(*p)) { 10.138 + cl->keep_alive(p); 10.139 + } else { 10.140 + // Clear dead reference 10.141 + *p = NULL; 10.142 + } 10.143 + } 10.144 + } 10.145 +} 10.146 + 10.147 +void G1StringDedupQueue::print_statistics(outputStream* st) { 10.148 + st->print_cr( 10.149 + " [Queue]\n" 10.150 + " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); 10.151 +} 10.152 + 10.153 +void G1StringDedupQueue::verify() { 10.154 + for (size_t i = 0; i < _queue->_nqueues; i++) { 10.155 + StackIterator<oop, mtGC> iter(_queue->_queues[i]); 10.156 + while (!iter.is_empty()) { 10.157 + oop obj = iter.next(); 10.158 + if (obj != NULL) { 10.159 + guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); 10.160 + guarantee(!obj->is_forwarded(), "Object must not be forwarded"); 10.161 + guarantee(java_lang_String::is_instance(obj), "Object must be a String"); 10.162 + } 10.163 + } 10.164 + } 10.165 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp Mon Mar 24 14:23:02 2014 -0700 11.3 @@ -0,0 +1,97 @@ 11.4 +/* 11.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + * 11.26 + */ 11.27 + 11.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP 11.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP 11.30 + 11.31 +#include "memory/allocation.hpp" 11.32 +#include "oops/oop.hpp" 11.33 +#include "utilities/stack.hpp" 11.34 + 11.35 +class G1StringDedupUnlinkOrOopsDoClosure; 11.36 + 11.37 +// 11.38 +// The deduplication queue acts as the communication channel between the stop-the-world 11.39 +// mark/evacuation phase and the concurrent deduplication phase. Deduplication candidates 11.40 +// found during mark/evacuation are placed on this queue for later processing in the 11.41 +// deduplication thread. A queue entry is an oop pointing to a String object (as opposed 11.42 +// to entries in the deduplication hashtable which points to character arrays). 11.43 +// 11.44 +// While users of the queue treat it as a single queue, it is implemented as a set of 11.45 +// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue 11.46 +// operations by the GC workers. 11.47 +// 11.48 +// The oops in the queue are treated as weak pointers, meaning the objects they point to 11.49 +// can become unreachable and pruned (cleared) before being popped by the deduplication 11.50 +// thread. 11.51 +// 11.52 +// Pushing to the queue is thread safe (this relies on each thread using a unique worker 11.53 +// id), but only allowed during a safepoint. Popping from the queue is NOT thread safe 11.54 +// and can only be done by the deduplication thread outside a safepoint. 11.55 +// 11.56 +// The StringDedupQueue_lock is only used for blocking and waking up the deduplication 11.57 +// thread in case the queue is empty or becomes non-empty, respectively. This lock does 11.58 +// not otherwise protect the queue content. 11.59 +// 11.60 +class G1StringDedupQueue : public CHeapObj<mtGC> { 11.61 +private: 11.62 + typedef Stack<oop, mtGC> G1StringDedupWorkerQueue; 11.63 + 11.64 + static G1StringDedupQueue* _queue; 11.65 + static const size_t _max_size; 11.66 + static const size_t _max_cache_size; 11.67 + 11.68 + G1StringDedupWorkerQueue* _queues; 11.69 + size_t _nqueues; 11.70 + size_t _cursor; 11.71 + volatile bool _empty; 11.72 + 11.73 + // Statistics counter, only used for logging. 11.74 + uintx _dropped; 11.75 + 11.76 + G1StringDedupQueue(); 11.77 + ~G1StringDedupQueue(); 11.78 + 11.79 + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue); 11.80 + 11.81 +public: 11.82 + static void create(); 11.83 + 11.84 + // Blocks and waits for the queue to become non-empty. 11.85 + static void wait(); 11.86 + 11.87 + // Pushes a deduplication candidate onto a specific GC worker queue. 11.88 + static void push(uint worker_id, oop java_string); 11.89 + 11.90 + // Pops a deduplication candidate from any queue, returns NULL if 11.91 + // all queues are empty. 11.92 + static oop pop(); 11.93 + 11.94 + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl); 11.95 + 11.96 + static void print_statistics(outputStream* st); 11.97 + static void verify(); 11.98 +}; 11.99 + 11.100 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp Mon Mar 24 14:23:02 2014 -0700 12.3 @@ -0,0 +1,162 @@ 12.4 +/* 12.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. 12.11 + * 12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 + * version 2 for more details (a copy is included in the LICENSE file that 12.16 + * accompanied this code). 12.17 + * 12.18 + * You should have received a copy of the GNU General Public License version 12.19 + * 2 along with this work; if not, write to the Free Software Foundation, 12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 + * 12.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.23 + * or visit www.oracle.com if you need additional information or have any 12.24 + * questions. 12.25 + * 12.26 + */ 12.27 + 12.28 +#include "precompiled.hpp" 12.29 +#include "gc_implementation/g1/g1StringDedupStat.hpp" 12.30 + 12.31 +G1StringDedupStat::G1StringDedupStat() : 12.32 + _inspected(0), 12.33 + _skipped(0), 12.34 + _hashed(0), 12.35 + _known(0), 12.36 + _new(0), 12.37 + _new_bytes(0), 12.38 + _deduped(0), 12.39 + _deduped_bytes(0), 12.40 + _deduped_young(0), 12.41 + _deduped_young_bytes(0), 12.42 + _deduped_old(0), 12.43 + _deduped_old_bytes(0), 12.44 + _idle(0), 12.45 + _exec(0), 12.46 + _block(0), 12.47 + _start(0.0), 12.48 + _idle_elapsed(0.0), 12.49 + _exec_elapsed(0.0), 12.50 + _block_elapsed(0.0) { 12.51 +} 12.52 + 12.53 +void G1StringDedupStat::add(const G1StringDedupStat& stat) { 12.54 + _inspected += stat._inspected; 12.55 + _skipped += stat._skipped; 12.56 + _hashed += stat._hashed; 12.57 + _known += stat._known; 12.58 + _new += stat._new; 12.59 + _new_bytes += stat._new_bytes; 12.60 + _deduped += stat._deduped; 12.61 + _deduped_bytes += stat._deduped_bytes; 12.62 + _deduped_young += stat._deduped_young; 12.63 + _deduped_young_bytes += stat._deduped_young_bytes; 12.64 + _deduped_old += stat._deduped_old; 12.65 + _deduped_old_bytes += stat._deduped_old_bytes; 12.66 + _idle += stat._idle; 12.67 + _exec += stat._exec; 12.68 + _block += stat._block; 12.69 + _idle_elapsed += stat._idle_elapsed; 12.70 + _exec_elapsed += stat._exec_elapsed; 12.71 + _block_elapsed += stat._block_elapsed; 12.72 +} 12.73 + 12.74 +void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { 12.75 + double total_deduped_bytes_percent = 0.0; 12.76 + 12.77 + if (total_stat._new_bytes > 0) { 12.78 + // Avoid division by zero 12.79 + total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0; 12.80 + } 12.81 + 12.82 + st->date_stamp(PrintGCDateStamps); 12.83 + st->stamp(PrintGCTimeStamps); 12.84 + st->print_cr( 12.85 + "[GC concurrent-string-deduplication, " 12.86 + G1_STRDEDUP_BYTES_FORMAT_NS"->"G1_STRDEDUP_BYTES_FORMAT_NS"("G1_STRDEDUP_BYTES_FORMAT_NS"), avg " 12.87 + G1_STRDEDUP_PERCENT_FORMAT_NS", "G1_STRDEDUP_TIME_FORMAT"]", 12.88 + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes), 12.89 + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes), 12.90 + G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes), 12.91 + total_deduped_bytes_percent, 12.92 + last_stat._exec_elapsed); 12.93 +} 12.94 + 12.95 +void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total) { 12.96 + double young_percent = 0.0; 12.97 + double old_percent = 0.0; 12.98 + double skipped_percent = 0.0; 12.99 + double hashed_percent = 0.0; 12.100 + double known_percent = 0.0; 12.101 + double new_percent = 0.0; 12.102 + double deduped_percent = 0.0; 12.103 + double deduped_bytes_percent = 0.0; 12.104 + double deduped_young_percent = 0.0; 12.105 + double deduped_young_bytes_percent = 0.0; 12.106 + double deduped_old_percent = 0.0; 12.107 + double deduped_old_bytes_percent = 0.0; 12.108 + 12.109 + if (stat._inspected > 0) { 12.110 + // Avoid division by zero 12.111 + skipped_percent = (double)stat._skipped / (double)stat._inspected * 100.0; 12.112 + hashed_percent = (double)stat._hashed / (double)stat._inspected * 100.0; 12.113 + known_percent = (double)stat._known / (double)stat._inspected * 100.0; 12.114 + new_percent = (double)stat._new / (double)stat._inspected * 100.0; 12.115 + } 12.116 + 12.117 + if (stat._new > 0) { 12.118 + // Avoid division by zero 12.119 + deduped_percent = (double)stat._deduped / (double)stat._new * 100.0; 12.120 + } 12.121 + 12.122 + if (stat._deduped > 0) { 12.123 + // Avoid division by zero 12.124 + deduped_young_percent = (double)stat._deduped_young / (double)stat._deduped * 100.0; 12.125 + deduped_old_percent = (double)stat._deduped_old / (double)stat._deduped * 100.0; 12.126 + } 12.127 + 12.128 + if (stat._new_bytes > 0) { 12.129 + // Avoid division by zero 12.130 + deduped_bytes_percent = (double)stat._deduped_bytes / (double)stat._new_bytes * 100.0; 12.131 + } 12.132 + 12.133 + if (stat._deduped_bytes > 0) { 12.134 + // Avoid division by zero 12.135 + deduped_young_bytes_percent = (double)stat._deduped_young_bytes / (double)stat._deduped_bytes * 100.0; 12.136 + deduped_old_bytes_percent = (double)stat._deduped_old_bytes / (double)stat._deduped_bytes * 100.0; 12.137 + } 12.138 + 12.139 + if (total) { 12.140 + st->print_cr( 12.141 + " [Total Exec: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Idle: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", 12.142 + stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed); 12.143 + } else { 12.144 + st->print_cr( 12.145 + " [Last Exec: "G1_STRDEDUP_TIME_FORMAT", Idle: "G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", 12.146 + stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed); 12.147 + } 12.148 + st->print_cr( 12.149 + " [Inspected: "G1_STRDEDUP_OBJECTS_FORMAT"]\n" 12.150 + " [Skipped: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" 12.151 + " [Hashed: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" 12.152 + " [Known: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" 12.153 + " [New: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"]\n" 12.154 + " [Deduplicated: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" 12.155 + " [Young: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" 12.156 + " [Old: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]", 12.157 + stat._inspected, 12.158 + stat._skipped, skipped_percent, 12.159 + stat._hashed, hashed_percent, 12.160 + stat._known, known_percent, 12.161 + stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes), 12.162 + stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent, 12.163 + stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent, 12.164 + stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); 12.165 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp Mon Mar 24 14:23:02 2014 -0700 13.3 @@ -0,0 +1,142 @@ 13.4 +/* 13.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. 13.11 + * 13.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.15 + * version 2 for more details (a copy is included in the LICENSE file that 13.16 + * accompanied this code). 13.17 + * 13.18 + * You should have received a copy of the GNU General Public License version 13.19 + * 2 along with this work; if not, write to the Free Software Foundation, 13.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.21 + * 13.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.23 + * or visit www.oracle.com if you need additional information or have any 13.24 + * questions. 13.25 + * 13.26 + */ 13.27 + 13.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP 13.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP 13.30 + 13.31 +#include "memory/allocation.hpp" 13.32 +#include "runtime/os.hpp" 13.33 + 13.34 +// Macros for GC log output formating 13.35 +#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12) 13.36 +#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs" 13.37 +#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%" 13.38 +#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%" 13.39 +#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s" 13.40 +#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s" 13.41 +#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes)) 13.42 + 13.43 +// 13.44 +// Statistics gathered by the deduplication thread. 13.45 +// 13.46 +class G1StringDedupStat : public StackObj { 13.47 +private: 13.48 + // Counters 13.49 + uintx _inspected; 13.50 + uintx _skipped; 13.51 + uintx _hashed; 13.52 + uintx _known; 13.53 + uintx _new; 13.54 + uintx _new_bytes; 13.55 + uintx _deduped; 13.56 + uintx _deduped_bytes; 13.57 + uintx _deduped_young; 13.58 + uintx _deduped_young_bytes; 13.59 + uintx _deduped_old; 13.60 + uintx _deduped_old_bytes; 13.61 + uintx _idle; 13.62 + uintx _exec; 13.63 + uintx _block; 13.64 + 13.65 + // Time spent by the deduplication thread in different phases 13.66 + double _start; 13.67 + double _idle_elapsed; 13.68 + double _exec_elapsed; 13.69 + double _block_elapsed; 13.70 + 13.71 +public: 13.72 + G1StringDedupStat(); 13.73 + 13.74 + void inc_inspected() { 13.75 + _inspected++; 13.76 + } 13.77 + 13.78 + void inc_skipped() { 13.79 + _skipped++; 13.80 + } 13.81 + 13.82 + void inc_hashed() { 13.83 + _hashed++; 13.84 + } 13.85 + 13.86 + void inc_known() { 13.87 + _known++; 13.88 + } 13.89 + 13.90 + void inc_new(uintx bytes) { 13.91 + _new++; 13.92 + _new_bytes += bytes; 13.93 + } 13.94 + 13.95 + void inc_deduped_young(uintx bytes) { 13.96 + _deduped++; 13.97 + _deduped_bytes += bytes; 13.98 + _deduped_young++; 13.99 + _deduped_young_bytes += bytes; 13.100 + } 13.101 + 13.102 + void inc_deduped_old(uintx bytes) { 13.103 + _deduped++; 13.104 + _deduped_bytes += bytes; 13.105 + _deduped_old++; 13.106 + _deduped_old_bytes += bytes; 13.107 + } 13.108 + 13.109 + void mark_idle() { 13.110 + _start = os::elapsedTime(); 13.111 + _idle++; 13.112 + } 13.113 + 13.114 + void mark_exec() { 13.115 + double now = os::elapsedTime(); 13.116 + _idle_elapsed = now - _start; 13.117 + _start = now; 13.118 + _exec++; 13.119 + } 13.120 + 13.121 + void mark_block() { 13.122 + double now = os::elapsedTime(); 13.123 + _exec_elapsed += now - _start; 13.124 + _start = now; 13.125 + _block++; 13.126 + } 13.127 + 13.128 + void mark_unblock() { 13.129 + double now = os::elapsedTime(); 13.130 + _block_elapsed += now - _start; 13.131 + _start = now; 13.132 + } 13.133 + 13.134 + void mark_done() { 13.135 + double now = os::elapsedTime(); 13.136 + _exec_elapsed += now - _start; 13.137 + } 13.138 + 13.139 + void add(const G1StringDedupStat& stat); 13.140 + 13.141 + static void print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); 13.142 + static void print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total); 13.143 +}; 13.144 + 13.145 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Mon Mar 24 14:23:02 2014 -0700 14.3 @@ -0,0 +1,569 @@ 14.4 +/* 14.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + * 14.26 + */ 14.27 + 14.28 +#include "precompiled.hpp" 14.29 +#include "classfile/altHashing.hpp" 14.30 +#include "classfile/javaClasses.hpp" 14.31 +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 14.32 +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" 14.33 +#include "gc_implementation/g1/g1StringDedupTable.hpp" 14.34 +#include "memory/gcLocker.hpp" 14.35 +#include "memory/padded.inline.hpp" 14.36 +#include "oops/typeArrayOop.hpp" 14.37 +#include "runtime/mutexLocker.hpp" 14.38 + 14.39 +// 14.40 +// Freelist in the deduplication table entry cache. Links table 14.41 +// entries together using their _next fields. 14.42 +// 14.43 +class G1StringDedupEntryFreeList : public CHeapObj<mtGC> { 14.44 +private: 14.45 + G1StringDedupEntry* _list; 14.46 + size_t _length; 14.47 + 14.48 +public: 14.49 + G1StringDedupEntryFreeList() : 14.50 + _list(NULL), 14.51 + _length(0) { 14.52 + } 14.53 + 14.54 + void add(G1StringDedupEntry* entry) { 14.55 + entry->set_next(_list); 14.56 + _list = entry; 14.57 + _length++; 14.58 + } 14.59 + 14.60 + G1StringDedupEntry* remove() { 14.61 + G1StringDedupEntry* entry = _list; 14.62 + if (entry != NULL) { 14.63 + _list = entry->next(); 14.64 + _length--; 14.65 + } 14.66 + return entry; 14.67 + } 14.68 + 14.69 + size_t length() { 14.70 + return _length; 14.71 + } 14.72 +}; 14.73 + 14.74 +// 14.75 +// Cache of deduplication table entries. This cache provides fast allocation and 14.76 +// reuse of table entries to lower the pressure on the underlying allocator. 14.77 +// But more importantly, it provides fast/deferred freeing of table entries. This 14.78 +// is important because freeing of table entries is done during stop-the-world 14.79 +// phases and it is not uncommon for large number of entries to be freed at once. 14.80 +// Tables entries that are freed during these phases are placed onto a freelist in 14.81 +// the cache. The deduplication thread, which executes in a concurrent phase, will 14.82 +// later reuse or free the underlying memory for these entries. 14.83 +// 14.84 +// The cache allows for single-threaded allocations and multi-threaded frees. 14.85 +// Allocations are synchronized by StringDedupTable_lock as part of a table 14.86 +// modification. 14.87 +// 14.88 +class G1StringDedupEntryCache : public CHeapObj<mtGC> { 14.89 +private: 14.90 + // One freelist per GC worker to allow lock less freeing of 14.91 + // entries while doing a parallel scan of the table. Using 14.92 + // PaddedEnd to avoid false sharing. 14.93 + PaddedEnd<G1StringDedupEntryFreeList>* _lists; 14.94 + size_t _nlists; 14.95 + 14.96 +public: 14.97 + G1StringDedupEntryCache(); 14.98 + ~G1StringDedupEntryCache(); 14.99 + 14.100 + // Get a table entry from the cache freelist, or allocate a new 14.101 + // entry if the cache is empty. 14.102 + G1StringDedupEntry* alloc(); 14.103 + 14.104 + // Insert a table entry into the cache freelist. 14.105 + void free(G1StringDedupEntry* entry, uint worker_id); 14.106 + 14.107 + // Returns current number of entries in the cache. 14.108 + size_t size(); 14.109 + 14.110 + // If the cache has grown above the given max size, trim it down 14.111 + // and deallocate the memory occupied by trimmed of entries. 14.112 + void trim(size_t max_size); 14.113 +}; 14.114 + 14.115 +G1StringDedupEntryCache::G1StringDedupEntryCache() { 14.116 + _nlists = MAX2(ParallelGCThreads, (size_t)1); 14.117 + _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists); 14.118 +} 14.119 + 14.120 +G1StringDedupEntryCache::~G1StringDedupEntryCache() { 14.121 + ShouldNotReachHere(); 14.122 +} 14.123 + 14.124 +G1StringDedupEntry* G1StringDedupEntryCache::alloc() { 14.125 + for (size_t i = 0; i < _nlists; i++) { 14.126 + G1StringDedupEntry* entry = _lists[i].remove(); 14.127 + if (entry != NULL) { 14.128 + return entry; 14.129 + } 14.130 + } 14.131 + return new G1StringDedupEntry(); 14.132 +} 14.133 + 14.134 +void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { 14.135 + assert(entry->obj() != NULL, "Double free"); 14.136 + assert(worker_id < _nlists, "Invalid worker id"); 14.137 + entry->set_obj(NULL); 14.138 + entry->set_hash(0); 14.139 + _lists[worker_id].add(entry); 14.140 +} 14.141 + 14.142 +size_t G1StringDedupEntryCache::size() { 14.143 + size_t size = 0; 14.144 + for (size_t i = 0; i < _nlists; i++) { 14.145 + size += _lists[i].length(); 14.146 + } 14.147 + return size; 14.148 +} 14.149 + 14.150 +void G1StringDedupEntryCache::trim(size_t max_size) { 14.151 + size_t cache_size = 0; 14.152 + for (size_t i = 0; i < _nlists; i++) { 14.153 + G1StringDedupEntryFreeList* list = &_lists[i]; 14.154 + cache_size += list->length(); 14.155 + while (cache_size > max_size) { 14.156 + G1StringDedupEntry* entry = list->remove(); 14.157 + assert(entry != NULL, "Should not be null"); 14.158 + cache_size--; 14.159 + delete entry; 14.160 + } 14.161 + } 14.162 +} 14.163 + 14.164 +G1StringDedupTable* G1StringDedupTable::_table = NULL; 14.165 +G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL; 14.166 + 14.167 +const size_t G1StringDedupTable::_min_size = (1 << 10); // 1024 14.168 +const size_t G1StringDedupTable::_max_size = (1 << 24); // 16777216 14.169 +const double G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load 14.170 +const double G1StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load 14.171 +const double G1StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size 14.172 +const uintx G1StringDedupTable::_rehash_multiple = 60; // Hash bucket has 60 times more collisions than expected 14.173 +const uintx G1StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor); 14.174 + 14.175 +uintx G1StringDedupTable::_entries_added = 0; 14.176 +uintx G1StringDedupTable::_entries_removed = 0; 14.177 +uintx G1StringDedupTable::_resize_count = 0; 14.178 +uintx G1StringDedupTable::_rehash_count = 0; 14.179 + 14.180 +G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) : 14.181 + _size(size), 14.182 + _entries(0), 14.183 + _grow_threshold((uintx)(size * _grow_load_factor)), 14.184 + _shrink_threshold((uintx)(size * _shrink_load_factor)), 14.185 + _rehash_needed(false), 14.186 + _hash_seed(hash_seed) { 14.187 + assert(is_power_of_2(size), "Table size must be a power of 2"); 14.188 + _buckets = NEW_C_HEAP_ARRAY(G1StringDedupEntry*, _size, mtGC); 14.189 + memset(_buckets, 0, _size * sizeof(G1StringDedupEntry*)); 14.190 +} 14.191 + 14.192 +G1StringDedupTable::~G1StringDedupTable() { 14.193 + FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets, mtGC); 14.194 +} 14.195 + 14.196 +void G1StringDedupTable::create() { 14.197 + assert(_table == NULL, "One string deduplication table allowed"); 14.198 + _entry_cache = new G1StringDedupEntryCache(); 14.199 + _table = new G1StringDedupTable(_min_size); 14.200 +} 14.201 + 14.202 +void G1StringDedupTable::add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list) { 14.203 + G1StringDedupEntry* entry = _entry_cache->alloc(); 14.204 + entry->set_obj(value); 14.205 + entry->set_hash(hash); 14.206 + entry->set_next(*list); 14.207 + *list = entry; 14.208 + _entries++; 14.209 +} 14.210 + 14.211 +void G1StringDedupTable::remove(G1StringDedupEntry** pentry, uint worker_id) { 14.212 + G1StringDedupEntry* entry = *pentry; 14.213 + *pentry = entry->next(); 14.214 + _entry_cache->free(entry, worker_id); 14.215 +} 14.216 + 14.217 +void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) { 14.218 + G1StringDedupEntry* entry = *pentry; 14.219 + *pentry = entry->next(); 14.220 + unsigned int hash = entry->hash(); 14.221 + size_t index = dest->hash_to_index(hash); 14.222 + G1StringDedupEntry** list = dest->bucket(index); 14.223 + entry->set_next(*list); 14.224 + *list = entry; 14.225 +} 14.226 + 14.227 +bool G1StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) { 14.228 + return (value1 == value2 || 14.229 + (value1->length() == value2->length() && 14.230 + (!memcmp(value1->base(T_CHAR), 14.231 + value2->base(T_CHAR), 14.232 + value1->length() * sizeof(jchar))))); 14.233 +} 14.234 + 14.235 +typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, unsigned int hash, 14.236 + G1StringDedupEntry** list, uintx &count) { 14.237 + for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) { 14.238 + if (entry->hash() == hash) { 14.239 + typeArrayOop existing_value = entry->obj(); 14.240 + if (equals(value, existing_value)) { 14.241 + // Match found 14.242 + return existing_value; 14.243 + } 14.244 + } 14.245 + count++; 14.246 + } 14.247 + 14.248 + // Not found 14.249 + return NULL; 14.250 +} 14.251 + 14.252 +typeArrayOop G1StringDedupTable::lookup_or_add_inner(typeArrayOop value, unsigned int hash) { 14.253 + size_t index = hash_to_index(hash); 14.254 + G1StringDedupEntry** list = bucket(index); 14.255 + uintx count = 0; 14.256 + 14.257 + // Lookup in list 14.258 + typeArrayOop existing_value = lookup(value, hash, list, count); 14.259 + 14.260 + // Check if rehash is needed 14.261 + if (count > _rehash_threshold) { 14.262 + _rehash_needed = true; 14.263 + } 14.264 + 14.265 + if (existing_value == NULL) { 14.266 + // Not found, add new entry 14.267 + add(value, hash, list); 14.268 + 14.269 + // Update statistics 14.270 + _entries_added++; 14.271 + } 14.272 + 14.273 + return existing_value; 14.274 +} 14.275 + 14.276 +unsigned int G1StringDedupTable::hash_code(typeArrayOop value) { 14.277 + unsigned int hash; 14.278 + int length = value->length(); 14.279 + const jchar* data = (jchar*)value->base(T_CHAR); 14.280 + 14.281 + if (use_java_hash()) { 14.282 + hash = java_lang_String::hash_code(data, length); 14.283 + } else { 14.284 + hash = AltHashing::murmur3_32(_table->_hash_seed, data, length); 14.285 + } 14.286 + 14.287 + return hash; 14.288 +} 14.289 + 14.290 +void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) { 14.291 + assert(java_lang_String::is_instance(java_string), "Must be a string"); 14.292 + No_Safepoint_Verifier nsv; 14.293 + 14.294 + stat.inc_inspected(); 14.295 + 14.296 + typeArrayOop value = java_lang_String::value(java_string); 14.297 + if (value == NULL) { 14.298 + // String has no value 14.299 + stat.inc_skipped(); 14.300 + return; 14.301 + } 14.302 + 14.303 + unsigned int hash = 0; 14.304 + 14.305 + if (use_java_hash()) { 14.306 + // Get hash code from cache 14.307 + hash = java_lang_String::hash(java_string); 14.308 + } 14.309 + 14.310 + if (hash == 0) { 14.311 + // Compute hash 14.312 + hash = hash_code(value); 14.313 + stat.inc_hashed(); 14.314 + } 14.315 + 14.316 + if (use_java_hash() && hash != 0) { 14.317 + // Store hash code in cache 14.318 + java_lang_String::set_hash(java_string, hash); 14.319 + } 14.320 + 14.321 + typeArrayOop existing_value = lookup_or_add(value, hash); 14.322 + if (existing_value == value) { 14.323 + // Same value, already known 14.324 + stat.inc_known(); 14.325 + return; 14.326 + } 14.327 + 14.328 + // Get size of value array 14.329 + uintx size_in_bytes = value->size() * HeapWordSize; 14.330 + stat.inc_new(size_in_bytes); 14.331 + 14.332 + if (existing_value != NULL) { 14.333 + // Enqueue the reference to make sure it is kept alive. Concurrent mark might 14.334 + // otherwise declare it dead if there are no other strong references to this object. 14.335 + G1SATBCardTableModRefBS::enqueue(existing_value); 14.336 + 14.337 + // Existing value found, deduplicate string 14.338 + java_lang_String::set_value(java_string, existing_value); 14.339 + 14.340 + if (G1CollectedHeap::heap()->is_in_young(value)) { 14.341 + stat.inc_deduped_young(size_in_bytes); 14.342 + } else { 14.343 + stat.inc_deduped_old(size_in_bytes); 14.344 + } 14.345 + } 14.346 +} 14.347 + 14.348 +G1StringDedupTable* G1StringDedupTable::prepare_resize() { 14.349 + size_t size = _table->_size; 14.350 + 14.351 + // Check if the hashtable needs to be resized 14.352 + if (_table->_entries > _table->_grow_threshold) { 14.353 + // Grow table, double the size 14.354 + size *= 2; 14.355 + if (size > _max_size) { 14.356 + // Too big, don't resize 14.357 + return NULL; 14.358 + } 14.359 + } else if (_table->_entries < _table->_shrink_threshold) { 14.360 + // Shrink table, half the size 14.361 + size /= 2; 14.362 + if (size < _min_size) { 14.363 + // Too small, don't resize 14.364 + return NULL; 14.365 + } 14.366 + } else if (StringDeduplicationResizeALot) { 14.367 + // Force grow 14.368 + size *= 2; 14.369 + if (size > _max_size) { 14.370 + // Too big, force shrink instead 14.371 + size /= 4; 14.372 + } 14.373 + } else { 14.374 + // Resize not needed 14.375 + return NULL; 14.376 + } 14.377 + 14.378 + // Update statistics 14.379 + _resize_count++; 14.380 + 14.381 + // Allocate the new table. The new table will be populated by workers 14.382 + // calling unlink_or_oops_do() and finally installed by finish_resize(). 14.383 + return new G1StringDedupTable(size, _table->_hash_seed); 14.384 +} 14.385 + 14.386 +void G1StringDedupTable::finish_resize(G1StringDedupTable* resized_table) { 14.387 + assert(resized_table != NULL, "Invalid table"); 14.388 + 14.389 + resized_table->_entries = _table->_entries; 14.390 + 14.391 + // Free old table 14.392 + delete _table; 14.393 + 14.394 + // Install new table 14.395 + _table = resized_table; 14.396 +} 14.397 + 14.398 +void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) { 14.399 + // The table is divided into partitions to allow lock-less parallel processing by 14.400 + // multiple worker threads. A worker thread first claims a partition, which ensures 14.401 + // exclusive access to that part of the table, then continues to process it. To allow 14.402 + // shrinking of the table in parallel we also need to make sure that the same worker 14.403 + // thread processes all partitions where entries will hash to the same destination 14.404 + // partition. Since the table size is always a power of two and we always shrink by 14.405 + // dividing the table in half, we know that for a given partition there is only one 14.406 + // other partition whoes entries will hash to the same destination partition. That 14.407 + // other partition is always the sibling partition in the second half of the table. 14.408 + // For example, if the table is divided into 8 partitions, the sibling of partition 0 14.409 + // is partition 4, the sibling of partition 1 is partition 5, etc. 14.410 + size_t table_half = _table->_size / 2; 14.411 + 14.412 + // Let each partition be one page worth of buckets 14.413 + size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(G1StringDedupEntry*)); 14.414 + assert(table_half % partition_size == 0, "Invalid partition size"); 14.415 + 14.416 + // Number of entries removed during the scan 14.417 + uintx removed = 0; 14.418 + 14.419 + for (;;) { 14.420 + // Grab next partition to scan 14.421 + size_t partition_begin = cl->claim_table_partition(partition_size); 14.422 + size_t partition_end = partition_begin + partition_size; 14.423 + if (partition_begin >= table_half) { 14.424 + // End of table 14.425 + break; 14.426 + } 14.427 + 14.428 + // Scan the partition followed by the sibling partition in the second half of the table 14.429 + removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id); 14.430 + removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id); 14.431 + } 14.432 + 14.433 + // Delayed update avoid contention on the table lock 14.434 + if (removed > 0) { 14.435 + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); 14.436 + _table->_entries -= removed; 14.437 + _entries_removed += removed; 14.438 + } 14.439 +} 14.440 + 14.441 +uintx G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, 14.442 + size_t partition_begin, 14.443 + size_t partition_end, 14.444 + uint worker_id) { 14.445 + uintx removed = 0; 14.446 + for (size_t bucket = partition_begin; bucket < partition_end; bucket++) { 14.447 + G1StringDedupEntry** entry = _table->bucket(bucket); 14.448 + while (*entry != NULL) { 14.449 + oop* p = (oop*)(*entry)->obj_addr(); 14.450 + if (cl->is_alive(*p)) { 14.451 + cl->keep_alive(p); 14.452 + if (cl->is_resizing()) { 14.453 + // We are resizing the table, transfer entry to the new table 14.454 + _table->transfer(entry, cl->resized_table()); 14.455 + } else { 14.456 + if (cl->is_rehashing()) { 14.457 + // We are rehashing the table, rehash the entry but keep it 14.458 + // in the table. We can't transfer entries into the new table 14.459 + // at this point since we don't have exclusive access to all 14.460 + // destination partitions. finish_rehash() will do a single 14.461 + // threaded transfer of all entries. 14.462 + typeArrayOop value = (typeArrayOop)*p; 14.463 + unsigned int hash = hash_code(value); 14.464 + (*entry)->set_hash(hash); 14.465 + } 14.466 + 14.467 + // Move to next entry 14.468 + entry = (*entry)->next_addr(); 14.469 + } 14.470 + } else { 14.471 + // Not alive, remove entry from table 14.472 + _table->remove(entry, worker_id); 14.473 + removed++; 14.474 + } 14.475 + } 14.476 + } 14.477 + 14.478 + return removed; 14.479 +} 14.480 + 14.481 +G1StringDedupTable* G1StringDedupTable::prepare_rehash() { 14.482 + if (!_table->_rehash_needed && !StringDeduplicationRehashALot) { 14.483 + // Rehash not needed 14.484 + return NULL; 14.485 + } 14.486 + 14.487 + // Update statistics 14.488 + _rehash_count++; 14.489 + 14.490 + // Compute new hash seed 14.491 + _table->_hash_seed = AltHashing::compute_seed(); 14.492 + 14.493 + // Allocate the new table, same size and hash seed 14.494 + return new G1StringDedupTable(_table->_size, _table->_hash_seed); 14.495 +} 14.496 + 14.497 +void G1StringDedupTable::finish_rehash(G1StringDedupTable* rehashed_table) { 14.498 + assert(rehashed_table != NULL, "Invalid table"); 14.499 + 14.500 + // Move all newly rehashed entries into the correct buckets in the new table 14.501 + for (size_t bucket = 0; bucket < _table->_size; bucket++) { 14.502 + G1StringDedupEntry** entry = _table->bucket(bucket); 14.503 + while (*entry != NULL) { 14.504 + _table->transfer(entry, rehashed_table); 14.505 + } 14.506 + } 14.507 + 14.508 + rehashed_table->_entries = _table->_entries; 14.509 + 14.510 + // Free old table 14.511 + delete _table; 14.512 + 14.513 + // Install new table 14.514 + _table = rehashed_table; 14.515 +} 14.516 + 14.517 +void G1StringDedupTable::verify() { 14.518 + for (size_t bucket = 0; bucket < _table->_size; bucket++) { 14.519 + // Verify entries 14.520 + G1StringDedupEntry** entry = _table->bucket(bucket); 14.521 + while (*entry != NULL) { 14.522 + typeArrayOop value = (*entry)->obj(); 14.523 + guarantee(value != NULL, "Object must not be NULL"); 14.524 + guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); 14.525 + guarantee(!value->is_forwarded(), "Object must not be forwarded"); 14.526 + guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); 14.527 + unsigned int hash = hash_code(value); 14.528 + guarantee((*entry)->hash() == hash, "Table entry has inorrect hash"); 14.529 + guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index"); 14.530 + entry = (*entry)->next_addr(); 14.531 + } 14.532 + 14.533 + // Verify that we do not have entries with identical oops or identical arrays. 14.534 + // We only need to compare entries in the same bucket. If the same oop or an 14.535 + // identical array has been inserted more than once into different/incorrect 14.536 + // buckets the verification step above will catch that. 14.537 + G1StringDedupEntry** entry1 = _table->bucket(bucket); 14.538 + while (*entry1 != NULL) { 14.539 + typeArrayOop value1 = (*entry1)->obj(); 14.540 + G1StringDedupEntry** entry2 = (*entry1)->next_addr(); 14.541 + while (*entry2 != NULL) { 14.542 + typeArrayOop value2 = (*entry2)->obj(); 14.543 + guarantee(!equals(value1, value2), "Table entries must not have identical arrays"); 14.544 + entry2 = (*entry2)->next_addr(); 14.545 + } 14.546 + entry1 = (*entry1)->next_addr(); 14.547 + } 14.548 + } 14.549 +} 14.550 + 14.551 +void G1StringDedupTable::trim_entry_cache() { 14.552 + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); 14.553 + size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor); 14.554 + _entry_cache->trim(max_cache_size); 14.555 +} 14.556 + 14.557 +void G1StringDedupTable::print_statistics(outputStream* st) { 14.558 + st->print_cr( 14.559 + " [Table]\n" 14.560 + " [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n" 14.561 + " [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n" 14.562 + " [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Cached: " UINTX_FORMAT ", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n" 14.563 + " [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n" 14.564 + " [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n" 14.565 + " [Age Threshold: "UINTX_FORMAT"]", 14.566 + G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), 14.567 + _table->_size, _min_size, _max_size, 14.568 + _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, 14.569 + _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, 14.570 + _rehash_count, _rehash_threshold, _table->_hash_seed, 14.571 + StringDeduplicationAgeThreshold); 14.572 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Mon Mar 24 14:23:02 2014 -0700 15.3 @@ -0,0 +1,230 @@ 15.4 +/* 15.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.7 + * 15.8 + * This code is free software; you can redistribute it and/or modify it 15.9 + * under the terms of the GNU General Public License version 2 only, as 15.10 + * published by the Free Software Foundation. 15.11 + * 15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15.15 + * version 2 for more details (a copy is included in the LICENSE file that 15.16 + * accompanied this code). 15.17 + * 15.18 + * You should have received a copy of the GNU General Public License version 15.19 + * 2 along with this work; if not, write to the Free Software Foundation, 15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 15.21 + * 15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 15.23 + * or visit www.oracle.com if you need additional information or have any 15.24 + * questions. 15.25 + * 15.26 + */ 15.27 + 15.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP 15.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP 15.30 + 15.31 +#include "gc_implementation/g1/g1StringDedupStat.hpp" 15.32 +#include "runtime/mutexLocker.hpp" 15.33 + 15.34 +class G1StringDedupEntryCache; 15.35 + 15.36 +// 15.37 +// Table entry in the deduplication hashtable. Points weakly to the 15.38 +// character array. Can be chained in a linked list in case of hash 15.39 +// collisions or when placed in a freelist in the entry cache. 15.40 +// 15.41 +class G1StringDedupEntry : public CHeapObj<mtGC> { 15.42 +private: 15.43 + G1StringDedupEntry* _next; 15.44 + unsigned int _hash; 15.45 + typeArrayOop _obj; 15.46 + 15.47 +public: 15.48 + G1StringDedupEntry() : 15.49 + _next(NULL), 15.50 + _hash(0), 15.51 + _obj(NULL) { 15.52 + } 15.53 + 15.54 + G1StringDedupEntry* next() { 15.55 + return _next; 15.56 + } 15.57 + 15.58 + G1StringDedupEntry** next_addr() { 15.59 + return &_next; 15.60 + } 15.61 + 15.62 + void set_next(G1StringDedupEntry* next) { 15.63 + _next = next; 15.64 + } 15.65 + 15.66 + unsigned int hash() { 15.67 + return _hash; 15.68 + } 15.69 + 15.70 + void set_hash(unsigned int hash) { 15.71 + _hash = hash; 15.72 + } 15.73 + 15.74 + typeArrayOop obj() { 15.75 + return _obj; 15.76 + } 15.77 + 15.78 + typeArrayOop* obj_addr() { 15.79 + return &_obj; 15.80 + } 15.81 + 15.82 + void set_obj(typeArrayOop obj) { 15.83 + _obj = obj; 15.84 + } 15.85 +}; 15.86 + 15.87 +// 15.88 +// The deduplication hashtable keeps track of all unique character arrays used 15.89 +// by String objects. Each table entry weakly points to an character array, allowing 15.90 +// otherwise unreachable character arrays to be declared dead and pruned from the 15.91 +// table. 15.92 +// 15.93 +// The table is dynamically resized to accommodate the current number of table entries. 15.94 +// The table has hash buckets with chains for hash collision. If the average chain 15.95 +// length goes above or below given thresholds the table grows or shrinks accordingly. 15.96 +// 15.97 +// The table is also dynamically rehashed (using a new hash seed) if it becomes severely 15.98 +// unbalanced, i.e., a hash chain is significantly longer than average. 15.99 +// 15.100 +// All access to the table is protected by the StringDedupTable_lock, except under 15.101 +// safepoints in which case GC workers are allowed to access a table partitions they 15.102 +// have claimed without first acquiring the lock. Note however, that this applies only 15.103 +// the table partition (i.e. a range of elements in _buckets), not other parts of the 15.104 +// table such as the _entries field, statistics counters, etc. 15.105 +// 15.106 +class G1StringDedupTable : public CHeapObj<mtGC> { 15.107 +private: 15.108 + // The currently active hashtable instance. Only modified when 15.109 + // the table is resizes or rehashed. 15.110 + static G1StringDedupTable* _table; 15.111 + 15.112 + // Cache for reuse and fast alloc/free of table entries. 15.113 + static G1StringDedupEntryCache* _entry_cache; 15.114 + 15.115 + G1StringDedupEntry** _buckets; 15.116 + size_t _size; 15.117 + uintx _entries; 15.118 + uintx _shrink_threshold; 15.119 + uintx _grow_threshold; 15.120 + bool _rehash_needed; 15.121 + 15.122 + // The hash seed also dictates which hash function to use. A 15.123 + // zero hash seed means we will use the Java compatible hash 15.124 + // function (which doesn't use a seed), and a non-zero hash 15.125 + // seed means we use the murmur3 hash function. 15.126 + jint _hash_seed; 15.127 + 15.128 + // Constants governing table resize/rehash/cache. 15.129 + static const size_t _min_size; 15.130 + static const size_t _max_size; 15.131 + static const double _grow_load_factor; 15.132 + static const double _shrink_load_factor; 15.133 + static const uintx _rehash_multiple; 15.134 + static const uintx _rehash_threshold; 15.135 + static const double _max_cache_factor; 15.136 + 15.137 + // Table statistics, only used for logging. 15.138 + static uintx _entries_added; 15.139 + static uintx _entries_removed; 15.140 + static uintx _resize_count; 15.141 + static uintx _rehash_count; 15.142 + 15.143 + G1StringDedupTable(size_t size, jint hash_seed = 0); 15.144 + ~G1StringDedupTable(); 15.145 + 15.146 + // Returns the hash bucket at the given index. 15.147 + G1StringDedupEntry** bucket(size_t index) { 15.148 + return _buckets + index; 15.149 + } 15.150 + 15.151 + // Returns the hash bucket index for the given hash code. 15.152 + size_t hash_to_index(unsigned int hash) { 15.153 + return (size_t)hash & (_size - 1); 15.154 + } 15.155 + 15.156 + // Adds a new table entry to the given hash bucket. 15.157 + void add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list); 15.158 + 15.159 + // Removes the given table entry from the table. 15.160 + void remove(G1StringDedupEntry** pentry, uint worker_id); 15.161 + 15.162 + // Transfers a table entry from the current table to the destination table. 15.163 + void transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest); 15.164 + 15.165 + // Returns an existing character array in the given hash bucket, or NULL 15.166 + // if no matching character array exists. 15.167 + typeArrayOop lookup(typeArrayOop value, unsigned int hash, 15.168 + G1StringDedupEntry** list, uintx &count); 15.169 + 15.170 + // Returns an existing character array in the table, or inserts a new 15.171 + // table entry if no matching character array exists. 15.172 + typeArrayOop lookup_or_add_inner(typeArrayOop value, unsigned int hash); 15.173 + 15.174 + // Thread safe lookup or add of table entry 15.175 + static typeArrayOop lookup_or_add(typeArrayOop value, unsigned int hash) { 15.176 + // Protect the table from concurrent access. Also note that this lock 15.177 + // acts as a fence for _table, which could have been replaced by a new 15.178 + // instance if the table was resized or rehashed. 15.179 + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); 15.180 + return _table->lookup_or_add_inner(value, hash); 15.181 + } 15.182 + 15.183 + // Returns true if the hashtable is currently using a Java compatible 15.184 + // hash function. 15.185 + static bool use_java_hash() { 15.186 + return _table->_hash_seed == 0; 15.187 + } 15.188 + 15.189 + static bool equals(typeArrayOop value1, typeArrayOop value2); 15.190 + 15.191 + // Computes the hash code for the given character array, using the 15.192 + // currently active hash function and hash seed. 15.193 + static unsigned int hash_code(typeArrayOop value); 15.194 + 15.195 + static uintx unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, 15.196 + size_t partition_begin, 15.197 + size_t partition_end, 15.198 + uint worker_id); 15.199 + 15.200 +public: 15.201 + static void create(); 15.202 + 15.203 + // Deduplicates the given String object, or adds its backing 15.204 + // character array to the deduplication hashtable. 15.205 + static void deduplicate(oop java_string, G1StringDedupStat& stat); 15.206 + 15.207 + // If a table resize is needed, returns a newly allocated empty 15.208 + // hashtable of the proper size. 15.209 + static G1StringDedupTable* prepare_resize(); 15.210 + 15.211 + // Installs a newly resized table as the currently active table 15.212 + // and deletes the previously active table. 15.213 + static void finish_resize(G1StringDedupTable* resized_table); 15.214 + 15.215 + // If a table rehash is needed, returns a newly allocated empty 15.216 + // hashtable and updates the hash seed. 15.217 + static G1StringDedupTable* prepare_rehash(); 15.218 + 15.219 + // Transfers rehashed entries from the currently active table into 15.220 + // the new table. Installs the new table as the currently active table 15.221 + // and deletes the previously active table. 15.222 + static void finish_rehash(G1StringDedupTable* rehashed_table); 15.223 + 15.224 + // If the table entry cache has grown too large, trim it down according to policy 15.225 + static void trim_entry_cache(); 15.226 + 15.227 + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id); 15.228 + 15.229 + static void print_statistics(outputStream* st); 15.230 + static void verify(); 15.231 +}; 15.232 + 15.233 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp Mon Mar 24 14:23:02 2014 -0700 16.3 @@ -0,0 +1,124 @@ 16.4 +/* 16.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 16.7 + * 16.8 + * This code is free software; you can redistribute it and/or modify it 16.9 + * under the terms of the GNU General Public License version 2 only, as 16.10 + * published by the Free Software Foundation. 16.11 + * 16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16.15 + * version 2 for more details (a copy is included in the LICENSE file that 16.16 + * accompanied this code). 16.17 + * 16.18 + * You should have received a copy of the GNU General Public License version 16.19 + * 2 along with this work; if not, write to the Free Software Foundation, 16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 16.21 + * 16.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 16.23 + * or visit www.oracle.com if you need additional information or have any 16.24 + * questions. 16.25 + * 16.26 + */ 16.27 + 16.28 +#include "precompiled.hpp" 16.29 +#include "gc_implementation/g1/g1Log.hpp" 16.30 +#include "gc_implementation/g1/g1StringDedup.hpp" 16.31 +#include "gc_implementation/g1/g1StringDedupTable.hpp" 16.32 +#include "gc_implementation/g1/g1StringDedupThread.hpp" 16.33 +#include "gc_implementation/g1/g1StringDedupQueue.hpp" 16.34 + 16.35 +G1StringDedupThread* G1StringDedupThread::_thread = NULL; 16.36 + 16.37 +G1StringDedupThread::G1StringDedupThread() : 16.38 + ConcurrentGCThread() { 16.39 + set_name("String Deduplication Thread"); 16.40 + create_and_start(); 16.41 +} 16.42 + 16.43 +G1StringDedupThread::~G1StringDedupThread() { 16.44 + ShouldNotReachHere(); 16.45 +} 16.46 + 16.47 +void G1StringDedupThread::create() { 16.48 + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); 16.49 + assert(_thread == NULL, "One string deduplication thread allowed"); 16.50 + _thread = new G1StringDedupThread(); 16.51 +} 16.52 + 16.53 +G1StringDedupThread* G1StringDedupThread::thread() { 16.54 + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); 16.55 + assert(_thread != NULL, "String deduplication thread not created"); 16.56 + return _thread; 16.57 +} 16.58 + 16.59 +void G1StringDedupThread::print_on(outputStream* st) const { 16.60 + st->print("\"%s\" ", name()); 16.61 + Thread::print_on(st); 16.62 + st->cr(); 16.63 +} 16.64 + 16.65 +void G1StringDedupThread::run() { 16.66 + G1StringDedupStat total_stat; 16.67 + 16.68 + initialize_in_thread(); 16.69 + wait_for_universe_init(); 16.70 + 16.71 + // Main loop 16.72 + for (;;) { 16.73 + G1StringDedupStat stat; 16.74 + 16.75 + stat.mark_idle(); 16.76 + 16.77 + // Wait for the queue to become non-empty 16.78 + G1StringDedupQueue::wait(); 16.79 + 16.80 + // Include this thread in safepoints 16.81 + stsJoin(); 16.82 + 16.83 + stat.mark_exec(); 16.84 + 16.85 + // Process the queue 16.86 + for (;;) { 16.87 + oop java_string = G1StringDedupQueue::pop(); 16.88 + if (java_string == NULL) { 16.89 + break; 16.90 + } 16.91 + 16.92 + G1StringDedupTable::deduplicate(java_string, stat); 16.93 + 16.94 + // Safepoint this thread if needed 16.95 + if (stsShouldYield()) { 16.96 + stat.mark_block(); 16.97 + stsYield(NULL); 16.98 + stat.mark_unblock(); 16.99 + } 16.100 + } 16.101 + 16.102 + G1StringDedupTable::trim_entry_cache(); 16.103 + 16.104 + stat.mark_done(); 16.105 + 16.106 + // Print statistics 16.107 + total_stat.add(stat); 16.108 + print(gclog_or_tty, stat, total_stat); 16.109 + 16.110 + // Exclude this thread from safepoints 16.111 + stsLeave(); 16.112 + } 16.113 + 16.114 + ShouldNotReachHere(); 16.115 +} 16.116 + 16.117 +void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { 16.118 + if (G1Log::fine() || PrintStringDeduplicationStatistics) { 16.119 + G1StringDedupStat::print_summary(st, last_stat, total_stat); 16.120 + if (PrintStringDeduplicationStatistics) { 16.121 + G1StringDedupStat::print_statistics(st, last_stat, false); 16.122 + G1StringDedupStat::print_statistics(st, total_stat, true); 16.123 + G1StringDedupTable::print_statistics(st); 16.124 + G1StringDedupQueue::print_statistics(st); 16.125 + } 16.126 + } 16.127 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp Mon Mar 24 14:23:02 2014 -0700 17.3 @@ -0,0 +1,56 @@ 17.4 +/* 17.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.7 + * 17.8 + * This code is free software; you can redistribute it and/or modify it 17.9 + * under the terms of the GNU General Public License version 2 only, as 17.10 + * published by the Free Software Foundation. 17.11 + * 17.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 17.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17.15 + * version 2 for more details (a copy is included in the LICENSE file that 17.16 + * accompanied this code). 17.17 + * 17.18 + * You should have received a copy of the GNU General Public License version 17.19 + * 2 along with this work; if not, write to the Free Software Foundation, 17.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17.21 + * 17.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 17.23 + * or visit www.oracle.com if you need additional information or have any 17.24 + * questions. 17.25 + * 17.26 + */ 17.27 + 17.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP 17.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP 17.30 + 17.31 +#include "gc_implementation/g1/g1StringDedupStat.hpp" 17.32 +#include "gc_implementation/shared/concurrentGCThread.hpp" 17.33 + 17.34 +// 17.35 +// The deduplication thread is where the actual deduplication occurs. It waits for 17.36 +// deduplication candidates to appear on the deduplication queue, removes them from 17.37 +// the queue and tries to deduplicate them. It uses the deduplication hashtable to 17.38 +// find identical, already existing, character arrays on the heap. The thread runs 17.39 +// concurrently with the Java application but participates in safepoints to allow 17.40 +// the GC to adjust and unlink oops from the deduplication queue and table. 17.41 +// 17.42 +class G1StringDedupThread: public ConcurrentGCThread { 17.43 +private: 17.44 + static G1StringDedupThread* _thread; 17.45 + 17.46 + G1StringDedupThread(); 17.47 + ~G1StringDedupThread(); 17.48 + 17.49 + void print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); 17.50 + 17.51 +public: 17.52 + static void create(); 17.53 + static G1StringDedupThread* thread(); 17.54 + 17.55 + virtual void run(); 17.56 + virtual void print_on(outputStream* st) const; 17.57 +}; 17.58 + 17.59 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
18.1 --- a/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Fri Feb 28 15:27:09 2014 +0100 18.2 +++ b/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Mon Mar 24 14:23:02 2014 -0700 18.3 @@ -1,5 +1,5 @@ 18.4 /* 18.5 - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 18.6 + * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 18.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.8 * 18.9 * This code is free software; you can redistribute it and/or modify it 18.10 @@ -30,10 +30,18 @@ 18.11 #include "utilities/stack.inline.hpp" 18.12 #include "utilities/macros.hpp" 18.13 #if INCLUDE_ALL_GCS 18.14 +#include "gc_implementation/g1/g1StringDedup.hpp" 18.15 #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" 18.16 #endif // INCLUDE_ALL_GCS 18.17 18.18 inline void MarkSweep::mark_object(oop obj) { 18.19 +#if INCLUDE_ALL_GCS 18.20 + if (G1StringDedup::is_enabled()) { 18.21 + // We must enqueue the object before it is marked 18.22 + // as we otherwise can't read the object's age. 18.23 + G1StringDedup::enqueue_from_mark(obj); 18.24 + } 18.25 +#endif 18.26 // some marks may contain information we need to preserve so we store them away 18.27 // and overwrite the mark. We'll restore it at the end of markSweep. 18.28 markOop mark = obj->mark();
19.1 --- a/src/share/vm/runtime/arguments.cpp Fri Feb 28 15:27:09 2014 +0100 19.2 +++ b/src/share/vm/runtime/arguments.cpp Mon Mar 24 14:23:02 2014 -0700 19.3 @@ -2217,6 +2217,8 @@ 19.4 "G1ConcRSHotCardLimit"); 19.5 status = status && verify_interval(G1ConcRSLogCacheSize, 0, 31, 19.6 "G1ConcRSLogCacheSize"); 19.7 + status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age, 19.8 + "StringDeduplicationAgeThreshold"); 19.9 } 19.10 if (UseConcMarkSweepGC) { 19.11 status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills");
20.1 --- a/src/share/vm/runtime/globals.hpp Fri Feb 28 15:27:09 2014 +0100 20.2 +++ b/src/share/vm/runtime/globals.hpp Mon Mar 24 14:23:02 2014 -0700 20.3 @@ -3812,6 +3812,22 @@ 20.4 experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \ 20.5 "Number of buckets in the JVM internal Symbol table") \ 20.6 \ 20.7 + product(bool, UseStringDeduplication, false, \ 20.8 + "Use string deduplication") \ 20.9 + \ 20.10 + product(bool, PrintStringDeduplicationStatistics, false, \ 20.11 + "Print string deduplication statistics") \ 20.12 + \ 20.13 + product(uintx, StringDeduplicationAgeThreshold, 3, \ 20.14 + "A string must reach this age (or be promoted to an old region) " \ 20.15 + "to be considered for deduplication") \ 20.16 + \ 20.17 + diagnostic(bool, StringDeduplicationResizeALot, false, \ 20.18 + "Force table resize every time the table is scanned") \ 20.19 + \ 20.20 + diagnostic(bool, StringDeduplicationRehashALot, false, \ 20.21 + "Force table rehash every time the table is scanned") \ 20.22 + \ 20.23 develop(bool, TraceDefaultMethods, false, \ 20.24 "Trace the default method processing steps") \ 20.25 \
21.1 --- a/src/share/vm/runtime/mutexLocker.cpp Fri Feb 28 15:27:09 2014 +0100 21.2 +++ b/src/share/vm/runtime/mutexLocker.cpp Mon Mar 24 14:23:02 2014 -0700 21.3 @@ -1,5 +1,5 @@ 21.4 /* 21.5 - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 21.6 + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 21.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.8 * 21.9 * This code is free software; you can redistribute it and/or modify it 21.10 @@ -58,6 +58,8 @@ 21.11 Mutex* VtableStubs_lock = NULL; 21.12 Mutex* SymbolTable_lock = NULL; 21.13 Mutex* StringTable_lock = NULL; 21.14 +Monitor* StringDedupQueue_lock = NULL; 21.15 +Mutex* StringDedupTable_lock = NULL; 21.16 Mutex* CodeCache_lock = NULL; 21.17 Mutex* MethodData_lock = NULL; 21.18 Mutex* RetData_lock = NULL; 21.19 @@ -196,6 +198,9 @@ 21.20 def(MMUTracker_lock , Mutex , leaf , true ); 21.21 def(HotCardCache_lock , Mutex , special , true ); 21.22 def(EvacFailureStack_lock , Mutex , nonleaf , true ); 21.23 + 21.24 + def(StringDedupQueue_lock , Monitor, leaf, true ); 21.25 + def(StringDedupTable_lock , Mutex , leaf, true ); 21.26 } 21.27 def(ParGCRareEvent_lock , Mutex , leaf , true ); 21.28 def(DerivedPointerTableGC_lock , Mutex, leaf, true );
22.1 --- a/src/share/vm/runtime/mutexLocker.hpp Fri Feb 28 15:27:09 2014 +0100 22.2 +++ b/src/share/vm/runtime/mutexLocker.hpp Mon Mar 24 14:23:02 2014 -0700 22.3 @@ -1,5 +1,5 @@ 22.4 /* 22.5 - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 22.6 + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 22.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 22.8 * 22.9 * This code is free software; you can redistribute it and/or modify it 22.10 @@ -63,6 +63,8 @@ 22.11 extern Mutex* VtableStubs_lock; // a lock on the VtableStubs 22.12 extern Mutex* SymbolTable_lock; // a lock on the symbol table 22.13 extern Mutex* StringTable_lock; // a lock on the interned string table 22.14 +extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue 22.15 +extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table 22.16 extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx 22.17 extern Mutex* MethodData_lock; // a lock on installation of method data 22.18 extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
23.1 --- a/test/gc/g1/TestGCLogMessages.java Fri Feb 28 15:27:09 2014 +0100 23.2 +++ b/test/gc/g1/TestGCLogMessages.java Mon Mar 24 14:23:02 2014 -0700 23.3 @@ -49,11 +49,13 @@ 23.4 23.5 output.shouldNotContain("[Redirty Cards"); 23.6 output.shouldNotContain("[Code Root Purge"); 23.7 + output.shouldNotContain("[String Dedup Fixup"); 23.8 output.shouldNotContain("[Young Free CSet"); 23.9 output.shouldNotContain("[Non-Young Free CSet"); 23.10 output.shouldHaveExitValue(0); 23.11 23.12 pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", 23.13 + "-XX:+UseStringDeduplication", 23.14 "-Xmx10M", 23.15 "-XX:+PrintGCDetails", 23.16 GCTest.class.getName()); 23.17 @@ -62,11 +64,13 @@ 23.18 23.19 output.shouldContain("[Redirty Cards"); 23.20 output.shouldContain("[Code Root Purge"); 23.21 + output.shouldContain("[String Dedup Fixup"); 23.22 output.shouldNotContain("[Young Free CSet"); 23.23 output.shouldNotContain("[Non-Young Free CSet"); 23.24 output.shouldHaveExitValue(0); 23.25 23.26 pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", 23.27 + "-XX:+UseStringDeduplication", 23.28 "-Xmx10M", 23.29 "-XX:+PrintGCDetails", 23.30 "-XX:+UnlockExperimentalVMOptions", 23.31 @@ -77,6 +81,7 @@ 23.32 23.33 output.shouldContain("[Redirty Cards"); 23.34 output.shouldContain("[Code Root Purge"); 23.35 + output.shouldContain("[String Dedup Fixup"); 23.36 output.shouldContain("[Young Free CSet"); 23.37 output.shouldContain("[Non-Young Free CSet"); 23.38
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/test/gc/g1/TestStringDeduplicationAgeThreshold.java Mon Mar 24 14:23:02 2014 -0700 24.3 @@ -0,0 +1,36 @@ 24.4 +/* 24.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 24.7 + * 24.8 + * This code is free software; you can redistribute it and/or modify it 24.9 + * under the terms of the GNU General Public License version 2 only, as 24.10 + * published by the Free Software Foundation. 24.11 + * 24.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 24.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 24.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24.15 + * version 2 for more details (a copy is included in the LICENSE file that 24.16 + * accompanied this code). 24.17 + * 24.18 + * You should have received a copy of the GNU General Public License version 24.19 + * 2 along with this work; if not, write to the Free Software Foundation, 24.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 24.21 + * 24.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24.23 + * or visit www.oracle.com if you need additional information or have any 24.24 + * questions. 24.25 + */ 24.26 + 24.27 +/* 24.28 + * @test TestStringDeduplicationAgeThreshold 24.29 + * @summary Test string deduplication age threshold 24.30 + * @bug 8029075 24.31 + * @key gc 24.32 + * @library /testlibrary 24.33 + */ 24.34 + 24.35 +public class TestStringDeduplicationAgeThreshold { 24.36 + public static void main(String[] args) throws Exception { 24.37 + TestStringDeduplicationTools.testAgeThreshold(); 24.38 + } 24.39 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/test/gc/g1/TestStringDeduplicationFullGC.java Mon Mar 24 14:23:02 2014 -0700 25.3 @@ -0,0 +1,36 @@ 25.4 +/* 25.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 25.7 + * 25.8 + * This code is free software; you can redistribute it and/or modify it 25.9 + * under the terms of the GNU General Public License version 2 only, as 25.10 + * published by the Free Software Foundation. 25.11 + * 25.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 25.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 25.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25.15 + * version 2 for more details (a copy is included in the LICENSE file that 25.16 + * accompanied this code). 25.17 + * 25.18 + * You should have received a copy of the GNU General Public License version 25.19 + * 2 along with this work; if not, write to the Free Software Foundation, 25.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 25.21 + * 25.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 25.23 + * or visit www.oracle.com if you need additional information or have any 25.24 + * questions. 25.25 + */ 25.26 + 25.27 +/* 25.28 + * @test TestStringDeduplicationFullGC 25.29 + * @summary Test string deduplication during full GC 25.30 + * @bug 8029075 25.31 + * @key gc 25.32 + * @library /testlibrary 25.33 + */ 25.34 + 25.35 +public class TestStringDeduplicationFullGC { 25.36 + public static void main(String[] args) throws Exception { 25.37 + TestStringDeduplicationTools.testFullGC(); 25.38 + } 25.39 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/test/gc/g1/TestStringDeduplicationInterned.java Mon Mar 24 14:23:02 2014 -0700 26.3 @@ -0,0 +1,36 @@ 26.4 +/* 26.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 26.7 + * 26.8 + * This code is free software; you can redistribute it and/or modify it 26.9 + * under the terms of the GNU General Public License version 2 only, as 26.10 + * published by the Free Software Foundation. 26.11 + * 26.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 26.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 26.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26.15 + * version 2 for more details (a copy is included in the LICENSE file that 26.16 + * accompanied this code). 26.17 + * 26.18 + * You should have received a copy of the GNU General Public License version 26.19 + * 2 along with this work; if not, write to the Free Software Foundation, 26.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26.21 + * 26.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 26.23 + * or visit www.oracle.com if you need additional information or have any 26.24 + * questions. 26.25 + */ 26.26 + 26.27 +/* 26.28 + * @test TestStringDeduplicationInterned 26.29 + * @summary Test string deduplication of interned strings 26.30 + * @bug 8029075 26.31 + * @key gc 26.32 + * @library /testlibrary 26.33 + */ 26.34 + 26.35 +public class TestStringDeduplicationInterned { 26.36 + public static void main(String[] args) throws Exception { 26.37 + TestStringDeduplicationTools.testInterned(); 26.38 + } 26.39 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/test/gc/g1/TestStringDeduplicationMemoryUsage.java Mon Mar 24 14:23:02 2014 -0700 27.3 @@ -0,0 +1,36 @@ 27.4 +/* 27.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 27.7 + * 27.8 + * This code is free software; you can redistribute it and/or modify it 27.9 + * under the terms of the GNU General Public License version 2 only, as 27.10 + * published by the Free Software Foundation. 27.11 + * 27.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 27.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 27.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27.15 + * version 2 for more details (a copy is included in the LICENSE file that 27.16 + * accompanied this code). 27.17 + * 27.18 + * You should have received a copy of the GNU General Public License version 27.19 + * 2 along with this work; if not, write to the Free Software Foundation, 27.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 27.21 + * 27.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 27.23 + * or visit www.oracle.com if you need additional information or have any 27.24 + * questions. 27.25 + */ 27.26 + 27.27 +/* 27.28 + * @test TestStringDeduplicationMemoryUsage 27.29 + * @summary Test string deduplication memory usage 27.30 + * @bug 8029075 27.31 + * @key gc 27.32 + * @library /testlibrary 27.33 + */ 27.34 + 27.35 +public class TestStringDeduplicationMemoryUsage { 27.36 + public static void main(String[] args) throws Exception { 27.37 + TestStringDeduplicationTools.testMemoryUsage(); 27.38 + } 27.39 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/test/gc/g1/TestStringDeduplicationPrintOptions.java Mon Mar 24 14:23:02 2014 -0700 28.3 @@ -0,0 +1,36 @@ 28.4 +/* 28.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 28.7 + * 28.8 + * This code is free software; you can redistribute it and/or modify it 28.9 + * under the terms of the GNU General Public License version 2 only, as 28.10 + * published by the Free Software Foundation. 28.11 + * 28.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 28.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 28.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28.15 + * version 2 for more details (a copy is included in the LICENSE file that 28.16 + * accompanied this code). 28.17 + * 28.18 + * You should have received a copy of the GNU General Public License version 28.19 + * 2 along with this work; if not, write to the Free Software Foundation, 28.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 28.21 + * 28.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28.23 + * or visit www.oracle.com if you need additional information or have any 28.24 + * questions. 28.25 + */ 28.26 + 28.27 +/* 28.28 + * @test TestStringDeduplicationPrintOptions 28.29 + * @summary Test string deduplication print options 28.30 + * @bug 8029075 28.31 + * @key gc 28.32 + * @library /testlibrary 28.33 + */ 28.34 + 28.35 +public class TestStringDeduplicationPrintOptions { 28.36 + public static void main(String[] args) throws Exception { 28.37 + TestStringDeduplicationTools.testPrintOptions(); 28.38 + } 28.39 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/test/gc/g1/TestStringDeduplicationTableRehash.java Mon Mar 24 14:23:02 2014 -0700 29.3 @@ -0,0 +1,36 @@ 29.4 +/* 29.5 + * Copyright (c) 2014, 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 + * @test TestStringDeduplicationTableRehash 29.29 + * @summary Test string deduplication table rehash 29.30 + * @bug 8029075 29.31 + * @key gc 29.32 + * @library /testlibrary 29.33 + */ 29.34 + 29.35 +public class TestStringDeduplicationTableRehash { 29.36 + public static void main(String[] args) throws Exception { 29.37 + TestStringDeduplicationTools.testTableRehash(); 29.38 + } 29.39 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/test/gc/g1/TestStringDeduplicationTableResize.java Mon Mar 24 14:23:02 2014 -0700 30.3 @@ -0,0 +1,36 @@ 30.4 +/* 30.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 30.7 + * 30.8 + * This code is free software; you can redistribute it and/or modify it 30.9 + * under the terms of the GNU General Public License version 2 only, as 30.10 + * published by the Free Software Foundation. 30.11 + * 30.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 30.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 30.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30.15 + * version 2 for more details (a copy is included in the LICENSE file that 30.16 + * accompanied this code). 30.17 + * 30.18 + * You should have received a copy of the GNU General Public License version 30.19 + * 2 along with this work; if not, write to the Free Software Foundation, 30.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 30.21 + * 30.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 30.23 + * or visit www.oracle.com if you need additional information or have any 30.24 + * questions. 30.25 + */ 30.26 + 30.27 +/* 30.28 + * @test TestStringDeduplicationTableResize 30.29 + * @summary Test string deduplication table resize 30.30 + * @bug 8029075 30.31 + * @key gc 30.32 + * @library /testlibrary 30.33 + */ 30.34 + 30.35 +public class TestStringDeduplicationTableResize { 30.36 + public static void main(String[] args) throws Exception { 30.37 + TestStringDeduplicationTools.testTableResize(); 30.38 + } 30.39 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/test/gc/g1/TestStringDeduplicationTools.java Mon Mar 24 14:23:02 2014 -0700 31.3 @@ -0,0 +1,512 @@ 31.4 +/* 31.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 31.7 + * 31.8 + * This code is free software; you can redistribute it and/or modify it 31.9 + * under the terms of the GNU General Public License version 2 only, as 31.10 + * published by the Free Software Foundation. 31.11 + * 31.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 31.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 31.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31.15 + * version 2 for more details (a copy is included in the LICENSE file that 31.16 + * accompanied this code). 31.17 + * 31.18 + * You should have received a copy of the GNU General Public License version 31.19 + * 2 along with this work; if not, write to the Free Software Foundation, 31.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 31.21 + * 31.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 31.23 + * or visit www.oracle.com if you need additional information or have any 31.24 + * questions. 31.25 + */ 31.26 + 31.27 +/* 31.28 + * Common code for string deduplication tests 31.29 + */ 31.30 + 31.31 +import java.lang.management.*; 31.32 +import java.lang.reflect.*; 31.33 +import java.security.*; 31.34 +import java.util.*; 31.35 +import com.oracle.java.testlibrary.*; 31.36 +import sun.misc.*; 31.37 + 31.38 +class TestStringDeduplicationTools { 31.39 + private static final String YoungGC = "YoungGC"; 31.40 + private static final String FullGC = "FullGC"; 31.41 + 31.42 + private static final int Xmn = 50; // MB 31.43 + private static final int Xms = 100; // MB 31.44 + private static final int Xmx = 100; // MB 31.45 + private static final int MB = 1024 * 1024; 31.46 + private static final int StringLength = 50; 31.47 + 31.48 + private static Field valueField; 31.49 + private static Unsafe unsafe; 31.50 + private static byte[] dummy; 31.51 + 31.52 + static { 31.53 + try { 31.54 + Field field = Unsafe.class.getDeclaredField("theUnsafe"); 31.55 + field.setAccessible(true); 31.56 + unsafe = (Unsafe)field.get(null); 31.57 + 31.58 + valueField = String.class.getDeclaredField("value"); 31.59 + valueField.setAccessible(true); 31.60 + } catch (Exception e) { 31.61 + throw new RuntimeException(e); 31.62 + } 31.63 + } 31.64 + 31.65 + private static Object getValue(String string) { 31.66 + try { 31.67 + return valueField.get(string); 31.68 + } catch (Exception e) { 31.69 + throw new RuntimeException(e); 31.70 + } 31.71 + } 31.72 + 31.73 + private static void doFullGc(int numberOfTimes) { 31.74 + for (int i = 0; i < numberOfTimes; i++) { 31.75 + System.out.println("Begin: Full GC " + (i + 1) + "/" + numberOfTimes); 31.76 + System.gc(); 31.77 + System.out.println("End: Full GC " + (i + 1) + "/" + numberOfTimes); 31.78 + } 31.79 + } 31.80 + 31.81 + private static void doYoungGc(int numberOfTimes) { 31.82 + // Provoke at least numberOfTimes young GCs 31.83 + final int objectSize = 128; 31.84 + final int maxObjectInYoung = (Xmn * MB) / objectSize; 31.85 + for (int i = 0; i < numberOfTimes; i++) { 31.86 + System.out.println("Begin: Young GC " + (i + 1) + "/" + numberOfTimes); 31.87 + for (int j = 0; j < maxObjectInYoung + 1; j++) { 31.88 + dummy = new byte[objectSize]; 31.89 + } 31.90 + System.out.println("End: Young GC " + (i + 1) + "/" + numberOfTimes); 31.91 + } 31.92 + } 31.93 + 31.94 + private static void forceDeduplication(int ageThreshold, String gcType) { 31.95 + // Force deduplication to happen by either causing a FullGC or a YoungGC. 31.96 + // We do several collections to also provoke a situation where the the 31.97 + // deduplication thread needs to yield while processing the queue. This 31.98 + // also tests that the references in the deduplication queue are adjusted 31.99 + // accordingly. 31.100 + if (gcType.equals(FullGC)) { 31.101 + doFullGc(3); 31.102 + } else { 31.103 + doYoungGc(ageThreshold + 3); 31.104 + } 31.105 + } 31.106 + 31.107 + private static String generateString(int id) { 31.108 + StringBuilder builder = new StringBuilder(StringLength); 31.109 + 31.110 + builder.append("DeduplicationTestString:" + id + ":"); 31.111 + 31.112 + while (builder.length() < StringLength) { 31.113 + builder.append('X'); 31.114 + } 31.115 + 31.116 + return builder.toString(); 31.117 + } 31.118 + 31.119 + private static ArrayList<String> createStrings(int total, int unique) { 31.120 + System.out.println("Creating strings: total=" + total + ", unique=" + unique); 31.121 + if (total % unique != 0) { 31.122 + throw new RuntimeException("Total must be divisible by unique"); 31.123 + } 31.124 + 31.125 + ArrayList<String> list = new ArrayList<String>(total); 31.126 + for (int j = 0; j < total / unique; j++) { 31.127 + for (int i = 0; i < unique; i++) { 31.128 + list.add(generateString(i)); 31.129 + } 31.130 + } 31.131 + 31.132 + return list; 31.133 + } 31.134 + 31.135 + private static void verifyStrings(ArrayList<String> list, int uniqueExpected) { 31.136 + for (;;) { 31.137 + // Check number of deduplicated strings 31.138 + ArrayList<Object> unique = new ArrayList<Object>(uniqueExpected); 31.139 + for (String string: list) { 31.140 + Object value = getValue(string); 31.141 + boolean uniqueValue = true; 31.142 + for (Object obj: unique) { 31.143 + if (obj == value) { 31.144 + uniqueValue = false; 31.145 + break; 31.146 + } 31.147 + } 31.148 + 31.149 + if (uniqueValue) { 31.150 + unique.add(value); 31.151 + } 31.152 + } 31.153 + 31.154 + System.out.println("Verifying strings: total=" + list.size() + 31.155 + ", uniqueFound=" + unique.size() + 31.156 + ", uniqueExpected=" + uniqueExpected); 31.157 + 31.158 + if (unique.size() == uniqueExpected) { 31.159 + System.out.println("Deduplication completed"); 31.160 + break; 31.161 + } else { 31.162 + System.out.println("Deduplication not completed, waiting..."); 31.163 + 31.164 + // Give the deduplication thread time to complete 31.165 + try { 31.166 + Thread.sleep(1000); 31.167 + } catch (Exception e) { 31.168 + throw new RuntimeException(e); 31.169 + } 31.170 + } 31.171 + } 31.172 + } 31.173 + 31.174 + private static OutputAnalyzer runTest(String... extraArgs) throws Exception { 31.175 + String[] defaultArgs = new String[] { 31.176 + "-Xmn" + Xmn + "m", 31.177 + "-Xms" + Xms + "m", 31.178 + "-Xmx" + Xmx + "m", 31.179 + "-XX:+UseG1GC", 31.180 + "-XX:+UnlockDiagnosticVMOptions", 31.181 + "-XX:+VerifyAfterGC" // Always verify after GC 31.182 + }; 31.183 + 31.184 + ArrayList<String> args = new ArrayList<String>(); 31.185 + args.addAll(Arrays.asList(defaultArgs)); 31.186 + args.addAll(Arrays.asList(extraArgs)); 31.187 + 31.188 + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()])); 31.189 + OutputAnalyzer output = new OutputAnalyzer(pb.start()); 31.190 + System.err.println(output.getStderr()); 31.191 + System.out.println(output.getStdout()); 31.192 + return output; 31.193 + } 31.194 + 31.195 + private static class DeduplicationTest { 31.196 + public static void main(String[] args) { 31.197 + System.out.println("Begin: DeduplicationTest"); 31.198 + 31.199 + final int numberOfStrings = Integer.parseUnsignedInt(args[0]); 31.200 + final int numberOfUniqueStrings = Integer.parseUnsignedInt(args[1]); 31.201 + final int ageThreshold = Integer.parseUnsignedInt(args[2]); 31.202 + final String gcType = args[3]; 31.203 + 31.204 + ArrayList<String> list = createStrings(numberOfStrings, numberOfUniqueStrings); 31.205 + forceDeduplication(ageThreshold, gcType); 31.206 + verifyStrings(list, numberOfUniqueStrings); 31.207 + 31.208 + System.out.println("End: DeduplicationTest"); 31.209 + } 31.210 + 31.211 + public static OutputAnalyzer run(int numberOfStrings, int ageThreshold, String gcType, String... extraArgs) throws Exception { 31.212 + String[] defaultArgs = new String[] { 31.213 + "-XX:+UseStringDeduplication", 31.214 + "-XX:StringDeduplicationAgeThreshold=" + ageThreshold, 31.215 + DeduplicationTest.class.getName(), 31.216 + "" + numberOfStrings, 31.217 + "" + numberOfStrings / 2, 31.218 + "" + ageThreshold, 31.219 + gcType 31.220 + }; 31.221 + 31.222 + ArrayList<String> args = new ArrayList<String>(); 31.223 + args.addAll(Arrays.asList(extraArgs)); 31.224 + args.addAll(Arrays.asList(defaultArgs)); 31.225 + 31.226 + return runTest(args.toArray(new String[args.size()])); 31.227 + } 31.228 + } 31.229 + 31.230 + private static class InternedTest { 31.231 + public static void main(String[] args) { 31.232 + // This test verifies that interned strings are always 31.233 + // deduplicated when being interned, and never after 31.234 + // being interned. 31.235 + 31.236 + System.out.println("Begin: InternedTest"); 31.237 + 31.238 + final int ageThreshold = Integer.parseUnsignedInt(args[0]); 31.239 + final String baseString = "DeduplicationTestString:" + InternedTest.class.getName(); 31.240 + 31.241 + // Create duplicate of baseString 31.242 + StringBuilder sb1 = new StringBuilder(baseString); 31.243 + String dupString1 = sb1.toString(); 31.244 + if (getValue(dupString1) == getValue(baseString)) { 31.245 + throw new RuntimeException("Values should not match"); 31.246 + } 31.247 + 31.248 + // Force baseString to be inspected for deduplication 31.249 + // and be inserted into the deduplication hashtable. 31.250 + forceDeduplication(ageThreshold, FullGC); 31.251 + 31.252 + // Wait for deduplication to occur 31.253 + while (getValue(dupString1) != getValue(baseString)) { 31.254 + System.out.println("Waiting..."); 31.255 + try { 31.256 + Thread.sleep(100); 31.257 + } catch (Exception e) { 31.258 + throw new RuntimeException(e); 31.259 + } 31.260 + } 31.261 + 31.262 + // Create a new duplicate of baseString 31.263 + StringBuilder sb2 = new StringBuilder(baseString); 31.264 + String dupString2 = sb2.toString(); 31.265 + if (getValue(dupString2) == getValue(baseString)) { 31.266 + throw new RuntimeException("Values should not match"); 31.267 + } 31.268 + 31.269 + // Intern the new duplicate 31.270 + Object beforeInternedValue = getValue(dupString2); 31.271 + String internedString = dupString2.intern(); 31.272 + if (internedString != dupString2) { 31.273 + throw new RuntimeException("String should match"); 31.274 + } 31.275 + if (getValue(internedString) != getValue(baseString)) { 31.276 + throw new RuntimeException("Values should match"); 31.277 + } 31.278 + 31.279 + // Check original value of interned string, to make sure 31.280 + // deduplication happened on the interned string and not 31.281 + // on the base string 31.282 + if (beforeInternedValue == getValue(baseString)) { 31.283 + throw new RuntimeException("Values should not match"); 31.284 + } 31.285 + 31.286 + System.out.println("End: InternedTest"); 31.287 + } 31.288 + 31.289 + public static OutputAnalyzer run() throws Exception { 31.290 + return runTest("-XX:+PrintGC", 31.291 + "-XX:+PrintGCDetails", 31.292 + "-XX:+UseStringDeduplication", 31.293 + "-XX:+PrintStringDeduplicationStatistics", 31.294 + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold, 31.295 + InternedTest.class.getName(), 31.296 + "" + DefaultAgeThreshold); 31.297 + } 31.298 + } 31.299 + 31.300 + private static class MemoryUsageTest { 31.301 + public static void main(String[] args) { 31.302 + System.out.println("Begin: MemoryUsageTest"); 31.303 + 31.304 + final boolean useStringDeduplication = Boolean.parseBoolean(args[0]); 31.305 + final int numberOfStrings = LargeNumberOfStrings; 31.306 + final int numberOfUniqueStrings = 1; 31.307 + 31.308 + ArrayList<String> list = createStrings(numberOfStrings, numberOfUniqueStrings); 31.309 + forceDeduplication(DefaultAgeThreshold, FullGC); 31.310 + 31.311 + if (useStringDeduplication) { 31.312 + verifyStrings(list, numberOfUniqueStrings); 31.313 + } 31.314 + 31.315 + System.gc(); 31.316 + System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); 31.317 + 31.318 + System.out.println("End: MemoryUsageTest"); 31.319 + } 31.320 + 31.321 + public static OutputAnalyzer run(boolean useStringDeduplication) throws Exception { 31.322 + String[] extraArgs = new String[0]; 31.323 + 31.324 + if (useStringDeduplication) { 31.325 + extraArgs = new String[] { 31.326 + "-XX:+UseStringDeduplication", 31.327 + "-XX:+PrintStringDeduplicationStatistics", 31.328 + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold 31.329 + }; 31.330 + } 31.331 + 31.332 + String[] defaultArgs = new String[] { 31.333 + "-XX:+PrintGC", 31.334 + "-XX:+PrintGCDetails", 31.335 + MemoryUsageTest.class.getName(), 31.336 + "" + useStringDeduplication 31.337 + }; 31.338 + 31.339 + ArrayList<String> args = new ArrayList<String>(); 31.340 + args.addAll(Arrays.asList(extraArgs)); 31.341 + args.addAll(Arrays.asList(defaultArgs)); 31.342 + 31.343 + return runTest(args.toArray(new String[args.size()])); 31.344 + } 31.345 + } 31.346 + 31.347 + /* 31.348 + * Tests 31.349 + */ 31.350 + 31.351 + private static final int LargeNumberOfStrings = 10000; 31.352 + private static final int SmallNumberOfStrings = 10; 31.353 + 31.354 + private static final int MaxAgeThreshold = 15; 31.355 + private static final int DefaultAgeThreshold = 3; 31.356 + private static final int MinAgeThreshold = 1; 31.357 + 31.358 + private static final int TooLowAgeThreshold = MinAgeThreshold - 1; 31.359 + private static final int TooHighAgeThreshold = MaxAgeThreshold + 1; 31.360 + 31.361 + public static void testYoungGC() throws Exception { 31.362 + // Do young GC to age strings to provoke deduplication 31.363 + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, 31.364 + DefaultAgeThreshold, 31.365 + YoungGC, 31.366 + "-XX:+PrintGC", 31.367 + "-XX:+PrintStringDeduplicationStatistics"); 31.368 + output.shouldNotContain("Full GC"); 31.369 + output.shouldContain("GC pause (G1 Evacuation Pause) (young)"); 31.370 + output.shouldContain("GC concurrent-string-deduplication"); 31.371 + output.shouldContain("Deduplicated:"); 31.372 + output.shouldHaveExitValue(0); 31.373 + } 31.374 + 31.375 + public static void testFullGC() throws Exception { 31.376 + // Do full GC to age strings to provoke deduplication 31.377 + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, 31.378 + DefaultAgeThreshold, 31.379 + FullGC, 31.380 + "-XX:+PrintGC", 31.381 + "-XX:+PrintStringDeduplicationStatistics"); 31.382 + output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)"); 31.383 + output.shouldContain("Full GC"); 31.384 + output.shouldContain("GC concurrent-string-deduplication"); 31.385 + output.shouldContain("Deduplicated:"); 31.386 + output.shouldHaveExitValue(0); 31.387 + } 31.388 + 31.389 + public static void testTableResize() throws Exception { 31.390 + // Test with StringDeduplicationResizeALot 31.391 + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, 31.392 + DefaultAgeThreshold, 31.393 + YoungGC, 31.394 + "-XX:+PrintGC", 31.395 + "-XX:+PrintStringDeduplicationStatistics", 31.396 + "-XX:+StringDeduplicationResizeALot"); 31.397 + output.shouldContain("GC concurrent-string-deduplication"); 31.398 + output.shouldContain("Deduplicated:"); 31.399 + output.shouldNotContain("Resize Count: 0"); 31.400 + output.shouldHaveExitValue(0); 31.401 + } 31.402 + 31.403 + public static void testTableRehash() throws Exception { 31.404 + // Test with StringDeduplicationRehashALot 31.405 + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, 31.406 + DefaultAgeThreshold, 31.407 + YoungGC, 31.408 + "-XX:+PrintGC", 31.409 + "-XX:+PrintStringDeduplicationStatistics", 31.410 + "-XX:+StringDeduplicationRehashALot"); 31.411 + output.shouldContain("GC concurrent-string-deduplication"); 31.412 + output.shouldContain("Deduplicated:"); 31.413 + output.shouldNotContain("Rehash Count: 0"); 31.414 + output.shouldNotContain("Hash Seed: 0x0"); 31.415 + output.shouldHaveExitValue(0); 31.416 + } 31.417 + 31.418 + public static void testAgeThreshold() throws Exception { 31.419 + OutputAnalyzer output; 31.420 + 31.421 + // Test with max age theshold 31.422 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.423 + MaxAgeThreshold, 31.424 + YoungGC, 31.425 + "-XX:+PrintGC", 31.426 + "-XX:+PrintStringDeduplicationStatistics"); 31.427 + output.shouldContain("GC concurrent-string-deduplication"); 31.428 + output.shouldContain("Deduplicated:"); 31.429 + output.shouldHaveExitValue(0); 31.430 + 31.431 + // Test with min age theshold 31.432 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.433 + MinAgeThreshold, 31.434 + YoungGC, 31.435 + "-XX:+PrintGC", 31.436 + "-XX:+PrintStringDeduplicationStatistics"); 31.437 + output.shouldContain("GC concurrent-string-deduplication"); 31.438 + output.shouldContain("Deduplicated:"); 31.439 + output.shouldHaveExitValue(0); 31.440 + 31.441 + // Test with too low age threshold 31.442 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.443 + TooLowAgeThreshold, 31.444 + YoungGC); 31.445 + output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold + 31.446 + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); 31.447 + output.shouldHaveExitValue(1); 31.448 + 31.449 + // Test with too high age threshold 31.450 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.451 + TooHighAgeThreshold, 31.452 + YoungGC); 31.453 + output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold + 31.454 + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); 31.455 + output.shouldHaveExitValue(1); 31.456 + } 31.457 + 31.458 + public static void testPrintOptions() throws Exception { 31.459 + OutputAnalyzer output; 31.460 + 31.461 + // Test without PrintGC and without PrintStringDeduplicationStatistics 31.462 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.463 + DefaultAgeThreshold, 31.464 + YoungGC); 31.465 + output.shouldNotContain("GC concurrent-string-deduplication"); 31.466 + output.shouldNotContain("Deduplicated:"); 31.467 + output.shouldHaveExitValue(0); 31.468 + 31.469 + // Test with PrintGC but without PrintStringDeduplicationStatistics 31.470 + output = DeduplicationTest.run(SmallNumberOfStrings, 31.471 + DefaultAgeThreshold, 31.472 + YoungGC, 31.473 + "-XX:+PrintGC"); 31.474 + output.shouldContain("GC concurrent-string-deduplication"); 31.475 + output.shouldNotContain("Deduplicated:"); 31.476 + output.shouldHaveExitValue(0); 31.477 + } 31.478 + 31.479 + public static void testInterned() throws Exception { 31.480 + // Test that interned strings are deduplicated before being interned 31.481 + OutputAnalyzer output = InternedTest.run(); 31.482 + output.shouldHaveExitValue(0); 31.483 + } 31.484 + 31.485 + public static void testMemoryUsage() throws Exception { 31.486 + // Test that memory usage is reduced after deduplication 31.487 + OutputAnalyzer output; 31.488 + final String usagePattern = "Heap Memory Usage: (\\d+)"; 31.489 + 31.490 + // Run without deduplication 31.491 + output = MemoryUsageTest.run(false); 31.492 + output.shouldHaveExitValue(0); 31.493 + final long memoryUsageWithoutDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); 31.494 + 31.495 + // Run with deduplication 31.496 + output = MemoryUsageTest.run(true); 31.497 + output.shouldHaveExitValue(0); 31.498 + final long memoryUsageWithDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); 31.499 + 31.500 + // Calculate expected memory usage with deduplication enabled. This calculation does 31.501 + // not take alignment and padding into account, so it's a conservative estimate. 31.502 + final long sizeOfChar = 2; // bytes 31.503 + final long bytesSaved = (LargeNumberOfStrings - 1) * (StringLength * sizeOfChar + unsafe.ARRAY_CHAR_BASE_OFFSET); 31.504 + final long memoryUsageWithDedupExpected = memoryUsageWithoutDedup - bytesSaved; 31.505 + 31.506 + System.out.println("Memory usage summary:"); 31.507 + System.out.println(" memoryUsageWithoutDedup: " + memoryUsageWithoutDedup); 31.508 + System.out.println(" memoryUsageWithDedup: " + memoryUsageWithDedup); 31.509 + System.out.println(" memoryUsageWithDedupExpected: " + memoryUsageWithDedupExpected); 31.510 + 31.511 + if (memoryUsageWithDedup > memoryUsageWithDedupExpected) { 31.512 + throw new Exception("Unexpected memory usage, memoryUsageWithDedup should less or equal to memoryUsageWithDedupExpected"); 31.513 + } 31.514 + } 31.515 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/test/gc/g1/TestStringDeduplicationYoungGC.java Mon Mar 24 14:23:02 2014 -0700 32.3 @@ -0,0 +1,36 @@ 32.4 +/* 32.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 32.7 + * 32.8 + * This code is free software; you can redistribute it and/or modify it 32.9 + * under the terms of the GNU General Public License version 2 only, as 32.10 + * published by the Free Software Foundation. 32.11 + * 32.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 32.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 32.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32.15 + * version 2 for more details (a copy is included in the LICENSE file that 32.16 + * accompanied this code). 32.17 + * 32.18 + * You should have received a copy of the GNU General Public License version 32.19 + * 2 along with this work; if not, write to the Free Software Foundation, 32.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 32.21 + * 32.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 32.23 + * or visit www.oracle.com if you need additional information or have any 32.24 + * questions. 32.25 + */ 32.26 + 32.27 +/* 32.28 + * @test TestStringDeduplicationYoungGC 32.29 + * @summary Test string deduplication during young GC 32.30 + * @bug 8029075 32.31 + * @key gc 32.32 + * @library /testlibrary 32.33 + */ 32.34 + 32.35 +public class TestStringDeduplicationYoungGC { 32.36 + public static void main(String[] args) throws Exception { 32.37 + TestStringDeduplicationTools.testYoungGC(); 32.38 + } 32.39 +}