Skip to content

Commit cf8a4c2

Browse files
authored
Add DynamoDB service performance test (#3472)
* add DynamoDB service performance test * address issues from code review for DynamoDB performance test * update performance test setup Outcome to use NoResult
1 parent dc68940 commit cf8a4c2

File tree

11 files changed

+494
-82
lines changed

11 files changed

+494
-82
lines changed

tests/performance-tests/include/performance-tests/PerformanceTestBase.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
#pragma once
77

8+
#include <aws/core/NoResult.h>
9+
#include <aws/core/utils/Outcome.h>
10+
#include <aws/core/utils/memory/stl/AWSString.h>
11+
812
namespace PerformanceTest {
913

1014
/**
@@ -16,8 +20,9 @@ class PerformanceTestBase {
1620

1721
/**
1822
* Initialize resources for the test.
23+
* @return Outcome indicating success or failure with error details
1924
*/
20-
virtual void Setup() = 0;
25+
virtual Aws::Utils::Outcome<Aws::NoResult, Aws::String> Setup() = 0;
2126

2227
/**
2328
* Run the performance test operations.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
#pragma once
7+
8+
#include <aws/core/NoResult.h>
9+
#include <aws/core/client/ClientConfiguration.h>
10+
#include <aws/core/utils/Outcome.h>
11+
#include <aws/core/utils/memory/AWSMemory.h>
12+
#include <aws/core/utils/memory/stl/AWSString.h>
13+
#include <aws/dynamodb/DynamoDBClient.h>
14+
#include <performance-tests/PerformanceTestBase.h>
15+
#include <performance-tests/services/dynamodb/DynamoDBTestConfig.h>
16+
17+
namespace PerformanceTest {
18+
namespace Services {
19+
namespace DynamoDB {
20+
21+
/**
22+
* DynamoDB performance test implementation.
23+
* Tests PutItem and GetItem operations with different payload sizes.
24+
*/
25+
class DynamoDBPerformanceTest : public PerformanceTestBase {
26+
public:
27+
DynamoDBPerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, const TestConfig::TestCase& testConfig,
28+
int iterations = 10);
29+
30+
Aws::Utils::Outcome<Aws::NoResult, Aws::String> Setup() override;
31+
void Run() override;
32+
void TearDown() override;
33+
34+
private:
35+
const Aws::UniquePtr<Aws::DynamoDB::DynamoDBClient> m_dynamodb;
36+
const TestConfig::TestCase m_testConfig;
37+
const int m_iterations;
38+
const Aws::String m_tableName;
39+
};
40+
41+
} // namespace DynamoDB
42+
} // namespace Services
43+
} // namespace PerformanceTest
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
#pragma once
7+
8+
#include <aws/core/utils/memory/stl/AWSString.h>
9+
10+
#include <array>
11+
#include <cstddef>
12+
13+
namespace PerformanceTest {
14+
namespace Services {
15+
namespace DynamoDB {
16+
namespace TestConfig {
17+
18+
/**
19+
* Payload sizes for DynamoDB performance tests.
20+
*/
21+
enum class PayloadSize { K8, K64, K392 };
22+
23+
/**
24+
* Configuration for DynamoDB performance test cases.
25+
*/
26+
struct TestCase {
27+
PayloadSize payloadSize;
28+
};
29+
30+
/**
31+
* Get the payload size in bytes for a given PayloadSize enum.
32+
* @param payloadSize The PayloadSize enum value
33+
* @return Size in bytes
34+
*/
35+
size_t GetPayloadSizeInBytes(PayloadSize payloadSize);
36+
37+
/**
38+
* Get the string label for a given PayloadSize enum.
39+
* @param payloadSize The PayloadSize enum value
40+
* @return String label (e.g., "8KB", "64KB", "392KB")
41+
*/
42+
Aws::String GetPayloadSizeLabel(PayloadSize payloadSize);
43+
44+
/** Operations tested in DynamoDB performance tests. */
45+
extern const std::array<const char*, 2> TestOperations;
46+
47+
/** Array of all test case combinations. */
48+
extern const std::array<TestCase, 3> TestMatrix;
49+
50+
/** Output filename for test results. */
51+
extern const char* OutputFilename;
52+
53+
} // namespace TestConfig
54+
} // namespace DynamoDB
55+
} // namespace Services
56+
} // namespace PerformanceTest

