Skip to content

Performance Optimizations - #28

Open
John-194 wants to merge 10 commits into
wangyiqiu:masterfrom
John-194:optimizations
Open

Performance Optimizations#28
John-194 wants to merge 10 commits into
wangyiqiu:masterfrom
John-194:optimizations

Conversation

@John-194

Copy link
Copy Markdown
Contributor

Performance Optimizations

  • Improved performance 1.7x - 2.9x
  • Fixes high idle CPU usage

Tested using:

  • 3K 3D — 3k-point 3D cloud
  • 13K 2D — 13k-point 2D cloud
  • 100K 2D — 100k-point 2D cloud

The baseline and these optimizations return the same DBSCAN results.
Memory leaks were not detected.

Results vs. baseline (dev branch)

Speed (ms/iter)

CommitDescription3K 3D13K 2D100K 2D
5c7fdd5baseline0.861.299.38
39805c2parfor heuristic0.380.768.86
8da5e33260% idle CPU usage fix0.400.798.88
96c9cffpre-compute cell keys0.400.797.71
4a4025fdefer cell/mutex init0.410.796.27
607417eO(n) cluster renumbering0.430.665.51
847e798eliminate sqrt0.320.645.41
909a621dynamic thread count0.300.655.45

Speedup per step (vs. previous commit)

CommitDescription3K 3D13K 2D100K 2D
5c7fdd5baseline---
39805c2parfor heuristic2.26x1.70x1.06x
8da5e33260% idle CPU usage fix0.95x0.96x1.00x
96c9cffpre-compute cell keys1.00x1.00x1.15x
4a4025fdefer cell/mutex init0.98x1.00x1.23x
607417eO(n) cluster renumbering0.95x1.20x1.14x
847e798eliminate sqrt1.34x1.03x1.02x
909a621dynamic thread count1.07x0.98x0.99x

Cumulative speedup (vs. baseline)

CommitDescription3K 3D13K 2D100K 2D
5c7fdd5baseline---
39805c2parfor heuristic2.26x1.70x1.06x
8da5e33260% idle CPU usage fix2.15x1.63x1.06x
96c9cffpre-compute cell keys2.15x1.63x1.22x
4a4025fdefer cell/mutex init2.10x1.63x1.50x
607417eO(n) cluster renumbering2.00x1.95x1.70x
847e798eliminate sqrt2.69x2.02x1.73x
909a621dynamic thread count2.87x1.98x1.72x

Summary of changes

1. 39805c2 — Replace timing-based granularity with simple heuristic in parfor
Removed get_granularity() which ran a timed benchmark to decide chunk sizes at runtime. Replaced with a simple n / (4 * num_threads) heuristic plus a sequential fast-path for small ranges. Biggest win on the small 3K cloud (2.26x).

2. 8da5e33 — Fix idle CPU usage via progressive backoff and CV-based sleep
Rewrote the work-stealing loop in scheduler.h with a 3-phase backoff: aggressive spinning, yielding, then sleeping on a condition variable. spawn() only signals the CV when threads are actually sleeping (zero-cost during active computation). Also changed wait() to opportunistically execute stolen work instead of re-entering start(), preventing potential deadlocks. Neutral on performance but eliminates CPU burn on idle threads.

3. 96c9cff — Pre-compute cell keys for grid sort, avoiding floor()
In grid.h, pre-computes integer cell coordinates (floor((P[i][d] - pMin[d]) / r)) into a flat array before sorting, so the sort comparator uses integer comparisons instead of repeated floating-point floor().

4. 4a4025f — Defer grid cell/mutex init to used cells only, reduce hash table size
Moves std::mutex construction and nbrCache/cells initialization from all cellCapacity slots to only the numCells actually used after insertion. Also shrinks the initial hash table from cellMax*2 to max(2048, cellMax/4) with a rebuild if the estimate is too small.

5. 607417e — O(n) cluster renumbering via prefix sum
Replaced an O(n log n) sampleSort + hash-table lookup for remapping cluster IDs with a simple O(n) approach: mark which IDs are used in a flag array, prefix-sum to get sequential IDs, then remap. Eliminates the myPair struct, hashSimplePair, and Table allocation entirely.

6. 847e798 — Eliminate sqrt from distance comparisons
Added nodeDistanceSqr() to kdNode.h and switched all distance comparisons in coreBccp.h, kdNode.h, and kdTree.h to use the existing distSqr() and the new nodeDistanceSqr() instead of dist()/nodeDistance(). The BCCP threshold r <= epsilon becomes r <= epsilon * epsilon. Uses ternary operators instead of std::max for branchless codegen hints. 1.34x on 3K.

7. 909a621 — Dynamic thread count via getWorkers()
Replaced hardcoded static const intT P = 36*8 with getWorkers() * 8 in boundingBoxParallel() and pMinParallel(). Also switched VLA-style stack arrays to heap-allocated (newA + free) since the count is now dynamic. Portable across machines with different core counts.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@John-194