Skip to content

Commit b7eba3a

Browse files
committed
changes based on PR comments
1 parent a6e80c4 commit b7eba3a

File tree

3 files changed

+78
-53
lines changed

3 files changed

+78
-53
lines changed

tests/performance-tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function(add_service_test SERVICE SDK_LIB PERF_TEST_FILE)
1919
set_compiler_warnings(${SERVICE}-performance-test)
2020
target_include_directories(${SERVICE}-performance-test PRIVATE include)
2121
target_link_libraries(${SERVICE}-performance-test PRIVATE aws-cpp-sdk-core ${SDK_LIB})
22+
target_compile_options(${SERVICE}-performance-test PRIVATE -std=c++17)
2223
endfunction()
2324

2425
add_service_test(s3 aws-cpp-sdk-s3 S3PerformanceTest.cpp)

tests/performance-tests/include/performance-tests/reporting/JsonReportingMetrics.h

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <aws/core/monitoring/MonitoringFactory.h>
1212
#include <aws/core/monitoring/MonitoringInterface.h>
1313
#include <aws/core/utils/DateTime.h>
14+
#include <aws/core/utils/json/JsonSerializer.h>
1415
#include <aws/core/utils/memory/AWSMemory.h>
1516
#include <aws/core/utils/memory/stl/AWSMap.h>
1617
#include <aws/core/utils/memory/stl/AWSSet.h>
@@ -19,30 +20,10 @@
1920

2021
#include <cstdint>
2122
#include <memory>
23+
#include <variant>
2224

