Skip to content

Commit

Permalink
feat(server): visualization with lcjs (#45)
Browse files Browse the repository at this point in the history
* refactor: 🚚 server folder structure

* feat: visualization with lcjs

* build(server): add eslint and prettier

* build(server): add lint and format to npm scripts

* fix(server): complex array formatter causing gen2 gc

* build(server): exclude configs from publish
  • Loading branch information
kahojyun authored Jul 21, 2023
1 parent eaa4f8d commit a256eaf
Show file tree
Hide file tree
Showing 56 changed files with 4,490 additions and 173 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ root = true
# All files
[*]
indent_style = space
charset = utf-8

# Xml files
[*.xml]
indent_size = 2

[*.{js,ts}]
indent_size = 2

# C# files
[*.cs]

Expand Down
8 changes: 8 additions & 0 deletions src/Qynit.PulseGen.Server/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* eslint-env node */
module.exports = {
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
root: true,
ignorePatterns: ["**/wwwroot/**/*", "Pages/**/*.js"],
};
3 changes: 3 additions & 0 deletions src/Qynit.PulseGen.Server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Ignore bundled JS files
**/*.razor.js
**/*.razor.js.map
16 changes: 16 additions & 0 deletions src/Qynit.PulseGen.Server/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
1 change: 1 addition & 0 deletions src/Qynit.PulseGen.Server/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
12 changes: 12 additions & 0 deletions src/Qynit.PulseGen.Server/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
55 changes: 55 additions & 0 deletions src/Qynit.PulseGen.Server/ArcUnsafe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace Qynit.PulseGen.Server;

public static class ArcUnsafe
{
public static ArcUnsafe<T> Wrap<T>(T disposable) where T : IDisposable
{
return new ArcUnsafe<T>(disposable);
}
}

public readonly struct ArcUnsafe<T> : IDisposable where T : IDisposable
{
private readonly RefCountBox _refCountBox;
public T Target { get; }

public ArcUnsafe(T disposable)
{
_refCountBox = new RefCountBox();
Target = disposable;
}

public ArcUnsafe<T> Clone()
{
_refCountBox.Acquire();
return this;
}

public void Dispose()
{
var refCount = _refCountBox.Release();
if (refCount == 0)
{
Target.Dispose();
}
}

private class RefCountBox
{
private int _referenceCount;
public int Acquire()
{
return Interlocked.Increment(ref _referenceCount);
}

public int Release()
{
return Interlocked.Decrement(ref _referenceCount);
}

public RefCountBox()
{
Acquire();
}
}
}
41 changes: 35 additions & 6 deletions src/Qynit.PulseGen.Server/ComplexArrayFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;

using MessagePack;
using MessagePack.Formatters;
Expand All @@ -21,10 +21,39 @@ public void Serialize(ref MessagePackWriter writer, PooledComplexArray<double> v
}

writer.WriteArrayHeader(2);
var nBytes = sizeof(double) * value.Length;
writer.WriteBinHeader(nBytes);
writer.WriteRaw(MemoryMarshal.AsBytes(value.DataI));
writer.WriteBinHeader(nBytes);
writer.WriteRaw(MemoryMarshal.AsBytes(value.DataQ));
var bytesI = MemoryMarshal.AsBytes(value.DataI);
var bytesQ = MemoryMarshal.AsBytes(value.DataQ);
var length = bytesI.Length;
if (length <= ushort.MaxValue)
{
writer.Write(bytesI);
writer.Write(bytesQ);
}
else
{
WriteBinHeader(ref writer, length);
writer.WriteRaw(bytesI);
WriteBinHeader(ref writer, length);
writer.WriteRaw(bytesQ);
}
}

private static void WriteBinHeader(ref MessagePackWriter writer, int length)
{
var span = writer.GetSpan(5);
span[0] = MessagePackCode.Bin32;
WriteBigEndian(length, span[1..]);
writer.Advance(5);
}

private static void WriteBigEndian(int value, Span<byte> span)
{
unchecked
{
span[3] = (byte)value;
span[2] = (byte)(value >> 8);
span[1] = (byte)(value >> 16);
span[0] = (byte)(value >> 24);
}
}
}
9 changes: 9 additions & 0 deletions src/Qynit.PulseGen.Server/DisposableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Qynit.PulseGen.Server;

internal static class DisposableExtensions
{
public static ArcUnsafe<T> ToArc<T>(this T disposable) where T : IDisposable
{
return new ArcUnsafe<T>(disposable);
}
}
6 changes: 6 additions & 0 deletions src/Qynit.PulseGen.Server/Hubs/IPlotClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Qynit.PulseGen.Server.Hubs;

public interface IPlotClient
{
Task ReceiveNames(IEnumerable<string> names);
}
8 changes: 8 additions & 0 deletions src/Qynit.PulseGen.Server/Hubs/PlotHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.SignalR;

namespace Qynit.PulseGen.Server.Hubs;

public class PlotHub : Hub<IPlotClient>
{
public const string Uri = "/plot/hub";
}
11 changes: 0 additions & 11 deletions src/Qynit.PulseGen.Server/Instruction.cs

This file was deleted.

28 changes: 0 additions & 28 deletions src/Qynit.PulseGen.Server/IqWaveform.cs

This file was deleted.

5 changes: 5 additions & 0 deletions src/Qynit.PulseGen.Server/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@inherits LayoutComponentBase

<PageTitle>PulseGen Viewer</PageTitle>

<main> @Body </main>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record ChannelInfo(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record HannShapeInfo : ShapeInfo
Expand Down
11 changes: 11 additions & 0 deletions src/Qynit.PulseGen.Server/Models/InstructionDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using MessagePack;

namespace Qynit.PulseGen.Server.Models;

[Union(0, typeof(PlayDto))]
[Union(1, typeof(ShiftPhaseDto))]
[Union(2, typeof(SetPhaseDto))]
[Union(3, typeof(ShiftFrequencyDto))]
[Union(4, typeof(SetFrequencyDto))]
[Union(5, typeof(SwapPhaseDto))]
public abstract record InstructionDto;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record InterpolatedShapeInfo(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record Play(
public sealed record PlayDto(
[property: Key(0)] double Time,
[property: Key(1)] int ChannelId,
[property: Key(2)] int ShapeId,
Expand All @@ -12,4 +12,4 @@ public sealed record Play(
[property: Key(5)] double FrequencyShift,
[property: Key(6)] double PhaseShift,
[property: Key(7)] double Amplitude,
[property: Key(8)] double DragCoefficient) : Instruction;
[property: Key(8)] double DragCoefficient) : InstructionDto;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record PulseGenRequest(
[property: Key(0)] IList<ChannelInfo> ChannelTable,
[property: Key(1)] IList<ShapeInfo> ShapeTable,
[property: Key(2)] IEnumerable<Instruction> Instructions);
[property: Key(2)] IEnumerable<InstructionDto> Instructions);
28 changes: 28 additions & 0 deletions src/Qynit.PulseGen.Server/Models/PulseGenResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using MessagePack;

namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed class PulseGenResponse : IDisposable
{
[Key(0)]
public IList<PooledComplexArray<double>> Waveforms { get; set; } = null!;

private readonly List<ArcUnsafe<PooledComplexArray<double>>> _disposables = null!;

public PulseGenResponse() { }

public PulseGenResponse(List<ArcUnsafe<PooledComplexArray<double>>> waveforms)
{
_disposables = waveforms;
Waveforms = _disposables.Select(x => x.Target).ToList();
}

public void Dispose()
{
foreach (var disposable in _disposables)
{
disposable.Dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

using MessagePack;

namespace Qynit.PulseGen.Server;
namespace Qynit.PulseGen.Server.Models;


[Union(0, typeof(PlayElementDto))]
Expand Down Expand Up @@ -66,7 +66,7 @@ public override ScheduleElement GetScheduleElement(ScheduleRequest request)
{
var shapes = request.ShapeTable;
Debug.Assert(shapes is not null);
var pulseShape = (ShapeId == -1) ? null : shapes[ShapeId].GetPulseShape();
var pulseShape = ShapeId == -1 ? null : shapes[ShapeId].GetPulseShape();
var envelope = new Envelope(pulseShape, Width, Plateau);
return new PlayElement(ChannelId, envelope, Frequency, Phase, Amplitude, DragCoefficient)
{
Expand Down Expand Up @@ -336,15 +336,3 @@ public override ScheduleElement GetScheduleElement(ScheduleRequest request)
return result;
}
}


[MessagePackObject]
public sealed class ScheduleRequest
{
[Key(0)]
public IList<ChannelInfo>? ChannelTable { get; init; }
[Key(1)]
public IList<ShapeInfo>? ShapeTable { get; init; }
[Key(2)]
public ScheduleElementDto? Schedule { get; init; }
}
14 changes: 14 additions & 0 deletions src/Qynit.PulseGen.Server/Models/ScheduleRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using MessagePack;

namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed class ScheduleRequest
{
[Key(0)]
public IList<ChannelInfo>? ChannelTable { get; init; }
[Key(1)]
public IList<ShapeInfo>? ShapeTable { get; init; }
[Key(2)]
public ScheduleElementDto? Schedule { get; init; }
}
9 changes: 9 additions & 0 deletions src/Qynit.PulseGen.Server/Models/SetFrequencyDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MessagePack;

namespace Qynit.PulseGen.Server.Models;

[MessagePackObject]
public sealed record SetFrequencyDto(
[property: Key(0)] double Time,
[property: Key(1)] int ChannelId,
[property: Key(2)] double Frequency) : InstructionDto;
Loading

0 comments on commit a256eaf

Please sign in to comment.