# HG changeset patch # User johnc # Date 1371583867 25200 # Node ID 01522ca68fc7b4ec126cb072907a6a22b44eb8ca # Parent 0abfeed51c9ebf9e9411e9d71ab8aebbb3a6b634 8015237: Parallelize string table scanning during strong root processing Summary: Parallelize the scanning of the intern string table by having each GC worker claim a given number of buckets. Changes were also reviewed by Per Liden . Reviewed-by: tschatzl, stefank, twisti diff -r 0abfeed51c9e -r 01522ca68fc7 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Fri Jun 14 08:02:32 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.cpp Tue Jun 18 12:31:07 2013 -0700 @@ -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 0abfeed51c9e -r 01522ca68fc7 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Fri Jun 14 08:02:32 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.hpp Tue Jun 18 12:31:07 2013 -0700 @@ -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 0abfeed51c9e -r 01522ca68fc7 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Fri Jun 14 08:02:32 2013 +0200 +++ b/src/share/vm/memory/sharedHeap.cpp Tue Jun 18 12:31:07 2013 -0700 @@ -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); } }