2325
namespace PerformanceTest {
2426
namespace Reporting {
25-
/**
26-
* A measurement value that supports different numeric types.
27-
*/
28-
class Measurement {
29-
public:
30-
enum Type { INTEGER, DOUBLE };
31-
32-
Measurement(int64_t value) : m_type(INTEGER) { m_data.i = value; }
33-
Measurement(double value) : m_type(DOUBLE) { m_data.d = value; }
34-
bool IsInt64() const { return m_type == INTEGER; }
35-
bool IsDouble() const { return m_type == DOUBLE; }
36-
int64_t AsInt64() const { return m_type == INTEGER ? m_data.i : static_cast<int64_t>(m_data.d); }
37-
double AsDouble() const { return m_type == DOUBLE ? m_data.d : static_cast<double>(m_data.i); }
38-
39-
private:
40-
Type m_type;
41-
union {
42-
int64_t i;
43-
double d;
44-
} m_data;
45-
};
4627

4728
/**
4829
* Container for a single performance metric record that stores measurement data and associated metadata.
@@ -52,7 +33,7 @@ struct PerformanceMetricRecord {
5233
Aws::String description;
5334
Aws::String unit;
5435
Aws::Utils::DateTime date;
55-
Aws::Vector<Measurement> measurements;
36+
Aws::Vector<std::variant<int64_t, double>> measurements;
5637
Aws::Map<Aws::String, Aws::String> dimensions;
5738
};
5839

@@ -134,29 +115,46 @@ class JsonReportingMetrics : public Aws::Monitoring::MonitoringInterface {
134115

135116
private:
136117
/**
137-
* Adds a performance record with a specified duration.
138-
* @param serviceName Name of the AWS service (e.g., "S3", "DynamoDB")
139-
* @param requestName Name of the operation (e.g., "PutObject", "GetItem")
118+
* Helper method to process request metrics and store in context.
119+
* @param serviceName Name of the AWS service
120+
* @param requestName Name of the operation
121+
* @param request HTTP request object
140122
* @param metricsFromCore Core metrics collection containing latency data
141-
* @param request HTTP request object (optional, for extracting test metadata)
142-
* @param durationMs Duration of the request in milliseconds (default: 0)
123+
* @param context Request context
124+
*/
125+
void StoreLatencyInContext(const Aws::String& serviceName, const Aws::String& requestName,
126+
const std::shared_ptr<const Aws::Http::HttpRequest>& request,
127+
const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const;
128+
129+
/**
130+
* Adds a performance record with a specified duration.
131+
* @param serviceName Name of the AWS service
132+
* @param requestName Name of the operation
133+
* @param request HTTP request object
134+
* @param durationMs Duration of the request in milliseconds
143135
*/
144136
void AddPerformanceRecord(const Aws::String& serviceName, const Aws::String& requestName,
145-
const Aws::Monitoring::CoreMetricsCollection& metricsFromCore,
146-
const std::shared_ptr<const Aws::Http::HttpRequest>& request = nullptr, int64_t durationMs = 0) const;
137+
const std::shared_ptr<const Aws::Http::HttpRequest>& request, const std::variant<int64_t, double>& durationMs) const;
147138

148139
/**
149140
* Outputs aggregated performance metrics to JSON file.
150141
* Groups records by name and dimensions, then writes to configured output file.
151142
*/
152143
void DumpJson() const;
153144

145+
/**
146+
* Writes JSON to the output file.
147+
* @param root The JSON root object to write
148+
*/
149+
void WriteJsonToFile(const Aws::Utils::Json::JsonValue& root) const;
150+
154151
mutable Aws::Vector<PerformanceMetricRecord> m_performanceRecords;
155152
Aws::Set<Aws::String> m_monitoredOperations;
156153
Aws::String m_productId;
157154
Aws::String m_sdkVersion;
158155
Aws::String m_commitId;
159156
Aws::String m_outputFilename;
157+
mutable bool m_hasInvalidLatency;
160158
};
161159

162160
/**

tests/performance-tests/src/reporting/JsonReportingMetrics.cpp

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@
2323
#include <fstream>
2424
#include <memory>
2525
#include <utility>
26+
#include <variant>
2627

2728
using namespace PerformanceTest::Reporting;
2829

2930
struct RequestContext {
30-
Aws::Utils::DateTime requestStartTime;
31+
Aws::String serviceName;
32+
Aws::String requestName;
33+
std::shared_ptr<const Aws::Http::HttpRequest> request;
34+
std::variant<int64_t, double> durationMs = int64_t(0);
3135
};
3236

3337
JsonReportingMetrics::JsonReportingMetrics(const Aws::Set<Aws::String>& monitoredOperations, const Aws::String& productId,
@@ -36,7 +40,10 @@ JsonReportingMetrics::JsonReportingMetrics(const Aws::Set<Aws::String>& monitore
3640
m_productId(productId),
3741
m_sdkVersion(sdkVersion),
3842
m_commitId(commitId),
39-
m_outputFilename(outputFilename) {}
43+
m_outputFilename(outputFilename),
44+
m_hasInvalidLatency(false) {}
45+
46+
JsonReportingMetrics::~JsonReportingMetrics() { DumpJson(); }
4047

4148
JsonReportingMetricsFactory::JsonReportingMetricsFactory(const Aws::Set<Aws::String>& monitoredOperations, const Aws::String& productId,
4249
const Aws::String& sdkVersion, const Aws::String& commitId,
@@ -47,16 +54,30 @@ JsonReportingMetricsFactory::JsonReportingMetricsFactory(const Aws::Set<Aws::Str
4754
m_commitId(commitId),
4855
m_outputFilename(outputFilename) {}
4956

50-
JsonReportingMetrics::~JsonReportingMetrics() { DumpJson(); }
51-
5257
Aws::UniquePtr<Aws::Monitoring::MonitoringInterface> JsonReportingMetricsFactory::CreateMonitoringInstance() const {
5358
return Aws::MakeUnique<JsonReportingMetrics>("JsonReportingMetrics", m_monitoredOperations, m_productId, m_sdkVersion, m_commitId,
5459
m_outputFilename);
5560
}
5661

62+
void JsonReportingMetrics::StoreLatencyInContext(const Aws::String& serviceName, const Aws::String& requestName,
63+
const std::shared_ptr<const Aws::Http::HttpRequest>& request,
64+
const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const {
65+
RequestContext* requestContext = static_cast<RequestContext*>(context);
66+
67+
Aws::String const latencyKey = Aws::Monitoring::GetHttpClientMetricNameByType(Aws::Monitoring::HttpClientMetricsType::RequestLatency);
68+
auto iterator = metricsFromCore.httpClientMetrics.find(latencyKey);
69+
if (iterator != metricsFromCore.httpClientMetrics.end() && iterator->second > 0) {
70+
requestContext->serviceName = serviceName;
71+
requestContext->requestName = requestName;
72+
requestContext->request = request;
73+
requestContext->durationMs = iterator->second;
74+
} else {
75+
m_hasInvalidLatency = true;
76+
}
77+
}
78+
5779
void JsonReportingMetrics::AddPerformanceRecord(const Aws::String& serviceName, const Aws::String& requestName,
58-
const Aws::Monitoring::CoreMetricsCollection&,
59-
const std::shared_ptr<const Aws::Http::HttpRequest>& request, int64_t durationMs) const {
80+
const std::shared_ptr<const Aws::Http::HttpRequest>& request, const std::variant<int64_t, double>& durationMs) const {
6081
// If no operations are registered, monitor all operations. Otherwise, only monitor registered operations
6182
if (!m_monitoredOperations.empty() && m_monitoredOperations.find(requestName) == m_monitoredOperations.end()) {
6283
return;
@@ -85,27 +106,22 @@ void JsonReportingMetrics::AddPerformanceRecord(const Aws::String& serviceName,
85106

86107
void* JsonReportingMetrics::OnRequestStarted(const Aws::String&, const Aws::String&,
87108
const std::shared_ptr<const Aws::Http::HttpRequest>&) const {
88-
auto context = Aws::New<RequestContext>("JsonReportingMetrics");
89-
context->requestStartTime = Aws::Utils::DateTime::Now();
109+
auto context = Aws::New<RequestContext>("RequestContext");
90110
return context;
91111
}
92112

93113
void JsonReportingMetrics::OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName,
94114
const std::shared_ptr<const Aws::Http::HttpRequest>& request,
95115
const Aws::Client::HttpResponseOutcome&,
96116
const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const {
97-
RequestContext* requestContext = static_cast<RequestContext*>(context);
98-
int64_t durationMs = (Aws::Utils::DateTime::Now() - requestContext->requestStartTime).count();
99-
AddPerformanceRecord(serviceName, requestName, metricsFromCore, request, durationMs);
117+
StoreLatencyInContext(serviceName, requestName, request, metricsFromCore, context);
100118
}
101119

102120
void JsonReportingMetrics::OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName,
103121
const std::shared_ptr<const Aws::Http::HttpRequest>& request,
104122
const Aws::Client::HttpResponseOutcome&,
105123
const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void* context) const {
106-
RequestContext* requestContext = static_cast<RequestContext*>(context);
107-
int64_t durationMs = (Aws::Utils::DateTime::Now() - requestContext->requestStartTime).count();
108-
AddPerformanceRecord(serviceName, requestName, metricsFromCore, request, durationMs);
124+
StoreLatencyInContext(serviceName, requestName, request, metricsFromCore, context);
109125
}
110126

111127
void JsonReportingMetrics::OnRequestRetry(const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
@@ -114,11 +130,24 @@ void JsonReportingMetrics::OnRequestRetry(const Aws::String&, const Aws::String&
114130
void JsonReportingMetrics::OnFinish(const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
115131
void* context) const {
116132
RequestContext* requestContext = static_cast<RequestContext*>(context);
133+
134+
if (std::visit([](auto&& v) { return v > 0; }, requestContext->durationMs)) {
135+
AddPerformanceRecord(requestContext->serviceName, requestContext->requestName, requestContext->request, requestContext->durationMs);
136+
}
137+
117138
Aws::Delete(requestContext);
118139
}
119140

120141
void JsonReportingMetrics::DumpJson() const {
121-
if (m_performanceRecords.empty()) {
142+
Aws::Utils::Json::JsonValue root;
143+
root.WithString("productId", m_productId);
144+
root.WithString("sdkVersion", m_sdkVersion);
145+
root.WithString("commitId", m_commitId);
146+
147+
// If there is an invalid latency or there are no records, then use an empty results array
148+
if (m_hasInvalidLatency || m_performanceRecords.empty()) {
149+
root.WithArray("results", Aws::Utils::Array<Aws::Utils::Json::JsonValue>(0));
150+
WriteJsonToFile(root);
122151
return;
123152
}
124153

@@ -140,12 +169,6 @@ void JsonReportingMetrics::DumpJson() const {
140169
}
141170
}
142171

143-
// Create the JSON output
144-
Aws::Utils::Json::JsonValue root;
145-
root.WithString("productId", m_productId);
146-
root.WithString("sdkVersion", m_sdkVersion);
147-
root.WithString("commitId", m_commitId);
148-
149172
Aws::Utils::Array<Aws::Utils::Json::JsonValue> results(aggregatedRecords.size());
150173
size_t index = 0;
151174

@@ -172,10 +195,10 @@ void JsonReportingMetrics::DumpJson() const {
172195
Aws::Utils::Array<Aws::Utils::Json::JsonValue> measurementsArray(record.measurements.size());
173196
for (size_t measurementIndex = 0; measurementIndex < record.measurements.size(); ++measurementIndex) {
174197
Aws::Utils::Json::JsonValue measurementValue;
175-
if (record.measurements[measurementIndex].IsDouble()) {
176-
measurementValue.AsDouble(record.measurements[measurementIndex].AsDouble());
198+
if (std::holds_alternative<double>(record.measurements[measurementIndex])) {
199+
measurementValue.AsDouble(std::get<double>(record.measurements[measurementIndex]));
177200
} else {
178-
measurementValue.AsInt64(record.measurements[measurementIndex].AsInt64());
201+
measurementValue.AsInt64(std::get<int64_t>(record.measurements[measurementIndex]));
179202
}
180203
measurementsArray[measurementIndex] = std::move(measurementValue);
181204
}
@@ -185,7 +208,10 @@ void JsonReportingMetrics::DumpJson() const {
185208
}
186209

187210
root.WithArray("results", std::move(results));
211+
WriteJsonToFile(root);
212+
}
188213

214+
void JsonReportingMetrics::WriteJsonToFile(const Aws::Utils::Json::JsonValue& root) const {
189215
std::ofstream outFile(m_outputFilename.c_str());
190216
if (outFile.is_open()) {
191217
outFile << root.View().WriteReadable();

0 commit comments

Comments
 (0)