Skip to content

Commit 052e329

Browse files
committed
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
1 parent 1d98aaa commit 052e329

File tree

4 files changed

+304
-2
lines changed

4 files changed

+304
-2
lines changed

oncrpc4j-benchmark/pom.xml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
4+
http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>org.dcache</groupId>
10+
<artifactId>oncrpc4j</artifactId>
11+
<version>3.1.0-SNAPSHOT</version>
12+
</parent>
13+
14+
<name>Set of JMH benchmarks for oncrpc4j</name>
15+
<artifactId>oncrpc4j-benchmarks</artifactId>
16+
<packaging>jar</packaging>
17+
18+
<profiles>
19+
<profile>
20+
<id>benchmark</id>
21+
<build>
22+
<plugins>
23+
<plugin>
24+
<groupId>org.codehaus.mojo</groupId>
25+
<artifactId>exec-maven-plugin</artifactId>
26+
<executions>
27+
<execution>
28+
<goals>
29+
<goal>exec</goal>
30+
</goals>
31+
<phase>integration-test</phase>
32+
</execution>
33+
</executions>
34+
<configuration>
35+
<executable>java</executable>
36+
<classpathScope>test</classpathScope>
37+
<arguments>
38+
<argument>-classpath</argument>
39+
<classpath />
40+
<argument>org.dcache.oncrpc4j.benchmarks.BenchmarkRunner</argument>
41+
<argument>.*</argument>
42+
</arguments>
43+
</configuration>
44+
</plugin>
45+
</plugins>
46+
</build>
47+
</profile>
48+
</profiles>
49+
50+
<!--
51+
EXTERNAL DEPENDENCIES
52+
-->
53+
<dependencies>
54+
<dependency>
55+
<groupId>org.openjdk.jmh</groupId>
56+
<artifactId>jmh-core</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.openjdk.jmh</groupId>
60+
<artifactId>jmh-generator-annprocess</artifactId>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.bouncycastle</groupId>
65+
<artifactId>bcprov-jdk15on</artifactId>
66+
</dependency>
67+
<dependency>
68+
<groupId>org.bouncycastle</groupId>
69+
<artifactId>bcprov-ext-jdk15on</artifactId>
70+
</dependency>
71+
<dependency>
72+
<groupId>org.bouncycastle</groupId>
73+
<artifactId>bcpkix-jdk15on</artifactId>
74+
</dependency>
75+
76+
<dependency>
77+
<groupId>org.dcache</groupId>
78+
<artifactId>oncrpc4j-core</artifactId>
79+
<version>${project.version}</version>
80+
</dependency>
81+
82+
</dependencies>
83+
84+
</project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.dcache.oncrpc4j.benchmarks;
2+
3+
import org.openjdk.jmh.results.format.ResultFormatType;
4+
import org.openjdk.jmh.runner.Runner;
5+
import org.openjdk.jmh.runner.RunnerException;
6+
import org.openjdk.jmh.runner.options.Options;
7+
import org.openjdk.jmh.runner.options.OptionsBuilder;
8+
9+
10+
/**
11+
*
12+
*/
13+
public class BenchmarkRunner {
14+
15+
public static void main(String[] args) throws RunnerException {
16+
Options opt = new OptionsBuilder()
17+
.include(TlsOverhead.class.getSimpleName())
18+
.resultFormat(ResultFormatType.JSON)
19+
.build();
20+
21+
new Runner(opt).run();
22+
}
23+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package org.dcache.oncrpc4j.benchmarks;
2+
3+
import java.io.IOException;
4+
import java.math.BigInteger;
5+
import java.security.GeneralSecurityException;
6+
import java.security.KeyPair;
7+
import java.security.KeyPairGenerator;
8+
import java.security.KeyStore;
9+
import java.security.SecureRandom;
10+
import java.security.cert.Certificate;
11+
import java.util.Date;
12+
import java.util.concurrent.TimeUnit;
13+
import javax.net.ssl.KeyManagerFactory;
14+
import javax.net.ssl.SSLContext;
15+
import javax.net.ssl.TrustManagerFactory;
16+
import org.bouncycastle.asn1.x500.X500Name;
17+
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
18+
import org.bouncycastle.cert.X509CertificateHolder;
19+
import org.bouncycastle.cert.X509v3CertificateBuilder;
20+
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
21+
import org.bouncycastle.operator.ContentSigner;
22+
import org.bouncycastle.operator.OperatorCreationException;
23+
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
24+
import org.dcache.oncrpc4j.rpc.OncRpcProgram;
25+
import org.dcache.oncrpc4j.rpc.OncRpcSvc;
26+
import org.dcache.oncrpc4j.rpc.OncRpcSvcBuilder;
27+
import org.dcache.oncrpc4j.rpc.RpcAuthTypeNone;
28+
import org.dcache.oncrpc4j.rpc.RpcCall;
29+
import org.dcache.oncrpc4j.rpc.RpcDispatchable;
30+
import org.dcache.oncrpc4j.rpc.RpcTransport;
31+
import org.dcache.oncrpc4j.rpc.net.IpProtocolType;
32+
import org.dcache.oncrpc4j.xdr.XdrAble;
33+
import org.dcache.oncrpc4j.xdr.XdrVoid;
34+
import org.openjdk.jmh.annotations.Benchmark;
35+
import org.openjdk.jmh.annotations.BenchmarkMode;
36+
import org.openjdk.jmh.annotations.Mode;
37+
import org.openjdk.jmh.annotations.Param;
38+
import org.openjdk.jmh.annotations.Scope;
39+
import org.openjdk.jmh.annotations.Setup;
40+
import org.openjdk.jmh.annotations.State;
41+
import org.openjdk.jmh.annotations.TearDown;
42+
43+
/**
44+
*
45+
*/
46+
@State(Scope.Thread)
47+
@BenchmarkMode(Mode.Throughput)
48+
public class TlsOverhead {
49+
50+
private static final int PROGNUM = 100017;
51+
private static final int PROGVER = 1;
52+
53+
@Param({"true", "false"})
54+
private String withTLS;
55+
56+
private OncRpcSvc svc;
57+
private OncRpcSvc clnt;
58+
private RpcCall clntCall;
59+
private SSLContext sslContext;
60+
61+
private final RpcDispatchable NULL = (RpcCall call) -> call.reply(XdrVoid.XDR_VOID);
62+
63+
@Setup
64+
public void setUp() throws IOException, Exception {
65+
66+
if (Boolean.getBoolean(withTLS)) {
67+
sslContext = createSslContext();
68+
}
69+
70+
svc = new OncRpcSvcBuilder()
71+
.withoutAutoPublish()
72+
.withTCP()
73+
.withWorkerThreadIoStrategy()
74+
.withBindAddress("127.0.0.1")
75+
.withSelectorThreadPoolSize(1)
76+
.withWorkerThreadPoolSize(1)
77+
.withRpcService(new OncRpcProgram(PROGNUM, PROGVER), NULL)
78+
.withSSLContext(sslContext)
79+
.withServiceName("svc")
80+
.build();
81+
svc.start();
82+
83+
clnt = new OncRpcSvcBuilder()
84+
.withoutAutoPublish()
85+
.withTCP()
86+
.withClientMode()
87+
.withWorkerThreadIoStrategy()
88+
.withSelectorThreadPoolSize(1)
89+
.withWorkerThreadPoolSize(1)
90+
.withSSLContext(sslContext)
91+
.withServiceName("clnt")
92+
.build();
93+
clnt.start();
94+
95+
RpcTransport t = clnt.connect(svc.getInetSocketAddress(IpProtocolType.TCP));
96+
clntCall = new RpcCall(PROGNUM, PROGVER, new RpcAuthTypeNone(), t);
97+
}
98+
99+
@TearDown
100+
public void shutdown() throws IOException {
101+
clnt.stop();
102+
svc.stop();
103+
}
104+
105+
@Benchmark
106+
public XdrAble callOpNull() throws IOException {
107+
108+
XdrVoid reply = new XdrVoid();
109+
clntCall.call(0, XdrVoid.XDR_VOID, reply);
110+
return reply;
111+
}
112+
113+
114+
public static SSLContext createSslContext() throws Exception {
115+
116+
char[] password = "password".toCharArray();
117+
118+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
119+
keyPairGenerator.initialize(2048, new SecureRandom());
120+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
121+
122+
Certificate certificate = generateSelfSignedCert(keyPair);
123+
Certificate[] certificateChain = {certificate};
124+
125+
// create emtpy keystore and put certificates into it
126+
KeyStore keyStore = createEmptyKeystore();
127+
keyStore.setKeyEntry("private", keyPair.getPrivate(), password, certificateChain);
128+
keyStore.setCertificateEntry("cert", certificate);
129+
130+
KeyManagerFactory keyManagerFactory
131+
= KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
132+
keyManagerFactory.init(keyStore, password);
133+
134+
TrustManagerFactory trustManagerFactory
135+
= TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
136+
trustManagerFactory.init(keyStore);
137+
138+
SSLContext sslContext = SSLContext.getInstance("TLS");
139+
sslContext.init(keyManagerFactory.getKeyManagers(),
140+
trustManagerFactory.getTrustManagers(),
141+
new SecureRandom());
142+
143+
return sslContext;
144+
}
145+
146+
private static Certificate generateSelfSignedCert(KeyPair keyPair) throws GeneralSecurityException, OperatorCreationException {
147+
148+
long notBefore = System.currentTimeMillis();
149+
long notAfter = notBefore + TimeUnit.DAYS.toMillis(1);
150+
151+
X500Name subjectDN = new X500Name("CN=localhost, O=dCache.org");
152+
X500Name issuerDN = subjectDN;
153+
154+
SubjectPublicKeyInfo subjectPublicKeyInfo
155+
= SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
156+
157+
X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(issuerDN,
158+
BigInteger.ONE,
159+
new Date(notBefore),
160+
new Date(notAfter), subjectDN,
161+
subjectPublicKeyInfo);
162+
163+
String signatureAlgorithm = "SHA256WithRSA";
164+
165+
// sign with own key
166+
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
167+
.build(keyPair.getPrivate());
168+
169+
X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);
170+
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
171+
}
172+
173+
private static KeyStore createEmptyKeystore() throws GeneralSecurityException {
174+
try {
175+
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
176+
keyStore.load(null, null);
177+
return keyStore;
178+
} catch (IOException e) {
179+
throw new AssertionError(e);
180+
}
181+
}
182+
183+
184+
}

