RFR(s): 8244733: Add ResourceHashtable::xxx_if_absent
Robbin Ehn
robbin.ehn at oracle.com
Tue May 19 06:54:11 UTC 2020
Hi Thomas,
On 2020-05-19 07:32, Thomas Stüfe wrote:
>
>
> On Mon, May 18, 2020 at 9:56 PM Robbin Ehn <robbin.ehn at oracle.com
> <mailto:robbin.ehn at oracle.com>> wrote:
>
> Hi Thomas,
>
> The Node constructor uses V copy constructor here:
> Node(unsigned hash, K const& key, V const& value) :
> _hash(hash), _key(key), _value(value), _next(NULL) {}
>
> So we create value to pass in and and then create a new _value, so two
> objects of type V are created.
>
> // Create a node with a default-constructed value.
> Node(unsigned hash, K const& key) :
> _hash(hash), _key(key), _value(), _next(NULL) {}
>
> Here we call the V default-constructor.
> If we manually later populate V we only need one object.
> But most often we already have written that code in the constructor.
> I would use placement new on that piece of memory when running V normal
> constructor instead. This would also remove the need for V having a
> default constructor.
>
> So my question was, if we are trying to avoid creating unnecessary
> objects of type V, do really want to use copy constructor here?
> (not your patch's doing)
>
> And manually populating V or writing a special method for this
> case to populate V feels odd?
>
> (note these are just questions, I guess most objects are trivial that
> uses this anyways)
>
> Thanks, Robbin
>
>
> Ah now I get it. Thanks for explaining.
>
> You are right, put_(default)_if_absent(k) makes most sense for complex
> data types with a cheapish default ctor and then later slow trickling in
> of information. Typical use would be stat counters or similar. Like the
> use cases in CDS:
> http://cr.openjdk.java.net/~stuefe/webrevs/8244733--add-resourcehashtable--compute_if_absent/webrev.02/webrev/src/hotspot/share/classfile/classLoaderStats.cpp.udiff.html.
> This variant forces you to have a default constructor; preventing you
> from using const members and similar annoyances.
>
> put_if_absent(k, v) makes sense for cases where copy construction is
> cheap, as is obtaining the information in the first place. Like here:
> http://cr.openjdk.java.net/~stuefe/webrevs/8244733--add-resourcehashtable--compute_if_absent/webrev.02/webrev/src/hotspot/share/classfile/bytecodeAssembler.cpp.udiff.html .
>
> None of these are perfect, but they mimic the existing code (when in
> Rome..) and I'd rather not extend the scope of this patch. It is
> difficult enough to agree on one form.
>
> That said, lets discuss your thought :)
>
> IIUC, what you propose is a variant which, given a key, would allocate
> backing memory for the value if it does not exist, but leave it
> uninitialized it? To be then used later with placement new?
>
> I'm not even sure how to do this in C++. Like this maybe:
>
> class Node {
> ...
> char[sizeof(V)] value_memory;
> }; ?
>
> And the use case would be complex objects with non-trivial non-cheap
> construction. But I do not see a pressing need for it. All use cases I
> fixed up were either PODs or very simple value holder structs like in CDS.
Ok
>
> Before doing any of this stuff I'd rather enhance ResourceHashTable in
> other areas. For instance, that thing never resizes the bucket array.
> The ClassLoaderStats hash table I worked recently on was 250 times
> overbooked with near perfect hash! OTOH the default bucket array size is
> 256, which is 2K for 64 platforms, which is kind of a lot, depending on
> what you do with it. So, a resizable hash table would be good - either
> automatic or manually triggered.
>
> Another though I have is that rather than avoiding the copy constructor,
> on quite a few call sites it would make sense to embrace it and go fully
> pass-by-value:
> - bool put(K const& key, V const& value) {
> + bool put(K key, V value) {
>
> since in many cases key or values are PODs. Sometimes key and value are
> even smaller than a pointer, so passing by reference unnecessarily uses
> 64bit beside the address-of and dereferencing.
Yes and if you have a complex type you often don't want it to have same
life-cycle as the Node. So V would be a pointer to the type, thus
copy-by value is also fine.
>
> Just some thoughts. One wish expressed in these reviews was that
> ResourceHashTable should stay simple, so this means none of these ideas
> may be doable.
Ok, sure!
Patch looks fine! But I would consider Coleen's suggestion:
+ V* put_if_absent(K const& key, bool* p_created) {
return put_if_absent(key, V(), p_created);
}
Thanks, Robbin
>
> Thanks, Thomas
>
>
More information about the hotspot-runtime-dev
mailing list