Last active
December 4, 2017 21:59
-
-
Save CalebWhiting/ef628ea8e1b6b30ca8f61adabd7019d5 to your computer and use it in GitHub Desktop.
Demonstrates the effect of reflection on performance.
This file contains hidden or 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
import java.lang.reflect.Method; | |
import java.util.stream.LongStream; | |
public class Main { | |
/** | |
* Run each test this many times to get a minimum, average, maximum value | |
*/ | |
private static final int TEST_ATTEMPTS = 5000; | |
/** | |
* How many operations to perform per test | |
*/ | |
private static final int THRESHOLD = 10_000_000; | |
/** | |
* The object to perform operations on | |
*/ | |
private static final Object TARGET = new Object(); | |
/** | |
* Optimise the reflection test | |
*/ | |
private static final Method OBJECT_HASHCODE; | |
static { | |
try { | |
OBJECT_HASHCODE = Object.class.getDeclaredMethod("hashCode"); | |
} catch (NoSuchMethodException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public static void main(String[] args) { | |
long[] direct = new long[TEST_ATTEMPTS]; | |
long directTime = test(Main::testDirect, direct); | |
long[] reflect = new long[TEST_ATTEMPTS]; | |
long reflectTime = test(Main::testReflect, reflect); | |
System.out.printf("Completed %,d attempts (%,d operations per test)%n", TEST_ATTEMPTS, THRESHOLD); | |
System.out.printf("| -----------------------------------|%n"); | |
System.out.printf("| Key | Direct | Reflect |%n"); | |
System.out.printf("| ------------|----------|-----------|%n"); | |
System.out.printf("| total-ms | % 8d | % 9d |%n", directTime, reflectTime); | |
System.out.printf("| min-time-ms | % 8d | % 9d |%n", | |
LongStream.of(direct).min().getAsLong(), LongStream.of(reflect).min().getAsLong()); | |
System.out.printf("| max-time-ms | % 8d | % 9d |%n", | |
LongStream.of(direct).max().getAsLong(), LongStream.of(reflect).max().getAsLong()); | |
System.out.printf("| avg-time-ms | %8s | %9s |%n", | |
LongStream.of(direct).average().getAsDouble(), LongStream.of(reflect).average().getAsDouble()); | |
System.out.printf("| -----------------------------------|%n"); | |
} | |
private static long test(Runnable func, long[] results) { | |
long totalStart = System.currentTimeMillis(); | |
for (int n = 0; n < TEST_ATTEMPTS; n++) { | |
long funcStart = System.currentTimeMillis(); | |
func.run(); | |
results[n] = (System.currentTimeMillis() - funcStart); | |
} | |
return (System.currentTimeMillis() - totalStart); | |
} | |
/** | |
* Calls Object#hashCode directly | |
*/ | |
private static void testDirect() { | |
for (int n = 0; n < THRESHOLD; n++) { | |
TARGET.hashCode(); | |
} | |
} | |
/** | |
* Calls Object#hashCode via reflection. | |
* In reality it would be very hard to optimise all reflective calls to this degree in production | |
*/ | |
private static void testReflect() { | |
try { | |
for (int n = 0; n < THRESHOLD; n++) { | |
OBJECT_HASHCODE.invoke(TARGET); | |
} | |
} catch (ReflectiveOperationException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment