Skip to content

feat!: Use STJ for SendPipeline serializer instead of Newtonsoft#468

Open
JR-Morgan wants to merge 49 commits into
mainfrom
jrm/stj-experiment
Open

feat!: Use STJ for SendPipeline serializer instead of Newtonsoft#468
JR-Morgan wants to merge 49 commits into
mainfrom
jrm/stj-experiment

Conversation

@JR-Morgan
Copy link
Copy Markdown
Member

@JR-Morgan JR-Morgan commented Apr 7, 2026

This is a semi-experimental change to replace newtonsoft with System.Text.Json for the new send pipeline serializer

See https://www.notion.so/speckle/Introducing-System-Text-Json-to-packfile-based-serializer-SendPipleine-357b78fc7aa6805bb472ca09b980b7fd
for the full context.


Serializer Benchmarks

Medium size model: https://app.speckle.systems/projects/bf5b49215c/models/0d573b9a34

NET 10

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
PR 2.209 s 0.3927 s 0.1400 s 60000.0000 18000.0000 1000.0000 1.83 GB
3.16.0 5.892 s 3.722 s 0.5760 s 234000.0000 20000.0000 5.19 GB

NET 8.0

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
PR 3.350 s 3.345 s 0.5176 s 61000.0000 19000.0000 1000.0000 1.85 GB
3.16.0 7.593 s 2.206 s 0.3414 s 234000.0000 20000.0000 5.19 GB

NET 4.8

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
PR 9.098 s 2.663 s 0.4122 s 588000.0000 30000.0000 1000.0000 4.39 GB
3.16.0 26.44 s 2.746 s 0.425 s 693000.0000 33000.0000 6.43 GB

Larger model (conf)

NET10

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
PR 5.188 s 1.121 s 0.1734 s 262000.0000 175000.0000 1000.0000 4.3 GB
3.16.0 11.35 s 0.598 s 0.093 s 532000.0000 222000.0000 1000.0000 9.03 GB

NET 4.8.1

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
PR 14.58 s 0.576 s 0.089 s 1271000.0000 416000.0000 1000.0000 7.67 GB
3.16.0 39.56 s 1.324 s 0.205 s 1906000.0000 535000.0000 1000.0000 12.26 GB

TODO:

  • re)Validate performance DONE!
    • I'm expecting the .NET8 and .NET 10 targets to be most benefited.
    • Memory allocations should be measurably lower.
    • Raw speed should also be improved too
    • .netstandard2.0 less so (I'm not expecting any regressions, but we should test)
  • DLL conflicts
    • for .netstandard2.0 we've introduced a dependency on STJ. Lets determine if this will be a problem. we may be able work around it with ILRepack, or by lowering the version requirement. ✅ - version lowered down to 5.x
  • Test coverage
    • Ensure test coverage of the simple stuff (id generation etc...)
  • IL repack System.Memory? or no? ❎Can't since we need to expose the IBufferWriter interface from Speckle.Sdk.Depedencies + no need, STJ pulls it in anyway.

@JR-Morgan JR-Morgan marked this pull request as draft April 7, 2026 09:35
@JR-Morgan JR-Morgan changed the title experiment: STJ feat!: Switch out Newtonsoft for STJ Apr 7, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

Codecov Report

❌ Patch coverage is 89.93840% with 49 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.71%. Comparing base (b86b712) to head (e5fa39d).

Files with missing lines Patch % Lines
src/Speckle.Sdk/Pipelines/Send/Serializer.cs 64.91% 39 Missing and 1 partial ⚠️
...nes/Send/Serialization/JsonIgnoreAttributeTests.cs 89.79% 5 Missing ⚠️
...yManagement/ArrayBufferWriterPooledObjectPolicy.cs 85.71% 1 Missing ⚠️
src/Speckle.Sdk/Models/Attributes.cs 75.00% 1 Missing ⚠️
src/Speckle.Sdk/Pipelines/Send/EfficientJson.cs 90.00% 1 Missing ⚠️
...ts.Integration/Pipelines/Send/SendPipelineTests.cs 98.83% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #468      +/-   ##
==========================================
+ Coverage   71.46%   73.71%   +2.25%     
==========================================
  Files         355      365      +10     
  Lines       14377    14745     +368     
  Branches     1209     1218       +9     
==========================================
+ Hits        10275    10870     +595     
+ Misses       3704     3468     -236     
- Partials      398      407       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JR-Morgan JR-Morgan force-pushed the jrm/stj-experiment branch from 4558f3e to 72f6898 Compare April 17, 2026 08:59
@JR-Morgan JR-Morgan force-pushed the jrm/stj-experiment branch from ea0a9ed to 87dc3ac Compare April 17, 2026 11:00
@JR-Morgan JR-Morgan marked this pull request as ready for review April 17, 2026 14:33
Comment thread src/Speckle.Sdk/Polyfills/ArrayBufferWriterPolyfill.cs
Comment thread src/Speckle.Sdk/Pipelines/Send/DiskStore.cs
Comment thread src/Speckle.Sdk/Api/Operations/Operations.Serialize.cs
new ArrayBufferWriterPooledObjectPolicy<byte>()
{
InitialCapacity = 512,
MaximumRetainedCapacity = 100 * 1024 * 1024,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

out of curiosity, why 100MB?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

MaximumRetainedCapacity is the maximum size a rented buffer can be for it to be placed back in the pool to be reused.

If you pick a number that' too high, you end up keeping super large buffers around in memory for longer than is needed (increasing peak memory usage)

If you pick a number that's too small, then you'll see greater buffer re-sizing for large objects, (leads to more garbage allocated)


I picked 100MB because most objects are going to be well under this limit. We've only seen objects get >100MB in super large models.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

stolicija-sayor

Comment thread src/Speckle.Sdk/Pipelines/Send/EfficientJson.cs Outdated
oguzhankoral
oguzhankoral previously approved these changes May 11, 2026
Copy link
Copy Markdown
Member

@oguzhankoral oguzhankoral left a comment

Choose a reason for hiding this comment

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

It would be great to go with the beta release first since its PITA to deal with bad releases on connectors

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants