Skip to content

Commit

Permalink
Add benchmark for DynamoDB serialization/deserialization (#507)
Browse files Browse the repository at this point in the history
* Add benchmark for DynamoDB serialization/deserialization

* CR feedback

* Remove async from benches and add benches to CI

* Update cargo check command in CI
  • Loading branch information
jdisanti authored Jun 17, 2021
1 parent 6482f0f commit 1fd6e97
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ jobs:
name: aws-sdk-${{ env.name }}-${{ github.sha }}
path: aws-sdk
- name: Cargo Check
run: cargo check
run: cargo check --lib --tests --benches
working-directory: aws-sdk
env:
RUSTFLAGS: -D warnings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import software.amazon.smithy.rust.codegen.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsSection
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.letIf

val TestedServices = setOf("aws-sdk-kms", "aws-sdk-dynamodb", "aws-sdk-qldbsession")
import java.nio.file.Files
import java.nio.file.Paths

class IntegrationTestDecorator : RustCodegenDecorator {
override val name: String = "IntegrationTest"
Expand All @@ -25,20 +24,42 @@ class IntegrationTestDecorator : RustCodegenDecorator {
override fun libRsCustomizations(
protocolConfig: ProtocolConfig,
baseCustomizations: List<LibRsCustomization>
): List<LibRsCustomization> = baseCustomizations.letIf(TestedServices.contains(protocolConfig.moduleName)) {
it + IntegrationTestDependencies(protocolConfig.runtimeConfig)
): List<LibRsCustomization> {
val integrationTestPath = Paths.get("aws/sdk/integration-tests")
check(Files.exists(integrationTestPath)) {
"IntegrationTestDecorator expects to be run from the smithy-rs package root"
}

val testPackagePath = integrationTestPath.resolve(protocolConfig.moduleName.substring("aws-sdk-".length))
return if (Files.exists(testPackagePath) && Files.exists(testPackagePath.resolve("Cargo.toml"))) {
val hasTests = Files.exists(testPackagePath.resolve("tests"))
val hasBenches = Files.exists(testPackagePath.resolve("benches"))
baseCustomizations + IntegrationTestDependencies(protocolConfig.runtimeConfig, hasTests, hasBenches)
} else {
baseCustomizations
}
}
}

class IntegrationTestDependencies(private val runtimeConfig: RuntimeConfig) : LibRsCustomization() {
class IntegrationTestDependencies(
private val runtimeConfig: RuntimeConfig,
private val hasTests: Boolean,
private val hasBenches: Boolean,
) : LibRsCustomization() {
override fun section(section: LibRsSection) = when (section) {
LibRsSection.Body -> writable {
addDependency(runtimeConfig.awsHyper().copy(scope = DependencyScope.Dev))
addDependency(Tokio)
if (hasTests) {
addDependency(runtimeConfig.awsHyper().copy(scope = DependencyScope.Dev))
addDependency(Tokio)
}
if (hasBenches) {
addDependency(Criterion)
}
}
else -> emptySection
}
}

val Criterion = CargoDependency("criterion", CratesIo("0.3"), scope = DependencyScope.Dev)
val Tokio = CargoDependency("tokio", CratesIo("1"), features = listOf("macros", "test-util"), scope = DependencyScope.Dev)
fun RuntimeConfig.awsHyper() = awsRuntimeDependency("aws-hyper", features = listOf("test-util"))
7 changes: 6 additions & 1 deletion aws/sdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ task("relocateServices") {
from(projectDir.resolve("integration-tests/${it.module}/tests"))
into(sdkOutputDir.resolve(it.module).resolve("tests"))
}

copy {
from(projectDir.resolve("integration-tests/${it.module}/benches"))
into(sdkOutputDir.resolve(it.module).resolve("benches"))
}
}
}
outputs.upToDateWhen { false }
Expand Down Expand Up @@ -240,7 +245,7 @@ tasks.register<Exec>("cargoCheck") {
workingDir(sdkOutputDir)
// disallow warnings
environment("RUSTFLAGS", "-D warnings")
commandLine("cargo", "check")
commandLine("cargo", "check", "--lib", "--tests", "--benches")
dependsOn("assemble")
}

Expand Down
22 changes: 16 additions & 6 deletions aws/sdk/integration-tests/dynamodb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@
[package]
name = "dynamo-tests"
version = "0.1.0"
authors = ["Russell Cohen <rcoh@amazon.com>"]
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Russell Cohen <rcoh@amazon.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aws-auth = { path = "../../build/aws-sdk/aws-auth" }
aws-http = { path = "../../build/aws-sdk/aws-http" }
aws-hyper = { path = "../../build/aws-sdk/aws-hyper", features = ["test-util"] }
aws-sdk-dynamodb = { path = "../../build/aws-sdk/dynamodb" }
smithy-http = { path = "../../build/aws-sdk/smithy-http" }
smithy-types = { path = "../../build/aws-sdk/smithy-types" }
bytes = "1"
criterion = { version = "0.3.4" }
http = "0.2.4"
serde_json = "1"
aws-hyper = { path = "../../build/aws-sdk/aws-hyper", features = ["test-util"] }
aws-auth = { path = "../../build/aws-sdk/aws-auth" }
aws-http = { path = "../../build/aws-sdk/aws-http" }
smithy-http = { path = "../../build/aws-sdk/smithy-http" }
smithy-types = { path = "../../build/aws-sdk/smithy-types" }
tokio = { version = "1", features = ["full", "test-util"]}
tracing-subscriber = "0.2.16"

[[bench]]
name = "deserialization_bench"
harness = false

[[bench]]
name = "serialization_bench"
harness = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

use aws_sdk_dynamodb::operation::Query;
use bytes::Bytes;
use criterion::{criterion_group, criterion_main, Criterion};
use smithy_http::body::SdkBody;
use smithy_http::response::ParseHttpResponse;

fn do_bench() {
let response = http::Response::builder()
.header("server", "Server")
.header("date", "Mon, 08 Mar 2021 15:51:23 GMT")
.header("content-type", "application/x-amz-json-1.0")
.header("content-length", "1231")
.header("connection", "keep-alive")
.header("x-amzn-requestid", "A5FGSJ9ET4OKB8183S9M47RQQBVV4KQNSO5AEMVJF66Q9ASUAAJG")
.header("x-amz-crc32", "624725176")
.status(http::StatusCode::from_u16(200).unwrap())
.body(Bytes::copy_from_slice(br#"{"Count":2,"Items":[{"year":{"N":"2013"},"info":{"M":{"actors":{"L":[{"S":"Daniel Bruhl"},{"S":"Chris Hemsworth"},{"S":"Olivia Wilde"}]},"plot":{"S":"A re-creation of the merciless 1970s rivalry between Formula One rivals James Hunt and Niki Lauda."},"release_date":{"S":"2013-09-02T00:00:00Z"},"image_url":{"S":"http://ia.media-imdb.com/images/M/MV5BMTQyMDE0MTY0OV5BMl5BanBnXkFtZTcwMjI2OTI0OQ@@._V1_SX400_.jpg"},"genres":{"L":[{"S":"Action"},{"S":"Biography"},{"S":"Drama"},{"S":"Sport"}]},"directors":{"L":[{"S":"Ron Howard"}]},"rating":{"N":"8.3"},"rank":{"N":"2"},"running_time_secs":{"N":"7380"}}},"title":{"S":"Rush"}},{"year":{"N":"2013"},"info":{"M":{"actors":{"L":[{"S":"David Matthewman"},{"S":"Ann Thomas"},{"S":"Jonathan G. Neff"}]},"release_date":{"S":"2013-01-18T00:00:00Z"},"plot":{"S":"A rock band plays their music at high volumes, annoying the neighbors."},"genres":{"L":[{"S":"Comedy"},{"S":"Drama"}]},"image_url":{"S":"http://ia.media-imdb.com/images/N/O9ERWAU7FS797AJ7LU8HN09AMUP908RLlo5JF90EWR7LJKQ7@@._V1_SX400_.jpg"},"directors":{"L":[{"S":"Alice Smith"},{"S":"Bob Jones"}]},"rating":{"N":"6.2"},"rank":{"N":"11"},"running_time_secs":{"N":"5215"}}},"title":{"S":"Turn It Down, Or Else!"}}],"ScannedCount":2}"#))
.unwrap();

let parser = Query::new();
let output = <Query as ParseHttpResponse<SdkBody>>::parse_loaded(&parser, &response).unwrap();
assert_eq!(2, output.count);
}

fn bench_group(c: &mut Criterion) {
c.bench_function("deserialization_bench", |b| b.iter(do_bench));
}

criterion_group!(benches, bench_group);
criterion_main!(benches);
74 changes: 74 additions & 0 deletions aws/sdk/integration-tests/dynamodb/benches/serialization_bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

use aws_sdk_dynamodb::input::PutItemInput;
use aws_sdk_dynamodb::model::AttributeValue;
use aws_sdk_dynamodb::Config;
use criterion::{criterion_group, criterion_main, Criterion};

macro_rules! attr_s {
($str_val:expr) => {
AttributeValue::S($str_val.into())
};
}
macro_rules! attr_n {
($str_val:expr) => {
AttributeValue::N($str_val.into())
};
}
macro_rules! attr_list {
( $($attr_val:expr),* ) => {
AttributeValue::L(vec![$($attr_val),*])
}
}
macro_rules! attr_obj {
{ $($str_val:expr => $attr_val:expr),* } => {
AttributeValue::M(
vec![
$(($str_val.to_string(), $attr_val)),*
].into_iter().collect()
)
};
}

fn do_bench(config: &Config, input: &PutItemInput) {
let operation = input
.make_operation(&config)
.expect("operation failed to build");
let (http_request, _parts) = operation.into_request_response().0.into_parts();
let body = http_request.body().bytes().unwrap();
assert_eq!(body[0], b'{');
}

fn bench_group(c: &mut Criterion) {
c.bench_function("serialization_bench", |b| {
let config = Config::builder().build();
let input = PutItemInput::builder()
.table_name("Movies-5")
.set_item(Some(
attr_obj! {
"year" => attr_n!("2013"),
"title" => attr_s!("Turn It Down, Or Else!"),
"info" => attr_obj! {
"directors" => attr_list![attr_s!("Alice Smith"), attr_s!("Bob Jones")],
"release_date" => attr_s!("2013-01-18T00:00:00Z"),
"rating" => attr_n!("6.2"),
"genres" => attr_list!(attr_s!("Comedy"), attr_s!("Drama")),
"image_url" => attr_s!("http://ia.media-imdb.com/images/N/O9ERWAU7FS797AJ7LU8HN09AMUP908RLlo5JF90EWR7LJKQ7@@._V1_SX400_.jpg"),
"plot" => attr_s!("A rock band plays their music at high volumes, annoying the neighbors."),
"rank" => attr_n!("11"),
"running_time_secs" => attr_n!("5215"),
"actors" => attr_list!(attr_s!("David Matthewman"), attr_s!("Ann Thomas"), attr_s!("Jonathan G. Neff"))
}
}.as_m().unwrap().clone(),
))
.build()
.expect("valid input");
b.iter(|| do_bench(&config, &input))
});
}

criterion_group!(benches, bench_group);
criterion_main!(benches);

0 comments on commit 1fd6e97

Please sign in to comment.