Skip to content

Commit 3f78ea1

Browse files
author
Michael Conrad
authored
Merge pull request #12 from MichaCo/copilot/add-cdt-benchmark-project
Add CDT.Comparison.Benchmarks — 6-library CDT/Delaunay performance comparison (Windows + Linux)
2 parents 732afa7 + 65a7073 commit 3f78ea1

14 files changed

Lines changed: 1001 additions & 8 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ jobs:
3838
8.0.x
3939
10.0.x
4040
41-
# Windows: restore full solution (includes Windows-only CDT.Viz)
41+
# Windows: restore cross-platform + Windows-only projects (CDT.Viz targets Windows only)
42+
# CDT.Comparison.Benchmarks is excluded: its native cmake/cargo build is too slow for CI
4243
- name: Restore dependencies
4344
if: runner.os == 'Windows'
44-
run: dotnet restore
45+
run: |
46+
dotnet restore src/CDT.Core/CDT.Core.csproj
47+
dotnet restore test/CDT.Tests/CDT.Tests.csproj
48+
dotnet restore benchmark/CDT.Benchmarks/CDT.Benchmarks.csproj
49+
dotnet restore viz/CDT.Viz/CDT.Viz.csproj
4550
4651
# Linux: restore only cross-platform projects (CDT.Viz targets Windows only)
4752
- name: Restore dependencies
@@ -50,10 +55,15 @@ jobs:
5055
dotnet restore src/CDT.Core/CDT.Core.csproj
5156
dotnet restore test/CDT.Tests/CDT.Tests.csproj
5257
53-
# Windows: build full solution
58+
# Windows: build cross-platform + Windows-only projects
59+
# CDT.Comparison.Benchmarks is excluded: its native cmake/cargo build is too slow for CI
5460
- name: Build
5561
if: runner.os == 'Windows'
56-
run: dotnet build --no-restore -c Release
62+
run: |
63+
dotnet build --no-restore -c Release src/CDT.Core/CDT.Core.csproj
64+
dotnet build --no-restore -c Release test/CDT.Tests/CDT.Tests.csproj
65+
dotnet build --no-restore -c Release benchmark/CDT.Benchmarks/CDT.Benchmarks.csproj
66+
dotnet build --no-restore -c Release viz/CDT.Viz/CDT.Viz.csproj
5767
5868
# Linux: build only cross-platform projects
5969
- name: Build
@@ -62,10 +72,10 @@ jobs:
6272
dotnet build --no-restore -c Release src/CDT.Core/CDT.Core.csproj
6373
dotnet build --no-restore -c Release test/CDT.Tests/CDT.Tests.csproj
6474
65-
# Windows: test full solution
75+
# Windows: test CDT.Tests only (CDT.Comparison.Benchmarks excluded from CI build)
6676
- name: Test
6777
if: runner.os == 'Windows'
68-
run: dotnet test --no-build -c Release --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=${{ github.workspace }}/coverage/coverage.cobertura.xml
78+
run: dotnet test --no-build -c Release --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=${{ github.workspace }}/coverage/coverage.cobertura.xml test/CDT.Tests/CDT.Tests.csproj
6979

7080
# Linux: test only CDT.Tests (CDT.Viz has no tests; benchmark is not a test project)
7181
- name: Test
@@ -110,11 +120,12 @@ jobs:
110120
with:
111121
fetch-depth: 0 # Required for SourceLink
112122

123+
# Only CDT.Core is needed for pack; CDT.Comparison.Benchmarks is excluded
113124
- name: Restore dependencies
114-
run: dotnet restore
125+
run: dotnet restore src/CDT.Core/CDT.Core.csproj
115126

116127
- name: Build
117-
run: dotnet build --no-restore -c Release
128+
run: dotnet build --no-restore -c Release src/CDT.Core/CDT.Core.csproj
118129

119130
- name: Pack
120131
shell: pwsh

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ _ReSharper*/
5151
# BenchmarkDotNet
5252
BenchmarkDotNet.Artifacts/
5353

54+
# Native build artifacts
55+
benchmark/CDT.Comparison.Benchmarks/native/cdt_wrapper/build/
56+
benchmark/CDT.Comparison.Benchmarks/native/cgal_wrapper/build/
57+
benchmark/CDT.Comparison.Benchmarks/native/spade_wrapper/target/
58+
5459
# OS generated files
5560
.DS_Store
5661
.DS_Store?
@@ -69,3 +74,5 @@ lcov.info
6974
# Temp files
7075
*.tmp
7176
*.temp
77+
_codeql_detected_source_root
78+
Program.cs

