Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit ae4c5fc

Browse files
authored
Jobify serialization (#1454)
* Serialize component updates in jobs * Fix early job schedule due to combined dependencies Filter on changed components to avoid scheduling jobs for unchanged chunks Don't reuse queue, dispose and re-create * Remove UnityComponentSenderGenerator and the ComponentSendSystem Hack MessagesToSend to store pre-serialized component updates * Add more profile markers * Dispose Native collections in right places Fixes unit tests * For performance tests by changing profiling marks Add DisableAutoCreate to ReplicationSystems * Fix code smells * Changelog * Fix netstats for component updates Rename AddComponentUpdate to AddComponentEvent * Better profile markers
1 parent f219927 commit ae4c5fc

19 files changed

+209
-292
lines changed

CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
## Unreleased
44

5+
### Added
6+
7+
- Added `MeansImplicitUse` attribute to `RequireAttribute` to reduce warnings in Rider IDE. [#1462](https://github.com/spatialos/gdk-for-unity/pull/1462)
8+
59
### Changed
610

711
- Upgrade to Worker SDK v14.8.0. [#1458](https://github.com/spatialos/gdk-for-unity/pull/1458)
812
- Migrated launch configurations to latest game templates. [#1457](https://github.com/spatialos/gdk-for-unity/pull/1457)
9-
- Added `MeansImplicitUse` attribute to `RequireAttribute` to reduce warnings in Rider IDE. [#1462](https://github.com/spatialos/gdk-for-unity/pull/1462)
13+
- Multithreaded component serialization through `SystemBase` jobs. [#1454](https://github.com/spatialos/gdk-for-unity/pull/1454)
1014

1115
## `0.3.10` - 2020-08-18
1216

workers/unity/Assets/Playground/Config/EntityTemplates.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static EntityTemplate CreateCubeEntityTemplate(Vector3 location)
6969
var template = new EntityTemplate();
7070
template.AddComponent(new Position.Snapshot(location.ToCoordinates()), WorkerUtils.UnityGameLogic);
7171
template.AddComponent(new Metadata.Snapshot("Cube"), WorkerUtils.UnityGameLogic);
72-
template.AddComponent(new Persistence.Snapshot(), WorkerUtils.UnityGameLogic);
72+
template.AddComponent(new Persistence.Snapshot());
7373
template.AddComponent(new CubeColor.Snapshot(), WorkerUtils.UnityGameLogic);
7474
template.AddComponent(new CubeTargetVelocity.Snapshot(new Vector3f(-2.0f, 0, 0)),
7575
WorkerUtils.UnityGameLogic);
@@ -99,7 +99,7 @@ public static EntityTemplate CreateSpinnerEntityTemplate(Coordinates coords)
9999
template.AddComponent(new Position.Snapshot(coords), WorkerUtils.UnityGameLogic);
100100
template.AddComponent(new Metadata.Snapshot("Spinner"), WorkerUtils.UnityGameLogic);
101101
template.AddComponent(transform, WorkerUtils.UnityGameLogic);
102-
template.AddComponent(new Persistence.Snapshot(), WorkerUtils.UnityGameLogic);
102+
template.AddComponent(new Persistence.Snapshot());
103103
template.AddComponent(new Collisions.Snapshot(), WorkerUtils.UnityGameLogic);
104104
template.AddComponent(new SpinnerColor.Snapshot(Color.BLUE), WorkerUtils.UnityGameLogic);
105105
template.AddComponent(new SpinnerRotation.Snapshot(), WorkerUtils.UnityGameLogic);
@@ -121,9 +121,9 @@ public static EntityTemplate CreateSpinnerEntityTemplate(Coordinates coords)
121121
public static EntityTemplate CreatePlayerSpawnerEntityTemplate(Coordinates playerSpawnerLocation)
122122
{
123123
var template = new EntityTemplate();
124-
template.AddComponent(new Position.Snapshot(playerSpawnerLocation), WorkerUtils.UnityGameLogic);
125-
template.AddComponent(new Metadata.Snapshot("PlayerCreator"), WorkerUtils.UnityGameLogic);
126-
template.AddComponent(new Persistence.Snapshot(), WorkerUtils.UnityGameLogic);
124+
template.AddComponent(new Position.Snapshot(playerSpawnerLocation));
125+
template.AddComponent(new Metadata.Snapshot("PlayerCreator"));
126+
template.AddComponent(new Persistence.Snapshot());
127127
template.AddComponent(new PlayerCreator.Snapshot(), WorkerUtils.UnityGameLogic);
128128

129129
return template;

workers/unity/Assets/Tests/PlaymodeTests/Performance/ComponentUpdateTests.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,10 @@ public void SinglePositionUpdate()
2626
{
2727
var markers = new[]
2828
{
29-
"GatherAllChunks",
30-
"ExecuteReplication",
31-
"Position.SendUpdates",
29+
"SpatialOSSendSystem.CompletingAllJobs",
30+
"SpatialOSSendSystem.QueueSerializedMessages",
3231
"WorkerSystem.SendMessages",
33-
"Position.ComponentSerializer.Serialize"
32+
"PositionSerializationJob"
3433
};
3534

3635
var currentState = World.Step(world =>

workers/unity/Packages/io.improbable.gdk.core/.codegen/Source/CoreCodegenJob.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public CoreCodegenJob(CodegenJobOptions options, IFileSystem fileSystem, Details
5252
Logger.Trace("Adding job targets for components.");
5353
AddGenerators(componentsToGenerate,
5454
c => ($"{c.Name}.cs", UnityComponentDataGenerator.Generate),
55-
c => ($"{c.Name}UpdateSender.cs", UnityComponentSenderGenerator.Generate),
55+
c => ($"{c.Name}ReplicationSystem.cs", UnityComponentReplicationSystemGenerator.Generate),
5656
c => ($"{c.Name}EcsViewManager.cs", UnityEcsViewManagerGenerator.Generate),
5757
c => ($"{c.Name}ComponentDiffStorage.cs", ComponentDiffStorageGenerator.Generate),
5858
c => ($"{c.Name}ComponentDiffDeserializer.cs", ComponentDiffDeserializerGenerator.Generate),

workers/unity/Packages/io.improbable.gdk.core/.codegen/Source/Generators/Core/ComponentDiffDeserializerGenerator.cs

+2-15
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,7 @@ public uint GetComponentId()
109109
{
110110
m.ProfileScope("serializeMarker", s =>
111111
{
112-
s.Line(@"
113-
var storage = messages.GetComponentDiffStorage(ComponentId);
114-
115-
var updates = ((IDiffUpdateStorage<Update>) storage).GetUpdates();
116-
117-
for (int i = 0; i < updates.Count; ++i)
118-
{
119-
ref readonly var update = ref updates[i];
120-
var schemaUpdate = SchemaComponentUpdate.Create();
121-
var componentUpdate = new ComponentUpdate(ComponentId, schemaUpdate);
122-
Serialization.SerializeUpdate(update.Update, schemaUpdate);
123-
serializedMessages.AddComponentUpdate(componentUpdate, update.EntityId.Id);
124-
}
125-
");
112+
s.Line("var storage = messages.GetComponentDiffStorage(ComponentId);");
126113

127114
foreach (var ev in eventDetailsList)
128115
{
@@ -138,7 +125,7 @@ public uint GetComponentId()
138125
var componentUpdate = new ComponentUpdate(ComponentId, schemaUpdate);
139126
var obj = schemaUpdate.GetEvents().AddObject({ev.EventIndex});
140127
{ev.FqnPayloadType}.Serialization.Serialize(ev.Event.Payload, obj);
141-
serializedMessages.AddComponentUpdate(componentUpdate, ev.EntityId.Id);
128+
serializedMessages.AddComponentEvent(componentUpdate, ev.EntityId.Id);
142129
}}
143130
"
144131
});

workers/unity/Packages/io.improbable.gdk.core/.codegen/Source/Generators/Core/MetaclassGenerator.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static CodeWriter Generate(UnityComponentDetails componentDetails)
4040
public Type Snapshot {{ get; }} = typeof({rootNamespace}.Snapshot);
4141
public Type Update {{ get; }} = typeof({rootNamespace}.Update);
4242
43-
public Type ReplicationHandler {{ get; }} = typeof({rootNamespace}.ComponentReplicator);
43+
public Type ReplicationSystem {{ get; }} = typeof({rootNamespace}.ReplicationSystem);
4444
public Type Serializer {{ get; }} = typeof({rootNamespace}.ComponentSerializer);
4545
public Type DiffDeserializer {{ get; }} = typeof({rootNamespace}.DiffComponentDeserializer);
4646
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using Improbable.Gdk.CodeGeneration.CodeWriter;
2+
using Improbable.Gdk.CodeGeneration.Model.Details;
3+
using NLog;
4+
5+
namespace Improbable.Gdk.CodeGenerator
6+
{
7+
public static class UnityComponentReplicationSystemGenerator
8+
{
9+
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
10+
11+
public static CodeWriter Generate(UnityComponentDetails componentDetails)
12+
{
13+
var componentNamespace = $"global::{componentDetails.Namespace}.{componentDetails.Name}";
14+
15+
Logger.Trace($"Generating {componentDetails.Namespace}.{componentDetails.Name}.ReplicationSystem internal class.");
16+
17+
return CodeWriter.Populate(cgw =>
18+
{
19+
cgw.UsingDirectives(
20+
"Improbable.Gdk.Core",
21+
"Improbable.Worker.CInterop",
22+
"Unity.Collections",
23+
"Unity.Entities",
24+
"Unity.Profiling"
25+
);
26+
27+
cgw.Namespace(componentDetails.Namespace, ns =>
28+
{
29+
ns.Type($"public partial class {componentDetails.Name}", partial =>
30+
{
31+
partial.Annotate("DisableAutoCreation, UpdateInGroup(typeof(SpatialOSSendGroup)), UpdateBefore(typeof(SpatialOSSendGroup.InternalSpatialOSSendGroup))")
32+
.Type("internal class ReplicationSystem : SystemBase", system =>
33+
{
34+
system.Line($@"
35+
private NativeQueue<SerializedMessagesToSend.UpdateToSend> dirtyComponents;
36+
private SpatialOSSendSystem spatialOsSendSystem;
37+
38+
private ProfilerMarker foreachMarker = new ProfilerMarker(""{componentDetails.Name}SerializationJob"");
39+
40+
protected override void OnCreate()
41+
{{
42+
spatialOsSendSystem = World.GetExistingSystem<SpatialOSSendSystem>();
43+
}}
44+
");
45+
system.Method("protected override void OnUpdate()", m =>
46+
{
47+
m.Line(new[]
48+
{
49+
"dirtyComponents = new NativeQueue<SerializedMessagesToSend.UpdateToSend>(Allocator.TempJob);",
50+
"var dirtyComponentsWriter = dirtyComponents.AsParallelWriter();",
51+
"var marker = foreachMarker;",
52+
});
53+
54+
m.Line($@"
55+
Dependency = Entities.WithName(""{componentDetails.Name}Replication"")");
56+
if (!componentDetails.IsBlittable)
57+
{
58+
m.Line(@"
59+
.WithoutBurst()");
60+
}
61+
62+
m.Line(@"
63+
.WithAll<HasAuthority>()
64+
.WithChangeFilter<Component>()
65+
.ForEach((ref Component component, in SpatialEntityId entity) =>
66+
{
67+
marker.Begin();
68+
if (!component.IsDataDirty())
69+
{
70+
marker.End();
71+
return;
72+
}
73+
74+
// Serialize component
75+
var schemaUpdate = SchemaComponentUpdate.Create();
76+
Serialization.SerializeUpdate(component, schemaUpdate);
77+
78+
component.MarkDataClean();
79+
80+
// Schedule update
81+
var componentUpdate = new ComponentUpdate(ComponentId, schemaUpdate);
82+
var update = new SerializedMessagesToSend.UpdateToSend(componentUpdate, entity.EntityId.Id);
83+
dirtyComponentsWriter.Enqueue(update);
84+
marker.End();
85+
})
86+
.ScheduleParallel(Dependency);
87+
88+
spatialOsSendSystem.AddReplicationJobProducer(Dependency, dirtyComponents);
89+
dirtyComponents = default;
90+
");
91+
});
92+
});
93+
});
94+
});
95+
});
96+
}
97+
}
98+
}

workers/unity/Packages/io.improbable.gdk.core/.codegen/Source/Generators/Core/UnityComponentSenderGenerator.cs

-105
This file was deleted.

workers/unity/Packages/io.improbable.gdk.core/Components/IComponentMetaclass.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface IComponentMetaclass
1313
Type Snapshot { get; }
1414
Type Update { get; }
1515

16-
Type ReplicationHandler { get; }
16+
Type ReplicationSystem { get; }
1717
Type Serializer { get; }
1818
Type DiffDeserializer { get; }
1919

workers/unity/Packages/io.improbable.gdk.core/Improbable.Gdk.Core.asmdef

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"references": [
44
"Unity.Entities",
55
"Unity.Entities.Hybrid",
6-
"Unity.Mathematics"
6+
"Unity.Mathematics",
7+
"Unity.Collections"
78
],
89
"includePlatforms": [],
910
"excludePlatforms": [],
@@ -12,5 +13,6 @@
1213
"precompiledReferences": [],
1314
"autoReferenced": true,
1415
"defineConstraints": [],
15-
"versionDefines": []
16+
"versionDefines": [],
17+
"noEngineReferences": false
1618
}

0 commit comments

Comments
 (0)