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.assertEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.ByteArrayInputStream;
024import java.io.ByteArrayOutputStream;
025import java.io.IOException;
026
027import org.apache.yetus.audience.InterfaceAudience;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030import org.apache.hadoop.hbase.Cell;
031import org.apache.hadoop.hbase.CellScanner;
032import org.apache.hadoop.hbase.KeyValue;
033import org.apache.hadoop.hbase.codec.CellCodec;
034import org.apache.hadoop.hbase.codec.Codec;
035import org.apache.hadoop.hbase.codec.KeyValueCodec;
036import org.apache.hadoop.hbase.codec.MessageCodec;
037import org.apache.hadoop.hbase.io.CellOutputStream;
038import org.apache.hadoop.hbase.util.Bytes;
039
040/**
041 * Do basic codec performance eval.
042 */
043@InterfaceAudience.Public
044public class CodecPerformance {
045  /** @deprecated LOG variable would be made private. since 1.2, remove in 3.0 */
046  @Deprecated
047  public static final Logger LOG = LoggerFactory.getLogger(CodecPerformance.class);
048
049  static Cell [] getCells(final int howMany) {
050    Cell [] cells = new Cell[howMany];
051    for (int i = 0; i < howMany; i++) {
052      byte [] index = Bytes.toBytes(i);
053      KeyValue kv = new KeyValue(index, Bytes.toBytes("f"), index, index);
054      cells[i] = kv;
055    }
056    return cells;
057  }
058
059  static int getRoughSize(final Cell [] cells) {
060    int size = 0;
061    for (Cell c: cells) {
062      size += c.getRowLength() + c.getFamilyLength() + c.getQualifierLength() + c.getValueLength();
063      size += Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE;
064    }
065    return size;
066  }
067
068  static byte [] runEncoderTest(final int index, final int initialBufferSize,
069      final ByteArrayOutputStream baos, final CellOutputStream encoder, final Cell [] cells)
070  throws IOException {
071    long startTime = System.currentTimeMillis();
072    for (int i = 0; i < cells.length; i++) {
073      encoder.write(cells[i]);
074    }
075    encoder.flush();
076    LOG.info("" + index + " encoded count=" + cells.length + " in " +
077      (System.currentTimeMillis() - startTime) + "ms for encoder " + encoder);
078    // Ensure we did not have to grow the backing buffer.
079    assertTrue(baos.size() < initialBufferSize);
080    return baos.toByteArray();
081  }
082
083  static Cell [] runDecoderTest(final int index, final int count, final CellScanner decoder)
084  throws IOException {
085    Cell [] cells = new Cell[count];
086    long startTime = System.currentTimeMillis();
087    for (int i = 0; decoder.advance(); i++) {
088      cells[i] = decoder.current();
089    }
090    LOG.info("" + index + " decoded count=" + cells.length + " in " +
091      (System.currentTimeMillis() - startTime) + "ms for decoder " + decoder);
092    // Ensure we did not have to grow the backing buffer.
093    assertTrue(cells.length == count);
094    return cells;
095  }
096
097  static void verifyCells(final Cell [] input, final Cell [] output) {
098    assertEquals(input.length, output.length);
099    for (int i = 0; i < input.length; i ++) {
100      input[i].equals(output[i]);
101    }
102  }
103
104  static void doCodec(final Codec codec, final Cell [] cells, final int cycles, final int count,
105      final int initialBufferSize)
106  throws IOException {
107    byte [] bytes = null;
108    Cell [] cellsDecoded = null;
109    for (int i = 0; i < cycles; i++) {
110      ByteArrayOutputStream baos = new ByteArrayOutputStream(initialBufferSize);
111      Codec.Encoder encoder = codec.getEncoder(baos);
112      bytes = runEncoderTest(i, initialBufferSize, baos, encoder, cells);
113    }
114    for (int i = 0; i < cycles; i++) {
115      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
116      Codec.Decoder decoder = codec.getDecoder(bais);
117      cellsDecoded = CodecPerformance.runDecoderTest(i, count, decoder);
118    }
119    verifyCells(cells, cellsDecoded);
120  }
121
122  public static void main(String[] args) throws IOException {
123    // How many Cells to encode/decode on each cycle.
124    final int count = 100000;
125    // How many times to do an operation; repeat gives hotspot chance to warm up.
126    final int cycles = 30;
127
128    Cell [] cells = getCells(count);
129    int size = getRoughSize(cells);
130    int initialBufferSize = 2 * size; // Multiply by 2 to ensure we don't have to grow buffer
131
132    // Test KeyValue codec.
133    doCodec(new KeyValueCodec(), cells, cycles, count, initialBufferSize);
134    doCodec(new CellCodec(), cells, cycles, count, initialBufferSize);
135    doCodec(new MessageCodec(), cells, cycles, count, initialBufferSize);
136  }
137}