diff --git a/build-tools/src/main/resources/software/amazon/awssdk/checkstyle-suppressions.xml b/build-tools/src/main/resources/software/amazon/awssdk/checkstyle-suppressions.xml index 17c617c0d12b..2a6e22ef28ba 100644 --- a/build-tools/src/main/resources/software/amazon/awssdk/checkstyle-suppressions.xml +++ b/build-tools/src/main/resources/software/amazon/awssdk/checkstyle-suppressions.xml @@ -50,6 +50,10 @@ + + + diff --git a/test/sdk-benchmarks/pom.xml b/test/sdk-benchmarks/pom.xml index 4f0a47cfc17a..983d5badbfd9 100644 --- a/test/sdk-benchmarks/pom.xml +++ b/test/sdk-benchmarks/pom.xml @@ -47,7 +47,7 @@ --> benchmarks - 1.11.404 + 1.12.797 1.6.0 @@ -87,18 +87,58 @@ aws-java-sdk-ec2 ${sdk-v1.version} + + com.amazonaws + aws-java-sdk-cloudfront + ${sdk-v1.version} + + + com.amazonaws + aws-java-sdk-sts + ${sdk-v1.version} + + + com.amazonaws + aws-java-sdk-lambda + ${sdk-v1.version} + + + com.amazonaws + aws-java-sdk-cloudwatch + ${sdk-v1.version} + software.amazon.awssdk ec2 ${awsjavasdk.version} + + software.amazon.awssdk + cloudfront + ${awsjavasdk.version} + + + software.amazon.awssdk + sts + ${awsjavasdk.version} + + + software.amazon.awssdk + lambda + ${awsjavasdk.version} + software.amazon.awssdk aws-query-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServer.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServer.java new file mode 100644 index 000000000000..96911c4e9442 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServer.java @@ -0,0 +1,70 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import software.amazon.awssdk.benchmark.utils.BenchmarkUtils; +import software.amazon.awssdk.utils.IoUtils; + +/** + * Lightweight Jetty server for protocol roundtrip benchmarks. + */ +class ProtocolRoundtripServer { + + private final Server server; + private final int port; + + ProtocolRoundtripServer(ProtocolRoundtripServlet servlet) throws IOException { + port = BenchmarkUtils.getUnusedPort(); + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(port); + server.setConnectors(new Connector[] {connector}); + + ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); + context.addServlet(new ServletHolder(servlet), "/*"); + server.setHandler(context); + } + + void start() throws Exception { + server.start(); + } + + void stop() throws Exception { + server.stop(); + } + + URI getHttpUri() { + return URI.create("http://localhost:" + port); + } + + static byte[] loadFixture(String path) throws IOException { + try (InputStream is = ProtocolRoundtripServer.class.getClassLoader() + .getResourceAsStream("fixtures/" + path)) { + if (is == null) { + throw new IOException("Fixture not found: fixtures/" + path); + } + return IoUtils.toByteArray(is); + } + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServlet.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServlet.java new file mode 100644 index 000000000000..abcce14534ad --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/ProtocolRoundtripServlet.java @@ -0,0 +1,39 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.io.IOException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +class ProtocolRoundtripServlet extends HttpServlet { + private final byte[] body; + private final String contentType; + + ProtocolRoundtripServlet(byte[] body, String contentType) { + this.body = body; + this.contentType = contentType; + } + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(200); + resp.setContentLength(body.length); + resp.setContentType(contentType); + resp.getOutputStream().write(body); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1CborRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1CborRoundtripBenchmark.java new file mode 100644 index 000000000000..eb7dfccee20c --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1CborRoundtripBenchmark.java @@ -0,0 +1,140 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.protocol.rpcv2cbor.SdkStructuredCborFactory; +import com.amazonaws.protocol.rpcv2cbor.StructuredRpcV2CborGenerator; +import com.amazonaws.services.cloudwatch.AmazonCloudWatch; +import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder; +import com.amazonaws.services.cloudwatch.model.GetMetricDataRequest; +import com.amazonaws.services.cloudwatch.model.Metric; +import com.amazonaws.services.cloudwatch.model.MetricDataQuery; +import com.amazonaws.services.cloudwatch.model.MetricStat; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for SmithyRpcV2 CBOR protocol using CloudWatch GetMetricData via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1CborRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AmazonCloudWatch client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = createCborResponseFixture(); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/cbor"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AmazonCloudWatchClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void getMetricData(Blackhole bh) { + Date end = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z")); + Date start = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z").minusSeconds(3600)); + GetMetricDataRequest request = new GetMetricDataRequest() + .withStartTime(start) + .withEndTime(end) + .withMaxDatapoints(1000) + .withMetricDataQueries( + new MetricDataQuery() + .withId("cpu") + .withMetricStat(new MetricStat() + .withMetric(new Metric() + .withNamespace("AWS/EC2") + .withMetricName("CPUUtilization")) + .withPeriod(300) + .withStat("Average")) + .withReturnData(true)); + + bh.consume(client.getMetricData(request)); + } + + private static byte[] createCborResponseFixture() { + StructuredRpcV2CborGenerator gen = + SdkStructuredCborFactory.SDK_CBOR_FACTORY.createWriter("application/cbor"); + gen.writeStartObject(); + gen.writeFieldName("MetricDataResults"); + gen.writeStartArray(); + gen.writeStartObject(); + gen.writeFieldName("Id"); + gen.writeValue("cpu"); + gen.writeFieldName("Label"); + gen.writeValue("CPUUtilization"); + gen.writeFieldName("StatusCode"); + gen.writeValue("Complete"); + gen.writeFieldName("Timestamps"); + gen.writeStartArray(); + long base = 1772611200L; + for (int i = 0; i < 12; i++) { + gen.writeValue((double) ((base + i * 300) * 1000)); + } + gen.writeEndArray(); + gen.writeFieldName("Values"); + gen.writeStartArray(); + for (int i = 0; i < 12; i++) { + gen.writeValue(45.2 + i * 1.1); + } + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + return gen.getBytes(); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1Ec2RoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1Ec2RoundtripBenchmark.java new file mode 100644 index 000000000000..6ae6df995a99 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1Ec2RoundtripBenchmark.java @@ -0,0 +1,87 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.ec2.AmazonEC2; +import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; +import com.amazonaws.services.ec2.model.DescribeInstancesRequest; +import com.amazonaws.services.ec2.model.Filter; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for EC2 protocol using EC2 DescribeInstances via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1Ec2RoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AmazonEC2 client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("ec2-protocol/describe-instances-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AmazonEC2ClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void describeInstances(Blackhole bh) { + DescribeInstancesRequest request = new DescribeInstancesRequest() + .withInstanceIds("i-0abcdef1234567890") + .withFilters( + new Filter("instance-state-name").withValues("running"), + new Filter("instance-type").withValues("m5.xlarge")) + .withMaxResults(100); + + bh.consume(client.describeInstances(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1JsonRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1JsonRoundtripBenchmark.java new file mode 100644 index 000000000000..58146050360c --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1JsonRoundtripBenchmark.java @@ -0,0 +1,112 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.model.AttributeValue; +import com.amazonaws.services.dynamodbv2.model.PutItemRequest; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for JSON protocol (aws-json) using DynamoDB PutItem via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1JsonRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AmazonDynamoDB client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("json-protocol/putitem-response.json"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/x-amz-json-1.0"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AmazonDynamoDBClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void putItem(Blackhole bh) { + PutItemRequest putItemRequest = new PutItemRequest() + .withTableName("benchmark-table") + .withItem(itemMap()); + + bh.consume(client.putItem(putItemRequest)); + } + + private static Map itemMap() { + Map item = new HashMap<>(); + item.put("pk", new AttributeValue().withS("benchmark-key")); + item.put("sk", new AttributeValue().withN("100")); + item.put("stringField", new AttributeValue().withS("test-value")); + item.put("numberField", new AttributeValue().withN("123.456")); + item.put("binaryField", new AttributeValue().withB(ByteBuffer.wrap("hello world".getBytes()))); + item.put("stringSetField", new AttributeValue().withSS("value1", "value2", "value3")); + item.put("numberSetField", new AttributeValue().withNS("1.1", "2.2", "3.3")); + item.put("boolField", new AttributeValue().withBOOL(false)); + item.put("nullField", new AttributeValue().withNULL(true)); + Map deep = new HashMap<>(); + deep.put("level2", new AttributeValue().withN("999")); + Map nested = new HashMap<>(); + nested.put("nested", new AttributeValue().withS("nested-value")); + nested.put("deepNested", new AttributeValue().withM(deep)); + item.put("mapField", new AttributeValue().withM(nested)); + item.put("listField", new AttributeValue().withL( + new AttributeValue().withS("item1"), + new AttributeValue().withN("42"), + new AttributeValue().withBOOL(true), + new AttributeValue().withNULL(true))); + return item; + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1QueryRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1QueryRoundtripBenchmark.java new file mode 100644 index 000000000000..3da508d4ff5c --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1QueryRoundtripBenchmark.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; +import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for Query protocol using STS AssumeRole via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1QueryRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AWSSecurityTokenService client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("query-protocol/assumerole-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AWSSecurityTokenServiceClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void assumeRole(Blackhole bh) { + AssumeRoleRequest request = new AssumeRoleRequest() + .withRoleArn("arn:aws:iam::123456789012:role/benchmark-role") + .withRoleSessionName("benchmark-session") + .withDurationSeconds(3600) + .withExternalId("benchmark-external-id") + .withPolicy("{\"Version\":\"2012-10-17\"}"); + + bh.consume(client.assumeRole(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestJsonRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestJsonRoundtripBenchmark.java new file mode 100644 index 000000000000..5bc6d9ca080f --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestJsonRoundtripBenchmark.java @@ -0,0 +1,104 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.lambda.AWSLambda; +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.model.CreateFunctionRequest; +import com.amazonaws.services.lambda.model.Environment; +import com.amazonaws.services.lambda.model.FunctionCode; +import com.amazonaws.services.lambda.model.Runtime; +import com.amazonaws.services.lambda.model.TracingConfig; +import com.amazonaws.services.lambda.model.TracingMode; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for REST-JSON protocol using Lambda CreateFunction via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1RestJsonRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AWSLambda client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("rest-json-protocol/createfunction-response.json"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/json"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AWSLambdaClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void createFunction(Blackhole bh) { + Map envVars = new HashMap<>(); + envVars.put("ENV_VAR_1", "value1"); + + CreateFunctionRequest request = new CreateFunctionRequest() + .withFunctionName("benchmark-function") + .withRuntime(Runtime.Java8) + .withRole("arn:aws:iam::123456789012:role/lambda-role") + .withHandler("com.example.Handler::handleRequest") + .withCode(new FunctionCode() + .withS3Bucket("my-deploy-bucket") + .withS3Key("code/function.zip")) + .withDescription("Benchmark test function") + .withTimeout(30) + .withMemorySize(512) + .withPublish(false) + .withEnvironment(new Environment().withVariables(envVars)) + .withTracingConfig(new TracingConfig().withMode(TracingMode.Active)); + + bh.consume(client.createFunction(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestXmlRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestXmlRoundtripBenchmark.java new file mode 100644 index 000000000000..ff42e19ada68 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V1RestXmlRoundtripBenchmark.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.cloudfront.AmazonCloudFront; +import com.amazonaws.services.cloudfront.AmazonCloudFrontClientBuilder; +import com.amazonaws.services.cloudfront.model.Aliases; +import com.amazonaws.services.cloudfront.model.AllowedMethods; +import com.amazonaws.services.cloudfront.model.CachedMethods; +import com.amazonaws.services.cloudfront.model.CreateDistributionRequest; +import com.amazonaws.services.cloudfront.model.DefaultCacheBehavior; +import com.amazonaws.services.cloudfront.model.DistributionConfig; +import com.amazonaws.services.cloudfront.model.Method; +import com.amazonaws.services.cloudfront.model.Origin; +import com.amazonaws.services.cloudfront.model.Origins; +import com.amazonaws.services.cloudfront.model.S3OriginConfig; +import com.amazonaws.services.cloudfront.model.ViewerProtocolPolicy; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * V1 roundtrip benchmark for REST-XML protocol using CloudFront CreateDistribution via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V1RestXmlRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private AmazonCloudFront client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("rest-xml-protocol/create-distribution-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = AmazonCloudFrontClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration( + server.getHttpUri().toString(), "us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("test", "test"))) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.shutdown(); + server.stop(); + } + + @Benchmark + public void createDistribution(Blackhole bh) { + CreateDistributionRequest request = new CreateDistributionRequest() + .withDistributionConfig(new DistributionConfig() + .withCallerReference("benchmark-ref-2024") + .withAliases(new Aliases() + .withQuantity(2) + .withItems("www.example.com", "cdn.example.com")) + .withDefaultRootObject("index.html") + .withOrigins(new Origins() + .withQuantity(1) + .withItems(new Origin() + .withId("myS3Origin") + .withDomainName("mybucket.s3.amazonaws.com") + .withOriginPath("/production") + .withS3OriginConfig(new S3OriginConfig() + .withOriginAccessIdentity("origin-access-identity/cloudfront/E127EXAMPLE51Z")))) + .withDefaultCacheBehavior(new DefaultCacheBehavior() + .withTargetOriginId("myS3Origin") + .withViewerProtocolPolicy(ViewerProtocolPolicy.RedirectToHttps) + .withAllowedMethods(new AllowedMethods() + .withQuantity(3) + .withItems(Method.GET, Method.HEAD, Method.OPTIONS) + .withCachedMethods(new CachedMethods() + .withQuantity(2) + .withItems(Method.GET, Method.HEAD))) + .withCompress(true))); + + bh.consume(client.createDistribution(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2CborRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2CborRoundtripBenchmark.java new file mode 100644 index 000000000000..f2f3e60a740b --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2CborRoundtripBenchmark.java @@ -0,0 +1,145 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkStructuredRpcV2CborFactory; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; +import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataRequest; +import software.amazon.awssdk.services.cloudwatch.model.Metric; +import software.amazon.awssdk.services.cloudwatch.model.MetricDataQuery; +import software.amazon.awssdk.services.cloudwatch.model.MetricStat; + +/** + * Roundtrip benchmark for SmithyRpcV2 CBOR protocol using CloudWatch GetMetricData via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2CborRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private CloudWatchClient client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = createCborResponseFixture(); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/cbor"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = CloudWatchClient.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void getMetricData(Blackhole bh) { + Instant end = Instant.parse("2026-03-09T00:00:00Z"); + Instant start = end.minusSeconds(3600); + GetMetricDataRequest request = GetMetricDataRequest.builder() + .startTime(start) + .endTime(end) + .maxDatapoints(1000) + .metricDataQueries( + MetricDataQuery.builder() + .id("cpu") + .metricStat(MetricStat.builder() + .metric(Metric.builder() + .namespace("AWS/EC2") + .metricName("CPUUtilization") + .build()) + .period(300) + .stat("Average") + .build()) + .returnData(true) + .build()) + .build(); + + bh.consume(client.getMetricData(request)); + } + + private static byte[] createCborResponseFixture() { + StructuredJsonGenerator gen = + SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY.createWriter("application/cbor"); + gen.writeStartObject(); + gen.writeFieldName("MetricDataResults"); + gen.writeStartArray(); + gen.writeStartObject(); + gen.writeFieldName("Id"); + gen.writeValue("cpu"); + gen.writeFieldName("Label"); + gen.writeValue("CPUUtilization"); + gen.writeFieldName("StatusCode"); + gen.writeValue("Complete"); + gen.writeFieldName("Timestamps"); + gen.writeStartArray(); + long base = 1772611200L; + for (int i = 0; i < 12; i++) { + gen.writeValue((double) ((base + i * 300) * 1000)); + } + gen.writeEndArray(); + gen.writeFieldName("Values"); + gen.writeStartArray(); + for (int i = 0; i < 12; i++) { + gen.writeValue(45.2 + i * 1.1); + } + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + return gen.getBytes(); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2Ec2RoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2Ec2RoundtripBenchmark.java new file mode 100644 index 000000000000..3dfdd9cd74d2 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2Ec2RoundtripBenchmark.java @@ -0,0 +1,89 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; +import software.amazon.awssdk.services.ec2.model.Filter; + +/** + * Roundtrip benchmark for EC2 protocol using EC2 DescribeInstances via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2Ec2RoundtripBenchmark { + + private ProtocolRoundtripServer server; + private Ec2Client client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("ec2-protocol/describe-instances-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = Ec2Client.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void describeInstances(Blackhole bh) { + DescribeInstancesRequest request = DescribeInstancesRequest.builder() + .instanceIds("i-0abcdef1234567890") + .filters( + Filter.builder().name("instance-state-name").values("running").build(), + Filter.builder().name("instance-type").values("m5.xlarge").build()) + .maxResults(100) + .build(); + + bh.consume(client.describeInstances(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2JsonRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2JsonRoundtripBenchmark.java new file mode 100644 index 000000000000..6d23fc581f6e --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2JsonRoundtripBenchmark.java @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; + +/** + * Roundtrip benchmark for JSON protocol (aws-json) using DynamoDB PutItem via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2JsonRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private DynamoDbClient client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("json-protocol/putitem-response.json"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/x-amz-json-1.0"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = DynamoDbClient.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void putItem(Blackhole bh) { + + PutItemRequest putItemRequest = PutItemRequest.builder() + .tableName("benchmark-table") + .item(itemMap()) + .build(); + bh.consume(client.putItem(putItemRequest)); + } + + private static Map itemMap() { + Map item = new HashMap<>(); + item.put("pk", AttributeValue.fromS("benchmark-key")); + item.put("sk", AttributeValue.fromN("100")); + item.put("stringField", AttributeValue.fromS("test-value")); + item.put("numberField", AttributeValue.fromN("123.456")); + item.put("binaryField", AttributeValue.fromB(SdkBytes.fromUtf8String("hello world"))); + item.put("stringSetField", AttributeValue.builder().ss("value1", "value2", "value3").build()); + item.put("numberSetField", AttributeValue.builder().ns("1.1", "2.2", "3.3").build()); + item.put("boolField", AttributeValue.fromBool(false)); + item.put("nullField", AttributeValue.builder().nul(true).build()); + Map deep = new HashMap<>(); + deep.put("level2", AttributeValue.fromN("999")); + Map nested = new HashMap<>(); + nested.put("nested", AttributeValue.fromS("nested-value")); + nested.put("deepNested", AttributeValue.fromM(deep)); + item.put("mapField", AttributeValue.fromM(nested)); + item.put("listField", AttributeValue.builder().l( + AttributeValue.fromS("item1"), + AttributeValue.fromN("42"), + AttributeValue.fromBool(true), + AttributeValue.builder().nul(true).build()).build()); + return item; + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2QueryRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2QueryRoundtripBenchmark.java new file mode 100644 index 000000000000..aff4d9c23cd2 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2QueryRoundtripBenchmark.java @@ -0,0 +1,88 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sts.StsClient; +import software.amazon.awssdk.services.sts.model.AssumeRoleRequest; + +/** + * Roundtrip benchmark for Query protocol using STS AssumeRole via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2QueryRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private StsClient client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("query-protocol/assumerole-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = StsClient.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void assumeRole(Blackhole bh) { + AssumeRoleRequest request = AssumeRoleRequest.builder() + .roleArn("arn:aws:iam::123456789012:role/benchmark-role") + .roleSessionName("benchmark-session") + .durationSeconds(3600) + .externalId("benchmark-external-id") + .policy("{\"Version\":\"2012-10-17\"}") + .build(); + + bh.consume(client.assumeRole(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestJsonRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestJsonRoundtripBenchmark.java new file mode 100644 index 000000000000..563ad7fd1dd3 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestJsonRoundtripBenchmark.java @@ -0,0 +1,107 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.lambda.LambdaClient; +import software.amazon.awssdk.services.lambda.model.CreateFunctionRequest; +import software.amazon.awssdk.services.lambda.model.Environment; +import software.amazon.awssdk.services.lambda.model.FunctionCode; +import software.amazon.awssdk.services.lambda.model.Runtime; +import software.amazon.awssdk.services.lambda.model.TracingConfig; +import software.amazon.awssdk.services.lambda.model.TracingMode; + +/** + * Roundtrip benchmark for REST-JSON protocol using Lambda CreateFunction via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2RestJsonRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private LambdaClient client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("rest-json-protocol/createfunction-response.json"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "application/json"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = LambdaClient.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void createFunction(Blackhole bh) { + Map envVars = new HashMap<>(); + envVars.put("ENV_VAR_1", "value1"); + + CreateFunctionRequest request = CreateFunctionRequest.builder() + .functionName("benchmark-function") + .runtime(Runtime.JAVA8) + .role("arn:aws:iam::123456789012:role/lambda-role") + .handler("com.example.Handler::handleRequest") + .code(FunctionCode.builder() + .s3Bucket("my-deploy-bucket") + .s3Key("code/function.zip") + .build()) + .description("Benchmark test function") + .timeout(30) + .memorySize(512) + .publish(false) + .environment(Environment.builder().variables(envVars).build()) + .tracingConfig(TracingConfig.builder().mode(TracingMode.ACTIVE).build()) + .build(); + + bh.consume(client.createFunction(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestXmlRoundtripBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestXmlRoundtripBenchmark.java new file mode 100644 index 000000000000..04cdea1b56ef --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/V2RestXmlRoundtripBenchmark.java @@ -0,0 +1,143 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.apicall.protocol; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.http.apache5.Apache5HttpClient; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cloudfront.CloudFrontClient; +import software.amazon.awssdk.services.cloudfront.model.Aliases; +import software.amazon.awssdk.services.cloudfront.model.AllowedMethods; +import software.amazon.awssdk.services.cloudfront.model.CachedMethods; +import software.amazon.awssdk.services.cloudfront.model.CreateDistributionRequest; +import software.amazon.awssdk.services.cloudfront.model.DefaultCacheBehavior; +import software.amazon.awssdk.services.cloudfront.model.DistributionConfig; +import software.amazon.awssdk.services.cloudfront.model.Method; +import software.amazon.awssdk.services.cloudfront.model.Origin; +import software.amazon.awssdk.services.cloudfront.model.Origins; +import software.amazon.awssdk.services.cloudfront.model.S3OriginConfig; +import software.amazon.awssdk.services.cloudfront.model.ViewerProtocolPolicy; + +/** + * Roundtrip benchmark for REST-XML protocol using CloudFront CreateDistribution via HTTP servlet. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class V2RestXmlRoundtripBenchmark { + + private ProtocolRoundtripServer server; + private CloudFrontClient client; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] response = ProtocolRoundtripServer.loadFixture("rest-xml-protocol/create-distribution-response.xml"); + + ProtocolRoundtripServlet servlet = new ProtocolRoundtripServlet(response, "text/xml"); + + server = new ProtocolRoundtripServer(servlet); + server.start(); + + client = CloudFrontClient.builder() + .endpointOverride(server.getHttpUri()) + .region(Region.US_EAST_1) + .credentialsProvider( + StaticCredentialsProvider.create( + AwsBasicCredentials.create("test", "test"))) + .httpClient(Apache5HttpClient.create()) + .build(); + } + + @TearDown(Level.Trial) + public void tearDown() throws Exception { + client.close(); + server.stop(); + } + + @Benchmark + public void createDistribution(Blackhole bh) { + S3OriginConfig s3Config = S3OriginConfig.builder() + .originAccessIdentity( + "origin-access-identity/cloudfront/E127EXAMPLE51Z") + .build(); + + Origin origin = Origin.builder() + .id("myS3Origin") + .domainName("mybucket.s3.amazonaws.com") + .originPath("/production") + .s3OriginConfig(s3Config) + .build(); + + CachedMethods cached = CachedMethods.builder() + .quantity(2) + .items(Method.GET, Method.HEAD) + .build(); + + AllowedMethods allowed = AllowedMethods.builder() + .quantity(3) + .items(Method.GET, Method.HEAD, Method.OPTIONS) + .cachedMethods(cached) + .build(); + + DefaultCacheBehavior cacheBehavior = + DefaultCacheBehavior.builder() + .targetOriginId("myS3Origin") + .viewerProtocolPolicy( + ViewerProtocolPolicy.REDIRECT_TO_HTTPS) + .allowedMethods(allowed) + .compress(true) + .build(); + + DistributionConfig config = DistributionConfig.builder() + .callerReference("benchmark-ref-2024") + .aliases(Aliases.builder() + .quantity(2) + .items("www.example.com", "cdn.example.com") + .build()) + .defaultRootObject("index.html") + .origins(Origins.builder() + .quantity(1) + .items(origin) + .build()) + .defaultCacheBehavior(cacheBehavior) + .build(); + + CreateDistributionRequest request = + CreateDistributionRequest.builder() + .distributionConfig(config) + .build(); + + bh.consume(client.createDistribution(request)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1CborProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1CborProtocolBenchmark.java new file mode 100644 index 000000000000..2214d797edbf --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1CborProtocolBenchmark.java @@ -0,0 +1,136 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.protocol.rpcv2cbor.RpcV2CborClientMetadata; +import com.amazonaws.protocol.rpcv2cbor.SdkRpcV2CborProtocolFactory; +import com.amazonaws.protocol.rpcv2cbor.SdkStructuredCborFactory; +import com.amazonaws.protocol.rpcv2cbor.StructuredRpcV2CborGenerator; +import com.amazonaws.services.cloudwatch.model.GetMetricDataRequest; +import com.amazonaws.services.cloudwatch.model.Metric; +import com.amazonaws.services.cloudwatch.model.MetricDataQuery; +import com.amazonaws.services.cloudwatch.model.MetricStat; +import com.amazonaws.services.cloudwatch.model.transform.GetMetricDataRequestProtocolMarshaller; +import com.amazonaws.services.cloudwatch.model.transform.GetMetricDataResultRpcV2CborUnmarshaller; +import com.amazonaws.transform.rpcv2cbor.RpcV2CborUnmarshallerContextImpl; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import com.fasterxml.jackson.dataformat.cbor.CBORParser; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1CborProtocolBenchmark { + + private static final CBORFactory CBOR_FACTORY = new CBORFactory(); + + private SdkRpcV2CborProtocolFactory protocolFactory; + private byte[] responseBytes; + private GetMetricDataRequest request; + + @Setup + public void setup() throws Exception { + protocolFactory = new SdkRpcV2CborProtocolFactory(new RpcV2CborClientMetadata()); + responseBytes = createCborResponseFixture(); + request = createRequest(); + } + + @Benchmark + public void getMetricDataDeser(Blackhole bh) throws Exception { + CBORParser parser = CBOR_FACTORY.createParser(responseBytes); + RpcV2CborUnmarshallerContextImpl ctx = new RpcV2CborUnmarshallerContextImpl( + parser, SdkStructuredCborFactory.CBOR_SCALAR_UNMARSHALLERS, null); + ctx.nextToken(); + bh.consume(GetMetricDataResultRpcV2CborUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void getMetricDataSer(Blackhole bh) { + bh.consume(new GetMetricDataRequestProtocolMarshaller(protocolFactory).marshall(request)); + } + + private static GetMetricDataRequest createRequest() { + Date end = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z")); + Date start = Date.from(java.time.Instant.parse("2026-03-09T00:00:00Z").minusSeconds(3600)); + return new GetMetricDataRequest() + .withStartTime(start) + .withEndTime(end) + .withMaxDatapoints(1000) + .withMetricDataQueries( + new MetricDataQuery() + .withId("cpu") + .withMetricStat(new MetricStat() + .withMetric(new Metric() + .withNamespace("AWS/EC2") + .withMetricName("CPUUtilization")) + .withPeriod(300) + .withStat("Average")) + .withReturnData(true)); + } + + private static byte[] createCborResponseFixture() { + StructuredRpcV2CborGenerator gen = + SdkStructuredCborFactory.SDK_CBOR_FACTORY.createWriter("application/cbor"); + gen.writeStartObject(); + gen.writeFieldName("MetricDataResults"); + gen.writeStartArray(); + gen.writeStartObject(); + gen.writeFieldName("Id"); + gen.writeValue("cpu"); + gen.writeFieldName("Label"); + gen.writeValue("CPUUtilization"); + gen.writeFieldName("StatusCode"); + gen.writeValue("Complete"); + gen.writeFieldName("Timestamps"); + gen.writeStartArray(); + long base = 1772611200L; + for (int i = 0; i < 12; i++) { + gen.writeValue((double) ((base + i * 300) * 1000)); + } + gen.writeEndArray(); + gen.writeFieldName("Values"); + gen.writeStartArray(); + for (int i = 0; i < 12; i++) { + gen.writeValue(45.2 + i * 1.1); + } + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + return gen.getBytes(); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1Ec2ProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1Ec2ProtocolBenchmark.java new file mode 100644 index 000000000000..9435f5c5c218 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1Ec2ProtocolBenchmark.java @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.services.ec2.model.DescribeInstancesRequest; +import com.amazonaws.services.ec2.model.Filter; +import com.amazonaws.services.ec2.model.transform.DescribeInstancesRequestMarshaller; +import com.amazonaws.services.ec2.model.transform.DescribeInstancesResultStaxUnmarshaller; +import com.amazonaws.transform.StaxUnmarshallerContext; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1Ec2ProtocolBenchmark { + + private static final XMLInputFactory XML_INPUT_FACTORY = + XMLInputFactory.newInstance(); + + private byte[] responseBytes; + private Map responseHeaders; + private DescribeInstancesRequestMarshaller marshaller; + private DescribeInstancesRequest request; + + @Setup + public void setup() throws Exception { + responseBytes = loadFixture("fixtures/ec2-protocol/describe-instances-response.xml"); + responseHeaders = new HashMap<>(); + marshaller = new DescribeInstancesRequestMarshaller(); + request = createRequest(); + } + + @Benchmark + public void describeInstancesDeser(Blackhole bh) throws Exception { + XMLEventReader reader = XML_INPUT_FACTORY.createXMLEventReader(new ByteArrayInputStream(responseBytes)); + StaxUnmarshallerContext ctx = new StaxUnmarshallerContext(reader, responseHeaders); + ctx.registerMetadataExpression("ResponseMetadata/RequestId", 2, "AWS_REQUEST_ID"); + + bh.consume(DescribeInstancesResultStaxUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void describeInstancesSer(Blackhole bh) { + bh.consume(marshaller.marshall(request)); + } + + private static DescribeInstancesRequest createRequest() { + return new DescribeInstancesRequest() + .withInstanceIds("i-0abcdef1234567890") + .withFilters( + new Filter("instance-state-name").withValues("running"), + new Filter("instance-type").withValues("m5.xlarge")) + .withMaxResults(100); + } + + private static byte[] loadFixture(String path) throws IOException { + return com.amazonaws.util.IOUtils.toByteArray( + V1Ec2ProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1JsonProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1JsonProtocolBenchmark.java new file mode 100644 index 000000000000..aee02c72626a --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1JsonProtocolBenchmark.java @@ -0,0 +1,121 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.http.HttpResponse; +import com.amazonaws.protocol.json.JsonClientMetadata; +import com.amazonaws.protocol.json.SdkJsonProtocolFactory; +import com.amazonaws.protocol.json.SdkStructuredPlainJsonFactory; +import com.amazonaws.services.dynamodbv2.model.AttributeValue; +import com.amazonaws.services.dynamodbv2.model.PutItemRequest; +import com.amazonaws.services.dynamodbv2.model.transform.PutItemRequestProtocolMarshaller; +import com.amazonaws.services.dynamodbv2.model.transform.PutItemResultJsonUnmarshaller; +import com.amazonaws.transform.JsonUnmarshallerContextImpl; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1JsonProtocolBenchmark { + + private static final JsonFactory JSON_FACTORY = new JsonFactory(); + private byte[] putItemResponseBytes; + private HttpResponse httpResponse; + private SdkJsonProtocolFactory protocolFactory; + private PutItemRequest putItemRequest; + + @Setup + public void setup() throws Exception { + putItemResponseBytes = loadFixture("fixtures/json-protocol/putitem-response.json"); + httpResponse = new HttpResponse(null, null); + httpResponse.setStatusCode(200); + protocolFactory = new SdkJsonProtocolFactory( + new JsonClientMetadata().withProtocolVersion("1.0")); + putItemRequest = new PutItemRequest() + .withTableName("benchmark-table") + .withItem(itemMap()); + } + + @Benchmark + public void putItemDeser(Blackhole bh) throws Exception { + JsonParser parser = JSON_FACTORY.createParser(new ByteArrayInputStream(putItemResponseBytes)); + JsonUnmarshallerContextImpl ctx = new JsonUnmarshallerContextImpl(parser, + SdkStructuredPlainJsonFactory.JSON_SCALAR_UNMARSHALLERS, + SdkStructuredPlainJsonFactory.JSON_CUSTOM_TYPE_UNMARSHALLERS, + httpResponse); + + bh.consume(PutItemResultJsonUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void putItemSer(Blackhole bh) { + bh.consume(new PutItemRequestProtocolMarshaller(protocolFactory).marshall(putItemRequest)); + } + + private static Map itemMap() { + Map item = new HashMap(); + item.put("pk", new AttributeValue().withS("benchmark-key")); + item.put("sk", new AttributeValue().withN("100")); + item.put("stringField", new AttributeValue().withS("test-value")); + item.put("numberField", new AttributeValue().withN("123.456")); + item.put("binaryField", new AttributeValue() + .withB(ByteBuffer.wrap("hello world".getBytes()))); + item.put("stringSetField", new AttributeValue() + .withSS("value1", "value2", "value3")); + item.put("numberSetField", new AttributeValue() + .withNS("1.1", "2.2", "3.3")); + item.put("boolField", new AttributeValue().withBOOL(false)); + item.put("nullField", new AttributeValue().withNULL(true)); + Map deep = new HashMap(); + deep.put("level2", new AttributeValue().withN("999")); + Map nested = new HashMap(); + nested.put("nested", new AttributeValue().withS("nested-value")); + nested.put("deepNested", new AttributeValue().withM(deep)); + item.put("mapField", new AttributeValue().withM(nested)); + item.put("listField", new AttributeValue().withL( + new AttributeValue().withS("item1"), + new AttributeValue().withN("42"), + new AttributeValue().withBOOL(true), + new AttributeValue().withNULL(true))); + return item; + } + + private static byte[] loadFixture(String path) throws IOException { + return com.amazonaws.util.IOUtils.toByteArray( + V1JsonProtocolBenchmark.class.getClassLoader().getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1QueryProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1QueryProtocolBenchmark.java new file mode 100644 index 000000000000..9e3ca35ad618 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1QueryProtocolBenchmark.java @@ -0,0 +1,93 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; +import com.amazonaws.services.securitytoken.model.transform.AssumeRoleRequestMarshaller; +import com.amazonaws.services.securitytoken.model.transform.AssumeRoleResultStaxUnmarshaller; +import com.amazonaws.transform.StaxUnmarshallerContext; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1QueryProtocolBenchmark { + + private static final XMLInputFactory XML_INPUT_FACTORY = + XMLInputFactory.newInstance(); + + private byte[] responseBytes; + private Map responseHeaders; + private AssumeRoleRequestMarshaller marshaller; + private AssumeRoleRequest request; + + @Setup + public void setup() throws Exception { + responseBytes = loadFixture("fixtures/query-protocol/assumerole-response.xml"); + responseHeaders = new HashMap<>(); + marshaller = new AssumeRoleRequestMarshaller(); + request = createRequest(); + } + + @Benchmark + public void assumeRoleDeser(Blackhole bh) throws Exception { + XMLEventReader reader = XML_INPUT_FACTORY.createXMLEventReader(new ByteArrayInputStream(responseBytes)); + StaxUnmarshallerContext ctx = new StaxUnmarshallerContext(reader, responseHeaders); + ctx.registerMetadataExpression("ResponseMetadata/RequestId", 2, "AWS_REQUEST_ID"); + + bh.consume(AssumeRoleResultStaxUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void assumeRoleSer(Blackhole bh) { + bh.consume(marshaller.marshall(request)); + } + + private static AssumeRoleRequest createRequest() { + return new AssumeRoleRequest() + .withRoleArn("arn:aws:iam::123456789012:role/benchmark-role") + .withRoleSessionName("benchmark-session") + .withDurationSeconds(3600) + .withExternalId("benchmark-external-id") + .withPolicy("{\"Version\":\"2012-10-17\"}"); + } + + private static byte[] loadFixture(String path) throws IOException { + return com.amazonaws.util.IOUtils.toByteArray( + V1QueryProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestJsonProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestJsonProtocolBenchmark.java new file mode 100644 index 000000000000..47da0763a6ac --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestJsonProtocolBenchmark.java @@ -0,0 +1,120 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.http.HttpResponse; +import com.amazonaws.protocol.json.JsonClientMetadata; +import com.amazonaws.protocol.json.SdkJsonProtocolFactory; +import com.amazonaws.protocol.json.SdkStructuredPlainJsonFactory; +import com.amazonaws.services.lambda.model.CreateFunctionRequest; +import com.amazonaws.services.lambda.model.Environment; +import com.amazonaws.services.lambda.model.FunctionCode; +import com.amazonaws.services.lambda.model.Runtime; +import com.amazonaws.services.lambda.model.TracingConfig; +import com.amazonaws.services.lambda.model.TracingMode; +import com.amazonaws.services.lambda.model.transform.CreateFunctionRequestProtocolMarshaller; +import com.amazonaws.services.lambda.model.transform.CreateFunctionResultJsonUnmarshaller; +import com.amazonaws.transform.JsonUnmarshallerContextImpl; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1RestJsonProtocolBenchmark { + + private static final JsonFactory JSON_FACTORY = new JsonFactory(); + + private byte[] responseBytes; + private HttpResponse httpResponse; + private SdkJsonProtocolFactory protocolFactory; + private CreateFunctionRequest request; + + @Setup + public void setup() throws Exception { + responseBytes = loadFixture("fixtures/rest-json-protocol/createfunction-response.json"); + httpResponse = new HttpResponse(null, null); + httpResponse.setStatusCode(200); + protocolFactory = new SdkJsonProtocolFactory(new JsonClientMetadata() + .withProtocolVersion("1.1") + .withContentTypeOverride("application/json")); + request = createRequest(); + } + + @Benchmark + public void createFunctionDeser(Blackhole bh) throws Exception { + JsonParser parser = JSON_FACTORY.createParser(new ByteArrayInputStream(responseBytes)); + JsonUnmarshallerContextImpl ctx = new JsonUnmarshallerContextImpl( + parser, + SdkStructuredPlainJsonFactory.JSON_SCALAR_UNMARSHALLERS, + SdkStructuredPlainJsonFactory.JSON_CUSTOM_TYPE_UNMARSHALLERS, + httpResponse); + + bh.consume(CreateFunctionResultJsonUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void createFunctionSer(Blackhole bh) { + bh.consume(new CreateFunctionRequestProtocolMarshaller(protocolFactory) + .marshall(request)); + } + + private static CreateFunctionRequest createRequest() { + Map envVars = new HashMap<>(); + envVars.put("ENV_VAR_1", "value1"); + + return new CreateFunctionRequest() + .withFunctionName("benchmark-function") + .withRuntime(Runtime.Java8) + .withRole("arn:aws:iam::123456789012:role/lambda-role") + .withHandler("com.example.Handler::handleRequest") + .withCode(new FunctionCode() + .withS3Bucket("my-deploy-bucket") + .withS3Key("code/function.zip")) + .withDescription("Benchmark test function") + .withTimeout(30) + .withMemorySize(512) + .withPublish(false) + .withEnvironment(new Environment().withVariables(envVars)) + .withTracingConfig(new TracingConfig() + .withMode(TracingMode.Active)); + } + + private static byte[] loadFixture(String path) throws IOException { + return com.amazonaws.util.IOUtils.toByteArray( + V1RestJsonProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestXmlProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestXmlProtocolBenchmark.java new file mode 100644 index 000000000000..b5b7f578992e --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V1RestXmlProtocolBenchmark.java @@ -0,0 +1,134 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import com.amazonaws.http.HttpResponse; +import com.amazonaws.services.cloudfront.model.Aliases; +import com.amazonaws.services.cloudfront.model.AllowedMethods; +import com.amazonaws.services.cloudfront.model.CachedMethods; +import com.amazonaws.services.cloudfront.model.CreateDistributionRequest; +import com.amazonaws.services.cloudfront.model.DefaultCacheBehavior; +import com.amazonaws.services.cloudfront.model.DistributionConfig; +import com.amazonaws.services.cloudfront.model.Method; +import com.amazonaws.services.cloudfront.model.Origin; +import com.amazonaws.services.cloudfront.model.Origins; +import com.amazonaws.services.cloudfront.model.S3OriginConfig; +import com.amazonaws.services.cloudfront.model.ViewerProtocolPolicy; +import com.amazonaws.services.cloudfront.model.transform.CreateDistributionRequestMarshaller; +import com.amazonaws.services.cloudfront.model.transform.CreateDistributionResultStaxUnmarshaller; +import com.amazonaws.transform.StaxUnmarshallerContext; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V1RestXmlProtocolBenchmark { + + private static final XMLInputFactory XML_INPUT_FACTORY = XMLInputFactory.newInstance(); + + private byte[] responseBytes; + private Map responseHeaders; + private CreateDistributionRequestMarshaller marshaller; + private CreateDistributionRequest request; + + @Setup + public void setup() throws Exception { + responseBytes = loadFixture("fixtures/rest-xml-protocol/create-distribution-response.xml"); + + responseHeaders = new HashMap<>(); + responseHeaders.put("ETag", "E2QWRUHEXAMPLE"); + responseHeaders.put("Location", "https://cloudfront.amazonaws.com/2020-05-31/distribution/EDFDVBD6EXAMPLE"); + + HttpResponse httpResponse = new HttpResponse(null, null); + httpResponse.setStatusCode(200); + for (Map.Entry e : responseHeaders.entrySet()) { + httpResponse.addHeader(e.getKey(), e.getValue()); + } + + marshaller = new CreateDistributionRequestMarshaller(); + request = createRequest(); + } + + @Benchmark + public void createDistributionDeser(Blackhole bh) throws Exception { + XMLEventReader reader = XML_INPUT_FACTORY.createXMLEventReader(new ByteArrayInputStream(responseBytes)); + StaxUnmarshallerContext ctx = new StaxUnmarshallerContext( + reader, responseHeaders); + ctx.registerMetadataExpression("ResponseMetadata/RequestId", 2, "AWS_REQUEST_ID"); + bh.consume(CreateDistributionResultStaxUnmarshaller.getInstance().unmarshall(ctx)); + } + + @Benchmark + public void createDistributionSer(Blackhole bh) { + bh.consume(marshaller.marshall(request)); + } + + private static CreateDistributionRequest createRequest() { + return new CreateDistributionRequest() + .withDistributionConfig(new DistributionConfig() + .withCallerReference("benchmark-ref-2024") + .withAliases(new Aliases() + .withQuantity(2) + .withItems("www.example.com", "cdn.example.com")) + .withDefaultRootObject("index.html") + .withOrigins(new Origins() + .withQuantity(1) + .withItems(new Origin() + .withId("myS3Origin") + .withDomainName("mybucket.s3.amazonaws.com") + .withOriginPath("/production") + .withS3OriginConfig(new S3OriginConfig() + .withOriginAccessIdentity( + "origin-access-identity/cloudfront/E127EXAMPLE51Z")))) + .withDefaultCacheBehavior(new DefaultCacheBehavior() + .withTargetOriginId("myS3Origin") + .withViewerProtocolPolicy( + ViewerProtocolPolicy.RedirectToHttps) + .withAllowedMethods(new AllowedMethods() + .withQuantity(3) + .withItems(Method.GET, Method.HEAD, Method.OPTIONS) + .withCachedMethods(new CachedMethods() + .withQuantity(2) + .withItems(Method.GET, Method.HEAD))) + .withCompress(true))); + } + + private static byte[] loadFixture(String path) throws IOException { + return com.amazonaws.util.IOUtils.toByteArray( + V1RestXmlProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2CborProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2CborProtocolBenchmark.java new file mode 100644 index 000000000000..4f2785ee156b --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2CborProtocolBenchmark.java @@ -0,0 +1,174 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; +import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; +import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkStructuredRpcV2CborFactory; +import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataRequest; +import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataResponse; +import software.amazon.awssdk.services.cloudwatch.model.Metric; +import software.amazon.awssdk.services.cloudwatch.model.MetricDataQuery; +import software.amazon.awssdk.services.cloudwatch.model.MetricStat; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2CborProtocolBenchmark { + + private static final String CONTENT_TYPE = "application/cbor"; + private static final URI ENDPOINT = URI.create("http://localhost/"); + + private static final AwsJsonProtocolMetadata METADATA = AwsJsonProtocolMetadata.builder() + .protocol(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) + .contentType(CONTENT_TYPE) + .build(); + + private static final OperationInfo OP_INFO = OperationInfo.builder() + .requestUri("/service/GraniteServiceVersion20100801/operation/GetMetricData") + .httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false) + .hasImplicitPayloadMembers(true) + .hasPayloadMembers(true) + .build(); + + private JsonProtocolUnmarshaller unmarshaller; + private byte[] responseBytes; + private GetMetricDataRequest request; + + @Setup + public void setup() throws Exception { + unmarshaller = JsonProtocolUnmarshaller.builder() + .enableFastUnmarshalling(true) + .protocolUnmarshallDependencies(SmithyRpcV2CborProtocolFactory.defaultProtocolUnmarshallDependencies()) + .build(); + + responseBytes = createCborResponseFixture(); + request = createRequest(); + } + + @Benchmark + public void getMetricDataDeser(Blackhole bh) throws Exception { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .putHeader("Content-Type", CONTENT_TYPE) + .content(AbortableInputStream.create(new ByteArrayInputStream(responseBytes))) + .build(); + bh.consume(unmarshaller.unmarshall(GetMetricDataResponse.builder(), response)); + } + + @Benchmark + public void getMetricDataSer(Blackhole bh) { + ProtocolMarshaller marshaller = JsonProtocolMarshallerBuilder.create() + .endpoint(ENDPOINT) + .jsonGenerator(SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY.createWriter(CONTENT_TYPE)) + .contentType(CONTENT_TYPE) + .operationInfo(OP_INFO) + .sendExplicitNullForPayload(false) + .protocolMetadata(METADATA) + .build(); + bh.consume(marshaller.marshall(request)); + } + + private static GetMetricDataRequest createRequest() { + Instant end = Instant.parse("2026-03-09T00:00:00Z"); + Instant start = end.minusSeconds(3600); + return GetMetricDataRequest.builder() + .startTime(start) + .endTime(end) + .maxDatapoints(1000) + .metricDataQueries( + MetricDataQuery.builder() + .id("cpu") + .metricStat(MetricStat.builder() + .metric(Metric.builder() + .namespace("AWS/EC2") + .metricName("CPUUtilization") + .build()) + .period(300) + .stat("Average") + .build()) + .returnData(true) + .build()) + .build(); + } + + private static byte[] createCborResponseFixture() { + StructuredJsonGenerator gen = + SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY.createWriter(CONTENT_TYPE); + gen.writeStartObject(); + gen.writeFieldName("MetricDataResults"); + gen.writeStartArray(); + gen.writeStartObject(); + gen.writeFieldName("Id"); + gen.writeValue("cpu"); + gen.writeFieldName("Label"); + gen.writeValue("CPUUtilization"); + gen.writeFieldName("StatusCode"); + gen.writeValue("Complete"); + gen.writeFieldName("Timestamps"); + gen.writeStartArray(); + long base = 1772611200L; + for (int i = 0; i < 12; i++) { + gen.writeValue((double) ((base + i * 300) * 1000)); + } + gen.writeEndArray(); + gen.writeFieldName("Values"); + gen.writeStartArray(); + for (int i = 0; i < 12; i++) { + gen.writeValue(45.2 + i * 1.1); + } + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + gen.writeEndArray(); + gen.writeFieldName("Messages"); + gen.writeStartArray(); + gen.writeEndArray(); + gen.writeEndObject(); + return gen.getBytes(); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2Ec2ProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2Ec2ProtocolBenchmark.java new file mode 100644 index 000000000000..677772608ac7 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2Ec2ProtocolBenchmark.java @@ -0,0 +1,113 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.query.internal.marshall.QueryProtocolMarshaller; +import software.amazon.awssdk.protocols.query.internal.unmarshall.QueryProtocolUnmarshaller; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; +import software.amazon.awssdk.services.ec2.model.Filter; +import software.amazon.awssdk.utils.Pair; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2Ec2ProtocolBenchmark { + + private static final URI ENDPOINT = URI.create("http://localhost/"); + private static final OperationInfo OP_INFO = OperationInfo.builder() + .requestUri("/") + .httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false) + .hasPayloadMembers(true) + .operationIdentifier("DescribeInstances") + .apiVersion("2016-11-15") + .build(); + + private QueryProtocolUnmarshaller unmarshaller; + private byte[] responseBytes; + private DescribeInstancesRequest request; + + @Setup + public void setup() throws Exception { + unmarshaller = QueryProtocolUnmarshaller.builder().hasResultWrapper(false).build(); + responseBytes = loadFixture("fixtures/ec2-protocol/describe-instances-response.xml"); + request = createRequest(); + } + + @Benchmark + public void describeInstancesDeser(Blackhole bh) { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .content(AbortableInputStream.create(new ByteArrayInputStream(responseBytes))) + .build(); + + Pair result = unmarshaller.unmarshall(DescribeInstancesResponse.builder(), response); + bh.consume(result.left()); + } + + @Benchmark + public void describeInstancesSer(Blackhole bh) { + ProtocolMarshaller marshaller = QueryProtocolMarshaller.builder() + .endpoint(ENDPOINT) + .operationInfo(OP_INFO) + .isEc2(true) + .build(); + bh.consume(marshaller.marshall(request)); + } + + private static DescribeInstancesRequest createRequest() { + return DescribeInstancesRequest.builder() + .instanceIds("i-0abcdef1234567890") + .filters( + Filter.builder().name("instance-state-name") + .values("running").build(), + Filter.builder().name("instance-type") + .values("m5.xlarge").build()) + .maxResults(100) + .build(); + } + + private static byte[] loadFixture(String path) throws IOException { + return software.amazon.awssdk.utils.IoUtils.toByteArray( + V2Ec2ProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2JsonProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2JsonProtocolBenchmark.java new file mode 100644 index 000000000000..1983abf9a931 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2JsonProtocolBenchmark.java @@ -0,0 +1,147 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; +import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory; +import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; +import software.amazon.awssdk.services.dynamodb.model.PutItemResponse; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2JsonProtocolBenchmark { + + private static final String CONTENT_TYPE = "application/x-amz-json-1.0"; + private static final URI ENDPOINT = URI.create("http://localhost/"); + private static final OperationInfo OP_INFO = OperationInfo.builder() + .httpMethod(SdkHttpMethod.POST) + .hasImplicitPayloadMembers(true) + .build(); + + private static final AwsJsonProtocolMetadata METADATA = AwsJsonProtocolMetadata.builder() + .protocol(AwsJsonProtocol.AWS_JSON) + .contentType(CONTENT_TYPE) + .build(); + + private JsonProtocolUnmarshaller unmarshaller; + private byte[] putItemResponseBytes; + private PutItemRequest putItemRequest; + + @Setup + public void setup() throws Exception { + unmarshaller = JsonProtocolUnmarshaller.builder() + .enableFastUnmarshalling(true) + .protocolUnmarshallDependencies(JsonProtocolUnmarshaller.defaultProtocolUnmarshallDependencies()) + .build(); + + putItemResponseBytes = loadFixture("fixtures/json-protocol/putitem-response.json"); + putItemRequest = PutItemRequest.builder() + .tableName("benchmark-table") + .item(itemMap()) + .build(); + } + + @Benchmark + public void putItemDeser(Blackhole bh) throws Exception { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .putHeader("Content-Type", CONTENT_TYPE) + .content(AbortableInputStream.create(new ByteArrayInputStream(putItemResponseBytes))) + .build(); + + bh.consume(unmarshaller.unmarshall(PutItemResponse.builder(), response)); + } + + @Benchmark + public void putItemSer(Blackhole bh) { + ProtocolMarshaller marshaller = JsonProtocolMarshallerBuilder.create() + .endpoint(ENDPOINT) + .jsonGenerator(AwsStructuredPlainJsonFactory.SDK_JSON_FACTORY + .createWriter(CONTENT_TYPE)) + .contentType(CONTENT_TYPE) + .operationInfo(OP_INFO) + .sendExplicitNullForPayload(false) + .protocolMetadata(METADATA) + .build(); + + bh.consume(marshaller.marshall(putItemRequest)); + } + + private static Map itemMap() { + Map item = new HashMap(); + item.put("pk", AttributeValue.fromS("benchmark-key")); + item.put("sk", AttributeValue.fromN("100")); + item.put("stringField", AttributeValue.fromS("test-value")); + item.put("numberField", AttributeValue.fromN("123.456")); + item.put("binaryField", AttributeValue.fromB( + SdkBytes.fromByteArray("hello world".getBytes()))); + item.put("stringSetField", AttributeValue.builder() + .ss("value1", "value2", "value3").build()); + item.put("numberSetField", AttributeValue.builder() + .ns("1.1", "2.2", "3.3").build()); + item.put("boolField", AttributeValue.fromBool(false)); + item.put("nullField", AttributeValue.builder().nul(true).build()); + Map deep = new HashMap(); + deep.put("level2", AttributeValue.fromN("999")); + Map nested = new HashMap(); + nested.put("nested", AttributeValue.fromS("nested-value")); + nested.put("deepNested", AttributeValue.fromM(deep)); + item.put("mapField", AttributeValue.fromM(nested)); + item.put("listField", AttributeValue.builder().l( + AttributeValue.fromS("item1"), + AttributeValue.fromN("42"), + AttributeValue.fromBool(true), + AttributeValue.builder().nul(true).build()).build()); + return item; + } + + private static byte[] loadFixture(String path) throws IOException { + return software.amazon.awssdk.utils.IoUtils.toByteArray( + V2JsonProtocolBenchmark.class.getClassLoader().getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2QueryProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2QueryProtocolBenchmark.java new file mode 100644 index 000000000000..6d902e72fb5f --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2QueryProtocolBenchmark.java @@ -0,0 +1,113 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.query.internal.marshall.QueryProtocolMarshaller; +import software.amazon.awssdk.protocols.query.internal.unmarshall.QueryProtocolUnmarshaller; +import software.amazon.awssdk.services.sts.model.AssumeRoleRequest; +import software.amazon.awssdk.services.sts.model.AssumeRoleResponse; +import software.amazon.awssdk.utils.Pair; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2QueryProtocolBenchmark { + + private static final URI ENDPOINT = URI.create("http://localhost/"); + private static final OperationInfo OP_INFO = OperationInfo.builder() + .requestUri("/") + .httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false) + .hasPayloadMembers(true) + .operationIdentifier("AssumeRole") + .apiVersion("2011-06-15") + .build(); + + private QueryProtocolUnmarshaller unmarshaller; + private byte[] responseBytes; + private AssumeRoleRequest request; + + @Setup + public void setup() throws Exception { + unmarshaller = QueryProtocolUnmarshaller.builder() + .hasResultWrapper(true) + .build(); + + responseBytes = loadFixture("fixtures/query-protocol/assumerole-response.xml"); + request = createRequest(); + } + + @Benchmark + public void assumeRoleDeser(Blackhole bh) { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .content(AbortableInputStream.create(new ByteArrayInputStream(responseBytes))) + .build(); + + Pair result = unmarshaller.unmarshall(AssumeRoleResponse.builder(), response); + bh.consume(result.left()); + } + + @Benchmark + public void assumeRoleSer(Blackhole bh) { + ProtocolMarshaller marshaller = QueryProtocolMarshaller.builder() + .endpoint(ENDPOINT) + .operationInfo(OP_INFO) + .isEc2(false) + .build(); + bh.consume(marshaller.marshall(request)); + } + + private static AssumeRoleRequest createRequest() { + return AssumeRoleRequest.builder() + .roleArn("arn:aws:iam::123456789012:role/benchmark-role") + .roleSessionName("benchmark-session") + .durationSeconds(3600) + .externalId("benchmark-external-id") + .policy("{\"Version\":\"2012-10-17\"}") + .build(); + } + + private static byte[] loadFixture(String path) throws IOException { + return software.amazon.awssdk.utils.IoUtils.toByteArray( + V2QueryProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestJsonProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestJsonProtocolBenchmark.java new file mode 100644 index 000000000000..41da5aa1e459 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestJsonProtocolBenchmark.java @@ -0,0 +1,149 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; +import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory; +import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.services.lambda.model.CreateFunctionRequest; +import software.amazon.awssdk.services.lambda.model.CreateFunctionResponse; +import software.amazon.awssdk.services.lambda.model.Environment; +import software.amazon.awssdk.services.lambda.model.FunctionCode; +import software.amazon.awssdk.services.lambda.model.Runtime; +import software.amazon.awssdk.services.lambda.model.TracingConfig; +import software.amazon.awssdk.services.lambda.model.TracingMode; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2RestJsonProtocolBenchmark { + + private static final String CONTENT_TYPE = "application/json"; + private static final URI ENDPOINT = URI.create("http://localhost/"); + private static final OperationInfo OP_INFO = OperationInfo.builder() + .requestUri("/2015-03-31/functions") + .httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false) + .hasImplicitPayloadMembers(true) + .hasPayloadMembers(true) + .build(); + + private static final AwsJsonProtocolMetadata METADATA = + AwsJsonProtocolMetadata.builder() + .protocol(AwsJsonProtocol.REST_JSON) + .protocolVersion("1.1") + .contentType(CONTENT_TYPE) + .build(); + + private JsonProtocolUnmarshaller unmarshaller; + private byte[] responseBytes; + private CreateFunctionRequest request; + + @Setup + public void setup() throws Exception { + unmarshaller = JsonProtocolUnmarshaller.builder() + .enableFastUnmarshalling(true) + .protocolUnmarshallDependencies(JsonProtocolUnmarshaller.defaultProtocolUnmarshallDependencies()) + .build(); + + responseBytes = loadFixture("fixtures/rest-json-protocol/createfunction-response.json"); + request = createRequest(); + } + + @Benchmark + public void createFunctionDeser(Blackhole bh) throws Exception { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .putHeader("Content-Type", CONTENT_TYPE) + .content(AbortableInputStream.create( + new ByteArrayInputStream(responseBytes))) + .build(); + bh.consume(unmarshaller.unmarshall(CreateFunctionResponse.builder(), response)); + } + + @Benchmark + public void createFunctionSer(Blackhole bh) { + ProtocolMarshaller marshaller = + JsonProtocolMarshallerBuilder.create() + .endpoint(ENDPOINT) + .jsonGenerator(AwsStructuredPlainJsonFactory.SDK_JSON_FACTORY + .createWriter(CONTENT_TYPE)) + .contentType(CONTENT_TYPE) + .operationInfo(OP_INFO) + .sendExplicitNullForPayload(false) + .protocolMetadata(METADATA) + .build(); + bh.consume(marshaller.marshall(request)); + } + + private static CreateFunctionRequest createRequest() { + Map envVars = new HashMap<>(); + envVars.put("ENV_VAR_1", "value1"); + + return CreateFunctionRequest.builder() + .functionName("benchmark-function") + .runtime(Runtime.JAVA8) + .role("arn:aws:iam::123456789012:role/lambda-role") + .handler("com.example.Handler::handleRequest") + .code(FunctionCode.builder() + .s3Bucket("my-deploy-bucket") + .s3Key("code/function.zip") + .build()) + .description("Benchmark test function") + .timeout(30) + .memorySize(512) + .publish(false) + .environment(Environment.builder().variables(envVars).build()) + .tracingConfig(TracingConfig.builder() + .mode(TracingMode.ACTIVE) + .build()) + .build(); + } + + private static byte[] loadFixture(String path) throws IOException { + return software.amazon.awssdk.utils.IoUtils.toByteArray( + V2RestJsonProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestXmlProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestXmlProtocolBenchmark.java new file mode 100644 index 000000000000..171099bd1be6 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/protocol/V2RestXmlProtocolBenchmark.java @@ -0,0 +1,150 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.benchmark.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.xml.AwsXmlProtocolFactory; +import software.amazon.awssdk.protocols.xml.internal.marshall.XmlGenerator; +import software.amazon.awssdk.protocols.xml.internal.marshall.XmlProtocolMarshaller; +import software.amazon.awssdk.protocols.xml.internal.unmarshall.XmlProtocolUnmarshaller; +import software.amazon.awssdk.services.cloudfront.model.Aliases; +import software.amazon.awssdk.services.cloudfront.model.AllowedMethods; +import software.amazon.awssdk.services.cloudfront.model.CachedMethods; +import software.amazon.awssdk.services.cloudfront.model.CreateDistributionRequest; +import software.amazon.awssdk.services.cloudfront.model.CreateDistributionResponse; +import software.amazon.awssdk.services.cloudfront.model.DefaultCacheBehavior; +import software.amazon.awssdk.services.cloudfront.model.DistributionConfig; +import software.amazon.awssdk.services.cloudfront.model.Method; +import software.amazon.awssdk.services.cloudfront.model.Origin; +import software.amazon.awssdk.services.cloudfront.model.Origins; +import software.amazon.awssdk.services.cloudfront.model.S3OriginConfig; +import software.amazon.awssdk.services.cloudfront.model.ViewerProtocolPolicy; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +@Fork(2) +public class V2RestXmlProtocolBenchmark { + + private static final String XMLNS = "http://cloudfront.amazonaws.com/doc/2020-05-31/"; + private static final URI ENDPOINT = URI.create("http://localhost/"); + private static final OperationInfo OP_INFO = OperationInfo.builder() + .requestUri("/2020-05-31/distribution") + .httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(true) + .hasPayloadMembers(true) + .putAdditionalMetadata(AwsXmlProtocolFactory.ROOT_MARSHALL_LOCATION_ATTRIBUTE, null) + .putAdditionalMetadata(AwsXmlProtocolFactory.XML_NAMESPACE_ATTRIBUTE, XMLNS) + .build(); + + private XmlProtocolUnmarshaller unmarshaller; + private byte[] responseBytes; + private CreateDistributionRequest request; + + @Setup + public void setup() throws Exception { + unmarshaller = XmlProtocolUnmarshaller.create(); + responseBytes = loadFixture("fixtures/rest-xml-protocol/create-distribution-response.xml"); + request = createRequest(); + } + + @Benchmark + public void createDistributionDeser(Blackhole bh) { + SdkHttpFullResponse response = SdkHttpFullResponse.builder() + .statusCode(200) + .putHeader("ETag", "E2QWRUHEXAMPLE") + .putHeader("Location", "https://cloudfront.amazonaws.com/2020-05-31/distribution/EDFDVBD6EXAMPLE") + .content(AbortableInputStream.create(new ByteArrayInputStream(responseBytes))) + .build(); + bh.consume(unmarshaller.unmarshall(CreateDistributionResponse.builder(), response)); + } + + @Benchmark + public void createDistributionSer(Blackhole bh) { + ProtocolMarshaller marshaller = XmlProtocolMarshaller.builder() + .endpoint(ENDPOINT) + .xmlGenerator(XmlGenerator.create(XMLNS, false)) + .operationInfo(OP_INFO) + .build(); + bh.consume(marshaller.marshall(request)); + } + + private static CreateDistributionRequest createRequest() { + return CreateDistributionRequest.builder() + .distributionConfig(DistributionConfig.builder() + .callerReference("benchmark-ref-2024") + .aliases(Aliases.builder() + .quantity(2) + .items("www.example.com", "cdn.example.com") + .build()) + .defaultRootObject("index.html") + .origins(Origins.builder() + .quantity(1) + .items(Origin.builder() + .id("myS3Origin") + .domainName("mybucket.s3.amazonaws.com") + .originPath("/production") + .s3OriginConfig(S3OriginConfig.builder() + .originAccessIdentity( + "origin-access-identity/cloudfront/E127EXAMPLE51Z") + .build()) + .build()) + .build()) + .defaultCacheBehavior(DefaultCacheBehavior.builder() + .targetOriginId("myS3Origin") + .viewerProtocolPolicy(ViewerProtocolPolicy.REDIRECT_TO_HTTPS) + .allowedMethods(AllowedMethods.builder() + .quantity(3) + .items(Method.GET, Method.HEAD, Method.OPTIONS) + .cachedMethods(CachedMethods.builder() + .quantity(2) + .items(Method.GET, Method.HEAD) + .build()) + .build()) + .compress(true) + .build()) + .build()) + .build(); + } + + private static byte[] loadFixture(String path) throws IOException { + return software.amazon.awssdk.utils.IoUtils.toByteArray( + V2RestXmlProtocolBenchmark.class.getClassLoader() + .getResourceAsStream(path)); + } +} diff --git a/test/sdk-benchmarks/src/main/resources/fixtures/ec2-protocol/describe-instances-response.xml b/test/sdk-benchmarks/src/main/resources/fixtures/ec2-protocol/describe-instances-response.xml new file mode 100644 index 000000000000..6a8153163fdb --- /dev/null +++ b/test/sdk-benchmarks/src/main/resources/fixtures/ec2-protocol/describe-instances-response.xml @@ -0,0 +1,37 @@ + + 8f7724cf-496f-496e-8fe2-example + + + r-0abcdef1234567890 + 123456789012 + + + i-0abcdef1234567890 + ami-0abcdef1234567890 + 16running + ip-10-0-0-1.ec2.internal + ec2-203-0-113-1.compute-1.amazonaws.com + m5.xlarge + 2024-01-15T10:30:00.000Z + us-east-1adefault + disabled + subnet-0abcdef1234567890 + vpc-0abcdef1234567890 + 10.0.0.1 + 203.0.113.1 + x86_64 + ebs + /dev/xvda + hvm + xen + + Namebenchmark-instance + Environmentproduction + + true + true + + + + + diff --git a/test/sdk-benchmarks/src/main/resources/fixtures/json-protocol/putitem-response.json b/test/sdk-benchmarks/src/main/resources/fixtures/json-protocol/putitem-response.json new file mode 100644 index 000000000000..df9f0e8ada3f --- /dev/null +++ b/test/sdk-benchmarks/src/main/resources/fixtures/json-protocol/putitem-response.json @@ -0,0 +1,24 @@ +{ + "Attributes": { + "pk": {"S": "benchmark-key"}, + "sk": {"N": "100"}, + "stringField": {"S": "test-value"}, + "numberField": {"N": "123.456"}, + "binaryField": {"B": "aGVsbG8gd29ybGQ="}, + "stringSetField": {"SS": ["value1", "value2", "value3"]}, + "numberSetField": {"NS": ["1.1", "2.2", "3.3"]}, + "binarySetField": {"BS": ["YmluMQ==", "YmluMg=="]}, + "mapField": {"M": { + "nested": {"S": "nested-value"}, + "deepNested": {"M": {"level2": {"N": "999"}}} + }}, + "listField": {"L": [ + {"S": "item1"}, + {"N": "42"}, + {"BOOL": true}, + {"NULL": true} + ]}, + "nullField": {"NULL": true}, + "boolField": {"BOOL": false} + } +} \ No newline at end of file diff --git a/test/sdk-benchmarks/src/main/resources/fixtures/query-protocol/assumerole-response.xml b/test/sdk-benchmarks/src/main/resources/fixtures/query-protocol/assumerole-response.xml new file mode 100644 index 000000000000..db2481e96745 --- /dev/null +++ b/test/sdk-benchmarks/src/main/resources/fixtures/query-protocol/assumerole-response.xml @@ -0,0 +1,19 @@ + + + + ASIAIOSFODNN7EXAMPLE + wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + FwoGZXIvYXdzEBYaDHqa0AP1 + 2024-01-15T12:00:00Z + + + AROA3XFRBF23EXAMPLE:benchmark-session + arn:aws:sts::123456789012:assumed-role/benchmark-role/benchmark-session + + 42 + benchmark-source + + + c6104cbe-af31-11e0-8154-cde7cf80f29a + + diff --git a/test/sdk-benchmarks/src/main/resources/fixtures/rest-json-protocol/createfunction-response.json b/test/sdk-benchmarks/src/main/resources/fixtures/rest-json-protocol/createfunction-response.json new file mode 100644 index 000000000000..638c54e42837 --- /dev/null +++ b/test/sdk-benchmarks/src/main/resources/fixtures/rest-json-protocol/createfunction-response.json @@ -0,0 +1,43 @@ +{ + "FunctionName": "benchmark-function", + "FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:benchmark-function", + "Runtime": "java21", + "Role": "arn:aws:iam::123456789012:role/lambda-role", + "Handler": "com.example.Handler::handleRequest", + "CodeSize": 5242880, + "Description": "Benchmark test function", + "Timeout": 30, + "MemorySize": 512, + "LastModified": "2024-01-15T10:30:00.000+0000", + "CodeSha256": "dGVzdGhhc2g=", + "Version": "$LATEST", + "Environment": { + "Variables": { + "ENV_VAR_1": "value1", + "ENV_VAR_2": "value2", + "TABLE_NAME": "my-table" + } + }, + "TracingConfig": { + "Mode": "Active" + }, + "RevisionId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111", + "Layers": [ + { + "Arn": "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:3", + "CodeSize": 1048576, + "SigningProfileVersionArn": "arn:aws:signer:us-east-1:123456789012:/signing-profiles/MyProfile" + } + ], + "State": "Active", + "LastUpdateStatus": "Successful", + "PackageType": "Zip", + "Architectures": ["arm64"], + "EphemeralStorage": { + "Size": 1024 + }, + "LoggingConfig": { + "LogFormat": "JSON", + "LogGroup": "/aws/lambda/benchmark-function" + } +} diff --git a/test/sdk-benchmarks/src/main/resources/fixtures/rest-xml-protocol/create-distribution-response.xml b/test/sdk-benchmarks/src/main/resources/fixtures/rest-xml-protocol/create-distribution-response.xml new file mode 100644 index 000000000000..1c88743e9b15 --- /dev/null +++ b/test/sdk-benchmarks/src/main/resources/fixtures/rest-xml-protocol/create-distribution-response.xml @@ -0,0 +1,209 @@ + + + EDFDVBD6EXAMPLE + arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE + Deployed + 2024-01-15T10:30:00Z + 0 + d111111abcdef8.cloudfront.net + + false + 0 + + + false + 0 + + + benchmark-ref-2024 + + 2 + + www.example.com + cdn.example.com + + + index.html + + 2 + + + myS3Origin + mybucket.s3.amazonaws.com + /production + + 1 + + + X-Custom-Header + benchmark-value + + + + + origin-access-identity/cloudfront/E127EXAMPLE51Z + + 3 + 10 + + true + us-east-1 + + + + myCustomOrigin + api.example.com + + + 0 + + + 80 + 443 + https-only + + 1 + + TLSv1.2 + + + 30 + 5 + + 3 + 10 + + + + + myS3Origin + + false + 0 + + + false + 0 + + redirect-to-https + + 3 + + GET + HEAD + OPTIONS + + + 2 + + GET + HEAD + + + + false + true + + 0 + + + 0 + + + 658327ea-f89d-4fab-a63d-7e88639e58f6 + + + 1 + + + /api/* + myCustomOrigin + + false + 0 + + + false + 0 + + https-only + + 7 + + GET + HEAD + OPTIONS + PUT + POST + PATCH + DELETE + + + 2 + + GET + HEAD + + + + false + true + + 0 + + + 0 + + + 4135ea2d-6df8-44a3-9df3-4b5a84be39ad + 88a5eaf4-2fd4-4709-b370-b4c650ea3fcf + + + + + 2 + + + 404 + /errors/404.html + 404 + 300 + + + 500 + /errors/500.html + 500 + 60 + + + + Benchmark distribution + + true + false + mylogs.s3.amazonaws.com + cf-logs/ + + PriceClass_100 + true + + arn:aws:acm:us-east-1:123456789012:certificate/abcd-1234 + sni-only + TLSv1.2_2021 + + + + whitelist + 3 + + US + CA + GB + + + + + http2 + true + +