tests/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,38 @@
55

66
#pragma once
77

8+
#include <aws/core/NoResult.h>
9+
#include <aws/core/client/ClientConfiguration.h>
10+
#include <aws/core/utils/Outcome.h>
811
#include <aws/core/utils/memory/AWSMemory.h>
912
#include <aws/core/utils/memory/stl/AWSString.h>
1013
#include <aws/s3/S3Client.h>
1114
#include <performance-tests/PerformanceTestBase.h>
12-
13-
#include <cstddef>
15+
#include <performance-tests/services/s3/S3TestConfig.h>
1416

1517
namespace PerformanceTest {
1618
namespace Services {
1719
namespace S3 {
18-
/**
19-
* Configuration for S3 performance test cases.
20-
*/
21-
struct TestCase {
22-
const char* sizeLabel;
23-
size_t sizeBytes;
24-
const char* bucketTypeLabel;
25-
};
2620

2721
/**
2822
* S3 performance test implementation.
2923
* Tests PutObject and GetObject operations with different payload sizes and bucket types.
3024
*/
3125
class S3PerformanceTest : public PerformanceTestBase {
3226
public:
33-
S3PerformanceTest(const Aws::String& region, const TestCase& config, const Aws::String& availabilityZoneId, int iterations = 10);
27+
S3PerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, const TestConfig::TestCase& testConfig, int iterations = 10,
28+
const Aws::String& availabilityZoneId = "");
3429

35-
void Setup() override;
36-
void TearDown() override;
30+
Aws::Utils::Outcome<Aws::NoResult, Aws::String> Setup() override;
3731
void Run() override;
32+
void TearDown() override;
3833

3934
private:
40-
const TestCase& m_config;
41-
const Aws::String m_region;
42-
const Aws::String m_availabilityZoneId;
35+
const Aws::UniquePtr<Aws::S3::S3Client> m_s3;
36+
const TestConfig::TestCase m_testConfig;
4337
const int m_iterations;
44-
Aws::UniquePtr<Aws::S3::S3Client> m_s3;
45-
Aws::String m_bucketName;
38+
const Aws::String m_bucketName;
39+
const Aws::String m_availabilityZoneId;
4640
};
4741

4842
} // namespace S3

tests/performance-tests/include/performance-tests/services/s3/S3TestConfig.h

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,64 @@
55

66
#pragma once
77

8-
#include <performance-tests/services/s3/S3PerformanceTest.h>
8+
#include <aws/core/utils/memory/stl/AWSString.h>
99

1010
#include <array>
11+
#include <cstddef>
1112

1213
namespace PerformanceTest {
1314
namespace Services {
1415
namespace S3 {
1516
namespace TestConfig {
17+
18+
/**
19+
* Payload sizes for S3 performance tests.
20+
*/
21+
enum class PayloadSize { K8, K64, M1 };
22+
23+
/**
24+
* Bucket types for S3 performance tests.
25+
*/
26+
enum class BucketType { Standard, Express };
27+
28+
/**
29+
* Configuration for S3 performance test cases.
30+
*/
31+
struct TestCase {
32+
PayloadSize payloadSize;
33+
BucketType bucketType;
34+
};
35+
36+
/**
37+
* Get the payload size in bytes for a given PayloadSize enum.
38+
* @param payloadSize The PayloadSize enum value
39+
* @return Size in bytes
40+
*/
41+
size_t GetPayloadSizeInBytes(PayloadSize payloadSize);
42+
43+
/**
44+
* Get the string label for a given PayloadSize enum.
45+
* @param payloadSize The PayloadSize enum value
46+
* @return String label (e.g., "8KB", "64KB", "1MB")
47+
*/
48+
Aws::String GetPayloadSizeLabel(PayloadSize payloadSize);
49+
50+
/**
51+
* Get the string label for a given BucketType enum.
52+
* @param bucketType The BucketType enum value
53+
* @return String label (e.g., "s3-standard", "s3-express")
54+
*/
55+
Aws::String GetBucketTypeLabel(BucketType bucketType);
56+
57+
/** Operations tested in S3 performance tests. */
1658
extern const std::array<const char*, 2> TestOperations;
59+
60+
/** Array of all test case combinations. */
1761
extern const std::array<TestCase, 6> TestMatrix;
62+
63+
/** Output filename for test results. */
1864
extern const char* OutputFilename;
65+
1966
} // namespace TestConfig
2067
} // namespace S3
2168
} // namespace Services
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
#include <aws/core/AmazonWebServiceResult.h>
7+
#include <aws/core/NoResult.h>
8+
#include <aws/core/client/ClientConfiguration.h>
9+
#include <aws/core/utils/Outcome.h>
10+
#include <aws/core/utils/logging/LogMacros.h>
11+
#include <aws/core/utils/memory/AWSMemory.h>
12+
#include <aws/core/utils/memory/stl/AWSString.h>
13+
#include <aws/dynamodb/DynamoDBClient.h>
14+
#include <aws/dynamodb/DynamoDBServiceClientModel.h>
15+
#include <aws/dynamodb/model/AttributeDefinition.h>
16+
#include <aws/dynamodb/model/AttributeValue.h>
17+
#include <aws/dynamodb/model/BillingMode.h>
18+
#include <aws/dynamodb/model/CreateTableRequest.h>
19+
#include <aws/dynamodb/model/DeleteTableRequest.h>
20+
#include <aws/dynamodb/model/DescribeTableRequest.h>
21+
#include <aws/dynamodb/model/GetItemRequest.h>
22+
#include <aws/dynamodb/model/KeySchemaElement.h>
23+
#include <aws/dynamodb/model/KeyType.h>
24+
#include <aws/dynamodb/model/PutItemRequest.h>
25+
#include <aws/dynamodb/model/ScalarAttributeType.h>
26+
#include <aws/dynamodb/model/TableStatus.h>
27+
#include <performance-tests/Utils.h>
28+
#include <performance-tests/services/dynamodb/DynamoDBPerformanceTest.h>
29+
#include <performance-tests/services/dynamodb/DynamoDBTestConfig.h>
30+
31+
#include <cassert>
32+
#include <chrono>
33+
#include <thread>
34+
35+
PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::DynamoDBPerformanceTest(const Aws::Client::ClientConfiguration& clientConfig,
36+
const TestConfig::TestCase& testConfig,
37+
int iterations)
38+
: m_dynamodb(Aws::MakeUnique<Aws::DynamoDB::DynamoDBClient>("DynamoDBPerformanceTest", clientConfig)),
39+
m_testConfig(testConfig),
40+
m_iterations(iterations),
41+
m_tableName("perf-table-" + PerformanceTest::Utils::GenerateUniqueId()) {
42+
assert(m_dynamodb && "DynamoDB client not initialized");
43+
}
44+
45+
Aws::Utils::Outcome<Aws::NoResult, Aws::String> PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Setup() {
46+
Aws::DynamoDB::Model::CreateTableRequest createTableRequest;
47+
createTableRequest.SetTableName(m_tableName);
48+
49+
Aws::DynamoDB::Model::AttributeDefinition hashKey;
50+
hashKey.SetAttributeName("data");
51+
hashKey.SetAttributeType(Aws::DynamoDB::Model::ScalarAttributeType::S);
52+
createTableRequest.AddAttributeDefinitions(hashKey);
53+
54+
Aws::DynamoDB::Model::KeySchemaElement keySchema;
55+
keySchema.WithAttributeName("data").WithKeyType(Aws::DynamoDB::Model::KeyType::HASH);
56+
createTableRequest.AddKeySchema(keySchema);
57+
58+
Aws::DynamoDB::Model::BillingMode const billingMode = Aws::DynamoDB::Model::BillingMode::PAY_PER_REQUEST;
59+
createTableRequest.SetBillingMode(billingMode);
60+
61+
auto createTableOutcome = m_dynamodb->CreateTable(createTableRequest);
62+
if (!createTableOutcome.IsSuccess()) {
63+
return "DynamoDB Setup() - CreateTable failed: " + createTableOutcome.GetError().GetMessage();
64+
}
65+
66+
// Wait for table to become active
67+
const int MAX_QUERIES = 20;
68+
Aws::DynamoDB::Model::DescribeTableRequest describeRequest;
69+
describeRequest.SetTableName(m_tableName);
70+
71+
int count = 0;
72+
while (count < MAX_QUERIES) {
73+
const Aws::DynamoDB::Model::DescribeTableOutcome& describeOutcome = m_dynamodb->DescribeTable(describeRequest);
74+
if (describeOutcome.IsSuccess()) {
75+
Aws::DynamoDB::Model::TableStatus const status = describeOutcome.GetResult().GetTable().GetTableStatus();
76+
if (Aws::DynamoDB::Model::TableStatus::ACTIVE == status) {
77+
break;
78+
}
79+
std::this_thread::sleep_for(std::chrono::seconds(1));
80+
} else {
81+
return "DynamoDB Setup() - DescribeTable failed: " + describeOutcome.GetError().GetMessage();
82+
}
83+
count++;
84+
}
85+
86+
if (count >= MAX_QUERIES) {
87+
return "DynamoDB Setup() - Table did not become active within timeout";
88+
}
89+
return Aws::NoResult();
90+
}
91+
92+
void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Run() {
93+
const auto payload = PerformanceTest::Utils::RandomString(TestConfig::GetPayloadSizeInBytes(m_testConfig.payloadSize));
94+
95+
// Run PutItem multiple times
96+
for (int i = 0; i < m_iterations; i++) {
97+
Aws::DynamoDB::Model::PutItemRequest putItemRequest;
98+
putItemRequest.SetTableName(m_tableName);
99+
putItemRequest.SetAdditionalCustomHeaderValue("test-dimension-size", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize));
100+
putItemRequest.AddItem("data", Aws::DynamoDB::Model::AttributeValue().SetS(payload));
101+
102+
auto putItemOutcome = m_dynamodb->PutItem(putItemRequest);
103+
if (!putItemOutcome.IsSuccess()) {
104+
AWS_LOG_ERROR("PerformanceTest", ("DynamoDB Run() - PutItem failed: " + putItemOutcome.GetError().GetMessage()).c_str());
105+
}
106+
}
107+
108+
// Run GetItem multiple times
109+
for (int i = 0; i < m_iterations; i++) {
110+
Aws::DynamoDB::Model::GetItemRequest getItemRequest;
111+
getItemRequest.SetTableName(m_tableName);
112+
getItemRequest.SetAdditionalCustomHeaderValue("test-dimension-size", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize));
113+
getItemRequest.AddKey("data", Aws::DynamoDB::Model::AttributeValue().SetS(payload));
114+
115+
auto getItemOutcome = m_dynamodb->GetItem(getItemRequest);
116+
if (!getItemOutcome.IsSuccess()) {
117+
AWS_LOG_ERROR("PerformanceTest", ("DynamoDB Run() - GetItem failed: " + getItemOutcome.GetError().GetMessage()).c_str());
118+
}
119+
}
120+
}
121+
122+
void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::TearDown() {
123+
Aws::DynamoDB::Model::DeleteTableRequest deleteTableRequest;
124+
deleteTableRequest.SetTableName(m_tableName);
125+
auto deleteTableOutcome = m_dynamodb->DeleteTable(deleteTableRequest);
126+
if (!deleteTableOutcome.IsSuccess()) {
127+
AWS_LOG_ERROR("PerformanceTest", ("DynamoDB TearDown() - DeleteTable failed: " + deleteTableOutcome.GetError().GetMessage()).c_str());
128+
}
129+
}

0 commit comments

Comments
 (0)