PageRenderTime 441ms CodeModel.GetById 38ms RepoModel.GetById 6ms app.codeStats 0ms

/tpc/src/serializers/BenchmarkRunner.java

http://thrift-protobuf-compare.googlecode.com/
Java | 424 lines | 326 code | 54 blank | 44 comment | 28 complexity | 6e3395d3cee5b8c950898ca93ba2487a MD5 | raw file
  1. package serializers;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.Comparator;
  5. import java.util.EnumMap;
  6. import java.util.HashMap;
  7. import java.util.LinkedHashMap;
  8. import java.util.LinkedHashSet;
  9. import java.util.Map;
  10. import java.util.Set;
  11. import java.util.Map.Entry;
  12. import serializers.avro.AvroGenericSerializer;
  13. import serializers.avro.specific.AvroSpecificSerializer;
  14. import serializers.kryo.KryoOptimizedSerializer;
  15. import serializers.kryo.KryoSerializer;
  16. public class BenchmarkRunner
  17. {
  18. public final static int ITERATIONS = 2000;
  19. public final static int TRIALS = 20;
  20. /**
  21. * Number of milliseconds to warm up for each operation type for each serializer. Let's
  22. * start with 3 seconds.
  23. */
  24. final static long WARMUP_MSECS = 3000;
  25. @SuppressWarnings("unchecked")
  26. private Set<ObjectSerializer> _serializers = new LinkedHashSet<ObjectSerializer>();
  27. public static void main(String... args) throws Exception
  28. {
  29. BenchmarkRunner runner = new BenchmarkRunner();
  30. // binary codecs first
  31. runner.addObjectSerializer(new AvroGenericSerializer());
  32. runner.addObjectSerializer(new AvroSpecificSerializer());
  33. runner.addObjectSerializer(new ActiveMQProtobufSerializer());
  34. runner.addObjectSerializer(new ProtobufSerializer());
  35. runner.addObjectSerializer(new ThriftSerializer());
  36. runner.addObjectSerializer(new HessianSerializer());
  37. runner.addObjectSerializer(new KryoSerializer());
  38. runner.addObjectSerializer(new KryoOptimizedSerializer());
  39. runner.addObjectSerializer(new MessagePackSerializer());
  40. // then language default serializers
  41. runner.addObjectSerializer(new JavaSerializer());
  42. runner.addObjectSerializer(new JavaExtSerializer());
  43. runner.addObjectSerializer(new ScalaSerializer());
  44. // then Json
  45. runner.addObjectSerializer(new JsonSerializer());
  46. runner.addObjectSerializer(new JsonDataBindingSerializer());
  47. runner.addObjectSerializer(new JsonMarshallerSerializer());
  48. runner.addObjectSerializer(new ProtostuffJsonSerializer());
  49. runner.addObjectSerializer(new ProtostuffNumericJsonSerializer());
  50. // this is pretty slow; so slow that it's almost not worth keeping but:
  51. runner.addObjectSerializer(new GsonSerializer());
  52. // then xml via stax, textual and binary
  53. runner.addObjectSerializer(new StaxSerializer("stax/woodstox",
  54. new com.ctc.wstx.stax.WstxInputFactory(),
  55. new com.ctc.wstx.stax.WstxOutputFactory()));
  56. runner.addObjectSerializer(new StaxSerializer("stax/aalto",
  57. new com.fasterxml.aalto.stax.InputFactoryImpl(),
  58. new com.fasterxml.aalto.stax.OutputFactoryImpl()));
  59. runner.addObjectSerializer(new StaxSerializer("binaryxml/FI",
  60. new com.sun.xml.fastinfoset.stax.factory.StAXInputFactory(),
  61. new com.sun.xml.fastinfoset.stax.factory.StAXOutputFactory()));
  62. // No point in running all 4 variants: let's just use fastest one:
  63. //runner.addObjectSerializer(new XStreamSerializer("xstream (xpp)", false, null, null));
  64. //runner.addObjectSerializer(new XStreamSerializer("xstream (xpp with conv)", true, null, null));
  65. //runner.addObjectSerializer(new XStreamSerializer("xstream (stax)", false, new com.ctc.wstx.stax.WstxInputFactory(), new com.ctc.wstx.stax.WstxOutputFactory()));
  66. runner.addObjectSerializer(new XStreamSerializer("xstream (stax with conv)",
  67. true,
  68. new com.ctc.wstx.stax.WstxInputFactory(),
  69. new com.ctc.wstx.stax.WstxOutputFactory()));
  70. runner.addObjectSerializer(new JavolutionXMLFormatSerializer());
  71. runner.addObjectSerializer(new SbinarySerializer());
  72. System.out.println("Starting");
  73. runner.start();
  74. }
  75. @SuppressWarnings("unchecked")
  76. private void addObjectSerializer(ObjectSerializer serializer)
  77. {
  78. _serializers.add(serializer);
  79. }
  80. private <T> double createObjects(ObjectSerializer<T> serializer, int iterations) throws Exception
  81. {
  82. long start = System.nanoTime();
  83. for (int i = 0; i < iterations; i++)
  84. {
  85. serializer.create();
  86. }
  87. return iterationTime(System.nanoTime() - start, iterations);
  88. }
  89. private double iterationTime(long delta, int iterations)
  90. {
  91. return (double) delta / (double) (iterations);
  92. }
  93. private <T> double serializeDifferentObjects(ObjectSerializer<T> serializer, int iterations) throws Exception
  94. {
  95. long start = System.nanoTime();
  96. for (int i = 0; i < iterations; i++)
  97. {
  98. T obj = serializer.create();
  99. serializer.serialize(obj);
  100. }
  101. return iterationTime(System.nanoTime()-start, iterations);
  102. }
  103. private <T> double serializeSameObject(ObjectSerializer<T> serializer, int iterations) throws Exception
  104. {
  105. // let's reuse same instance to reduce overhead
  106. T obj = serializer.create();
  107. long delta = 0;
  108. for (int i = 0; i < iterations; i++)
  109. {
  110. long start = System.nanoTime();
  111. serializer.serialize(obj);
  112. delta += System.nanoTime() - start;
  113. if (i % 1000 == 0)
  114. doGc();
  115. }
  116. return iterationTime(delta, iterations);
  117. }
  118. private <T> double deserializeNoFieldAccess(ObjectSerializer<T> serializer, int iterations) throws Exception
  119. {
  120. byte[] array = serializer.serialize(serializer.create());
  121. long start = System.nanoTime();
  122. T result = null;
  123. for (int i = 0; i < iterations; i++)
  124. {
  125. result = serializer.deserialize(array);
  126. }
  127. return iterationTime(System.nanoTime()-start, iterations);
  128. }
  129. private <T> double deserializeAndCheckAllFields(CheckingObjectSerializer<T> serializer, int iterations) throws Exception
  130. {
  131. byte[] array = serializer.serialize(serializer.create());
  132. long delta = 0;
  133. for (int i = 0; i < iterations; i++)
  134. {
  135. long start = System.nanoTime();
  136. T obj = serializer.deserialize(array);
  137. serializer.checkAllFields(obj);
  138. delta += System.nanoTime() - start;
  139. }
  140. return iterationTime(delta, iterations);
  141. }
  142. private <T> double deserializeAndCheckMediaField(CheckingObjectSerializer<T> serializer, int iterations) throws Exception
  143. {
  144. byte[] array = serializer.serialize(serializer.create());
  145. long delta = 0;
  146. for (int i = 0; i < iterations; i++)
  147. {
  148. long start = System.nanoTime();
  149. T obj = serializer.deserialize(array);
  150. serializer.checkMediaField(obj);
  151. delta += System.nanoTime() - start;
  152. }
  153. return iterationTime(delta, iterations);
  154. }
  155. /**
  156. * JVM is not required to honor GC requests, but adding bit of sleep around request is
  157. * most likely to give it a chance to do it.
  158. */
  159. private void doGc()
  160. {
  161. try {
  162. Thread.sleep(50L);
  163. } catch (InterruptedException ie) { }
  164. System.gc();
  165. try { // longer sleep afterwards (not needed by GC, but may help with scheduling)
  166. Thread.sleep(200L);
  167. } catch (InterruptedException ie) { }
  168. }
  169. enum measurements
  170. {
  171. timeCreate, timeSerializeDifferentObjects, timeSerializeSameObject, timeDeserializeNoFieldAccess, timeDeserializeAndCheckMediaField, timeDeserializeAndCheckAllFields, totalTime, length
  172. }
  173. @SuppressWarnings("unchecked")
  174. private void start() throws Exception
  175. {
  176. System.out.printf("%-24s, %15s, %15s, %15s, %15s, %15s, %15s, %15s, %10s\n",
  177. " ",
  178. "Object create",
  179. "Serialize",
  180. "/w Same Object",
  181. "Deserialize",
  182. "and Check Media",
  183. "and Check All",
  184. "Total Time",
  185. "Serialized Size");
  186. EnumMap<measurements, Map<String, Double>> values = new EnumMap<measurements, Map<String, Double>>(measurements.class);
  187. for (measurements m : measurements.values())
  188. values.put(m, new HashMap<String, Double>());
  189. for (ObjectSerializer serializer : _serializers)
  190. {
  191. /*
  192. * Should only warm things for the serializer that we test next: HotSpot JIT will
  193. * otherwise spent most of its time optimizing slower ones... Use
  194. * -XX:CompileThreshold=1 to hint the JIT to start immediately
  195. *
  196. * Actually: 1 is often not a good value -- threshold is the number
  197. * of samples needed to trigger inlining, and there's no point in
  198. * inlining everything. Default value is in thousands, so lowering
  199. * it to, say, 1000 is usually better.
  200. */
  201. warmCreation(serializer);
  202. doGc();
  203. double timeCreate = Double.MAX_VALUE;
  204. // do more iteration for object creation because of its short time
  205. for (int i = 0; i < TRIALS; i++)
  206. timeCreate = Math.min(timeCreate, createObjects(serializer, ITERATIONS * 100));
  207. warmSerialization(serializer);
  208. // actually: let's verify serializer actually works now:
  209. checkCorrectness(serializer);
  210. doGc();
  211. double timeSerializeDifferentObjects = Double.MAX_VALUE;
  212. for (int i = 0; i < TRIALS; i++)
  213. timeSerializeDifferentObjects = Math.min(timeSerializeDifferentObjects, serializeDifferentObjects(serializer, ITERATIONS));
  214. doGc();
  215. double timeSerializeSameObject = Double.MAX_VALUE;
  216. for (int i = 0; i < TRIALS; i++)
  217. timeSerializeSameObject = Math.min(timeSerializeSameObject, serializeSameObject(serializer, ITERATIONS));
  218. warmDeserialization(serializer);
  219. doGc();
  220. double timeDeserializeNoFieldAccess = Double.MAX_VALUE;
  221. for (int i = 0; i < TRIALS; i++)
  222. timeDeserializeNoFieldAccess = Math.min(timeDeserializeNoFieldAccess, deserializeNoFieldAccess(serializer, ITERATIONS));
  223. double timeDeserializeAndCheckAllFields = timeDeserializeNoFieldAccess;
  224. double timeDeserializeAndCheckMediaField = timeDeserializeNoFieldAccess;
  225. double totalTime = timeSerializeDifferentObjects + timeDeserializeNoFieldAccess;
  226. if( serializer instanceof CheckingObjectSerializer) {
  227. CheckingObjectSerializer checkingSerializer = (CheckingObjectSerializer)serializer;
  228. timeDeserializeAndCheckMediaField = Double.MAX_VALUE;
  229. doGc();
  230. for (int i = 0; i < TRIALS; i++)
  231. timeDeserializeAndCheckMediaField = Math.min(timeDeserializeAndCheckMediaField, deserializeAndCheckMediaField(checkingSerializer, ITERATIONS));
  232. timeDeserializeAndCheckAllFields = Double.MAX_VALUE;
  233. doGc();
  234. for (int i = 0; i < TRIALS; i++)
  235. timeDeserializeAndCheckAllFields = Math.min(timeDeserializeAndCheckAllFields, deserializeAndCheckAllFields(checkingSerializer, ITERATIONS));
  236. totalTime = timeSerializeDifferentObjects + timeDeserializeAndCheckAllFields;
  237. }
  238. byte[] array = serializer.serialize(serializer.create());
  239. System.out.printf("%-24s, %15.5f, %15.5f, %15.5f, %15.5f, %15.5f, %15.5f, %15.5f, %10d\n",
  240. serializer.getName(),
  241. timeCreate,
  242. timeSerializeDifferentObjects,
  243. timeSerializeSameObject,
  244. timeDeserializeNoFieldAccess,
  245. timeDeserializeAndCheckMediaField,
  246. timeDeserializeAndCheckAllFields,
  247. totalTime,
  248. array.length);
  249. addValue(values, serializer.getName(), timeCreate, timeSerializeDifferentObjects, timeSerializeSameObject,
  250. timeDeserializeNoFieldAccess, timeDeserializeAndCheckMediaField, timeDeserializeAndCheckAllFields, totalTime, array.length);
  251. }
  252. printImages(values);
  253. }
  254. /**
  255. * Method that tries to validate correctness of serializer, using
  256. * round-trip (construct, serializer, deserialize; compare objects
  257. * after steps 1 and 3).
  258. * Currently only done for StdMediaDeserializer...
  259. */
  260. private void checkCorrectness(ObjectSerializer serializer)
  261. throws Exception
  262. {
  263. Object input = serializer.create();
  264. byte[] array = serializer.serialize(input);
  265. Object output = serializer.deserialize(array);
  266. if (!input.equals(output)) {
  267. /* Should throw an exception; but for now (that we have a few
  268. * failures) let's just whine...
  269. */
  270. String msg = "serializer '"+serializer.getName()+"' failed round-trip test (ser+deser produces Object different from input), input="+input+", output="+output;
  271. //throw new Exception("Error: "+msg);
  272. System.err.println("WARN: "+msg);
  273. }
  274. }
  275. private void printImages(EnumMap<measurements, Map<String, Double>> values)
  276. {
  277. for (measurements m : values.keySet()) {
  278. Map<String, Double> map = values.get(m);
  279. ArrayList<Entry> list = new ArrayList(map.entrySet());
  280. Collections.sort(list, new Comparator<Entry>() {
  281. public int compare (Entry o1, Entry o2) {
  282. double diff = (Double)o1.getValue() - (Double)o2.getValue();
  283. return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
  284. }
  285. });
  286. LinkedHashMap<String, Double> sortedMap = new LinkedHashMap<String, Double>();
  287. for (Entry<String, Double> entry : list) {
  288. if( !entry.getValue().isNaN() ) {
  289. sortedMap.put(entry.getKey(), entry.getValue());
  290. }
  291. }
  292. if (!sortedMap.isEmpty()) printImage(sortedMap, m);
  293. }
  294. }
  295. private void printImage(Map<String, Double> map, measurements m)
  296. {
  297. StringBuilder valSb = new StringBuilder();
  298. String names = "";
  299. double max = Double.MIN_NORMAL;
  300. for (Entry<String, Double> entry : map.entrySet())
  301. {
  302. valSb.append(entry.getValue()).append(',');
  303. max = Math.max(max, entry.getValue());
  304. names = entry.getKey() + '|' + names;
  305. }
  306. int height = Math.min(30+map.size()*20, 430);
  307. double scale = max * 1.1;
  308. System.out.println("<img src='http://chart.apis.google.com/chart?chtt="
  309. + m.name()
  310. + "&chf=c||lg||0||FFFFFF||1||76A4FB||0|bg||s||EFEFEF&chs=689x"+height+"&chd=t:"
  311. + valSb.toString().substring(0, valSb.length() - 1)
  312. + "&chds=0,"+ scale
  313. + "&chxt=y"
  314. + "&chxl=0:|" + names.substring(0, names.length() - 1)
  315. + "&chm=N *f*,000000,0,-1,10&lklk&chdlp=t&chco=660000|660033|660066|660099|6600CC|6600FF|663300|663333|663366|663399|6633CC|6633FF|666600|666633|666666&cht=bhg&chbh=10&nonsense=aaa.png'/>");
  316. }
  317. private void addValue(EnumMap<measurements, Map<String, Double>> values,
  318. String name,
  319. double timeCreate,
  320. double timeSerializeDifferentObjects,
  321. double timeSerializeSameObject,
  322. double timeDeserializeNoFieldAccess,
  323. double timeDeserializeAndCheckMediaField,
  324. double timeDeserializeAndCheckAllFields,
  325. double totalTime,
  326. double length)
  327. {
  328. // Omit some charts for serializers that are extremely slow.
  329. if (!name.equals("json/google-gson") && !name.equals("scala")) {
  330. values.get(measurements.timeSerializeDifferentObjects).put(name, timeSerializeDifferentObjects);
  331. values.get(measurements.timeSerializeSameObject).put(name, timeSerializeSameObject);
  332. values.get(measurements.timeDeserializeNoFieldAccess).put(name, timeDeserializeNoFieldAccess);
  333. values.get(measurements.timeDeserializeAndCheckMediaField).put(name, timeDeserializeAndCheckMediaField);
  334. values.get(measurements.timeDeserializeAndCheckAllFields).put(name, timeDeserializeAndCheckAllFields);
  335. values.get(measurements.totalTime).put(name, totalTime);
  336. }
  337. values.get(measurements.length).put(name, length);
  338. values.get(measurements.timeCreate).put(name, timeCreate);
  339. }
  340. private <T> void warmCreation(ObjectSerializer<T> serializer) throws Exception
  341. {
  342. // Instead of fixed counts, let's try to prime by running for N seconds
  343. long endTime = System.currentTimeMillis() + WARMUP_MSECS;
  344. do
  345. {
  346. createObjects(serializer, 1);
  347. }
  348. while (System.currentTimeMillis() < endTime);
  349. }
  350. private <T> void warmSerialization(ObjectSerializer<T> serializer) throws Exception
  351. {
  352. // Instead of fixed counts, let's try to prime by running for N seconds
  353. long endTime = System.currentTimeMillis() + WARMUP_MSECS;
  354. do
  355. {
  356. serializeDifferentObjects(serializer, 1);
  357. }
  358. while (System.currentTimeMillis() < endTime);
  359. }
  360. private <T> void warmDeserialization(ObjectSerializer<T> serializer) throws Exception
  361. {
  362. // Instead of fixed counts, let's try to prime by running for N seconds
  363. long endTime = System.currentTimeMillis() + WARMUP_MSECS;
  364. do
  365. {
  366. deserializeNoFieldAccess(serializer, 1);
  367. }
  368. while (System.currentTimeMillis() < endTime);
  369. }
  370. }