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