View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.codec;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.classification.InterfaceAudience;
30  import org.apache.hadoop.hbase.classification.InterfaceStability;
31  import org.apache.hadoop.hbase.Cell;
32  import org.apache.hadoop.hbase.CellScanner;
33  import org.apache.hadoop.hbase.KeyValue;
34  import org.apache.hadoop.hbase.codec.CellCodec;
35  import org.apache.hadoop.hbase.codec.Codec;
36  import org.apache.hadoop.hbase.codec.KeyValueCodec;
37  import org.apache.hadoop.hbase.codec.MessageCodec;
38  import org.apache.hadoop.hbase.io.CellOutputStream;
39  import org.apache.hadoop.hbase.util.Bytes;
40  
41  /**
42   * Do basic codec performance eval.
43   */
44  @InterfaceAudience.Public
45  @InterfaceStability.Evolving
46  public class CodecPerformance {
47    public static final Log LOG = LogFactory.getLog(CodecPerformance.class);
48  
49    static Cell [] getCells(final int howMany) {
50      Cell [] cells = new Cell[howMany];
51      for (int i = 0; i < howMany; i++) {
52        byte [] index = Bytes.toBytes(i);
53        KeyValue kv = new KeyValue(index, Bytes.toBytes("f"), index, index);
54        cells[i] = kv;
55      }
56      return cells;
57    }
58  
59    static int getRoughSize(final Cell [] cells) {
60      int size = 0;
61      for (Cell c: cells) {
62        size += c.getRowLength() + c.getFamilyLength() + c.getQualifierLength() + c.getValueLength();
63        size += Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE;
64      }
65      return size;
66    }
67  
68    static byte [] runEncoderTest(final int index, final int initialBufferSize,
69        final ByteArrayOutputStream baos, final CellOutputStream encoder, final Cell [] cells)
70    throws IOException {
71      long startTime = System.currentTimeMillis();
72      for (int i = 0; i < cells.length; i++) {
73        encoder.write(cells[i]);
74      }
75      encoder.flush();
76      LOG.info("" + index + " encoded count=" + cells.length + " in " +
77        (System.currentTimeMillis() - startTime) + "ms for encoder " + encoder);
78      // Ensure we did not have to grow the backing buffer.
79      assertTrue(baos.size() < initialBufferSize);
80      return baos.toByteArray();
81    }
82  
83    static Cell [] runDecoderTest(final int index, final int count, final CellScanner decoder)
84    throws IOException {
85      Cell [] cells = new Cell[count];
86      long startTime = System.currentTimeMillis();
87      for (int i = 0; decoder.advance(); i++) {
88        cells[i] = decoder.current();
89      }
90      LOG.info("" + index + " decoded count=" + cells.length + " in " +
91        (System.currentTimeMillis() - startTime) + "ms for decoder " + decoder);
92      // Ensure we did not have to grow the backing buffer.
93      assertTrue(cells.length == count);
94      return cells;
95    }
96  
97    static void verifyCells(final Cell [] input, final Cell [] output) {
98      assertEquals(input.length, output.length);
99      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 }