Create a gist now

Instantly share code, notes, and snippets.

@digitalstain /Ballast.java Secret
Last active Dec 31, 2015

Code for the first experiment set of the Software Sympathy post. The driver code is in RegionSizeGames3.java. Ballast is the class whose objectshold the reference and have a well known size.
package gc.ballast;
class FrontBallast
{
protected long long01;
}
class Reference extends FrontBallast
{
protected Object reference;
}
// ObjectLayout says objects of this class take up 32 bytes
public class Ballast extends Reference
{
public void setReference( Object reference )
{
this.reference = reference;
}
public void setLongValue( long value )
{
long01 = value;
}
public long doNotOptimizeAway()
{
return long01 + 32;
}
}
package gc;
import gc.ballast.Ballast;
public class RegionSizeGamesTake3
{
public static final int RegionsToAllocate = 128;
/*
* Allocate a region worth of objects. A region is the heap average size (min size + max size divided by 2)
* divided by 2048. That means that for a heap of 1Gb, each region is 2^30/2^11 = 2^19 bytes big. If Ballast
* is 32 (2^5) then that means we require 2^19 / 2^5 = 16384 objects of that class to fill a region.
*
* We'll do two runs. Both will allocate 32768 Ballast objects. One run will set references from the first 512
* to the second 512 and from the third 512 to the fourth 512 (and back, for each couple). The other run will
* set references from the first 1024 to the second 1024 (and back). We expect the first run to have much
* bigger throughput even though the number of allocations and reference sets will be exactly the same.
*/
public static void main( String[] args )
{
RegionSizeGamesTake3 carrier = new RegionSizeGamesTake3();
// Hotspot, deal with these please
for ( int i = 0; i < 1000; i++ )
{
if ( i % 100 == 0)
{
System.out.println("Warmup round " + i + " reached");
}
carrier.firstRun();
carrier.secondRun();
}
long startTime = System.currentTimeMillis();
for( int i = 0; i < 5000; i++ )
{
carrier.firstRun();
}
System.out.println( "First run took " + (System.currentTimeMillis() - startTime) + "ms" );
startTime = System.currentTimeMillis();
for( int i = 0; i < 5000; i++ )
{
carrier.secondRun();
}
System.out.println("Second run took " + (System.currentTimeMillis() - startTime) + "ms");
}
private void firstRun()
{
Region[] regions = new Region[ RegionsToAllocate ];
for ( int i = 0; i < regions.length; i++ )
{
regions[i] = new Region();
regions[i].setCrossInternal();
}
}
private void secondRun()
{
Region[] regions = new Region[ RegionsToAllocate ];
for ( int i = 0; i < regions.length/2; i++ )
{
int firstHalf = i;
int secondHalf = i + regions.length / 2;
regions[firstHalf] = new Region();
regions[secondHalf] = new Region();
regions[firstHalf].setCrossToExternal( regions[secondHalf] );
regions[secondHalf].setCrossToExternal( regions[firstHalf] );
}
}
private static class Region
{
private final Ballast[] stuff;
public Region()
{
this.stuff = new Ballast[ 16384 ];
for ( int i = 0; i < stuff.length; i++ )
{
stuff[i] = new Ballast();
}
}
public Ballast at( int i )
{
return stuff[i];
}
public void setCrossInternal()
{
// Point the first half to the second half
for ( int i = 0; i < stuff.length / 2 ; i++ )
{
stuff[i].setReference( stuff[i + stuff.length/2] );
stuff[i + stuff.length/2].setReference( stuff[i] );
}
}
public void setCrossToExternal( Region region )
{
for ( int i = 0; i < stuff.length; i++ )
{
stuff[i].setReference( region.at( i ) );
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment