# HG changeset patch # User ehelin # Date 1371715438 -7200 # Node ID 9f9c0a163cc5a37a9affdd76115a027b93b545e6 # Parent 726d2d4913fc773d878818fb21b36b4d2d93b0af# Parent 493089fd29df788bdd797fc89a06bcdb630f0cd0 Merge diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.cpp Thu Jun 20 10:03:58 2013 +0200 @@ -598,6 +598,8 @@ bool StringTable::_needs_rehashing = false; +volatile int StringTable::_parallel_claimed_idx = 0; + // Pick hashing algorithm unsigned int StringTable::hash_string(const jchar* s, int len) { return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : @@ -761,8 +763,18 @@ } } -void StringTable::oops_do(OopClosure* f) { - for (int i = 0; i < the_table()->table_size(); ++i) { +void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { + const int limit = the_table()->table_size(); + + assert(0 <= start_idx && start_idx <= limit, + err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); + assert(0 <= end_idx && end_idx <= limit, + err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); + assert(start_idx <= end_idx, + err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, + start_idx, end_idx)); + + for (int i = start_idx; i < end_idx; i += 1) { HashtableEntry* entry = the_table()->bucket(i); while (entry != NULL) { assert(!entry->is_shared(), "CDS not used for the StringTable"); @@ -774,6 +786,27 @@ } } +void StringTable::oops_do(OopClosure* f) { + buckets_do(f, 0, the_table()->table_size()); +} + +void StringTable::possibly_parallel_oops_do(OopClosure* f) { + const int ClaimChunkSize = 32; + const int limit = the_table()->table_size(); + + for (;;) { + // Grab next set of buckets to scan + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; + if (start_idx >= limit) { + // End of table + break; + } + + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); + buckets_do(f, start_idx, end_idx); + } +} + void StringTable::verify() { for (int i = 0; i < the_table()->table_size(); ++i) { HashtableEntry* p = the_table()->bucket(i); diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.hpp Thu Jun 20 10:03:58 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,12 +246,19 @@ // Set if one bucket is out of balance due to hash algorithm deficiency static bool _needs_rehashing; + // Claimed high water mark for parallel chunked scanning + static volatile int _parallel_claimed_idx; + static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS); oop basic_add(int index, Handle string_or_null, jchar* name, int len, unsigned int hashValue, TRAPS); oop lookup(int index, jchar* chars, int length, unsigned int hashValue); + // Apply the give oop closure to the entries to the buckets + // in the range [start_idx, end_idx). + static void buckets_do(OopClosure* f, int start_idx, int end_idx); + StringTable() : Hashtable((int)StringTableSize, sizeof (HashtableEntry)) {} @@ -277,9 +284,12 @@ unlink_or_oops_do(cl, NULL); } - // Invoke "f->do_oop" on the locations of all oops in the table. + // Serially invoke "f->do_oop" on the locations of all oops in the table. static void oops_do(OopClosure* f); + // Possibly parallel version of the above + static void possibly_parallel_oops_do(OopClosure* f); + // Hashing algorithm, used as the hash value used by the // StringTable for bucket selection and comparison (stored in the // HashtableEntry structures). This is used in the String.intern() method. @@ -315,5 +325,8 @@ // Rehash the symbol table if it gets out of balance static void rehash_table(); static bool needs_rehashing() { return _needs_rehashing; } + + // Parallel chunked scanning + static void clear_parallel_claimed_index() { _parallel_claimed_idx = 0; } }; #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Thu Jun 20 10:03:58 2013 +0200 @@ -1250,14 +1250,13 @@ avg_promoted()->deviation()); } - gclog_or_tty->print( " avg_promoted_padded_avg: %f" + gclog_or_tty->print_cr( " avg_promoted_padded_avg: %f" " avg_pretenured_padded_avg: %f" " tenuring_thresh: %d" " target_size: " SIZE_FORMAT, avg_promoted()->padded_average(), _avg_pretenured->padded_average(), tenuring_threshold, target_size); - tty->cr(); } set_survivor_size(target_size); @@ -1279,7 +1278,7 @@ avg_promoted()->sample(promoted + _avg_pretenured->padded_average()); if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print( + gclog_or_tty->print_cr( "AdaptiveSizePolicy::update_averages:" " survived: " SIZE_FORMAT " promoted: " SIZE_FORMAT diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/memory/allocation.hpp Thu Jun 20 10:03:58 2013 +0200 @@ -732,13 +732,21 @@ // is set so that we always use malloc except for Solaris where we set the // limit to get mapped memory. template -class ArrayAllocator : StackObj { +class ArrayAllocator VALUE_OBJ_CLASS_SPEC { char* _addr; bool _use_malloc; size_t _size; + bool _free_in_destructor; public: - ArrayAllocator() : _addr(NULL), _use_malloc(false), _size(0) { } - ~ArrayAllocator() { free(); } + ArrayAllocator(bool free_in_destructor = true) : + _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { } + + ~ArrayAllocator() { + if (_free_in_destructor) { + free(); + } + } + E* allocate(size_t length); void free(); }; diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/memory/sharedHeap.cpp Thu Jun 20 10:03:58 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ SH_PS_SystemDictionary_oops_do, SH_PS_ClassLoaderDataGraph_oops_do, SH_PS_jvmti_oops_do, - SH_PS_StringTable_oops_do, SH_PS_CodeCache_oops_do, // Leave this one last. SH_PS_NumElements @@ -127,6 +126,8 @@ { if (_active) { outer->change_strong_roots_parity(); + // Zero the claimed high water mark in the StringTable + StringTable::clear_parallel_claimed_index(); } } @@ -154,14 +155,16 @@ // Global (strong) JNI handles if (!_process_strong_tasks->is_task_claimed(SH_PS_JNIHandles_oops_do)) JNIHandles::oops_do(roots); + // All threads execute this; the individual threads are task groups. CLDToOopClosure roots_from_clds(roots); CLDToOopClosure* roots_from_clds_p = (is_scavenging ? NULL : &roots_from_clds); - if (ParallelGCThreads > 0) { - Threads::possibly_parallel_oops_do(roots, roots_from_clds_p ,code_roots); + if (CollectedHeap::use_parallel_gc_threads()) { + Threads::possibly_parallel_oops_do(roots, roots_from_clds_p, code_roots); } else { Threads::oops_do(roots, roots_from_clds_p, code_roots); } + if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do)) ObjectSynchronizer::oops_do(roots); if (!_process_strong_tasks->is_task_claimed(SH_PS_FlatProfiler_oops_do)) @@ -189,8 +192,12 @@ } } - if (!_process_strong_tasks->is_task_claimed(SH_PS_StringTable_oops_do)) { - if (so & SO_Strings) { + // All threads execute the following. A specific chunk of buckets + // from the StringTable are the individual tasks. + if (so & SO_Strings) { + if (CollectedHeap::use_parallel_gc_threads()) { + StringTable::possibly_parallel_oops_do(roots); + } else { StringTable::oops_do(roots); } } diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Thu Jun 20 10:03:58 2013 +0200 @@ -1566,6 +1566,15 @@ return result; } +void Arguments::set_heap_base_min_address() { + if (FLAG_IS_DEFAULT(HeapBaseMinAddress) && UseG1GC && HeapBaseMinAddress < 1*G) { + // By default HeapBaseMinAddress is 2G on all platforms except Solaris x86. + // G1 currently needs a lot of C-heap, so on Solaris we have to give G1 + // some extra space for the C-heap compared to other collectors. + FLAG_SET_ERGO(uintx, HeapBaseMinAddress, 1*G); + } +} + void Arguments::set_heap_size() { if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) { // Deprecated flag @@ -3525,6 +3534,8 @@ } } + set_heap_base_min_address(); + // Set heap size based on available physical memory set_heap_size(); diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/runtime/arguments.hpp Thu Jun 20 10:03:58 2013 +0200 @@ -315,6 +315,8 @@ // limits the given memory size by the maximum amount of memory this process is // currently allowed to allocate or reserve. static julong limit_by_allocatable_memory(julong size); + // Setup HeapBaseMinAddress + static void set_heap_base_min_address(); // Setup heap size static void set_heap_size(); // Based on automatic selection criteria, should the diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/utilities/bitMap.cpp --- a/src/share/vm/utilities/bitMap.cpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/utilities/bitMap.cpp Thu Jun 20 10:03:58 2013 +0200 @@ -41,7 +41,7 @@ BitMap::BitMap(bm_word_t* map, idx_t size_in_bits) : - _map(map), _size(size_in_bits) + _map(map), _size(size_in_bits), _map_allocator(false) { assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); assert(size_in_bits >= 0, "just checking"); @@ -49,7 +49,7 @@ BitMap::BitMap(idx_t size_in_bits, bool in_resource_area) : - _map(NULL), _size(0) + _map(NULL), _size(0), _map_allocator(false) { assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); resize(size_in_bits, in_resource_area); @@ -65,8 +65,10 @@ if (in_resource_area) { _map = NEW_RESOURCE_ARRAY(bm_word_t, new_size_in_words); } else { - if (old_map != NULL) FREE_C_HEAP_ARRAY(bm_word_t, _map, mtInternal); - _map = NEW_C_HEAP_ARRAY(bm_word_t, new_size_in_words, mtInternal); + if (old_map != NULL) { + _map_allocator.free(); + } + _map = _map_allocator.allocate(new_size_in_words); } Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, MIN2(old_size_in_words, new_size_in_words)); diff -r 726d2d4913fc -r 9f9c0a163cc5 src/share/vm/utilities/bitMap.hpp --- a/src/share/vm/utilities/bitMap.hpp Wed Jun 19 18:13:52 2013 +0200 +++ b/src/share/vm/utilities/bitMap.hpp Thu Jun 20 10:03:58 2013 +0200 @@ -48,6 +48,7 @@ } RangeSizeHint; private: + ArrayAllocator _map_allocator; bm_word_t* _map; // First word in bitmap idx_t _size; // Size of bitmap (in bits) @@ -113,7 +114,7 @@ public: // Constructs a bitmap with no map, and size 0. - BitMap() : _map(NULL), _size(0) {} + BitMap() : _map(NULL), _size(0), _map_allocator(false) {} // Constructs a bitmap with the given map and size. BitMap(bm_word_t* map, idx_t size_in_bits);