Skip to content

Add Ser/De + roundtrip protocol benchmarks#6776

Open
RanVaknin wants to merge 7 commits intomasterfrom
rvaknin/isolated-protocol-benchmarks
Open

Add Ser/De + roundtrip protocol benchmarks#6776
RanVaknin wants to merge 7 commits intomasterfrom
rvaknin/isolated-protocol-benchmarks

Conversation

@RanVaknin
Copy link
Contributor

@RanVaknin RanVaknin commented Mar 11, 2026

Benchmarking notes

  1. Isolated serialization/deserialization — uses the lowest-level public marshalling/unmarshalling API in each SDK. Due to architectural differences between v1 and v2, the deserialization benchmarks have one minor asymmetry worth noting:
    For JSON/RestJson/CBOR deserialization, v2's narrowest unmarshalling entry point takes an SdkHttpFullResponse, so the v2 benchmarks create an SdkHttpFullResponse wrapper per iteration. v1's narrowest entry point takes a raw parser, so it doesn't have this overhead. Even though v2's deserialization benchmark is slightly disadvantaged, it is faster across the board.
Protocol Operation V1 (ops/µs) V2 (ops/µs) Delta
RestJson CreateFunction deser 0.068 0.176 +159%
RestJson CreateFunction ser 0.468 0.284 -39%
JSON DynamoDB PutItem deser 0.072 0.141 +96%
JSON DynamoDB PutItem ser 0.139 0.101 -27%
CBOR CloudWatch GetMetricData deser 0.279 0.382 +37%
CBOR CloudWatch GetMetricData ser 0.719 0.416 -42%
EC2 DescribeInstances deser 0.014 0.019 +36%
EC2 DescribeInstances ser 1.724 1.068 -38%
Query STS AssumeRole deser 0.037 0.038 +3%
Query STS AssumeRole ser 3.181 1.394 -56%
RestXml CloudFront CreateDistribution deser 0.004 0.005 +25%
RestXml CloudFront CreateDistribution ser 0.047 0.079 +68%
  1. Stubbed response roundtrip — full SDK client call through a local Jetty servlet that returns canned responses. Measures the entire request/response pipeline. v1 uses its default HTTP client; V2 uses Apache 5.
Protocol Operation V1 (ops/s) V2 (ops/s) Delta
RestJson Lambda#CreateFunction 6,832 5,502 -19.5%
JSON DDB#PutItem 6,389 5,078 -20.5%
CBOR CW#GetMetricData 6,804 5,487 -19.3%
EC2 EC2#DescribeInstances 4,168 3,717 -10.8%
Query STS#AssumeRole 5,319 4,739 -10.9%
RestXml CF#CreateDistribution 2,034 2,036 +0.1%

Benchmarks for all 6 AWS protocol types measuring serialization and
deserialization in isolation (no HTTP, signing, or retries):

- JSON (DynamoDB PutItem)
- REST-JSON (Lambda CreateFunction)
- REST-XML (CloudFront CreateDistribution)
- Query (STS AssumeRole)
- EC2 (EC2 DescribeInstances)
- CBOR (CloudWatch GetMetricData)

Each protocol has a V1 and V2 benchmark class with @benchmark methods
for both ser and deser, using the same JMH configuration and fixture
data for fair comparison.
@RanVaknin RanVaknin requested a review from a team as a code owner March 11, 2026 06:15
@RanVaknin RanVaknin added changelog-not-required Indicate changelog entry is not required for a specific PR no-api-surface-area-change Indicate there is no API surface area change and thus API surface area review is not required labels Mar 11, 2026
@RanVaknin RanVaknin changed the title Add Ser/De protocol benchmarks Add Ser/De + roundtrip protocol benchmarks Mar 17, 2026

Instant end = Instant.parse("2026-03-09T00:00:00Z");
Instant start = end.minusSeconds(3600);
request = GetMetricDataRequest.builder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we consider the request object to be non-reusable in v2 and best practice is for users to create a new request per operation invocation. There is a (small) cost to this that maybe we should be including in these benchmarks. I'm on the fence about it - it's not as apples to apples with v1 benchmarks but it is our best practice guidance to not reuse request objects, so maybe we should capture that cost in the comparison?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you on this. Since we are measuring the entire roundtrip it makes sense to include the request building within the benchmark runner. Just pushed the change.

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setStatus(200);
resp.setContentLength(body.length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also probably be setting content-type? I'm not quite sure if it matters or not


@Benchmark
public void getMetricDataSer(Blackhole bh) {
bh.consume(new GetMetricDataRequestProtocolMarshaller(protocolFactory).marshall(request));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't remember how the marshallers work here - but do they mutate the request at all? If so, that could leak state between iterations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell there are no mutations happening. The marshaller just calls .get* on each field and passes it on to the marshalling function. There are no setters that mutate the reqeust (at least in the benchmarks codepath).

I wrote a small test to prove that:

        GetMetricDataRequest request = createRequest();
        SdkRpcV2CborProtocolFactory protocolFactory = new SdkRpcV2CborProtocolFactory(new RpcV2CborClientMetadata());

        String before = request.toString();
        new GetMetricDataRequestProtocolMarshaller(protocolFactory).marshall(request);
        new GetMetricDataRequestProtocolMarshaller(protocolFactory).marshall(request);
        String after = request.toString();

        System.out.println(before.equals(after)); // prints true

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
6 Security Hotspots
4.1% Coverage on New Code (required ≥ 80%)
3.7% Duplication on New Code (required ≤ 3%)
E Security Rating on New Code (required ≥ A)
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-not-required Indicate changelog entry is not required for a specific PR no-api-surface-area-change Indicate there is no API surface area change and thus API surface area review is not required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants