Skip to content

Commit

Permalink
Make WorkSync not reverse the batch prior to combining
Browse files Browse the repository at this point in the history
This saves one iteration (via volatile reads) through the batch, and is allowed because the work units are commutative and associative.
  • Loading branch information
chrisvest committed Oct 6, 2016
1 parent 59595bf commit 8ae9dcc
Showing 1 changed file with 14 additions and 26 deletions.
Expand Up @@ -45,7 +45,7 @@
*
* @see Work
*/
@SuppressWarnings( "unchecked" )
@SuppressWarnings( {"unchecked", "NumberEquality"} )
public class WorkSync<Material, W extends Work<Material,W>>
{
private final Material material;
Expand Down Expand Up @@ -96,7 +96,7 @@ public void apply( W work ) throws ExecutionException
private WorkUnit<Material,W> enqueueWork( W work )
{
WorkUnit<Material,W> unit = new WorkUnit<>( work, Thread.currentThread() );
unit.next = stack.getAndSet( unit ); // benign race, see reverse()
unit.next = stack.getAndSet( unit ); // benign race, see the batch.next read-loop in combine()
return unit;
}

Expand Down Expand Up @@ -169,7 +169,7 @@ private void unlock()

private WorkUnit<Material,W> grabBatch()
{
return reverse( stack.getAndSet( (WorkUnit<Material,W>) stackEnd ) );
return stack.getAndSet( (WorkUnit<Material,W>) stackEnd );
}

private Throwable doSynchronizedWork( WorkUnit<Material,W> batch )
Expand All @@ -191,28 +191,6 @@ private Throwable doSynchronizedWork( WorkUnit<Material,W> batch )
return failure;
}

private WorkUnit<Material,W> reverse( WorkUnit<Material,W> batch )
{
WorkUnit<Material,W> result = (WorkUnit<Material,W>) stackEnd;
while ( batch != stackEnd )
{
WorkUnit<Material,W> tmp = batch.next;
while ( tmp == null )
{
// We may see 'null' via race, as work units are put on the
// stack before their 'next' pointers are updated. We just spin
// until we observe their volatile write to 'next'.
// todo Java9: Thread.onSpinWait() ?
Thread.yield();
tmp = batch.next;
}
batch.next = result;
result = batch;
batch = tmp;
}
return result;
}

private W combine( WorkUnit<Material,W> batch )
{
W result = null;
Expand All @@ -227,7 +205,17 @@ private W combine( WorkUnit<Material,W> batch )
result = result.combine( batch.work );
}

batch = batch.next;
WorkUnit<Material,W> tmp = batch.next;
while ( tmp == null )
{
// We may see 'null' via race, as work units are put on the
// stack before their 'next' pointers are updated. We just spin
// until we observe their volatile write to 'next'.
// todo Java9: Thread.onSpinWait() ?
Thread.yield();
tmp = batch.next;
}
batch = tmp;
}
return result;
}
Expand Down

0 comments on commit 8ae9dcc

Please sign in to comment.