From 0f7ea8a06184a0c4daa07fb47453916189bff159 Mon Sep 17 00:00:00 2001 From: jmmorato Date: Tue, 8 Oct 2024 13:48:10 +0200 Subject: [PATCH] [feature] CDR structures serialization (#257) * [feature] CDR structures serialization * Test performance * Transport tunning * Use pointer for sample info * Revert "Use pointer for sample info" This reverts commit 982911b3d2e4fec4c5ee6efa4c9ec7b1a13fe259. * Updated dotnet version * Updated latency performance test * Register instance CDR * RTI register instances * Prepare for debug * Added [SuppressGCTransition] * Changed to CallConvSuppressGCTransition * Adjusted transport config * Ensure Release build * Fixed CXX flags * Use CXX 17 * Add optimization for msvc * -DCMAKE_BUILD_TYPE=Release * Added -DCMAKE_BUILD_TYPE=Release * Ensure Release when building * Refactor cmake file * Increased buffers size * Allow Debug builds for Windows OS * Added ToCDR and FromCDR methods * Complie with CXX 14 * Refactor Benchmark performance test * Restore/Build before publish benchmark test * Commented performance test to ensure the cache * Added LD_LIBRARY_PATH to the unix perf test * Use bash shell * Do not run RTI benchmark (no license) * Use sudo user for the perf test * Activate all performance tests * added option -E to sudo calls * Use sudo env * Added env variable in the sudo call * Use pwsh for windows scripts * Build sequentially * Removed ToolExe for windows * Do not use inprocess * append CMAKE_CXX_FLAGS_RELEASE * Use /MD for libraries * Refactored cxx flags * Use InProcessEmitToolchain * Added lib folders to the path * Implemented Nested struct * Escape paths * set path on script * Implemented sequences of structs * Implemented struct array * Implemented structs multi-array * Fixed alignment * Execute full test in windows * Added --project parameter to dotnet run * Only execute once in windows too * Added continue-on-error: true to latency tests --- .github/workflows/ci_standard.yaml | 66 +- .../OpenDDSharp.Build.csproj | 6 +- .../Tasks/BuildOpenDDSharpNativeTask.cs | 12 +- .../Tasks/SetupThirdPartyTask.cs | 15 +- .../ConsoleDemoCore/ConsoleDemoCore.csproj | 6 +- Native/CMakeLists.txt | 2 +- Native/CMakeListsTemplate.txt | 26 +- Native/CSharpCDRImplTemplate.txt | 22 +- Native/CWrapperHeaderTemplate.txt | 2 + Native/CWrapperImplTemplate.txt | 7 + Native/OpenDDSWrapper/CMakeLists.txt | 22 +- Native/OpenDDSharp.IdlGenerator.targets | 14 +- .../OpenDDSharp.IdlGenerator/CMakeLists.txt | 11 +- .../csharp_cdr_generator.cpp | 662 +++++++++++++++--- .../csharp_cdr_generator.h | 6 + .../OpenDDSharp.BuildTasks.csproj | 8 +- .../OpenDDSharp.Marshaller/Cdr/CdrReader.cs | 2 +- .../OpenDDSharp.Marshaller/Cdr/CdrWriter.cs | 2 +- .../OpenDDSharp.Marshaller.csproj | 6 +- Sources/OpenDDSharp/DDS/Duration.cs | 25 + Sources/OpenDDSharp/DDS/SampleInfo.cs | 48 ++ Sources/OpenDDSharp/OpenDDSharp.csproj | 7 +- Sources/OpenDDSharp/TimeValue.cs | 25 + Sources/OpenDDSharp/Timestamp.cs | 25 + .../BenchmarkPerformance.csproj | 2 +- .../LatencyTestConfiguration.cs | 11 +- .../CustomColumns/LatencyAverageColumn.cs | 2 +- .../CustomColumns/LatencyDeviationColumn.cs | 2 +- .../CustomColumns/LatencyFiftyColumn.cs | 2 +- .../CustomColumns/LatencyMaximumColumn.cs | 2 +- .../CustomColumns/LatencyMinimumColumn.cs | 2 +- .../CustomColumns/LatencyNinetyColumn.cs | 2 +- .../CustomColumns/LatencyNinetyNineColumn.cs | 2 +- ...hroughputMissingSamplesPercentageColumn.cs | 2 +- .../ThroughputSamplesReceivedColumn.cs | 2 +- .../PerformanceTests/LatencyTest.cs | 44 +- .../OpenDDSharpLatencyTest.cs | 81 ++- .../PerformanceTests/RtiConnextLatencyTest.cs | 37 +- Tests/BenchmarkPerformance/Program.cs | 105 +-- .../AssemblyInitializer.cs | 2 +- .../CodeGeneratorCdrWrapperTest.cs | 418 ++++++++++- .../OpenDDSharp.UnitTest.csproj | 12 +- Tests/TestIdlCdr/IDL/Test.idl | 36 +- Tests/TestIdlCdr/TestIdlCdr.csproj | 18 +- Tests/TestIdlJson/TestIdlJson.csproj | 14 +- .../TestSupportProcessCore.csproj | 6 +- global.json | 2 +- 47 files changed, 1536 insertions(+), 297 deletions(-) diff --git a/.github/workflows/ci_standard.yaml b/.github/workflows/ci_standard.yaml index 398dc511..9b9f9bc3 100644 --- a/.github/workflows/ci_standard.yaml +++ b/.github/workflows/ci_standard.yaml @@ -114,6 +114,28 @@ jobs: flag-name: coverage-windows-${{ join(matrix.*, '-') }} fail-on-error: false + - name: Add OpenDDS lib folders to path + shell: pwsh + run: | + $env:PATH = "${{ github.workspace }}\ext\OpenDDS_${{ matrix.BuildPlatform }}\lib;${{ github.workspace }}\ext\OpenDDS_${{ matrix.BuildPlatform }}\ACE_wrappers\lib;$env:PATH" + echo "PATH=$env:PATH" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + + - name: Latency Performance Test + shell: cmd + run: | + dotnet clean ${{ github.workspace }}\Tests\TestIdlCdr\TestIdlCdr.csproj + dotnet clean ${{ github.workspace }}\Tests\BenchmarkPerformance\BenchmarkPerformance.csproj + dotnet restore ${{ github.workspace }}\Tests\TestIdlCdr\TestIdlCdr.csproj + dotnet restore ${{ github.workspace }}\Tests\BenchmarkPerformance\BenchmarkPerformance.csproj + dotnet build -m:1 ${{ github.workspace }}\Tests\TestIdlCdr\TestIdlCdr.csproj --configuration Release --runtime win-${{ matrix.BuildPlatform }} + dotnet build -m:1 ${{ github.workspace }}\Tests\BenchmarkPerformance\BenchmarkPerformance.csproj --configuration Release --runtime win-${{ matrix.BuildPlatform }} + dotnet run --project ${{ github.workspace }}\Tests\BenchmarkPerformance\BenchmarkPerformance.csproj "-1" --configuration Release --runtime win-${{ matrix.BuildPlatform }} + env: + DDS_ROOT: "${{ github.workspace }}\\ext\\OpenDDS_${{ matrix.BuildPlatform }}" + ACE_ROOT: "${{ github.workspace }}\\ext\\OpenDDS_${{ matrix.BuildPlatform }}\\ACE_wrappers" + TAO_ROOT: "${{ github.workspace }}\\ext\\OpenDDS_${{ matrix.BuildPlatform }}\\ACE_wrappers\\TAO" + continue-on-error: true + build_linux: runs-on: ubuntu-20.04 @@ -185,6 +207,8 @@ jobs: dotnet restore ${{ github.workspace }}/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj --packages "${{ github.workspace }}/packages" --no-cache --configfile ${{ github.workspace }}/nuget.config dotnet restore ${{ github.workspace }}/Tests/OpenDDSharp.UnitTest/OpenDDSharp.UnitTest.csproj --packages "${{ github.workspace }}/packages" --no-cache --configfile ${{ github.workspace }}/nuget.config dotnet restore ${{ github.workspace }}/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj --packages "${{ github.workspace }}/packages" --no-cache --configfile ${{ github.workspace }}/nuget.config + dotnet restore ${{ github.workspace }}/Tests/TestIdlCdr/TestIdlCdr.csproj --packages "${{ github.workspace }}/packages" --no-cache --configfile ${{ github.workspace }}/nuget.config + dotnet restore ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --packages "${{ github.workspace }}/packages" --no-cache --configfile ${{ github.workspace }}/nuget.config working-directory: ${{ github.workspace }} - name: Build OpenDDSharp.BuildTasks project @@ -243,6 +267,21 @@ jobs: flag-name: coverage-linux-x64-Release fail-on-error: false + - name: Latency Performance Test + shell: bash + run: | + dotnet build ${{ github.workspace }}/Tests/TestIdlCdr/TestIdlCdr.csproj --configuration Release --runtime linux-x64 + dotnet build ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime linux-x64 + dotnet publish ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime linux-x64 + cd ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/linux-x64/publish + sudo LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/linux-x64/publish/BenchmarkPerformance -1 + working-directory: ${{ github.workspace }} + env: + DDS_ROOT: "${{ github.workspace }}/ext/OpenDDS_Linux" + ACE_ROOT: "${{ github.workspace }}/ext/OpenDDS_Linux/ACE_wrappers" + TAO_ROOT: "${{ github.workspace }}/ext/OpenDDS_Linux/ACE_wrappers/TAO" + continue-on-error: true + build_macos_x64: runs-on: macos-13 @@ -372,6 +411,19 @@ jobs: flag-name: coverage-macos-x64-Release fail-on-error: false + - name: Latency Performance Test + shell: bash + run: | + dotnet build ${{ github.workspace }}/Tests/TestIdlCdr/TestIdlCdr.csproj --configuration Release --runtime osx-x64 + dotnet build ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime osx-x64 + dotnet publish ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime osx-x64 + sudo env DYLD_LIBRARY_PATH="./:$DYLD_LIBRARY_PATH" + sudo env DYLD_FALLBACK_LIBRARY_PATH="./:$DYLD_FALLBACK_LIBRARY_PATH" + cd ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/osx-x64/publish + sudo -E ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/osx-x64/publish/BenchmarkPerformance -1 + working-directory: ${{ github.workspace }} + continue-on-error: true + build_macos_arm64: runs-on: macos-14 @@ -501,6 +553,19 @@ jobs: flag-name: coverage-macos-arm64-Release fail-on-error: false + - name: Latency Performance Test + shell: bash + run: | + dotnet build ${{ github.workspace }}/Tests/TestIdlCdr/TestIdlCdr.csproj --configuration Release --runtime osx-arm64 + dotnet build ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime osx-arm64 + dotnet publish ${{ github.workspace }}/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj --configuration Release --runtime osx-arm64 + sudo env DYLD_LIBRARY_PATH="./:$DYLD_LIBRARY_PATH" + sudo env DYLD_FALLBACK_LIBRARY_PATH="./:$DYLD_FALLBACK_LIBRARY_PATH" + cd ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/osx-arm64/publish + sudo -E ${{ github.workspace }}/Tests/BenchmarkPerformance/bin/Release/net8.0/osx-arm64/publish/BenchmarkPerformance -1 + working-directory: ${{ github.workspace }} + continue-on-error: true + publish_coveralls: runs-on: ubuntu-latest needs: [build_windows, build_linux, build_macos_x64, build_macos_arm64] @@ -512,4 +577,3 @@ jobs: parallel-finished: true carryforward: coverage-windows-x64-Release,coverage-windows-x86-Release,coverage-linux-x64-Release,coverage-macos-x64-Release,coverage-macos-arm64-Release fail-on-error: false - diff --git a/Build/OpenDDSharp.Build/OpenDDSharp.Build.csproj b/Build/OpenDDSharp.Build/OpenDDSharp.Build.csproj index a439a8bd..b0708690 100644 --- a/Build/OpenDDSharp.Build/OpenDDSharp.Build.csproj +++ b/Build/OpenDDSharp.Build/OpenDDSharp.Build.csproj @@ -24,7 +24,7 @@ - + all @@ -35,11 +35,11 @@ all - + all - + all diff --git a/Build/OpenDDSharp.Build/Tasks/BuildOpenDDSharpNativeTask.cs b/Build/OpenDDSharp.Build/Tasks/BuildOpenDDSharpNativeTask.cs index adacf342..f298bd1a 100644 --- a/Build/OpenDDSharp.Build/Tasks/BuildOpenDDSharpNativeTask.cs +++ b/Build/OpenDDSharp.Build/Tasks/BuildOpenDDSharpNativeTask.cs @@ -44,22 +44,22 @@ public override void Run(BuildContext context) { buildFoder += $"_{context.BuildPlatform}"; } - var arguments = $"--no-warn-unused-cli -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -A {platform} -H{nativeFolder} -B{buildFoder}"; + var arguments = $"--no-warn-unused-cli -DCMAKE_BUILD_TYPE={context.BuildConfiguration} -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -A {platform} -H{nativeFolder} -B{buildFoder}"; if (BuildContext.IsLinux) { buildFoder += "_Linux"; - arguments = $"--no-warn-unused-cli -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; + arguments = $"--no-warn-unused-cli -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; } else if (BuildContext.IsOSX && BuildContext.IsARM64) { buildFoder += "_osx-arm64"; - arguments = $"--no-warn-unused-cli -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; + arguments = $"--no-warn-unused-cli -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; } else if (BuildContext.IsOSX && !BuildContext.IsARM64) { buildFoder += "_osx-x64"; - arguments = $"--no-warn-unused-cli -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; + arguments = $"--no-warn-unused-cli -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH={Path.GetFullPath(context.DdsRoot)} -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H{nativeFolder} -B{buildFoder}"; } context.CMake(new CMakeSettings @@ -94,6 +94,10 @@ public override void Run(BuildContext context) { buildSettings.Configuration = context.BuildConfiguration; } + else + { + buildSettings.Configuration = "Release"; + } context.CMakeBuild(buildSettings); } } diff --git a/Build/OpenDDSharp.Build/Tasks/SetupThirdPartyTask.cs b/Build/OpenDDSharp.Build/Tasks/SetupThirdPartyTask.cs index c1821b61..7d3fc4f3 100644 --- a/Build/OpenDDSharp.Build/Tasks/SetupThirdPartyTask.cs +++ b/Build/OpenDDSharp.Build/Tasks/SetupThirdPartyTask.cs @@ -117,11 +117,7 @@ public override void Run(BuildContext context) if (BuildContext.IsLinux || BuildContext.IsOSX) { var configurePath = System.IO.Path.Combine(_clonePath.FullPath, "configure"); - var arguments = " -v --doc-group3 --no-test --no-debug --optimize --install-origin-relative --prefix=/usr/lib"; - if (BuildContext.IsOSX) - { - arguments += " --std=c++11"; - } + const string arguments = " -v --doc-group3 --no-test --no-debug --optimize --install-origin-relative --prefix=/usr/lib --std=c++14"; context.Log.Information(arguments); var exit = context.StartProcess(configurePath, new ProcessSettings @@ -148,8 +144,8 @@ public override void Run(BuildContext context) Version = version, }); - var vcvar = $"\\VC\\Auxiliary\\Build\\vcvarsall.bat\" {context.BuildPlatform}"; // -vcvars_ver=14.36.32532 - var arguments = " /c \"" + vsPath.FullPath + vcvar + " && " + configurePath + " -v --doc-group3 --no-test"; + var vcvar = $"\\VC\\Auxiliary\\Build\\vcvarsall.bat\" {context.BuildPlatform}"; + var arguments = " /c \"" + vsPath.FullPath + vcvar + " && " + configurePath + " -v --doc-group3 --no-test --std=c++14"; if (context.BuildConfiguration == "Release") { arguments += " --no-debug --optimize"; @@ -165,6 +161,7 @@ public override void Run(BuildContext context) Arguments = arguments, WorkingDirectory = context.DdsRoot, }); + if (exit != 0) { throw new BuildException($"Error calling the OpenDDS configure script. Exit code: {exit}"); @@ -228,10 +225,10 @@ private string GitDescribe(BuildContext context) { try { - var output = process.GetStandardOutput(); + var output = process.GetStandardOutput().ToList(); if (output.Any()) { - return output.First(); + return output[0]; } } catch diff --git a/Examples/ConsoleDemoCore/ConsoleDemoCore.csproj b/Examples/ConsoleDemoCore/ConsoleDemoCore.csproj index fb6efd50..b07ad62b 100644 --- a/Examples/ConsoleDemoCore/ConsoleDemoCore.csproj +++ b/Examples/ConsoleDemoCore/ConsoleDemoCore.csproj @@ -15,7 +15,7 @@ - + all @@ -26,11 +26,11 @@ all - + all - + all diff --git a/Native/CMakeLists.txt b/Native/CMakeLists.txt index b32fc3c6..f6f2cbf2 100644 --- a/Native/CMakeLists.txt +++ b/Native/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.19.1) +cmake_minimum_required(VERSION 3.19.2) project(Native) diff --git a/Native/CMakeListsTemplate.txt b/Native/CMakeListsTemplate.txt index b907e4d2..10ef3574 100644 --- a/Native/CMakeListsTemplate.txt +++ b/Native/CMakeListsTemplate.txt @@ -1,18 +1,13 @@ -cmake_minimum_required(VERSION 3.19.1) +cmake_minimum_required(VERSION 3.19.2) project(${PROJECT_NAME} CXX) find_package(OpenDDS REQUIRED) -if(MSVC) - add_compile_options(/bigobj) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) -endif() +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) if(APPLE) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) elseif(UNIX) SET(CMAKE_SKIP_BUILD_RPATH FALSE) SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) @@ -22,13 +17,18 @@ endif() add_library(${PROJECT_NAME} SHARED ${WRAPPER_FILES}) if(MSVC) - target_compile_options(${PROJECT_NAME} PUBLIC /wd4190) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /wd4190") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /Oi /D NDEBUG /D NOMINMAX /MD") elseif(APPLE) - target_compile_options(${PROJECT_NAME} PUBLIC -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare) - set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,@executable_path -Wl,-rpath,@loader_path") + set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,@executable_path -Wl,-rpath,@loader_path") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare -pthread") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") elseif(UNIX) - target_compile_options(${PROJECT_NAME} PUBLIC -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,$ORIGIN") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare -pthread") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") endif() OPENDDS_TARGET_SOURCES(${PROJECT_NAME} diff --git a/Native/CSharpCDRImplTemplate.txt b/Native/CSharpCDRImplTemplate.txt index 91703703..5aeac32e 100644 --- a/Native/CSharpCDRImplTemplate.txt +++ b/Native/CSharpCDRImplTemplate.txt @@ -117,10 +117,9 @@ { InstanceHandle ret = InstanceHandle.HandleNil; - var str = _typeSupport.EncodeToString(instance); - var json_data = MarshalHelper.NativeUtf8FromString(str); + var bytes = _typeSupport.EncodeToBytes(instance); - ret = <%TYPE%>DataWriterNative.RegisterInstance(_native, json_data); + ret = <%TYPE%>DataWriterNative.RegisterInstance(_native, bytes, (UIntPtr)bytes.Length); return ret; } @@ -302,8 +301,9 @@ internal static partial IntPtr Narrow(IntPtr dw); [SuppressUnmanagedCodeSecurity] + [SuppressGCTransition] [LibraryImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_Write_Cdr")] - [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] + [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvSuppressGCTransition) })] internal static partial int Write(IntPtr dw, byte[] cdrData, UIntPtr size, int handle); [SuppressUnmanagedCodeSecurity] @@ -316,6 +316,12 @@ [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] internal static partial int RegisterInstance(IntPtr dw, IntPtr jsonData); + [SuppressUnmanagedCodeSecurity] + [SuppressGCTransition] + [LibraryImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_RegisterInstance_Cdr")] + [UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvSuppressGCTransition) })] + internal static partial int RegisterInstance(IntPtr dw, byte[] cdrData, UIntPtr size); + [SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity] [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_RegisterInstanceTimestamp_Json", CallingConvention = CallingConvention.Cdecl)] @@ -367,6 +373,10 @@ [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_RegisterInstance_Json", CallingConvention = CallingConvention.Cdecl)] internal static extern int RegisterInstance(IntPtr dw, [In] IntPtr jsonData); + [SuppressUnmanagedCodeSecurity] + [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_RegisterInstance_Cdr", CallingConvention = CallingConvention.Cdecl)] + internal static extern int RegisterInstance(IntPtr dw, byte[] cdrData, UIntPtr size); + [SuppressUnmanagedCodeSecurity] [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataWriter_RegisterInstanceTimestamp_Json", CallingConvention = CallingConvention.Cdecl)] internal static extern int RegisterInstanceTimestamp(IntPtr dw, [In] IntPtr jsonData, [MarshalAs(UnmanagedType.Struct), In] Timestamp timestamp); @@ -1131,7 +1141,7 @@ ReturnCode ret = ReturnCode.Error; var ptr = IntPtr.Zero; var infoWrapper = new SampleInfoWrapper(); - UIntPtr size = UIntPtr.Zero; + var size = UIntPtr.Zero; ret = (ReturnCode)<%TYPE%>DataReaderNative.TakeNextSample(_native, ref ptr, ref size, ref infoWrapper); if (ret == ReturnCode.Ok) { @@ -1263,10 +1273,12 @@ internal static partial int TakeNextInstanceWithCondition(IntPtr dr, ref IntPtr receivedData, ref IntPtr receivedInfo, int handle, int maxSamples, IntPtr condition); [SuppressUnmanagedCodeSecurity] + [SuppressGCTransition] [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataReader_ReadNextSample_Cdr", CallingConvention = CallingConvention.Cdecl)] internal static extern int ReadNextSample(IntPtr dr, [In, Out] ref IntPtr cdr_data, [In, Out] ref UIntPtr size, [In, Out] ref SampleInfoWrapper sampleInfo); [SuppressUnmanagedCodeSecurity] + [SuppressGCTransition] [DllImport(<%TYPE%>.API_DLL, EntryPoint = "<%SCOPED_METHOD%>DataReader_TakeNextSample_Cdr", CallingConvention = CallingConvention.Cdecl)] internal static extern int TakeNextSample(IntPtr dr, [In, Out] ref IntPtr cdr_data, [In, Out] ref UIntPtr size, [In, Out] ref SampleInfoWrapper sampleInfo); diff --git a/Native/CWrapperHeaderTemplate.txt b/Native/CWrapperHeaderTemplate.txt index 94df1f1b..27e26de8 100644 --- a/Native/CWrapperHeaderTemplate.txt +++ b/Native/CWrapperHeaderTemplate.txt @@ -23,6 +23,8 @@ EXTERN_METHOD_EXPORT int <%SCOPED_METHOD%>DataWriter_WriteWithTimestamp_Json(<%S EXTERN_METHOD_EXPORT int <%SCOPED_METHOD%>DataWriter_RegisterInstance_Json(<%SCOPED%>DataWriter_ptr dw, const char* json_data); +EXTERN_METHOD_EXPORT int <%SCOPED_METHOD%>DataWriter_RegisterInstance_Cdr(<%SCOPED%>DataWriter_ptr dw, const char* cdr_data, size_t size); + EXTERN_METHOD_EXPORT int <%SCOPED_METHOD%>DataWriter_RegisterInstanceTimestamp_Json(<%SCOPED%>DataWriter_ptr dw, const char* json_data, ::DDS::Time_t time); EXTERN_METHOD_EXPORT int <%SCOPED_METHOD%>DataWriter_LookupInstance_Json(<%SCOPED%>DataWriter_ptr dw, const char* json_data); diff --git a/Native/CWrapperImplTemplate.txt b/Native/CWrapperImplTemplate.txt index c991daaa..8955572c 100644 --- a/Native/CWrapperImplTemplate.txt +++ b/Native/CWrapperImplTemplate.txt @@ -71,6 +71,13 @@ int <%SCOPED_METHOD%>DataWriter_RegisterInstance_Json(<%SCOPED%>DataWriter_ptr d return dw->register_instance(sample); } +int <%SCOPED_METHOD%>DataWriter_RegisterInstance_Cdr(<%SCOPED%>DataWriter_ptr dw, const char* cdr_data, size_t size) +{ + <%SCOPED%> sample = <%SCOPED_METHOD%>_deserialize_from_bytes(cdr_data, size); + + return dw->register_instance(sample); +} + int <%SCOPED_METHOD%>DataWriter_RegisterInstanceTimestamp_Json(<%SCOPED%>DataWriter_ptr dw, const char* json_data, ::DDS::Time_t time) { <%SCOPED%>_var samplev = <%SCOPED_METHOD%>_DecodeJsonSample(json_data); diff --git a/Native/OpenDDSWrapper/CMakeLists.txt b/Native/OpenDDSWrapper/CMakeLists.txt index a7b910b9..92728481 100644 --- a/Native/OpenDDSWrapper/CMakeLists.txt +++ b/Native/OpenDDSWrapper/CMakeLists.txt @@ -1,11 +1,12 @@ -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.19.2) project(OpenDDSWrapper CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + if (APPLE) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) elseif (UNIX) set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) @@ -69,15 +70,18 @@ add_library(OpenDDSWrapper SHARED MultiTopic.h MultiTopic.cpp) if (MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) - target_compile_options(OpenDDSWrapper PUBLIC /wd4190) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /wd4190") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /Oi /D NDEBUG /D NOMINMAX /MD") elseif (APPLE) - target_compile_options(OpenDDSWrapper PUBLIC -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare) set_target_properties(OpenDDSWrapper PROPERTIES LINK_FLAGS "-Wl,-rpath,@executable_path -Wl,-rpath,@loader_path") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare -pthread") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") elseif (UNIX) - target_compile_options(OpenDDSWrapper PUBLIC -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare) set_target_properties(OpenDDSWrapper PROPERTIES LINK_FLAGS "-Wl,-rpath,$ORIGIN") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith -Wno-switch -Wno-return-type-c-linkage -Wno-tautological-pointer-compare -pthread") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") endif () target_link_libraries(OpenDDSWrapper OpenDDS::OpenDDS) diff --git a/Native/OpenDDSharp.IdlGenerator.targets b/Native/OpenDDSharp.IdlGenerator.targets index 7ec024ca..1c1e9b2a 100644 --- a/Native/OpenDDSharp.IdlGenerator.targets +++ b/Native/OpenDDSharp.IdlGenerator.targets @@ -176,29 +176,29 @@ - + - + - + - + - + - + @@ -206,7 +206,7 @@ - + diff --git a/Native/OpenDDSharp.IdlGenerator/CMakeLists.txt b/Native/OpenDDSharp.IdlGenerator/CMakeLists.txt index 3622a08a..dc0d93db 100644 --- a/Native/OpenDDSharp.IdlGenerator/CMakeLists.txt +++ b/Native/OpenDDSharp.IdlGenerator/CMakeLists.txt @@ -1,11 +1,10 @@ +cmake_minimum_required(VERSION 3.19.2) + project(openddsharp_idl CXX) -cmake_minimum_required(VERSION 3.8.2) -if (APPLE) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif () +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) find_package(OpenDDS REQUIRED) diff --git a/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.cpp b/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.cpp index ceee2dff..8a9bed74 100644 --- a/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.cpp +++ b/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.cpp @@ -81,8 +81,8 @@ bool csharp_cdr_generator::gen_module_end() { } bool csharp_cdr_generator::gen_const(UTL_ScopedName *name, bool nestedInInteface, AST_Constant *constant) { - std::string csharp_type(""); - std::string str_value(""); + std::string csharp_type; + std::string str_value; switch (constant->et()) { case AST_Expression::EV_short: @@ -269,7 +269,7 @@ csharp_cdr_generator::gen_union(AST_Union *, UTL_ScopedName *name, const std::ve std::string csharp_cdr_generator::declare_struct_fields(const std::vector &fields, const std::string indent) { - std::string ret(""); + std::string ret; for (unsigned int i = 0; i < fields.size(); i++) { AST_Field *field = fields[i]; @@ -321,7 +321,7 @@ csharp_cdr_generator::implement_struct_constructor(const std::vector &fields, const std::string indent) { - std::string ret(""); + std::string ret; for (unsigned int i = 0; i < fields.size(); i++) { AST_Field *field = fields[i]; @@ -387,16 +387,13 @@ csharp_cdr_generator::get_csharp_type(AST_Type *type) { switch (node_type) { case AST_Decl::NT_union: - case AST_Decl::NT_struct: { - ret = replaceString(std::string(type->full_name()), std::string("::"), std::string(".")); - break; - } + case AST_Decl::NT_struct: case AST_Decl::NT_enum: { ret = replaceString(std::string(type->full_name()), std::string("::"), std::string(".")); break; } case AST_Decl::NT_typedef: { - AST_Typedef *typedef_type = dynamic_cast(type); + auto *typedef_type = dynamic_cast(type); ret = get_csharp_type(typedef_type->base_type()); break; } @@ -410,7 +407,7 @@ csharp_cdr_generator::get_csharp_type(AST_Type *type) { break; } case AST_Decl::NT_pre_defined: { - AST_PredefinedType *predefined_type = dynamic_cast(type); + auto *predefined_type = dynamic_cast(type); switch (predefined_type->pt()) { case AST_PredefinedType::PT_int8: @@ -460,7 +457,7 @@ csharp_cdr_generator::get_csharp_type(AST_Type *type) { break; } case AST_Decl::NT_array: { - AST_Array *arr_type = dynamic_cast(type); + auto *arr_type = dynamic_cast(type); std::string base_type = get_csharp_type(arr_type->base_type()); ret = base_type; @@ -472,7 +469,7 @@ csharp_cdr_generator::get_csharp_type(AST_Type *type) { break; } case AST_Decl::NT_sequence: { - AST_Sequence *seq_type = dynamic_cast(type); + auto *seq_type = dynamic_cast(type); std::string base_type = get_csharp_type(seq_type->base_type()); ret = "IList<"; @@ -501,7 +498,7 @@ csharp_cdr_generator::get_csharp_default_value(AST_Type *type, const char *field break; } case AST_Decl::NT_typedef: { - AST_Typedef *typedef_type = dynamic_cast(type); + auto *typedef_type = dynamic_cast(type); ret = get_csharp_default_value(typedef_type->base_type(), field_name); break; } @@ -515,7 +512,7 @@ csharp_cdr_generator::get_csharp_default_value(AST_Type *type, const char *field break; } case AST_Decl::NT_pre_defined: { - AST_PredefinedType *predefined_type = dynamic_cast(type); + auto *predefined_type = dynamic_cast(type); switch (predefined_type->pt()) { case AST_PredefinedType::PT_int8: case AST_PredefinedType::PT_uint8: @@ -542,7 +539,7 @@ csharp_cdr_generator::get_csharp_default_value(AST_Type *type, const char *field break; } case AST_Decl::NT_array: { - AST_Array *arr_type = dynamic_cast(type); + auto *arr_type = dynamic_cast(type); std::string base_type = get_csharp_type(arr_type->base_type()); AST_Expression **dims = arr_type->dims(); AST_Decl::NodeType base_node_type = arr_type->base_type()->node_type(); @@ -592,7 +589,7 @@ csharp_cdr_generator::get_csharp_default_value(AST_Type *type, const char *field break; } case AST_Decl::NT_sequence: { - AST_Sequence *seq_type = dynamic_cast(type); + auto *seq_type = dynamic_cast(type); std::string base_type = get_csharp_type(seq_type->base_type()); ret = "new List<"; @@ -615,16 +612,16 @@ csharp_cdr_generator::get_csharp_default_value(AST_Type *type, const char *field std::string csharp_cdr_generator::get_csharp_constructor_initialization(AST_Type *type, const char *name) { AST_Decl::NodeType node_type = type->node_type(); - std::string ret(""); + std::string ret; switch (node_type) { case AST_Decl::NT_typedef: { - AST_Typedef *typedef_type = dynamic_cast(type); + auto *typedef_type = dynamic_cast(type); ret = get_csharp_constructor_initialization(typedef_type->base_type(), name); break; } case AST_Decl::NT_array: { - AST_Array *arr_type = dynamic_cast(type); + auto *arr_type = dynamic_cast(type); std::string base_type = get_csharp_type(arr_type->base_type()); AST_Expression **dims = arr_type->dims(); AST_Decl::NodeType base_node_type = arr_type->base_type()->node_type(); @@ -635,61 +632,62 @@ csharp_cdr_generator::get_csharp_constructor_initialization(AST_Type *type, cons case AST_Decl::NT_union: case AST_Decl::NT_struct: { std::string loop_indent(" "); - for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { - ret.append(loop_indent); - ret.append("for (int i"); - ret.append(std::to_string(i)); - ret.append(" = 0; i"); - ret.append(std::to_string(i)); - ret.append(" < "); - ret.append(std::to_string(dims[i]->ev()->u.ulval)); - ret.append("; ++i"); - ret.append(std::to_string(i)); - ret.append(") {\n"); - - loop_indent.append(" "); - - if (i + 1 < total_dim) { - ret.append(loop_indent); - ret.append(name); - for (unsigned int j = 0; j < i + 1; ++j) { - - ret.append("[i"); - ret.append(std::to_string(j)); - ret.append("]"); - } - ret.append(" = new "); - ret.append(csharp_base_type); - ret.append("["); - ret.append(std::to_string(dims[i + 1]->ev()->u.ulval)); - ret.append("]"); - for (unsigned int j = i + 2; j < total_dim; ++j) { - ret.append("[]"); - } - ret.append(";\n"); - } - } - - ret.append(loop_indent); - ret.append(name); - ret.append("["); - for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { - ret.append("i"); - ret.append(std::to_string(i)); - if (i + 1 < arr_type->n_dims()) { - ret.append("]["); - } - } - ret.append("] = new "); - ret.append( - replaceString(std::string(arr_type->base_type()->full_name()), std::string("::"), std::string("."))); - ret.append("();\n"); - - for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { - loop_indent.erase(0, 4); - ret.append(loop_indent); - ret.append("}\n"); - } + ret.append(get_csharp_struct_array_constructor_initialization(type, name, loop_indent)); +// for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { +// ret.append(loop_indent); +// ret.append("for (int i"); +// ret.append(std::to_string(i)); +// ret.append(" = 0; i"); +// ret.append(std::to_string(i)); +// ret.append(" < "); +// ret.append(std::to_string(dims[i]->ev()->u.ulval)); +// ret.append("; ++i"); +// ret.append(std::to_string(i)); +// ret.append(") {\n"); +// +// loop_indent.append(" "); +// +// if (i + 1 < total_dim) { +// ret.append(loop_indent); +// ret.append(name); +// for (unsigned int j = 0; j < i + 1; ++j) { +// +// ret.append("[i"); +// ret.append(std::to_string(j)); +// ret.append("]"); +// } +// ret.append(" = new "); +// ret.append(csharp_base_type); +// ret.append("["); +// ret.append(std::to_string(dims[i + 1]->ev()->u.ulval)); +// ret.append("]"); +// for (unsigned int j = i + 2; j < total_dim; ++j) { +// ret.append("[]"); +// } +// ret.append(";\n"); +// } +// } +// +// ret.append(loop_indent); +// ret.append(name); +// ret.append("["); +// for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { +// ret.append("i"); +// ret.append(std::to_string(i)); +// if (i + 1 < arr_type->n_dims()) { +// ret.append("]["); +// } +// } +// ret.append("] = new "); +// ret.append( +// replaceString(std::string(arr_type->base_type()->full_name()), std::string("::"), std::string("."))); +// ret.append("();\n"); +// +// for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { +// loop_indent.erase(0, 4); +// ret.append(loop_indent); +// ret.append("}\n"); +// } break; } case AST_Decl::NT_string: @@ -800,6 +798,79 @@ csharp_cdr_generator::get_csharp_constructor_initialization(AST_Type *type, cons return ret; } +std::string +csharp_cdr_generator::get_csharp_struct_array_constructor_initialization(AST_Type *type, const char *name, std::string loop_indent) +{ + std::string ret; + auto *arr_type = dynamic_cast(type); + std::string base_type = get_csharp_type(arr_type->base_type()); + AST_Expression **dims = arr_type->dims(); + AST_Decl::NodeType base_node_type = arr_type->base_type()->node_type(); + unsigned int total_dim = arr_type->n_dims(); + std::string csharp_base_type = get_csharp_type(arr_type->base_type()); + + for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { + ret.append(loop_indent); + ret.append("for (int i"); + ret.append(std::to_string(i)); + ret.append(" = 0; i"); + ret.append(std::to_string(i)); + ret.append(" < "); + ret.append(std::to_string(dims[i]->ev()->u.ulval)); + ret.append("; ++i"); + ret.append(std::to_string(i)); + ret.append(")\n"); + + ret.append(loop_indent); + ret.append("{\n"); + + loop_indent.append(" "); + + if (i + 1 < total_dim) { + ret.append(loop_indent); + ret.append(name); + for (unsigned int j = 0; j < i + 1; ++j) { + + ret.append("[i"); + ret.append(std::to_string(j)); + ret.append("]"); + } + ret.append(" = new "); + ret.append(csharp_base_type); + ret.append("["); + ret.append(std::to_string(dims[i + 1]->ev()->u.ulval)); + ret.append("]"); + for (unsigned int j = i + 2; j < total_dim; ++j) { + ret.append("[]"); + } + ret.append(";\n"); + } + } + + ret.append(loop_indent); + ret.append(name); + ret.append("["); + for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { + ret.append("i"); + ret.append(std::to_string(i)); + if (i + 1 < arr_type->n_dims()) { + ret.append("]["); + } + } + ret.append("] = new "); + ret.append( + replaceString(std::string(arr_type->base_type()->full_name()), std::string("::"), std::string("."))); + ret.append("();\n"); + + for (ACE_UINT32 i = 0; i < arr_type->n_dims(); i++) { + loop_indent.erase(0, 4); + ret.append(loop_indent); + ret.append("}\n"); + } + + return ret; +} + std::string csharp_cdr_generator::implement_to_cdr(const std::vector &fields, const std::string indent) { @@ -824,6 +895,24 @@ csharp_cdr_generator::implement_to_cdr(const std::vector &fields, c ret.append(indent); ret.append("}\n\n"); + ret.append(indent); + ret.append("public ReadOnlySpan ToCDR(OpenDDSharp.Marshaller.Cdr.CdrWriter writer)\n"); + ret.append(indent); + ret.append("{\n"); + + for (unsigned int i = 0; i < fields.size(); i++) { + AST_Field *field = fields[i]; + AST_Type *field_type = field->field_type(); + const char *field_name = field->local_name()->get_string(); + + ret.append(implement_to_cdr_field(field_type, field_name, indent)); + } + + ret.append(indent); + ret.append(" return writer.GetBuffer();\n"); + ret.append(indent); + ret.append("}\n\n"); + return ret; } @@ -835,10 +924,17 @@ csharp_cdr_generator::implement_to_cdr_field(AST_Type *field_type, std::string f AST_Decl::NodeType node_type = field_type->node_type(); switch (node_type) { case AST_Decl::NT_typedef: { - AST_Typedef *typedef_type = dynamic_cast(field_type); + auto *typedef_type = dynamic_cast(field_type); ret = implement_to_cdr_field(typedef_type->base_type(), field_name, indent); break; } + case AST_Decl::NT_struct: { + ret.append(indent); + ret.append(" writer.WriteBytes("); + ret.append(field_name); + ret.append(".ToCDR());\n"); + break; + } case AST_Decl::NT_string: { ret.append(" writer.WriteString("); ret.append(field_name); @@ -852,7 +948,7 @@ csharp_cdr_generator::implement_to_cdr_field(AST_Type *field_type, std::string f break; } case AST_Decl::NT_pre_defined: { - AST_PredefinedType *predefined_type = dynamic_cast(field_type); + auto *predefined_type = dynamic_cast(field_type); switch (predefined_type->pt()) { case AST_PredefinedType::PT_int8: ret.append(" writer.WriteSByte("); @@ -938,13 +1034,13 @@ csharp_cdr_generator::implement_to_cdr_field(AST_Type *field_type, std::string f break; } case AST_Decl::NT_sequence: { - AST_Sequence *seq_type = dynamic_cast(field_type); + auto *seq_type = dynamic_cast(field_type); AST_Type *base_type = seq_type->base_type(); AST_Decl::NodeType base_node_type = base_type->node_type(); switch (base_node_type) { case AST_Decl::NT_pre_defined: { - AST_PredefinedType *base_predefined_type = dynamic_cast(base_type); + auto *base_predefined_type = dynamic_cast(base_type); switch (base_predefined_type->pt()) { case AST_PredefinedType::PT_int8: ret.append(" writer.WriteSByteSequence("); @@ -1046,13 +1142,58 @@ csharp_cdr_generator::implement_to_cdr_field(AST_Type *field_type, std::string f ret.append(".Select(e => (uint)e)).ToList());\n"); break; } + case AST_Decl::NT_struct: { + ret.append(" if ("); + ret.append(field_name); + ret.append(" != null && "); + ret.append(field_name); + ret.append(".Count > 0)\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" writer.WriteUInt32((uint)"); + ret.append(field_name); + ret.append(".Count);\n"); + + ret.append(indent); + ret.append(" foreach (var s in "); + ret.append(field_name); + ret.append(")\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" s.ToCDR(writer);\n"); + + ret.append(indent); + ret.append(" }\n"); + + ret.append(indent); + ret.append(" }\n"); + + ret.append(indent); + ret.append(" else\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" writer.WriteUInt32(0);\n"); + + ret.append(indent); + ret.append(" }\n"); + break; + } default: break; } break; } case AST_Decl::NT_array: { - AST_Array *arr_type = dynamic_cast(field_type); + auto *arr_type = dynamic_cast(field_type); AST_Type *base_type = arr_type->base_type(); AST_Expression **dims = arr_type->dims(); AST_Decl::NodeType base_node_type = arr_type->base_type()->node_type(); @@ -1288,6 +1429,76 @@ csharp_cdr_generator::implement_to_cdr_field(AST_Type *field_type, std::string f } break; } + case AST_Decl::NT_struct: { + std::string struct_type = replaceString(std::string(base_type->full_name()), std::string("::"), std::string(".")); + ret.append(" if ("); + ret.append(field_name); + ret.append(" == null)\n"); + + ret.append(indent); + ret.append(" {\n"); + + std::string default_value = get_csharp_default_value(field_type, field_name.c_str()); + std::string loop_indent(indent + " "); + std::string initialization = get_csharp_struct_array_constructor_initialization(field_type, field_name.c_str(), loop_indent); + + ret.append(indent + " "); + ret.append(field_name); + ret.append(" = "); + ret.append(default_value); + ret.append(";\n"); + + ret.append(initialization); + + ret.append(indent); + ret.append(" }\n"); + + if (total_dim == 1) { + ret.append(indent); + ret.append(" foreach (var s in "); + ret.append(field_name); + ret.append(")\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" if (s == null)\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" var aux = new "); + ret.append(struct_type); + ret.append("();\n"); + + ret.append(indent); + ret.append(" aux.ToCDR(writer);\n"); + + ret.append(indent); + ret.append(" }\n"); + + ret.append(indent); + ret.append(" else\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" s.ToCDR(writer);\n"); + + ret.append(indent); + ret.append(" }\n"); + + ret.append(indent); + ret.append(" }\n"); + + } else { + ret.append(write_cdr_struct_multi_array(field_name, struct_type, dims, total_dim, indent)); + } + break; + } } break; } @@ -1321,6 +1532,22 @@ csharp_cdr_generator::implement_from_cdr(const std::vector &fields, ret.append(implement_from_cdr_field(field_type, field_name, indent)); } + ret.append(indent); + ret.append("}\n\n"); + + ret.append(indent); + ret.append("public void FromCDR(OpenDDSharp.Marshaller.Cdr.CdrReader reader)\n"); + ret.append(indent); + ret.append("{\n"); + + for (unsigned int i = 0; i < fields.size(); i++) { + AST_Field *field = fields[i]; + AST_Type *field_type = field->field_type(); + const char *field_name = field->local_name()->get_string(); + + ret.append(implement_from_cdr_field(field_type, field_name, indent)); + } + ret.append(indent); ret.append("}\n"); @@ -1335,10 +1562,23 @@ csharp_cdr_generator::implement_from_cdr_field(AST_Type *field_type, std::string AST_Decl::NodeType node_type = field_type->node_type(); switch (node_type) { case AST_Decl::NT_typedef: { - AST_Typedef *typedef_type = dynamic_cast(field_type); + auto *typedef_type = dynamic_cast(field_type); ret = implement_from_cdr_field(typedef_type->base_type(), field_name, indent); break; } + case AST_Decl::NT_struct: { + ret.append(" "); + ret.append(field_name); + ret.append(" = new "); + ret.append(replaceString(std::string(field_type->full_name()), std::string("::"), std::string("."))); + ret.append("();\n"); + + ret.append(indent); + ret.append(" "); + ret.append(field_name); + ret.append(".FromCDR(reader);\n"); + break; + } case AST_Decl::NT_string: { ret.append(" "); ret.append(field_name); @@ -1352,7 +1592,7 @@ csharp_cdr_generator::implement_from_cdr_field(AST_Type *field_type, std::string break; } case AST_Decl::NT_pre_defined: { - AST_PredefinedType *predefined_type = dynamic_cast(field_type); + auto *predefined_type = dynamic_cast(field_type); switch (predefined_type->pt()) { case AST_PredefinedType::PT_int8: ret.append(" "); @@ -1433,13 +1673,13 @@ csharp_cdr_generator::implement_from_cdr_field(AST_Type *field_type, std::string break; } case AST_Decl::NT_sequence: { - AST_Sequence *seq_type = dynamic_cast(field_type); + auto *seq_type = dynamic_cast(field_type); AST_Type *base_type = seq_type->base_type(); AST_Decl::NodeType base_node_type = base_type->node_type(); switch (base_node_type) { case AST_Decl::NT_pre_defined: { - AST_PredefinedType *base_predefined_type = dynamic_cast(base_type); + auto *base_predefined_type = dynamic_cast(base_type); switch (base_predefined_type->pt()) { case AST_PredefinedType::PT_int8: ret.append(" "); @@ -1543,18 +1783,56 @@ csharp_cdr_generator::implement_from_cdr_field(AST_Type *field_type, std::string ret.append(")e)).ToList();\n"); break; } + case AST_Decl::NT_struct: { + ret.append(" "); + ret.append(field_name); + ret.append(" = new List<"); + ret.append(replaceString(std::string(base_type->full_name()), std::string("::"), std::string("."))); + ret.append(">();\n"); + + ret.append(indent); + ret.append(" var count"); + ret.append(field_name); + ret.append(" = reader.ReadUInt32();\n"); + + ret.append(indent); + ret.append(" for (int i = 0; i < count"); + ret.append(field_name); + ret.append("; i++)\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" var aux = new "); + ret.append(replaceString(std::string(base_type->full_name()), std::string("::"), std::string("."))); + ret.append("();\n"); + + ret.append(indent); + ret.append(" aux.FromCDR(reader);\n"); + + ret.append(indent); + ret.append(" "); + ret.append(field_name); + ret.append(".Add(aux);\n"); + + ret.append(indent); + ret.append(" }\n"); + + break; + } } break; } case AST_Decl::NT_array: { - AST_Array *arr_type = dynamic_cast(field_type); + auto *arr_type = dynamic_cast(field_type); AST_Type *base_type = arr_type->base_type(); AST_Expression **dims = arr_type->dims(); AST_Decl::NodeType base_node_type = arr_type->base_type()->node_type(); unsigned int total_dim = arr_type->n_dims(); switch (base_node_type) { case AST_Decl::NT_pre_defined: { - AST_PredefinedType *base_predefined_type = dynamic_cast(base_type); + auto *base_predefined_type = dynamic_cast(base_type); switch (base_predefined_type->pt()) { case AST_PredefinedType::PT_int8: if (total_dim == 1) { @@ -1767,6 +2045,43 @@ csharp_cdr_generator::implement_from_cdr_field(AST_Type *field_type, std::string } break; } + case AST_Decl::NT_struct: { + if (total_dim == 1) { + ret.append(" "); + ret.append(field_name); + ret.append(" = new "); + ret.append(replaceString(std::string(base_type->full_name()), std::string("::"), std::string("."))); + ret.append("["); + ret.append(std::to_string(dims[0]->ev()->u.ulval)); + ret.append("];\n"); + + ret.append(indent); + ret.append(" for (int i = 0; i < "); + ret.append(std::to_string(dims[0]->ev()->u.ulval)); + ret.append("; i++)\n"); + + ret.append(indent); + ret.append(" {\n"); + + ret.append(indent); + ret.append(" "); + ret.append(field_name); + ret.append("[i] = new "); + ret.append(replaceString(std::string(base_type->full_name()), std::string("::"), std::string("."))); + ret.append("();\n"); + + ret.append(indent); + ret.append(" "); + ret.append(field_name); + ret.append("[i].FromCDR(reader);\n"); + + ret.append(indent); + ret.append(" }\n"); + } else { + ret.append(read_cdr_struct_multi_array(field_name, replaceString(std::string(base_type->full_name()), std::string("::"), std::string(".")), dims, total_dim, indent)); + } + break; + } } break; } @@ -1846,9 +2161,13 @@ csharp_cdr_generator::read_cdr_multi_array(std::string name, std::string csharp_ ret.append("]["); } } - ret.append("] = reader."); - ret.append(read_method); - ret.append("();\n"); + if (read_method == "FromCDR") { + ret.append("].FromCDR(reader);\n"); + } else { + ret.append("] = reader."); + ret.append(read_method); + ret.append("();\n"); + } for (ACE_UINT32 i = 0; i < total_dim; i++) { loop_indent.erase(0, 4); @@ -1937,10 +2256,99 @@ csharp_cdr_generator::read_cdr_enum_multi_array(std::string name, std::string cs return ret; } +std::string +csharp_cdr_generator::read_cdr_struct_multi_array(std::string name, std::string csharp_base_type, AST_Expression **dims, int total_dim, std::string indent) +{ + std::string ret(" "); + + ret.append(name); + ret.append(" = new "); + ret.append(csharp_base_type); + ret.append("["); + ret.append(std::to_string(dims[0]->ev()->u.ulval)); + ret.append("]"); + for (unsigned int i = 1; i < total_dim; ++i) { + ret.append("[]"); + } + ret.append(";\n"); + + indent.append(" "); + std::string loop_indent(indent); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append(loop_indent); + ret.append("for (int i"); + ret.append(std::to_string(i)); + ret.append(" = 0; i"); + ret.append(std::to_string(i)); + ret.append(" < "); + ret.append(std::to_string(dims[i]->ev()->u.ulval)); + ret.append("; ++i"); + ret.append(std::to_string(i)); + ret.append(") {\n"); + + loop_indent.append(" "); + + if (i + 1 < total_dim) { + ret.append(loop_indent); + ret.append(name); + for (unsigned int j = 0; j < i + 1; ++j) { + + ret.append("[i"); + ret.append(std::to_string(j)); + ret.append("]"); + } + ret.append(" = new "); + ret.append(csharp_base_type); + ret.append("["); + ret.append(std::to_string(dims[i + 1]->ev()->u.ulval)); + ret.append("]"); + for (unsigned int j = i + 2; j < total_dim; ++j) { + ret.append("[]"); + } + ret.append(";\n"); + } + } + + ret.append(loop_indent); + ret.append(name); + ret.append("["); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append("i"); + ret.append(std::to_string(i)); + if (i + 1 < total_dim) { + ret.append("]["); + } + } + ret.append("] = new "); + ret.append(csharp_base_type); + ret.append("();\n"); + + + ret.append(loop_indent); + ret.append(name); + ret.append("["); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append("i"); + ret.append(std::to_string(i)); + if (i + 1 < total_dim) { + ret.append("]["); + } + } + ret.append("].FromCDR(reader);\n"); + + for (ACE_UINT32 i = 0; i < total_dim; i++) { + loop_indent.erase(0, 4); + ret.append(loop_indent); + ret.append("}\n"); + } + + return ret; +} + std::string csharp_cdr_generator::write_cdr_multi_array(std::string name, std::string csharp_base_type, std::string write_method, AST_Expression **dims, int total_dim, std::string indent) { - std::string ret(""); + std::string ret; indent.append(" "); std::string loop_indent(indent); @@ -1986,7 +2394,7 @@ csharp_cdr_generator::write_cdr_multi_array(std::string name, std::string csharp std::string csharp_cdr_generator::write_cdr_enum_multi_array(std::string name, std::string csharp_base_type, std::string write_method, AST_Expression **dims, int total_dim, std::string indent) { - std::string ret(""); + std::string ret; indent.append(" "); std::string loop_indent(indent); @@ -2026,5 +2434,79 @@ csharp_cdr_generator::write_cdr_enum_multi_array(std::string name, std::string c ret.append("}\n"); } + return ret; +} + +std::string +csharp_cdr_generator::write_cdr_struct_multi_array(std::string name, std::string csharp_base_type, AST_Expression **dims, int total_dim, std::string indent) +{ + std::string ret; + + indent.append(" "); + std::string loop_indent(indent); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append(loop_indent); + ret.append("for (int i"); + ret.append(std::to_string(i)); + ret.append(" = 0; i"); + ret.append(std::to_string(i)); + ret.append(" < "); + ret.append(std::to_string(dims[i]->ev()->u.ulval)); + ret.append("; ++i"); + ret.append(std::to_string(i)); + ret.append(") {\n"); + + loop_indent.append(" "); + } + + ret.append(loop_indent); + ret.append("if ("); + ret.append(name); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append("[i"); + ret.append(std::to_string(i)); + ret.append("]"); + } + ret.append(" == null)\n"); + + ret.append(loop_indent); + ret.append("{\n"); + + loop_indent.append(" "); + + ret.append(loop_indent); + ret.append(name); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append("[i"); + ret.append(std::to_string(i)); + ret.append("]"); + } + ret.append(" = new "); + ret.append(csharp_base_type); + ret.append("();\n"); + + loop_indent.erase(0, 4); + + ret.append(loop_indent); + ret.append("}\n"); + + ret.append(loop_indent); + ret.append(name); + ret.append("["); + for (ACE_UINT32 i = 0; i < total_dim; i++) { + ret.append("i"); + ret.append(std::to_string(i)); + if (i + 1 < total_dim) { + ret.append("]["); + } + } + ret.append("].ToCDR(writer);\n"); + + for (ACE_UINT32 i = 0; i < total_dim; i++) { + loop_indent.erase(0, 4); + ret.append(loop_indent); + ret.append("}\n"); + } + return ret; } \ No newline at end of file diff --git a/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.h b/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.h index b23df2df..4ff9358c 100644 --- a/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.h +++ b/Native/OpenDDSharp.IdlGenerator/csharp_cdr_generator.h @@ -56,6 +56,8 @@ class csharp_cdr_generator : public dds_generator { std::string get_csharp_constructor_initialization(AST_Type *type, const char *name); + std::string get_csharp_struct_array_constructor_initialization(AST_Type *type, const char *name, std::string loop_indent); + std::string implement_to_cdr(const std::vector &fields, const std::string indent); std::string implement_to_cdr_field(AST_Type *field_type, std::string field_name, std::string indent); @@ -68,9 +70,13 @@ class csharp_cdr_generator : public dds_generator { std::string read_cdr_enum_multi_array(std::string name, std::string csharp_base_type, std::string read_method, AST_Expression **dims, int total_dim, std::string indent); + std::string read_cdr_struct_multi_array(std::string name, std::string csharp_base_type, AST_Expression **dims, int total_dim, std::string indent); + std::string write_cdr_multi_array(std::string name, std::string csharp_base_type, std::string write_method, AST_Expression **dims, int total_dim, std::string indent); std::string write_cdr_enum_multi_array(std::string name, std::string csharp_base_type, std::string write_method, AST_Expression **dims, int total_dim, std::string indent); + + std::string write_cdr_struct_multi_array(std::string name, std::string csharp_base_type, AST_Expression **dims, int total_dim, std::string indent); }; #endif diff --git a/Sources/OpenDDSharp.BuildTasks/OpenDDSharp.BuildTasks.csproj b/Sources/OpenDDSharp.BuildTasks/OpenDDSharp.BuildTasks.csproj index b205b5a7..0d67fa19 100644 --- a/Sources/OpenDDSharp.BuildTasks/OpenDDSharp.BuildTasks.csproj +++ b/Sources/OpenDDSharp.BuildTasks/OpenDDSharp.BuildTasks.csproj @@ -10,11 +10,11 @@ - - + + - + all @@ -25,7 +25,7 @@ all - + all diff --git a/Sources/OpenDDSharp.Marshaller/Cdr/CdrReader.cs b/Sources/OpenDDSharp.Marshaller/Cdr/CdrReader.cs index 3f41fef9..8365d37c 100644 --- a/Sources/OpenDDSharp.Marshaller/Cdr/CdrReader.cs +++ b/Sources/OpenDDSharp.Marshaller/Cdr/CdrReader.cs @@ -189,7 +189,7 @@ public string ReadString() } /// - /// Reads an string from the stream. + /// Reads a string from the stream. /// /// The string value. public string ReadWString() diff --git a/Sources/OpenDDSharp.Marshaller/Cdr/CdrWriter.cs b/Sources/OpenDDSharp.Marshaller/Cdr/CdrWriter.cs index ed735be3..5a45f96f 100644 --- a/Sources/OpenDDSharp.Marshaller/Cdr/CdrWriter.cs +++ b/Sources/OpenDDSharp.Marshaller/Cdr/CdrWriter.cs @@ -60,7 +60,7 @@ public ReadOnlySpan GetBuffer() public void WriteSByte(sbyte b) => _writer.Write(b); /// - /// Writes a array of unsigned bytes to the stream. + /// Writes an array of unsigned bytes to the stream. /// /// The unsigned bytes to be written. public void WriteBytes(ReadOnlySpan buf) diff --git a/Sources/OpenDDSharp.Marshaller/OpenDDSharp.Marshaller.csproj b/Sources/OpenDDSharp.Marshaller/OpenDDSharp.Marshaller.csproj index 1c24db94..06fa5fcd 100644 --- a/Sources/OpenDDSharp.Marshaller/OpenDDSharp.Marshaller.csproj +++ b/Sources/OpenDDSharp.Marshaller/OpenDDSharp.Marshaller.csproj @@ -40,7 +40,7 @@ - + all @@ -51,7 +51,7 @@ all - + all @@ -83,7 +83,7 @@ - <_Parameter1>true + <_Parameter1>false <_Parameter1_TypeName>System.Boolean diff --git a/Sources/OpenDDSharp/DDS/Duration.cs b/Sources/OpenDDSharp/DDS/Duration.cs index a77eaf7f..aa68e3a0 100644 --- a/Sources/OpenDDSharp/DDS/Duration.cs +++ b/Sources/OpenDDSharp/DDS/Duration.cs @@ -75,6 +75,31 @@ public uint NanoSeconds } #endregion + #region Methods + /// + /// Converts the time value to a CDR representation. + /// + /// The byte span serialized. + internal ReadOnlySpan ToCDR() + { + var writer = new Marshaller.Cdr.CdrWriter(); + writer.WriteInt32(Seconds); + writer.WriteUInt32(NanoSeconds); + return writer.GetBuffer(); + } + + /// + /// Updates the time value from a CDR representation. + /// + /// The byte span serialized. + internal void FromCDR(ReadOnlySpan data) + { + var reader = new Marshaller.Cdr.CdrReader(data.ToArray()); + Seconds = reader.ReadInt32(); + NanoSeconds = reader.ReadUInt32(); + } + #endregion + #region IEquatable Members /// /// Indicates whether the current object is equal to another object of the same type. diff --git a/Sources/OpenDDSharp/DDS/SampleInfo.cs b/Sources/OpenDDSharp/DDS/SampleInfo.cs index 9a6ca293..d39cc013 100644 --- a/Sources/OpenDDSharp/DDS/SampleInfo.cs +++ b/Sources/OpenDDSharp/DDS/SampleInfo.cs @@ -146,6 +146,54 @@ public void FromNative(SampleInfoWrapper wrapper) ValidData = wrapper.ValidData; ViewState = wrapper.ViewState; } + + /// + /// Converts the time value to a CDR representation. + /// + /// The byte span serialized. + internal ReadOnlySpan ToCDR() + { + var writer = new Marshaller.Cdr.CdrWriter(); + writer.WriteBool(ValidData); + writer.WriteUInt32(SampleState); + writer.WriteUInt32(ViewState); + writer.WriteUInt32(InstanceState); + writer.WriteInt32(SourceTimestamp.Seconds); + writer.WriteUInt32(SourceTimestamp.NanoSeconds); + writer.WriteInt32(InstanceHandle); + writer.WriteInt32(PublicationHandle); + writer.WriteInt32(DisposedGenerationCount); + writer.WriteInt32(NoWritersGenerationCount); + writer.WriteInt32(SampleRank); + writer.WriteInt32(GenerationRank); + writer.WriteInt32(AbsoluteGenerationRank); + return writer.GetBuffer(); + } + + /// + /// Updates the time value from a CDR representation. + /// + /// The byte span serialized. + internal void FromCDR(ReadOnlySpan data) + { + var reader = new Marshaller.Cdr.CdrReader(data.ToArray()); + ValidData = reader.ReadBool(); + SampleState = reader.ReadUInt32(); + ViewState = reader.ReadUInt32(); + InstanceState = reader.ReadUInt32(); + SourceTimestamp = new Timestamp + { + Seconds = reader.ReadInt32(), + NanoSeconds = reader.ReadUInt32(), + }; + InstanceHandle = reader.ReadInt32(); + PublicationHandle = reader.ReadInt32(); + DisposedGenerationCount = reader.ReadInt32(); + NoWritersGenerationCount = reader.ReadInt32(); + SampleRank = reader.ReadInt32(); + GenerationRank = reader.ReadInt32(); + AbsoluteGenerationRank = reader.ReadInt32(); + } #endregion #region IEquatable Members diff --git a/Sources/OpenDDSharp/OpenDDSharp.csproj b/Sources/OpenDDSharp/OpenDDSharp.csproj index 12d25946..eaa7c7b8 100644 --- a/Sources/OpenDDSharp/OpenDDSharp.csproj +++ b/Sources/OpenDDSharp/OpenDDSharp.csproj @@ -42,7 +42,7 @@ - + all @@ -53,17 +53,18 @@ all - + all - + all + diff --git a/Sources/OpenDDSharp/TimeValue.cs b/Sources/OpenDDSharp/TimeValue.cs index b7f98f78..3728aadf 100644 --- a/Sources/OpenDDSharp/TimeValue.cs +++ b/Sources/OpenDDSharp/TimeValue.cs @@ -53,6 +53,31 @@ public int MicroSeconds } #endregion + #region Methods + /// + /// Converts the time value to a CDR representation. + /// + /// The byte span serialized. + internal ReadOnlySpan ToCDR() + { + var writer = new Marshaller.Cdr.CdrWriter(); + writer.WriteInt64(Seconds); + writer.WriteInt32(MicroSeconds); + return writer.GetBuffer(); + } + + /// + /// Updates the time value from a CDR representation. + /// + /// The byte span serialized. + internal void FromCDR(ReadOnlySpan data) + { + var reader = new Marshaller.Cdr.CdrReader(data.ToArray()); + Seconds = reader.ReadInt64(); + MicroSeconds = reader.ReadInt32(); + } + #endregion + #region IEquatable Members /// /// Indicates whether the current object is equal to another object of the same type. diff --git a/Sources/OpenDDSharp/Timestamp.cs b/Sources/OpenDDSharp/Timestamp.cs index e63c087d..97e3220f 100644 --- a/Sources/OpenDDSharp/Timestamp.cs +++ b/Sources/OpenDDSharp/Timestamp.cs @@ -53,6 +53,31 @@ public uint NanoSeconds } #endregion + #region Methods + /// + /// Converts the time value to a CDR representation. + /// + /// The byte span serialized. + internal ReadOnlySpan ToCDR() + { + var writer = new Marshaller.Cdr.CdrWriter(); + writer.WriteInt32(Seconds); + writer.WriteUInt32(NanoSeconds); + return writer.GetBuffer(); + } + + /// + /// Updates the time value from a CDR representation. + /// + /// The byte span serialized. + internal void FromCDR(ReadOnlySpan data) + { + var reader = new Marshaller.Cdr.CdrReader(data.ToArray()); + Seconds = reader.ReadInt32(); + NanoSeconds = reader.ReadUInt32(); + } + #endregion + #region IEquatable Members /// /// Indicates whether the current object is equal to another object of the same type. diff --git a/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj b/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj index f9c4590d..07450711 100644 --- a/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj +++ b/Tests/BenchmarkPerformance/BenchmarkPerformance.csproj @@ -11,7 +11,7 @@ - + diff --git a/Tests/BenchmarkPerformance/Configurations/LatencyTestConfiguration.cs b/Tests/BenchmarkPerformance/Configurations/LatencyTestConfiguration.cs index c08fb9bb..a824bab0 100644 --- a/Tests/BenchmarkPerformance/Configurations/LatencyTestConfiguration.cs +++ b/Tests/BenchmarkPerformance/Configurations/LatencyTestConfiguration.cs @@ -1,5 +1,4 @@ -using System.Linq; -using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Configs; using BenchmarkDotNet.Exporters; using BenchmarkDotNet.Exporters.Csv; using BenchmarkDotNet.Jobs; @@ -12,7 +11,13 @@ internal class LatencyTestConfiguration : ManualConfig { public LatencyTestConfiguration() { - AddJob(Job.Dry.WithIterationCount(1).WithToolchain(InProcessEmitToolchain.Instance)); + AddJob(Job.Default + .WithIterationCount(10) + .WithUnrollFactor(1) + .WithInvocationCount(1) + .WithToolchain(InProcessEmitToolchain.Instance)); + + WithOption(ConfigOptions.DisableOptimizationsValidator, true); AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray()); AddColumn(new LatencyAverageColumn()); AddColumn(new LatencyDeviationColumn()); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyAverageColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyAverageColumn.cs index 3a316654..e19c46fe 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyAverageColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyAverageColumn.cs @@ -36,7 +36,7 @@ internal class LatencyAverageColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyDeviationColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyDeviationColumn.cs index 2a77f2de..02a53be3 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyDeviationColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyDeviationColumn.cs @@ -36,7 +36,7 @@ internal class LatencyDeviationColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyFiftyColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyFiftyColumn.cs index 1d9ee83a..571cdb53 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyFiftyColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyFiftyColumn.cs @@ -36,7 +36,7 @@ internal class LatencyFiftyColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyMaximumColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyMaximumColumn.cs index d3320d47..b7b5f3c2 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyMaximumColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyMaximumColumn.cs @@ -36,7 +36,7 @@ internal class LatencyMaximumColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyMinimumColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyMinimumColumn.cs index 6919f23e..97817c08 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyMinimumColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyMinimumColumn.cs @@ -36,7 +36,7 @@ internal class LatencyMinimumColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyColumn.cs index 90f3fd43..e4861a00 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyColumn.cs @@ -36,7 +36,7 @@ internal class LatencyNinetyColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyNineColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyNineColumn.cs index ff100099..1dab87ee 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyNineColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/LatencyNinetyNineColumn.cs @@ -36,7 +36,7 @@ internal class LatencyNinetyNineColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("LatencyTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/ThroughputMissingSamplesPercentageColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/ThroughputMissingSamplesPercentageColumn.cs index 721c7fdd..6995d4c2 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/ThroughputMissingSamplesPercentageColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/ThroughputMissingSamplesPercentageColumn.cs @@ -36,7 +36,7 @@ internal class ThroughputMissingSamplesPercentageColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("ThroughputTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/CustomColumns/ThroughputSamplesReceivedColumn.cs b/Tests/BenchmarkPerformance/CustomColumns/ThroughputSamplesReceivedColumn.cs index 57c118f6..0952a875 100644 --- a/Tests/BenchmarkPerformance/CustomColumns/ThroughputSamplesReceivedColumn.cs +++ b/Tests/BenchmarkPerformance/CustomColumns/ThroughputSamplesReceivedColumn.cs @@ -38,7 +38,7 @@ internal class ThroughputSamplesReceivedColumn : IColumn public string GetValue(Summary summary, BenchmarkCase benchmarkCase) { var name = benchmarkCase.Descriptor.WorkloadMethod.Name. - Replace("TestLatency", string.Empty, StringComparison.InvariantCultureIgnoreCase). + Replace("ThroughputTest", string.Empty, StringComparison.InvariantCultureIgnoreCase). ToLowerInvariant(); var numInstancesParam = benchmarkCase.Parameters.Items.FirstOrDefault(x => x.Name == "TotalInstances"); diff --git a/Tests/BenchmarkPerformance/PerformanceTests/LatencyTest.cs b/Tests/BenchmarkPerformance/PerformanceTests/LatencyTest.cs index 6d00d9ed..6c082094 100644 --- a/Tests/BenchmarkPerformance/PerformanceTests/LatencyTest.cs +++ b/Tests/BenchmarkPerformance/PerformanceTests/LatencyTest.cs @@ -1,11 +1,18 @@ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using BenchmarkDotNet.Attributes; using OpenDDSharp.BenchmarkPerformance.CustomColumns; +using OpenDDSharp.OpenDDS.DCPS; +using OpenDDSharp.OpenDDS.RTPS; namespace OpenDDSharp.BenchmarkPerformance.PerformanceTests; +[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global", Justification = "Required by BenchmarkDotNet.")] public class LatencyTest { + private const int DOMAIN_ID = 42; + private const string RTPS_DISCOVERY = "RtpsDiscovery"; + private OpenDDSharpLatencyTest _openDDSharpLatencyTest; private RtiConnextLatencyTest _rtiConnextLatencyTest; private IList _latencyHistory; @@ -25,9 +32,39 @@ public class LatencyTest /// /// Gets or sets the payload size for the test. /// - [Params(512)] + [Params(512, 1024, 2048)] public ulong TotalPayload { get; set; } + [GlobalSetup(Target = nameof(OpenDDSharpLatencyTest))] + public void OpenDDSharpGlobalSetup() + { + Ace.Init(); + + var disc = new RtpsDiscovery(RTPS_DISCOVERY) + { + SedpMulticast = false, + SedpLocalAddress = "127.0.0.1:0", + SpdpLocalAddress = "127.0.0.1:0", + ResendPeriod = new TimeValue + { + Seconds = 1, + MicroSeconds = 0, + }, + }; + + ParticipantService.Instance.AddDiscovery(disc); + ParticipantService.Instance.DefaultDiscovery = RTPS_DISCOVERY; + ParticipantService.Instance.SetRepoDomain(DOMAIN_ID, RTPS_DISCOVERY); + } + + [GlobalCleanup(Target = nameof(OpenDDSharpLatencyTest))] + public void OpenDDSharpGlobalCleanup() + { + ParticipantService.Instance.Shutdown(); + + Ace.Fini(); + } + [IterationSetup(Target = nameof(OpenDDSharpLatencyTest))] public void OpenDDSharpIterationSetup() { @@ -66,7 +103,8 @@ public void OpenDDSharpLatencyTest() _latencyHistory = _openDDSharpLatencyTest.Run(); } - [Benchmark] + // Cannot run without a valid RTI Connext license. + // [Benchmark] public void RtiConnextLatencyTest() { _latencyHistory= _rtiConnextLatencyTest.Run(); @@ -127,4 +165,4 @@ private void LatencyStatistics(string name) File.WriteAllText(Path.Combine(LatencyNinetyNineColumn.OutputFolder, ninetyNineFile), _latencyHistory[count * 99 / 100].TotalMilliseconds.ToString("0.0000", CultureInfo.InvariantCulture)); } -} \ No newline at end of file +} diff --git a/Tests/BenchmarkPerformance/PerformanceTests/OpenDDSharpLatencyTest.cs b/Tests/BenchmarkPerformance/PerformanceTests/OpenDDSharpLatencyTest.cs index 11d94c2b..1de03081 100644 --- a/Tests/BenchmarkPerformance/PerformanceTests/OpenDDSharpLatencyTest.cs +++ b/Tests/BenchmarkPerformance/PerformanceTests/OpenDDSharpLatencyTest.cs @@ -13,7 +13,8 @@ internal sealed class OpenDDSharpLatencyTest : IDisposable private readonly Random _random = new (); private readonly int _totalInstances; private readonly int _totalSamples; - private readonly byte[] _payload; + private readonly Dictionary _instanceHandles = new(); + private readonly KeyedOctets _sample; private int _count; @@ -34,32 +35,39 @@ public OpenDDSharpLatencyTest(int totalInstances, int totalSamples, ulong totalP _totalSamples = totalSamples; _evt = new ManualResetEventSlim(false); - _payload = new byte[totalPayload]; - _random.NextBytes(_payload); + var payload = new byte[totalPayload]; + _random.NextBytes(payload); InitializeDDSEntities(); - } - public IList Run() - { _count = 0; - var latencyHistory = new List(); - _readerThread.Start(); - var sample = new KeyedOctets + _sample = new KeyedOctets { - ValueField = _payload, + ValueField = payload, }; + } + + public IList Run() + { + var latencyHistory = new List(); for (var i = 1; i <= _totalSamples; i++) { for (var j = 1; j <= _totalInstances; j++) { - sample.KeyField = j.ToString(CultureInfo.InvariantCulture); + _sample.KeyField = j.ToString(CultureInfo.InvariantCulture); - var publicationTime = DateTime.Now.Ticks; - _dataWriter.Write(sample); + if (!_instanceHandles.TryGetValue(j, out var instanceHandle)) + { + instanceHandle = _dataWriter.RegisterInstance(_sample); + _instanceHandles.Add(j, instanceHandle); + } + + var publicationTime = DateTime.UtcNow.Ticks; + + _dataWriter.Write(_sample, instanceHandle); _evt.Wait(); @@ -68,7 +76,7 @@ public IList Run() latencyHistory.Add(latency); _evt.Reset(); - }; + } } _readerThread.Join(); @@ -86,22 +94,12 @@ private void InitializeDDSEntities() var config = TransportRegistry.Instance.CreateConfig(configName); var inst = TransportRegistry.Instance.CreateInst(instName, "rtps_udp"); - var rui = new RtpsUdpInst(inst) + var transport = new RtpsUdpInst(inst) { UseMulticast = false, - LocalAddress = "127.0.0.1", - NakResponseDelay = new TimeValue - { - Seconds = 0, - MicroSeconds = 50_000, - }, - HeartbeatPeriod = new TimeValue - { - Seconds = 0, - MicroSeconds = 50_000, - }, + LocalAddress = "127.0.0.1:0", }; - config.Insert(rui); + config.Insert(transport); _participant = _dpf.CreateParticipant(DOMAIN_ID); TransportRegistry.Instance.BindConfig(configName, _participant); @@ -112,7 +110,11 @@ private void InitializeDDSEntities() _topic = _participant.CreateTopic("LatencyTest", typeName); - _publisher = _participant.CreatePublisher(); + var pubQos = new PublisherQos + { + EntityFactory = { AutoenableCreatedEntities = false } + }; + _publisher = _participant.CreatePublisher(pubQos); var dwQos = new DataWriterQos { @@ -124,10 +126,14 @@ private void InitializeDDSEntities() }, }; var dw = _publisher.CreateDataWriter(_topic, dwQos); - TransportRegistry.Instance.BindConfig(configName, dw); _dataWriter = new KeyedOctetsDataWriter(dw); - _subscriber = _participant.CreateSubscriber(); + var subQos = new SubscriberQos + { + EntityFactory = { AutoenableCreatedEntities = false } + }; + _subscriber = _participant.CreateSubscriber(subQos); + var drQos = new DataReaderQos { Reliability = { Kind = ReliabilityQosPolicyKind.ReliableReliabilityQos }, @@ -138,9 +144,11 @@ private void InitializeDDSEntities() }, }; var dr = _subscriber.CreateDataReader(_topic, drQos); - TransportRegistry.Instance.BindConfig(configName, dr); _dataReader = new KeyedOctetsDataReader(dr); + _dataWriter.Enable(); + _dataReader.Enable(); + _waitSet = new WaitSet(); _statusCondition = _dataReader.StatusCondition; _statusCondition.EnabledStatuses = StatusKind.DataAvailableStatus; @@ -149,20 +157,18 @@ private void InitializeDDSEntities() _readerThread = new Thread(ReaderThreadProc) { IsBackground = true, + Priority = ThreadPriority.Highest, }; + + Thread.Sleep(2_000); } private void ReaderThreadProc() { - var duration = new Duration - { - Seconds = 1, - NanoSeconds = 0, - }; while (true) { var conditions = new List(); - _waitSet.Wait(conditions, duration); + _waitSet.Wait(conditions); var sample = new KeyedOctets(); var sampleInfo = new SampleInfo(); @@ -186,6 +192,7 @@ public void Dispose() _publisher.DeleteContainedEntities(); _participant.DeletePublisher(_publisher); + _waitSet.DetachCondition(_statusCondition); _dataReader.DeleteContainedEntities(); _subscriber.DeleteDataReader(_dataReader); _subscriber.DeleteContainedEntities(); diff --git a/Tests/BenchmarkPerformance/PerformanceTests/RtiConnextLatencyTest.cs b/Tests/BenchmarkPerformance/PerformanceTests/RtiConnextLatencyTest.cs index 443ecfb3..cdf38c18 100644 --- a/Tests/BenchmarkPerformance/PerformanceTests/RtiConnextLatencyTest.cs +++ b/Tests/BenchmarkPerformance/PerformanceTests/RtiConnextLatencyTest.cs @@ -18,7 +18,8 @@ internal sealed class RtiConnextLatencyTest : IDisposable private readonly Random _random = new (); private readonly int _totalInstances; private readonly int _totalSamples; - private readonly byte[] _payload; + private readonly Dictionary _instanceHandles = new(); + private readonly KeyedOctetsTopicType _sample; private int _count; @@ -38,29 +39,37 @@ public RtiConnextLatencyTest(int totalInstances, int totalSamples, ulong totalPa _evt = new ManualResetEventSlim(false); - _payload = new byte[totalPayload]; - _random.NextBytes(_payload); + var payload = new byte[totalPayload]; + _random.NextBytes(payload); InitializeDDSEntities(); + + _count = 0; + + _readerThread.Start(); + + _sample = new KeyedOctetsTopicType(); + _sample.Value.AddRange(payload); } public IList Run() { var latencyHistory = new List(); - _readerThread.Start(); - - var sample = new KeyedOctetsTopicType(); - sample.Value.AddRange(_payload); - for (var i = 1; i <= _totalSamples; i++) { for (var j = 1; j <= _totalInstances; j++) { - sample.Key = j.ToString(CultureInfo.InvariantCulture); + _sample.Key = j.ToString(CultureInfo.InvariantCulture); + + if (!_instanceHandles.TryGetValue(j, out var instanceHandle)) + { + instanceHandle = _dataWriter.RegisterInstance(_sample); + _instanceHandles.Add(j, instanceHandle); + } - var publicationTime = DateTime.Now.Ticks; - _dataWriter.Write(sample); + var publicationTime = DateTime.UtcNow.Ticks; + _dataWriter.Write(_sample); _evt.Wait(); @@ -94,6 +103,8 @@ public void Dispose() _participant.DisposeContainedEntities(); _participant.Dispose(); + + DomainParticipantFactory.Instance.Dispose(); } private void InitializeDDSEntities() @@ -107,7 +118,7 @@ private void InitializeDDSEntities() .WithTransportBuiltin(t => t.Mask = TransportBuiltinMask.Udpv4); _participant = DomainParticipantFactory.Instance.CreateParticipant(DOMAIN_ID, pQos); - _topic = _participant.CreateTopic("KeyedOctetsTopic"); + _topic = _participant.CreateTopic("LatencyTestRtiConnext"); _publisher = _participant.CreatePublisher(); _subscriber = _participant.CreateSubscriber(); @@ -133,6 +144,8 @@ private void InitializeDDSEntities() { IsBackground = true, }; + + Thread.Sleep(2_000); } private void ReaderThread() diff --git a/Tests/BenchmarkPerformance/Program.cs b/Tests/BenchmarkPerformance/Program.cs index 857c7284..eb32e0cb 100644 --- a/Tests/BenchmarkPerformance/Program.cs +++ b/Tests/BenchmarkPerformance/Program.cs @@ -1,58 +1,85 @@ -using BenchmarkDotNet.Running; -using CdrWrapper; +using System.Diagnostics; +using BenchmarkDotNet.Running; using OpenDDSharp; using OpenDDSharp.BenchmarkPerformance.Configurations; using OpenDDSharp.BenchmarkPerformance.PerformanceTests; using OpenDDSharp.OpenDDS.DCPS; using OpenDDSharp.OpenDDS.RTPS; -const int DOMAIN_ID = 42; const string RTPS_DISCOVERY = "RtpsDiscovery"; +const int DOMAIN_ID = 42; var artifactsPath = Path.Combine(Environment.CurrentDirectory, "PerformanceTestArtifacts"); -Ace.Init(); - -var disc = new RtpsDiscovery(RTPS_DISCOVERY) +string input; +if (args.Length == 0) +{ + Console.WriteLine("Menu: "); + Console.WriteLine("[1] Latency Performance Test"); + Console.WriteLine("[2] Throughput Performance Test"); + Console.WriteLine("Anything else will stop the program."); + Console.Write("> "); + input = Console.ReadLine(); + Console.WriteLine(); +} +else { - SedpMulticast = false, - SedpLocalAddress = "127.0.0.1", - SpdpLocalAddress = "127.0.0.1", - ResendPeriod = new TimeValue - { - Seconds = 0, - MicroSeconds = 50_000, - }, -}; - -ParticipantService.Instance.AddDiscovery(disc); -ParticipantService.Instance.DefaultDiscovery = RTPS_DISCOVERY; -ParticipantService.Instance.SetRepoDomain(DOMAIN_ID, RTPS_DISCOVERY); - -//var test = new OpenDDSharpLatencyTest(1000, 100, 512); -//test.Run(); -//test.Dispose(); - -Console.WriteLine("Menu: "); -Console.WriteLine("[1] Latency Performance Test"); -Console.WriteLine("[2] Throughput Performance Test"); -Console.WriteLine("Anything else will stop the program."); -Console.Write("> "); -var input = Console.ReadLine(); -Console.WriteLine(); + input = args[0]; +} + switch (input) { - case "1": - { - var config = new LatencyTestConfiguration + case "-1": + Ace.Init(); + + var disc = new RtpsDiscovery(RTPS_DISCOVERY) { - ArtifactsPath = artifactsPath, + SedpMulticast = false, + SedpLocalAddress = "127.0.0.1:0", + SpdpLocalAddress = "127.0.0.1:0", + ResendPeriod = new TimeValue + { + Seconds = 1, + MicroSeconds = 0, + }, }; - _ = BenchmarkRunner.Run(config); + + ParticipantService.Instance.AddDiscovery(disc); + ParticipantService.Instance.DefaultDiscovery = RTPS_DISCOVERY; + ParticipantService.Instance.SetRepoDomain(DOMAIN_ID, RTPS_DISCOVERY); + + var test = new OpenDDSharpLatencyTest(1000, 100, 2048); + Stopwatch stopwatch = new(); + stopwatch.Start(); + test.Run(); + stopwatch.Stop(); + test.Dispose(); + + Console.WriteLine($"OpenDDSharp Latency Test {stopwatch.Elapsed.TotalSeconds}"); + + ParticipantService.Instance.Shutdown(); + + Ace.Fini(); + + // // Requires RTI Connext DDS valid license. + // var test1 = new RtiConnextLatencyTest(1000, 100, 2048); + // stopwatch.Reset(); + // stopwatch.Start(); + // test1.Run(); + // stopwatch.Stop(); + // test1.Dispose(); + // + // Console.WriteLine($"RTI Connext Latency Test {stopwatch.Elapsed.TotalSeconds}"); break; - } + case "1": + { + var config = new LatencyTestConfiguration + { + ArtifactsPath = artifactsPath, + }; + _ = BenchmarkRunner.Run(config); + break; + } } -Ace.Fini(); - Console.WriteLine("Press any button to exit the application."); \ No newline at end of file diff --git a/Tests/OpenDDSharp.UnitTest/AssemblyInitializer.cs b/Tests/OpenDDSharp.UnitTest/AssemblyInitializer.cs index ea78a60e..07eb1314 100644 --- a/Tests/OpenDDSharp.UnitTest/AssemblyInitializer.cs +++ b/Tests/OpenDDSharp.UnitTest/AssemblyInitializer.cs @@ -28,7 +28,7 @@ You should have received a copy of the GNU Lesser General Public License namespace OpenDDSharp.UnitTest { /// - /// The assemble initializer class. + /// The assembly initializer class. /// [TestClass] public static class AssemblyInitializer diff --git a/Tests/OpenDDSharp.UnitTest/CodeGeneratorCdrWrapperTest.cs b/Tests/OpenDDSharp.UnitTest/CodeGeneratorCdrWrapperTest.cs index 81192795..55477cda 100644 --- a/Tests/OpenDDSharp.UnitTest/CodeGeneratorCdrWrapperTest.cs +++ b/Tests/OpenDDSharp.UnitTest/CodeGeneratorCdrWrapperTest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -438,12 +439,16 @@ public void TestGeneratedPrimitivesArrayTypes() var defaultStruct = new TestPrimitiveArray(); + var random = new Random(); + var payload = new byte[2048]; + random.NextBytes(payload); + var data = new TestPrimitiveArray { BooleanArrayField = new[] { true, true, false, false, true }, CharArrayField = new[] { 'a', 'b', 'c', 'd', 'e' }, WCharArrayField = new[] { 'あ', 'な', 'た', 'の', '基' }, - ByteArrayField = new byte[] { 0x04, 0x05, 0x06, 0x07, 0x08 }, + ByteArrayField = payload, Int16ArrayField = new short[] { 4, -5, 6, -7, 8 }, UInt16ArrayField = new ushort[] { 4, 5, 6, 7, 8 }, Int32ArrayField = new[] { -1, 2, -3, 100, -200 }, @@ -520,7 +525,7 @@ public void TestGeneratedPrimitivesArrayTypes() } Assert.IsNotNull(defaultStruct.ByteArrayField); - Assert.AreEqual(5, defaultStruct.ByteArrayField.Length); + Assert.AreEqual(2048, defaultStruct.ByteArrayField.Length); foreach (var i in defaultStruct.ByteArrayField) { Assert.AreEqual(default, i); @@ -1830,6 +1835,415 @@ public void TestGeneratedEnumsMultiArrayTypes() Assert.IsTrue(TestHelper.CompareMultiArray(defaultStruct.EnumMultiArrayField, defaultArray)); } + /// + /// Test the code generated for the structures types. + /// + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void TestGeneratedStructuresTypes() + { + using var evt = new ManualResetEventSlim(false); + + var typeSupport = new TestStructTypeSupport(); + var typeName = typeSupport.GetTypeName(); + var ret = typeSupport.RegisterType(_participant, typeName); + Assert.AreEqual(ReturnCode.Ok, ret); + + _topic = _participant.CreateTopic(TestContext.TestName, typeName); + Assert.IsNotNull(_topic); + + var drQos = new DataReaderQos + { + Reliability = + { + Kind = ReliabilityQosPolicyKind.ReliableReliabilityQos, + }, + }; + var dr = _subscriber.CreateDataReader(_topic, drQos); + Assert.IsNotNull(dr); + var dataReader = new TestStructDataReader(dr); + + var dw = _publisher.CreateDataWriter(_topic); + Assert.IsNotNull(dw); + var dataWriter = new TestStructDataWriter(dw); + + Assert.IsTrue(dataWriter.WaitForSubscriptions(1, 5000)); + Assert.IsTrue(dataReader.WaitForPublications(1, 5000)); + + var statusCondition = dr.StatusCondition; + Assert.IsNotNull(statusCondition); + statusCondition.EnabledStatuses = StatusKind.DataAvailableStatus; + TestHelper.CreateWaitSetThread(evt, statusCondition); + + var defaultStruct = new TestStruct(); + + var data = new TestStruct + { + NestedStructField = new NestedStruct { Id = 1, Message = "Do androids dream of electric sheep?" }, + }; + + ret = dataWriter.Write(data); + Assert.AreEqual(ReturnCode.Ok, ret); + + ret = dataWriter.WaitForAcknowledgments(new Duration { Seconds = 5 }); + Assert.AreEqual(ReturnCode.Ok, ret); + + Assert.IsTrue(evt.Wait(1_500)); + + var received = new TestStruct(); + var sampleInfo = new SampleInfo(); + ret = dataReader.ReadNextSample(received, sampleInfo); + + Assert.AreEqual(ReturnCode.Ok, ret); + Assert.IsNotNull(received.NestedStructField); + Assert.AreEqual(data.NestedStructField.Id, received.NestedStructField.Id); + Assert.AreEqual(data.NestedStructField.Message, received.NestedStructField.Message); + + Assert.AreEqual(typeof(NestedStruct), data.NestedStructField.GetType()); + + Assert.IsNotNull(defaultStruct.NestedStructField); + Assert.AreEqual(0, defaultStruct.NestedStructField.Id); + Assert.AreEqual(string.Empty, defaultStruct.NestedStructField.Message); + } + + /// + /// Test the code generated for the sequence of structures. + /// + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void TestGeneratedStructureSequences() + { + using var evt = new ManualResetEventSlim(false); + + var typeSupport = new TestStructSequenceTypeSupport(); + var typeName = typeSupport.GetTypeName(); + var ret = typeSupport.RegisterType(_participant, typeName); + Assert.AreEqual(ReturnCode.Ok, ret); + + _topic = _participant.CreateTopic(TestContext.TestName, typeName); + Assert.IsNotNull(_topic); + + var drQos = new DataReaderQos + { + Reliability = + { + Kind = ReliabilityQosPolicyKind.ReliableReliabilityQos, + }, + }; + var dr = _subscriber.CreateDataReader(_topic, drQos); + Assert.IsNotNull(dr); + var dataReader = new TestStructSequenceDataReader(dr); + + var dw = _publisher.CreateDataWriter(_topic); + Assert.IsNotNull(dw); + var dataWriter = new TestStructSequenceDataWriter(dw); + + Assert.IsTrue(dataWriter.WaitForSubscriptions(1, 5000)); + Assert.IsTrue(dataReader.WaitForPublications(1, 5000)); + + var statusCondition = dr.StatusCondition; + Assert.IsNotNull(statusCondition); + statusCondition.EnabledStatuses = StatusKind.DataAvailableStatus; + TestHelper.CreateWaitSetThread(evt, statusCondition); + + var defaultStruct = new TestStructSequence(); + + var data = new TestStructSequence + { + UnboundedStructSequenceField = + { + new NestedStruct { Id = 1, Message = "With your feet in the air and your head on the ground" }, + new NestedStruct { Id = 2, Message = "Try this trick and spin it, yeah" }, + new NestedStruct { Id = 3, Message = "Your head will collapse" }, + new NestedStruct { Id = 4, Message = "But there's nothing in it" }, + new NestedStruct { Id = 5, Message = "And you'll ask yourself" }, + new NestedStruct { Id = 6, Message = "Where is my mind?" }, + }, + BoundedStructSequenceField = + { + new NestedStruct { Id = 1, Message = "With your feet in the air and your head on the ground" }, + new NestedStruct { Id = 2, Message = "Try this trick and spin it, yeah" }, + new NestedStruct { Id = 3, Message = "Your head will collapse" }, + new NestedStruct { Id = 4, Message = "But there's nothing in it" }, + new NestedStruct { Id = 5, Message = "And you'll ask yourself" }, + }, + }; + + ret = dataWriter.Write(data); + Assert.AreEqual(ReturnCode.Ok, ret); + + ret = dataWriter.WaitForAcknowledgments(new Duration { Seconds = 5 }); + Assert.AreEqual(ReturnCode.Ok, ret); + + Assert.IsTrue(evt.Wait(1_500)); + + var received = new TestStructSequence(); + var sampleInfo = new SampleInfo(); + ret = dataReader.ReadNextSample(received, sampleInfo); + Assert.AreEqual(ReturnCode.Ok, ret); + + for (var i = 1; i < data.BoundedStructSequenceField.Count; i++) + { + Assert.AreEqual(data.BoundedStructSequenceField[i].Id, received.BoundedStructSequenceField[i].Id); + Assert.AreEqual(data.BoundedStructSequenceField[i].Message, received.BoundedStructSequenceField[i].Message); + } + for (var i = 1; i < data.BoundedStructSequenceField.Count; i++) + { + Assert.AreEqual(data.UnboundedStructSequenceField[i].Id, received.UnboundedStructSequenceField[i].Id); + Assert.AreEqual(data.UnboundedStructSequenceField[i].Message, received.UnboundedStructSequenceField[i].Message); + } + + Assert.AreEqual(data.BoundedStructSequenceField.GetType(), typeof(List)); + Assert.AreEqual(data.UnboundedStructSequenceField.GetType(), typeof(List)); + + Assert.IsNotNull(defaultStruct.BoundedStructSequenceField); + Assert.AreEqual(0, defaultStruct.BoundedStructSequenceField.Count); + Assert.IsNotNull(defaultStruct.UnboundedStructSequenceField); + Assert.AreEqual(0, defaultStruct.UnboundedStructSequenceField.Count); + } + + /// + /// Test the code generated for the array of structures. + /// + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void TestGeneratedStructureArrays() + { + using var evt = new ManualResetEventSlim(false); + + var typeSupport = new TestStructArrayTypeSupport(); + var typeName = typeSupport.GetTypeName(); + var ret = typeSupport.RegisterType(_participant, typeName); + Assert.AreEqual(ReturnCode.Ok, ret); + + _topic = _participant.CreateTopic(TestContext.TestName, typeName); + Assert.IsNotNull(_topic); + + var drQos = new DataReaderQos + { + Reliability = + { + Kind = ReliabilityQosPolicyKind.ReliableReliabilityQos, + }, + }; + var dr = _subscriber.CreateDataReader(_topic, drQos); + Assert.IsNotNull(dr); + var dataReader = new TestStructArrayDataReader(dr); + + var dw = _publisher.CreateDataWriter(_topic); + Assert.IsNotNull(dw); + var dataWriter = new TestStructArrayDataWriter(dw); + + Assert.IsTrue(dataWriter.WaitForSubscriptions(1, 5000)); + Assert.IsTrue(dataReader.WaitForPublications(1, 5000)); + + var statusCondition = dr.StatusCondition; + Assert.IsNotNull(statusCondition); + statusCondition.EnabledStatuses = StatusKind.DataAvailableStatus; + TestHelper.CreateWaitSetThread(evt, statusCondition); + + var defaultStruct = new TestStructArray(); + + var data = new TestStructArray + { + StructArrayField = new[] + { + new NestedStruct { Message = "Pressure pushing down on me", Id = 1 }, + new NestedStruct { Message = "Pressing down on you, no man ask for", Id = 2 }, + new NestedStruct { Message = "Under pressure that burns a building down", Id = 3 }, + new NestedStruct { Message = "Splits a family in two", Id = 4 }, + new NestedStruct { Message = "Puts people on streets", Id = 5 }, + }, + }; + + ret = dataWriter.Write(data); + Assert.AreEqual(ReturnCode.Ok, ret); + + ret = dataWriter.WaitForAcknowledgments(new Duration { Seconds = 5 }); + Assert.AreEqual(ReturnCode.Ok, ret); + + Assert.IsTrue(evt.Wait(1_500)); + + var received = new TestStructArray(); + var sampleInfo = new SampleInfo(); + ret = dataReader.ReadNextSample(received, sampleInfo); + Assert.AreEqual(ReturnCode.Ok, ret); + + for (var i = 0; i < 5; i++) + { + Assert.AreEqual(data.StructArrayField[i].Id, received.StructArrayField[i].Id); + Assert.AreEqual(data.StructArrayField[i].Message, received.StructArrayField[i].Message); + } + + Assert.AreEqual(typeof(NestedStruct[]), data.StructArrayField.GetType()); + + Assert.IsNotNull(defaultStruct.StructArrayField); + Assert.AreEqual(5, defaultStruct.StructArrayField.Length); + foreach (var s in defaultStruct.StructArrayField) + { + Assert.IsNotNull(s); + } + } + + /// + /// Test the code generated for the multi-array of structures. + /// + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void TestGeneratedStructureMultiArrays() + { + using var evt = new ManualResetEventSlim(false); + + var typeSupport = new TestStructMultiArrayTypeSupport(); + var typeName = typeSupport.GetTypeName(); + var ret = typeSupport.RegisterType(_participant, typeName); + Assert.AreEqual(ReturnCode.Ok, ret); + + _topic = _participant.CreateTopic(TestContext.TestName, typeName); + Assert.IsNotNull(_topic); + + var drQos = new DataReaderQos + { + Reliability = + { + Kind = ReliabilityQosPolicyKind.ReliableReliabilityQos, + }, + }; + var dr = _subscriber.CreateDataReader(_topic, drQos); + Assert.IsNotNull(dr); + var dataReader = new TestStructMultiArrayDataReader(dr); + + var dw = _publisher.CreateDataWriter(_topic); + Assert.IsNotNull(dw); + var dataWriter = new TestStructMultiArrayDataWriter(dw); + + Assert.IsTrue(dataWriter.WaitForSubscriptions(1, 5000)); + Assert.IsTrue(dataReader.WaitForPublications(1, 5000)); + + var statusCondition = dr.StatusCondition; + Assert.IsNotNull(statusCondition); + statusCondition.EnabledStatuses = StatusKind.DataAvailableStatus; + TestHelper.CreateWaitSetThread(evt, statusCondition); + + var defaultStruct = new TestStructMultiArray(); + + var data = new TestStructMultiArray + { + StructMultiArrayField = new[] + { + new[] + { + new[] + { + new NestedStruct{ Id = 1, Message = "01" }, + new NestedStruct{ Id = 2, Message = "02" }, + }, + new[] + { + new NestedStruct { Id = 3, Message = "03" }, + new NestedStruct { Id = 4, Message = "04" }, + }, + new[] + { + new NestedStruct { Id = 5, Message = "05" }, + new NestedStruct { Id = 6, Message = "06" }, + }, + new[] + { + new NestedStruct { Id = 7, Message = "07" }, + new NestedStruct { Id = 8, Message = "08" }, + }, + }, + new[] + { + new[] + { + new NestedStruct { Id = 9, Message = "09" }, + new NestedStruct { Id = 10, Message = "10" }, + }, + new[] + { + new NestedStruct { Id = 11, Message = "11" }, + new NestedStruct { Id = 12, Message = "12" }, + }, + new[] + { + new NestedStruct { Id = 13, Message = "13" }, + new NestedStruct { Id = 14, Message = "14" }, + }, + new[] + { + new NestedStruct { Id = 15, Message = "15" }, + new NestedStruct{ Id = 16, Message = "16" }, + }, + }, + new[] + { + new[] + { + new NestedStruct{ Id = 17, Message = "17" }, + new NestedStruct{ Id = 18, Message = "18" }, + }, + new[] + { + new NestedStruct{ Id = 19, Message = "19" }, + new NestedStruct{ Id = 20, Message = "20" }, + }, + new[] + { + new NestedStruct{ Id = 21, Message = "21" }, + new NestedStruct{ Id = 22, Message = "22" }, + }, + new[] + { + new NestedStruct{ Id = 23, Message = "23" }, + new NestedStruct{ Id = 24, Message = "24" }, + }, + }, + }, + }; + + ret = dataWriter.Write(data); + Assert.AreEqual(ReturnCode.Ok, ret); + + ret = dataWriter.WaitForAcknowledgments(new Duration { Seconds = 5 }); + Assert.AreEqual(ReturnCode.Ok, ret); + + Assert.IsTrue(evt.Wait(1_500)); + + var received = new TestStructMultiArray(); + var sampleInfo = new SampleInfo(); + ret = dataReader.ReadNextSample(received, sampleInfo); + Assert.AreEqual(ReturnCode.Ok, ret); + + for (var i0 = 0; i0 < 3; i0++) + { + for (var i1 = 0; i1 < 4; i1++) + { + for (var i2 = 0; i2 < 2; i2++) + { + Assert.AreEqual(data.StructMultiArrayField[i0][i1][i2].Id, + received.StructMultiArrayField[i0][i1][i2].Id); + Assert.AreEqual(data.StructMultiArrayField[i0][i1][i2].Message, + received.StructMultiArrayField[i0][i1][i2].Message); + } + } + } + + Assert.AreEqual(typeof(NestedStruct[][][]), data.StructMultiArrayField.GetType()); + + for (var i0 = 0; i0 < 3; i0++) + { + for (var i1 = 0; i1 < 4; i1++) + { + for (var i2 = 0; i2 < 2; i2++) + { + Assert.IsNotNull(defaultStruct.StructMultiArrayField[i0][i1][i2]); + } + } + } + } + /// /// Test the code generated for the constants. /// diff --git a/Tests/OpenDDSharp.UnitTest/OpenDDSharp.UnitTest.csproj b/Tests/OpenDDSharp.UnitTest/OpenDDSharp.UnitTest.csproj index 865a0c6e..d1ac2ee2 100644 --- a/Tests/OpenDDSharp.UnitTest/OpenDDSharp.UnitTest.csproj +++ b/Tests/OpenDDSharp.UnitTest/OpenDDSharp.UnitTest.csproj @@ -61,9 +61,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + @@ -73,7 +73,7 @@ - + all @@ -81,11 +81,11 @@ all - + all - + all diff --git a/Tests/TestIdlCdr/IDL/Test.idl b/Tests/TestIdlCdr/IDL/Test.idl index 878496bc..e591f60b 100644 --- a/Tests/TestIdlCdr/IDL/Test.idl +++ b/Tests/TestIdlCdr/IDL/Test.idl @@ -48,7 +48,7 @@ module CdrWrapper { typedef char CharArrayType[5]; typedef wchar WCharArrayType[5]; typedef boolean BooleanArrayType[5]; - typedef octet OctetArrayType[5]; + typedef octet OctetArrayType[2048]; typedef int8 Int8ArrayType[5]; typedef uint8 UInt8ArrayType[5]; typedef short Int16ArrayType[5]; @@ -115,6 +115,40 @@ module CdrWrapper { typedef TestEnum EnumMultiArrayType[3][4][2]; + @topic + struct NestedStruct { + long Id; + string Message; + }; + + typedef sequence UnboundedStructSequenceType; + typedef sequence BoundedStructSequenceType; + + typedef NestedStruct StructArrayType[5]; + + typedef NestedStruct StructMultiArrayType[3][4][2]; + + @topic + struct TestStruct { + NestedStruct NestedStructField; + }; + + @topic + struct TestStructSequence { + UnboundedStructSequenceType UnboundedStructSequenceField; + BoundedStructSequenceType BoundedStructSequenceField; + }; + + @topic + struct TestStructArray { + StructArrayType StructArrayField; + }; + + @topic + struct TestStructMultiArray { + StructMultiArrayType StructMultiArrayField; + }; + @topic struct TestPrimitive { boolean BoolField; diff --git a/Tests/TestIdlCdr/TestIdlCdr.csproj b/Tests/TestIdlCdr/TestIdlCdr.csproj index 3961c846..ca90e7c4 100644 --- a/Tests/TestIdlCdr/TestIdlCdr.csproj +++ b/Tests/TestIdlCdr/TestIdlCdr.csproj @@ -162,7 +162,7 @@ - + @@ -180,23 +180,23 @@ - + - + - + - + - + @@ -206,17 +206,17 @@ - + - + - + diff --git a/Tests/TestIdlJson/TestIdlJson.csproj b/Tests/TestIdlJson/TestIdlJson.csproj index cd86caf7..f586a669 100644 --- a/Tests/TestIdlJson/TestIdlJson.csproj +++ b/Tests/TestIdlJson/TestIdlJson.csproj @@ -171,23 +171,23 @@ - + - + - + - + - + @@ -197,11 +197,11 @@ - + - + diff --git a/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj b/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj index 7b715074..5d4d6f41 100644 --- a/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj +++ b/Tests/TestSupportProcessCore/TestSupportProcessCore.csproj @@ -36,7 +36,7 @@ - + all @@ -48,11 +48,11 @@ all - + all - + all diff --git a/global.json b/global.json index e18484ac..f202156d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.301", + "version": "8.0.401", "rollForward": "latestFeature", "allowPrerelease": false }