Closed austinbhale closed 9 months ago
Hi, sorry for missing this until now. One quick question: is the behavior reproducible outside of UWP and without StereoKit? Can you construct a more minimal test example that exhibits the behavior?
No worries! Yes, I've modified the script to a DotNet console app where you can comment out the specific portion in the Vertex
struct to use either 1) common float array or 2) MathNet types. The tests at the bottom also exhibit the runtime differences when TrackMessageSize
is enabled or not.
using Microsoft.Psi;
using Microsoft.Psi.Data;
using System.Diagnostics;
using MathNet.Spatial.Euclidean;
int[] sizes = { 1000, 10000, 20000, 30000 };
foreach (int size in sizes)
{
using var pipeline = Pipeline.Create(
"TestHang",
enableDiagnostics: true,
diagnosticsConfiguration: new Microsoft.Psi.Diagnostics.DiagnosticsConfiguration
{
TrackMessageSize = true,
AveragingTimeSpan = TimeSpan.FromSeconds(2),
SamplingInterval = TimeSpan.FromSeconds(10),
IncludeStoppedPipelines = true,
IncludeStoppedPipelineElements = true,
});
PsiExporter store = PsiStore.Create(pipeline, pipeline.Name, Directory.GetCurrentDirectory());
pipeline.Diagnostics.Write("Diagnostics", store);
Generators.Range(pipeline, 0, 5, TimeSpan.FromMilliseconds(1))
.PipeTo(new TstProducer(pipeline, size))
.PipeTo(new TstReceiver(pipeline));
Stopwatch? sw = null;
pipeline.PipelineRun += (_, _) => { Console.WriteLine("Started!"); sw = Stopwatch.StartNew(); };
pipeline.PipelineCompleted += (_, _) => { Console.WriteLine($"Completed in {sw?.ElapsedMilliseconds}"); };
pipeline.Run();
}
public struct Vertex
{
public Vertex() {}
// TEST 1: common types
public double[] pos = {0, 0, 0};
public double[] norm = {0, 0, 0};
public double[] uv = {0, 0, 0};
// TEST 2: MathNet types
// public Vector3D pos;
// public Vector3D norm;
// public Vector3D uv;
}
class TstProducer : IConsumer<int>, IProducer<Shared<Vertex[]>>
{
public Receiver<int> In { get; }
public Emitter<Shared<Vertex[]>> Out { get; }
public TstProducer(Pipeline pipeline, int size)
{
Out = pipeline.CreateEmitter<Shared<Vertex[]>>(this, nameof(Out));
In = pipeline.CreateReceiver<int>(this, (_, env) =>
{
using var verts = Shared.Create(new Vertex[size]);
Out.Post(verts, env.OriginatingTime);
}, nameof(In));
}
}
class TstReceiver : IConsumer<Shared<Vertex[]>>
{
public Receiver<Shared<Vertex[]>> In { get; }
public TstReceiver(Pipeline pipeline)
{
In = pipeline.CreateReceiver<Shared<Vertex[]>>(this, (msg, env) =>
{
Console.WriteLine($"msg length: {msg.Resource.Length}");
}, nameof(In));
}
}
TrackMessageSize=TRUE
>dotnet run
Started!
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
Completed in 42
Started!
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
Completed in 148
Started!
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
Completed in 1619
Started!
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
Completed in 4974
TrackMessageSize=TRUE
>dotnet run
Started!
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
Completed in 45
Started!
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
Completed in 2989
Started!
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
Completed in 6232
Started!
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
Completed in 12080
TrackMessageSize=FALSE
>dotnet run
Started!
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
Completed in 40
Started!
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
Completed in 4
Started!
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
Completed in 5
Started!
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
Completed in 5
TrackMessageSize=FALSE
>dotnet run
Started!
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
msg length: 1000
Completed in 40
Started!
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
msg length: 10000
Completed in 4
Started!
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
msg length: 20000
Completed in 4
Started!
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
msg length: 30000
Completed in 4
Thanks for the test code. We've identified a buffer allocation issue in BufferWriter
. The fix in #293 should resolve this issue.
That makes a huge difference, thank you all so much!
When enabling diagnostics for a pipeline with
TrackMessageSize
turned on, I found one of my receivers hanging for a very long time, for at least several minutes.I attached a sample x64/ARM UWP script using StereoKit's Vertex struct, which wraps
System.Numerics
data types.When computing the data size, is it expected for serialization to take (sometimes) several milliseconds per element in the array? Is it because it has to resolve the
Systems.Numerics
data type for each value? https://github.com/microsoft/psi/blob/d08fdd34f6957a92a6343d6e7978c2b8efc5f83a/Sources/Runtime/Microsoft.Psi/Serialization/ArraySerializer.cs#L45I tested the array size with different values like so: