Files
OpenNest/docs/performance/fill-verification.md
T
aj a27290a29c perf(fill): prepare overlap polygons once per check
Both HasOverlappingParts loops rebuilt each part's polygon from its
Program on every pair. PartOverlapChecker prepares each distinct Program
(reference identity) once and each part's world polygon once per call,
then uses the overlap-only Collision.HasOverlap. Loop order, bounding-box
prefilter, early exit and returned indices are unchanged; Part.Intersects
shares the material/polygon recipe and still returns crossing points.

Verification:
- Frozen LegacyPartOverlap differential (original Intersects and both
  loops): verdicts, indices and world polygons bit-identical across fill
  grids, patterns, touching/epsilon gaps, scribe/rapid/empty programs.
- Debug OverlapPolygonPreparations: 246 -> 1 and 64 -> 2 per check.
- Corpus job (169 parts, --engines Default --parallel 1, with 1a):
  median 18,885 -> 13,464 ms over 4+4 alternating runs, identical
  outcomes; serialized layout byte-identical to the base.
2026-09-27 13:34:04 -04:00

3.8 KiB

Fill performance verification

Opt-in synthetic measurements (OpenNest.Tests/Fill/FillPerformanceTests.cs):

OPENNEST_RUN_FILL_PERF=1 dotnet test OpenNest.Tests/OpenNest.Tests.csproj -c Release \
  --filter 'Category=FillPerformance' --logger 'console;verbosity=detailed'

Only the exact value 1 enables these tests; otherwise they skip; README documents the PowerShell equivalent.

The category covers comparer, group-pattern, rotated-pattern, extents-column, feature-extraction, no-model angle, and FillLinear offset-geometry workloads; individual filters match benchmark method names in FillPerformanceTests.cs. Overlap checks are measured separately by OverlapCheck_ReportsPolygonPairsAndGridChecks in OpenNest.Tests/Fill/OverlapCheckPerformanceTests.cs (same category). Keep harness, inputs, warmups and batches identical before/after; exclude setup/assertions from timing. Comparer/extents allocations are synchronous and current-thread only; parallel group fills omit allocation totals. No timing CI gates or whole-job speedup claims. Preserve evidence in the measured report.

Debug behavior/skipped-work checks:

dotnet test OpenNest.Tests/OpenNest.Tests.csproj -c Debug \
  --filter 'FullyQualifiedName~DefaultFillComparerWorkTests|FullyQualifiedName~FillHelpersTests|FullyQualifiedName~FillExtentsTests|FullyQualifiedName~StrategyOverlapTests|FullyQualifiedName~FillLinearGeometryReuseTests|FullyQualifiedName~CollisionOverlapOnlyTests|FullyQualifiedName~PartOverlapCheckerTests'

PerfCounters.FillScoreComputations, PartBoundaryPreparations, PartBoundsUpdates, OffsetPerimeterEntities, FeatureBitmaskCells, CrossingPointScans, and OverlapPolygonPreparations increments compile away in Release: zero Release counters prove nothing. OverlapPolygonPreparations counts overlap-preparation starts (material extraction), not completed polygons: Part.Intersects counts both parts on every call, PartOverlapChecker counts once per distinct Program. Serialize counter assertions in FillCacheCollection and reset in finally. Keep OpenNest.Tests/Fill/LegacyFillExtents.cs, OpenNest.Tests/Fill/LegacyFillLinear.cs, OpenNest.Tests/Geometry/LegacyCollision.cs, and OpenNest.Tests/Fill/LegacyPartOverlap.cs frozen for differential tests (never route them through production helpers), not production or before timings; measure the actual baseline production code.

Task 4b checks: dotnet test OpenNest.Tests/OpenNest.Tests.csproj -c Release --filter "FullyQualifiedName~AngleCandidateBuilderTests|FullyQualifiedName~AnglePredictorTests|FullyQualifiedName~FeatureExtractorTests" (repeat in Debug for bitmap counters). IrregularAngles_ReportsWarmNoModelPath measures the public builder with a missing model and skips when a model is installed; never remove real model files to benchmark. FeatureExtraction_ReportsFullAndScalarOnly measures extraction separately.

Predictor availability uses the same one-attempt session initialization as inference. Publish completion only after assignment or definitive failure; concurrent callers must wait for the outcome. The builder skips extraction when unavailable and requests scalar-only features when available. Tests use isolated loaders/prediction doubles, not evidence of real ONNX inference.

Whole-job before/after comparisons use OpenNest.Benchmark with a *.manifest.json corpus and --parallel 1 (see the report's Task 5 section for the delivered real-DXF manifest, hashes, outcome confirmation, and inconclusive whole-job timing). Circle-heavy archive drawings can validate INVALID at spacing even on the pre-batch baseline, and larger quantities can crash both trees identically; record such pre-existing behaviors instead of treating them as regressions or tuning around them.