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    /** @deprecated LOG variable would be made private. */
48    @Deprecated
49    public static final Log LOG = LogFactory.getLog(CodecPerformance.class);
50  
51    static Cell [] getCells(final int howMany) {
52      Cell [] cells = new Cell[howMany];
53      for (int i = 0; i < howMany; i++) {
54        byte [] index = Bytes.toBytes(i);
55        KeyValue kv = new KeyValue(index, Bytes.toBytes("f"), index, index);
56        cells[i] = kv;
57      }
58      return cells;
59    }
60  
61    static int getRoughSize(final Cell [] cells) {
62      int size = 0;
63      for (Cell c: cells) {
64        size += c.getRowLength() + c.getFamilyLength() + c.getQualifierLength() + c.getValueLength();
65        size += Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE;
66      }
67      return size;
68    }
69  
70    static byte [] runEncoderTest(final int index, final int initialBufferSize,
71        final ByteArrayOutputStream baos, final CellOutputStream encoder, final Cell [] cells)
72    throws IOException {
73      long startTime = System.currentTimeMillis();
74      for (int i = 0; i < cells.length; i++) {
75        encoder.write(cells[i]);
76      }
77      encoder.flush();
78      LOG.info("" + index + " encoded count=" + cells.length + " in " +
79        (System.currentTimeMillis() - startTime) + "ms for encoder " + encoder);
80      // Ensure we did not have to grow the backing buffer.
81      assertTrue(baos.size() < initialBufferSize);
82      return baos.toByteArray();
83    }
84  
85    static Cell [] runDecoderTest(final int index, final int count, final CellScanner decoder)
86    throws IOException {
87      Cell [] cells = new Cell[count];
88      long startTime = System.currentTimeMillis();
89      for (int i = 0; decoder.advance(); i++) {
90        cells[i] = decoder.current();
91      }
92      LOG.info("" + index + " decoded count=" + cells.length + " in " +
93        (System.currentTimeMillis() - startTime) + "ms for decoder " + decoder);
94      // Ensure we did not have to grow the backing buffer.
95      assertTrue(cells.length == count);
96      return cells;
97    }
98  
99    static void verifyCells(final Cell [] input, final Cell [] output) {
100     assertEquals(input.length, output.length);
101     for (int i = 0; i < input.length; i ++) {
102       input[i].equals(output[i]);
103     }
104   }
105 
106   static void doCodec(final Codec codec, final Cell [] cells, final int cycles, final int count,
107       final int initialBufferSize)
108   throws IOException {
109     byte [] bytes = null;
110     Cell [] cellsDecoded = null;
111     for (int i = 0; i < cycles; i++) {
112       ByteArrayOutputStream baos = new ByteArrayOutputStream(initialBufferSize);
113       Codec.Encoder encoder = codec.getEncoder(baos);
114       bytes = runEncoderTest(i, initialBufferSize, baos, encoder, cells);
115     }
116     for (int i = 0; i < cycles; i++) {
117       ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
118       Codec.Decoder decoder = codec.getDecoder(bais);
119       cellsDecoded = CodecPerformance.runDecoderTest(i, count, decoder);
120     }
121     verifyCells(cells, cellsDecoded);
122   }
123 
124   public static void main(String[] args) throws IOException {
125     // How many Cells to encode/decode on each cycle.
126     final int count = 100000;
127     // How many times to do an operation; repeat gives hotspot chance to warm up.
128     final int cycles = 30;
129 
130     Cell [] cells = getCells(count);
131     int size = getRoughSize(cells);
132     int initialBufferSize = 2 * size; // Multiply by 2 to ensure we don't have to grow buffer
133 
134     // Test KeyValue codec.
135     doCodec(new KeyValueCodec(), cells, cycles, count, initialBufferSize);
136     doCodec(new CellCodec(), cells, cycles, count, initialBufferSize);
137     doCodec(new MessageCodec(), cells, cycles, count, initialBufferSize);
138   }
139 }