-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
benchmarks: add throughput benchmark for TLS and non TLS configurations
Motivation: benchmark TLS protocol overhead when used with RPC. Modification: Introduce package oncrpc4j-benchmark. Added profile to run benchmarks at verify stage: $ mvn verify -Pbenchmark Update pom to point to JMH dependencies. Update maven exec plugin version. Result: measurable TLS overhead ~0.5% Benchmark (withTLS) Mode Cnt Score Error Units TlsOverhead.callOpNull true thrpt 25 12865.357 ± 135.963 ops/s TlsOverhead.callOpNull false thrpt 25 12802.179 ± 156.782 ops/s Acked-by: Paul Millar Target: master
- Loading branch information
Showing
4 changed files
with
304 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 | ||
http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.dcache</groupId> | ||
<artifactId>oncrpc4j</artifactId> | ||
<version>3.1.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<name>Set of JMH benchmarks for oncrpc4j</name> | ||
<artifactId>oncrpc4j-benchmarks</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<profiles> | ||
<profile> | ||
<id>benchmark</id> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>exec-maven-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>exec</goal> | ||
</goals> | ||
<phase>integration-test</phase> | ||
</execution> | ||
</executions> | ||
<configuration> | ||
<executable>java</executable> | ||
<classpathScope>test</classpathScope> | ||
<arguments> | ||
<argument>-classpath</argument> | ||
<classpath /> | ||
<argument>org.dcache.oncrpc4j.benchmarks.BenchmarkRunner</argument> | ||
<argument>.*</argument> | ||
</arguments> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</profile> | ||
</profiles> | ||
|
||
<!-- | ||
EXTERNAL DEPENDENCIES | ||
--> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-generator-annprocess</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.bouncycastle</groupId> | ||
<artifactId>bcprov-jdk15on</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.bouncycastle</groupId> | ||
<artifactId>bcprov-ext-jdk15on</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.bouncycastle</groupId> | ||
<artifactId>bcpkix-jdk15on</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.dcache</groupId> | ||
<artifactId>oncrpc4j-core</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
|
||
</dependencies> | ||
|
||
</project> |
23 changes: 23 additions & 0 deletions
23
oncrpc4j-benchmark/src/main/java/org/dcache/oncrpc4j/benchmarks/BenchmarkRunner.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.dcache.oncrpc4j.benchmarks; | ||
|
||
import org.openjdk.jmh.results.format.ResultFormatType; | ||
import org.openjdk.jmh.runner.Runner; | ||
import org.openjdk.jmh.runner.RunnerException; | ||
import org.openjdk.jmh.runner.options.Options; | ||
import org.openjdk.jmh.runner.options.OptionsBuilder; | ||
|
||
|
||
/** | ||
* | ||
*/ | ||
public class BenchmarkRunner { | ||
|
||
public static void main(String[] args) throws RunnerException { | ||
Options opt = new OptionsBuilder() | ||
.include(TlsOverhead.class.getSimpleName()) | ||
.resultFormat(ResultFormatType.JSON) | ||
.build(); | ||
|
||
new Runner(opt).run(); | ||
} | ||
} |
184 changes: 184 additions & 0 deletions
184
oncrpc4j-benchmark/src/main/java/org/dcache/oncrpc4j/benchmarks/TlsOverhead.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
package org.dcache.oncrpc4j.benchmarks; | ||
|
||
import java.io.IOException; | ||
import java.math.BigInteger; | ||
import java.security.GeneralSecurityException; | ||
import java.security.KeyPair; | ||
import java.security.KeyPairGenerator; | ||
import java.security.KeyStore; | ||
import java.security.SecureRandom; | ||
import java.security.cert.Certificate; | ||
import java.util.Date; | ||
import java.util.concurrent.TimeUnit; | ||
import javax.net.ssl.KeyManagerFactory; | ||
import javax.net.ssl.SSLContext; | ||
import javax.net.ssl.TrustManagerFactory; | ||
import org.bouncycastle.asn1.x500.X500Name; | ||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; | ||
import org.bouncycastle.cert.X509CertificateHolder; | ||
import org.bouncycastle.cert.X509v3CertificateBuilder; | ||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | ||
import org.bouncycastle.operator.ContentSigner; | ||
import org.bouncycastle.operator.OperatorCreationException; | ||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; | ||
import org.dcache.oncrpc4j.rpc.OncRpcProgram; | ||
import org.dcache.oncrpc4j.rpc.OncRpcSvc; | ||
import org.dcache.oncrpc4j.rpc.OncRpcSvcBuilder; | ||
import org.dcache.oncrpc4j.rpc.RpcAuthTypeNone; | ||
import org.dcache.oncrpc4j.rpc.RpcCall; | ||
import org.dcache.oncrpc4j.rpc.RpcDispatchable; | ||
import org.dcache.oncrpc4j.rpc.RpcTransport; | ||
import org.dcache.oncrpc4j.rpc.net.IpProtocolType; | ||
import org.dcache.oncrpc4j.xdr.XdrAble; | ||
import org.dcache.oncrpc4j.xdr.XdrVoid; | ||
import org.openjdk.jmh.annotations.Benchmark; | ||
import org.openjdk.jmh.annotations.BenchmarkMode; | ||
import org.openjdk.jmh.annotations.Mode; | ||
import org.openjdk.jmh.annotations.Param; | ||
import org.openjdk.jmh.annotations.Scope; | ||
import org.openjdk.jmh.annotations.Setup; | ||
import org.openjdk.jmh.annotations.State; | ||
import org.openjdk.jmh.annotations.TearDown; | ||
|
||
/** | ||
* | ||
*/ | ||
@State(Scope.Thread) | ||
@BenchmarkMode(Mode.Throughput) | ||
public class TlsOverhead { | ||
|
||
private static final int PROGNUM = 100017; | ||
private static final int PROGVER = 1; | ||
|
||
@Param({"true", "false"}) | ||
private String withTLS; | ||
|
||
private OncRpcSvc svc; | ||
private OncRpcSvc clnt; | ||
private RpcCall clntCall; | ||
private SSLContext sslContext; | ||
|
||
private final RpcDispatchable NULL = (RpcCall call) -> call.reply(XdrVoid.XDR_VOID); | ||
|
||
@Setup | ||
public void setUp() throws IOException, Exception { | ||
|
||
if (Boolean.getBoolean(withTLS)) { | ||
sslContext = createSslContext(); | ||
} | ||
|
||
svc = new OncRpcSvcBuilder() | ||
.withoutAutoPublish() | ||
.withTCP() | ||
.withWorkerThreadIoStrategy() | ||
.withBindAddress("127.0.0.1") | ||
.withSelectorThreadPoolSize(1) | ||
.withWorkerThreadPoolSize(1) | ||
.withRpcService(new OncRpcProgram(PROGNUM, PROGVER), NULL) | ||
.withSSLContext(sslContext) | ||
.withServiceName("svc") | ||
.build(); | ||
svc.start(); | ||
|
||
clnt = new OncRpcSvcBuilder() | ||
.withoutAutoPublish() | ||
.withTCP() | ||
.withClientMode() | ||
.withWorkerThreadIoStrategy() | ||
.withSelectorThreadPoolSize(1) | ||
.withWorkerThreadPoolSize(1) | ||
.withSSLContext(sslContext) | ||
.withServiceName("clnt") | ||
.build(); | ||
clnt.start(); | ||
|
||
RpcTransport t = clnt.connect(svc.getInetSocketAddress(IpProtocolType.TCP)); | ||
clntCall = new RpcCall(PROGNUM, PROGVER, new RpcAuthTypeNone(), t); | ||
} | ||
|
||
@TearDown | ||
public void shutdown() throws IOException { | ||
clnt.stop(); | ||
svc.stop(); | ||
} | ||
|
||
@Benchmark | ||
public XdrAble callOpNull() throws IOException { | ||
|
||
XdrVoid reply = new XdrVoid(); | ||
clntCall.call(0, XdrVoid.XDR_VOID, reply); | ||
return reply; | ||
} | ||
|
||
|
||
public static SSLContext createSslContext() throws Exception { | ||
|
||
char[] password = "password".toCharArray(); | ||
|
||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC"); | ||
keyPairGenerator.initialize(2048, new SecureRandom()); | ||
KeyPair keyPair = keyPairGenerator.generateKeyPair(); | ||
|
||
Certificate certificate = generateSelfSignedCert(keyPair); | ||
Certificate[] certificateChain = {certificate}; | ||
|
||
// create emtpy keystore and put certificates into it | ||
KeyStore keyStore = createEmptyKeystore(); | ||
keyStore.setKeyEntry("private", keyPair.getPrivate(), password, certificateChain); | ||
keyStore.setCertificateEntry("cert", certificate); | ||
|
||
KeyManagerFactory keyManagerFactory | ||
= KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); | ||
keyManagerFactory.init(keyStore, password); | ||
|
||
TrustManagerFactory trustManagerFactory | ||
= TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
trustManagerFactory.init(keyStore); | ||
|
||
SSLContext sslContext = SSLContext.getInstance("TLS"); | ||
sslContext.init(keyManagerFactory.getKeyManagers(), | ||
trustManagerFactory.getTrustManagers(), | ||
new SecureRandom()); | ||
|
||
return sslContext; | ||
} | ||
|
||
private static Certificate generateSelfSignedCert(KeyPair keyPair) throws GeneralSecurityException, OperatorCreationException { | ||
|
||
long notBefore = System.currentTimeMillis(); | ||
long notAfter = notBefore + TimeUnit.DAYS.toMillis(1); | ||
|
||
X500Name subjectDN = new X500Name("CN=localhost, O=dCache.org"); | ||
X500Name issuerDN = subjectDN; | ||
|
||
SubjectPublicKeyInfo subjectPublicKeyInfo | ||
= SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); | ||
|
||
X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(issuerDN, | ||
BigInteger.ONE, | ||
new Date(notBefore), | ||
new Date(notAfter), subjectDN, | ||
subjectPublicKeyInfo); | ||
|
||
String signatureAlgorithm = "SHA256WithRSA"; | ||
|
||
// sign with own key | ||
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm) | ||
.build(keyPair.getPrivate()); | ||
|
||
X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner); | ||
return new JcaX509CertificateConverter().getCertificate(certificateHolder); | ||
} | ||
|
||
private static KeyStore createEmptyKeystore() throws GeneralSecurityException { | ||
try { | ||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | ||
keyStore.load(null, null); | ||
return keyStore; | ||
} catch (IOException e) { | ||
throw new AssertionError(e); | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters