Skip to content

Commit 8113a10

Browse files
committed
DynamoDb Enhanced perf testing
Tests overhead of GET and PUT item over the low level client, as well as performance of those operations compared to the V1 mapper.
1 parent 22505f5 commit 8113a10

File tree

11 files changed

+2548
-1
lines changed

11 files changed

+2548
-1
lines changed

buildspecs/benchmarks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ phases:
1010
- mvn install -P quick -pl :sdk-benchmarks --am
1111
- mvn install -pl :bom-internal
1212
- cd test/sdk-benchmarks
13-
- mvn exec:exec
13+
- java -jar target/benchmarks.jar -f 1 -wi 8 -i 8 software.amazon.awssdk.benchmark.enhanced.dynamodb

test/sdk-benchmarks/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,16 @@
134134
<artifactId>netty-nio-client</artifactId>
135135
<version>${awsjavasdk.version}</version>
136136
</dependency>
137+
<dependency>
138+
<groupId>software.amazon.awssdk</groupId>
139+
<artifactId>dynamodb-enhanced</artifactId>
140+
<version>${awsjavasdk.version}-PREVIEW</version>
141+
</dependency>
142+
<dependency>
143+
<groupId>com.amazonaws</groupId>
144+
<artifactId>aws-java-sdk-dynamodb</artifactId>
145+
<version>1.11.748</version>
146+
</dependency>
137147
<dependency>
138148
<groupId>io.netty</groupId>
139149
<artifactId>netty-tcnative-boringssl-static</artifactId>

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import software.amazon.awssdk.benchmark.apicall.protocol.XmlProtocolBenchmark;
3737
import software.amazon.awssdk.benchmark.coldstart.V2DefaultClientCreationBenchmark;
3838
import software.amazon.awssdk.benchmark.coldstart.V2OptimizedClientCreationBenchmark;
39+
import software.amazon.awssdk.benchmark.enhanced.dynamodb.EnhancedClientGetOverheadBenchmark;
40+
import software.amazon.awssdk.benchmark.enhanced.dynamodb.EnhancedClientPutOverheadBenchmark;
41+
import software.amazon.awssdk.benchmark.enhanced.dynamodb.V1MapperComparisonBenchmark;
3942
import software.amazon.awssdk.utils.Logger;
4043

4144

@@ -58,6 +61,12 @@ public class BenchmarkRunner {
5861
V2OptimizedClientCreationBenchmark.class.getSimpleName(),
5962
V2DefaultClientCreationBenchmark.class.getSimpleName());
6063

64+
private static final List<String> MAPPER_BENCHMARKS = Arrays.asList(
65+
EnhancedClientGetOverheadBenchmark.class.getSimpleName(),
66+
EnhancedClientPutOverheadBenchmark.class.getSimpleName(),
67+
V1MapperComparisonBenchmark.class.getSimpleName()
68+
);
69+
6170
private static final Logger log = Logger.loggerFor(BenchmarkRunner.class);
6271

6372
private final List<String> benchmarksToRun;
@@ -74,6 +83,7 @@ public static void main(String... args) throws RunnerException, JsonProcessingEx
7483
benchmarksToRun.addAll(ASYNC_BENCHMARKS);
7584
benchmarksToRun.addAll(PROTOCOL_BENCHMARKS);
7685
benchmarksToRun.addAll(COLD_START_BENCHMARKS);
86+
benchmarksToRun.addAll(MAPPER_BENCHMARKS);
7787