pom.xml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<module>oncrpc4j-spring</module>
4242
<module>oncrpc4j-rpcgen</module>
4343
<module>oncrpc4j-portmapdaemon</module>
44+
<module>oncrpc4j-benchmark</module>
4445
</modules>
4546

4647
<properties>
@@ -51,7 +52,7 @@
5152

5253
<!-- version of plugins in pluginManagement -->
5354
<build-helper-maven-plugin.version>1.9.1</build-helper-maven-plugin.version>
54-
<exec-maven-plugin.version>1.4.0</exec-maven-plugin.version>
55+
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
5556
<maven-pmd-plugin.version>3.0.1</maven-pmd-plugin.version>
5657

5758
<!-- version of other plugins-->
@@ -72,6 +73,7 @@
7273
<junit.version>4.12</junit.version>
7374
<mockito-core.version>2.22.0</mockito-core.version>
7475
<logback-classic.version>1.2.3</logback-classic.version>
76+
<jmh.version>1.21</jmh.version>
7577
</properties>
7678

7779

@@ -272,7 +274,16 @@
272274
<artifactId>bctls-jdk15on</artifactId>
273275
<version>${bc.version}</version>
274276
</dependency>
275-
277+
<dependency>
278+
<groupId>org.openjdk.jmh</groupId>
279+
<artifactId>jmh-core</artifactId>
280+
<version>${jmh.version}</version>
281+
</dependency>
282+
<dependency>
283+
<groupId>org.openjdk.jmh</groupId>
284+
<artifactId>jmh-generator-annprocess</artifactId>
285+
<version>${jmh.version}</version>
286+
</dependency>
276287
</dependencies>
277288
</dependencyManagement>
278289

0 commit comments

Comments
 (0)