From 6ac42afdc646acc4f9cd6e2d8844f86304d187c7 Mon Sep 17 00:00:00 2001 From: Ferdinand Xu Date: Fri, 15 Apr 2016 06:35:33 +0800 Subject: [PATCH] CRYPTO-2: Create benchmark for Apache Commons Crypto Rebase code update gitignore file Add script to support multi-JDK --- .gitignore | 4 +- conf/benchmark.properties.template | 24 ++ pom.xml | 18 ++ sbin/run-benchmark.sh | 35 +++ .../benchmark/CommonsCryptoBenchmark.java | 121 ++++++++++ .../benchmark/CryptoStreamBenchmark.java | 211 ++++++++++++++++++ .../benchmark/option/BenchmarkOption.java | 83 +++++++ .../crypto/benchmark/option/StreamOption.java | 95 ++++++++ 8 files changed, 589 insertions(+), 2 deletions(-) create mode 100644 conf/benchmark.properties.template create mode 100644 sbin/run-benchmark.sh create mode 100644 src/test/java/org/apache/commons/crypto/benchmark/CommonsCryptoBenchmark.java create mode 100644 src/test/java/org/apache/commons/crypto/benchmark/CryptoStreamBenchmark.java create mode 100644 src/test/java/org/apache/commons/crypto/benchmark/option/BenchmarkOption.java create mode 100644 src/test/java/org/apache/commons/crypto/benchmark/option/StreamOption.java diff --git a/.gitignore b/.gitignore index 8a5dd749d..27c910121 100644 --- a/.gitignore +++ b/.gitignore @@ -32,5 +32,5 @@ derby.log dist/ unit-tests.log /lib/ -src/main/resources/com/intel/chimera/native/ -src/main/resources/com/intel/chimera/native/* \ No newline at end of file +dependency-reduced-pom.xml +conf/benchmark.properties diff --git a/conf/benchmark.properties.template b/conf/benchmark.properties.template new file mode 100644 index 000000000..53bbc94dd --- /dev/null +++ b/conf/benchmark.properties.template @@ -0,0 +1,24 @@ +# +# 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. +# +warmupIterations 1000 +iterations 1000 +dataSize 1073741824 +operationSize 8192 + +bufferSize 20 +cipherClasses org.apache.commons.crypto.cipher.OpensslCipher,org.apache.commons.crypto.cipher.JceCipher +transformations AES/CTR/NoPadding,AES/CBC/NoPadding \ No newline at end of file diff --git a/pom.xml b/pom.xml index 479e3b053..231f4154d 100644 --- a/pom.xml +++ b/pom.xml @@ -138,6 +138,8 @@ http://maven.apache.org/maven-v4_0_0.xsd"> CRYPTO 12320024 true + 1.6 + 2.4.3 @@ -332,6 +334,22 @@ http://maven.apache.org/maven-v4_0_0.xsd"> org.apache.maven.plugins maven-compiler-plugin + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + + + + package + + shade + + + + diff --git a/sbin/run-benchmark.sh b/sbin/run-benchmark.sh new file mode 100644 index 000000000..513b5bf50 --- /dev/null +++ b/sbin/run-benchmark.sh @@ -0,0 +1,35 @@ +# +# 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. +# +#!/bin/bash +set -x +if [ "$#" -ne 2 ];then + echo "Usage: sh run-benchmark.sh path/to/JDKwithoutAESNIsupport path/to/JDKwithAESNIsupport \n JDK7u45 or higher supports AES-NI." + exit 1 +fi +echo "This benchmark will evaluate the performance of Chimera in different transfomations, ciphers and JDK versions" + +if [ ! -f "conf/benchmark.properties" ];then + echo "Not able to find the benchmark.propety, will use default propety instead" + cp conf/benchmark.properties.template conf/benchmark.properties +fi + +CRYPTO_JAR=`find . -name commons-crypto*.jar` + +echo "Using JDK in path $1 to evalue the performance" +$1/bin/java -Djava.library.path="$PATH" -cp $CRYPTO_JAR:target/test-classes org.apache.commons.crypto.benchmark.CommonsCryptoBenchmark conf/benchmark.properties +echo "Using JDK in path $2 to evaluate the performance" +$2/bin/java -Djava.library.path="$PATH" -cp $CRYPTO_JAR:target/test-classes org.apache.commons.crypto.benchmark.CommonsCryptoBenchmark conf/benchmark.properties diff --git a/src/test/java/org/apache/commons/crypto/benchmark/CommonsCryptoBenchmark.java b/src/test/java/org/apache/commons/crypto/benchmark/CommonsCryptoBenchmark.java new file mode 100644 index 000000000..cad82bb9f --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/benchmark/CommonsCryptoBenchmark.java @@ -0,0 +1,121 @@ +/** + * 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.commons.crypto.benchmark; + +import org.apache.commons.crypto.benchmark.option.BenchmarkOption; +import org.apache.commons.crypto.benchmark.option.StreamOption; +import org.apache.commons.crypto.cipher.CipherTransformation; + +import java.io.*; +import java.util.Properties; + +public class CommonsCryptoBenchmark { + static String defaultConfigPath = "./conf/benchmark.properties"; + + public static void main(String[] args) throws IOException { + Properties prop = new Properties(); + String propFileName = "benchmark.properties"; + + if (args != null && args.length != 0 && args.length != 1 && args.length != 4) { + System.out.println( + "Usage: java -Djava.library.path=\"$PATH\" -cp path/to/commons-crypto-[version].jar:path/to/target/test-classes/ org.apache.commons.crypto.benchmark.CommonsCryptoBenchmark [warmupIterations] [iterations] [dataSize] [operationSize] or java -Djava.library.path=\"$PATH\" -cp commons-crypto-[version].jar:path/to/Chimera/target/test-classes/ org.apache.commons.crypto.benchmark.CommonsCryptoBenchmark [path/to/configuration]"); + System.out.println("args[0]: " + args[0]); + System.exit(1); + } + + String confFilePath = defaultConfigPath; + if (args.length == 1) { + System.out + .println("Use configurations specified by a configuration file."); + confFilePath = args[0]; + } + + File configFile = new File(confFilePath); + InputStream inputStream; + + if (args.length == 0 || args.length == 1) { + if (configFile.exists()) { + inputStream = new FileInputStream(configFile); + } else { + System.out.println( + "can not find the configuration file under the current path"); + inputStream = CommonsCryptoBenchmark.class.getClassLoader() + .getResourceAsStream(propFileName); + } + prop.load(inputStream); + } + + // Benchmark related configurations + BenchmarkOption.CipherBenchmarkOptionBuilder cipherBenchmarkOptionBuilder + = BenchmarkOption.newBuilder(); + if(args.length == 1){ + if (prop.containsKey("warmupIterations")) { + cipherBenchmarkOptionBuilder.buildWarmupIterations(Integer + .parseInt(prop.getProperty("warmupIterations"))); + } + if (prop.containsKey("iterations")) { + cipherBenchmarkOptionBuilder.buildIterations(Integer + .parseInt(prop.getProperty("iterations"))); + } + if (prop.containsKey("dataSize")) { + cipherBenchmarkOptionBuilder.buildDataSize(Integer.parseInt( + prop.getProperty("dataSize"))); + } + if (prop.containsKey("operationSize")) { + cipherBenchmarkOptionBuilder.buildOperationSize(Integer + .parseInt(prop.getProperty("operationSize"))); + } + }else{ + // specify by cmd + cipherBenchmarkOptionBuilder.buildWarmupIterations(Integer + .parseInt(args[0])); + cipherBenchmarkOptionBuilder.buildIterations(Integer + .parseInt(args[1])); + cipherBenchmarkOptionBuilder.buildDataSize(Integer + .parseInt(args[2])); + cipherBenchmarkOptionBuilder.buildOperationSize(Integer + .parseInt(args[3])); + } + + BenchmarkOption benchmarkOption = cipherBenchmarkOptionBuilder.create(); + + System.out.println("current benchmarkOption option is " + benchmarkOption); + // Stream related configuration + String transformations = (prop.contains("transformations")) ? prop + .getProperty( + "transformations") : ("AES/CTR/NoPadding,AES/CBC/NoPadding"); + String cipherClazzNames = (prop.contains("cipherClasses")) ? prop + .getProperty("cipherClasses") : ("org.apache.commons.crypto.cipher" + + ".OpensslCipher,org.apache.commons.crypto.cipher.JceCipher"); + int bufferSize = (prop.containsKey("bufferSize")) ? Integer + .parseInt(prop.getProperty("bufferSize")) : (512 * 1024); + for (String t : transformations.split(",")) { + for(String c : cipherClazzNames.split(",")){ + CipherTransformation transformation = CipherTransformation.fromName(t); + StreamOption streamOption = StreamOption.newBuilder() + .setBufferSize(bufferSize) + .setCipherTransformation(transformation) + .setCipherClazzName(c).build(); + System.out.println("current stream option is " + streamOption); + CryptoStreamBenchmark cryptoStreamBenchmark = new CryptoStreamBenchmark( + benchmarkOption, streamOption); + cryptoStreamBenchmark.getBenchMarkData(); + } + } + } +} diff --git a/src/test/java/org/apache/commons/crypto/benchmark/CryptoStreamBenchmark.java b/src/test/java/org/apache/commons/crypto/benchmark/CryptoStreamBenchmark.java new file mode 100644 index 000000000..e274e403a --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/benchmark/CryptoStreamBenchmark.java @@ -0,0 +1,211 @@ +/** + * 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.commons.crypto.benchmark; + +import org.apache.commons.crypto.benchmark.option.BenchmarkOption; +import org.apache.commons.crypto.benchmark.option.StreamOption; +import org.apache.commons.crypto.conf.ConfigurationKeys; +import org.apache.commons.crypto.stream.CryptoInputStream; +import org.apache.commons.crypto.stream.CryptoOutputStream; + +import java.io.*; +import java.util.Calendar; +import java.util.Properties; +import java.util.Random; +import java.util.TimeZone; + +public class CryptoStreamBenchmark { + protected String benchMarkName; + protected BenchmarkOption benchmarkOption; + protected StreamOption streamOption; + byte[] inputData; + CryptoInputStream cryptoInputStream; + OutputStream cryptoOutputStream; + ByteArrayInputStream inputStream; + ByteArrayOutputStream outputStream; + + public CryptoStreamBenchmark(BenchmarkOption benchmarkOption, + StreamOption streamOption) { + this.benchmarkOption = benchmarkOption; + this.streamOption = streamOption; + outputStream = new ByteArrayOutputStream(benchmarkOption.dataSize); + inputData = prepareData(benchmarkOption.dataSize); + inputStream = new ByteArrayInputStream(inputData); + benchMarkName = "Benchmark test using " + streamOption + .getCipherClazzName() + " in transformation " + streamOption + .getTransformation(); + } + + OutputStream getCryptoOutputStream() throws IOException { + if (cryptoOutputStream == null) { + Random r = new Random(); + byte[] iv = new byte[16]; + byte[] key = new byte[16]; + r.nextBytes(iv); + r.nextBytes(key); + + Properties props = new Properties(); + props.put(ConfigurationKeys.CHIMERA_CRYPTO_CIPHER_CLASSES_KEY, + streamOption.getCipherClazzName()); + props.put(ConfigurationKeys.CHIMERA_CRYPTO_STREAM_BUFFER_SIZE_KEY, + streamOption.getBufferSize()); + cryptoOutputStream = new CryptoOutputStream( + streamOption.getTransformation(), props, outputStream, key, iv); + } + return cryptoOutputStream; + } + + protected InputStream getCryptoInputStream() throws IOException { + if (cryptoInputStream == null) { + Random r = new Random(); + byte[] iv = new byte[16]; + byte[] key = new byte[16]; + r.nextBytes(iv); + r.nextBytes(key); + + Properties props = new Properties(); + props.put(ConfigurationKeys.CHIMERA_CRYPTO_CIPHER_CLASSES_KEY, + streamOption.getCipherClazzName()); + props.put(ConfigurationKeys.CHIMERA_CRYPTO_STREAM_BUFFER_SIZE_KEY, + streamOption.getBufferSize()); + cryptoInputStream = new CryptoInputStream( + streamOption.getTransformation(), props, inputStream, key, iv); + } + return cryptoInputStream; + } + + protected byte[] prepareData(int size) { + byte[] data = new byte[size]; + Random r = new Random(); + r.nextBytes(data); + return data; + } + + public void testEncryption(int iterations) { + try { + OutputStream cryptoOutputStream = getCryptoOutputStream(); + + System.out.println("warming up"); + // warm up + for (int i = 0; i < benchmarkOption.warmupIterations; i++) { + doWriteOperation(outputStream, cryptoOutputStream, inputData); + } + + System.out.println("warming up complete."); + + long begin = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + .getTimeInMillis(); + for (int i = 0; i < iterations; i++) { + doWriteOperation(outputStream, cryptoOutputStream, inputData); + } + + long end = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + .getTimeInMillis(); + printResult("===encryption", + 1000.0 * benchmarkOption.dataSize * iterations / ((end - begin) * + 1024.0 * 1024.0)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void testDecryption(int iterations) { + try { + InputStream cryptoInputStream = getCryptoInputStream(); + + byte[] outputData = new byte[benchmarkOption.dataSize]; + + System.out.println("Warming up."); + // warm up + for (int i = 0; i < benchmarkOption.warmupIterations; i++) { + doReadOperation(inputStream, cryptoInputStream, outputData); + } + + System.out.println("warming up complete."); + long begin = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + .getTimeInMillis(); + + for (int i = 0; i < iterations; i++) { + doReadOperation(inputStream, cryptoInputStream, outputData); + } + + long end = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + .getTimeInMillis(); + printResult("=== decryption", + 1000.0 * benchmarkOption.dataSize * iterations / ((end - begin) * + 1024.0 * 1024.0)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void doWriteOperation(ByteArrayOutputStream outputStream, + OutputStream cryptoOutputStream, byte[] inputData) + throws IOException { + int offset = 0; + int remaining = benchmarkOption.dataSize; + while (remaining > 0) { + int len = (benchmarkOption.operationSize < remaining) ? + benchmarkOption.operationSize : remaining; + cryptoOutputStream.write(inputData, offset, len); + offset += len; + remaining -= len; + } + outputStream.reset(); + } + + private void doReadOperation(ByteArrayInputStream inputStream, + InputStream cryptoInputStream, byte[] outputData) + throws IOException { + int remaining = benchmarkOption.dataSize; + int offset = 0; + while (remaining > 0) { + int len = (remaining < benchmarkOption.operationSize) ? remaining : + benchmarkOption.operationSize; + int v = cryptoInputStream.read(outputData, offset, len); + offset += v; + remaining -= v; + } + inputStream.reset(); + } + + public void getBenchMarkData() { + System.out.println(); + System.out.println(getBenchMarkName() + " begins!"); + System.out.println("Encryption starts."); + testEncryption(benchmarkOption.iterations); + System.out.println("Encryption ends."); + + System.out.println("Decryption starts."); + testDecryption(benchmarkOption.iterations); + System.out.println("Decryption ends."); + System.out.println(getBenchMarkName() + " ends!"); + System.out.println(); + } + + protected String getBenchMarkName() { + return benchMarkName; + } + + protected void printResult(String operation, double timeCost) { + System.out.println( + "result of " + getBenchMarkName() + " for the " + operation + " operation is " + timeCost + + " M/s"); + System.out.println(); + } +} diff --git a/src/test/java/org/apache/commons/crypto/benchmark/option/BenchmarkOption.java b/src/test/java/org/apache/commons/crypto/benchmark/option/BenchmarkOption.java new file mode 100644 index 000000000..2879b0c0d --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/benchmark/option/BenchmarkOption.java @@ -0,0 +1,83 @@ +/** + * 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.commons.crypto.benchmark.option; + +public class BenchmarkOption { + public int dataSize; + public int operationSize; + public int warmupIterations; + public int iterations; + + private BenchmarkOption() { + } + + private BenchmarkOption(int dataSize, int operationSize, + int warmupIterations, int iterations) { + this.dataSize = dataSize; + this.operationSize = operationSize; + this.warmupIterations = warmupIterations; + this.iterations = iterations; + } + + public static CipherBenchmarkOptionBuilder newBuilder() { + return new CipherBenchmarkOptionBuilder(); + } + + public String toString() { + return "dataSize is " + dataSize + " operationSize is " + operationSize + + " warmupIterations is " + warmupIterations + " iterations is " + + iterations; + } + + public static class CipherBenchmarkOptionBuilder { + public static final int DEFAULT_DATASIZE = 1073741824; + public static final int DEFAULT_OPERATIONSIZE = 8192; + public static final int DEFAULT_WARMUPITERATIONS = 1000; + public static final int DEFAULT_ITERATIONS = 1000; + public int dataSize = DEFAULT_DATASIZE; + public int operationSize = DEFAULT_OPERATIONSIZE; + public int warmupIterations = DEFAULT_WARMUPITERATIONS; + public int iterations = DEFAULT_ITERATIONS; + + public CipherBenchmarkOptionBuilder buildDataSize(int dataSize) { + this.dataSize = dataSize; + return this; + } + + public CipherBenchmarkOptionBuilder buildOperationSize(int operationSize) { + this.operationSize = operationSize; + return this; + } + + public CipherBenchmarkOptionBuilder buildWarmupIterations( + int warmupIterations) { + this.warmupIterations = warmupIterations; + return this; + } + + public CipherBenchmarkOptionBuilder buildIterations(int iterations) { + this.iterations = iterations; + return this; + } + + public BenchmarkOption create() { + return new BenchmarkOption(dataSize, operationSize, warmupIterations, + iterations); + } + } +} diff --git a/src/test/java/org/apache/commons/crypto/benchmark/option/StreamOption.java b/src/test/java/org/apache/commons/crypto/benchmark/option/StreamOption.java new file mode 100644 index 000000000..af2cdfc9f --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/benchmark/option/StreamOption.java @@ -0,0 +1,95 @@ +/** + * 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.commons.crypto.benchmark.option; + +import org.apache.commons.crypto.cipher.CipherTransformation; + +public class StreamOption { + + private CipherTransformation transformation; + private String cipherClazzName; + private int bufferSize; + + private StreamOption() { + } + + private StreamOption(int bufferSize, CipherTransformation transformation, + String cipherClazzName) { + this.bufferSize = bufferSize; + this.transformation = transformation; + this.cipherClazzName = cipherClazzName; + } + + public CipherTransformation getTransformation() { + return transformation; + } + + public void setTransformation( + CipherTransformation transformation) { + this.transformation = transformation; + } + + public int getBufferSize() { + return bufferSize; + } + + public String getCipherClazzName(){ + return cipherClazzName; + } + + public void setBufferSize(int bufferSize) { + this.bufferSize = bufferSize; + } + + public String toString() { + return "CipherTransformation is " + transformation + " " + + "cipherClazzName is " + cipherClazzName + " bufferSize is " + + bufferSize; + } + + public static StreamOptionBuilder newBuilder() { + return new StreamOptionBuilder(); + } + + public static class StreamOptionBuilder { + private static final int DEFAULT_BUFFERSIZE = 512 * 1024; + private CipherTransformation transformation; + private int bufferSize = DEFAULT_BUFFERSIZE; + private String cipherClazzName; + + public StreamOptionBuilder setBufferSize(int bufferSize) { + this.bufferSize = bufferSize; + return this; + } + + public StreamOptionBuilder setCipherTransformation( + CipherTransformation transformation) { + this.transformation = transformation; + return this; + } + + public StreamOptionBuilder setCipherClazzName(String cipherClazzName){ + this.cipherClazzName = cipherClazzName; + return this; + } + + public StreamOption build() { + return new StreamOption(bufferSize, transformation, cipherClazzName); + } + } +}