RFR(S): 8015237: Parallelize string table scanning during strong root processing

John Cuthbertson john.cuthbertson at oracle.com
Tue May 28 22:31:34 UTC 2013

Hi Thomas,

Thanks for taking a look. Replies inline....

On 5/27/2013 1:04 AM, Thomas Schatzl wrote:
> Hi John,
> On Fri, 2013-05-24 at 15:36 -0700, John Cuthbertson wrote:
>> Hi Everyone,
>> On 5/24/2013 3:19 PM, John Cuthbertson wrote:
>>> Hi Everyone,
>>> Can I have a couple of reviewers look over these changes - the
>>> webrev is: http://cr.openjdk.java.net/~johnc/8015237/webrev.0/
>>> Summary:
>>> On some workloads we are seeing that the scan of the intern string
>>> table (among others) can sometimes take quite a while. This showed
>>> up on some FMW workloads with G1 where the scan of the string table
>>> dominated the pause time for some pauses. G1 was particularly
>>> affected since it doesn't do class unloading (and hence pruning of
>>> the string table) except at full GCs. The solution was to change the
>>> string table from being considered a single root task and treat
>>> similarly to the Java thread stacks: each GC worker claims a given
>>> number of buckets and scans the entries in those buckets.
>>> Testing
>>> Kitchensink; jprt; GC test suite. With all collectors.
> Looks good. A few minor nits:
> - in StringTable::possibly_parallel_oops_do() there is some commented
> debugging code left.
> - one suggestion for refactoring: the worker loop for
> StringTable::possibly_parallel_oops_do() and ::oops_do() are the same,
> except for the difference in the bounds for that loop.
> So maybe this could be factored out into a helper routine (e.g.
> StringTable::process_entries(OopClosure * f, uint start_idx, uint
> end_idx) {
>    for (uint i = start_idx; i < end_idx; i += 1) {
>      HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i);
>      HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i);
>      while (entry != NULL) {
>        f->do_oop((oop*)entry->literal_addr());
>        // Did the closure remove the literal from the table?
>        if (entry->literal() == NULL) {
>          assert(!entry->is_shared(), "immutable hashtable entry?");
>          *p = entry->next();
>          the_table()->free_entry(entry);
>        } else {
>          p = entry->next_addr();
>        }
>        entry = (HashtableEntry<oop, mtSymbol>*)HashtableEntry<oop,
> mtSymbol>::make_ptr(*p);
>      }
>    }
> }
> and called by both StringTable::possibly_parallel_oops_do()
> and ::oops_do() with appropriate parameters?

That's a good idea. A better name might be buckets_do, process_buckets, 
oops_buckets_do (as in oops_interpreted_frame_do).

> (maybe find a better name for that method :)
> - in SharedHeap.cpp:163 there is a misplaced colon in the call to
> Threads::possibly_parallel_oops_do(); this has been the case before as
> well, so it's not really an issue.

OK. Sure I can clean that up.

> - this is just a suggestion: if this is a problem (it does not seem so),
> and of course it also depends on the size of the table (the number of
> synchronizations), why not make the size of the chunks a function of the
> number of threads and the size of the string table?

I thought about this but decided to leave it for another CR. I actually 
like Per's idea of basing the number of buckets on the value of 
CACHE_LINE_SIZE so will probably go with that.

Expect a new webrev soon.


More information about the hotspot-gc-dev mailing list