feat: integrate performance upgrade and agent inspection tooling
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using ShrinkContext;
|
||||
using ShrinkNetwork;
|
||||
using ShrinkEventBus;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public sealed class PlayerContracts
|
||||
{
|
||||
[Test]
|
||||
public void DotNetGoldenFrameIsIdenticalInPlayer()
|
||||
{
|
||||
var bytes = UnityEngine.Resources.Load<UnityEngine.TextAsset>("ShrinkV2Golden").bytes;
|
||||
var packet = ShrinkPacketCodec.Decode(bytes);
|
||||
var codec = new ShrinkJsonNetworkSerializer();
|
||||
var message = (Message)codec.Deserialize(packet.Payload, typeof(Message));
|
||||
Assert.That(message.Text, Is.EqualTo("跨宿主-v2"));
|
||||
using var encoded = ShrinkPacketCodec.Encode(new ShrinkNetworkPacket { Opcode = 42, Route = "跨宿主" }, codec, message);
|
||||
Assert.That(encoded.WrittenMemory.ToArray(), Is.EqualTo(bytes));
|
||||
}
|
||||
[Test]
|
||||
public void BinaryEnvelopeAndLegacyRejection()
|
||||
{
|
||||
var codec = new ShrinkJsonNetworkSerializer();
|
||||
foreach (var size in new[] { 64, 1024, 32768 })
|
||||
{
|
||||
var message = new Message { Text = new string('x', size) };
|
||||
using var frame = ShrinkPacketCodec.Encode(new ShrinkNetworkPacket { Opcode = 42, Route = "跨宿主" }, codec, message);
|
||||
var packet = ShrinkPacketCodec.Decode(frame.WrittenMemory);
|
||||
Assert.That(((Message)codec.Deserialize(packet.Payload, typeof(Message))).Text, Is.EqualTo(message.Text));
|
||||
var copy = frame.WrittenMemory.ToArray(); copy[4] = 1;
|
||||
Assert.Throws<ShrinkProtocolException>(() => ShrinkPacketCodec.Decode(copy));
|
||||
}
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator ContextTenThousandRetirements() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var runtime = new ShrinkContextRuntime(16);
|
||||
var watch = Stopwatch.StartNew();
|
||||
for (var i = 0; i < 10000; i++) await runtime.RetireAsync(runtime.Use(new Provider()));
|
||||
Assert.That(runtime.Fibers.Count, Is.Zero);
|
||||
Assert.That(runtime.CaptureDiagnostic().Fibers.Count, Is.EqualTo(16));
|
||||
UnityEngine.Debug.Log("PLAYER Context 10000 retirements ms=" + watch.Elapsed.TotalMilliseconds);
|
||||
await runtime.ShutdownAsync();
|
||||
});
|
||||
[Test]
|
||||
public void EventDispatchAllocations()
|
||||
{
|
||||
using var binding = ShrinkGeneratedBinding.Subscribe<Event>(ShrinkGeneratedBinding.RuntimeResolver, null, null, null, _ => { }, ShrinkEventPriority.Normal, 0, false);
|
||||
for (var i = 0; i < 100; i++) EventBus.Post(new Event());
|
||||
var watch = Stopwatch.StartNew();
|
||||
for (var i = 0; i < 10000; i++) EventBus.Post(new Event());
|
||||
watch.Stop();
|
||||
var events=PlayerPerformance.AllocationEvents(() => EventBus.Post(new Event()),10000);
|
||||
UnityEngine.Debug.Log("PLAYER EventBus 10000 posts allocationEvents="+events+" ms="+watch.Elapsed.TotalMilliseconds);
|
||||
using var host=new ShrinkEventBusHost();
|
||||
var local=host.CreateBus(ShrinkBusKey.Game,ShrinkBusOptions.Inline());
|
||||
using var localBinding=ShrinkGeneratedBinding.Subscribe<Event>(host,null,null,null,_=>{},ShrinkEventPriority.Normal,0,false);
|
||||
for(var i=0;i<100;i++) local.Post(new Event());
|
||||
var isolatedEvents=PlayerPerformance.AllocationEvents(()=>local.Post(new Event()),10000);
|
||||
UnityEngine.Debug.Log("PLAYER EventBus isolated 10000 posts allocationEvents="+isolatedEvents);
|
||||
Assert.That(isolatedEvents,Is.Zero);
|
||||
Assert.Throws<ArgumentNullException>(()=>local.Post<ReferenceEvent>(null));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator LoopbackRpc() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var a = new ShrinkLoopbackTransport(); var b = new ShrinkLoopbackTransport(); a.LinkPeer(b);
|
||||
var client = new ShrinkNetworkService(); var server = new ShrinkNetworkService();
|
||||
foreach (var service in new[] { client, server }) { service.RegisterMessage<Request>(1); service.RegisterMessage<Response>(2); }
|
||||
server.RegisterRequestHandler<Request, Response>((_, r) => UniTask.FromResult(new Response { Text = r.Text }));
|
||||
client.BindTransport(a); server.BindTransport(b); a.OpenSession(1);
|
||||
try { Assert.That((await client.CallAsync<Request, Response>(client.Sessions[1], new Request { Text = "Unity Player" })).Text, Is.EqualTo("Unity Player")); }
|
||||
finally { a.Stop(); b.Stop(); }
|
||||
});
|
||||
[UnityTest]
|
||||
public IEnumerator SavePhaseMatrix() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var root = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ShrinkPlayerSave-" + Guid.NewGuid().ToString("N"));
|
||||
var storage = new ShrinkDataSaver.LocalStorageProvider(root);
|
||||
var initialize = typeof(ShrinkDataSaver.ShrinkSave).GetMethod("Initialize", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
initialize.Invoke(null, new object[] { storage, System.IO.Path.Combine(root, "saves"), ".sav", 1 });
|
||||
try
|
||||
{
|
||||
foreach (var size in new[] { 100 * 1024, 1024 * 1024, 10 * 1024 * 1024 })
|
||||
foreach (var background in new[] { false, true })
|
||||
{
|
||||
var value = new string('s', size); var owner = System.Threading.Thread.CurrentThread.ManagedThreadId; var captureThread = -1;
|
||||
ShrinkDataSaver.ShrinkSave.RegisterModule("player-benchmark", () => { captureThread = System.Threading.Thread.CurrentThread.ManagedThreadId; return value; }, _ => { });
|
||||
var options = new ShrinkDataSaver.SaveOptions { EncodeInBackground = background, CollectTimings = true };
|
||||
await ShrinkDataSaver.ShrinkSave.SaveSlotAsync(0, options);
|
||||
Assert.That(captureThread, Is.EqualTo(owner));
|
||||
Assert.That(options.LastTimings.EncodedBytes, Is.GreaterThan(size));
|
||||
UnityEngine.Debug.Log("PLAYER Save " + size + " background=" + background + " " + "captureMs=" + options.LastTimings.CaptureMilliseconds + " encodeMs=" + options.LastTimings.EncodeMilliseconds + " encryptMs=" + options.LastTimings.EncryptMilliseconds + " writeMs=" + options.LastTimings.WriteMilliseconds + " bytes=" + options.LastTimings.EncodedBytes);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ShrinkDataSaver.ShrinkSave.UnregisterModule("player-benchmark");
|
||||
if (System.IO.Directory.Exists(root)) System.IO.Directory.Delete(root, true);
|
||||
}
|
||||
});
|
||||
public sealed class Message : IShrinkNetworkMessage { public string Text { get; set; } }
|
||||
public sealed class Request : IShrinkNetworkRequest { public string Text { get; set; } }
|
||||
public sealed class Response : ShrinkRpcResponseBase { public string Text { get; set; } }
|
||||
public readonly struct Event : IShrinkEvent { }
|
||||
public sealed class ReferenceEvent : IShrinkEvent { }
|
||||
private sealed class Provider : IShrinkComponent
|
||||
{
|
||||
public string Name => "test";
|
||||
public IReadOnlyList<string> Inject => Array.Empty<string>();
|
||||
public IReadOnlyList<string> Provide => new[] { "value" };
|
||||
public UniTask ApplyAsync(ShrinkCtx ctx, object config) { ctx.Set("value", this); return UniTask.CompletedTask; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user