Skip to content

Commit 36ca8df

Browse files
committed
Add isolated protocol ser/de benchmarks for V1 vs V2
Benchmarks for all 6 AWS protocol types measuring serialization and deserialization in isolation (no HTTP, signing, or retries): - JSON (DynamoDB PutItem) - REST-JSON (Lambda CreateFunction) - REST-XML (CloudFront CreateDistribution) - Query (STS AssumeRole) - EC2 (EC2 DescribeInstances) - CBOR (CloudWatch GetMetricData) Each protocol has a V1 and V2 benchmark class with @benchmark methods for both ser and deser, using the same JMH configuration and fixture data for fair comparison.
1 parent 1ac242b commit 36ca8df

19 files changed

+1969
-1
lines changed

build-tools/src/main/resources/software/amazon/awssdk/checkstyle-suppressions.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
<!-- Allow non-java.base usage in tests -->
5151
<suppress checks="software.amazon.awssdk.buildtools.checkstyle.NonJavaBaseModuleCheck" files=".*testutils.*"/>
5252

53+
<!-- Allow javax.xml.stream in benchmark protocol files (needed for V1 StAX unmarshalling) -->
54+
<suppress checks="software.amazon.awssdk.buildtools.checkstyle.NonJavaBaseModuleCheck"
55+
files=".*benchmark[\\/]protocol[\\/].*\.java$"/>
56+
5357
<!-- Allow private field declaration before public, to have correct initialization order -->
5458
<suppress checks="DeclarationOrder"
5559
files=".*SdkAdvancedClientOption\.java$"/>

test/sdk-benchmarks/pom.xml

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
-->
4848
<uberjar.name>benchmarks</uberjar.name>
4949

50-
<sdk-v1.version>1.11.404</sdk-v1.version>
50+
<sdk-v1.version>1.12.797</sdk-v1.version>
5151
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
5252
</properties>
5353

@@ -87,18 +87,58 @@
8787
<artifactId>aws-java-sdk-ec2</artifactId>
8888
<version>${sdk-v1.version}</version>
8989
</dependency>
90+
<dependency>
91+
<groupId>com.amazonaws</groupId>
92+
<artifactId>aws-java-sdk-cloudfront</artifactId>
93+
<version>${sdk-v1.version}</version>
94+
</dependency>
95+
<dependency>
96+
<groupId>com.amazonaws</groupId>
97+
<artifactId>aws-java-sdk-sts</artifactId>
98+
<version>${sdk-v1.version}</version>
99+
</dependency>
100+
<dependency>
101+
<groupId>com.amazonaws</groupId>
102+
<artifactId>aws-java-sdk-lambda</artifactId>
103+
<version>${sdk-v1.version}</version>
104+
</dependency>
105+
<dependency>
106+
<groupId>com.amazonaws</groupId>
107+
<artifactId>aws-java-sdk-cloudwatch</artifactId>
108+
<version>${sdk-v1.version}</version>
109+
</dependency>
90110

91111
<dependency>
92112
<groupId>software.amazon.awssdk</groupId>
93113
<artifactId>ec2</artifactId>
94114
<version>${awsjavasdk.version}</version>
95115
</dependency>
116+
<dependency>
117+
<groupId>software.amazon.awssdk</groupId>
118+
<artifactId>cloudfront</artifactId>
119+
<version>${awsjavasdk.version}</version>
120+
</dependency>
121+
<dependency>
122+
<groupId>software.amazon.awssdk</groupId>
123+
<artifactId>sts</artifactId>
124+
<version>${awsjavasdk.version}</version>
125+
</dependency>
126+
<dependency>
127+
<groupId>software.amazon.awssdk</groupId>
128+
<artifactId>lambda</artifactId>
129+
<version>${awsjavasdk.version}</version>
130+
</dependency>
96131

97132
<dependency>
98133
<groupId>software.amazon.awssdk</groupId>
99134
<artifactId>aws-query-protocol</artifactId>
100135
<version>${awsjavasdk.version}</version>
101136
</dependency>
137+
<dependency>
138+
<groupId>software.amazon.awssdk</groupId>
139+
<artifactId>smithy-rpcv2-protocol</artifactId>
140+
<version>${awsjavasdk.version}</version>
141+
</dependency>
102142

