Primitive Queue<any T> considerations

Brian Goetz brian.goetz at oracle.com
Wed Nov 18 20:45:36 UTC 2015


Your sense of "what people are not going to complain about" is woefully 
optimistic :)

On 11/18/2015 3:38 PM, Vitaly Davidovich wrote:
>
>     Converting an array of big values to an array of boxes
>     (transparently) is one of the options the VM has regardless of
>     atomicity requirements.  For big values, passing them by value is
>     expensive anyway, and the VM has the right to silently box and
>     pass a reference instead if it thinks this will be faster (this
>     will be invisible to the user.)  An array of boxes has the nice
>     property in that references are small enough that atomicity is
>     free. So one way to get atomicity for an array of 1000-bit values
>     is to use an array of references to boxed values.  Again, VM's
>     choice. 
>
>
> I know we discussed this automatic boxing before, and I still think 
> it's a bad idea to do this behind the user's back.  A large point of 
> value types is they do not touch the heap, and thus do not contribute 
> to any subsequent GC pauses. If I had a large struct, I may be just 
> fine having a slower copy operation percolating through the stack.  
> This is like escape analysis, nobody that's avoiding GC is actually 
> relying on it because of this "VM's choice" aspect.  I urge you to 
> reconsider this automatic boxing aspect.  Nobody is going to complain 
> that the JVM is not automatically boxing their large struct, but 
> someone will complain if there's heap allocation behind the scenes.
>
>     Nullability is orthogonal to atomicity.  If he wants nullability,
>     he wraps his values with Optional<T>.  (For refs, Optional<T> will
>     hopefully be the same size as a ref, so it isn't a problem to do
>     this across the board.)
>     For atomicity, you don't switch on size, you just ask for it.  If
>     the values are small, atomicity will be free or cheap anyway.
>
>
> Well, if there's going to be a way to request just atomicity (and not 
> ordering as well), which will nop if size is atomic natively, then 
> great.  Otherwise, I'd hate for there to be *any* performance penalty 
> if the size is <= word size.
>
> On Wed, Nov 18, 2015 at 3:24 PM, Brian Goetz <brian.goetz at oracle.com 
> <mailto:brian.goetz at oracle.com>> wrote:
>
>
>     On 11/18/2015 3:16 PM, Vitaly Davidovich wrote:
>>
>>     Right, I was talking about case where atomicity is explicitly
>>     requested.  I understand JVM can pick, I'm curious on where it
>>     would get a lock from.  I'm also unclear how boxing helps since
>>     the data has to be unpacked atomically anyway.
>>
>
>     The lock used would be invisible to the calling code.  Lots of
>     degrees of freedom for the VM here, of course.  If transactional
>     memory ever starts working well enough, that's an option as well.
>
>     Converting an array of big values to an array of boxes
>     (transparently) is one of the options the VM has regardless of
>     atomicity requirements.  For big values, passing them by value is
>     expensive anyway, and the VM has the right to silently box and
>     pass a reference instead if it thinks this will be faster (this
>     will be invisible to the user.)  An array of boxes has the nice
>     property in that references are small enough that atomicity is
>     free. So one way to get atomicity for an array of 1000-bit values
>     is to use an array of references to boxed values. Again, VM's choice.
>
>>     Using David's example, say he wanted to have queue of nullable
>>     longs, which internally he'd store as Optional<long>.  But how
>>     does he specify in his generic class definition that when sizeof
>>     (Optional<T>) > word size that he'd like atomic access? This goes
>>     back to specialization selection, but has size constraint.
>>
>
>     Nullability is orthogonal to atomicity.  If he wants nullability,
>     he wraps his values with Optional<T>.  (For refs, Optional<T> will
>     hopefully be the same size as a ref, so it isn't a problem to do
>     this across the board.)
>
>     For atomicity, you don't switch on size, you just ask for it.  If
>     the values are small, atomicity will be free or cheap anyway.
>
>
>>     sent from my phone
>>
>>     On Nov 18, 2015 3:07 PM, "Brian Goetz" <brian.goetz at oracle.com
>>     <mailto:brian.goetz at oracle.com>> wrote:
>>
>>         If the value is "too big" and no atomicity has been requested
>>         (via use-site volatile indication, declaration-site
>>         indication, etc), then tearing is possible.  If atomicity is
>>         requested, the VM is free to pick the most efficient means to
>>         transparently achieve this, whether this be atomic
>>         load/store, seq lock, spin lock, Java lock, boxing, etc.
>>
>>         On 11/18/2015 3:01 PM, Vitaly Davidovich wrote:
>>>         This is good to hear Brian.
>>>
>>>             So the answer is not "reads and writes need to be
>>>             atomic", but instead "there should be a way to ask for
>>>             atomic reads/writes." The current front-runner here
>>>             builds on an existing story -- using volatile to make
>>>             longs/double fields atomic.  We can easily extend this
>>>             to values. 
>>>
>>>
>>>         Just to spitball this a bit, if the value type is larger
>>>         than max atomic transfer unit on the machine, what's the
>>>         thinking? I suppose you'd need some locking, but where would
>>>         it get a lock for this? Would a synthetic one be generated
>>>         automatically (javac or JVM)?
>>>
>>>         On Wed, Nov 18, 2015 at 2:56 PM, Brian Goetz
>>>         <brian.goetz at oracle.com <mailto:brian.goetz at oracle.com>> wrote:
>>>
>>>
>>>>             If value types are final, that means the array-store
>>>>             and array-load have to be atomic in some way for
>>>>             fast-flow to work, i.e., mark has to be written last
>>>>             and read first in the structured array.
>>>>
>>>
>>>             That would be putting it too strongly.
>>>
>>>             Your concern is structure tearing.  If thread A writes a
>>>             value to an array element (or a field) and thread B
>>>             reads it, you are concerned that the reader see some
>>>             consistent value that was put there by a single write in
>>>             the past (even if stale.)
>>>
>>>             Obviously for "small enough" values, this isn't an
>>>             issue, but small enough is pretty small (64 bits on
>>>             today's hardware).   Also note that the JLS / JVMS have
>>>             allowed tearing of longs and doubles since day one,
>>>             unless they are declared volatile.
>>>
>>>             Note that the bad outcome -- tearing -- /only happens in
>>>             the presence of a data race/.  So the question is, what
>>>             should we do to protect the too-clever (and
>>>             too-unclever) folks from their own mistakes?  The answer
>>>             is certainly not to make all value reads and writes
>>>             atomics -- this would be burdening all of the users who
>>>             follow the rules with a crippling performance penalty
>>>             (and it is really bad for larger-than-64-bit values) for
>>>             the sake of the few who are living on the edge.
>>>
>>>             So the answer is not "reads and writes need to be
>>>             atomic", but instead "there should be a way to ask for
>>>             atomic reads/writes."  The current front-runner here
>>>             builds on an existing story -- using volatile to make
>>>             longs/double fields atomic.  We can easily extend this
>>>             to values.
>>>
>>>             That leaves two cases uncovered:
>>>              - What about arrays -- there is currently no means to
>>>             declare an array with volatile (or final) elements. This
>>>             is being explored now.
>>>              - What about classes that are intrinsically
>>>             security-sensitive, and could not tolerate tearing in
>>>             any case?  For this case, we are considering a
>>>             declaration-site indication that a value is "unbreakable".
>>>
>>>             Summary:
>>>              - Tearing is going to be a risk when accessing shared
>>>             mutable state via a data race.
>>>              - There will be use-site and likely also
>>>             declaration-site tools to opt into atomicity, with a cost.
>>>
>>>
>>>
>>
>
>



More information about the valhalla-dev mailing list