/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.hadoop.record; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; /** * Benchmark for various types of serializations */ public class RecordBench { private static class Times { long init; long serialize; long deserialize; long write; long readFields; }; private static final long SEED = 0xDEADBEEFL; private static final Random rand = new Random(); /** Do not allow to create a new instance of RecordBench */ private RecordBench() {} private static void initBuffers(Record[] buffers) { final int BUFLEN = 32; for (int idx = 0; idx < buffers.length; idx++) { buffers[idx] = new RecBuffer(); int buflen = rand.nextInt(BUFLEN); byte[] bytes = new byte[buflen]; rand.nextBytes(bytes); ((RecBuffer)buffers[idx]).setData(new Buffer(bytes)); } } private static void initStrings(Record[] strings) { final int STRLEN = 32; for (int idx = 0; idx < strings.length; idx++) { strings[idx] = new RecString(); int strlen = rand.nextInt(STRLEN); StringBuilder sb = new StringBuilder(strlen); for (int ich = 0; ich < strlen; ich++) { int cpt = 0; while (true) { cpt = rand.nextInt(0x10FFFF+1); if (Utils.isValidCodePoint(cpt)) { break; } } sb.appendCodePoint(cpt); } ((RecString)strings[idx]).setData(sb.toString()); } } private static void initInts(Record[] ints) { for (int idx = 0; idx < ints.length; idx++) { ints[idx] = new RecInt(); ((RecInt)ints[idx]).setData(rand.nextInt()); } } private static Record[] makeArray(String type, int numRecords, Times times) { Method init = null; try { init = RecordBench.class.getDeclaredMethod("init"+ toCamelCase(type) + "s", new Class[] {Record[].class}); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } Record[] records = new Record[numRecords]; times.init = System.nanoTime(); try { init.invoke(null, new Object[]{records}); } catch (Exception ex) { throw new RuntimeException(ex); } times.init = System.nanoTime() - times.init; return records; } private static void runBinaryBench(String type, int numRecords, Times times) throws IOException { Record[] records = makeArray(type, numRecords, times); ByteArrayOutputStream bout = new ByteArrayOutputStream(); BinaryRecordOutput rout = new BinaryRecordOutput(bout); DataOutputStream dout = new DataOutputStream(bout); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } bout.reset(); times.serialize = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } times.serialize = System.nanoTime() - times.serialize; byte[] serialized = bout.toByteArray(); ByteArrayInputStream bin = new ByteArrayInputStream(serialized); BinaryRecordInput rin = new BinaryRecordInput(bin); times.deserialize = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].deserialize(rin); } times.deserialize = System.nanoTime() - times.deserialize; bout.reset(); times.write = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].write(dout); } times.write = System.nanoTime() - times.write; bin.reset(); DataInputStream din = new DataInputStream(bin); times.readFields = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].readFields(din); } times.readFields = System.nanoTime() - times.readFields; } private static void runCsvBench(String type, int numRecords, Times times) throws IOException { Record[] records = makeArray(type, numRecords, times); ByteArrayOutputStream bout = new ByteArrayOutputStream(); CsvRecordOutput rout = new CsvRecordOutput(bout); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } bout.reset(); times.serialize = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } times.serialize = System.nanoTime() - times.serialize; byte[] serialized = bout.toByteArray(); ByteArrayInputStream bin = new ByteArrayInputStream(serialized); CsvRecordInput rin = new CsvRecordInput(bin); times.deserialize = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].deserialize(rin); } times.deserialize = System.nanoTime() - times.deserialize; } private static void runXmlBench(String type, int numRecords, Times times) throws IOException { Record[] records = makeArray(type, numRecords, times); ByteArrayOutputStream bout = new ByteArrayOutputStream(); XmlRecordOutput rout = new XmlRecordOutput(bout); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } bout.reset(); bout.write("<records>\n".getBytes()); times.serialize = System.nanoTime(); for(int idx = 0; idx < numRecords; idx++) { records[idx].serialize(rout); } times.serialize = System.nanoTime() - times.serialize; bout.write("</records>\n".getBytes()); byte[] serialized = bout.toByteArray(); ByteArrayInputStream bin = new ByteArrayInputStream(serialized); times.deserialize = System.nanoTime(); XmlRecordInput rin = new XmlRecordInput(bin); for(int idx = 0; idx < numRecords; idx++) { records[idx].deserialize(rin); } times.deserialize = System.nanoTime() - times.deserialize; } private static void printTimes(String type, String format, int numRecords, Times times) { System.out.println("Type: " + type + " Format: " + format + " #Records: "+numRecords); if (times.init != 0) { System.out.println("Initialization Time (Per record) : "+ times.init/numRecords + " Nanoseconds"); } if (times.serialize != 0) { System.out.println("Serialization Time (Per Record) : "+ times.serialize/numRecords + " Nanoseconds"); } if (times.deserialize != 0) { System.out.println("Deserialization Time (Per Record) : "+ times.deserialize/numRecords + " Nanoseconds"); } if (times.write != 0) { System.out.println("Write Time (Per Record) : "+ times.write/numRecords + " Nanoseconds"); } if (times.readFields != 0) { System.out.println("ReadFields Time (Per Record) : "+ times.readFields/numRecords + " Nanoseconds"); } System.out.println(); } private static String toCamelCase(String inp) { char firstChar = inp.charAt(0); if (Character.isLowerCase(firstChar)) { return ""+Character.toUpperCase(firstChar) + inp.substring(1); } return inp; } private static void exitOnError() { String usage = "RecordBench {buffer|string|int}"+ " {binary|csv|xml} <numRecords>"; System.out.println(usage); System.exit(1); } /** * @param args the command line arguments */ public static void main(String[] args) throws IOException { String version = "RecordBench v0.1"; System.out.println(version+"\n"); if (args.length != 3) { exitOnError(); } String typeName = args[0]; String format = args[1]; int numRecords = Integer.decode(args[2]).intValue(); Method bench = null; try { bench = RecordBench.class.getDeclaredMethod("run"+ toCamelCase(format) + "Bench", new Class[] {String.class, Integer.TYPE, Times.class}); } catch (NoSuchMethodException ex) { ex.printStackTrace(); exitOnError(); } if (numRecords < 0) { exitOnError(); } // dry run rand.setSeed(SEED); Times times = new Times(); try { bench.invoke(null, new Object[] {typeName, numRecords, times}); } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } // timed run rand.setSeed(SEED); try { bench.invoke(null, new Object[] {typeName, numRecords, times}); } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } printTimes(typeName, format, numRecords, times); } }