Last active
March 17, 2026 15:09
-
-
Save stonstad/0a3da869099ef1eb22bb50268aaa1d9f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Text.Json; | |
| using NUnit.Framework; | |
| using Unity.PerformanceTesting; | |
| using UnityEngine; | |
| public class JsonSerializationPerformanceTests | |
| { | |
| private const int ItemCount = 1000; | |
| private TestPayload _payload; | |
| private string _unityJson; | |
| private string _systemTextJson; | |
| private JsonSerializerOptions _systemTextJsonOptions; | |
| [Serializable] | |
| public class TestPayload | |
| { | |
| public int id; | |
| public string name; | |
| public float score; | |
| public bool isActive; | |
| public long createdAtTicks; | |
| public NestedData nested; | |
| public List<ItemData> items; | |
| } | |
| [Serializable] | |
| public class NestedData | |
| { | |
| public int level; | |
| public string description; | |
| public Vector3Data position; | |
| } | |
| [Serializable] | |
| public class Vector3Data | |
| { | |
| public float x; | |
| public float y; | |
| public float z; | |
| } | |
| [Serializable] | |
| public class ItemData | |
| { | |
| public int index; | |
| public string label; | |
| public float value; | |
| public bool enabled; | |
| } | |
| [SetUp] | |
| public void SetUp() | |
| { | |
| _payload = BuildPayload(ItemCount); | |
| _systemTextJsonOptions = new JsonSerializerOptions | |
| { | |
| IncludeFields = true, | |
| WriteIndented = false | |
| }; | |
| // Warm-up / baseline cached data | |
| _unityJson = JsonUtility.ToJson(_payload); | |
| _systemTextJson = JsonSerializer.Serialize(_payload, _systemTextJsonOptions); | |
| // Sanity checks so the benchmark doesn't run against broken setup | |
| Assert.IsFalse(string.IsNullOrEmpty(_unityJson)); | |
| Assert.IsFalse(string.IsNullOrEmpty(_systemTextJson)); | |
| } | |
| [Test, Performance] | |
| public void Unity_JsonUtility_Serialize() | |
| { | |
| Measure.Method(() => | |
| { | |
| var json = JsonUtility.ToJson(_payload); | |
| GC.KeepAlive(json); | |
| }) | |
| .WarmupCount(10) | |
| .MeasurementCount(30) | |
| .IterationsPerMeasurement(100) | |
| .GC() | |
| .Run(); | |
| } | |
| [Test, Performance] | |
| public void SystemTextJson_Serialize() | |
| { | |
| Measure.Method(() => | |
| { | |
| var json = JsonSerializer.Serialize(_payload, _systemTextJsonOptions); | |
| GC.KeepAlive(json); | |
| }) | |
| .WarmupCount(10) | |
| .MeasurementCount(30) | |
| .IterationsPerMeasurement(100) | |
| .GC() | |
| .Run(); | |
| } | |
| [Test, Performance] | |
| public void Unity_JsonUtility_Deserialize() | |
| { | |
| Measure.Method(() => | |
| { | |
| var obj = JsonUtility.FromJson<TestPayload>(_unityJson); | |
| GC.KeepAlive(obj); | |
| }) | |
| .WarmupCount(10) | |
| .MeasurementCount(30) | |
| .IterationsPerMeasurement(100) | |
| .GC() | |
| .Run(); | |
| } | |
| [Test, Performance] | |
| public void SystemTextJson_Deserialize() | |
| { | |
| Measure.Method(() => | |
| { | |
| var obj = JsonSerializer.Deserialize<TestPayload>(_systemTextJson, _systemTextJsonOptions); | |
| GC.KeepAlive(obj); | |
| }) | |
| .WarmupCount(10) | |
| .MeasurementCount(30) | |
| .IterationsPerMeasurement(100) | |
| .GC() | |
| .Run(); | |
| } | |
| [Test] | |
| public void SanityCheck_BothSerializers_CreateUsableJson() | |
| { | |
| Debug.Log($"Unity JsonUtility length: {_unityJson.Length}"); | |
| Debug.Log($"System.Text.Json length: {_systemTextJson.Length}"); | |
| var unityObj = JsonUtility.FromJson<TestPayload>(_unityJson); | |
| var systemObj = JsonSerializer.Deserialize<TestPayload>(_systemTextJson, _systemTextJsonOptions); | |
| Assert.NotNull(unityObj); | |
| Assert.NotNull(systemObj); | |
| Assert.AreEqual(_payload.id, unityObj.id); | |
| Assert.AreEqual(_payload.id, systemObj.id); | |
| Assert.AreEqual(_payload.items.Count, unityObj.items.Count); | |
| Assert.AreEqual(_payload.items.Count, systemObj.items.Count); | |
| } | |
| private static TestPayload BuildPayload(int itemCount) | |
| { | |
| var payload = new TestPayload | |
| { | |
| id = 12345, | |
| name = "Benchmark Payload", | |
| score = 98.76f, | |
| isActive = true, | |
| createdAtTicks = DateTime.UtcNow.Ticks, | |
| nested = new NestedData | |
| { | |
| level = 7, | |
| description = "Nested benchmark object", | |
| position = new Vector3Data | |
| { | |
| x = 12.34f, | |
| y = 56.78f, | |
| z = 90.12f | |
| } | |
| }, | |
| items = new List<ItemData>(itemCount) | |
| }; | |
| for (int i = 0; i < itemCount; i++) | |
| { | |
| payload.items.Add(new ItemData | |
| { | |
| index = i, | |
| label = $"Item_{i}", | |
| value = i * 1.2345f, | |
| enabled = (i % 2) == 0 | |
| }); | |
| } | |
| return payload; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "TestSuite": "Playmode", | |
| "Date": 1773759692576, | |
| "Player": { | |
| "Development": true, | |
| "ScreenWidth": 5120, | |
| "ScreenHeight": 2160, | |
| "ScreenRefreshRate": 60, | |
| "Fullscreen": false, | |
| "Vsync": 1, | |
| "AntiAliasing": 2, | |
| "Batchmode": false, | |
| "RenderThreadingMode": "MultiThreaded", | |
| "MtRendering": true, | |
| "GraphicsJobs": false, | |
| "GpuSkinning": false, | |
| "Platform": "WindowsEditor", | |
| "ColorSpace": "Linear", | |
| "AnisotropicFiltering": "ForceEnable", | |
| "BlendWeights": "Unlimited", | |
| "GraphicsApi": "Direct3D12", | |
| "ScriptingBackend": "IL2CPP", | |
| "AndroidTargetSdkVersion": "AndroidApiLevelAuto", | |
| "AndroidBuildSystem": "Gradle", | |
| "BuildTarget": "StandaloneWindows64", | |
| "StereoRenderingPath": "MultiPass" | |
| }, | |
| "Hardware": { | |
| "OperatingSystem": "Windows 11 (10.0.26200)", | |
| "DeviceModel": "System Product Name (ASUS)", | |
| "DeviceName": "SHAUN-PC", | |
| "ProcessorType": "AMD Ryzen 9 7950X 16-Core Processor ", | |
| "ProcessorCount": 32, | |
| "GraphicsDeviceName": "NVIDIA GeForce RTX 4090", | |
| "SystemMemorySizeMB": 64654 | |
| }, | |
| "Editor": { | |
| "Version": "6000.3.10f1", | |
| "Branch": "6000.3/staging", | |
| "Changeset": "e35f0c77bd8e", | |
| "Date": 1771318112 | |
| }, | |
| "Dependencies": [ | |
| "com.unity.collab-proxy@2.11.3", | |
| "com.unity.feature.2d@2.0.2", | |
| "com.unity.ide.rider@3.0.39", | |
| "com.unity.ide.visualstudio@2.0.26", | |
| "com.unity.inputsystem@1.18.0", | |
| "com.unity.test-framework@1.6.0", | |
| "com.unity.test-framework.performance@3.2.1", | |
| "com.unity.timeline@1.8.10", | |
| "com.unity.ugui@2.0.0", | |
| "com.unity.ui.test-framework@6.3.0", | |
| "com.unity.visualscripting@1.9.9", | |
| "org.nuget.system.text.json@10.0.5", | |
| "com.unity.modules.accessibility@1.0.0", | |
| "com.unity.modules.adaptiveperformance@1.0.0", | |
| "com.unity.modules.ai@1.0.0", | |
| "com.unity.modules.androidjni@1.0.0", | |
| "com.unity.modules.animation@1.0.0", | |
| "com.unity.modules.assetbundle@1.0.0", | |
| "com.unity.modules.audio@1.0.0", | |
| "com.unity.modules.cloth@1.0.0", | |
| "com.unity.modules.director@1.0.0", | |
| "com.unity.modules.imageconversion@1.0.0", | |
| "com.unity.modules.imgui@1.0.0", | |
| "com.unity.modules.jsonserialize@1.0.0", | |
| "com.unity.modules.particlesystem@1.0.0", | |
| "com.unity.modules.physics@1.0.0", | |
| "com.unity.modules.physics2d@1.0.0", | |
| "com.unity.modules.screencapture@1.0.0", | |
| "com.unity.modules.terrain@1.0.0", | |
| "com.unity.modules.terrainphysics@1.0.0", | |
| "com.unity.modules.tilemap@1.0.0", | |
| "com.unity.modules.ui@1.0.0", | |
| "com.unity.modules.uielements@1.0.0", | |
| "com.unity.modules.umbra@1.0.0", | |
| "com.unity.modules.unityanalytics@1.0.0", | |
| "com.unity.modules.unitywebrequest@1.0.0", | |
| "com.unity.modules.unitywebrequestassetbundle@1.0.0", | |
| "com.unity.modules.unitywebrequestaudio@1.0.0", | |
| "com.unity.modules.unitywebrequesttexture@1.0.0", | |
| "com.unity.modules.unitywebrequestwww@1.0.0", | |
| "com.unity.modules.vectorgraphics@1.0.0", | |
| "com.unity.modules.vehicles@1.0.0", | |
| "com.unity.modules.video@1.0.0", | |
| "com.unity.modules.vr@1.0.0", | |
| "com.unity.modules.wind@1.0.0", | |
| "com.unity.modules.xr@1.0.0", | |
| "com.unity.modules.subsystems@1.0.0", | |
| "com.unity.modules.hierarchycore@1.0.0", | |
| "org.nuget.microsoft.bcl.asyncinterfaces@10.0.5", | |
| "org.nuget.system.io.pipelines@10.0.5", | |
| "org.nuget.system.text.encodings.web@10.0.5", | |
| "org.nuget.system.buffers@4.6.1", | |
| "org.nuget.system.memory@4.6.3", | |
| "org.nuget.system.runtime.compilerservices.unsafe@6.1.2", | |
| "org.nuget.system.threading.tasks.extensions@4.6.3", | |
| "com.unity.ext.nunit@2.0.5", | |
| "com.unity.2d.animation@13.0.4", | |
| "com.unity.2d.pixel-perfect@5.1.1", | |
| "com.unity.2d.psdimporter@12.0.1", | |
| "com.unity.2d.sprite@1.0.0", | |
| "com.unity.2d.spriteshape@13.0.0", | |
| "com.unity.2d.tilemap@1.0.0", | |
| "com.unity.2d.tilemap.extras@6.0.1", | |
| "com.unity.2d.aseprite@3.0.1", | |
| "com.unity.2d.tooling@1.0.2", | |
| "org.nuget.system.numerics.vectors@4.6.1", | |
| "com.unity.2d.common@12.0.2", | |
| "com.unity.mathematics@1.3.3", | |
| "com.unity.collections@2.6.2", | |
| "com.unity.burst@1.8.28", | |
| "com.unity.nuget.mono-cecil@1.11.6" | |
| ], | |
| "Results": [ | |
| { | |
| "Name": "JsonSerializationPerformanceTests.SystemTextJson_Deserialize", | |
| "ClassName": "JsonSerializationPerformanceTests", | |
| "MethodName": "SystemTextJson_Deserialize", | |
| "Version": "1", | |
| "Categories": [ | |
| "Performance" | |
| ], | |
| "SampleGroups": [ | |
| { | |
| "Name": "Time.GC()", | |
| "Unit": 8, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0, | |
| 6029.0 | |
| ], | |
| "Min": 6029.0, | |
| "Max": 6029.0, | |
| "Median": 6029.0, | |
| "Average": 6029.0, | |
| "StandardDeviation": 0.0, | |
| "Sum": 180870.0 | |
| }, | |
| { | |
| "Name": "Time", | |
| "Unit": 2, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 219.69190000000004, | |
| 219.6502999999998, | |
| 221.1895999999997, | |
| 226.79500000000008, | |
| 257.2282999999998, | |
| 222.4369999999999, | |
| 223.0891999999999, | |
| 222.4702000000002, | |
| 221.9940999999999, | |
| 262.0772999999999, | |
| 222.58780000000025, | |
| 222.70150000000013, | |
| 221.9795999999997, | |
| 221.5095999999994, | |
| 264.5603000000001, | |
| 220.4915000000001, | |
| 220.4309999999996, | |
| 221.09439999999996, | |
| 221.44920000000006, | |
| 257.0628999999999, | |
| 374.58440000000067, | |
| 254.76310000000013, | |
| 219.9979000000003, | |
| 219.84159999999978, | |
| 219.47419999999969, | |
| 219.39170000000017, | |
| 261.3117999999995, | |
| 220.52080000000024, | |
| 223.61709999999949, | |
| 223.89670000000116 | |
| ], | |
| "Min": 219.39170000000017, | |
| "Max": 374.58440000000067, | |
| "Median": 222.2155499999999, | |
| "Average": 234.263, | |
| "StandardDeviation": 30.194203124849513, | |
| "Sum": 7027.889999999999 | |
| } | |
| ] | |
| }, | |
| { | |
| "Name": "JsonSerializationPerformanceTests.SystemTextJson_Serialize", | |
| "ClassName": "JsonSerializationPerformanceTests", | |
| "MethodName": "SystemTextJson_Serialize", | |
| "Version": "1", | |
| "Categories": [ | |
| "Performance" | |
| ], | |
| "SampleGroups": [ | |
| { | |
| "Name": "Time.GC()", | |
| "Unit": 8, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0, | |
| 5018.0 | |
| ], | |
| "Min": 5018.0, | |
| "Max": 5018.0, | |
| "Median": 5018.0, | |
| "Average": 5018.0, | |
| "StandardDeviation": 0.0, | |
| "Sum": 150540.0 | |
| }, | |
| { | |
| "Name": "Time", | |
| "Unit": 2, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 192.9550999999999, | |
| 177.51659999999993, | |
| 176.6638999999998, | |
| 177.0019000000002, | |
| 195.8095000000003, | |
| 178.6963000000001, | |
| 178.6501000000003, | |
| 178.6278000000002, | |
| 194.0826000000002, | |
| 178.87760000000029, | |
| 179.05510000000005, | |
| 193.26009999999997, | |
| 179.4454999999998, | |
| 178.48759999999994, | |
| 178.58819999999924, | |
| 192.01800000000004, | |
| 177.29970000000049, | |
| 178.8801000000003, | |
| 178.94360000000052, | |
| 195.4291999999996, | |
| 178.7588999999998, | |
| 178.4949999999999, | |
| 193.9444999999996, | |
| 176.52939999999945, | |
| 175.77700000000005, | |
| 176.09209999999985, | |
| 190.91429999999949, | |
| 176.14129999999933, | |
| 176.03039999999965, | |
| 175.8089 | |
| ], | |
| "Min": 175.77700000000005, | |
| "Max": 195.8095000000003, | |
| "Median": 178.6732000000002, | |
| "Average": 181.9593433333333, | |
| "StandardDeviation": 7.113551924586527, | |
| "Sum": 5458.780299999998 | |
| } | |
| ] | |
| }, | |
| { | |
| "Name": "JsonSerializationPerformanceTests.Unity_JsonUtility_Deserialize", | |
| "ClassName": "JsonSerializationPerformanceTests", | |
| "MethodName": "Unity_JsonUtility_Deserialize", | |
| "Version": "1", | |
| "Categories": [ | |
| "Performance" | |
| ], | |
| "SampleGroups": [ | |
| { | |
| "Name": "Time.GC()", | |
| "Unit": 8, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0, | |
| 2007.0 | |
| ], | |
| "Min": 2007.0, | |
| "Max": 2007.0, | |
| "Median": 2007.0, | |
| "Average": 2007.0, | |
| "StandardDeviation": 0.0, | |
| "Sum": 60210.0 | |
| }, | |
| { | |
| "Name": "Time", | |
| "Unit": 2, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 79.64330000000007, | |
| 86.45499999999993, | |
| 113.8247, | |
| 80.13830000000007, | |
| 80.26660000000016, | |
| 80.05079999999998, | |
| 79.96709999999985, | |
| 80.05830000000015, | |
| 79.61950000000002, | |
| 79.15109999999982, | |
| 79.06040000000007, | |
| 79.1241, | |
| 79.19600000000014, | |
| 79.1051, | |
| 88.5603000000001, | |
| 114.34370000000013, | |
| 80.02590000000009, | |
| 80.16570000000002, | |
| 80.66829999999982, | |
| 80.4014000000002, | |
| 80.55099999999993, | |
| 79.89870000000019, | |
| 79.70389999999998, | |
| 79.49720000000025, | |
| 79.6251000000002, | |
| 79.529, | |
| 82.68589999999995, | |
| 121.93769999999997, | |
| 80.5881000000004, | |
| 80.90249999999969 | |
| ], | |
| "Min": 79.06040000000007, | |
| "Max": 121.93769999999997, | |
| "Median": 80.05455000000007, | |
| "Average": 84.1581566666667, | |
| "StandardDeviation": 11.094777683687737, | |
| "Sum": 2524.744700000001 | |
| } | |
| ] | |
| }, | |
| { | |
| "Name": "JsonSerializationPerformanceTests.Unity_JsonUtility_Serialize", | |
| "ClassName": "JsonSerializationPerformanceTests", | |
| "MethodName": "Unity_JsonUtility_Serialize", | |
| "Version": "1", | |
| "Categories": [ | |
| "Performance" | |
| ], | |
| "SampleGroups": [ | |
| { | |
| "Name": "Time.GC()", | |
| "Unit": 8, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0, | |
| 1.0 | |
| ], | |
| "Min": 1.0, | |
| "Max": 1.0, | |
| "Median": 1.0, | |
| "Average": 1.0, | |
| "StandardDeviation": 0.0, | |
| "Sum": 30.0 | |
| }, | |
| { | |
| "Name": "Time", | |
| "Unit": 2, | |
| "IncreaseIsBetter": false, | |
| "Samples": [ | |
| 48.370000000000008, | |
| 48.6653, | |
| 48.36110000000008, | |
| 48.46260000000007, | |
| 48.21680000000004, | |
| 48.289499999999978, | |
| 62.58420000000001, | |
| 48.301000000000048, | |
| 48.33269999999993, | |
| 48.20500000000004, | |
| 48.48040000000003, | |
| 48.98990000000004, | |
| 49.06560000000013, | |
| 49.05319999999983, | |
| 62.92329999999993, | |
| 49.144399999999908, | |
| 49.24420000000009, | |
| 48.98220000000015, | |
| 49.078899999999979, | |
| 48.95399999999995, | |
| 48.91819999999984, | |
| 49.149400000000017, | |
| 63.25890000000004, | |
| 49.18909999999983, | |
| 49.07410000000005, | |
| 48.90020000000004, | |
| 49.049800000000008, | |
| 49.0744000000002, | |
| 49.09940000000006, | |
| 48.99289999999996 | |
| ], | |
| "Min": 48.20500000000004, | |
| "Max": 63.25890000000004, | |
| "Median": 48.9914, | |
| "Average": 50.21369000000001, | |
| "StandardDeviation": 4.249973620886756, | |
| "Sum": 1506.4107 | |
| } | |
| ] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment