1*0ed15c77SAndroid Build Coastguard Worker package perf; 2*0ed15c77SAndroid Build Coastguard Worker 3*0ed15c77SAndroid Build Coastguard Worker import java.io.*; 4*0ed15c77SAndroid Build Coastguard Worker 5*0ed15c77SAndroid Build Coastguard Worker import com.fasterxml.jackson.databind.*; 6*0ed15c77SAndroid Build Coastguard Worker 7*0ed15c77SAndroid Build Coastguard Worker abstract class ObjectReaderTestBase 8*0ed15c77SAndroid Build Coastguard Worker { 9*0ed15c77SAndroid Build Coastguard Worker protected final static int WARMUP_ROUNDS = 5; 10*0ed15c77SAndroid Build Coastguard Worker 11*0ed15c77SAndroid Build Coastguard Worker protected String _desc1, _desc2; 12*0ed15c77SAndroid Build Coastguard Worker 13*0ed15c77SAndroid Build Coastguard Worker protected int hash; 14*0ed15c77SAndroid Build Coastguard Worker protected long startMeasure = System.currentTimeMillis() + 5000L; 15*0ed15c77SAndroid Build Coastguard Worker protected int roundsDone = 0; 16*0ed15c77SAndroid Build Coastguard Worker protected int REPS; 17*0ed15c77SAndroid Build Coastguard Worker private double[] timeMsecs; 18*0ed15c77SAndroid Build Coastguard Worker targetSizeMegs()19*0ed15c77SAndroid Build Coastguard Worker protected abstract int targetSizeMegs(); 20*0ed15c77SAndroid Build Coastguard Worker testFromBytes(ObjectMapper mapper1, String desc1, Object inputValue1, Class<?> inputClass1, ObjectMapper mapper2, String desc2, Object inputValue2, Class<?> inputClass2)21*0ed15c77SAndroid Build Coastguard Worker protected void testFromBytes(ObjectMapper mapper1, String desc1, 22*0ed15c77SAndroid Build Coastguard Worker Object inputValue1, Class<?> inputClass1, 23*0ed15c77SAndroid Build Coastguard Worker ObjectMapper mapper2, String desc2, 24*0ed15c77SAndroid Build Coastguard Worker Object inputValue2, Class<?> inputClass2) 25*0ed15c77SAndroid Build Coastguard Worker throws Exception 26*0ed15c77SAndroid Build Coastguard Worker { 27*0ed15c77SAndroid Build Coastguard Worker final byte[] byteInput1 = mapper1.writeValueAsBytes(inputValue1); 28*0ed15c77SAndroid Build Coastguard Worker final byte[] byteInput2 = mapper2.writeValueAsBytes(inputValue2); 29*0ed15c77SAndroid Build Coastguard Worker // Let's try to guestimate suitable size... to get to N megs to process 30*0ed15c77SAndroid Build Coastguard Worker REPS = (int) ((double) (targetSizeMegs() * 1000 * 1000) / (double) byteInput1.length); 31*0ed15c77SAndroid Build Coastguard Worker 32*0ed15c77SAndroid Build Coastguard Worker // sanity check: 33*0ed15c77SAndroid Build Coastguard Worker /*T1 back1 =*/ mapper1.readValue(byteInput1, inputClass1); 34*0ed15c77SAndroid Build Coastguard Worker /*T2 back2 =*/ mapper2.readValue(byteInput2, inputClass2); 35*0ed15c77SAndroid Build Coastguard Worker System.out.println("Input successfully round-tripped for both styles..."); 36*0ed15c77SAndroid Build Coastguard Worker 37*0ed15c77SAndroid Build Coastguard Worker _desc1 = String.format("%s (%d bytes)", desc1, byteInput1.length); 38*0ed15c77SAndroid Build Coastguard Worker _desc2 = String.format("%s (%d bytes)", desc2, byteInput2.length); 39*0ed15c77SAndroid Build Coastguard Worker 40*0ed15c77SAndroid Build Coastguard Worker doTest(mapper1, byteInput1, inputClass1, mapper2, byteInput2, inputClass2); 41*0ed15c77SAndroid Build Coastguard Worker } 42*0ed15c77SAndroid Build Coastguard Worker testFromString(ObjectMapper mapper1, String desc1, Object inputValue1, Class<?> inputClass1, ObjectMapper mapper2, String desc2, Object inputValue2, Class<?> inputClass2)43*0ed15c77SAndroid Build Coastguard Worker protected void testFromString(ObjectMapper mapper1, String desc1, 44*0ed15c77SAndroid Build Coastguard Worker Object inputValue1, Class<?> inputClass1, 45*0ed15c77SAndroid Build Coastguard Worker ObjectMapper mapper2, String desc2, 46*0ed15c77SAndroid Build Coastguard Worker Object inputValue2, Class<?> inputClass2) 47*0ed15c77SAndroid Build Coastguard Worker throws Exception 48*0ed15c77SAndroid Build Coastguard Worker { 49*0ed15c77SAndroid Build Coastguard Worker final String input1 = mapper1.writeValueAsString(inputValue1); 50*0ed15c77SAndroid Build Coastguard Worker final String input2 = mapper2.writeValueAsString(inputValue2); 51*0ed15c77SAndroid Build Coastguard Worker // Let's try to guestimate suitable size... to get to N megs to process 52*0ed15c77SAndroid Build Coastguard Worker REPS = (int) ((double) (targetSizeMegs() * 1000 * 1000) / (double) input1.length()); 53*0ed15c77SAndroid Build Coastguard Worker _desc1 = String.format("%s (%d chars)", desc1, input1.length()); 54*0ed15c77SAndroid Build Coastguard Worker _desc2 = String.format("%s (%d chars)", desc2, input2.length()); 55*0ed15c77SAndroid Build Coastguard Worker 56*0ed15c77SAndroid Build Coastguard Worker // sanity check: 57*0ed15c77SAndroid Build Coastguard Worker /*T1 back1 =*/ mapper1.readValue(input1, inputClass1); 58*0ed15c77SAndroid Build Coastguard Worker /*T2 back2 =*/ mapper2.readValue(input2, inputClass2); 59*0ed15c77SAndroid Build Coastguard Worker System.out.println("Input successfully round-tripped for both styles..."); 60*0ed15c77SAndroid Build Coastguard Worker 61*0ed15c77SAndroid Build Coastguard Worker doTest(mapper1, input1, inputClass1, mapper2, input2, inputClass2); 62*0ed15c77SAndroid Build Coastguard Worker } 63*0ed15c77SAndroid Build Coastguard Worker doTest(ObjectMapper mapper1, byte[] byteInput1, Class<?> inputClass1, ObjectMapper mapper2, byte[] byteInput2, Class<?> inputClass2)64*0ed15c77SAndroid Build Coastguard Worker protected void doTest(ObjectMapper mapper1, byte[] byteInput1, Class<?> inputClass1, 65*0ed15c77SAndroid Build Coastguard Worker ObjectMapper mapper2, byte[] byteInput2, Class<?> inputClass2) 66*0ed15c77SAndroid Build Coastguard Worker throws Exception 67*0ed15c77SAndroid Build Coastguard Worker { 68*0ed15c77SAndroid Build Coastguard Worker System.out.printf("Read %d bytes to bind (%d as array); will do %d repetitions\n", 69*0ed15c77SAndroid Build Coastguard Worker byteInput1.length, byteInput2.length, REPS); 70*0ed15c77SAndroid Build Coastguard Worker System.out.print("Warming up"); 71*0ed15c77SAndroid Build Coastguard Worker 72*0ed15c77SAndroid Build Coastguard Worker final ObjectReader jsonReader = mapper1.reader() 73*0ed15c77SAndroid Build Coastguard Worker .forType(inputClass1); 74*0ed15c77SAndroid Build Coastguard Worker final ObjectReader arrayReader = mapper2.reader() 75*0ed15c77SAndroid Build Coastguard Worker .forType(inputClass2); 76*0ed15c77SAndroid Build Coastguard Worker 77*0ed15c77SAndroid Build Coastguard Worker int i = 0; 78*0ed15c77SAndroid Build Coastguard Worker final int TYPES = 2; 79*0ed15c77SAndroid Build Coastguard Worker 80*0ed15c77SAndroid Build Coastguard Worker timeMsecs = new double[TYPES]; 81*0ed15c77SAndroid Build Coastguard Worker 82*0ed15c77SAndroid Build Coastguard Worker while (true) { 83*0ed15c77SAndroid Build Coastguard Worker Thread.sleep(100L); 84*0ed15c77SAndroid Build Coastguard Worker final int type = (i++ % TYPES); 85*0ed15c77SAndroid Build Coastguard Worker 86*0ed15c77SAndroid Build Coastguard Worker String msg; 87*0ed15c77SAndroid Build Coastguard Worker double msesc; 88*0ed15c77SAndroid Build Coastguard Worker 89*0ed15c77SAndroid Build Coastguard Worker switch (type) { 90*0ed15c77SAndroid Build Coastguard Worker case 0: 91*0ed15c77SAndroid Build Coastguard Worker msg = _desc1; 92*0ed15c77SAndroid Build Coastguard Worker msesc = testDeser1(REPS, byteInput1, jsonReader); 93*0ed15c77SAndroid Build Coastguard Worker break; 94*0ed15c77SAndroid Build Coastguard Worker case 1: 95*0ed15c77SAndroid Build Coastguard Worker msg = _desc2; 96*0ed15c77SAndroid Build Coastguard Worker msesc = testDeser2(REPS, byteInput2, arrayReader); 97*0ed15c77SAndroid Build Coastguard Worker break; 98*0ed15c77SAndroid Build Coastguard Worker default: 99*0ed15c77SAndroid Build Coastguard Worker throw new Error(); 100*0ed15c77SAndroid Build Coastguard Worker } 101*0ed15c77SAndroid Build Coastguard Worker updateStats(type, (i % 17) == 0, msg, msesc); 102*0ed15c77SAndroid Build Coastguard Worker } 103*0ed15c77SAndroid Build Coastguard Worker } 104*0ed15c77SAndroid Build Coastguard Worker doTest(ObjectMapper mapper1, String input1, Class<?> inputClass1, ObjectMapper mapper2, String input2, Class<?> inputClass2)105*0ed15c77SAndroid Build Coastguard Worker protected void doTest(ObjectMapper mapper1, String input1, Class<?> inputClass1, 106*0ed15c77SAndroid Build Coastguard Worker ObjectMapper mapper2, String input2, Class<?> inputClass2) 107*0ed15c77SAndroid Build Coastguard Worker throws Exception 108*0ed15c77SAndroid Build Coastguard Worker { 109*0ed15c77SAndroid Build Coastguard Worker System.out.printf("Read %d bytes to bind (%d as array); will do %d repetitions\n", 110*0ed15c77SAndroid Build Coastguard Worker input1.length(), input2.length(), REPS); 111*0ed15c77SAndroid Build Coastguard Worker System.out.print("Warming up"); 112*0ed15c77SAndroid Build Coastguard Worker 113*0ed15c77SAndroid Build Coastguard Worker final ObjectReader jsonReader = mapper1.reader() 114*0ed15c77SAndroid Build Coastguard Worker .with(DeserializationFeature.EAGER_DESERIALIZER_FETCH) 115*0ed15c77SAndroid Build Coastguard Worker .forType(inputClass1); 116*0ed15c77SAndroid Build Coastguard Worker final ObjectReader arrayReader = mapper2.reader() 117*0ed15c77SAndroid Build Coastguard Worker .with(DeserializationFeature.EAGER_DESERIALIZER_FETCH) 118*0ed15c77SAndroid Build Coastguard Worker .forType(inputClass2); 119*0ed15c77SAndroid Build Coastguard Worker 120*0ed15c77SAndroid Build Coastguard Worker int i = 0; 121*0ed15c77SAndroid Build Coastguard Worker final int TYPES = 2; 122*0ed15c77SAndroid Build Coastguard Worker 123*0ed15c77SAndroid Build Coastguard Worker timeMsecs = new double[TYPES]; 124*0ed15c77SAndroid Build Coastguard Worker 125*0ed15c77SAndroid Build Coastguard Worker while (true) { 126*0ed15c77SAndroid Build Coastguard Worker Thread.sleep(100L); 127*0ed15c77SAndroid Build Coastguard Worker int type = (i++ % TYPES); 128*0ed15c77SAndroid Build Coastguard Worker String msg; 129*0ed15c77SAndroid Build Coastguard Worker double msecs; 130*0ed15c77SAndroid Build Coastguard Worker 131*0ed15c77SAndroid Build Coastguard Worker switch (type) { 132*0ed15c77SAndroid Build Coastguard Worker case 0: 133*0ed15c77SAndroid Build Coastguard Worker msg = _desc1; 134*0ed15c77SAndroid Build Coastguard Worker msecs = testDeser1(REPS, input1, jsonReader); 135*0ed15c77SAndroid Build Coastguard Worker break; 136*0ed15c77SAndroid Build Coastguard Worker case 1: 137*0ed15c77SAndroid Build Coastguard Worker msg = _desc2; 138*0ed15c77SAndroid Build Coastguard Worker msecs = testDeser2(REPS, input2, arrayReader); 139*0ed15c77SAndroid Build Coastguard Worker break; 140*0ed15c77SAndroid Build Coastguard Worker default: 141*0ed15c77SAndroid Build Coastguard Worker throw new Error(); 142*0ed15c77SAndroid Build Coastguard Worker } 143*0ed15c77SAndroid Build Coastguard Worker updateStats(type, (i % 17) == 0, msg, msecs); 144*0ed15c77SAndroid Build Coastguard Worker } 145*0ed15c77SAndroid Build Coastguard Worker } 146*0ed15c77SAndroid Build Coastguard Worker updateStats(int type, boolean doGc, String msg, double msecs)147*0ed15c77SAndroid Build Coastguard Worker private void updateStats(int type, boolean doGc, String msg, double msecs) 148*0ed15c77SAndroid Build Coastguard Worker throws Exception 149*0ed15c77SAndroid Build Coastguard Worker { 150*0ed15c77SAndroid Build Coastguard Worker final boolean lf = (type == (timeMsecs.length - 1)); 151*0ed15c77SAndroid Build Coastguard Worker 152*0ed15c77SAndroid Build Coastguard Worker if (startMeasure == 0L) { // skip first N seconds 153*0ed15c77SAndroid Build Coastguard Worker timeMsecs[type] += msecs; 154*0ed15c77SAndroid Build Coastguard Worker } else { 155*0ed15c77SAndroid Build Coastguard Worker if (lf) { 156*0ed15c77SAndroid Build Coastguard Worker if (System.currentTimeMillis() >= startMeasure) { 157*0ed15c77SAndroid Build Coastguard Worker startMeasure = 0L; 158*0ed15c77SAndroid Build Coastguard Worker System.out.println(" complete!"); 159*0ed15c77SAndroid Build Coastguard Worker } else { 160*0ed15c77SAndroid Build Coastguard Worker System.out.print("."); 161*0ed15c77SAndroid Build Coastguard Worker } 162*0ed15c77SAndroid Build Coastguard Worker } 163*0ed15c77SAndroid Build Coastguard Worker return; 164*0ed15c77SAndroid Build Coastguard Worker } 165*0ed15c77SAndroid Build Coastguard Worker 166*0ed15c77SAndroid Build Coastguard Worker System.out.printf("Test '%s' [hash: 0x%s] -> %.1f msecs\n", msg, Integer.toHexString(hash), msecs); 167*0ed15c77SAndroid Build Coastguard Worker if (lf) { 168*0ed15c77SAndroid Build Coastguard Worker ++roundsDone; 169*0ed15c77SAndroid Build Coastguard Worker if ((roundsDone % 3) == 0 ) { 170*0ed15c77SAndroid Build Coastguard Worker double den = (double) roundsDone; 171*0ed15c77SAndroid Build Coastguard Worker System.out.printf("Averages after %d rounds (%s/%s): %.1f / %.1f msecs\n", 172*0ed15c77SAndroid Build Coastguard Worker (int) den, _desc1, _desc2, 173*0ed15c77SAndroid Build Coastguard Worker timeMsecs[0] / den, timeMsecs[1] / den); 174*0ed15c77SAndroid Build Coastguard Worker } 175*0ed15c77SAndroid Build Coastguard Worker System.out.println(); 176*0ed15c77SAndroid Build Coastguard Worker } 177*0ed15c77SAndroid Build Coastguard Worker if (doGc) { 178*0ed15c77SAndroid Build Coastguard Worker System.out.println("[GC]"); 179*0ed15c77SAndroid Build Coastguard Worker Thread.sleep(100L); 180*0ed15c77SAndroid Build Coastguard Worker System.gc(); 181*0ed15c77SAndroid Build Coastguard Worker Thread.sleep(100L); 182*0ed15c77SAndroid Build Coastguard Worker } 183*0ed15c77SAndroid Build Coastguard Worker } 184*0ed15c77SAndroid Build Coastguard Worker testDeser1(int reps, byte[] input, ObjectReader reader)185*0ed15c77SAndroid Build Coastguard Worker protected double testDeser1(int reps, byte[] input, ObjectReader reader) throws Exception { 186*0ed15c77SAndroid Build Coastguard Worker return _testDeser(reps, input, reader); 187*0ed15c77SAndroid Build Coastguard Worker } testDeser2(int reps, byte[] input, ObjectReader reader)188*0ed15c77SAndroid Build Coastguard Worker protected double testDeser2(int reps, byte[] input, ObjectReader reader) throws Exception { 189*0ed15c77SAndroid Build Coastguard Worker return _testDeser(reps, input, reader); 190*0ed15c77SAndroid Build Coastguard Worker } 191*0ed15c77SAndroid Build Coastguard Worker _testDeser(int reps, byte[] input, ObjectReader reader)192*0ed15c77SAndroid Build Coastguard Worker protected final double _testDeser(int reps, byte[] input, ObjectReader reader) throws Exception 193*0ed15c77SAndroid Build Coastguard Worker { 194*0ed15c77SAndroid Build Coastguard Worker long start = System.nanoTime(); 195*0ed15c77SAndroid Build Coastguard Worker Object result = null; 196*0ed15c77SAndroid Build Coastguard Worker while (--reps >= 0) { 197*0ed15c77SAndroid Build Coastguard Worker result = reader.readValue(input); 198*0ed15c77SAndroid Build Coastguard Worker } 199*0ed15c77SAndroid Build Coastguard Worker hash = result.hashCode(); 200*0ed15c77SAndroid Build Coastguard Worker // return microseconds 201*0ed15c77SAndroid Build Coastguard Worker return _msecsFromNanos(System.nanoTime() - start); 202*0ed15c77SAndroid Build Coastguard Worker } 203*0ed15c77SAndroid Build Coastguard Worker testDeser1(int reps, String input, ObjectReader reader)204*0ed15c77SAndroid Build Coastguard Worker protected double testDeser1(int reps, String input, ObjectReader reader) throws Exception { 205*0ed15c77SAndroid Build Coastguard Worker return _testDeser(reps, input, reader); 206*0ed15c77SAndroid Build Coastguard Worker } 207*0ed15c77SAndroid Build Coastguard Worker testDeser2(int reps, String input, ObjectReader reader)208*0ed15c77SAndroid Build Coastguard Worker protected double testDeser2(int reps, String input, ObjectReader reader) throws Exception { 209*0ed15c77SAndroid Build Coastguard Worker return _testDeser(reps, input, reader); 210*0ed15c77SAndroid Build Coastguard Worker } 211*0ed15c77SAndroid Build Coastguard Worker _testDeser(int reps, String input, ObjectReader reader)212*0ed15c77SAndroid Build Coastguard Worker protected final double _testDeser(int reps, String input, ObjectReader reader) throws Exception 213*0ed15c77SAndroid Build Coastguard Worker { 214*0ed15c77SAndroid Build Coastguard Worker long start = System.nanoTime(); 215*0ed15c77SAndroid Build Coastguard Worker Object result = null; 216*0ed15c77SAndroid Build Coastguard Worker while (--reps >= 0) { 217*0ed15c77SAndroid Build Coastguard Worker result = reader.readValue(input); 218*0ed15c77SAndroid Build Coastguard Worker } 219*0ed15c77SAndroid Build Coastguard Worker hash = result.hashCode(); 220*0ed15c77SAndroid Build Coastguard Worker return _msecsFromNanos(System.nanoTime() - start); 221*0ed15c77SAndroid Build Coastguard Worker } 222*0ed15c77SAndroid Build Coastguard Worker _msecsFromNanos(long nanos)223*0ed15c77SAndroid Build Coastguard Worker protected final double _msecsFromNanos(long nanos) { 224*0ed15c77SAndroid Build Coastguard Worker return (nanos / 1000000.0); 225*0ed15c77SAndroid Build Coastguard Worker } 226*0ed15c77SAndroid Build Coastguard Worker readAll(String filename)227*0ed15c77SAndroid Build Coastguard Worker protected static byte[] readAll(String filename) throws IOException 228*0ed15c77SAndroid Build Coastguard Worker { 229*0ed15c77SAndroid Build Coastguard Worker File f = new File(filename); 230*0ed15c77SAndroid Build Coastguard Worker ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) f.length()); 231*0ed15c77SAndroid Build Coastguard Worker byte[] buffer = new byte[4000]; 232*0ed15c77SAndroid Build Coastguard Worker int count; 233*0ed15c77SAndroid Build Coastguard Worker FileInputStream in = new FileInputStream(f); 234*0ed15c77SAndroid Build Coastguard Worker 235*0ed15c77SAndroid Build Coastguard Worker while ((count = in.read(buffer)) > 0) { 236*0ed15c77SAndroid Build Coastguard Worker bytes.write(buffer, 0, count); 237*0ed15c77SAndroid Build Coastguard Worker } 238*0ed15c77SAndroid Build Coastguard Worker in.close(); 239*0ed15c77SAndroid Build Coastguard Worker return bytes.toByteArray(); 240*0ed15c77SAndroid Build Coastguard Worker } 241*0ed15c77SAndroid Build Coastguard Worker } 242