001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.codec;
019
020import static org.junit.Assert.assertArrayEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.ByteArrayInputStream;
024import java.io.ByteArrayOutputStream;
025import java.io.IOException;
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.CellScanner;
028import org.apache.hadoop.hbase.KeyValue;
029import org.apache.hadoop.hbase.io.CellOutputStream;
030import org.apache.hadoop.hbase.util.Bytes;
031import org.apache.yetus.audience.InterfaceAudience;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035/**
036 * Do basic codec performance eval.
037 */
038@InterfaceAudience.Public
039public class CodecPerformance {
040  /** @deprecated LOG variable would be made private. since 1.2, remove in 3.0 */
041  @Deprecated
042  public static final Logger LOG = LoggerFactory.getLogger(CodecPerformance.class);
043
044  static Cell[] getCells(final int howMany) {
045    Cell[] cells = new Cell[howMany];
046    for (int i = 0; i < howMany; i++) {
047      byte[] index = Bytes.toBytes(i);
048      KeyValue kv = new KeyValue(index, Bytes.toBytes("f"), index, index);
049      cells[i] = kv;
050    }
051    return cells;
052  }
053
054  static int getRoughSize(final Cell[] cells) {
055    int size = 0;
056    for (Cell c : cells) {
057      size += c.getRowLength() + c.getFamilyLength() + c.getQualifierLength() + c.getValueLength();
058      size += Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE;
059    }
060    return size;
061  }
062
063  static byte[] runEncoderTest(final int index, final int initialBufferSize,
064    final ByteArrayOutputStream baos, final CellOutputStream encoder, final Cell[] cells)
065    throws IOException {
066    long startTime = System.currentTimeMillis();
067    for (int i = 0; i < cells.length; i++) {
068      encoder.write(cells[i]);
069    }
070    encoder.flush();
071    LOG.info("" + index + " encoded count=" + cells.length + " in "
072      + (System.currentTimeMillis() - startTime) + "ms for encoder " + encoder);
073    // Ensure we did not have to grow the backing buffer.
074    assertTrue(baos.size() < initialBufferSize);
075    return baos.toByteArray();
076  }
077
078  static Cell[] runDecoderTest(final int index, final int count, final CellScanner decoder)
079    throws IOException {
080    Cell[] cells = new Cell[count];
081    long startTime = System.currentTimeMillis();
082    for (int i = 0; decoder.advance(); i++) {
083      cells[i] = decoder.current();
084    }
085    LOG.info("" + index + " decoded count=" + cells.length + " in "
086      + (System.currentTimeMillis() - startTime) + "ms for decoder " + decoder);
087    // Ensure we did not have to grow the backing buffer.
088    assertTrue(cells.length == count);
089    return cells;
090  }
091
092  static void verifyCells(final Cell[] input, final Cell[] output) {
093    assertArrayEquals(input, output);
094  }
095
096  static void doCodec(final Codec codec, final Cell[] cells, final int cycles, final int count,
097    final int initialBufferSize) throws IOException {
098    byte[] bytes = null;
099    Cell[] cellsDecoded = null;
100    for (int i = 0; i < cycles; i++) {
101      ByteArrayOutputStream baos = new ByteArrayOutputStream(initialBufferSize);
102      Codec.Encoder encoder = codec.getEncoder(baos);
103      bytes = runEncoderTest(i, initialBufferSize, baos, encoder, cells);
104    }
105    for (int i = 0; i < cycles; i++) {
106      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
107      Codec.Decoder decoder = codec.getDecoder(bais);
108      cellsDecoded = CodecPerformance.runDecoderTest(i, count, decoder);
109    }
110    verifyCells(cells, cellsDecoded);
111  }
112
113  public static void main(String[] args) throws IOException {
114    // How many Cells to encode/decode on each cycle.
115    final int count = 100000;
116    // How many times to do an operation; repeat gives hotspot chance to warm up.
117    final int cycles = 30;
118
119    Cell[] cells = getCells(count);
120    int size = getRoughSize(cells);
121    int initialBufferSize = 2 * size; // Multiply by 2 to ensure we don't have to grow buffer
122
123    // Test KeyValue codec.
124    doCodec(new KeyValueCodec(), cells, cycles, count, initialBufferSize);
125    doCodec(new CellCodec(), cells, cycles, count, initialBufferSize);
126    doCodec(new MessageCodec(), cells, cycles, count, initialBufferSize);
127  }
128}