Created
October 30, 2015 12:55
-
-
Save edefazio/85cd0c1264a0938b88a8 to your computer and use it in GitHub Desktop.
Unsafe.allocateMemory(...) performs 2x BETTER when we pass in an int verses a long (of the same value)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package strangeunsafe; | |
import java.lang.reflect.Field; | |
import java.util.Random; | |
import sun.misc.Unsafe | |
/** | |
* Illustrate "strange" issue where Unsafe.allocateMemory(...) performs BETTER | |
* when we pass in an int parameter verses a long parameter (of the same value). | |
* (more detail in description) | |
* <PRE> | |
* Took 665ms to scan LANE 1 100000 8bit bytes 10000x and find 197690000 | |
* Took 1138ms to scan LANE 2 100000 8bit bytes 10000x and find 197690000 | |
* | |
* Took 6597ms to scan LANE 1 100000000 8bit bytes 100x and find 2000811000 | |
* Took 11335ms to scan LANE 2 100000000 8bit bytes 100x and find 2000811000 | |
* | |
* Took 6489ms to scan LANE 1 100000000 8bit bytes 100x and find 1999797500 | |
* Took 11319ms to scan LANE 2 100000000 8bit bytes 100x and find 1999797500 | |
* </PRE> | |
*/ | |
public class UnsafeAllocateMemoryConstructorEffectsScanPerformance | |
{ | |
public static final int LANE1_DATASET_SIZE = 100000000; | |
public static final long LANE2_DATASET_SIZE = LANE1_DATASET_SIZE; | |
public static final long ITERATIONS = 100; | |
public static void main ( String[] args ) | |
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException | |
{ | |
Unsafe theUnsafe = getUnsafe(); | |
//NOTE: the addresses are BOTH longs | |
long startLane1 = theUnsafe.allocateMemory( LANE1_DATASET_SIZE ); | |
long startLane2 = theUnsafe.allocateMemory( LANE2_DATASET_SIZE ); | |
// I "thought" perhaps there was some optimization going on | |
// with the addressing, but BOTH of the addresses SEEM to be | |
// using only 31/32-bits of the 64-bit address... | |
// (so both physical memory addresses are using only 32-bits of the 64-bits) | |
System.out.println ("LANE1 MEMORY ADDRESS BINARY "+ Long.toString ( startLane1 , 2 ) ); | |
System.out.println ("LANE2 MEMORY ADDRESS BINARY "+ Long.toString ( startLane2 , 2 ) ); | |
Random r = new Random(); | |
long lane1Address = startLane1; | |
long lane2Address = startLane2; | |
for ( int i = 0; i < LANE1_DATASET_SIZE; i++ ) | |
{ | |
//populate data [1...5] in each byte (the same data in each "lane") | |
byte oneTo5 = (byte) ( r.nextInt( 5 ) + 1 ); | |
theUnsafe.putByte( lane1Address, oneTo5 ); | |
theUnsafe.putByte( lane2Address, oneTo5 ); | |
lane1Address++; | |
lane2Address++; | |
} | |
long start = System.currentTimeMillis(); | |
//lets scan through lane1, counting the number of matches | |
int count = 0; | |
for ( int it = 0; it < ITERATIONS; it++ ) | |
{ | |
lane1Address = startLane1; | |
for ( int i = 0; i < LANE1_DATASET_SIZE; i++ ) | |
{ | |
if ( theUnsafe.getByte( lane1Address ) == 5 ) | |
{ | |
count++; | |
} | |
lane1Address++; | |
} | |
} | |
long end = System.currentTimeMillis(); | |
System.out.println ("Took "+(end-start)+"ms to scan LANE 1 "+ LANE1_DATASET_SIZE+" 8bit bytes "+ITERATIONS+"x and find "+count); | |
theUnsafe.freeMemory( startLane1 ); | |
//lets do the same with lane 2 | |
start = System.currentTimeMillis(); //RESET START | |
count = 0; | |
for ( int it = 0; it < ITERATIONS; it++ ) | |
{ | |
lane2Address = startLane2; | |
for ( int i = 0; i < LANE2_DATASET_SIZE; i++ ) | |
{ | |
if ( theUnsafe.getByte( lane2Address ) == 5 ) | |
{ | |
count++; | |
} | |
lane2Address++; | |
} | |
} | |
end = System.currentTimeMillis(); | |
System.out.println ("Took "+(end-start)+"ms to scan LANE 2 "+ LANE1_DATASET_SIZE+" 8bit bytes "+ITERATIONS+"x and find "+count); | |
theUnsafe.freeMemory( startLane2 ); | |
} | |
private static Unsafe getUnsafe() | |
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException | |
{ | |
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); | |
theUnsafe.setAccessible(true); | |
Unsafe unsafe = (Unsafe) theUnsafe.get(null); | |
return unsafe; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nitsan's (Video) "The Illusion of Execution" describing JVM execution.
The whole video is great, relevant to this faux paus (non-counted Loops and safe points) starts at about ~12:15:
https://vimeo.com/138863976