| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.cassandra.test.microbench; |
| |
| import net.jpountz.lz4.LZ4Compressor; |
| import net.jpountz.lz4.LZ4Factory; |
| import net.jpountz.lz4.LZ4SafeDecompressor; |
| import org.openjdk.jmh.annotations.*; |
| import org.xerial.snappy.Snappy; |
| |
| import java.io.IOException; |
| import java.util.concurrent.ThreadLocalRandom; |
| import java.util.concurrent.TimeUnit; |
| |
| @BenchmarkMode(Mode.Throughput) |
| @OutputTimeUnit(TimeUnit.MILLISECONDS) |
| @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) |
| @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) |
| @Fork(value = 1, jvmArgsAppend = "-Xmx512M") |
| @Threads(1) |
| @State(Scope.Benchmark) |
| public class Sample |
| { |
| @Param({"65536"}) |
| private int pageSize; |
| |
| @Param({"1024"}) |
| private int uniquePages; |
| |
| @Param({"0.1"}) |
| private double randomRatio; |
| |
| @Param({"4..16"}) |
| private String randomRunLength; |
| |
| @Param({"4..128"}) |
| private String duplicateLookback; |
| |
| private byte[][] lz4Bytes; |
| private byte[][] snappyBytes; |
| private byte[][] rawBytes; |
| |
| private LZ4SafeDecompressor lz4Decompressor = LZ4Factory.fastestInstance().safeDecompressor(); |
| |
| private LZ4Compressor lz4Compressor = LZ4Factory.fastestInstance().fastCompressor(); |
| |
| @State(Scope.Thread) |
| public static class ThreadState |
| { |
| byte[] bytes; |
| } |
| |
| @Setup |
| public void setup() throws IOException |
| { |
| ThreadLocalRandom random = ThreadLocalRandom.current(); |
| int[] randomRunLength = range(this.randomRunLength); |
| int[] duplicateLookback = range(this.duplicateLookback); |
| rawBytes = new byte[uniquePages][pageSize]; |
| lz4Bytes = new byte[uniquePages][]; |
| snappyBytes = new byte[uniquePages][]; |
| byte[][] runs = new byte[duplicateLookback[1] - duplicateLookback[0]][]; |
| for (int i = 0 ; i < rawBytes.length ; i++) |
| { |
| byte[] trg = rawBytes[0]; |
| int runCount = 0; |
| int byteCount = 0; |
| while (byteCount < trg.length) |
| { |
| byte[] nextRun; |
| if (runCount == 0 || random.nextDouble() < this.randomRatio) |
| { |
| nextRun = new byte[random.nextInt(randomRunLength[0], randomRunLength[1])]; |
| random.nextBytes(nextRun ); |
| runs[runCount % runs.length] = nextRun; |
| runCount++; |
| } |
| else |
| { |
| int index = runCount < duplicateLookback[1] |
| ? random.nextInt(runCount) |
| : (runCount - random.nextInt(duplicateLookback[0], duplicateLookback[1])); |
| nextRun = runs[index % runs.length]; |
| } |
| System.arraycopy(nextRun, 0, trg, byteCount, Math.min(nextRun.length, trg.length - byteCount)); |
| byteCount += nextRun.length; |
| } |
| lz4Bytes[i] = lz4Compressor.compress(trg); |
| snappyBytes[i] = Snappy.compress(trg); |
| } |
| } |
| |
| static int[] range(String spec) |
| { |
| String[] split = spec.split("\\.\\."); |
| return new int[] { Integer.parseInt(split[0]), Integer.parseInt(split[1]) }; |
| } |
| |
| @Benchmark |
| public void lz4(ThreadState state) |
| { |
| if (state.bytes == null) |
| state.bytes = new byte[this.pageSize]; |
| byte[] in = lz4Bytes[ThreadLocalRandom.current().nextInt(lz4Bytes.length)]; |
| lz4Decompressor.decompress(in, state.bytes); |
| } |
| |
| @Benchmark |
| public void snappy(ThreadState state) throws IOException |
| { |
| byte[] in = snappyBytes[ThreadLocalRandom.current().nextInt(snappyBytes.length)]; |
| state.bytes = Snappy.uncompress(in); |
| } |
| } |