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