[
https://issues.apache.org/jira/browse/IGNITE-28835?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18092680#comment-18092680
]
Ignite TC Bot commented on IGNITE-28835:
----------------------------------------
{panel:title=Branch: [pull/13295/head] Base: [master] : No blockers
found!|borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}{panel}
{panel:title=Branch: [pull/13295/head] Base: [master] : New Tests
(4)|borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}
{color:#00008b}Binary Objects{color} [[tests
4|https://ci2.ignite.apache.org/viewLog.html?buildId=9161582]]
* {color:#013220}IgniteBinaryObjectsTestSuite:
BinaryMarshallerSelfTest.testMarshalToStreamMatchesArray[useBinaryArrays =
true] - PASSED{color}
* {color:#013220}IgniteBinaryObjectsTestSuite:
BinaryMarshallerNonCompactSelfTest.testMarshalToStreamMatchesArray[useBinaryArrays
= false] - PASSED{color}
* {color:#013220}IgniteBinaryObjectsTestSuite:
BinaryMarshallerNonCompactSelfTest.testMarshalToStreamMatchesArray[useBinaryArrays
= true] - PASSED{color}
* {color:#013220}IgniteBinaryObjectsTestSuite:
BinaryMarshallerSelfTest.testMarshalToStreamMatchesArray[useBinaryArrays =
false] - PASSED{color}
{panel}
[TeamCity *--> Run :: All*
Results|https://ci2.ignite.apache.org/viewLog.html?buildId=9161723&buildTypeId=IgniteTests24Java8_RunAll]
{color:#ffffff}tcbot-analysis-comment chainBuildId=9161723
rerunBuildIds=none{color}
> BinaryMarshaller: avoid redundant full-object byte[] copy and double
> node-name scope on marshal-to-stream
> ---------------------------------------------------------------------------------------------------------
>
> Key: IGNITE-28835
> URL: https://issues.apache.org/jira/browse/IGNITE-28835
> Project: Ignite
> Issue Type: Task
> Reporter: Anton Vinogradov
> Assignee: Anton Vinogradov
> Priority: Major
>
> {{BinaryMarshaller.marshal0(Object, OutputStream)}} has two avoidable
> inefficiencies on the hot marshalling-to-stream path:
> _1. Full-size temporary array copy (main issue)._
> {code:java}
> @Override protected void marshal0(Object obj, OutputStream out) {
> byte[] arr = marshal(obj); // GridBinaryMarshaller.marshal -> writer.array()
> == Arrays.copyOf (full copy)
> out.write(arr);
> ...
> }
> {code}
> The whole serialized object is allocated and copied once
> ({{{}writer.array(){}}} trims via {{{}Arrays.copyOf{}}}) only to be
> immediately streamed out. The temporary array and the copy are unnecessary —
> the writer's internal buffer can be written straight to \{{out}} by length.
> _2. Redundant node-name scope._
> {\{marshal0(obj, out)}} calls the *public* \{{marshal(obj)}}, which re-enters
> \{{AbstractNodeNameAwareMarshaller}}'s
> \{{setCurrentIgniteName}}/\{{restoreOldIgniteName}} scope a second time,
> although \{{marshal0}} already runs inside the scope established by the outer
> \{{marshal(obj, out)}}. It should call the protected \{{marshal0(obj)}} (or a
> new stream method) directly.
> *Proposed change*
> * Add a "marshal directly into \{{OutputStream}}" path in
> \{{GridBinaryMarshaller}} that writes \{{writer.internalArray()}} for
> \{{writer.outputSize()}} bytes to \{{out}}, avoiding the trim-copy and the
> temporary array.
> * In \{{BinaryMarshaller.marshal0(obj, out)}} call that path instead of the
> public \{{marshal(obj)}}, removing the second name-scope.
> * Minor: reuse a shared single-byte \{{NULL}} array for the \{{obj == null}}
> fast path instead of allocating per call.
> *Benchmark*
> Isolated JMH micro-benchmark of the avoided work (serialization excluded,
> identical in both variants; AverageTime, ns/op, JDK 17):
> {noformat}
> #1 redundant name-scope (per marshal-to-stream call):
> current : 13.00 ns
> proposed : 11.16 ns (-14%, -1.84 ns/call)
> #2 full-object copy in marshal0(obj, out) — copy+write vs write-directly:
> object size current proposed gain
> 64 B 4.96 ns 2.14 ns -57%
> 1 KB 43.7 ns 18.8 ns -57%
> 16 KB 667 ns 364 ns -45%
> 256 KB 10563 ns 3756 ns -64% (-6.8 us)
> {noformat}
> The stream-tail cost roughly halves and scales with object size; additionally
> a full-size temporary allocation per call is eliminated (reduced GC
> pressure), which the ns/op figures do not fully capture.
> Note: these are isolated deltas of the avoided copy/scope, not end-to-end
> marshaller throughput — in the full cycle the relative gain is smaller since
> serialization dominates, but the eliminated copy is absolute and proportional
> to object size, so the benefit is meaningful for large objects at high
> throughput.
> *Scope / risk*
> Local change in the \{{binary}} module, no public API or wire-format change.
> Behavior-preserving; covered by existing marshaller tests.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)