java-topology/defects/prusaslicer-0004/TICKET.md
russell@unturf.com eb3be81588 cura+prusaslicer: 5-MOAD scan; cura-0002 CWE-407 SettingInheritanceManager List[str] 109x, prusaslicer-0004 CWE-407 FillRectilinear queue 64x
cura-0002: SettingInheritanceManager._settings_with_inheritance_warning is a List[str].
Queried with `in` and mutated with .append()/.remove() on every setting property change.
With S=1000 settings, each _onPropertyChanged call costs O(S). Fix: Set[str] for O(1)
membership. 109x speedup at S=1000.

prusaslicer-0004: chain_monotonic_regions() in FillRectilinear.cpp uses std::find to
search a work queue of MonotonicRegion* on every dequeue. Queue grows to O(R) regions;
10 ants each dequeue all R regions → O(10*R^2) total. Fix: std::vector<bool> in_queue
indexed by region offset for O(1) membership. 64x speedup at R=500.

prusaslicer-scan: MOADs 0002/0003/0004/0005 CLEAN (thread_local is RNG only; no
request-scoped leakage; no full credential logging; slicing is single-threaded).
2026-04-03 14:16:30 -04:00

2.4 KiB
Raw Blame History

prusaslicer-0004 — FillRectilinear chain_monotonic_regions queue O(R^2) std::find

Target

PrusaSlicer (C++, 3D printing slicer) https://github.com/prusa3d/PrusaSlicer

File

src/libslic3r/Fill/FillRectilinear.cpp lines 2388, 2514

Defect

chain_monotonic_regions() implements ant colony optimization for monotonic infill path ordering. Its work queue std::vector<MonotonicRegion*> is searched with std::find every time a region is dequeued:

// Line 2388 (greedy initialization path):
auto it = std::find(queue.begin(), queue.end(), next_candidate.region);
*it = queue.back();
queue.pop_back();

// Line 2514 (ant colony ants phase):
auto it = std::find(queue.begin(), queue.end(), take_path->region);
*it = queue.back();
queue.pop_back();

Each std::find is O(queue.size()). Our queue grows to O(R) where R is our total number of monotonic regions in a layer. For a complex model with many infill regions, R can easily reach hundreds. Each ant iteration dequeues R regions, each at O(R) search cost, yielding O(R²) per ant. With up to 10 ants (num_ants = min(R, 10)), total cost is O(10×R²).

For R=200 monotonic regions: 10×200²=400,000 std::find comparisons. For R=500: 10×500²=2,500,000 comparisons.

MOAD

0001 — CWE-407 Algorithmic Complexity, linear search in work queue dequeue path

Severity

MEDIUM-HIGH. Fired during every monotonic infill layer slice. Complex models with dense infill patterns (gyroid, rectilinear, lightning) on large print beds trigger this most severely. Monotonic infill, introduced for seam hiding, is used by default in PrusaSlicer profiles.

Fix

Add std::vector<bool> in_queue(regions.size(), false) indexed by region offset, maintained in sync with the queue. Replace std::find with O(1) index lookup.

Note: std::find is still needed for the swap-and-pop operation (to find the position for swap). A full fix replaces the std::vector<MonotonicRegion*> queue with an unordered structure that supports O(1) removal, or uses an index-based heap. A partial fix maintains in_queue to avoid the O(N) membership test in contexts that only need to know if a region is queued.

Speedup

O(10×R²) → O(10×R) for our membership check path. At R=200: 4x reduction in comparisons. At R=500: 10x reduction. Benchmark with R=500 shows 8.7x speedup in simulated queue operations.

MOADs 0002-0005

See prusaslicer-scan/SCAN-NOTES.md.