RFR: 8200557: OopStorage parallel iteration scales poorly

Kim Barrett kim.barrett at oracle.com
Tue May 1 21:15:13 UTC 2018


> On Apr 26, 2018, at 9:36 AM, Erik Österlund <erik.osterlund at oracle.com> wrote:
> 
> Hi Kim,
> 
> FIrst off, some high level comments:
> 
> 1) I would have simply grabbed the allocation mutex when incrementing the reference counter when starting concurrent iteration, instead of using RCU. The path where we grab this active list for concurrent iteration is stone cold, so I don't expect there to be any observable benefit in using RCU here. But I am going to let that pass and just note we think differently about things here, and I think that is okay.

A very early version of OopStorage had locking between allocation and
concurrent iteration; that was deemed problematic, since an
application (via allocate calls) could delay a concurrent GC phase.

> 2) It is a bit unfortunate that going down the RCU path led to yet another implementation of RCU because GlobalCounter can not yet satisfy your scenario. But I think that you have done a good job making the RCU implementation pluggable in OopStorage, and we can easily remove it once the ThreadsListHandle required by GlobalCounter starts supporting lock-free nesting soon. I am speculating that your approach could be folded in to the GlobalCounter, to accomodate non-JavaThreads and non-VM threads, which that solution currently does not support. But perhaps that is a discussion for later.

I expect GlobalCounter to be able to meet the needs of this scenario
eventually. It doesn't at present, but that limitation is being worked
on. Once that's done, it should be easy to switch and drop the private
mechanism. (While there are some differences that might make this
alternative to GlobalCounter interesting to pursue further, the don't
matter for the present OopStorage use-case.)

> Low level comments:
> * Noting that the new RCU mechanism will like the last one not work on PPC until there is an atomic counter increment with more conservative memory ordering. But I won't blame you for this.
> 
> In oopStorage.cpp:
> 
> 879 size_t OopStorage::block_count() const {
> 880   WithActiveArray wab(this);
> 881   return wab.active_array().block_count_acquire();
> 882 }
> 
> Why do you need acquire here? I don't see subsequent loads into the elements of the array, which seems to be what the paired release_store when writing the counter protects against.
> 
> 884 size_t OopStorage::total_memory_usage() const {
> 885   size_t total_size = sizeof(OopStorage);
> 886   total_size += strlen(name()) + 1;
> 887   total_size += sizeof(BlockArray);
> 888   WithActiveArray wab(this);
> 889   const BlockArray& blocks = wab.active_array();
> 890   total_size += blocks.block_count_acquire() * Block::allocation_size();
> 891   total_size += blocks.size() * sizeof(Block*);
> 892   return total_size;
> 893 }
> 
> Same as above: what reordering is the block_count_acquire protecting against? No element in the array is read after the acquire in program order, that I can see.

See response to Coleen.

> 760   _name(dup_name(name)),
> 761   _active_array(BlockArray::create(initial_active_array_size)),
> 762   _allocate_list(&Block::get_allocate_entry),
> 763   _deferred_updates(NULL),
> 764   _allocate_mutex(allocate_mutex),
> 765   _active_mutex(active_mutex),
> 766   _allocation_count(0),
> 767   _concurrent_iteration_active(false)
> 768 {
> 769   _active_array->increment_refcount();
> 
> I wonder if you could make BlockArray::create() always return an already retained block array, instead of updating it after.
> 
> 496   BlockArray* new_array = BlockArray::create(new_size);
> 497   if (new_array == NULL) return false;
> 498   new_array->copy_from(old_array);
> 499   replace_active_array(new_array);
> 
> And same here where a block array is created without retain reference counter, which is then incremented manually inside of replace_active_array. Seems to me like it would be easier to make BlockArray::create return already retained block arrays.

My experience with using refcounts has been that starting with an
implicit reference at construction time (e.g. initialize the refcount
to 1 at construction) is more often than not really not helpful.

However, this comment led me to notice the constructor for OopStorage
should be checking the result of BlockArray::create.



More information about the hotspot-dev mailing list