103143
<dependency>
104144
<groupId>software.amazon.awssdk</groupId>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.protocol;
17+
18+
import com.amazonaws.protocol.rpcv2cbor.RpcV2CborClientMetadata;
19+
import com.amazonaws.protocol.rpcv2cbor.SdkRpcV2CborProtocolFactory;
20+
import com.amazonaws.protocol.rpcv2cbor.SdkStructuredCborFactory;
21+
import com.amazonaws.protocol.rpcv2cbor.StructuredRpcV2CborGenerator;
22+
import com.amazonaws.services.cloudwatch.model.GetMetricDataRequest;
23+
import com.amazonaws.services.cloudwatch.model.Metric;
24+
import com.amazonaws.services.cloudwatch.model.MetricDataQuery;
25+
import com.amazonaws.services.cloudwatch.model.MetricStat;
26+
import com.amazonaws.services.cloudwatch.model.transform.GetMetricDataRequestProtocolMarshaller;
27+
import com.amazonaws.services.cloudwatch.model.transform.GetMetricDataResultRpcV2CborUnmarshaller;
28+
import com.amazonaws.transform.rpcv2cbor.RpcV2CborUnmarshallerContextImpl;
29+
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
30+
import com.fasterxml.jackson.dataformat.cbor.CBORParser;
31+
import java.util.Date;
32+
import java.util.concurrent.TimeUnit;
33+
import org.openjdk.jmh.annotations.Benchmark;
34+
import org.openjdk.jmh.annotations.BenchmarkMode;
35+
import org.openjdk.jmh.annotations.Fork;
36+
import org.openjdk.jmh.annotations.Measurement;
37+
import org.openjdk.jmh.annotations.Mode;
38+
import org.openjdk.jmh.annotations.OutputTimeUnit;
39+
import org.openjdk.jmh.annotations.Scope;
40+
import org.openjdk.jmh.annotations.Setup;
41+
import org.openjdk.jmh.annotations.State;
42+
import org.openjdk.jmh.annotations.Warmup;
43+
import org.openjdk.jmh.infra.Blackhole;
44+
45+
/**
46+
* Isolated ser/de benchmark for V1 CloudWatch (smithy-rpc-v2-cbor protocol).
47+
* Measures only CBOR parsing + object construction -- no HTTP, signing, or retries.
48+
*/
49+
@State(Scope.Benchmark)
50+
@BenchmarkMode(Mode.SampleTime)
51+
@OutputTimeUnit(TimeUnit.MICROSECONDS)
52+
@Warmup(iterations = 5)
53+
@Measurement(iterations = 5)
54+
@Fork(2)
55+
public class V1CborProtocolBenchmark {
56+
57+
private static final CBORFactory CBOR_FACTORY = new CBORFactory();
58+
59+
private SdkRpcV2CborProtocolFactory protocolFactory;
60+
private byte[] responseBytes;
61+
private GetMetricDataRequest request;
62+
63+
@Setup
64+
public void setup() throws Exception {
65+
protocolFactory = new SdkRpcV2CborProtocolFactory(new RpcV2CborClientMetadata());
66+
responseBytes = createCborResponseFixture();
67+
request = createRequest();
68+
}
69+
70+
@Benchmark
71+
public void getMetricDataDeser(Blackhole bh) throws Exception {
72+
CBORParser parser = CBOR_FACTORY.createParser(responseBytes);
73+
RpcV2CborUnmarshallerContextImpl ctx = new RpcV2CborUnmarshallerContextImpl(
74+
parser, SdkStructuredCborFactory.CBOR_SCALAR_UNMARSHALLERS, null);
75+
ctx.nextToken();
76+
bh.consume(GetMetricDataResultRpcV2CborUnmarshaller.getInstance().unmarshall(ctx));
77+
}
78+
79+
@Benchmark
80+
public void getMetricDataSer(Blackhole bh) {
81+
bh.consume(new GetMetricDataRequestProtocolMarshaller(protocolFactory).marshall(request));
82+
}
83+
84+
private static GetMetricDataRequest createRequest() {
85+
Date end = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z"));
86+
Date start = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z").minusSeconds(3600));
87+
return new GetMetricDataRequest()
88+
.withStartTime(start)
89+
.withEndTime(end)
90+
.withMaxDatapoints(1000)
91+
.withMetricDataQueries(
92+
new MetricDataQuery()
93+
.withId("cpu")
94+
.withMetricStat(new MetricStat()
95+
.withMetric(new Metric()
96+
.withNamespace("AWS/EC2")
97+
.withMetricName("CPUUtilization"))
98+
.withPeriod(300)
99+
.withStat("Average"))
100+
.withReturnData(true));
101+
}
102+
103+
private static byte[] createCborResponseFixture() {
104+
StructuredRpcV2CborGenerator gen =
105+
SdkStructuredCborFactory.SDK_CBOR_FACTORY.createWriter("application/cbor");
106+
gen.writeStartObject();
107+
gen.writeFieldName("MetricDataResults");
108+
gen.writeStartArray();
109+
gen.writeStartObject();
110+
gen.writeFieldName("Id");
111+
gen.writeValue("cpu");
112+
gen.writeFieldName("Label");
113+
gen.writeValue("CPUUtilization");
114+
gen.writeFieldName("StatusCode");
115+
gen.writeValue("Complete");
116+
gen.writeFieldName("Timestamps");
117+
gen.writeStartArray();
118+
long base = 1772611200L;
119+
for (int i = 0; i < 12; i++) {
120+
gen.writeValue((double) ((base + i * 300) * 1000));
121+
}
122+
gen.writeEndArray();
123+
gen.writeFieldName("Values");
124+
gen.writeStartArray();
125+
for (int i = 0; i < 12; i++) {
126+
gen.writeValue(45.2 + i * 1.1);
127+
}
128+
gen.writeEndArray();
129+
gen.writeFieldName("Messages");
130+
gen.writeStartArray();
131+
gen.writeEndArray();
132+
gen.writeEndObject();
133+
gen.writeEndArray();
134+
gen.writeFieldName("Messages");
135+
gen.writeStartArray();
136+
gen.writeEndArray();
137+
gen.writeEndObject();
138+
return gen.getBytes();
139+
}
140+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.protocol;
17+
18+
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
19+
import com.amazonaws.services.ec2.model.Filter;
20+
import com.amazonaws.services.ec2.model.transform.DescribeInstancesRequestMarshaller;
21+
import com.amazonaws.services.ec2.model.transform.DescribeInstancesResultStaxUnmarshaller;
22+
import com.amazonaws.transform.StaxUnmarshallerContext;
23+
import java.io.ByteArrayInputStream;
24+
import java.io.IOException;
25+
import java.util.HashMap;
26+
import java.util.Map;
27+
import java.util.concurrent.TimeUnit;
28+
import javax.xml.stream.XMLEventReader;
29+
import javax.xml.stream.XMLInputFactory;
30+
import org.openjdk.jmh.annotations.Benchmark;
31+
import org.openjdk.jmh.annotations.BenchmarkMode;
32+
import org.openjdk.jmh.annotations.Fork;
33+
import org.openjdk.jmh.annotations.Measurement;
34+
import org.openjdk.jmh.annotations.Mode;
35+
import org.openjdk.jmh.annotations.OutputTimeUnit;
36+
import org.openjdk.jmh.annotations.Scope;
37+
import org.openjdk.jmh.annotations.Setup;
38+
import org.openjdk.jmh.annotations.State;
39+
import org.openjdk.jmh.annotations.Warmup;
40+
import org.openjdk.jmh.infra.Blackhole;
41+
42+
/**
43+
* Isolated ser/de benchmark for V1 EC2 (EC2 Query protocol).
44+
* Measures only XML parsing + form encoding -- no HTTP, signing, or retries.
45+
*/
46+
@State(Scope.Benchmark)
47+
@BenchmarkMode(Mode.SampleTime)
48+
@OutputTimeUnit(TimeUnit.MICROSECONDS)
49+
@Warmup(iterations = 5)
50+
@Measurement(iterations = 5)
51+
@Fork(2)
52+
public class V1Ec2ProtocolBenchmark {
53+
54+
private static final XMLInputFactory XML_INPUT_FACTORY =
55+
XMLInputFactory.newInstance();
56+
57+
private byte[] responseBytes;
58+
private Map<String, String> responseHeaders;
59+
private DescribeInstancesRequestMarshaller marshaller;
60+
private DescribeInstancesRequest request;
61+
62+
@Setup
63+
public void setup() throws Exception {
64+
responseBytes = loadFixture("fixtures/ec2-protocol/describe-instances-response.xml");
65+
responseHeaders = new HashMap<>();
66+
marshaller = new DescribeInstancesRequestMarshaller();
67+
request = createRequest();
68+
}
69+
70+
@Benchmark
71+
public void describeInstancesDeser(Blackhole bh) throws Exception {
72+
XMLEventReader reader = XML_INPUT_FACTORY.createXMLEventReader(new ByteArrayInputStream(responseBytes));
73+
StaxUnmarshallerContext ctx = new StaxUnmarshallerContext(reader, responseHeaders);
74+
ctx.registerMetadataExpression("ResponseMetadata/RequestId", 2, "AWS_REQUEST_ID");
75+
76+
bh.consume(DescribeInstancesResultStaxUnmarshaller.getInstance().unmarshall(ctx));
77+
}
78+
79+
@Benchmark
80+
public void describeInstancesSer(Blackhole bh) {
81+
bh.consume(marshaller.marshall(request));
82+
}
83+
84+
private static DescribeInstancesRequest createRequest() {
85+
return new DescribeInstancesRequest()
86+
.withInstanceIds("i-0abcdef1234567890")
87+
.withFilters(
88+
new Filter("instance-state-name").withValues("running"),
89+
new Filter("instance-type").withValues("m5.xlarge"))
90+
.withMaxResults(100);
91+
}
92+
93+
private static byte[] loadFixture(String path) throws IOException {
94+
return com.amazonaws.util.IOUtils.toByteArray(
95+
V1Ec2ProtocolBenchmark.class.getClassLoader()
96+
.getResourceAsStream(path));
97+
}
98+
}

0 commit comments

Comments
 (0)