1 package perf; 2 3 import com.fasterxml.jackson.databind.ObjectMapper; 4 import com.fasterxml.jackson.databind.ObjectWriter; 5 import com.fasterxml.jackson.databind.SerializationFeature; 6 7 abstract class ObjectWriterTestBase<T1,T2> 8 { 9 protected int hash; 10 targetSizeMegs()11 protected abstract int targetSizeMegs(); 12 test(ObjectMapper mapper, String desc1, T1 inputValue1, Class<? extends T1> inputClass1, String desc2, T2 inputValue2, Class<? extends T2> inputClass2)13 protected void test(ObjectMapper mapper, 14 String desc1, T1 inputValue1, Class<? extends T1> inputClass1, 15 String desc2, T2 inputValue2, Class<? extends T2> inputClass2) 16 throws Exception 17 { 18 final int REPS; 19 { 20 final byte[] input1 = mapper.writeValueAsBytes(inputValue1); 21 final byte[] input2 = mapper.writeValueAsBytes(inputValue2); 22 23 // Let's try to guestimate suitable size, N megs of output 24 REPS = (int) ((double) (targetSizeMegs() * 1000 * 1000) / (double) input1.length); 25 System.out.printf("Read %d bytes to bind (%d as array); will do %d repetitions\n", 26 input1.length, input2.length, REPS); 27 } 28 29 final ObjectWriter writer0 = mapper.writer().with(SerializationFeature.EAGER_SERIALIZER_FETCH); 30 final ObjectWriter writer1 = writer0.forType(inputClass1); 31 final ObjectWriter writer2 = writer0.forType(inputClass2); 32 33 int i = 0; 34 int roundsDone = 0; 35 final int TYPES = 2; 36 37 // Skip first 5 seconds 38 long startMeasure = System.currentTimeMillis() + 5000L; 39 System.out.print("Warming up"); 40 41 final double[] timesMsec = new double[TYPES]; 42 43 while (true) { 44 final int round = (i % TYPES); 45 final boolean lf = (++i % TYPES) == 0; 46 47 String msg; 48 49 ObjectWriter writer; 50 Object value; 51 switch (round) { 52 case 0: 53 msg = desc1; 54 writer = writer1; 55 value = inputValue1; 56 break; 57 case 1: 58 msg = desc2; 59 writer = writer2; 60 value = inputValue2; 61 break; 62 default: 63 throw new Error(); 64 } 65 66 double msecs = testSer(REPS, value, writer); 67 68 // skip first N seconds to let results stabilize 69 if (startMeasure > 0L) { 70 if ((round != 0) || (System.currentTimeMillis() < startMeasure)) { 71 System.out.print("."); 72 continue; 73 } 74 startMeasure = 0L; 75 System.out.println(); 76 System.out.println("Starting measurements..."); 77 Thread.sleep(250L); 78 System.out.println(); 79 } 80 81 timesMsec[round] += msecs; 82 83 if ((i % 17) == 0) { 84 System.out.println("[GC]"); 85 Thread.sleep(100L); 86 System.gc(); 87 Thread.sleep(100L); 88 } 89 90 System.out.printf("Test '%s' [hash: 0x%s] -> %.1f msecs\n", msg, hash, msecs); 91 Thread.sleep(50L); 92 if (!lf) { 93 continue; 94 } 95 96 if ((++roundsDone % 3) == 0) { 97 double den = (double) roundsDone; 98 System.out.printf("Averages after %d rounds (%s/%s): %.1f / %.1f msecs\n", 99 roundsDone, desc1, desc2, 100 timesMsec[0] / den, timesMsec[1] / den); 101 } 102 System.out.println(); 103 } 104 } 105 testSer(int REPS, Object value, ObjectWriter writer)106 protected double testSer(int REPS, Object value, ObjectWriter writer) throws Exception 107 { 108 final NopOutputStream out = new NopOutputStream(); 109 long start = System.nanoTime(); 110 while (--REPS >= 0) { 111 writer.writeValue(out, value); 112 } 113 hash = out.size(); 114 long nanos = System.nanoTime() - start; 115 out.close(); 116 return _msecsFromNanos(nanos); 117 } 118 _msecsFromNanos(long nanos)119 protected final double _msecsFromNanos(long nanos) { 120 return (nanos / 1000000.0); 121 } 122 } 123