/* * Copyright 2014 the original author or authors. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.xd.samples.serialization; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.esotericsoftware.kryo.io.Output; import org.junit.Before; import org.junit.Test; import org.springframework.util.Assert; import org.springframework.util.StopWatch; import org.springframework.xd.dirt.integration.bus.serializer.kryo.PojoCodec; /** * Base class for microbenchmarking PojoCodec. * * @author David Turanski */ public abstract class AbstractCodecBenchmarkTest { private StopWatch stopWatch; // protected static final int ITERATIONS = 50000; protected final static int ITERATIONS = 2000; protected final static int TEST_DURATION_MILLIS = 15000; // 15 seconds private final static Map<String, Integer> counts = new HashMap<String, Integer>(); @Before public void setUp() throws IOException { stopWatch = new StopWatch("PojoCodec ser/deser - Iterations:" + ITERATIONS + " Duration (ms):" + TEST_DURATION_MILLIS); } @Test public void runBenchmark() throws IOException { PojoCodec codec = getPojoCodec(); Object objectToSerialize = getObjectToSerialize(); Assert.notNull(objectToSerialize, "object to serialized cannot be null."); Assert.notNull(codec, "codec cannot be null."); String className = objectToSerialize.getClass().getName(); warmup(codec, objectToSerialize); doGc(); warmup(codec, objectToSerialize, 3); doGc(); runSerializationBenchmark("serialize " + className, codec, objectToSerialize); doGc(); runDeserializationBenchmark("deserialize " + className, codec, objectToSerialize); report(); } void report() { System.out.println(stopWatch.prettyPrint()); for (StopWatch.TaskInfo taskInfo : stopWatch.getTaskInfo()) { String taskName = taskInfo.getTaskName(); if (!taskName.startsWith("warmup")) { double nanosecs = taskInfo.getTimeMillis() * 1000000.0; double averagens = nanosecs / counts.get(taskName); System.out.println(taskName + ": avg time (ns) " + averagens); } } } private void runSerializationBenchmark(String taskName, PojoCodec codec, Object object) throws IOException { final byte[] buffer = new byte[1024]; stopWatch.start(taskName); long start = System.currentTimeMillis(); int count = 0; while (System.currentTimeMillis() - start < TEST_DURATION_MILLIS) { for (int i = 0; i < ITERATIONS; i++) { final Output output = new Output(buffer, -1); codec.serialize(object, output); count++; } } stopWatch.stop(); counts.put(taskName, count); } private void runDeserializationBenchmark(String taskName, PojoCodec codec, Object object) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); codec.serialize(object, bos); byte[] buffer = bos.toByteArray(); int count = 0; stopWatch.start(taskName); long start = System.currentTimeMillis(); count = 0; while (System.currentTimeMillis() - start < TEST_DURATION_MILLIS) { for (int i = 0; i < ITERATIONS; i++) { codec.deserialize(buffer, object.getClass()); count++; } } stopWatch.stop(); counts.put(taskName, count); } private void warmup(PojoCodec codec, Object obj) throws IOException { warmup(codec, obj, 10); } private void warmup(PojoCodec codec, Object obj, int seconds) throws IOException { //warm up long endTime = System.currentTimeMillis() + seconds * 1000; int i=0; do { runSerializationBenchmark("warmup ("+ seconds + " sec.) iteration:" + i , codec, obj); i++; } while (System.currentTimeMillis() < endTime); } // JVM is not required to honor GC requests, but adding bit of sleep around request is // most likely to give it a chance to do it. protected static void doGc() { try { Thread.sleep(50L); } catch (InterruptedException ie) { System.err.println("Interrupted while sleeping in doGc()"); } System.gc(); try { // longer sleep afterwards (not needed by GC, but may help with scheduling) Thread.sleep(200L); } catch (InterruptedException ie) { System.err.println("Interrupted while sleeping in doGc()"); } } protected abstract PojoCodec getPojoCodec(); protected abstract Object getObjectToSerialize(); }