-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add s3 service performance tests #3470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Alan4506
wants to merge
3
commits into
main
Choose a base branch
from
s3-perf-test
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0. | ||
# | ||
|
||
add_project(performance-tests | ||
"A suite of AWS C++ SDK performance tests" | ||
aws-cpp-sdk-core | ||
aws-cpp-sdk-s3 | ||
aws-cpp-sdk-dynamodb | ||
) | ||
|
||
include(FetchContent) | ||
FetchContent_Declare( | ||
cxxopts | ||
GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git | ||
GIT_TAG v3.1.1 | ||
) | ||
FetchContent_MakeAvailable(cxxopts) | ||
|
||
function(add_service_test SERVICE SDK_LIB PERF_TEST_FILE) | ||
add_executable(${SERVICE}-performance-test | ||
src/services/${SERVICE}/main.cpp | ||
src/reporting/JsonReportingMetrics.cpp | ||
src/services/${SERVICE}/${PERF_TEST_FILE} | ||
) | ||
set_compiler_flags(${SERVICE}-performance-test) | ||
set_compiler_warnings(${SERVICE}-performance-test) | ||
target_include_directories(${SERVICE}-performance-test PRIVATE include) | ||
target_link_libraries(${SERVICE}-performance-test PRIVATE aws-cpp-sdk-core ${SDK_LIB} cxxopts::cxxopts) | ||
target_compile_options(${SERVICE}-performance-test PRIVATE -std=c++17 -fexceptions) | ||
endfunction() | ||
|
||
add_service_test(s3 aws-cpp-sdk-s3 S3PerformanceTest.cpp) | ||
add_service_test(dynamodb aws-cpp-sdk-dynamodb DynamoDBPerformanceTest.cpp) |
33 changes: 33 additions & 0 deletions
33
tests/performance-tests/include/performance-tests/PerformanceTestBase.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#pragma once | ||
|
||
namespace PerformanceTest { | ||
|
||
/** | ||
* Base class for all performance tests. | ||
*/ | ||
class PerformanceTestBase { | ||
public: | ||
virtual ~PerformanceTestBase() = default; | ||
|
||
/** | ||
* Initialize resources for the test. | ||
*/ | ||
virtual void Setup() = 0; | ||
|
||
/** | ||
* Run the performance test operations. | ||
*/ | ||
virtual void Run() = 0; | ||
|
||
/** | ||
* Clean up resources created during setup. | ||
*/ | ||
virtual void TearDown() = 0; | ||
}; | ||
|
||
} // namespace PerformanceTest |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <aws/core/utils/StringUtils.h> | ||
#include <aws/core/utils/UUID.h> | ||
#include <aws/core/utils/memory/stl/AWSString.h> | ||
|
||
#include <algorithm> | ||
#include <cstddef> | ||
#include <cstdlib> | ||
|
||
namespace PerformanceTest { | ||
namespace Utils { | ||
/** | ||
* Generate a random string of specified length. | ||
* @param length The desired length of the string | ||
* @return A random string containing lowercase letters and digits | ||
*/ | ||
static inline Aws::String RandomString(size_t length) { | ||
auto randchar = []() -> char { | ||
const char charset[] = | ||
"0123456789" | ||
"abcdefghijklmnopqrstuvwxyz"; | ||
const size_t max_index = (sizeof(charset) - 1); | ||
return charset[rand() % max_index]; | ||
}; | ||
Aws::String str(length, 0); | ||
std::generate_n(str.begin(), length, randchar); | ||
return str; | ||
} | ||
|
||
/** | ||
* Generate a unique identifier using UUID. | ||
* @return A 10-character lowercase UUID substring | ||
*/ | ||
static inline Aws::String GenerateUniqueId() { | ||
Aws::String const rawUUID = Aws::Utils::UUID::RandomUUID(); | ||
return Aws::Utils::StringUtils::ToLower(rawUUID.c_str()).substr(0, 10); | ||
} | ||
|
||
} // namespace Utils | ||
} // namespace PerformanceTest |
50 changes: 50 additions & 0 deletions
50
tests/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <aws/core/utils/memory/AWSMemory.h> | ||
#include <aws/core/utils/memory/stl/AWSString.h> | ||
#include <aws/s3/S3Client.h> | ||
#include <performance-tests/PerformanceTestBase.h> | ||
|
||
#include <cstddef> | ||
|
||
namespace PerformanceTest { | ||
namespace Services { | ||
namespace S3 { | ||
/** | ||
* Configuration for S3 performance test cases. | ||
*/ | ||
struct TestCase { | ||
const char* sizeLabel; | ||
size_t sizeBytes; | ||
const char* bucketTypeLabel; | ||
}; | ||
|
||
/** | ||
* S3 performance test implementation. | ||
* Tests PutObject and GetObject operations with different payload sizes and bucket types. | ||
*/ | ||
class S3PerformanceTest : public PerformanceTestBase { | ||
public: | ||
S3PerformanceTest(const Aws::String& region, const TestCase& config, const Aws::String& availabilityZoneId, int iterations = 3); | ||
|
||
void Setup() override; | ||
void TearDown() override; | ||
void Run() override; | ||
|
||
private: | ||
const TestCase& m_config; | ||
const Aws::String m_region; | ||
const Aws::String m_availabilityZoneId; | ||
const int m_iterations; | ||
Aws::UniquePtr<Aws::S3::S3Client> m_s3; | ||
Aws::String m_bucketName; | ||
}; | ||
|
||
} // namespace S3 | ||
} // namespace Services | ||
} // namespace PerformanceTest |
30 changes: 30 additions & 0 deletions
30
tests/performance-tests/include/performance-tests/services/s3/S3TestConfig.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <performance-tests/services/s3/S3PerformanceTest.h> | ||
|
||
#include <array> | ||
#include <set> | ||
|
||
namespace PerformanceTest { | ||
namespace Services { | ||
namespace S3 { | ||
namespace TestConfig { | ||
const std::set<const char*> TestOperations = {"PutObject", "GetObject"}; | ||
|
||
const std::array<TestCase, 6> TestMatrix = {{{"8KB", 8 * 1024, "s3-standard"}, | ||
{"64KB", 64 * 1024, "s3-standard"}, | ||
{"1MB", 1024 * 1024, "s3-standard"}, | ||
{"8KB", 8 * 1024, "s3-express"}, | ||
{"64KB", 64 * 1024, "s3-express"}, | ||
{"1MB", 1024 * 1024, "s3-express"}}}; | ||
|
||
const char* OutputFilename = "s3-performance-test-results.json"; | ||
} // namespace TestConfig | ||
} // namespace S3 | ||
} // namespace Services | ||
} // namespace PerformanceTest |
119 changes: 119 additions & 0 deletions
119
tests/performance-tests/src/services/s3/S3PerformanceTest.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#include <aws/core/client/ClientConfiguration.h> | ||
#include <aws/core/utils/StringUtils.h> | ||
#include <aws/core/utils/logging/LogMacros.h> | ||
#include <aws/core/utils/memory/AWSMemory.h> | ||
#include <aws/core/utils/memory/stl/AWSAllocator.h> | ||
#include <aws/core/utils/memory/stl/AWSString.h> | ||
#include <aws/core/utils/memory/stl/AWSStringStream.h> | ||
#include <aws/s3/S3Client.h> | ||
#include <aws/s3/model/BucketInfo.h> | ||
#include <aws/s3/model/BucketType.h> | ||
#include <aws/s3/model/CreateBucketConfiguration.h> | ||
#include <aws/s3/model/CreateBucketRequest.h> | ||
#include <aws/s3/model/DataRedundancy.h> | ||
#include <aws/s3/model/DeleteBucketRequest.h> | ||
#include <aws/s3/model/DeleteObjectRequest.h> | ||
#include <aws/s3/model/GetObjectRequest.h> | ||
#include <aws/s3/model/LocationType.h> | ||
#include <aws/s3/model/PutObjectRequest.h> | ||
#include <performance-tests/Utils.h> | ||
#include <performance-tests/services/s3/S3PerformanceTest.h> | ||
|
||
#include <cstring> | ||
|
||
PerformanceTest::Services::S3::S3PerformanceTest::S3PerformanceTest(const Aws::String& region, const TestCase& config, | ||
const Aws::String& availabilityZoneId, int iterations) | ||
: m_config(config), m_region(region), m_availabilityZoneId(availabilityZoneId), m_iterations(iterations) {} | ||
|
||
void PerformanceTest::Services::S3::S3PerformanceTest::Setup() { | ||
Aws::Client::ClientConfiguration cfg; | ||
cfg.region = m_region; | ||
m_s3 = Aws::MakeUnique<Aws::S3::S3Client>("S3PerformanceTest", cfg); | ||
|
||
Aws::S3::Model::CreateBucketRequest cbr; | ||
Aws::String const bucketId = PerformanceTest::Utils::GenerateUniqueId(); | ||
|
||
if (strcmp(m_config.bucketTypeLabel, "s3-express") == 0) { | ||
m_bucketName = "perf-express-" + bucketId + "--" + m_availabilityZoneId + "--x-s3"; | ||
cbr.SetBucket(m_bucketName); | ||
Aws::S3::Model::CreateBucketConfiguration bucketConfig; | ||
bucketConfig.SetLocation( | ||
Aws::S3::Model::LocationInfo().WithType(Aws::S3::Model::LocationType::AvailabilityZone).WithName(m_availabilityZoneId)); | ||
|
||
bucketConfig.SetBucket(Aws::S3::Model::BucketInfo() | ||
.WithType(Aws::S3::Model::BucketType::Directory) | ||
.WithDataRedundancy(Aws::S3::Model::DataRedundancy::SingleAvailabilityZone)); | ||
|
||
cbr.SetCreateBucketConfiguration(bucketConfig); | ||
} else { | ||
m_bucketName = "perf-standard-" + bucketId; | ||
cbr.SetBucket(m_bucketName); | ||
} | ||
|
||
auto createOutcome = m_s3->CreateBucket(cbr); | ||
if (!createOutcome.IsSuccess()) { | ||
AWS_LOG_ERROR("PerformanceTest", ("S3:CreateBucket failed: " + createOutcome.GetError().GetMessage()).c_str()); | ||
m_bucketName.clear(); | ||
} | ||
} | ||
|
||
void PerformanceTest::Services::S3::S3PerformanceTest::Run() { | ||
if (m_bucketName.empty()) { | ||
AWS_LOG_ERROR("PerformanceTest", "S3:Run - Bucket setup failed, skipping test"); | ||
return; | ||
} | ||
|
||
const auto randomPayload = PerformanceTest::Utils::RandomString(m_config.sizeBytes); | ||
|
||
// Run PutObject multiple times | ||
for (int i = 0; i < m_iterations; i++) { | ||
auto stream = Aws::MakeShared<Aws::StringStream>("PerfStream"); | ||
*stream << randomPayload; | ||
|
||
Aws::S3::Model::PutObjectRequest por; | ||
por.WithBucket(m_bucketName).WithKey("test-object-" + Aws::Utils::StringUtils::to_string(i)).SetBody(stream); | ||
por.SetAdditionalCustomHeaderValue("test-dimension-size", m_config.sizeLabel); | ||
por.SetAdditionalCustomHeaderValue("test-dimension-bucket-type", m_config.bucketTypeLabel); | ||
auto putOutcome = m_s3->PutObject(por); | ||
if (!putOutcome.IsSuccess()) { | ||
AWS_LOG_ERROR("PerformanceTest", ("S3:PutObject failed: " + putOutcome.GetError().GetMessage()).c_str()); | ||
} | ||
} | ||
|
||
// Run GetObject multiple times | ||
for (int i = 0; i < m_iterations; i++) { | ||
Aws::S3::Model::GetObjectRequest gor; | ||
gor.WithBucket(m_bucketName).WithKey("test-object-" + Aws::Utils::StringUtils::to_string(i)); | ||
gor.SetAdditionalCustomHeaderValue("test-dimension-size", m_config.sizeLabel); | ||
gor.SetAdditionalCustomHeaderValue("test-dimension-bucket-type", m_config.bucketTypeLabel); | ||
auto getOutcome = m_s3->GetObject(gor); | ||
if (!getOutcome.IsSuccess()) { | ||
AWS_LOG_ERROR("PerformanceTest", ("S3:GetObject failed: " + getOutcome.GetError().GetMessage()).c_str()); | ||
} | ||
} | ||
} | ||
|
||
void PerformanceTest::Services::S3::S3PerformanceTest::TearDown() { | ||
if (m_bucketName.empty()) { | ||
AWS_LOG_ERROR("PerformanceTest", "S3:TearDown - No bucket to clean up, setup likely failed"); | ||
return; | ||
} | ||
|
||
for (int i = 0; i < m_iterations; i++) { | ||
auto deleteObjectOutcome = m_s3->DeleteObject( | ||
Aws::S3::Model::DeleteObjectRequest().WithBucket(m_bucketName).WithKey("test-object-" + Aws::Utils::StringUtils::to_string(i))); | ||
if (!deleteObjectOutcome.IsSuccess()) { | ||
AWS_LOG_ERROR("PerformanceTest", ("S3:DeleteObject failed: " + deleteObjectOutcome.GetError().GetMessage()).c_str()); | ||
} | ||
} | ||
|
||
auto deleteBucketOutcome = m_s3->DeleteBucket(Aws::S3::Model::DeleteBucketRequest().WithBucket(m_bucketName)); | ||
if (!deleteBucketOutcome.IsSuccess()) { | ||
AWS_LOG_ERROR("PerformanceTest", ("S3:DeleteBucket failed: " + deleteBucketOutcome.GetError().GetMessage()).c_str()); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0. | ||
*/ | ||
|
||
#include <aws/core/Aws.h> | ||
#include <aws/core/Version.h> | ||
#include <aws/core/monitoring/MonitoringFactory.h> | ||
#include <aws/core/utils/StringUtils.h> | ||
#include <aws/core/utils/memory/AWSMemory.h> | ||
#include <aws/core/utils/memory/stl/AWSSet.h> | ||
#include <aws/core/utils/memory/stl/AWSString.h> | ||
#include <performance-tests/reporting/JsonReportingMetrics.h> | ||
#include <performance-tests/services/s3/S3PerformanceTest.h> | ||
#include <performance-tests/services/s3/S3TestConfig.h> | ||
|
||
#include <cxxopts.hpp> | ||
#include <string> | ||
|
||
int main(int argc, char** argv) { | ||
cxxopts::Options options("s3-perf-test", "S3 Performance Test"); | ||
options.add_options()("r,region", "AWS region", cxxopts::value<std::string>()->default_value("us-east-1"))( | ||
"a,az-id", "Availability zone ID", cxxopts::value<std::string>()->default_value("use1-az4"))( | ||
"i,iterations", "Number of iterations", cxxopts::value<int>()->default_value("10"))( | ||
"c,commit-id", "Commit ID", cxxopts::value<std::string>()->default_value("unknown")); | ||
|
||
auto const result = options.parse(argc, argv); | ||
|
||
Aws::String const region = Aws::Utils::StringUtils::to_string(result["region"].as<std::string>()); | ||
Aws::String const availabilityZoneId = Aws::Utils::StringUtils::to_string(result["az-id"].as<std::string>()); | ||
Aws::String const commitId = Aws::Utils::StringUtils::to_string(result["commit-id"].as<std::string>()); | ||
int const iterations = result["iterations"].as<int>(); | ||
|
||
Aws::SDKOptions sdkOptions; | ||
Aws::String const versionStr = Aws::Version::GetVersionString(); | ||
|
||
sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr<Aws::Monitoring::MonitoringFactory> { | ||
Aws::Set<Aws::String> operations; | ||
for (const auto& operation : PerformanceTest::Services::S3::TestConfig::TestOperations) { | ||
operations.insert(operation); | ||
} | ||
return Aws::MakeUnique<PerformanceTest::Reporting::JsonReportingMetricsFactory>( | ||
"JsonReportingMetricsFactory", operations, "cpp1", versionStr, commitId, PerformanceTest::Services::S3::TestConfig::OutputFilename); | ||
}}; | ||
|
||
Aws::InitAPI(sdkOptions); | ||
|
||
{ | ||
for (const auto& config : PerformanceTest::Services::S3::TestConfig::TestMatrix) { | ||
auto performanceTest = Aws::MakeUnique<PerformanceTest::Services::S3::S3PerformanceTest>("S3PerformanceTest", region, config, | ||
availabilityZoneId, iterations); | ||
performanceTest->Setup(); | ||
performanceTest->Run(); | ||
performanceTest->TearDown(); | ||
} | ||
} | ||
|
||
Aws::ShutdownAPI(sdkOptions); | ||
return 0; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why
std::string
? maybe a unused import