com.wallstop-studios.dxmessaging 2.0.0-rc14 → 2.0.0-rc16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.config/dotnet-tools.json +10 -0
- package/.editorconfig +184 -0
- package/.pre-commit-config.yaml +22 -0
- package/README.md +12 -11
- package/Runtime/Core/InstanceId.cs +7 -6
- package/Runtime/Core/MessageBus/IMessageBus.cs +36 -30
- package/Runtime/Core/MessageBus/MessageBus.cs +8 -2
- package/Runtime/Core/MessageHandler.cs +169 -155
- package/Runtime/Core/MessagingDebug.cs +2 -2
- package/Runtime/Unity/MessageAwareComponent.cs +0 -1
- package/Tests/Runtime/Benchmarks/PerformanceTests.cs +129 -78
- package/Tests/Runtime/Core/MessagingTestBase.cs +24 -9
- package/package.json +2 -2
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/// <summary>
|
|
17
|
-
/// Debug functionality for all
|
|
17
|
+
/// Debug functionality for all the Messaging Components.
|
|
18
18
|
/// </summary>
|
|
19
19
|
public static class MessagingDebug
|
|
20
20
|
{
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
public static Action<LogLevel, string> LogFunction = null;
|
|
30
30
|
|
|
31
31
|
/// <summary>
|
|
32
|
-
/// Logs a message to the debug log function
|
|
32
|
+
/// Logs a message to the debug log function if it's not null.
|
|
33
33
|
/// </summary>
|
|
34
34
|
/// <param name="logLevel">Severity of the message.</param>
|
|
35
35
|
/// <param name="message">Message to log.</param>
|
|
@@ -6,59 +6,30 @@
|
|
|
6
6
|
using DxMessaging.Core;
|
|
7
7
|
using DxMessaging.Core.Extensions;
|
|
8
8
|
using global::Unity.PerformanceTesting;
|
|
9
|
-
using global::Unity.Profiling;
|
|
10
9
|
using NUnit.Framework;
|
|
11
10
|
using Scripts.Components;
|
|
12
11
|
using Scripts.Messages;
|
|
13
12
|
using UnityEngine;
|
|
14
|
-
using UnityEngine.
|
|
13
|
+
using UnityEngine.TestTools.Constraints;
|
|
15
14
|
using Debug = UnityEngine.Debug;
|
|
15
|
+
using Is = NUnit.Framework.Is;
|
|
16
16
|
using Object = UnityEngine.Object;
|
|
17
17
|
|
|
18
18
|
public sealed class PerformanceTests : MessagingTestBase
|
|
19
19
|
{
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
if (bytes < 1024)
|
|
23
|
-
{
|
|
24
|
-
return $"{bytes} B";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
string[] sizes = { "KB", "MB", "GB", "TB", "PB", "EB" };
|
|
28
|
-
double len = bytes;
|
|
29
|
-
int order = 0;
|
|
30
|
-
|
|
31
|
-
while (1024 <= len && order < sizes.Length - 1)
|
|
32
|
-
{
|
|
33
|
-
len /= 1024;
|
|
34
|
-
order++;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return $"{len:0.##} {sizes[order]}";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
[SetUp]
|
|
41
|
-
public override void Setup()
|
|
42
|
-
{
|
|
43
|
-
base.Setup();
|
|
44
|
-
MessagingDebug.LogFunction = (_, _) => { };
|
|
45
|
-
}
|
|
20
|
+
protected override bool MessagingDebugEnabled => false;
|
|
46
21
|
|
|
47
22
|
[Test]
|
|
48
23
|
public void Benchmark()
|
|
49
24
|
{
|
|
50
25
|
TimeSpan timeout = TimeSpan.FromSeconds(2);
|
|
51
26
|
|
|
52
|
-
Debug.Log("| Message Tech | Operations / Second |
|
|
53
|
-
Debug.Log("| ------------ | ------------------- |
|
|
27
|
+
Debug.Log("| Message Tech | Operations / Second | Allocations? |");
|
|
28
|
+
Debug.Log("| ------------ | ------------------- | ------------ | ");
|
|
54
29
|
|
|
55
30
|
ComplexTargetedMessage message = new(Guid.NewGuid());
|
|
56
31
|
Stopwatch timer = Stopwatch.StartNew();
|
|
57
|
-
|
|
58
|
-
ProfilerCategory.Memory,
|
|
59
|
-
"GC.Alloc"
|
|
60
|
-
);
|
|
61
|
-
recorder.Stop();
|
|
32
|
+
|
|
62
33
|
RunTest(component => Unity(timer, timeout, component.gameObject, message));
|
|
63
34
|
RunTest(component => NormalGameObject(timer, timeout, component, message));
|
|
64
35
|
RunTest(component => NormalComponent(timer, timeout, component, message));
|
|
@@ -77,16 +48,19 @@
|
|
|
77
48
|
MessageRegistrationToken token = GetToken(
|
|
78
49
|
go.GetComponent<EmptyMessageAwareComponent>()
|
|
79
50
|
);
|
|
51
|
+
// ReSharper disable once NotAccessedVariable
|
|
80
52
|
int count = 0;
|
|
81
53
|
token.RegisterGameObjectBroadcast<SimpleBroadcastMessage>(go, Handle);
|
|
82
54
|
|
|
83
55
|
SimpleBroadcastMessage message = new();
|
|
56
|
+
SampleGroup time = new("Time", SampleUnit.Nanosecond);
|
|
84
57
|
|
|
85
58
|
Measure
|
|
86
59
|
.Method(() => message.EmitGameObjectBroadcast(go))
|
|
60
|
+
.SampleGroup(time)
|
|
87
61
|
.WarmupCount(10)
|
|
88
|
-
.IterationsPerMeasurement(
|
|
89
|
-
.MeasurementCount(
|
|
62
|
+
.IterationsPerMeasurement(1)
|
|
63
|
+
.MeasurementCount(10_000)
|
|
90
64
|
.Run();
|
|
91
65
|
return;
|
|
92
66
|
|
|
@@ -104,16 +78,19 @@
|
|
|
104
78
|
MessageRegistrationToken token = GetToken(
|
|
105
79
|
go.GetComponent<EmptyMessageAwareComponent>()
|
|
106
80
|
);
|
|
81
|
+
// ReSharper disable once NotAccessedVariable
|
|
107
82
|
int count = 0;
|
|
108
83
|
token.RegisterGameObjectTargeted<SimpleTargetedMessage>(go, Handle);
|
|
109
84
|
|
|
110
85
|
SimpleTargetedMessage message = new();
|
|
86
|
+
SampleGroup time = new("Time", SampleUnit.Nanosecond);
|
|
111
87
|
|
|
112
88
|
Measure
|
|
113
89
|
.Method(() => message.EmitGameObjectTargeted(go))
|
|
90
|
+
.SampleGroup(time)
|
|
114
91
|
.WarmupCount(10)
|
|
115
|
-
.IterationsPerMeasurement(
|
|
116
|
-
.MeasurementCount(
|
|
92
|
+
.IterationsPerMeasurement(1)
|
|
93
|
+
.MeasurementCount(10_000)
|
|
117
94
|
.Run();
|
|
118
95
|
return;
|
|
119
96
|
|
|
@@ -131,16 +108,19 @@
|
|
|
131
108
|
MessageRegistrationToken token = GetToken(
|
|
132
109
|
go.GetComponent<EmptyMessageAwareComponent>()
|
|
133
110
|
);
|
|
111
|
+
// ReSharper disable once NotAccessedVariable
|
|
134
112
|
int count = 0;
|
|
135
113
|
token.RegisterUntargeted<SimpleUntargetedMessage>(Handle);
|
|
136
114
|
|
|
137
115
|
SimpleUntargetedMessage message = new();
|
|
116
|
+
SampleGroup time = new("Time", SampleUnit.Nanosecond);
|
|
138
117
|
|
|
139
118
|
Measure
|
|
140
119
|
.Method(() => message.EmitUntargeted())
|
|
120
|
+
.SampleGroup(time)
|
|
141
121
|
.WarmupCount(10)
|
|
142
|
-
.IterationsPerMeasurement(
|
|
143
|
-
.MeasurementCount(
|
|
122
|
+
.IterationsPerMeasurement(1)
|
|
123
|
+
.MeasurementCount(10_000)
|
|
144
124
|
.Run();
|
|
145
125
|
return;
|
|
146
126
|
|
|
@@ -169,11 +149,11 @@
|
|
|
169
149
|
string testName,
|
|
170
150
|
int count,
|
|
171
151
|
TimeSpan timeout,
|
|
172
|
-
|
|
152
|
+
bool allocating
|
|
173
153
|
)
|
|
174
154
|
{
|
|
175
155
|
Debug.Log(
|
|
176
|
-
$"| {testName} | {Math.Floor(count / timeout.TotalSeconds):N0} | {
|
|
156
|
+
$"| {testName} | {Math.Floor(count / timeout.TotalSeconds):N0} | {(allocating ? "Yes" : "No")} |"
|
|
177
157
|
);
|
|
178
158
|
}
|
|
179
159
|
|
|
@@ -201,10 +181,12 @@
|
|
|
201
181
|
int count = 0;
|
|
202
182
|
var component = target.AddComponent<SimpleMessageAwareComponent>();
|
|
203
183
|
component.slowComplexTargetedHandler = () => ++count;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
184
|
+
// Pre-warm
|
|
185
|
+
target.SendMessage(
|
|
186
|
+
nameof(SimpleMessageAwareComponent.HandleSlowComplexTargetedMessage),
|
|
187
|
+
message
|
|
207
188
|
);
|
|
189
|
+
|
|
208
190
|
timer.Restart();
|
|
209
191
|
do
|
|
210
192
|
{
|
|
@@ -213,8 +195,25 @@
|
|
|
213
195
|
message
|
|
214
196
|
);
|
|
215
197
|
} while (timer.Elapsed < timeout);
|
|
216
|
-
|
|
217
|
-
|
|
198
|
+
|
|
199
|
+
bool allocating;
|
|
200
|
+
try
|
|
201
|
+
{
|
|
202
|
+
Assert.That(
|
|
203
|
+
() =>
|
|
204
|
+
target.SendMessage(
|
|
205
|
+
nameof(SimpleMessageAwareComponent.HandleSlowComplexTargetedMessage),
|
|
206
|
+
message
|
|
207
|
+
),
|
|
208
|
+
Is.Not.AllocatingGCMemory()
|
|
209
|
+
);
|
|
210
|
+
allocating = false;
|
|
211
|
+
}
|
|
212
|
+
catch
|
|
213
|
+
{
|
|
214
|
+
allocating = true;
|
|
215
|
+
}
|
|
216
|
+
DisplayCount("Unity", count, timeout, allocating);
|
|
218
217
|
}
|
|
219
218
|
|
|
220
219
|
private void NormalGameObject(
|
|
@@ -229,18 +228,26 @@
|
|
|
229
228
|
|
|
230
229
|
GameObject go = component.gameObject;
|
|
231
230
|
token.RegisterGameObjectTargeted<ComplexTargetedMessage>(go, Handle);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
);
|
|
231
|
+
// Pre-warm
|
|
232
|
+
message.EmitGameObjectTargeted(go);
|
|
233
|
+
|
|
236
234
|
timer.Restart();
|
|
237
235
|
do
|
|
238
236
|
{
|
|
239
237
|
message.EmitGameObjectTargeted(go);
|
|
240
238
|
} while (timer.Elapsed < timeout);
|
|
239
|
+
bool allocating;
|
|
240
|
+
try
|
|
241
|
+
{
|
|
242
|
+
Assert.That(() => message.EmitGameObjectTargeted(go), Is.Not.AllocatingGCMemory());
|
|
243
|
+
allocating = false;
|
|
244
|
+
}
|
|
245
|
+
catch
|
|
246
|
+
{
|
|
247
|
+
allocating = true;
|
|
248
|
+
}
|
|
241
249
|
|
|
242
|
-
|
|
243
|
-
DisplayCount("DxMessaging (GameObject) - Normal", count, timeout, recorder.LastValue);
|
|
250
|
+
DisplayCount("DxMessaging (GameObject) - Normal", count, timeout, allocating);
|
|
244
251
|
return;
|
|
245
252
|
|
|
246
253
|
void Handle(ComplexTargetedMessage _)
|
|
@@ -260,17 +267,29 @@
|
|
|
260
267
|
var token = GetToken(component);
|
|
261
268
|
|
|
262
269
|
token.RegisterComponentTargeted<ComplexTargetedMessage>(component, Handle);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
);
|
|
270
|
+
// Pre-warm
|
|
271
|
+
message.EmitComponentTargeted(component);
|
|
272
|
+
|
|
267
273
|
timer.Restart();
|
|
268
274
|
do
|
|
269
275
|
{
|
|
270
276
|
message.EmitComponentTargeted(component);
|
|
271
277
|
} while (timer.Elapsed < timeout);
|
|
272
|
-
|
|
273
|
-
|
|
278
|
+
|
|
279
|
+
bool allocating;
|
|
280
|
+
try
|
|
281
|
+
{
|
|
282
|
+
Assert.That(
|
|
283
|
+
() => message.EmitComponentTargeted(component),
|
|
284
|
+
Is.Not.AllocatingGCMemory()
|
|
285
|
+
);
|
|
286
|
+
allocating = false;
|
|
287
|
+
}
|
|
288
|
+
catch
|
|
289
|
+
{
|
|
290
|
+
allocating = true;
|
|
291
|
+
}
|
|
292
|
+
DisplayCount("DxMessaging (Component) - Normal", count, timeout, allocating);
|
|
274
293
|
return;
|
|
275
294
|
|
|
276
295
|
void Handle(ComplexTargetedMessage _)
|
|
@@ -291,17 +310,28 @@
|
|
|
291
310
|
|
|
292
311
|
GameObject go = component.gameObject;
|
|
293
312
|
token.RegisterGameObjectTargeted<ComplexTargetedMessage>(go, Handle);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
);
|
|
313
|
+
// Pre-warm
|
|
314
|
+
message.EmitGameObjectTargeted(component.gameObject);
|
|
315
|
+
|
|
298
316
|
timer.Restart();
|
|
299
317
|
do
|
|
300
318
|
{
|
|
301
319
|
message.EmitGameObjectTargeted(component.gameObject);
|
|
302
320
|
} while (timer.Elapsed < timeout);
|
|
303
|
-
|
|
304
|
-
|
|
321
|
+
bool allocating;
|
|
322
|
+
try
|
|
323
|
+
{
|
|
324
|
+
Assert.That(
|
|
325
|
+
() => message.EmitGameObjectTargeted(component.gameObject),
|
|
326
|
+
Is.Not.AllocatingGCMemory()
|
|
327
|
+
);
|
|
328
|
+
allocating = false;
|
|
329
|
+
}
|
|
330
|
+
catch
|
|
331
|
+
{
|
|
332
|
+
allocating = true;
|
|
333
|
+
}
|
|
334
|
+
DisplayCount("DxMessaging (GameObject) - No-Copy", count, timeout, allocating);
|
|
305
335
|
return;
|
|
306
336
|
|
|
307
337
|
void Handle(ref ComplexTargetedMessage _)
|
|
@@ -321,17 +351,29 @@
|
|
|
321
351
|
var token = GetToken(component);
|
|
322
352
|
|
|
323
353
|
token.RegisterComponentTargeted<ComplexTargetedMessage>(component, Handle);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
);
|
|
354
|
+
// Pre-warm
|
|
355
|
+
message.EmitComponentTargeted(component);
|
|
356
|
+
|
|
328
357
|
timer.Restart();
|
|
329
358
|
do
|
|
330
359
|
{
|
|
331
360
|
message.EmitComponentTargeted(component);
|
|
332
361
|
} while (timer.Elapsed < timeout);
|
|
333
|
-
|
|
334
|
-
|
|
362
|
+
|
|
363
|
+
bool allocating;
|
|
364
|
+
try
|
|
365
|
+
{
|
|
366
|
+
Assert.That(
|
|
367
|
+
() => message.EmitComponentTargeted(component),
|
|
368
|
+
Is.Not.AllocatingGCMemory()
|
|
369
|
+
);
|
|
370
|
+
allocating = false;
|
|
371
|
+
}
|
|
372
|
+
catch
|
|
373
|
+
{
|
|
374
|
+
allocating = true;
|
|
375
|
+
}
|
|
376
|
+
DisplayCount("DxMessaging (Component) - No-Copy", count, timeout, allocating);
|
|
335
377
|
return;
|
|
336
378
|
|
|
337
379
|
void Handle(ref ComplexTargetedMessage _)
|
|
@@ -351,17 +393,26 @@
|
|
|
351
393
|
var token = GetToken(component);
|
|
352
394
|
|
|
353
395
|
token.RegisterUntargeted<SimpleUntargetedMessage>(Handle);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
);
|
|
396
|
+
// Pre-warm
|
|
397
|
+
message.EmitUntargeted();
|
|
398
|
+
|
|
358
399
|
timer.Restart();
|
|
359
400
|
do
|
|
360
401
|
{
|
|
361
402
|
message.EmitUntargeted();
|
|
362
403
|
} while (timer.Elapsed < timeout);
|
|
363
|
-
|
|
364
|
-
|
|
404
|
+
|
|
405
|
+
bool allocating;
|
|
406
|
+
try
|
|
407
|
+
{
|
|
408
|
+
Assert.That(() => message.EmitUntargeted(), Is.Not.AllocatingGCMemory());
|
|
409
|
+
allocating = false;
|
|
410
|
+
}
|
|
411
|
+
catch
|
|
412
|
+
{
|
|
413
|
+
allocating = true;
|
|
414
|
+
}
|
|
415
|
+
DisplayCount("DxMessaging (Untargeted) - No-Copy", count, timeout, allocating);
|
|
365
416
|
return;
|
|
366
417
|
|
|
367
418
|
void Handle(ref SimpleUntargetedMessage _)
|
|
@@ -22,9 +22,12 @@
|
|
|
22
22
|
protected readonly List<GameObject> _spawned = new();
|
|
23
23
|
protected readonly Random _random = new();
|
|
24
24
|
|
|
25
|
+
protected virtual bool MessagingDebugEnabled => true;
|
|
26
|
+
|
|
25
27
|
[SetUp]
|
|
26
28
|
public virtual void Setup()
|
|
27
29
|
{
|
|
30
|
+
MessagingDebug.enabled = MessagingDebugEnabled;
|
|
28
31
|
MessagingDebug.LogFunction = (level, message) =>
|
|
29
32
|
{
|
|
30
33
|
switch (level)
|
|
@@ -45,6 +48,18 @@
|
|
|
45
48
|
Assert.IsNotNull(messageBus);
|
|
46
49
|
messageBus.Log.Enabled = true;
|
|
47
50
|
_numRegistrations = 150;
|
|
51
|
+
|
|
52
|
+
LogMessageBusStatus();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected void LogMessageBusStatus()
|
|
56
|
+
{
|
|
57
|
+
MessageBus messageBus = MessageHandler.MessageBus;
|
|
58
|
+
Debug.Log(
|
|
59
|
+
$"Untargeted registrations: {messageBus.RegisteredUntargeted}, "
|
|
60
|
+
+ $"targeted registrations: {messageBus.RegisteredTargeted}, "
|
|
61
|
+
+ $"broadcast registrations: {messageBus.RegisteredBroadcast}."
|
|
62
|
+
);
|
|
48
63
|
}
|
|
49
64
|
|
|
50
65
|
[TearDown]
|
|
@@ -154,20 +169,12 @@
|
|
|
154
169
|
|
|
155
170
|
protected IEnumerator WaitUntilMessageHandlerIsFresh()
|
|
156
171
|
{
|
|
157
|
-
Setup();
|
|
158
172
|
MessageBus messageBus = MessageHandler.MessageBus;
|
|
159
173
|
Assert.IsNotNull(messageBus);
|
|
160
174
|
|
|
161
175
|
Stopwatch timer = Stopwatch.StartNew();
|
|
162
176
|
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
return messageBus.RegisteredUntargeted != 0
|
|
166
|
-
|| messageBus.RegisteredTargeted != 0
|
|
167
|
-
|| messageBus.RegisteredBroadcast != 0;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
while (IsStale() && timer.Elapsed < TimeSpan.FromSeconds(2.5))
|
|
177
|
+
while (IsStale() && timer.Elapsed < TimeSpan.FromSeconds(1.25))
|
|
171
178
|
{
|
|
172
179
|
yield return null;
|
|
173
180
|
}
|
|
@@ -180,6 +187,14 @@
|
|
|
180
187
|
messageBus.RegisteredBroadcast,
|
|
181
188
|
messageBus.Log
|
|
182
189
|
);
|
|
190
|
+
yield break;
|
|
191
|
+
|
|
192
|
+
bool IsStale()
|
|
193
|
+
{
|
|
194
|
+
return messageBus.RegisteredUntargeted != 0
|
|
195
|
+
|| messageBus.RegisteredTargeted != 0
|
|
196
|
+
|| messageBus.RegisteredBroadcast != 0;
|
|
197
|
+
}
|
|
183
198
|
}
|
|
184
199
|
}
|
|
185
200
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "com.wallstop-studios.dxmessaging",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc16",
|
|
4
4
|
"displayName": "DxMessaging",
|
|
5
5
|
"description": "Synchronous Event Bus for Unity",
|
|
6
6
|
"unity": "2021.3",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"com.wallstop-studios.unity-helpers" : "2.0.0-
|
|
8
|
+
"com.wallstop-studios.unity-helpers" : "2.0.0-rc50"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
11
|
"messaging",
|