Skip to content

Commit

Permalink
benchmarks: add throughput benchmark for TLS and non TLS configurations
Browse files Browse the repository at this point in the history
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
kofemann committed Apr 9, 2019
1 parent 1d98aaa commit 052e329
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 2 deletions.
84 changes: 84 additions & 0 deletions oncrpc4j-benchmark/pom.xml
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>
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();
}
}
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);
}
}


}
15 changes: 13 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<module>oncrpc4j-spring</module>
<module>oncrpc4j-rpcgen</module>
<module>oncrpc4j-portmapdaemon</module>
<module>oncrpc4j-benchmark</module>
</modules>

<properties>
Expand All @@ -51,7 +52,7 @@

<!-- version of plugins in pluginManagement -->
<build-helper-maven-plugin.version>1.9.1</build-helper-maven-plugin.version>
<exec-maven-plugin.version>1.4.0</exec-maven-plugin.version>
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
<maven-pmd-plugin.version>3.0.1</maven-pmd-plugin.version>

<!-- version of other plugins-->
Expand All @@ -72,6 +73,7 @@
<junit.version>4.12</junit.version>
<mockito-core.version>2.22.0</mockito-core.version>
<logback-classic.version>1.2.3</logback-classic.version>
<jmh.version>1.21</jmh.version>
</properties>


Expand Down Expand Up @@ -272,7 +274,16 @@
<artifactId>bctls-jdk15on</artifactId>
<version>${bc.version}</version>
</dependency>

<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down

0 comments on commit 052e329

Please sign in to comment.