CDT.NET.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Solution>
22
<Folder Name="/benchmark/">
33
<Project Path="benchmark/CDT.Benchmarks/CDT.Benchmarks.csproj" />
4+
<Project Path="benchmark/CDT.Comparison.Benchmarks/CDT.Comparison.Benchmarks.csproj" />
45
</Folder>
56
<Folder Name="/Solution Items/">
67
<File Path=".editorconfig" />
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
9+
</PropertyGroup>
10+
11+
<!-- Exclude native/ from all MSBuild default SDK globs.
12+
Without this, .resx files inside Boost's downloaded sources
13+
(e.g., boost_math .NET examples) get picked up as EmbeddedResource
14+
items and cause MSB3822 build errors. -->
15+
<PropertyGroup>
16+
<DefaultItemExcludes>$(DefaultItemExcludes);native\**</DefaultItemExcludes>
17+
</PropertyGroup>
18+
19+
<!-- CDT.NET (baseline) -->
20+
<ItemGroup>
21+
<ProjectReference Include="..\..\src\CDT.Core\CDT.Core.csproj" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
26+
<!-- Triangle.NET: classic robust CDT, supports constrained edges via Segments -->
27+
<PackageReference Include="Unofficial.Triangle.NET" Version="0.0.1" />
28+
<!-- NetTopologySuite: conforming CDT (may insert Steiner points) -->
29+
<PackageReference Include="NetTopologySuite" Version="2.6.0" />
30+
</ItemGroup>
31+
32+
<!-- Copy test input files so benchmarks can find them at runtime -->
33+
<ItemGroup>
34+
<Content Include="..\..\test\CDT.Tests\inputs\*.txt"
35+
CopyToOutputDirectory="PreserveNewest"
36+
Link="inputs\%(Filename)%(Extension)" />
37+
</ItemGroup>
38+
39+
<!--
40+
═══════════════════════════════════════════════════════════════════════════
41+
Native wrapper configuration (artem-ogre/CDT C++, CGAL C++, Spade Rust)
42+
43+
Requirements
44+
C++ wrappers: cmake ≥ 3.20, a C++17 compiler, internet access (FetchContent)
45+
Rust wrapper: cargo / rustup, internet access (crates.io)
46+
47+
Output filename conventions (all end up in $(OutputPath)):
48+
Windows : cdt_wrapper.dll / cgal_wrapper.dll / spade_wrapper.dll
49+
macOS : libcdt_wrapper.dylib / libcgal_wrapper.dylib / libspade_wrapper.dylib
50+
Linux : libcdt_wrapper.so / libcgal_wrapper.so / libspade_wrapper.so
51+
═══════════════════════════════════════════════════════════════════════════
52+
-->
53+
<PropertyGroup>
54+
<_CdtNativeDir>$(MSBuildThisFileDirectory)native/cdt_wrapper</_CdtNativeDir>
55+
<_CdtBuildDir>$(_CdtNativeDir)/build</_CdtBuildDir>
56+
<_CgalNativeDir>$(MSBuildThisFileDirectory)native/cgal_wrapper</_CgalNativeDir>
57+
<_CgalBuildDir>$(_CgalNativeDir)/build</_CgalBuildDir>
58+
<_SpadeNativeDir>$(MSBuildThisFileDirectory)native/spade_wrapper</_SpadeNativeDir>
59+
<_SpadeReleaseDir>$(_SpadeNativeDir)/target/release</_SpadeReleaseDir>
60+
61+
<!-- lib prefix: empty on Windows, "lib" everywhere else -->
62+
<_NativeLibPrefix Condition="'$(OS)' != 'Windows_NT'">lib</_NativeLibPrefix>
63+
64+
<!-- extension: .dll on Windows, .dylib on macOS, .so on Linux -->
65+
<_NativeLibExt Condition="'$(OS)' == 'Windows_NT'">.dll</_NativeLibExt>
66+
<_NativeLibExt Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))">.dylib</_NativeLibExt>
67+
<_NativeLibExt Condition="'$(_NativeLibExt)' == ''">.so</_NativeLibExt>
68+
69+
<!-- Source-side paths (in native/*/build or target/) -->
70+
<_CdtLibFile>$(_CdtBuildDir)/$(_NativeLibPrefix)cdt_wrapper$(_NativeLibExt)</_CdtLibFile>
71+
<_CgalLibFile>$(_CgalBuildDir)/$(_NativeLibPrefix)cgal_wrapper$(_NativeLibExt)</_CgalLibFile>
72+
<_SpadeLibFile>$(_SpadeReleaseDir)/$(_NativeLibPrefix)spade_wrapper$(_NativeLibExt)</_SpadeLibFile>
73+
</PropertyGroup>
74+
75+
<!-- ── artem-ogre/CDT C++ wrapper ──────────────────────────────────────── -->
76+
77+
<!-- Friendly error when cmake is not on PATH (shared by both C++ wrappers).
78+
BeforeTargets means this is also skipped when its owning targets are
79+
skipped via Condition (i.e. when the output libs already exist). -->
80+
<Target Name="CheckCmake" BeforeTargets="BuildCdtNative;BuildCgalNative">
81+
<Exec Command="cmake --version"
82+
IgnoreExitCode="true"
83+
ConsoleToMSBuild="true"
84+
StandardOutputImportance="Low"
85+
StandardErrorImportance="Low">
86+
<Output TaskParameter="ExitCode" PropertyName="_CmakeExitCode" />
87+
</Exec>
88+
<Error Condition="'$(_CmakeExitCode)' != '0'"
89+
Text="cmake was not found on PATH. It is required to build the C++ wrappers. Install CMake from https://cmake.org/download/ and ensure it is on your PATH." />
90+
</Target>
91+
92+
<!--
93+
IMPORTANT: $(OutputPath) is empty at PropertyGroup evaluation time in SDK-style
94+
projects, so the output lib paths must be inlined directly in Condition attributes
95+
(which are evaluated at target-execution time when $(OutputPath) is fully resolved).
96+
97+
Condition="!Exists('$(OutputPath)...')" means:
98+
• First build (or after `dotnet clean`): output lib is missing → run cmake/cargo.
99+
The BeforeTargets check targets (CheckCmake/CheckCargo) also run.
100+
• Every subsequent `dotnet build`: output lib already in output dir → entire
101+
target AND its BeforeTargets prerequisites are skipped — no cmake or cargo invoked.
102+
The cmake/cargo build dirs (native/*/build, native/*/target) are NOT cleaned by
103+
`dotnet clean`, so a rebuild after clean is fast (only re-links if needed).
104+
-->
105+
<Target Name="BuildCdtNative" BeforeTargets="Build"
106+
Condition="!Exists('$(OutputPath)$(_NativeLibPrefix)cdt_wrapper$(_NativeLibExt)')">
107+
<MakeDir Directories="$(_CdtBuildDir)" />
108+
<Exec Command="cmake -S &quot;$(_CdtNativeDir)&quot; -B &quot;$(_CdtBuildDir)&quot; -DCMAKE_BUILD_TYPE=Release" />
109+
<Exec Command="cmake --build &quot;$(_CdtBuildDir)&quot; --config Release" />
110+
<MakeDir Directories="$(OutputPath)" />
111+
<Copy SourceFiles="$(_CdtLibFile)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
112+
</Target>
113+
114+
<!-- ── CGAL C++ wrapper ─────────────────────────────────────────────────── -->
115+
116+
<Target Name="BuildCgalNative" BeforeTargets="Build"
117+
Condition="!Exists('$(OutputPath)$(_NativeLibPrefix)cgal_wrapper$(_NativeLibExt)')">
118+
<MakeDir Directories="$(_CgalBuildDir)" />
119+
<Exec Command="cmake -S &quot;$(_CgalNativeDir)&quot; -B &quot;$(_CgalBuildDir)&quot; -DCMAKE_BUILD_TYPE=Release" />
120+
<Exec Command="cmake --build &quot;$(_CgalBuildDir)&quot; --config Release" />
121+
<MakeDir Directories="$(OutputPath)" />
122+
<Copy SourceFiles="$(_CgalLibFile)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
123+
</Target>
124+
125+
<!-- ── Spade Rust wrapper ───────────────────────────────────────────────── -->
126+
127+
<!-- Friendly error when cargo is not on PATH -->
128+
<Target Name="CheckCargo" BeforeTargets="BuildSpadeNative">
129+
<Exec Command="cargo --version"
130+
IgnoreExitCode="true"
131+
ConsoleToMSBuild="true"
132+
StandardOutputImportance="Low"
133+
StandardErrorImportance="Low">
134+
<Output TaskParameter="ExitCode" PropertyName="_CargoExitCode" />
135+
</Exec>
136+
<Error Condition="'$(_CargoExitCode)' != '0'"
137+
Text="cargo was not found on PATH. It is required to build the Spade Rust wrapper. Install Rust from https://rustup.rs/ and ensure cargo is on your PATH." />
138+
</Target>
139+
140+
<Target Name="BuildSpadeNative" BeforeTargets="Build"
141+
Condition="!Exists('$(OutputPath)$(_NativeLibPrefix)spade_wrapper$(_NativeLibExt)')">
142+
<Exec Command="cargo build --release --manifest-path &quot;$(_SpadeNativeDir)/Cargo.toml&quot;" />
143+
<MakeDir Directories="$(OutputPath)" />
144+
<Copy SourceFiles="$(_SpadeLibFile)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
145+
</Target>
146+
147+
<!-- ── Clean hook ───────────────────────────────────────────────────────── -->
148+
149+
<!-- Remove the native libs from the output dir when `dotnet clean` runs,
150+
so the next build will re-copy (and re-compile if needed) them. -->
151+
<Target Name="CleanNativeWrappers" AfterTargets="Clean">
152+
<Delete Files="$(OutputPath)$(_NativeLibPrefix)cdt_wrapper$(_NativeLibExt);
153+
$(OutputPath)$(_NativeLibPrefix)cgal_wrapper$(_NativeLibExt);
154+
$(OutputPath)$(_NativeLibPrefix)spade_wrapper$(_NativeLibExt)" />
155+
</Target>
156+
157+
</Project>

0 commit comments

Comments
 (0)