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