@jbroll/jscad-modeling 2.13.2 → 2.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bench/compare-branches.sh +131 -0
- package/bench/compare-perf-branches.sh +126 -0
- package/bench/results/archive/base.txt +6 -0
- package/bench/results/archive/extrude.txt +6 -0
- package/bench/results/archive/flatten.txt +6 -0
- package/bench/results/archive/object-pooling.txt +6 -0
- package/bench/results/archive/polygontree.txt +6 -0
- package/bench/results/archive/splitpolygon.txt +6 -0
- package/bench/results/archive/summary.txt +26 -0
- package/bench/results/base-new.txt +12 -0
- package/bench/results/base.txt +6 -0
- package/bench/results/extrude-new.txt +12 -0
- package/bench/results/extrude.txt +6 -0
- package/bench/results/flatten-new.txt +12 -0
- package/bench/results/flatten.txt +6 -0
- package/bench/results/master-new.txt +12 -0
- package/bench/results/object-pooling-new.txt +12 -0
- package/bench/results/object-pooling.txt +6 -0
- package/bench/results/perf-optimization-analysis.md +80 -0
- package/bench/results/polygontree-new.txt +12 -0
- package/bench/results/polygontree.txt +6 -0
- package/bench/results/splitpolygon-new.txt +12 -0
- package/bench/results/splitpolygon.txt +6 -0
- package/bench/results/summary.txt +26 -0
- package/benchmarks/compare-branches.js +419 -0
- package/benchmarks/quick-timing.js +219 -0
- package/dist/jscad-modeling.min.js +165 -162
- package/package.json +1 -1
- package/src/index.js +1 -0
- package/src/operations/booleans/index.js +2 -2
- package/src/operations/minkowski/index.d.ts +0 -2
- package/src/operations/minkowski/minkowskiSum.js +40 -37
- package/src/operations/minkowski/minkowskiSum.test.js +44 -6
- package/src/operations/booleans/intersectMenger.test.js +0 -154
- package/src/operations/booleans/minkowski.js +0 -223
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Compare performance across optimization branches
|
|
4
|
+
# Usage: ./compare-branches.sh
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
BASE_COMMIT="93d5df5d"
|
|
10
|
+
BRANCHES=(
|
|
11
|
+
"origin/pr/upstream-perf-polygontree"
|
|
12
|
+
"origin/pr/upstream-perf-splitpolygon"
|
|
13
|
+
"origin/pr/upstream-perf-flatten"
|
|
14
|
+
"origin/pr/upstream-perf-object-pooling"
|
|
15
|
+
"origin/pr/upstream-perf-extrude"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
RESULTS_DIR="bench/results"
|
|
19
|
+
BENCH_BACKUP="/tmp/jscad-bench-$$"
|
|
20
|
+
mkdir -p "$RESULTS_DIR"
|
|
21
|
+
|
|
22
|
+
# Save current state
|
|
23
|
+
ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || git rev-parse HEAD)
|
|
24
|
+
echo "Saving current state: $ORIGINAL_BRANCH"
|
|
25
|
+
|
|
26
|
+
# Backup bench scripts (they may not exist in base commit)
|
|
27
|
+
echo "Backing up bench scripts to $BENCH_BACKUP"
|
|
28
|
+
cp -r bench "$BENCH_BACKUP"
|
|
29
|
+
|
|
30
|
+
cleanup() {
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Restoring original state: $ORIGINAL_BRANCH"
|
|
33
|
+
git checkout -f -q "$ORIGINAL_BRANCH" 2>/dev/null || git checkout -f -q -
|
|
34
|
+
# Restore bench scripts
|
|
35
|
+
cp -r "$BENCH_BACKUP"/* bench/ 2>/dev/null || true
|
|
36
|
+
rm -rf "$BENCH_BACKUP"
|
|
37
|
+
}
|
|
38
|
+
trap cleanup EXIT
|
|
39
|
+
|
|
40
|
+
checkout_and_restore() {
|
|
41
|
+
local ref="$1"
|
|
42
|
+
# Remove bench scripts but keep results
|
|
43
|
+
rm -f bench/*.js bench/*.sh 2>/dev/null || true
|
|
44
|
+
git checkout -f -q "$ref"
|
|
45
|
+
# Restore bench scripts
|
|
46
|
+
mkdir -p bench
|
|
47
|
+
cp "$BENCH_BACKUP"/*.js "$BENCH_BACKUP"/*.sh bench/ 2>/dev/null || true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
run_benchmarks() {
|
|
51
|
+
local name="$1"
|
|
52
|
+
local outfile="$RESULTS_DIR/${name}.txt"
|
|
53
|
+
|
|
54
|
+
echo "Running benchmarks for: $name"
|
|
55
|
+
echo "=== $name ===" > "$outfile"
|
|
56
|
+
echo "" >> "$outfile"
|
|
57
|
+
|
|
58
|
+
# Run boolean benchmarks (most affected by optimizations)
|
|
59
|
+
echo "--- booleans.bench.js ---" >> "$outfile"
|
|
60
|
+
node bench/booleans.bench.js 2>&1 >> "$outfile"
|
|
61
|
+
|
|
62
|
+
echo "" >> "$outfile"
|
|
63
|
+
echo "--- splitPolygon.bench.js ---" >> "$outfile"
|
|
64
|
+
node --expose-gc bench/splitPolygon.bench.js 2>&1 >> "$outfile"
|
|
65
|
+
|
|
66
|
+
echo " -> Saved to $outfile"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
echo "============================================================"
|
|
70
|
+
echo "Performance Comparison: Base vs Optimization Branches"
|
|
71
|
+
echo "============================================================"
|
|
72
|
+
echo ""
|
|
73
|
+
echo "Base commit: $BASE_COMMIT"
|
|
74
|
+
echo "Branches to test: ${#BRANCHES[@]}"
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
# Run on base commit
|
|
78
|
+
echo "------------------------------------------------------------"
|
|
79
|
+
echo "[1/$((${#BRANCHES[@]}+1))] Checking out BASE: $BASE_COMMIT"
|
|
80
|
+
echo "------------------------------------------------------------"
|
|
81
|
+
checkout_and_restore "$BASE_COMMIT"
|
|
82
|
+
run_benchmarks "base"
|
|
83
|
+
echo ""
|
|
84
|
+
|
|
85
|
+
# Run on each optimization branch
|
|
86
|
+
i=2
|
|
87
|
+
for branch in "${BRANCHES[@]}"; do
|
|
88
|
+
short_name=$(echo "$branch" | sed 's|origin/pr/upstream-perf-||')
|
|
89
|
+
echo "------------------------------------------------------------"
|
|
90
|
+
echo "[$i/$((${#BRANCHES[@]}+1))] Checking out: $short_name"
|
|
91
|
+
echo "------------------------------------------------------------"
|
|
92
|
+
checkout_and_restore "$branch"
|
|
93
|
+
run_benchmarks "$short_name"
|
|
94
|
+
echo ""
|
|
95
|
+
((i++))
|
|
96
|
+
done
|
|
97
|
+
|
|
98
|
+
echo "============================================================"
|
|
99
|
+
echo "All benchmarks complete. Results in $RESULTS_DIR/"
|
|
100
|
+
echo "============================================================"
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
# Generate comparison summary
|
|
104
|
+
echo "Generating comparison summary..."
|
|
105
|
+
echo ""
|
|
106
|
+
echo "=== COMPARISON SUMMARY ===" | tee "$RESULTS_DIR/summary.txt"
|
|
107
|
+
echo "" | tee -a "$RESULTS_DIR/summary.txt"
|
|
108
|
+
|
|
109
|
+
# Extract key metrics from each result file
|
|
110
|
+
for result in "$RESULTS_DIR"/*.txt; do
|
|
111
|
+
name=$(basename "$result" .txt)
|
|
112
|
+
[[ "$name" == "summary" ]] && continue
|
|
113
|
+
|
|
114
|
+
echo "--- $name ---" | tee -a "$RESULTS_DIR/summary.txt"
|
|
115
|
+
|
|
116
|
+
# Extract torus(32) union time (good stress test metric)
|
|
117
|
+
torus_time=$(grep "union: torus(32)" "$result" | awk '{print $4}')
|
|
118
|
+
if [[ -n "$torus_time" ]]; then
|
|
119
|
+
echo " union torus(32)+torus(32): ${torus_time} ms/op" | tee -a "$RESULTS_DIR/summary.txt"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Extract spanning split time
|
|
123
|
+
spanning_time=$(grep "spanning split.*quad" "$result" | awk '{print $6}')
|
|
124
|
+
if [[ -n "$spanning_time" ]]; then
|
|
125
|
+
echo " spanning split (quad): ${spanning_time} µs/op" | tee -a "$RESULTS_DIR/summary.txt"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
echo "" | tee -a "$RESULTS_DIR/summary.txt"
|
|
129
|
+
done
|
|
130
|
+
|
|
131
|
+
echo "Done! See $RESULTS_DIR/summary.txt for quick comparison."
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Compare performance across optimization branches using standardized benchmarks
|
|
4
|
+
#
|
|
5
|
+
# Usage: ./compare-perf-branches.sh [runs]
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
MODELING_DIR="/home/john/pkg/OpenJSCAD.org/packages/modeling"
|
|
11
|
+
BENCHMARK_RUNNER="/home/john/src/jscadui/apps/jscad-web/run-benchmarks.cjs"
|
|
12
|
+
|
|
13
|
+
BASE_COMMIT="93d5df5d"
|
|
14
|
+
BRANCHES=(
|
|
15
|
+
"origin/pr/upstream-perf-polygontree"
|
|
16
|
+
"origin/pr/upstream-perf-splitpolygon"
|
|
17
|
+
"origin/pr/upstream-perf-flatten"
|
|
18
|
+
"origin/pr/upstream-perf-object-pooling"
|
|
19
|
+
"origin/pr/upstream-perf-extrude"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Key benchmarks that stress boolean operations
|
|
23
|
+
BENCHMARKS="sphere-union,swiss-cheese,chainmail,menger-intersect,sphere-cloud"
|
|
24
|
+
|
|
25
|
+
RUNS="${1:-3}"
|
|
26
|
+
RESULTS_DIR="$MODELING_DIR/bench/results"
|
|
27
|
+
mkdir -p "$RESULTS_DIR"
|
|
28
|
+
|
|
29
|
+
cd "$MODELING_DIR"
|
|
30
|
+
|
|
31
|
+
# Save current state
|
|
32
|
+
ORIGINAL_REF=$(git rev-parse HEAD)
|
|
33
|
+
echo "Saving current state: $ORIGINAL_REF"
|
|
34
|
+
|
|
35
|
+
cleanup() {
|
|
36
|
+
echo ""
|
|
37
|
+
echo "Restoring original state..."
|
|
38
|
+
git checkout -f -q "$ORIGINAL_REF" 2>/dev/null || true
|
|
39
|
+
}
|
|
40
|
+
trap cleanup EXIT
|
|
41
|
+
|
|
42
|
+
run_benchmarks() {
|
|
43
|
+
local name="$1"
|
|
44
|
+
local outfile="$RESULTS_DIR/${name}.txt"
|
|
45
|
+
|
|
46
|
+
echo "=== $name ===" > "$outfile"
|
|
47
|
+
|
|
48
|
+
# Run each key benchmark
|
|
49
|
+
for bench in ${BENCHMARKS//,/ }; do
|
|
50
|
+
result=$(node "$BENCHMARK_RUNNER" "$bench" "$RUNS" "$MODELING_DIR" 2>&1 | grep "benchmark-" | awk '{print $2}')
|
|
51
|
+
echo "$bench $result" >> "$outfile"
|
|
52
|
+
done
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
echo "============================================================"
|
|
56
|
+
echo "Performance Comparison: Base vs Optimization Branches"
|
|
57
|
+
echo "============================================================"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "Modeling dir: $MODELING_DIR"
|
|
60
|
+
echo "Base commit: $BASE_COMMIT"
|
|
61
|
+
echo "Runs: $RUNS"
|
|
62
|
+
echo "Benchmarks: $BENCHMARKS"
|
|
63
|
+
echo ""
|
|
64
|
+
|
|
65
|
+
# Run on base commit
|
|
66
|
+
echo "------------------------------------------------------------"
|
|
67
|
+
echo "[1/$((${#BRANCHES[@]}+1))] BASE: $BASE_COMMIT"
|
|
68
|
+
echo "------------------------------------------------------------"
|
|
69
|
+
git checkout -f -q "$BASE_COMMIT"
|
|
70
|
+
run_benchmarks "base"
|
|
71
|
+
cat "$RESULTS_DIR/base.txt"
|
|
72
|
+
echo ""
|
|
73
|
+
|
|
74
|
+
# Run on each optimization branch
|
|
75
|
+
i=2
|
|
76
|
+
for branch in "${BRANCHES[@]}"; do
|
|
77
|
+
short_name=$(echo "$branch" | sed 's|origin/pr/upstream-perf-||')
|
|
78
|
+
echo "------------------------------------------------------------"
|
|
79
|
+
echo "[$i/$((${#BRANCHES[@]}+1))] $short_name"
|
|
80
|
+
echo "------------------------------------------------------------"
|
|
81
|
+
git checkout -f -q "$branch"
|
|
82
|
+
run_benchmarks "$short_name"
|
|
83
|
+
cat "$RESULTS_DIR/${short_name}.txt"
|
|
84
|
+
echo ""
|
|
85
|
+
((i++))
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
echo "============================================================"
|
|
89
|
+
echo "COMPARISON TABLE"
|
|
90
|
+
echo "============================================================"
|
|
91
|
+
echo ""
|
|
92
|
+
|
|
93
|
+
# Print header
|
|
94
|
+
printf "%-16s" "Benchmark"
|
|
95
|
+
printf "%10s" "base"
|
|
96
|
+
for branch in "${BRANCHES[@]}"; do
|
|
97
|
+
short=$(echo "$branch" | sed 's|origin/pr/upstream-perf-||')
|
|
98
|
+
printf "%10s" "$short"
|
|
99
|
+
done
|
|
100
|
+
echo ""
|
|
101
|
+
printf "%-16s" "--------"
|
|
102
|
+
printf "%10s" "----"
|
|
103
|
+
for branch in "${BRANCHES[@]}"; do
|
|
104
|
+
printf "%10s" "----"
|
|
105
|
+
done
|
|
106
|
+
echo ""
|
|
107
|
+
|
|
108
|
+
# Print data rows
|
|
109
|
+
for bench in ${BENCHMARKS//,/ }; do
|
|
110
|
+
printf "%-16s" "$bench"
|
|
111
|
+
# Base time
|
|
112
|
+
base_time=$(grep "^$bench " "$RESULTS_DIR/base.txt" | awk '{print $2}')
|
|
113
|
+
printf "%10s" "$base_time"
|
|
114
|
+
|
|
115
|
+
# Branch times
|
|
116
|
+
for branch in "${BRANCHES[@]}"; do
|
|
117
|
+
short=$(echo "$branch" | sed 's|origin/pr/upstream-perf-||')
|
|
118
|
+
time=$(grep "^$bench " "$RESULTS_DIR/${short}.txt" | awk '{print $2}')
|
|
119
|
+
printf "%10s" "$time"
|
|
120
|
+
done
|
|
121
|
+
echo ""
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
echo ""
|
|
125
|
+
echo "Times in milliseconds (lower is better)"
|
|
126
|
+
echo "Results saved to: $RESULTS_DIR/"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
=== COMPARISON SUMMARY ===
|
|
2
|
+
|
|
3
|
+
--- base ---
|
|
4
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
5
|
+
spanning split (quad): quad µs/op
|
|
6
|
+
|
|
7
|
+
--- extrude ---
|
|
8
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
9
|
+
spanning split (quad): quad µs/op
|
|
10
|
+
|
|
11
|
+
--- flatten ---
|
|
12
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
13
|
+
spanning split (quad): quad µs/op
|
|
14
|
+
|
|
15
|
+
--- object-pooling ---
|
|
16
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
17
|
+
spanning split (quad): quad µs/op
|
|
18
|
+
|
|
19
|
+
--- polygontree ---
|
|
20
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
21
|
+
spanning split (quad): quad µs/op
|
|
22
|
+
|
|
23
|
+
--- splitpolygon ---
|
|
24
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
25
|
+
spanning split (quad): quad µs/op
|
|
26
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 31.18s
|
|
6
|
+
sphere-union 33.42s
|
|
7
|
+
sphere-cloud 26.82s
|
|
8
|
+
menger-intersect 25.53s
|
|
9
|
+
chainmail 22.86s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 139.81s
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 25.24s
|
|
6
|
+
sphere-union 32.29s
|
|
7
|
+
sphere-cloud 31.38s
|
|
8
|
+
menger-intersect 24.88s
|
|
9
|
+
chainmail 38.30s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 152.09s
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 27.92s
|
|
6
|
+
sphere-union 27.01s
|
|
7
|
+
sphere-cloud 28.25s
|
|
8
|
+
menger-intersect 31.02s
|
|
9
|
+
chainmail 89.45s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 203.66s
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 24.93s
|
|
6
|
+
sphere-union 25.32s
|
|
7
|
+
sphere-cloud 15.51s
|
|
8
|
+
menger-intersect 7.52s
|
|
9
|
+
chainmail 9.62s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 82.90s
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 23.33s
|
|
6
|
+
sphere-union 25.65s
|
|
7
|
+
sphere-cloud 25.16s
|
|
8
|
+
menger-intersect 23.30s
|
|
9
|
+
chainmail 44.90s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 142.34s
|
|
12
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Performance Optimization Analysis
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-06
|
|
4
|
+
**Base commit:** 93d5df5d
|
|
5
|
+
**Branches analyzed:** origin/pr/upstream-perf-*
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
Five performance optimization branches were analyzed. When combined on master, they produce a **3-4x speedup** on complex boolean operations. Individual branches show less improvement due to remaining O(n²) bottlenecks and high benchmark variance.
|
|
10
|
+
|
|
11
|
+
## Optimization Branches
|
|
12
|
+
|
|
13
|
+
| Branch | Optimization | Complexity Fix |
|
|
14
|
+
|--------|-------------|----------------|
|
|
15
|
+
| `splitpolygon` | Replace splice with filter in duplicate vertex removal | O(n²) → O(n) |
|
|
16
|
+
| `polygontree` | Defer PolygonTreeNode cleanup, avoid splice in remove() | O(n²) → O(1) |
|
|
17
|
+
| `flatten` | Iterative flatten with stack instead of recursive concat | O(n²) → O(n) |
|
|
18
|
+
| `extrude` | Replace concat with push in extrudeFromSlices | O(n²) → O(n) |
|
|
19
|
+
| `object-pooling` | Pre-allocate arrays in splitPolygonByPlane + O(n) fix | Reduces allocations |
|
|
20
|
+
|
|
21
|
+
## Benchmark Results (Heavy Mode)
|
|
22
|
+
|
|
23
|
+
### Chainmail Benchmark (36 tori union)
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Branch Time (3 runs) Variance
|
|
27
|
+
base 37.7s, 39.7s, 39.4s ±3% (consistent)
|
|
28
|
+
splitpolygon 39.1s, 37.9s, 60.6s ±37% (variable)
|
|
29
|
+
object-pooling 17.8s, 23.7s, 55.2s ±68% (very variable)
|
|
30
|
+
master 9.5s, 12.1s, 14.1s ±19% (fast)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Full Suite (Single Run)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
swiss-cheese sphere-union sphere-cloud menger chainmail TOTAL
|
|
37
|
+
base 31.2s 33.4s 26.8s 25.5s 22.9s 139.8s
|
|
38
|
+
splitpolygon 25.3s 26.7s 23.8s 21.6s 22.9s 120.3s
|
|
39
|
+
master 24.9s 25.3s 15.5s 7.5s 9.6s 82.9s
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Key Findings
|
|
43
|
+
|
|
44
|
+
1. **High variance** - The chainmail benchmark shows up to 3x variance between runs on the same code. Single-run benchmarks are unreliable.
|
|
45
|
+
|
|
46
|
+
2. **Synergistic optimizations** - Master (with all optimizations) achieves 3-4x speedup because fixing ALL O(n²) bottlenecks produces compounding benefits.
|
|
47
|
+
|
|
48
|
+
3. **splitPolygonByPlane is the hot path** - This function is called thousands of times during complex boolean operations. The O(n²) splice in duplicate vertex removal was the primary bottleneck.
|
|
49
|
+
|
|
50
|
+
4. **Individual branches don't show full benefit** - Each branch fixes one bottleneck while others remain, limiting observable improvement.
|
|
51
|
+
|
|
52
|
+
## Recommended Push Order
|
|
53
|
+
|
|
54
|
+
1. **splitpolygon** - Highest impact, minimal change, foundation for others
|
|
55
|
+
2. **polygontree** - Independent O(n²) fix, high impact
|
|
56
|
+
3. **flatten** - Independent O(n²) fix, moderate impact
|
|
57
|
+
4. **extrude** - Independent optimization, lower impact
|
|
58
|
+
5. **object-pooling** - Adds pooling on top of splitpolygon fix (push after #1)
|
|
59
|
+
|
|
60
|
+
## Additional Optimizations on Master
|
|
61
|
+
|
|
62
|
+
These commits are on master but not in the upstream-perf branches:
|
|
63
|
+
|
|
64
|
+
- `3d6214b6` - poly3 V8 performance optimization
|
|
65
|
+
- `818a2a1a` - vec2 allocation reduction in reTesselateCoplanarPolygons
|
|
66
|
+
|
|
67
|
+
## Files Changed
|
|
68
|
+
|
|
69
|
+
| Branch | Files Modified |
|
|
70
|
+
|--------|---------------|
|
|
71
|
+
| splitpolygon | `src/operations/booleans/trees/splitPolygonByPlane.js` |
|
|
72
|
+
| polygontree | `src/operations/booleans/trees/PolygonTreeNode.js` |
|
|
73
|
+
| flatten | `src/utils/flatten.js` |
|
|
74
|
+
| extrude | `src/operations/extrusions/extrudeFromSlices.js` |
|
|
75
|
+
| object-pooling | `src/operations/booleans/trees/splitPolygonByPlane.js` |
|
|
76
|
+
|
|
77
|
+
## Benchmarking Tools
|
|
78
|
+
|
|
79
|
+
- `benchmarks/quick-timing.js` - Quick single-run timing (lite/heavy modes)
|
|
80
|
+
- `benchmarks/compare-branches.js` - Interleaved multi-run comparison between branches
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 20.74s
|
|
6
|
+
sphere-union 25.81s
|
|
7
|
+
sphere-cloud 23.89s
|
|
8
|
+
menger-intersect 14.02s
|
|
9
|
+
chainmail 64.09s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 148.55s
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
════════════════════════════════════════════════════════════
|
|
2
|
+
Quick Benchmark Timing (heavy mode)
|
|
3
|
+
════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
swiss-cheese 25.27s
|
|
6
|
+
sphere-union 26.73s
|
|
7
|
+
sphere-cloud 23.81s
|
|
8
|
+
menger-intersect 21.60s
|
|
9
|
+
chainmail 22.92s
|
|
10
|
+
────────────────────────────────
|
|
11
|
+
TOTAL 120.32s
|
|
12
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
=== COMPARISON SUMMARY ===
|
|
2
|
+
|
|
3
|
+
--- base ---
|
|
4
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
5
|
+
spanning split (quad): quad µs/op
|
|
6
|
+
|
|
7
|
+
--- extrude ---
|
|
8
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
9
|
+
spanning split (quad): quad µs/op
|
|
10
|
+
|
|
11
|
+
--- flatten ---
|
|
12
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
13
|
+
spanning split (quad): quad µs/op
|
|
14
|
+
|
|
15
|
+
--- object-pooling ---
|
|
16
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
17
|
+
spanning split (quad): quad µs/op
|
|
18
|
+
|
|
19
|
+
--- polygontree ---
|
|
20
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
21
|
+
spanning split (quad): quad µs/op
|
|
22
|
+
|
|
23
|
+
--- splitpolygon ---
|
|
24
|
+
union torus(32)+torus(32): torus(32) ms/op
|
|
25
|
+
spanning split (quad): quad µs/op
|
|
26
|
+
|