diff --git a/CMakeLists.txt b/CMakeLists.txt index 164f1ad479e..59c9cb14e4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ if (LEGACY_BUILD) option(ENABLE_ZLIB_REQUEST_COMPRESSION "For services that support it, request content will be compressed. On by default if dependency available" ON) option(DISABLE_INTERNAL_IMDSV1_CALLS "Disables IMDSv1 internal client calls" OFF) option(BUILD_BENCHMARKS "Enables building the benchmark executable" OFF) + option(BUILD_PERFORMANCE_TESTS "Enables building the performance test executables" OFF) option(BUILD_OPTEL "Enables building the open telemetry implementation of tracing" OFF) option(AWS_SDK_WARNINGS_ARE_ERRORS "Compiler warning is treated as an error. Try turning this off when observing errors on a new or uncommon compiler" ON) option(BUILD_OPTEL_OTLP_BENCHMARKS "Enables building the benchmark tests with open telemetry OTLP clients" OFF) @@ -341,6 +342,11 @@ if (LEGACY_BUILD) add_sdks() include(tests) + # Performance tests for services + if (BUILD_PERFORMANCE_TESTS) + add_subdirectory(tests/performance-tests) + endif() + # for user friendly cmake usage include(setup_cmake_find_module) diff --git a/docs/CMake_Parameters.md b/docs/CMake_Parameters.md index 146b4affddf..e2328b73838 100644 --- a/docs/CMake_Parameters.md +++ b/docs/CMake_Parameters.md @@ -128,6 +128,9 @@ You can also tell gcc or clang to pass these linker flags by specifying `-Wl,--g ### BUILD_BENCHMARKS (Defaults to OFF) Enables building the benchmark executable +### BUILD_PERFORMANCE_TESTS +(Defaults to OFF) Enables building the performance test executables for S3 and DynamoDB. These tests measure operation latencies and output results to JSON files. Requires S3 and DynamoDB clients to be built. + ### BUILD_OPTEL (Defaults to OFF) Enables building the open telemetry implementation of tracing diff --git a/tests/aws-cpp-sdk-s3-crt-integration-tests/BucketAndObjectOperationTest.cpp b/tests/aws-cpp-sdk-s3-crt-integration-tests/BucketAndObjectOperationTest.cpp index 9f1c56490ec..37edc9a916d 100644 --- a/tests/aws-cpp-sdk-s3-crt-integration-tests/BucketAndObjectOperationTest.cpp +++ b/tests/aws-cpp-sdk-s3-crt-integration-tests/BucketAndObjectOperationTest.cpp @@ -83,7 +83,7 @@ namespace static const char* TEST_OBJ_KEY = "TestObjectKey"; static const char* TEST_NOT_MODIFIED_OBJ_KEY = "TestNotModifiedObjectKey"; static const char* TEST_DNS_UNFRIENDLY_OBJ_KEY = "WhySoHostile"; - static const char* TEST_EVENT_STREAM_OBJ_KEY = "TestEventStream.csv"; + // static const char* TEST_EVENT_STREAM_OBJ_KEY = "TestEventStream.csv"; //windows won't let you hard code unicode strings in a source file and assign them to a char*. Every other compiler does and I need to test this. //to get around this, this string is url encoded version of "TestUnicode中国Key". At test time, we'll convert it to the unicode string static const char* URLENCODED_UNICODE_KEY = "TestUnicode%E4%B8%AD%E5%9B%BDKey"; @@ -978,339 +978,6 @@ namespace AWS_ASSERT_SUCCESS(copyOutcome); } - TEST_F(BucketAndObjectOperationTest, TestObjectOperationWithEventStream) - { - Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = Client->CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\nAlice,1\nBob,2"; - Aws::String firstColumn = "Name\nAlice\nBob\n"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - // putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::NONE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isRecordsEventReceived = false; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - isRecordsEventReceived = true; - auto recordsVector = recordsEvent.GetPayload(); - Aws::String records(recordsVector.begin(), recordsVector.end()); - ASSERT_STREQ(firstColumn.c_str(), records.c_str()); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(static_cast(firstColumn.size()), statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - AWS_ASSERT_SUCCESS(selectObjectContentOutcome); - ASSERT_TRUE(isRecordsEventReceived); - ASSERT_TRUE(isStatsEventReceived); - } - -#if 0 - // S3 CRT Client doesn't support custom retry strategy right now. - // This test is to test failed event stream request will not cause crash during retry. - TEST_F(BucketAndObjectOperationTest, TestSelectObjectOperationWithEventStreamFailWithRetry) - { - Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = Client->CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName)); - TagTestBucket(fullBucketName); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\nAlice,1\nBob,2"; - Aws::String firstColumn = "Name\nAlice\nBob\n"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey("ANonExistenceKey"); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::NONE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isRecordsEventReceived = false; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - isRecordsEventReceived = true; - auto recordsVector = recordsEvent.GetPayload(); - Aws::String records(recordsVector.begin(), recordsVector.end()); - ASSERT_STREQ(firstColumn.c_str(), records.c_str()); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(static_cast(firstColumn.size()), statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = retryClient->SelectObjectContent(selectObjectContentRequest); - ASSERT_FALSE(selectObjectContentOutcome.IsSuccess()); - } -#endif - - TEST_F(BucketAndObjectOperationTest, TestEventStreamWithLargeFile) - { - Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_LARGE_FILE_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = Client->CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\n"; - for (int i = 0; i < 1000000; i++) - { - *objectStream << "foo,0\n"; - } - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - // putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select * from S3Object where cast(number as int) < 1"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - size_t recordsTotalLength = 0; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - recordsTotalLength += recordsEvent.GetPayload().size(); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(12ll/*length of the 1st row*/ + 6/*length of all the other row*/ * 1000000ll, statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(6000012ll, statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(6000000ll, statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - ASSERT_EQ(6000000u, recordsTotalLength); - ASSERT_TRUE(isStatsEventReceived); - } - - TEST_F(BucketAndObjectOperationTest, TestErrorsInXml) - { - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket("adskflaklfakl"); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - ASSERT_FALSE(selectObjectContentOutcome.IsSuccess()); -#if ENABLE_CURL_CLIENT - ASSERT_FALSE(selectObjectContentOutcome.GetError().GetRemoteHostIpAddress().empty()); -#endif - ASSERT_FALSE(selectObjectContentOutcome.GetError().GetRequestId().empty()); - ASSERT_EQ(S3CrtErrors::NO_SUCH_BUCKET, selectObjectContentOutcome.GetError().GetErrorType()); - } - - TEST_F(BucketAndObjectOperationTest, TestErrorsInEventStream) - { - Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_ERRORS_IN_EVENT_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = Client->CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\n"; - for (int i = 0; i < 1000000; i++) - { - *objectStream << "foo,0\n"; - } - *objectStream << "bar,NAN"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - // putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select * from S3Object where cast(number as int) < 1"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isErrorEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetOnErrorCallback([&](const AWSError& s3Error) - { - isErrorEventReceived = true; - ASSERT_EQ(CoreErrors::UNKNOWN, static_cast(s3Error.GetErrorType())); - ASSERT_STREQ("CastFailed", s3Error.GetExceptionName().c_str()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - Client->SelectObjectContent(selectObjectContentRequest); - - ASSERT_TRUE(isErrorEventReceived); - } - TEST_F(BucketAndObjectOperationTest, TestNullBody) { const Aws::String fullBucketName = CalculateBucketName(BASE_PUT_OBJECTS_BUCKET_NAME.c_str()); diff --git a/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp b/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp index 1f13967b7fb..e1a07c640ba 100644 --- a/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp +++ b/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp @@ -96,7 +96,7 @@ namespace static const char* TEST_NOT_MODIFIED_OBJ_KEY = "TestNotModifiedObjectKey"; static const char* TEST_OBJECT_LOCK_OBJ_KEY = "TestObjectLock"; static const char* TEST_DNS_UNFRIENDLY_OBJ_KEY = "WhySoHostile"; - static const char* TEST_EVENT_STREAM_OBJ_KEY = "TestEventStream.csv"; + // static const char* TEST_EVENT_STREAM_OBJ_KEY = "TestEventStream.csv"; //windows won't let you hard code unicode strings in a source file and assign them to a char*. Every other compiler does and I need to test this. //to get around this, this string is url encoded version of "TestUnicode中国Key". At test time, we'll convert it to the unicode string static const char* URLENCODED_UNICODE_KEY = "TestUnicode%E4%B8%AD%E5%9B%BDKey"; @@ -1592,336 +1592,6 @@ namespace AWS_ASSERT_SUCCESS(deleteObjectOutcome); } - TEST_F(BucketAndObjectOperationTest, TestObjectOperationWithEventStream) - { - const Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName, Client)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\nAlice,1\nBob,2"; - Aws::String firstColumn = "Name\nAlice\nBob\n"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::NONE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isRecordsEventReceived = false; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - isRecordsEventReceived = true; - auto recordsVector = recordsEvent.GetPayload(); - Aws::String records(recordsVector.begin(), recordsVector.end()); - ASSERT_STREQ(firstColumn.c_str(), records.c_str()); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(static_cast(firstColumn.size()), statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - AWS_ASSERT_SUCCESS(selectObjectContentOutcome); - ASSERT_TRUE(isRecordsEventReceived); - ASSERT_TRUE(isStatsEventReceived); - } - - // This test is to test failed event stream request will not cause crash during retry. - TEST_F(BucketAndObjectOperationTest, TestSelectObjectOperationWithEventStreamFailWithRetry) - { - const Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName, Client)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\nAlice,1\nBob,2"; - Aws::String firstColumn = "Name\nAlice\nBob\n"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey("ANonExistenceKey"); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::NONE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isRecordsEventReceived = false; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - isRecordsEventReceived = true; - auto recordsVector = recordsEvent.GetPayload(); - Aws::String records(recordsVector.begin(), recordsVector.end()); - ASSERT_STREQ(firstColumn.c_str(), records.c_str()); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(static_cast(objectSize), statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(static_cast(firstColumn.size()), statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = retryClient->SelectObjectContent(selectObjectContentRequest); - ASSERT_FALSE(selectObjectContentOutcome.IsSuccess()); - } - - TEST_F(BucketAndObjectOperationTest, TestEventStreamWithLargeFile) - { - const Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_LARGE_FILE_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName, Client)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\n"; - for (int i = 0; i < 1000000; i++) - { - *objectStream << "foo,0\n"; - } - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select * from S3Object where cast(number as int) < 1"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - size_t recordsTotalLength = 0; - bool isStatsEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetRecordsEventCallback([&](const RecordsEvent& recordsEvent) - { - recordsTotalLength += recordsEvent.GetPayload().size(); - }); - handler.SetStatsEventCallback([&](const StatsEvent& statsEvent) - { - isStatsEventReceived = true; - ASSERT_EQ(12ll/*length of the 1st row*/ + 6/*length of all the other row*/ * 1000000ll, statsEvent.GetDetails().GetBytesScanned()); - ASSERT_EQ(6000012ll, statsEvent.GetDetails().GetBytesProcessed()); - ASSERT_EQ(6000000ll, statsEvent.GetDetails().GetBytesReturned()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - ASSERT_EQ(6000000u, recordsTotalLength); - ASSERT_TRUE(isStatsEventReceived); - } - - TEST_F(BucketAndObjectOperationTest, TestErrorsInXml) - { - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket("adskflaklfakl"); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select s._1 from S3Object s"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - auto selectObjectContentOutcome = Client->SelectObjectContent(selectObjectContentRequest); - ASSERT_FALSE(selectObjectContentOutcome.IsSuccess()); -#if ENABLE_CURL_CLIENT - ASSERT_FALSE(selectObjectContentOutcome.GetError().GetRemoteHostIpAddress().empty()); -#endif - ASSERT_FALSE(selectObjectContentOutcome.GetError().GetRequestId().empty()); - ASSERT_EQ(S3Errors::NO_SUCH_BUCKET, selectObjectContentOutcome.GetError().GetErrorType()); - } - - TEST_F(BucketAndObjectOperationTest, TestErrorsInEventStream) - { - const Aws::String fullBucketName = CalculateBucketName(BASE_EVENT_STREAM_ERRORS_IN_EVENT_TEST_BUCKET_NAME.c_str()); - SCOPED_TRACE(Aws::String("FullBucketName ") + fullBucketName); - CreateBucketRequest createBucketRequest; - createBucketRequest.SetBucket(fullBucketName); - createBucketRequest.SetACL(BucketCannedACL::private_); - CreateBucketOutcome createBucketOutcome = CreateBucket(createBucketRequest); - AWS_ASSERT_SUCCESS(createBucketOutcome); - ASSERT_TRUE(WaitForBucketToPropagate(fullBucketName, Client)); - TagTestBucket(fullBucketName, Client); - - PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(fullBucketName); - - std::shared_ptr objectStream = Aws::MakeShared(ALLOCATION_TAG); - *objectStream << "Name,Number\n"; - for (int i = 0; i < 1000000; i++) - { - *objectStream << "foo,0\n"; - } - *objectStream << "bar,NAN"; - objectStream->flush(); - putObjectRequest.SetBody(objectStream); - putObjectRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - auto objectSize = putObjectRequest.GetBody()->tellp(); - putObjectRequest.SetContentLength(static_cast(objectSize)); - putObjectRequest.SetContentMD5(HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType("text/csv"); - - PutObjectOutcome putObjectOutcome = Client->PutObject(putObjectRequest); - AWS_ASSERT_SUCCESS(putObjectOutcome); - - ASSERT_TRUE(WaitForObjectToPropagate(fullBucketName, TEST_EVENT_STREAM_OBJ_KEY)); - - SelectObjectContentRequest selectObjectContentRequest; - selectObjectContentRequest.SetBucket(fullBucketName); - selectObjectContentRequest.SetKey(TEST_EVENT_STREAM_OBJ_KEY); - - selectObjectContentRequest.SetExpressionType(ExpressionType::SQL); - - selectObjectContentRequest.SetExpression("select * from S3Object where cast(number as int) < 1"); - - CSVInput csvInput; - csvInput.SetFileHeaderInfo(FileHeaderInfo::USE); - InputSerialization inputSerialization; - inputSerialization.SetCSV(csvInput); - selectObjectContentRequest.SetInputSerialization(inputSerialization); - - CSVOutput csvOutput; - OutputSerialization outputSerialization; - outputSerialization.SetCSV(csvOutput); - selectObjectContentRequest.SetOutputSerialization(outputSerialization); - - bool isErrorEventReceived = false; - - SelectObjectContentHandler handler; - handler.SetOnErrorCallback([&](const AWSError& s3Error) - { - isErrorEventReceived = true; - ASSERT_EQ(CoreErrors::UNKNOWN, static_cast(s3Error.GetErrorType())); - ASSERT_STREQ("CastFailed", s3Error.GetExceptionName().c_str()); - }); - - selectObjectContentRequest.SetEventStreamHandler(handler); - - Client->SelectObjectContent(selectObjectContentRequest); - - ASSERT_TRUE(isErrorEventReceived); - } - TEST_F(BucketAndObjectOperationTest, TestFlexibleChecksums) { const Aws::String fullBucketName = CalculateBucketName(BASE_CHECKSUMS_BUCKET_NAME.c_str()); diff --git a/tests/performance-tests/CMakeLists.txt b/tests/performance-tests/CMakeLists.txt new file mode 100644 index 00000000000..002a8ca0df3 --- /dev/null +++ b/tests/performance-tests/CMakeLists.txt @@ -0,0 +1,37 @@ +# 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) + string(TOLOWER ${SERVICE} SERVICE_LOWER) + add_executable(${SERVICE_LOWER}-performance-test + src/services/${SERVICE_LOWER}/main.cpp + src/reporting/JsonReportingMetrics.cpp + src/services/${SERVICE_LOWER}/${SERVICE}PerformanceTest.cpp + src/services/${SERVICE_LOWER}/${SERVICE}TestConfig.cpp + ) + set_compiler_flags(${SERVICE_LOWER}-performance-test) + set_compiler_warnings(${SERVICE_LOWER}-performance-test) + target_include_directories(${SERVICE_LOWER}-performance-test PRIVATE include) + target_link_libraries(${SERVICE_LOWER}-performance-test PRIVATE aws-cpp-sdk-core aws-cpp-sdk-${SERVICE_LOWER} cxxopts::cxxopts) + set_property(TARGET ${SERVICE_LOWER}-performance-test PROPERTY CXX_STANDARD 20) + set_property(TARGET ${SERVICE_LOWER}-performance-test PROPERTY COMPILE_OPTIONS "-fexceptions") +endfunction() + +add_service_test(S3) +add_service_test(DynamoDB) diff --git a/tests/performance-tests/include/performance-tests/PerformanceTestBase.h b/tests/performance-tests/include/performance-tests/PerformanceTestBase.h new file mode 100644 index 00000000000..0fdfe303062 --- /dev/null +++ b/tests/performance-tests/include/performance-tests/PerformanceTestBase.h @@ -0,0 +1,38 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include + +namespace PerformanceTest { + +/** + * Base class for all performance tests. + */ +class PerformanceTestBase { + public: + virtual ~PerformanceTestBase() = default; + + /** + * Initialize resources for the test. + * @return Outcome indicating success or failure with error details + */ + virtual Aws::Utils::Outcome Setup() = 0; + + /** + * Run the performance test operations. + */ + virtual void Run() = 0; + + /** + * Clean up resources created during setup. + */ + virtual void TearDown() = 0; +}; + +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/Utils.h b/tests/performance-tests/include/performance-tests/Utils.h new file mode 100644 index 00000000000..eac2f4ab7e8 --- /dev/null +++ b/tests/performance-tests/include/performance-tests/Utils.h @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +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 \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/reporting/JsonReportingMetrics.h b/tests/performance-tests/include/performance-tests/reporting/JsonReportingMetrics.h new file mode 100644 index 00000000000..4adb2fac74b --- /dev/null +++ b/tests/performance-tests/include/performance-tests/reporting/JsonReportingMetrics.h @@ -0,0 +1,205 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace PerformanceTest { +namespace Reporting { + +/** + * Container for a single performance metric record that stores measurement data and associated metadata. + */ +struct PerformanceMetricRecord { + Aws::String name; + Aws::String description; + Aws::String unit; + Aws::Utils::DateTime date; + Aws::Vector> measurements; + Aws::Map dimensions; +}; + +/** + * Context will be shared between monitor invocations. + */ +struct RequestContext; + +/** + * An implementation of the MonitoringInterface that collects performance metrics + * and reports them in a JSON format. + */ +class JsonReportingMetrics : public Aws::Monitoring::MonitoringInterface { + public: + /** + * Constructor that initializes the metrics collector with configuration parameters. + * @param monitoredOperations Set of operations to monitor (empty means monitor all) + * @param productId Product identifier (e.g., "cpp1") + * @param sdkVersion SDK version string + * @param commitId Git commit identifier + * @param outputFilename Path to output file (e.g., "s3-perf-results.json") + * @param buildMode Build mode ("debug" or "release") + */ + JsonReportingMetrics(const Aws::Set& monitoredOperations = Aws::Set(), const Aws::String& productId = "unknown", + const Aws::String& sdkVersion = "unknown", const Aws::String& commitId = "unknown", + const Aws::String& outputFilename = "performance-test-results.json", const Aws::String& buildMode = "unknown"); + + ~JsonReportingMetrics() override; + + /** + * Called when an AWS request is started. Creates and returns context for tracking. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @return Context pointer to newly created RequestContext + */ + void* OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request) const override; + + /** + * Called when an AWS request succeeds. Stores latency metrics in context. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param outcome HTTP response outcome + * @param metrics Core metrics collection containing latency data + * @param context Request context + */ + void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, const Aws::Client::HttpResponseOutcome& outcome, + const Aws::Monitoring::CoreMetricsCollection& metrics, void* context) const override; + + /** + * Called when an AWS request fails. Stores latency metrics in context. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param outcome HTTP response outcome + * @param metrics Core metrics collection containing latency data + * @param context Request context + */ + void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, const Aws::Client::HttpResponseOutcome& outcome, + const Aws::Monitoring::CoreMetricsCollection& metrics, void* context) const override; + + /** + * Called when an AWS request is retried. No action taken. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param context Request context + */ + void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, void* context) const override; + + /** + * Called when an AWS request finishes. Processes stored metrics and cleans up context. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param context Request context + */ + void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, void* context) const override; + + private: + /** + * Helper method to process request metrics and store in context. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param metricsFromCore Core metrics collection containing latency data + * @param context Request context + */ + void StoreLatencyInContext(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const; + + /** + * Adds a performance record with a specified duration. + * @param serviceName Name of the AWS service + * @param requestName Name of the operation + * @param request HTTP request object + * @param durationMs Duration of the request in milliseconds + */ + void AddPerformanceRecord(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const std::variant& durationMs) const; + + /** + * Outputs aggregated performance metrics to JSON file. + * Groups records by name and dimensions, then writes to configured output file. + */ + void DumpJson() const; + + /** + * Writes JSON to the output file. + * @param root The JSON root object to write + */ + void WriteJsonToFile(const Aws::Utils::Json::JsonValue& root) const; + + mutable Aws::Vector m_performanceRecords; + mutable Aws::UnorderedMap> m_requestContexts; + Aws::Set m_monitoredOperations; + Aws::String m_productId; + Aws::String m_sdkVersion; + Aws::String m_commitId; + Aws::String m_outputFilename; + Aws::String m_buildMode; +}; + +/** + * A factory for creating instances of JsonReportingMetrics. + * Used by the AWS SDK monitoring system to instantiate performance metrics collectors. + */ +class JsonReportingMetricsFactory : public Aws::Monitoring::MonitoringFactory { + public: + /** + * Constructor that initializes the factory with configuration parameters. + * @param monitoredOperations Set of operations to monitor (empty means monitor all) + * @param productId Product identifier (e.g., "cpp1") + * @param sdkVersion SDK version string + * @param commitId Git commit identifier + * @param outputFilename Path to output file (e.g., "s3-perf-results.json") + * @param buildMode Build mode ("debug" or "release") + */ + JsonReportingMetricsFactory(const Aws::Set& monitoredOperations = Aws::Set(), + const Aws::String& productId = "unknown", const Aws::String& sdkVersion = "unknown", + const Aws::String& commitId = "unknown", const Aws::String& outputFilename = "performance-test-results.json", + const Aws::String& buildMode = "unknown"); + + ~JsonReportingMetricsFactory() override = default; + + /** + * Creates a new JsonReportingMetrics instance for performance monitoring. + * @return Unique pointer to monitoring interface implementation + */ + Aws::UniquePtr CreateMonitoringInstance() const override; + + private: + Aws::Set m_monitoredOperations; + Aws::String m_productId; + Aws::String m_sdkVersion; + Aws::String m_commitId; + Aws::String m_outputFilename; + Aws::String m_buildMode; +}; +} // namespace Reporting +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h b/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h new file mode 100644 index 00000000000..660bfc567f2 --- /dev/null +++ b/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h @@ -0,0 +1,43 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { + +/** + * DynamoDB performance test implementation. + * Tests PutItem and GetItem operations with different payload sizes. + */ +class DynamoDBPerformanceTest : public PerformanceTestBase { + public: + DynamoDBPerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, const TestConfig::TestCase& testConfig, + int iterations = 10); + + Aws::Utils::Outcome Setup() override; + void Run() override; + void TearDown() override; + + private: + const Aws::UniquePtr m_dynamodb; + const TestConfig::TestCase m_testConfig; + const int m_iterations; + const Aws::String m_tableName; +}; + +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h b/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h new file mode 100644 index 00000000000..786a2032f2e --- /dev/null +++ b/tests/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h @@ -0,0 +1,56 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include + +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { +namespace TestConfig { + +/** + * Payload sizes for DynamoDB performance tests. + */ +enum class PayloadSize { K8, K64, K392 }; + +/** + * Configuration for DynamoDB performance test cases. + */ +struct TestCase { + PayloadSize payloadSize; +}; + +/** + * Get the payload size in bytes for a given PayloadSize enum. + * @param payloadSize The PayloadSize enum value + * @return Size in bytes + */ +size_t GetPayloadSizeInBytes(PayloadSize payloadSize); + +/** + * Get the string label for a given PayloadSize enum. + * @param payloadSize The PayloadSize enum value + * @return String label (e.g., "8KB", "64KB", "392KB") + */ +Aws::String GetPayloadSizeLabel(PayloadSize payloadSize); + +/** Operations tested in DynamoDB performance tests. */ +extern const std::array TestOperations; + +/** Array of all test case combinations. */ +extern const std::array TestMatrix; + +/** Output filename for test results. */ +extern const char* OutputFilename; + +} // namespace TestConfig +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h b/tests/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h new file mode 100644 index 00000000000..002d0c1b451 --- /dev/null +++ b/tests/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h @@ -0,0 +1,44 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace S3 { + +/** + * S3 performance test implementation. + * Tests PutObject and GetObject operations with different payload sizes and bucket types. + */ +class S3PerformanceTest : public PerformanceTestBase { + public: + S3PerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, const TestConfig::TestCase& testConfig, int iterations = 10, + const Aws::String& availabilityZoneId = ""); + + Aws::Utils::Outcome Setup() override; + void Run() override; + void TearDown() override; + + private: + const Aws::UniquePtr m_s3; + const TestConfig::TestCase m_testConfig; + const int m_iterations; + const Aws::String m_bucketName; + const Aws::String m_availabilityZoneId; +}; + +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/include/performance-tests/services/s3/S3TestConfig.h b/tests/performance-tests/include/performance-tests/services/s3/S3TestConfig.h new file mode 100644 index 00000000000..9f180b21c59 --- /dev/null +++ b/tests/performance-tests/include/performance-tests/services/s3/S3TestConfig.h @@ -0,0 +1,69 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include + +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace S3 { +namespace TestConfig { + +/** + * Payload sizes for S3 performance tests. + */ +enum class PayloadSize { K8, K64, M1 }; + +/** + * Bucket types for S3 performance tests. + */ +enum class BucketType { Standard, Express }; + +/** + * Configuration for S3 performance test cases. + */ +struct TestCase { + PayloadSize payloadSize; + BucketType bucketType; +}; + +/** + * Get the payload size in bytes for a given PayloadSize enum. + * @param payloadSize The PayloadSize enum value + * @return Size in bytes + */ +size_t GetPayloadSizeInBytes(PayloadSize payloadSize); + +/** + * Get the string label for a given PayloadSize enum. + * @param payloadSize The PayloadSize enum value + * @return String label (e.g., "8KB", "64KB", "1MB") + */ +Aws::String GetPayloadSizeLabel(PayloadSize payloadSize); + +/** + * Get the string label for a given BucketType enum. + * @param bucketType The BucketType enum value + * @return String label (e.g., "s3-standard", "s3-express") + */ +Aws::String GetBucketTypeLabel(BucketType bucketType); + +/** Operations tested in S3 performance tests. */ +extern const std::array TestOperations; + +/** Array of all test case combinations. */ +extern const std::array TestMatrix; + +/** Output filename for test results. */ +extern const char* OutputFilename; + +} // namespace TestConfig +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/src/reporting/JsonReportingMetrics.cpp b/tests/performance-tests/src/reporting/JsonReportingMetrics.cpp new file mode 100644 index 00000000000..a106c1bcc80 --- /dev/null +++ b/tests/performance-tests/src/reporting/JsonReportingMetrics.cpp @@ -0,0 +1,234 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace PerformanceTest::Reporting; + +struct PerformanceTest::Reporting::RequestContext { + Aws::Utils::UUID requestId{Aws::Utils::UUID::RandomUUID()}; + Aws::String serviceName; + Aws::String requestName; + std::shared_ptr request; + std::variant durationMs = int64_t(0); + bool failed = false; +}; + +JsonReportingMetrics::JsonReportingMetrics(const Aws::Set& monitoredOperations, const Aws::String& productId, + const Aws::String& sdkVersion, const Aws::String& commitId, const Aws::String& outputFilename, + const Aws::String& buildMode) + : m_monitoredOperations(monitoredOperations), + m_productId(productId), + m_sdkVersion(sdkVersion), + m_commitId(commitId), + m_outputFilename(outputFilename), + m_buildMode(buildMode) {} + +JsonReportingMetrics::~JsonReportingMetrics() { DumpJson(); } + +JsonReportingMetricsFactory::JsonReportingMetricsFactory(const Aws::Set& monitoredOperations, const Aws::String& productId, + const Aws::String& sdkVersion, const Aws::String& commitId, + const Aws::String& outputFilename, const Aws::String& buildMode) + : m_monitoredOperations(monitoredOperations), + m_productId(productId), + m_sdkVersion(sdkVersion), + m_commitId(commitId), + m_outputFilename(outputFilename), + m_buildMode(buildMode) {} + +Aws::UniquePtr JsonReportingMetricsFactory::CreateMonitoringInstance() const { + return Aws::MakeUnique("JsonReportingMetrics", m_monitoredOperations, m_productId, m_sdkVersion, m_commitId, + m_outputFilename, m_buildMode); +} + +void JsonReportingMetrics::StoreLatencyInContext(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const { + RequestContext* requestContext = static_cast(context); + + Aws::String const latencyKey = Aws::Monitoring::GetHttpClientMetricNameByType(Aws::Monitoring::HttpClientMetricsType::RequestLatency); + auto iterator = metricsFromCore.httpClientMetrics.find(latencyKey); + if (iterator != metricsFromCore.httpClientMetrics.end() && iterator->second > 0) { + requestContext->serviceName = serviceName; + requestContext->requestName = requestName; + requestContext->request = request; + requestContext->durationMs = iterator->second; + } else { + requestContext->failed = true; + } +} + +void JsonReportingMetrics::AddPerformanceRecord(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const std::variant& durationMs) const { + // If no operations are registered, monitor all operations. Otherwise, only monitor registered operations + if (!m_monitoredOperations.empty() && m_monitoredOperations.find(requestName) == m_monitoredOperations.end()) { + return; + } + + PerformanceMetricRecord record; + record.name = + Aws::Utils::StringUtils::ToLower(serviceName.c_str()) + "." + Aws::Utils::StringUtils::ToLower(requestName.c_str()) + ".latency"; + record.description = "Time to complete " + requestName + " operation"; + record.unit = "Milliseconds"; + record.date = Aws::Utils::DateTime::Now(); + record.measurements.emplace_back(durationMs); + + if (request) { + auto headers = request->GetHeaders(); + for (const auto& header : headers) { + if (header.first.find("test-dimension-") == 0) { + Aws::String const key = header.first.substr(15); + record.dimensions[key] = header.second; + } + } + } + + m_performanceRecords.push_back(record); +} + +void* JsonReportingMetrics::OnRequestStarted(const Aws::String&, const Aws::String&, + const std::shared_ptr&) const { + auto context = Aws::MakeUnique("RequestContext"); + auto requestID = context->requestId; + m_requestContexts.emplace(requestID, std::move(context)); + return m_requestContexts[requestID].get(); +} + +void JsonReportingMetrics::OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const Aws::Client::HttpResponseOutcome&, + const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const { + StoreLatencyInContext(serviceName, requestName, request, metricsFromCore, context); +} + +void JsonReportingMetrics::OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr& request, + const Aws::Client::HttpResponseOutcome&, + const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const { + StoreLatencyInContext(serviceName, requestName, request, metricsFromCore, context); +} + +void JsonReportingMetrics::OnRequestRetry(const Aws::String&, const Aws::String&, const std::shared_ptr&, + void*) const {} + +void JsonReportingMetrics::OnFinish(const Aws::String&, const Aws::String&, const std::shared_ptr&, + void* context) const { + RequestContext* requestContext = static_cast(context); + + if (!requestContext->failed) { + AddPerformanceRecord(requestContext->serviceName, requestContext->requestName, requestContext->request, requestContext->durationMs); + } + + m_requestContexts.erase(requestContext->requestId); +} + +void JsonReportingMetrics::DumpJson() const { + Aws::Utils::Json::JsonValue root; + root.WithString("productId", m_productId); + root.WithString("sdkVersion", m_sdkVersion); + root.WithString("commitId", m_commitId); + + if (m_performanceRecords.empty()) { + root.WithArray("results", Aws::Utils::Array(0)); + WriteJsonToFile(root); + return; + } + + // Group performance records by name and dimensions + Aws::Map aggregatedRecords; + + for (const auto& record : m_performanceRecords) { + Aws::String key = record.name; + for (const auto& dim : record.dimensions) { + key += ":" + Aws::String(dim.first) + "=" + Aws::String(dim.second); + } + + if (aggregatedRecords.find(key) == aggregatedRecords.end()) { + aggregatedRecords[key] = record; + } else { + for (const auto& measurement : record.measurements) { + aggregatedRecords[key].measurements.push_back(measurement); + } + } + } + + Aws::Utils::Array results(aggregatedRecords.size()); + size_t index = 0; + + for (const auto& pair : aggregatedRecords) { + const auto& record = pair.second; + Aws::Utils::Json::JsonValue jsonMetric; + jsonMetric.WithString("name", record.name); + jsonMetric.WithString("description", record.description); + jsonMetric.WithString("unit", record.unit); + jsonMetric.WithInt64("date", record.date.Seconds()); + + if (!record.dimensions.empty()) { + Aws::Utils::Array dimensionsArray(record.dimensions.size() + (m_buildMode == "unknown" ? 0 : 1)); + size_t dimensionIndex = 0; + + if (m_buildMode != "unknown") { + Aws::Utils::Json::JsonValue buildModeDimension; + buildModeDimension.WithString("name", "build-mode"); + buildModeDimension.WithString("value", m_buildMode); + dimensionsArray[dimensionIndex++] = std::move(buildModeDimension); + } + + for (const auto& dim : record.dimensions) { + Aws::Utils::Json::JsonValue dimension; + dimension.WithString("name", dim.first); + dimension.WithString("value", dim.second); + dimensionsArray[dimensionIndex++] = std::move(dimension); + } + jsonMetric.WithArray("dimensions", std::move(dimensionsArray)); + } + + Aws::Utils::Array measurementsArray(record.measurements.size()); + for (size_t measurementIndex = 0; measurementIndex < record.measurements.size(); ++measurementIndex) { + Aws::Utils::Json::JsonValue measurementValue; + if (std::holds_alternative(record.measurements[measurementIndex])) { + measurementValue.AsDouble(std::get(record.measurements[measurementIndex])); + } else { + measurementValue.AsInt64(std::get(record.measurements[measurementIndex])); + } + measurementsArray[measurementIndex] = std::move(measurementValue); + } + jsonMetric.WithArray("measurements", std::move(measurementsArray)); + + results[index++] = std::move(jsonMetric); + } + + root.WithArray("results", std::move(results)); + WriteJsonToFile(root); +} + +void JsonReportingMetrics::WriteJsonToFile(const Aws::Utils::Json::JsonValue& root) const { + std::ofstream outFile(m_outputFilename.c_str()); + if (outFile.is_open()) { + outFile << root.View().WriteReadable(); + } +} \ No newline at end of file diff --git a/tests/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp b/tests/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp new file mode 100644 index 00000000000..bc678640c88 --- /dev/null +++ b/tests/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp @@ -0,0 +1,129 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::DynamoDBPerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, + const TestConfig::TestCase& testConfig, + int iterations) + : m_dynamodb(Aws::MakeUnique("DynamoDBPerformanceTest", clientConfig)), + m_testConfig(testConfig), + m_iterations(iterations), + m_tableName("perf-table-" + PerformanceTest::Utils::GenerateUniqueId()) { + assert(m_dynamodb && "DynamoDB client not initialized"); +} + +Aws::Utils::Outcome PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Setup() { + Aws::DynamoDB::Model::CreateTableRequest createTableRequest; + createTableRequest.SetTableName(m_tableName); + + Aws::DynamoDB::Model::AttributeDefinition hashKey; + hashKey.SetAttributeName("data"); + hashKey.SetAttributeType(Aws::DynamoDB::Model::ScalarAttributeType::S); + createTableRequest.AddAttributeDefinitions(hashKey); + + Aws::DynamoDB::Model::KeySchemaElement keySchema; + keySchema.WithAttributeName("data").WithKeyType(Aws::DynamoDB::Model::KeyType::HASH); + createTableRequest.AddKeySchema(keySchema); + + Aws::DynamoDB::Model::BillingMode const billingMode = Aws::DynamoDB::Model::BillingMode::PAY_PER_REQUEST; + createTableRequest.SetBillingMode(billingMode); + + auto createTableOutcome = m_dynamodb->CreateTable(createTableRequest); + if (!createTableOutcome.IsSuccess()) { + return "DynamoDB Setup() - CreateTable failed: " + createTableOutcome.GetError().GetMessage(); + } + + // Wait for table to become active + const int MAX_QUERIES = 20; + Aws::DynamoDB::Model::DescribeTableRequest describeRequest; + describeRequest.SetTableName(m_tableName); + + int count = 0; + while (count < MAX_QUERIES) { + const Aws::DynamoDB::Model::DescribeTableOutcome& describeOutcome = m_dynamodb->DescribeTable(describeRequest); + if (describeOutcome.IsSuccess()) { + Aws::DynamoDB::Model::TableStatus const status = describeOutcome.GetResult().GetTable().GetTableStatus(); + if (Aws::DynamoDB::Model::TableStatus::ACTIVE == status) { + break; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + } else { + return "DynamoDB Setup() - DescribeTable failed: " + describeOutcome.GetError().GetMessage(); + } + count++; + } + + if (count >= MAX_QUERIES) { + return "DynamoDB Setup() - Table did not become active within timeout"; + } + return Aws::NoResult(); +} + +void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Run() { + const auto payload = PerformanceTest::Utils::RandomString(TestConfig::GetPayloadSizeInBytes(m_testConfig.payloadSize)); + + // Run PutItem multiple times + for (int i = 0; i < m_iterations; i++) { + Aws::DynamoDB::Model::PutItemRequest putItemRequest; + putItemRequest.SetTableName(m_tableName); + putItemRequest.SetAdditionalCustomHeaderValue("test-dimension-size", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize)); + putItemRequest.AddItem("data", Aws::DynamoDB::Model::AttributeValue().SetS(payload)); + + auto putItemOutcome = m_dynamodb->PutItem(putItemRequest); + if (!putItemOutcome.IsSuccess()) { + AWS_LOG_ERROR("PerformanceTest", ("DynamoDB Run() - PutItem failed: " + putItemOutcome.GetError().GetMessage()).c_str()); + } + } + + // Run GetItem multiple times + for (int i = 0; i < m_iterations; i++) { + Aws::DynamoDB::Model::GetItemRequest getItemRequest; + getItemRequest.SetTableName(m_tableName); + getItemRequest.SetAdditionalCustomHeaderValue("test-dimension-size", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize)); + getItemRequest.AddKey("data", Aws::DynamoDB::Model::AttributeValue().SetS(payload)); + + auto getItemOutcome = m_dynamodb->GetItem(getItemRequest); + if (!getItemOutcome.IsSuccess()) { + AWS_LOG_ERROR("PerformanceTest", ("DynamoDB Run() - GetItem failed: " + getItemOutcome.GetError().GetMessage()).c_str()); + } + } +} + +void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::TearDown() { + Aws::DynamoDB::Model::DeleteTableRequest deleteTableRequest; + deleteTableRequest.SetTableName(m_tableName); + auto deleteTableOutcome = m_dynamodb->DeleteTable(deleteTableRequest); + if (!deleteTableOutcome.IsSuccess()) { + AWS_LOG_ERROR("PerformanceTest", ("DynamoDB TearDown() - DeleteTable failed: " + deleteTableOutcome.GetError().GetMessage()).c_str()); + } +} \ No newline at end of file diff --git a/tests/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp b/tests/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp new file mode 100644 index 00000000000..c9718f8384a --- /dev/null +++ b/tests/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp @@ -0,0 +1,49 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { +namespace TestConfig { + +const std::array TestOperations = {"PutItem", "GetItem"}; + +const std::array TestMatrix = { + {{.payloadSize = PayloadSize::K8}, {.payloadSize = PayloadSize::K64}, {.payloadSize = PayloadSize::K392}}}; + +const char* OutputFilename = "dynamodb-performance-test-results.json"; + +size_t GetPayloadSizeInBytes(PayloadSize size) { + switch (size) { + case PayloadSize::K8: + return 8 * 1024; + case PayloadSize::K64: + return 64 * 1024; + case PayloadSize::K392: + return 392 * 1024; + } +} + +Aws::String GetPayloadSizeLabel(PayloadSize size) { + switch (size) { + case PayloadSize::K8: + return "8KB"; + case PayloadSize::K64: + return "64KB"; + case PayloadSize::K392: + return "392KB"; + } +} + +} // namespace TestConfig +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/src/services/dynamodb/main.cpp b/tests/performance-tests/src/services/dynamodb/main.cpp new file mode 100644 index 00000000000..85a29602049 --- /dev/null +++ b/tests/performance-tests/src/services/dynamodb/main.cpp @@ -0,0 +1,68 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char** argv) { + cxxopts::Options options("dynamodb-perf-test", "DynamoDB Performance Test"); + options.add_options()("r,region", "AWS region", cxxopts::value()->default_value("us-east-1"))( + "i,iterations", "Number of iterations", cxxopts::value()->default_value("10"))( + "c,commit-id", "Commit ID", cxxopts::value()->default_value("unknown"))( + "b,build-mode", "Build mode (debug or release)", cxxopts::value()->default_value("unknown")); + + auto const result = options.parse(argc, argv); + + Aws::String const region = Aws::Utils::StringUtils::to_string(result["region"].as()); + Aws::String const commitId = Aws::Utils::StringUtils::to_string(result["commit-id"].as()); + Aws::String const buildMode = Aws::Utils::StringUtils::to_string(result["build-mode"].as()); + int const iterations = result["iterations"].as(); + + Aws::SDKOptions sdkOptions; + Aws::String const versionStr = Aws::Version::GetVersionString(); + + sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr { + Aws::Set operations; + for (const auto& operation : PerformanceTest::Services::DynamoDB::TestConfig::TestOperations) { + operations.insert(operation); + } + return Aws::MakeUnique( + "JsonReportingMetricsFactory", operations, "cpp1", versionStr, commitId, + PerformanceTest::Services::DynamoDB::TestConfig::OutputFilename, buildMode); + }}; + + Aws::InitAPI(sdkOptions); + + { + for (const auto& testConfig : PerformanceTest::Services::DynamoDB::TestConfig::TestMatrix) { + Aws::Client::ClientConfiguration clientConfig; + clientConfig.region = region; + PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest performanceTest(clientConfig, testConfig, iterations); + auto setupOutcome = performanceTest.Setup(); + if (setupOutcome.IsSuccess()) { + performanceTest.Run(); + } else { + AWS_LOG_ERROR("PerformanceTest", setupOutcome.GetError().c_str()); + } + performanceTest.TearDown(); + } + } + + Aws::ShutdownAPI(sdkOptions); + return 0; +} \ No newline at end of file diff --git a/tests/performance-tests/src/services/s3/S3PerformanceTest.cpp b/tests/performance-tests/src/services/s3/S3PerformanceTest.cpp new file mode 100644 index 00000000000..8e58191f587 --- /dev/null +++ b/tests/performance-tests/src/services/s3/S3PerformanceTest.cpp @@ -0,0 +1,112 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +PerformanceTest::Services::S3::S3PerformanceTest::S3PerformanceTest(const Aws::Client::ClientConfiguration& clientConfig, + const TestConfig::TestCase& testConfig, int iterations, + const Aws::String& availabilityZoneId) + : m_s3(Aws::MakeUnique("S3PerformanceTest", clientConfig)), + m_testConfig(testConfig), + m_iterations(iterations), + m_bucketName(testConfig.bucketType == TestConfig::BucketType::Express + ? "perf-express-" + PerformanceTest::Utils::GenerateUniqueId() + "--" + availabilityZoneId + "--x-s3" + : "perf-standard-" + PerformanceTest::Utils::GenerateUniqueId()), + m_availabilityZoneId(availabilityZoneId) { + assert(m_s3 && "S3 client not initialized"); +} + +Aws::Utils::Outcome PerformanceTest::Services::S3::S3PerformanceTest::Setup() { + Aws::S3::Model::CreateBucketRequest cbr; + cbr.SetBucket(m_bucketName); + + if (m_testConfig.bucketType == TestConfig::BucketType::Express) { + 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); + } + + auto createOutcome = m_s3->CreateBucket(cbr); + if (!createOutcome.IsSuccess()) { + return "S3 Setup() - CreateBucket failed: " + createOutcome.GetError().GetMessage(); + } + return Aws::NoResult(); +} + +void PerformanceTest::Services::S3::S3PerformanceTest::Run() { + const auto randomPayload = PerformanceTest::Utils::RandomString(TestConfig::GetPayloadSizeInBytes(m_testConfig.payloadSize)); + + // Run PutObject multiple times + for (int i = 0; i < m_iterations; i++) { + const auto stream = Aws::MakeShared("PerfStream", 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", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize)); + por.SetAdditionalCustomHeaderValue("test-dimension-bucket-type", TestConfig::GetBucketTypeLabel(m_testConfig.bucketType)); + auto putOutcome = m_s3->PutObject(por); + if (!putOutcome.IsSuccess()) { + AWS_LOG_ERROR("PerformanceTest", ("S3 Run() - 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", TestConfig::GetPayloadSizeLabel(m_testConfig.payloadSize)); + gor.SetAdditionalCustomHeaderValue("test-dimension-bucket-type", TestConfig::GetBucketTypeLabel(m_testConfig.bucketType)); + auto getOutcome = m_s3->GetObject(gor); + if (!getOutcome.IsSuccess()) { + AWS_LOG_ERROR("PerformanceTest", ("S3 Run() - GetObject failed: " + getOutcome.GetError().GetMessage()).c_str()); + } + } +} + +void PerformanceTest::Services::S3::S3PerformanceTest::TearDown() { + 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 TearDown() - 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 TearDown() - DeleteBucket failed: " + deleteBucketOutcome.GetError().GetMessage()).c_str()); + } +} \ No newline at end of file diff --git a/tests/performance-tests/src/services/s3/S3TestConfig.cpp b/tests/performance-tests/src/services/s3/S3TestConfig.cpp new file mode 100644 index 00000000000..2b0b359de8f --- /dev/null +++ b/tests/performance-tests/src/services/s3/S3TestConfig.cpp @@ -0,0 +1,62 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include +#include + +namespace PerformanceTest { +namespace Services { +namespace S3 { +namespace TestConfig { + +const std::array TestOperations = {"PutObject", "GetObject"}; + +const std::array TestMatrix = {{{.payloadSize = PayloadSize::K8, .bucketType = BucketType::Standard}, + {.payloadSize = PayloadSize::K64, .bucketType = BucketType::Standard}, + {.payloadSize = PayloadSize::M1, .bucketType = BucketType::Standard}, + {.payloadSize = PayloadSize::K8, .bucketType = BucketType::Express}, + {.payloadSize = PayloadSize::K64, .bucketType = BucketType::Express}, + {.payloadSize = PayloadSize::M1, .bucketType = BucketType::Express}}}; + +const char* OutputFilename = "s3-performance-test-results.json"; + +size_t GetPayloadSizeInBytes(PayloadSize size) { + switch (size) { + case PayloadSize::K8: + return 8 * 1024; + case PayloadSize::K64: + return 64 * 1024; + case PayloadSize::M1: + return 1024 * 1024; + } +} + +Aws::String GetPayloadSizeLabel(PayloadSize size) { + switch (size) { + case PayloadSize::K8: + return "8KB"; + case PayloadSize::K64: + return "64KB"; + case PayloadSize::M1: + return "1MB"; + } +} + +Aws::String GetBucketTypeLabel(BucketType type) { + switch (type) { + case BucketType::Standard: + return "s3-standard"; + case BucketType::Express: + return "s3-express"; + } +} + +} // namespace TestConfig +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tests/performance-tests/src/services/s3/main.cpp b/tests/performance-tests/src/services/s3/main.cpp new file mode 100644 index 00000000000..566208ac6e8 --- /dev/null +++ b/tests/performance-tests/src/services/s3/main.cpp @@ -0,0 +1,70 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char** argv) { + cxxopts::Options options("s3-perf-test", "S3 Performance Test"); + options.add_options()("r,region", "AWS region", cxxopts::value()->default_value("us-east-1"))( + "a,az-id", "Availability zone ID", cxxopts::value()->default_value("use1-az4"))( + "i,iterations", "Number of iterations", cxxopts::value()->default_value("10"))( + "c,commit-id", "Commit ID", cxxopts::value()->default_value("unknown"))( + "b,build-mode", "Build mode (debug or release)", cxxopts::value()->default_value("unknown")); + + auto const result = options.parse(argc, argv); + + Aws::String const region = Aws::Utils::StringUtils::to_string(result["region"].as()); + Aws::String const availabilityZoneId = Aws::Utils::StringUtils::to_string(result["az-id"].as()); + Aws::String const commitId = Aws::Utils::StringUtils::to_string(result["commit-id"].as()); + Aws::String const buildMode = Aws::Utils::StringUtils::to_string(result["build-mode"].as()); + int const iterations = result["iterations"].as(); + + Aws::SDKOptions sdkOptions; + Aws::String const versionStr = Aws::Version::GetVersionString(); + + sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr { + Aws::Set operations; + for (const auto& operation : PerformanceTest::Services::S3::TestConfig::TestOperations) { + operations.insert(operation); + } + return Aws::MakeUnique( + "JsonReportingMetricsFactory", operations, "cpp1", versionStr, commitId, PerformanceTest::Services::S3::TestConfig::OutputFilename, + buildMode); + }}; + + Aws::InitAPI(sdkOptions); + + { + for (const auto& testConfig : PerformanceTest::Services::S3::TestConfig::TestMatrix) { + Aws::Client::ClientConfiguration clientConfig; + clientConfig.region = region; + PerformanceTest::Services::S3::S3PerformanceTest performanceTest(clientConfig, testConfig, iterations, availabilityZoneId); + auto setupOutcome = performanceTest.Setup(); + if (setupOutcome.IsSuccess()) { + performanceTest.Run(); + } else { + AWS_LOG_ERROR("PerformanceTest", setupOutcome.GetError().c_str()); + } + performanceTest.TearDown(); + } + } + + Aws::ShutdownAPI(sdkOptions); + return 0; +} \ No newline at end of file diff --git a/tools/perf-gen/configs/dynamodb_perf_test.json b/tools/perf-gen/configs/dynamodb_perf_test.json new file mode 100644 index 00000000000..82eb52614ff --- /dev/null +++ b/tools/perf-gen/configs/dynamodb_perf_test.json @@ -0,0 +1,47 @@ +{ + "service": "DynamoDB", + "service_lower": "dynamodb", + "resource_name_variable": "m_tableName", + "operations": [ + "PutItem", + "GetItem" + ], + "test_matrix": [ + { + "sizeLabel": "8KB", + "sizeBytes": "8 * 1024" + }, + { + "sizeLabel": "64KB", + "sizeBytes": "64 * 1024" + }, + { + "sizeLabel": "392KB", + "sizeBytes": "392 * 1024" + } + ], + "output_filename": "dynamodb-performance-test-results.json", + "main_args": [ + { + "name": "region", + "short": "r", + "description": "AWS region", + "type": "std::string", + "default": "us-east-1" + }, + { + "name": "iterations", + "short": "i", + "description": "Number of iterations", + "type": "int", + "default": "10" + }, + { + "name": "commit-id", + "short": "c", + "description": "Commit ID", + "type": "std::string", + "default": "unknown" + } + ] +} \ No newline at end of file diff --git a/tools/perf-gen/configs/s3_perf_test.json b/tools/perf-gen/configs/s3_perf_test.json new file mode 100644 index 00000000000..4d654745853 --- /dev/null +++ b/tools/perf-gen/configs/s3_perf_test.json @@ -0,0 +1,78 @@ +{ + "service": "S3", + "service_lower": "s3", + "resource_name_variable": "m_bucketName", + "operations": [ + "PutObject", + "GetObject" + ], + "constructor_params": [ + { + "type": "const Aws::String&", + "main_arg_name": "az-id" + } + ], + "test_matrix": [ + { + "sizeLabel": "8KB", + "sizeBytes": "8 * 1024", + "bucketTypeLabel": "s3-standard" + }, + { + "sizeLabel": "64KB", + "sizeBytes": "64 * 1024", + "bucketTypeLabel": "s3-standard" + }, + { + "sizeLabel": "1MB", + "sizeBytes": "1024 * 1024", + "bucketTypeLabel": "s3-standard" + }, + { + "sizeLabel": "8KB", + "sizeBytes": "8 * 1024", + "bucketTypeLabel": "s3-express" + }, + { + "sizeLabel": "64KB", + "sizeBytes": "64 * 1024", + "bucketTypeLabel": "s3-express" + }, + { + "sizeLabel": "1MB", + "sizeBytes": "1024 * 1024", + "bucketTypeLabel": "s3-express" + } + ], + "output_filename": "s3-performance-test-results.json", + "main_args": [ + { + "name": "region", + "short": "r", + "description": "AWS region", + "type": "std::string", + "default": "us-east-1" + }, + { + "name": "az-id", + "short": "a", + "description": "Availability zone ID", + "type": "std::string", + "default": "use1-az4" + }, + { + "name": "iterations", + "short": "i", + "description": "Number of iterations", + "type": "int", + "default": "10" + }, + { + "name": "commit-id", + "short": "c", + "description": "Commit ID", + "type": "std::string", + "default": "unknown" + } + ] +} \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h b/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h new file mode 100644 index 00000000000..f2b4add5b6c --- /dev/null +++ b/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBPerformanceTest.h @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { +/** + * Configuration for DynamoDB performance test cases. + */ +struct TestCase { + const char* sizeLabel; + size_t sizeBytes; +}; + +/** + * DynamoDB performance test implementation. + */ +class DynamoDBPerformanceTest : public PerformanceTestBase { + public: + DynamoDBPerformanceTest(const Aws::String& region, const TestCase& config, int iterations = 10); + + Aws::Utils::Outcome Setup() override; + void TearDown() override; + void Run() override; + + private: + const TestCase m_config; + const Aws::String m_region; + const int m_iterations; + Aws::UniquePtr m_dynamodb; + Aws::String m_tableName; +}; + +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h b/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h new file mode 100644 index 00000000000..467b3efa552 --- /dev/null +++ b/tools/perf-gen/performance-tests/include/performance-tests/services/dynamodb/DynamoDBTestConfig.h @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { +namespace TestConfig { +extern const std::array TestOperations; +extern const std::array TestMatrix; +extern const char* OutputFilename; +} // namespace TestConfig +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h b/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h new file mode 100644 index 00000000000..84c4387cad2 --- /dev/null +++ b/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3PerformanceTest.h @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +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. + */ +class S3PerformanceTest : public PerformanceTestBase { + public: + S3PerformanceTest(const Aws::String& region, const TestCase& config, const Aws::String& az_id, int iterations = 10); + + Aws::Utils::Outcome Setup() override; + void TearDown() override; + void Run() override; + + private: + const TestCase m_config; + const Aws::String m_region; + const Aws::String m_az_id; + const int m_iterations; + Aws::UniquePtr m_s3; + Aws::String m_bucketName; +}; + +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3TestConfig.h b/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3TestConfig.h new file mode 100644 index 00000000000..1daa595ba52 --- /dev/null +++ b/tools/perf-gen/performance-tests/include/performance-tests/services/s3/S3TestConfig.h @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace S3 { +namespace TestConfig { +extern const std::array TestOperations; +extern const std::array TestMatrix; +extern const char* OutputFilename; +} // namespace TestConfig +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp b/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp new file mode 100644 index 00000000000..fc05745c0d5 --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBPerformanceTest.cpp @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Include the service-specific AWS SDK headers here. +PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::DynamoDBPerformanceTest(const Aws::String& region, const TestCase& config, int iterations) + : m_config(config), m_region(region), m_iterations(iterations) { + Aws::Client::ClientConfiguration cfg; + cfg.region = m_region; + m_dynamodb = Aws::MakeUnique("DynamoDBPerformanceTest", cfg); +} + +Aws::Utils::Outcome PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Setup() { + // Write resource Setup logic here. + + return true; +} + +void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::Run() { + assert(m_dynamodb && "DynamoDB client not initialized - Setup() must succeed before Run()"); + assert(!m_tableName.empty() && "DynamoDB resource name empty - Setup() must succeed before Run()"); + + // Write Run logic here. +} + +void PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest::TearDown() { + if (!m_dynamodb || m_tableName.empty()) { + return; + } + + // Write resource cleanup (TearDown) logic here. +} \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp b/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp new file mode 100644 index 00000000000..06e10084c27 --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/dynamodb/DynamoDBTestConfig.cpp @@ -0,0 +1,25 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace DynamoDB { +namespace TestConfig { + +const std::array TestOperations = {"PutItem", "GetItem"}; + +const std::array TestMatrix = {{{.sizeLabel = "8KB", .sizeBytes = 8 * 1024},{.sizeLabel = "64KB", .sizeBytes = 64 * 1024},{.sizeLabel = "392KB", .sizeBytes = 392 * 1024}}}; + +const char* OutputFilename = "dynamodb-performance-test-results.json"; + +} // namespace TestConfig +} // namespace DynamoDB +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/dynamodb/main.cpp b/tools/perf-gen/performance-tests/src/services/dynamodb/main.cpp new file mode 100644 index 00000000000..211e1748d6a --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/dynamodb/main.cpp @@ -0,0 +1,61 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char** argv) { + cxxopts::Options options("dynamodb-perf-test", "DynamoDB Performance Test"); + options.add_options()("r,region", "AWS region", cxxopts::value()->default_value("us-east-1"))("i,iterations", "Number of iterations", cxxopts::value()->default_value("10"))("c,commit-id", "Commit ID", cxxopts::value()->default_value("unknown")); + + auto const result = options.parse(argc, argv); + + Aws::String const region = Aws::Utils::StringUtils::to_string(result["region"].as()); + int const iterations = result["iterations"].as(); + Aws::String const commit_id = Aws::Utils::StringUtils::to_string(result["commit-id"].as()); + + Aws::SDKOptions sdkOptions; + Aws::String const versionStr = Aws::Version::GetVersionString(); + + sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr { + Aws::Set operations; + for (const auto& operation : PerformanceTest::Services::DynamoDB::TestConfig::TestOperations) { + operations.insert(operation); + } + return Aws::MakeUnique( + "JsonReportingMetricsFactory", operations, "cpp1", versionStr, commit_id, PerformanceTest::Services::DynamoDB::TestConfig::OutputFilename); + }}; + + Aws::InitAPI(sdkOptions); + + { + for (const auto& config : PerformanceTest::Services::DynamoDB::TestConfig::TestMatrix) { + PerformanceTest::Services::DynamoDB::DynamoDBPerformanceTest performanceTest(region, config, iterations); + auto setupResult = performanceTest.Setup(); + if (setupResult.IsSuccess()) { + performanceTest.Run(); + } else { + AWS_LOG_ERROR("PerformanceTest", setupResult.GetError().message.c_str()); + } + performanceTest.TearDown(); + } + } + + Aws::ShutdownAPI(sdkOptions); + return 0; +} \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/s3/S3PerformanceTest.cpp b/tools/perf-gen/performance-tests/src/services/s3/S3PerformanceTest.cpp new file mode 100644 index 00000000000..c543604a173 --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/s3/S3PerformanceTest.cpp @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Include the service-specific AWS SDK headers here. +PerformanceTest::Services::S3::S3PerformanceTest::S3PerformanceTest(const Aws::String& region, const TestCase& config, const Aws::String& az_id, int iterations) + : m_config(config), m_region(region), m_az_id(az_id), m_iterations(iterations) { + Aws::Client::ClientConfiguration cfg; + cfg.region = m_region; + m_s3 = Aws::MakeUnique("S3PerformanceTest", cfg); +} + +Aws::Utils::Outcome PerformanceTest::Services::S3::S3PerformanceTest::Setup() { + // Write resource Setup logic here. + + return true; +} + +void PerformanceTest::Services::S3::S3PerformanceTest::Run() { + assert(m_s3 && "S3 client not initialized - Setup() must succeed before Run()"); + assert(!m_bucketName.empty() && "S3 resource name empty - Setup() must succeed before Run()"); + + // Write Run logic here. +} + +void PerformanceTest::Services::S3::S3PerformanceTest::TearDown() { + if (!m_s3 || m_bucketName.empty()) { + return; + } + + // Write resource cleanup (TearDown) logic here. +} \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/s3/S3TestConfig.cpp b/tools/perf-gen/performance-tests/src/services/s3/S3TestConfig.cpp new file mode 100644 index 00000000000..f19ecc4cde8 --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/s3/S3TestConfig.cpp @@ -0,0 +1,25 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace S3 { +namespace TestConfig { + +const std::array TestOperations = {"PutObject", "GetObject"}; + +const std::array TestMatrix = {{{.sizeLabel = "8KB", .sizeBytes = 8 * 1024, .bucketTypeLabel = "s3-standard"},{.sizeLabel = "64KB", .sizeBytes = 64 * 1024, .bucketTypeLabel = "s3-standard"},{.sizeLabel = "1MB", .sizeBytes = 1024 * 1024, .bucketTypeLabel = "s3-standard"},{.sizeLabel = "8KB", .sizeBytes = 8 * 1024, .bucketTypeLabel = "s3-express"},{.sizeLabel = "64KB", .sizeBytes = 64 * 1024, .bucketTypeLabel = "s3-express"},{.sizeLabel = "1MB", .sizeBytes = 1024 * 1024, .bucketTypeLabel = "s3-express"}}}; + +const char* OutputFilename = "s3-performance-test-results.json"; + +} // namespace TestConfig +} // namespace S3 +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/performance-tests/src/services/s3/main.cpp b/tools/perf-gen/performance-tests/src/services/s3/main.cpp new file mode 100644 index 00000000000..10a60b720aa --- /dev/null +++ b/tools/perf-gen/performance-tests/src/services/s3/main.cpp @@ -0,0 +1,62 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char** argv) { + cxxopts::Options options("s3-perf-test", "S3 Performance Test"); + options.add_options()("r,region", "AWS region", cxxopts::value()->default_value("us-east-1"))("a,az-id", "Availability zone ID", cxxopts::value()->default_value("use1-az4"))("i,iterations", "Number of iterations", cxxopts::value()->default_value("10"))("c,commit-id", "Commit ID", cxxopts::value()->default_value("unknown")); + + auto const result = options.parse(argc, argv); + + Aws::String const region = Aws::Utils::StringUtils::to_string(result["region"].as()); + Aws::String const az_id = Aws::Utils::StringUtils::to_string(result["az-id"].as()); + int const iterations = result["iterations"].as(); + Aws::String const commit_id = Aws::Utils::StringUtils::to_string(result["commit-id"].as()); + + Aws::SDKOptions sdkOptions; + Aws::String const versionStr = Aws::Version::GetVersionString(); + + sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr { + Aws::Set operations; + for (const auto& operation : PerformanceTest::Services::S3::TestConfig::TestOperations) { + operations.insert(operation); + } + return Aws::MakeUnique( + "JsonReportingMetricsFactory", operations, "cpp1", versionStr, commit_id, PerformanceTest::Services::S3::TestConfig::OutputFilename); + }}; + + Aws::InitAPI(sdkOptions); + + { + for (const auto& config : PerformanceTest::Services::S3::TestConfig::TestMatrix) { + PerformanceTest::Services::S3::S3PerformanceTest performanceTest(region, config, az_id, iterations); + auto setupResult = performanceTest.Setup(); + if (setupResult.IsSuccess()) { + performanceTest.Run(); + } else { + AWS_LOG_ERROR("PerformanceTest", setupResult.GetError().message.c_str()); + } + performanceTest.TearDown(); + } + } + + Aws::ShutdownAPI(sdkOptions); + return 0; +} \ No newline at end of file diff --git a/tools/perf-gen/performance_test_generator.py b/tools/perf-gen/performance_test_generator.py new file mode 100644 index 00000000000..eae5e6d2de9 --- /dev/null +++ b/tools/perf-gen/performance_test_generator.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +import os +import json +from jinja2 import Environment, FileSystemLoader, select_autoescape +import argparse + +def generate_performance_test(config_path, template_dir, output_dir): + with open(config_path, 'r', encoding='utf-8') as f: + config = json.load(f) + + service_name = config['service'] + service_lower = config['service_lower'] + + env = Environment( + loader=FileSystemLoader(template_dir), + trim_blocks=True, + lstrip_blocks=True, + autoescape=select_autoescape(['html', 'xml']) + ) + + service_src_dir = os.path.join(output_dir, f"performance-tests/src/services/{service_lower}") + service_include_dir = os.path.join(output_dir, f"performance-tests/include/performance-tests/services/{service_lower}") + + os.makedirs(service_src_dir, exist_ok=True) + os.makedirs(service_include_dir, exist_ok=True) + + templates_to_render = { + 'main.cpp.j2': os.path.join(service_src_dir, 'main.cpp'), + 'PerformanceTest.h.j2': os.path.join(service_include_dir, f'{service_name}PerformanceTest.h'), + 'PerformanceTest.cpp.j2': os.path.join(service_src_dir, f'{service_name}PerformanceTest.cpp'), + 'TestConfig.h.j2': os.path.join(service_include_dir, f'{service_name}TestConfig.h'), + 'TestConfig.cpp.j2': os.path.join(service_src_dir, f'{service_name}TestConfig.cpp'), + } + + for template_file, output_path in templates_to_render.items(): + template = env.get_template(template_file) + rendered_content = template.render(config) + with open(output_path, 'w', encoding='utf-8') as f: + f.write(rendered_content) + print(f"Successfully generated file: {output_path}") + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Generate a performance test framework for the AWS C++ SDK.') + parser.add_argument('--config', required=True, help='Path to the service JSON configuration file.') + parser.add_argument('--templates', default='templates', help='Path to the directory containing Jinja2 templates.') + parser.add_argument('--output', default='.', help='The root output directory for the generated code.') + + args = parser.parse_args() + + if not os.path.exists(args.config): + print(f"Error: Configuration file '{args.config}' not found.") + exit(1) + + generate_performance_test(args.config, args.templates, args.output) \ No newline at end of file diff --git a/tools/perf-gen/templates/PerformanceTest.cpp.j2 b/tools/perf-gen/templates/PerformanceTest.cpp.j2 new file mode 100644 index 00000000000..1e6d4fbe5cb --- /dev/null +++ b/tools/perf-gen/templates/PerformanceTest.cpp.j2 @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Include the service-specific AWS SDK headers here. +PerformanceTest::Services::{{ service }}::{{ service }}PerformanceTest::{{ service }}PerformanceTest(const Aws::String& region, const TestCase& config, {% if constructor_params %}{% for param in constructor_params %}{{ param.type }} {{ param.main_arg_name | replace('-', '_') }}{% if not loop.last %}, {% endif %}{% endfor %}, {% endif %}int iterations) + : m_config(config), m_region(region){% if constructor_params %}, {% for param in constructor_params %}m_{{ param.main_arg_name | replace('-', '_') }}({{ param.main_arg_name | replace('-', '_') }}){% if not loop.last %}, {% endif %}{% endfor %}{% endif %}, m_iterations(iterations) { + Aws::Client::ClientConfiguration cfg; + cfg.region = m_region; + m_{{ service_lower }} = Aws::MakeUnique("{{ service }}PerformanceTest", cfg); +} + +Aws::Utils::Outcome PerformanceTest::Services::{{ service }}::{{ service }}PerformanceTest::Setup() { + // Write resource Setup logic here. + + return true; +} + +void PerformanceTest::Services::{{ service }}::{{ service }}PerformanceTest::Run() { + assert(m_{{ service_lower }} && "{{ service }} client not initialized - Setup() must succeed before Run()"); + assert(!{{ resource_name_variable }}.empty() && "{{ service }} resource name empty - Setup() must succeed before Run()"); + + // Write Run logic here. +} + +void PerformanceTest::Services::{{ service }}::{{ service }}PerformanceTest::TearDown() { + if (!m_{{ service_lower }} || {{ resource_name_variable }}.empty()) { + return; + } + + // Write resource cleanup (TearDown) logic here. +} \ No newline at end of file diff --git a/tools/perf-gen/templates/PerformanceTest.h.j2 b/tools/perf-gen/templates/PerformanceTest.h.j2 new file mode 100644 index 00000000000..9ce09bf0473 --- /dev/null +++ b/tools/perf-gen/templates/PerformanceTest.h.j2 @@ -0,0 +1,58 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace {{ service }} { +/** + * Configuration for {{ service }} performance test cases. + */ +struct TestCase { +{% for key in test_matrix[0].keys() %} +{% if key.endswith("Bytes") %} + size_t {{ key }}; +{% else %} + const char* {{ key }}; +{% endif %} +{% endfor %} +}; + +/** + * {{ service }} performance test implementation. + */ +class {{ service }}PerformanceTest : public PerformanceTestBase { + public: + {{ service }}PerformanceTest(const Aws::String& region, const TestCase& config, {% if constructor_params %}{% for param in constructor_params %}{{ param.type }} {{ param.main_arg_name | replace('-', '_') }}{% if not loop.last %}, {% endif %}{% endfor %}, {% endif %}int iterations = 10); + + Aws::Utils::Outcome Setup() override; + void TearDown() override; + void Run() override; + + private: + const TestCase m_config; + const Aws::String m_region; +{% if constructor_params %} +{% for param in constructor_params %} + const Aws::String m_{{ param.main_arg_name | replace('-', '_') }}; +{% endfor %} +{% endif %} + const int m_iterations; + Aws::UniquePtr m_{{ service_lower }}; + Aws::String {{ resource_name_variable }}; +}; + +} // namespace {{ service }} +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/templates/TestConfig.cpp.j2 b/tools/perf-gen/templates/TestConfig.cpp.j2 new file mode 100644 index 00000000000..f6a50b371e8 --- /dev/null +++ b/tools/perf-gen/templates/TestConfig.cpp.j2 @@ -0,0 +1,37 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace {{ service }} { +namespace TestConfig { + +const std::array TestOperations = { +{%- for op in operations -%} +"{{ op }}"{% if not loop.last %}, {% endif %} +{%- endfor -%} +}; + +const std::array TestMatrix = {% raw %}{{% endraw %}{% raw %}{{% endraw %} +{% for item in test_matrix %} +{ +{%- for key, value in item.items() -%} +.{{ key }} = {% if key.endswith('Bytes') %}{{ value }}{% else %}"{{ value }}"{% endif %}{% if not loop.last %}, {% endif %} +{%- endfor -%} +}{% if not loop.last %},{% endif %} +{% endfor %} +{% raw %}}{% endraw %}{% raw %}}{% endraw %}; + +const char* OutputFilename = "{{ output_filename }}"; + +} // namespace TestConfig +} // namespace {{ service }} +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/templates/TestConfig.h.j2 b/tools/perf-gen/templates/TestConfig.h.j2 new file mode 100644 index 00000000000..9708cb6b68d --- /dev/null +++ b/tools/perf-gen/templates/TestConfig.h.j2 @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include + +#include + +namespace PerformanceTest { +namespace Services { +namespace {{ service }} { +namespace TestConfig { +extern const std::array TestOperations; +extern const std::array TestMatrix; +extern const char* OutputFilename; +} // namespace TestConfig +} // namespace {{ service }} +} // namespace Services +} // namespace PerformanceTest \ No newline at end of file diff --git a/tools/perf-gen/templates/main.cpp.j2 b/tools/perf-gen/templates/main.cpp.j2 new file mode 100644 index 00000000000..044583fd6e0 --- /dev/null +++ b/tools/perf-gen/templates/main.cpp.j2 @@ -0,0 +1,69 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char** argv) { + cxxopts::Options options("{{ service_lower }}-perf-test", "{{ service }} Performance Test"); + options.add_options() +{%- for arg in main_args -%} +("{{ arg.short }},{{ arg.name }}", "{{ arg.description }}", cxxopts::value<{{ arg.type }}>()->default_value("{{ arg.default }}")) +{%- endfor -%} +; + + auto const result = options.parse(argc, argv); + +{% for arg in main_args %} +{% if arg.type == 'int' %} + int const {{ arg.name | replace('-', '_') }} = result["{{ arg.name }}"].as(); +{% else %} + Aws::String const {{ arg.name | replace('-', '_') }} = Aws::Utils::StringUtils::to_string(result["{{ arg.name }}"].as()); +{% endif %} +{% endfor %} + + Aws::SDKOptions sdkOptions; + Aws::String const versionStr = Aws::Version::GetVersionString(); + + sdkOptions.monitoringOptions.customizedMonitoringFactory_create_fn = {[&]() -> Aws::UniquePtr { + Aws::Set operations; + for (const auto& operation : PerformanceTest::Services::{{ service }}::TestConfig::TestOperations) { + operations.insert(operation); + } + return Aws::MakeUnique( + "JsonReportingMetricsFactory", operations, "cpp1", versionStr, commit_id, PerformanceTest::Services::{{ service }}::TestConfig::OutputFilename); + }}; + + Aws::InitAPI(sdkOptions); + + { + for (const auto& config : PerformanceTest::Services::{{ service }}::TestConfig::TestMatrix) { + PerformanceTest::Services::{{ service }}::{{ service }}PerformanceTest performanceTest(region, config, {% if constructor_params %}{% for param in constructor_params %}{{ param.main_arg_name | replace('-', '_') }}{% if not loop.last %}, {% endif %}{% endfor %}, {% endif %}iterations); + auto setupResult = performanceTest.Setup(); + if (setupResult.IsSuccess()) { + performanceTest.Run(); + } else { + AWS_LOG_ERROR("PerformanceTest", setupResult.GetError().message.c_str()); + } + performanceTest.TearDown(); + } + } + + Aws::ShutdownAPI(sdkOptions); + return 0; +} \ No newline at end of file diff --git a/tools/scripts/build-tests/build-al2-debug-default.sh b/tools/scripts/build-tests/build-al2-debug-default.sh index 39c63d0f32f..f3b6408be94 100755 --- a/tools/scripts/build-tests/build-al2-debug-default.sh +++ b/tools/scripts/build-tests/build-al2-debug-default.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-ggdb -fsanitize=address" -DMINIMIZE_SIZE=ON -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" +cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-ggdb -fsanitize=address" -DMINIMIZE_SIZE=ON -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DBUILD_PERFORMANCE_TESTS=ON ninja-build -j $(grep -c ^processor /proc/cpuinfo) ninja-build install diff --git a/tools/scripts/build-tests/run-al2-dynamodb-performance-tests.sh b/tools/scripts/build-tests/run-al2-dynamodb-performance-tests.sh new file mode 100644 index 00000000000..642e33ff784 --- /dev/null +++ b/tools/scripts/build-tests/run-al2-dynamodb-performance-tests.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. + +# This script runs the pre-built DynamoDB performance test executable +# Expects SDK build directory at ${PREFIX_DIR}/al2-build, source project at ${PREFIX_DIR}/aws-sdk-cpp, +# and SDK installation directory at ${PREFIX_DIR}/al2-install +# Platform: Amazon Linux 2 + +set -e + +DEFAULT_REGION="us-east-1" +DEFAULT_ITERATIONS=10 +DEFAULT_BUILD_MODE="unknown" + +if [ "$#" -lt 1 ]; then + echo "Error: Missing required argument. Usage: ${0} PREFIX_DIR [-r|--region REGION] [-i|--iterations NUM] [-b|--build-mode BUILD_MODE]" + exit 1 +fi + +PREFIX_DIR="$1" +shift + +REGION="$DEFAULT_REGION" +ITERATIONS="$DEFAULT_ITERATIONS" +BUILD_MODE="$DEFAULT_BUILD_MODE" + +while [[ "$#" -gt 0 ]]; do + case "$1" in + -r|--region) REGION="$2"; shift 2 ;; + -i|--iterations) ITERATIONS="$2"; shift 2 ;; + -b|--build-mode) BUILD_MODE="$2"; shift 2 ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac +done + +SDK_REPO_PATH="${PREFIX_DIR}/aws-sdk-cpp" +if [ -d "$SDK_REPO_PATH" ]; then + COMMIT_ID=$(cd "$SDK_REPO_PATH" && git rev-parse HEAD) +else + echo "Error: Git repository not found at $SDK_REPO_PATH" + exit 1 +fi + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${PREFIX_DIR}/al2-install/lib64/" + +cd "${PREFIX_DIR}/al2-build" +if [ "$BUILD_MODE" = "debug" ] && [ -f "${PREFIX_DIR}/aws-sdk-cpp/tools/scripts/suppressions.txt" ]; then + export LSAN_OPTIONS=suppressions="${PREFIX_DIR}/aws-sdk-cpp/tools/scripts/suppressions.txt" +fi +./tests/performance-tests/dynamodb-performance-test --region "$REGION" --iterations "$ITERATIONS" --commit-id "$COMMIT_ID" --build-mode "$BUILD_MODE" +cat dynamodb-performance-test-results.json \ No newline at end of file diff --git a/tools/scripts/build-tests/run-al2-integ-tests.sh b/tools/scripts/build-tests/run-al2-integ-tests.sh index ac8ee3af18a..153e87feb45 100755 --- a/tools/scripts/build-tests/run-al2-integ-tests.sh +++ b/tools/scripts/build-tests/run-al2-integ-tests.sh @@ -21,7 +21,7 @@ AWS_ROLE_SESSION_NAME="$3" echo "Setting the run environment" export TEST_ASSUME_ROLE_ARN=arn:aws:iam::${AWS_ACCOUNT}:role/IntegrationTest -export TEST_LAMBDA_CODE_PATH=${PREFIX_DIR}/aws-sdk-cpp/tests/aws-cpp-sdk-lambda-integration-tests/resources +export TEST_LAMBDA_CODE_PATH=${PREFIX_DIR}/aws-sdk-cpp/tools/aws-cpp-sdk-lambda-integration-tests/resources export sts=$(aws sts assume-role --role-arn "$TEST_ASSUME_ROLE_ARN" --role-session-name "${AWS_ROLE_SESSION_NAME}" --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]') export profile=sdk-integ-test aws configure set aws_access_key_id $(echo "$sts" | jq -r '.[0]') --profile "$profile" diff --git a/tools/scripts/build-tests/run-al2-s3-performance-tests.sh b/tools/scripts/build-tests/run-al2-s3-performance-tests.sh new file mode 100644 index 00000000000..06674abfa1f --- /dev/null +++ b/tools/scripts/build-tests/run-al2-s3-performance-tests.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. + +# This script runs the pre-built S3 performance test executable +# Expects SDK build directory at ${PREFIX_DIR}/al2-build, source project at ${PREFIX_DIR}/aws-sdk-cpp, +# and SDK installation directory at ${PREFIX_DIR}/al2-install +# Platform: Amazon Linux 2 + +set -e + +DEFAULT_REGION="us-east-1" +DEFAULT_AZ_ID="use1-az4" +DEFAULT_ITERATIONS=10 +DEFAULT_BUILD_MODE="unknown" + +if [ "$#" -lt 1 ]; then + echo "Error: Missing required argument. Usage: ${0} PREFIX_DIR [-r|--region REGION] [-a|--az-id AZ_ID] [-i|--iterations NUM] [-b|--build-mode BUILD_MODE]" + exit 1 +fi + +PREFIX_DIR="$1" +shift + +REGION="$DEFAULT_REGION" +AZ_ID="$DEFAULT_AZ_ID" +ITERATIONS="$DEFAULT_ITERATIONS" +BUILD_MODE="$DEFAULT_BUILD_MODE" + +while [[ "$#" -gt 0 ]]; do + case "$1" in + -r|--region) REGION="$2"; shift 2 ;; + -a|--az-id) AZ_ID="$2"; shift 2 ;; + -i|--iterations) ITERATIONS="$2"; shift 2 ;; + -b|--build-mode) BUILD_MODE="$2"; shift 2 ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac +done + +SDK_REPO_PATH="${PREFIX_DIR}/aws-sdk-cpp" +if [ -d "$SDK_REPO_PATH" ]; then + COMMIT_ID=$(cd "$SDK_REPO_PATH" && git rev-parse HEAD) +else + echo "Error: Git repository not found at $SDK_REPO_PATH" + exit 1 +fi + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${PREFIX_DIR}/al2-install/lib64/" + +cd "${PREFIX_DIR}/al2-build" +if [ "$BUILD_MODE" = "debug" ] && [ -f "${PREFIX_DIR}/aws-sdk-cpp/tools/scripts/suppressions.txt" ]; then + export LSAN_OPTIONS=suppressions="${PREFIX_DIR}/aws-sdk-cpp/tools/scripts/suppressions.txt" +fi +./tests/performance-tests/s3-performance-test --region "$REGION" --az-id "$AZ_ID" --iterations "$ITERATIONS" --commit-id "$COMMIT_ID" --build-mode "$BUILD_MODE" +cat s3-performance-test-results.json \ No newline at end of file diff --git a/tools/scripts/endpoints_checker.py b/tools/scripts/endpoints_checker.py index 80fc38170d0..7d14ad11089 100644 --- a/tools/scripts/endpoints_checker.py +++ b/tools/scripts/endpoints_checker.py @@ -47,6 +47,7 @@ def skip_file(filename): '|.*source/[^/]+Endpoint.cpp' '|.*aws-cpp-sdk-core/include/aws/core/Region.h' '|.*tests/.*Test.cpp' + '|.*tools/perf-gen/' # add more white lists here ) if skip_file_pattern.match(filename): diff --git a/tools/scripts/run_integration_tests.py b/tools/scripts/run_integration_tests.py index 0c7125e53f8..8c9081615f9 100644 --- a/tools/scripts/run_integration_tests.py +++ b/tools/scripts/run_integration_tests.py @@ -45,7 +45,7 @@ def main(): "aws-cpp-sdk-s3-unit-tests", "aws-cpp-sdk-s3-crt-integration-tests", #"aws-cpp-sdk-s3control-integration-tests", - "aws-cpp-sdk-lambda-integration-tests", + #"aws-cpp-sdk-lambda-integration-tests", "aws-cpp-sdk-cognitoidentity-integration-tests", #"aws-cpp-sdk-transfer-tests", #"aws-cpp-sdk-s3-encryption-integration-tests", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy