From 8f34e061ec79066c3029cbdb5d004dd410fcdcc1 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:16:32 -0800 Subject: [PATCH 01/12] Prepare native AOT tests --- .gitignore | 1 + .../FlatSharp.Runtime.csproj | 2 + .../GeneratedSerializerWrapper.cs | 8 +- src/FlatSharp.Runtime/IO/ArrayInputBuffer.cs | 16 ---- .../IO/ArraySegmentInputBuffer.cs | 16 ---- src/FlatSharp.Runtime/IO/IInputBuffer.cs | 24 ------ src/FlatSharp.Runtime/IO/MemoryInputBuffer.cs | 16 ---- .../IO/ReadOnlyMemoryInputBuffer.cs | 16 ---- src/FlatSharp.Runtime/SortedVectorHelpers.cs | 10 +++ .../CompileTests/NativeAot/NativeAot.csproj | 17 ++++ .../CompileTests/NativeAot/NativeAot.sln | 31 +++++++ src/Tests/CompileTests/NativeAot/Program.cs | 81 +++++++++++++++++++ src/Tests/CompileTests/NativeAot/Schema.fbs | 26 ++++++ 13 files changed, 172 insertions(+), 92 deletions(-) create mode 100644 src/Tests/CompileTests/NativeAot/NativeAot.csproj create mode 100644 src/Tests/CompileTests/NativeAot/NativeAot.sln create mode 100644 src/Tests/CompileTests/NativeAot/Program.cs create mode 100644 src/Tests/CompileTests/NativeAot/Schema.fbs diff --git a/.gitignore b/.gitignore index b33eaac6..cbdb58f4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ /src/Benchmarks/ExperimentalBenchmark/FlatSharp.generated.cs /src/Tests/FlatSharpEndToEndTests_Generated/FlatSharpEndToEndTestsGenerated.xml **/BenchmarkDotNet.Artifacts/** +/src/Tests/CompileTests/NativeAot/FlatSharp.generated.cs diff --git a/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj b/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj index db9cce9a..6e253074 100644 --- a/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj +++ b/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj @@ -14,6 +14,8 @@ enable + true + true diff --git a/src/FlatSharp.Runtime/GeneratedSerializerWrapper.cs b/src/FlatSharp.Runtime/GeneratedSerializerWrapper.cs index 141f1ce7..44a01ae8 100644 --- a/src/FlatSharp.Runtime/GeneratedSerializerWrapper.cs +++ b/src/FlatSharp.Runtime/GeneratedSerializerWrapper.cs @@ -119,19 +119,19 @@ public T Parse(TInputBuffer buffer, FlatBufferDeserializationOptio switch (option ?? this.option) { case FlatBufferDeserializationOption.Lazy: - item = buffer.InvokeLazyParse(inner, in parseArgs); + item = inner.ParseLazy(buffer, in parseArgs); break; case FlatBufferDeserializationOption.Greedy: - item = buffer.InvokeGreedyParse(inner, in parseArgs); + item = inner.ParseGreedy(buffer, in parseArgs); break; case FlatBufferDeserializationOption.GreedyMutable: - item = buffer.InvokeGreedyMutableParse(inner, in parseArgs); + item = inner.ParseGreedyMutable(buffer, in parseArgs); break; case FlatBufferDeserializationOption.Progressive: - item = buffer.InvokeProgressiveParse(inner, in parseArgs); + item = inner.ParseProgressive(buffer, in parseArgs); break; default: diff --git a/src/FlatSharp.Runtime/IO/ArrayInputBuffer.cs b/src/FlatSharp.Runtime/IO/ArrayInputBuffer.cs index 8dc550fc..11692f89 100644 --- a/src/FlatSharp.Runtime/IO/ArrayInputBuffer.cs +++ b/src/FlatSharp.Runtime/IO/ArrayInputBuffer.cs @@ -133,20 +133,4 @@ public ReadOnlyMemory GetReadOnlyMemory() { return this.memory; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeLazyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseLazy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeProgressiveParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseProgressive(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyMutableParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedyMutable(this, in arguments); } diff --git a/src/FlatSharp.Runtime/IO/ArraySegmentInputBuffer.cs b/src/FlatSharp.Runtime/IO/ArraySegmentInputBuffer.cs index 5a2fe07f..e3de0e77 100644 --- a/src/FlatSharp.Runtime/IO/ArraySegmentInputBuffer.cs +++ b/src/FlatSharp.Runtime/IO/ArraySegmentInputBuffer.cs @@ -134,22 +134,6 @@ public ReadOnlyMemory GetReadOnlyMemory() return this.pointer.segment; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeLazyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseLazy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeProgressiveParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseProgressive(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyMutableParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedyMutable(this, in arguments); - // Array Segment is a relatively heavy struct. It contains an array pointer, an int offset, and and int length. // Copying this by value for each method call is actually slower than having a little private pointer to a single item. private class ArraySegmentPointer diff --git a/src/FlatSharp.Runtime/IO/IInputBuffer.cs b/src/FlatSharp.Runtime/IO/IInputBuffer.cs index 690ebfad..9563a864 100644 --- a/src/FlatSharp.Runtime/IO/IInputBuffer.cs +++ b/src/FlatSharp.Runtime/IO/IInputBuffer.cs @@ -112,28 +112,4 @@ public interface IInputBuffer /// Gets a memory covering the entire input buffer. /// Memory GetMemory(); - - /// - /// Invokes the parse method on the parameter. Allows passing - /// generic parameters. - /// - TItem InvokeLazyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments); - - /// - /// Invokes the parse method on the parameter. Allows passing - /// generic parameters. - /// - TItem InvokeProgressiveParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments); - - /// - /// Invokes the parse method on the parameter. Allows passing - /// generic parameters. - /// - TItem InvokeGreedyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments); - - /// - /// Invokes the parse method on the parameter. Allows passing - /// generic parameters. - /// - TItem InvokeGreedyMutableParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments); } \ No newline at end of file diff --git a/src/FlatSharp.Runtime/IO/MemoryInputBuffer.cs b/src/FlatSharp.Runtime/IO/MemoryInputBuffer.cs index d9f260c5..dedeb7ee 100644 --- a/src/FlatSharp.Runtime/IO/MemoryInputBuffer.cs +++ b/src/FlatSharp.Runtime/IO/MemoryInputBuffer.cs @@ -138,22 +138,6 @@ public Memory GetMemory() return this.pointer.memory; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeLazyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseLazy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeProgressiveParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseProgressive(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyMutableParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedyMutable(this, in arguments); - // Memory is a relatively heavy struct. It's cheaper to wrap it in a // a reference that will be collected ephemerally in Gen0 than it is to // copy it around. diff --git a/src/FlatSharp.Runtime/IO/ReadOnlyMemoryInputBuffer.cs b/src/FlatSharp.Runtime/IO/ReadOnlyMemoryInputBuffer.cs index 046940c1..84df4e78 100644 --- a/src/FlatSharp.Runtime/IO/ReadOnlyMemoryInputBuffer.cs +++ b/src/FlatSharp.Runtime/IO/ReadOnlyMemoryInputBuffer.cs @@ -132,22 +132,6 @@ public ReadOnlyMemory GetReadOnlyMemory() return this.pointer.memory; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeLazyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseLazy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeProgressiveParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseProgressive(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedy(this, in arguments); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TItem InvokeGreedyMutableParse(IGeneratedSerializer serializer, in GeneratedSerializerParseArguments arguments) - => serializer.ParseGreedyMutable(this, in arguments); - public Span GetSpan() { FSThrow.InvalidOperation(ErrorMessage); diff --git a/src/FlatSharp.Runtime/SortedVectorHelpers.cs b/src/FlatSharp.Runtime/SortedVectorHelpers.cs index 1e134fb2..0c65d044 100644 --- a/src/FlatSharp.Runtime/SortedVectorHelpers.cs +++ b/src/FlatSharp.Runtime/SortedVectorHelpers.cs @@ -35,6 +35,7 @@ of this software and associated documentation files (the "Software"), to deal using System.Reflection; using System.Diagnostics.CodeAnalysis; using System.Net.WebSockets; +using System.Runtime.InteropServices; namespace FlatSharp; @@ -187,9 +188,18 @@ internal static class KeyLookup { static KeyLookup() { +#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER // Convention is for static constructors in the table to register key lookups. Force them to run here before fields // are accessed. + if (RuntimeFeature.IsDynamicCodeSupported) // this should be true for all cases except native AOT. This does not need to run for NativeAOT since static constructors are pre-executed. + { +#pragma warning disable IL2059 + RuntimeHelpers.RunClassConstructor(typeof(TTable).TypeHandle); +#pragma warning restore IL2059 + } +#else RuntimeHelpers.RunClassConstructor(typeof(TTable).TypeHandle); +#endif } private static string NotInitializedErrorMessage = $"Type '{typeof(TTable).Name}' has not registered a sorted vector key of type '{typeof(TKey).Name}'."; diff --git a/src/Tests/CompileTests/NativeAot/NativeAot.csproj b/src/Tests/CompileTests/NativeAot/NativeAot.csproj new file mode 100644 index 00000000..ae61f423 --- /dev/null +++ b/src/Tests/CompileTests/NativeAot/NativeAot.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + annotations + true + true + true + + + + + + + diff --git a/src/Tests/CompileTests/NativeAot/NativeAot.sln b/src/Tests/CompileTests/NativeAot/NativeAot.sln new file mode 100644 index 00000000..19ccea0d --- /dev/null +++ b/src/Tests/CompileTests/NativeAot/NativeAot.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34616.47 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeAot", "NativeAot.csproj", "{FE0D4FB2-1E8E-4A2B-81C0-A23384C66598}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlatSharp.Runtime", "..\..\..\FlatSharp.Runtime\FlatSharp.Runtime.csproj", "{39A4F280-BC8A-498A-8F0A-E617DEA455FA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FE0D4FB2-1E8E-4A2B-81C0-A23384C66598}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE0D4FB2-1E8E-4A2B-81C0-A23384C66598}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE0D4FB2-1E8E-4A2B-81C0-A23384C66598}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE0D4FB2-1E8E-4A2B-81C0-A23384C66598}.Release|Any CPU.Build.0 = Release|Any CPU + {39A4F280-BC8A-498A-8F0A-E617DEA455FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39A4F280-BC8A-498A-8F0A-E617DEA455FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39A4F280-BC8A-498A-8F0A-E617DEA455FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39A4F280-BC8A-498A-8F0A-E617DEA455FA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DAA100EE-7E3A-4209-985E-2CA4FCB8F1E4} + EndGlobalSection +EndGlobal diff --git a/src/Tests/CompileTests/NativeAot/Program.cs b/src/Tests/CompileTests/NativeAot/Program.cs new file mode 100644 index 00000000..c4f65158 --- /dev/null +++ b/src/Tests/CompileTests/NativeAot/Program.cs @@ -0,0 +1,81 @@ +using FlatSharp; + +namespace NativeAot +{ + internal class Program + { + static void Main(string[] args) + { + Root root = new() + { + IndexedVector = new IndexedVector + { + new KeyValuePair { Key = "a", Value = 0 }, + new KeyValuePair { Key = "b", Value = 1 }, + new KeyValuePair { Key = "c", Value = 2 }, + }, + IntVector = new int[] { 1, 2, 3 }, + StructVector = new List + { + new Vec3 { X = 1, Y = 2, Z = 3 }, + new Vec3 { X = 4, Y = 5, Z = 6 }, + new Vec3 { X = 7, Y = 8, Z = 9 }, + } + }; + + int maxSize = Root.Serializer.GetMaxSize(root); + Console.WriteLine("Max size: " + maxSize); + + byte[] buffer = new byte[maxSize]; + int bytesWritten = Root.Serializer.Write(buffer, root); + + Console.WriteLine("Serialization complete. Bytes written = " + bytesWritten); + + foreach (var option in Enum.GetValues()) + { + Traverse(root, new(buffer), option); + Traverse(root, new(buffer), option); + Traverse(root, new(buffer), option); + Traverse(root, new(buffer), option); + } + } + + public static void Traverse(Root original, TInputBuffer buffer, FlatBufferDeserializationOption option) + where TInputBuffer : IInputBuffer + { + Console.WriteLine($"Parsing [ {option} ][ {typeof(TInputBuffer).Name} ]"); + + Root parsed = Root.Serializer.Parse(buffer, option); + + for (int i = 0; i < original.IntVector.Count; ++i) + { + if (original.IntVector[i] != parsed.IntVector[i]) + { + throw new Exception(); + } + } + + foreach (var kvp in original.IndexedVector) + { + string key = kvp.Key; + int value = kvp.Value.Value; + + if (!parsed.IndexedVector.TryGetValue(key, out var parsedValue) || parsedValue.Value != value) + { + throw new Exception(); + } + } + + for (int i = 0; i < original.StructVector.Count; ++i) + { + Vec3 originalItem = original.StructVector[i]; + Vec3 parsedItem = parsed.StructVector[i]; + + if (originalItem.X != parsedItem.X || originalItem.Y != parsedItem.Y || originalItem.Z != parsedItem.Z) + { + throw new Exception(); + } + } + } + } +} diff --git a/src/Tests/CompileTests/NativeAot/Schema.fbs b/src/Tests/CompileTests/NativeAot/Schema.fbs new file mode 100644 index 00000000..07242a62 --- /dev/null +++ b/src/Tests/CompileTests/NativeAot/Schema.fbs @@ -0,0 +1,26 @@ + +attribute "fs_serializer"; +attribute "fs_valueStruct"; +attribute "fs_vector"; + +namespace NativeAot; + +struct Vec3 +{ + x : float; + y : float; + z : float; +} + +table KeyValuePair +{ + key : string (key); + value : int; +} + +table Root (fs_serializer) +{ + struct_vector : [ Vec3 ]; + int_vector : [ int ]; + indexed_vector : [ KeyValuePair ] (fs_vector:"IIndexedVector"); +} \ No newline at end of file From ff872feb6b892710a12fc74790347cdd69a57bfe Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:17:56 -0800 Subject: [PATCH 02/12] Update csproj --- src/FlatSharp.Runtime/FlatSharp.Runtime.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj b/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj index 6e253074..cbd6b77e 100644 --- a/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj +++ b/src/FlatSharp.Runtime/FlatSharp.Runtime.csproj @@ -14,8 +14,7 @@ enable - true - true + true From 44c5630c23b0721a656afaa1d35af0e03c12b5e7 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:23:06 -0800 Subject: [PATCH 03/12] Create NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/NativeAotTest.yml diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml new file mode 100644 index 00000000..aa4cdeab --- /dev/null +++ b/.github/workflows/NativeAotTest.yml @@ -0,0 +1,57 @@ +name: NativeAot Validation + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + os: [ windows-latest, ubuntu-latest, macos-latest ] + runs-on: ${{ matrix.os }} + env: + AppVeyorBuild: true + steps: + - uses: actions/checkout@v2 + + - name: Setup .NET 8 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + working-directory: src + run: dotnet restore + + - name: Build FlatSharp.Compiler + working-directory: src/FlatSharp.Compiler + run: dotnet build -c Release + + - name: Run FlatSharp.Compiler + # You may pin to the exact commit or the version. + # uses: Amadevus/pwsh-script@97a8b211a5922816aa8a69ced41fa32f23477186 + uses: Amadevus/pwsh-script@v2.0.3 + with: + # PowerShell script to execute in Actions-hydrated context + script: | + $fbs = (gci -r src/Tests/CompileTests/NativeAot/*.fbs) -join ";" + dotnet src/FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o src/tests/CompileTests/NativeAot + + - name: Build + working-directory: src/tests/CompileTests/NativeAot + run: dotnet publish -c Release -r win-x64 -f net8.0 + + - name: Run + working-directory: src/tests/CompileTests/NativeAot/bin/Release/net8.0/win-x64/publish + run: NativeAot + + - name: Upload Files + uses: actions/upload-artifact@v3 + if: failure() + with: + name: generated-csharp + path: src/tests/CompileTests/NativeAot/bin/**/*.* From 5a97c721089cc74d321ff2ffb8f1aba0d82e1510 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:26:11 -0800 Subject: [PATCH 04/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index aa4cdeab..fb9f68e0 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -39,14 +39,14 @@ jobs: # PowerShell script to execute in Actions-hydrated context script: | $fbs = (gci -r src/Tests/CompileTests/NativeAot/*.fbs) -join ";" - dotnet src/FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o src/tests/CompileTests/NativeAot + dotnet src/FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o src/Tests/CompileTests/NativeAot - name: Build - working-directory: src/tests/CompileTests/NativeAot + working-directory: src/Tests/CompileTests/NativeAot run: dotnet publish -c Release -r win-x64 -f net8.0 - name: Run - working-directory: src/tests/CompileTests/NativeAot/bin/Release/net8.0/win-x64/publish + working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/win-x64/publish run: NativeAot - name: Upload Files @@ -54,4 +54,4 @@ jobs: if: failure() with: name: generated-csharp - path: src/tests/CompileTests/NativeAot/bin/**/*.* + path: src/Tests/CompileTests/NativeAot/bin/**/*.* From 5c8dc10b4eaf0962745a50098327239c6f1d722e Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:35:21 -0800 Subject: [PATCH 05/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index fb9f68e0..56895e24 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -11,7 +11,14 @@ jobs: build: strategy: matrix: - os: [ windows-latest, ubuntu-latest, macos-latest ] + include: + - os: windows-latest + rid: win-x64 + - os: ubuntu-latest + rid: linux-x64 + - os: macos-latest + rid: macos-x64 + runs-on: ${{ matrix.os }} env: AppVeyorBuild: true @@ -43,10 +50,10 @@ jobs: - name: Build working-directory: src/Tests/CompileTests/NativeAot - run: dotnet publish -c Release -r win-x64 -f net8.0 + run: dotnet publish -c Release -r ${{ matrix.rid }} -f net8.0 - name: Run - working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/win-x64/publish + working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish run: NativeAot - name: Upload Files From 72f777fd03459da049295b7bca673a09162e91b6 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:39:16 -0800 Subject: [PATCH 06/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index 56895e24..278da9fd 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -17,7 +17,7 @@ jobs: - os: ubuntu-latest rid: linux-x64 - os: macos-latest - rid: macos-x64 + rid: osx-x64 runs-on: ${{ matrix.os }} env: From 7f2b4c08cf9288077f1e0180b16732620f23a513 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:43:13 -0800 Subject: [PATCH 07/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index 278da9fd..e329b809 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -52,9 +52,15 @@ jobs: working-directory: src/Tests/CompileTests/NativeAot run: dotnet publish -c Release -r ${{ matrix.rid }} -f net8.0 - - name: Run + - if: runner.os == 'Windows' + name: Run working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish - run: NativeAot + run: NativeAot.exe + + - if: runner.os != 'Windows' + name: Run + working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish + run: ./NativeAot - name: Upload Files uses: actions/upload-artifact@v3 From ac310b4855008f4556160f819e32517f3a0a6ea8 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:50:14 -0800 Subject: [PATCH 08/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index e329b809..d5f98eb2 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -52,10 +52,10 @@ jobs: working-directory: src/Tests/CompileTests/NativeAot run: dotnet publish -c Release -r ${{ matrix.rid }} -f net8.0 - - if: runner.os == 'Windows' - name: Run - working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish - run: NativeAot.exe + #- if: runner.os == 'Windows' + # name: Run + # working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish + # run: NativeAot.exe - if: runner.os != 'Windows' name: Run @@ -64,7 +64,6 @@ jobs: - name: Upload Files uses: actions/upload-artifact@v3 - if: failure() with: - name: generated-csharp + name: assembly path: src/Tests/CompileTests/NativeAot/bin/**/*.* From c81fc0cc2ca6e84bf74f9845bc6c6bfa6b3a2881 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 16:58:43 -0800 Subject: [PATCH 09/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index d5f98eb2..cd70c4c5 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -52,10 +52,10 @@ jobs: working-directory: src/Tests/CompileTests/NativeAot run: dotnet publish -c Release -r ${{ matrix.rid }} -f net8.0 - #- if: runner.os == 'Windows' - # name: Run - # working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish - # run: NativeAot.exe + - if: runner.os == 'Windows' + name: Run + working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish + run: NativeAot - if: runner.os != 'Windows' name: Run From 8737dcc83a75783370666cd43938144621cc83ae Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 18:04:20 -0800 Subject: [PATCH 10/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index cd70c4c5..90690aca 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -55,7 +55,7 @@ jobs: - if: runner.os == 'Windows' name: Run working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish - run: NativeAot + run: ./NativeAot - if: runner.os != 'Windows' name: Run From bc1da7a4f7ab736d78678296e3a0e2b11a4ca0c0 Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 18:10:05 -0800 Subject: [PATCH 11/12] Update NativeAotTest.yml --- .github/workflows/NativeAotTest.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/NativeAotTest.yml b/.github/workflows/NativeAotTest.yml index 90690aca..35a2daff 100644 --- a/.github/workflows/NativeAotTest.yml +++ b/.github/workflows/NativeAotTest.yml @@ -51,14 +51,8 @@ jobs: - name: Build working-directory: src/Tests/CompileTests/NativeAot run: dotnet publish -c Release -r ${{ matrix.rid }} -f net8.0 - - - if: runner.os == 'Windows' - name: Run - working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish - run: ./NativeAot - - - if: runner.os != 'Windows' - name: Run + + - name: Run working-directory: src/Tests/CompileTests/NativeAot/bin/Release/net8.0/${{ matrix.rid }}/publish run: ./NativeAot From 4b8fce1b67b3db1f415bb986b68af8c2b2310ead Mon Sep 17 00:00:00 2001 From: James Courtney Date: Fri, 23 Feb 2024 19:42:56 -0800 Subject: [PATCH 12/12] Add some more useful output --- src/Tests/CompileTests/NativeAot/Program.cs | 178 +++++++++++++++++--- 1 file changed, 151 insertions(+), 27 deletions(-) diff --git a/src/Tests/CompileTests/NativeAot/Program.cs b/src/Tests/CompileTests/NativeAot/Program.cs index c4f65158..a098acbf 100644 --- a/src/Tests/CompileTests/NativeAot/Program.cs +++ b/src/Tests/CompileTests/NativeAot/Program.cs @@ -1,4 +1,6 @@ using FlatSharp; +using System.Diagnostics; +using System.Text; namespace NativeAot { @@ -6,14 +8,15 @@ internal class Program { static void Main(string[] args) { + IndexedVector indexedVector = new(); + for (int i = 0; i < 1000; ++i) + { + indexedVector.Add(new KeyValuePair { Key = Guid.NewGuid().ToString(), Value = i }); + } + Root root = new() { - IndexedVector = new IndexedVector - { - new KeyValuePair { Key = "a", Value = 0 }, - new KeyValuePair { Key = "b", Value = 1 }, - new KeyValuePair { Key = "c", Value = 2 }, - }, + IndexedVector = indexedVector, IntVector = new int[] { 1, 2, 3 }, StructVector = new List { @@ -27,9 +30,22 @@ static void Main(string[] args) Console.WriteLine("Max size: " + maxSize); byte[] buffer = new byte[maxSize]; - int bytesWritten = Root.Serializer.Write(buffer, root); + int bytesWritten = 0; + + for (int i = 0; i < 10; ++i) + { + bytesWritten = Root.Serializer.Write(buffer, root); + } + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 1000; ++i) + { + bytesWritten = Root.Serializer.Write(buffer, root); + } + sw.Stop(); - Console.WriteLine("Serialization complete. Bytes written = " + bytesWritten); + Console.WriteLine($"Serialization complete. Bytes written = {bytesWritten}. TotalTime = {sw.Elapsed.TotalMicroseconds:N0}us"); + Console.WriteLine(); foreach (var option in Enum.GetValues()) { @@ -37,44 +53,152 @@ static void Main(string[] args) Traverse(root, new(buffer), option); Traverse(root, new(buffer), option); Traverse(root, new(buffer), option); + Traverse(root, new(new ArrayInputBuffer(buffer)), option); + Console.WriteLine(); } } public static void Traverse(Root original, TInputBuffer buffer, FlatBufferDeserializationOption option) where TInputBuffer : IInputBuffer { - Console.WriteLine($"Parsing [ {option} ][ {typeof(TInputBuffer).Name} ]"); + for (int i = 0; i < 10; ++i) + { + ParseAndTraverse(original, buffer, option); + } + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 1000; ++i) + { + ParseAndTraverse(original, buffer, option); + } + sw.Stop(); - Root parsed = Root.Serializer.Parse(buffer, option); + Console.WriteLine($"Parsing [ {option} ][ {typeof(TInputBuffer).Name} ]. TotalTime = {sw.Elapsed.TotalMicroseconds:N0}us"); - for (int i = 0; i < original.IntVector.Count; ++i) + static void ParseAndTraverse(Root original, TInputBuffer buffer, FlatBufferDeserializationOption option) { - if (original.IntVector[i] != parsed.IntVector[i]) + Root parsed = Root.Serializer.Parse(buffer, option); + + for (int i = 0; i < original.IntVector.Count; ++i) { - throw new Exception(); + if (original.IntVector[i] != parsed.IntVector[i]) + { + throw new Exception(); + } } - } - foreach (var kvp in original.IndexedVector) - { - string key = kvp.Key; - int value = kvp.Value.Value; + foreach (var kvp in original.IndexedVector) + { + string key = kvp.Key; + int value = kvp.Value.Value; - if (!parsed.IndexedVector.TryGetValue(key, out var parsedValue) || parsedValue.Value != value) + if (!parsed.IndexedVector.TryGetValue(key, out var parsedValue) || parsedValue.Value != value) + { + throw new Exception(); + } + } + + for (int i = 0; i < original.StructVector.Count; ++i) { - throw new Exception(); + Vec3 originalItem = original.StructVector[i]; + Vec3 parsedItem = parsed.StructVector[i]; + + if (originalItem.X != parsedItem.X || originalItem.Y != parsedItem.Y || originalItem.Z != parsedItem.Z) + { + throw new Exception(); + } } } + } - for (int i = 0; i < original.StructVector.Count; ++i) + private class CustomInputBuffer : IInputBuffer + { + private readonly IInputBuffer inner; + + public CustomInputBuffer(IInputBuffer inner) { - Vec3 originalItem = original.StructVector[i]; - Vec3 parsedItem = parsed.StructVector[i]; + this.inner = inner; + } - if (originalItem.X != parsedItem.X || originalItem.Y != parsedItem.Y || originalItem.Z != parsedItem.Z) - { - throw new Exception(); - } + public bool IsReadOnly => inner.IsReadOnly; + + public bool IsPinned => inner.IsPinned; + + public int Length => inner.Length; + + public Memory GetMemory() + { + return inner.GetMemory(); + } + + public ReadOnlyMemory GetReadOnlyMemory() + { + return inner.GetReadOnlyMemory(); + } + + public ReadOnlySpan GetReadOnlySpan() + { + return inner.GetReadOnlySpan(); + } + + public Span GetSpan() + { + return inner.GetSpan(); + } + + public byte ReadByte(int offset) + { + return inner.ReadByte(offset); + } + + public double ReadDouble(int offset) + { + return inner.ReadDouble(offset); + } + + public float ReadFloat(int offset) + { + return inner.ReadFloat(offset); + } + + public int ReadInt(int offset) + { + return inner.ReadInt(offset); + } + + public long ReadLong(int offset) + { + return inner.ReadLong(offset); + } + + public sbyte ReadSByte(int offset) + { + return inner.ReadSByte(offset); + } + + public short ReadShort(int offset) + { + return inner.ReadShort(offset); + } + + public string ReadString(int offset, int byteLength, Encoding encoding) + { + return inner.ReadString(offset, byteLength, encoding); + } + + public uint ReadUInt(int offset) + { + return inner.ReadUInt(offset); + } + + public ulong ReadULong(int offset) + { + return inner.ReadULong(offset); + } + + public ushort ReadUShort(int offset) + { + return inner.ReadUShort(offset); } } }