7888
BenchmarkRunner runner = new BenchmarkRunner(benchmarksToRun);
7989

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.enhanced.dynamodb;
17+
18+
import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT;
19+
20+
import java.io.IOException;
21+
import java.io.UncheckedIOException;
22+
import java.net.URI;
23+
import java.util.Map;
24+
import org.openjdk.jmh.annotations.Benchmark;
25+
import org.openjdk.jmh.annotations.BenchmarkMode;
26+
import org.openjdk.jmh.annotations.Fork;
27+
import org.openjdk.jmh.annotations.Measurement;
28+
import org.openjdk.jmh.annotations.Mode;
29+
import org.openjdk.jmh.annotations.Param;
30+
import org.openjdk.jmh.annotations.Scope;
31+
import org.openjdk.jmh.annotations.Setup;
32+
import org.openjdk.jmh.annotations.State;
33+
import org.openjdk.jmh.annotations.Warmup;
34+
import org.openjdk.jmh.infra.Blackhole;
35+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
36+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
37+
import software.amazon.awssdk.benchmark.utils.MockHttpClient;
38+
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
39+
import software.amazon.awssdk.core.interceptor.Context;
40+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
41+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
42+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
43+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
44+
import software.amazon.awssdk.enhanced.dynamodb.Key;
45+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
46+
import software.amazon.awssdk.protocols.json.AwsJsonProtocol;
47+
import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory;
48+
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
49+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
50+
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
51+
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
52+
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
53+
import software.amazon.awssdk.services.dynamodb.transform.PutItemRequestMarshaller;
54+
import software.amazon.awssdk.utils.IoUtils;
55+
56+
@BenchmarkMode(Mode.Throughput)
57+
@Warmup(iterations = 5)
58+
@Measurement(iterations = 5)
59+
@Fork(2)
60+
@State(Scope.Benchmark)
61+
public class EnhancedClientGetOverheadBenchmark {
62+
private static final AwsJsonProtocolFactory JSON_PROTOCOL_FACTORY = AwsJsonProtocolFactory
63+
.builder()
64+
.clientConfiguration(SdkClientConfiguration.builder()
65+
.option(ENDPOINT, URI.create("https://dynamodb.amazonaws.com"))
66+
.build())
67+
.defaultServiceExceptionSupplier(DynamoDbException::builder)
68+
.protocol(AwsJsonProtocol.AWS_JSON)
69+
.protocolVersion("1.0")
70+
.build();
71+
72+
private static final PutItemRequestMarshaller PUT_ITEM_REQUEST_MARSHALLER =
73+
new PutItemRequestMarshaller(JSON_PROTOCOL_FACTORY);
74+
75+
private static final V2ItemFactory ITEM_FACTORY = new V2ItemFactory();
76+
77+
private final Key testKey = Key.builder().partitionValue("key").build();
78+
79+
80+
@Benchmark
81+
public Object llGet(TestState s) {
82+
return s.dynamoDb.getItem(GetItemRequest.builder().build());
83+
}
84+
85+
@Benchmark
86+
public Object enhGet(TestState s) {
87+
return s.table.getItem(testKey);
88+
}
89+
90+
@State(Scope.Benchmark)
91+
public static class TestState {
92+
private DynamoDbClient dynamoDb;
93+
94+
@Param({"TINY", "SMALL", "HUGE", "HUGE_FLAT"})
95+
private TestItem testItem;
96+
97+
private DynamoDbTable table;
98+
99+
@Setup
100+
public void setup(Blackhole bh) {
101+
dynamoDb = DynamoDbClient.builder()
102+
.credentialsProvider(StaticCredentialsProvider.create(
103+
AwsBasicCredentials.create("akid", "skid")))
104+
.httpClient(new MockHttpClient(testItem.responseContent, "{}"))
105+
.overrideConfiguration(o -> o.addExecutionInterceptor(new ExecutionInterceptor() {
106+
@Override
107+
public void afterUnmarshalling(Context.AfterUnmarshalling context,
108+
ExecutionAttributes executionAttributes) {
109+
bh.consume(context);
110+
bh.consume(executionAttributes);
111+
}
112+
}))
113+
.build();
114+
115+
DynamoDbEnhancedClient ddbEnh = DynamoDbEnhancedClient.builder()
116+
.dynamoDbClient(dynamoDb)
117+
.build();
118+
119+
table = ddbEnh.table(testItem.name(), testItem.tableSchema);
120+
}
121+
}
122+
123+
public enum TestItem {
124+
TINY(marshall(ITEM_FACTORY.tiny()), V2ItemFactory.TINY_BEAN_TABLE_SCHEMA),
125+
SMALL(marshall(ITEM_FACTORY.small()), V2ItemFactory.SMALL_BEAN_TABLE_SCHEMA),
126+
HUGE(marshall(ITEM_FACTORY.huge()), V2ItemFactory.HUGE_BEAN_TABLE_SCHEMA),
127+
HUGE_FLAT(marshall(ITEM_FACTORY.hugeFlat()), V2ItemFactory.HUGE_BEAN_FLAT_TABLE_SCHEMA)
128+
;
129+
130+
private String responseContent;
131+
private TableSchema tableSchema;
132+
133+
TestItem(String responseContent, TableSchema tableSchema) {
134+
this.responseContent = responseContent;
135+
this.tableSchema = tableSchema;
136+
}
137+
}
138+
139+
private static String marshall(Map<String, AttributeValue> item) {
140+
return PUT_ITEM_REQUEST_MARSHALLER.marshall(PutItemRequest.builder().item(item).build())
141+
.contentStreamProvider().map(cs -> {
142+
try {
143+
return IoUtils.toUtf8String(cs.newStream());
144+
} catch (IOException e) {
145+
throw new UncheckedIOException(e);
146+
}
147+
}).orElse(null);
148+
}
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.enhanced.dynamodb;
17+
18+
import java.util.Map;
19+
import org.openjdk.jmh.annotations.Benchmark;
20+
import org.openjdk.jmh.annotations.BenchmarkMode;
21+
import org.openjdk.jmh.annotations.Fork;
22+
import org.openjdk.jmh.annotations.Measurement;
23+
import org.openjdk.jmh.annotations.Mode;
24+
import org.openjdk.jmh.annotations.Param;
25+
import org.openjdk.jmh.annotations.Scope;
26+
import org.openjdk.jmh.annotations.Setup;
27+
import org.openjdk.jmh.annotations.State;
28+
import org.openjdk.jmh.annotations.Warmup;
29+
import org.openjdk.jmh.infra.Blackhole;
30+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
31+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
32+
import software.amazon.awssdk.benchmark.utils.MockHttpClient;
33+
import software.amazon.awssdk.core.interceptor.Context;
34+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
35+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
36+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
37+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
38+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
39+
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
40+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
41+
42+
@BenchmarkMode(Mode.Throughput)
43+
@Warmup(iterations = 5)
44+
@Measurement(iterations = 5)
45+
@Fork(2)
46+
@State(Scope.Benchmark)
47+
public class EnhancedClientPutOverheadBenchmark {
48+
@Benchmark
49+
public void llPut(TestState s) {
50+
s.ddb.putItem(r -> r.item(s.testItem.av));
51+
}
52+
53+
@Benchmark
54+
public void enhPut(TestState s) {
55+
s.enhTable.putItem(s.testItem.bean);
56+
}
57+
58+
@State(Scope.Benchmark)
59+
public static class TestState {
60+
@Param({"TINY", "SMALL", "HUGE", "HUGE_FLAT"})
61+
private TestItem testItem;
62+
private DynamoDbClient ddb;
63+
64+
private DynamoDbTable enhTable;
65+
66+
@Setup
67+
public void setup(Blackhole bh) {
68+
ddb = DynamoDbClient.builder()
69+
.credentialsProvider(StaticCredentialsProvider.create(
70+
AwsBasicCredentials.create("akid", "skid")))
71+
.httpClient(new MockHttpClient("{}", "{}"))
72+
.overrideConfiguration(c -> c.addExecutionInterceptor(new ExecutionInterceptor() {
73+
@Override
74+
public void afterUnmarshalling(Context.AfterUnmarshalling context,
75+
ExecutionAttributes executionAttributes) {
76+
bh.consume(context);
77+
bh.consume(executionAttributes);
78+
}
79+
}))
80+
.build();
81+
82+
DynamoDbEnhancedClient ddbEnh = DynamoDbEnhancedClient.builder()
83+
.dynamoDbClient(ddb)
84+
.build();
85+
86+
enhTable = ddbEnh.table(testItem.name(), testItem.tableSchema);
87+
}
88+
}
89+
90+
public enum TestItem {
91+
TINY,
92+
SMALL,
93+
HUGE,
94+
HUGE_FLAT
95+
;
96+
97+
private static final V2ItemFactory FACTORY = new V2ItemFactory();
98+
99+
private Map<String, AttributeValue> av;
100+
101+
private TableSchema tableSchema;
102+
private Object bean;
103+
104+
static {
105+
TINY.av = FACTORY.tiny();
106+
TINY.tableSchema = V2ItemFactory.TINY_BEAN_TABLE_SCHEMA;
107+
TINY.bean = FACTORY.tinyBean();
108+
109+
SMALL.av = FACTORY.small();
110+
SMALL.tableSchema = V2ItemFactory.SMALL_BEAN_TABLE_SCHEMA;
111+
SMALL.bean = FACTORY.smallBean();
112+
113+
HUGE.av = FACTORY.huge();
114+
HUGE.tableSchema = V2ItemFactory.HUGE_BEAN_TABLE_SCHEMA;
115+
HUGE.bean = FACTORY.hugeBean();
116+
117+
HUGE_FLAT.av = FACTORY.hugeFlat();
118+
HUGE_FLAT.tableSchema = V2ItemFactory.HUGE_BEAN_FLAT_TABLE_SCHEMA;
119+
HUGE_FLAT.bean = FACTORY.hugeBeanFlat();
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)