Make vector mesh branch detection and free-point click targets O(n) instead of O(n^2) (#4255)

* Make is_branching and free-point click targets O(n) instead of O(n^2)

* usize -> u8

* Fix profiling CI treating performance improvements as regressions
This commit is contained in:
Keavon Chambers
2026-06-18 21:52:02 -07:00
committed by GitHub
parent 236ab7a11c
commit 13abf9fa8c
3 changed files with 32 additions and 11 deletions
@@ -137,6 +137,7 @@ jobs:
const sectionTitles = ['Compilation', 'Update', 'Run Once', 'Cached Execution']; const sectionTitles = ['Compilation', 'Update', 'Run Once', 'Cached Execution'];
let hasSignificantChanges = false; let hasSignificantChanges = false;
let hasRegressions = false;
let regressionDetails = []; let regressionDetails = [];
for (let i = 0; i < allOutputs.length; i++) { for (let i = 0; i < allOutputs.length; i++) {
@@ -153,19 +154,25 @@ jobs:
if (isSignificantChange(diffPct, absoluteChange, outputName)) { if (isSignificantChange(diffPct, absoluteChange, outputName)) {
hasSignificantChanges = true; hasSignificantChanges = true;
regressionDetails.push({
module_path: benchmark.module_path, // Only an increase in instruction count is a regression; improvements must not fail CI.
id: benchmark.id, if (diffPct > 0) {
diffPct, hasRegressions = true;
absoluteChange, regressionDetails.push({
sectionTitle module_path: benchmark.module_path,
}); id: benchmark.id,
diffPct,
absoluteChange,
sectionTitle
});
}
} }
} }
} }
} }
core.setOutput('has-significant-changes', hasSignificantChanges); core.setOutput('has-significant-changes', hasSignificantChanges);
core.setOutput('has-regressions', hasRegressions);
core.setOutput('regression-details', JSON.stringify(regressionDetails)); core.setOutput('regression-details', JSON.stringify(regressionDetails));
- name: Comment PR - name: Comment PR
@@ -319,7 +326,7 @@ jobs:
} }
- name: Fail on significant regressions - name: Fail on significant regressions
if: steps.analyze.outputs.has-significant-changes == 'true' if: steps.analyze.outputs.has-regressions == 'true'
uses: actions/github-script@v8 uses: actions/github-script@v8
with: with:
script: | script: |
@@ -1714,8 +1714,14 @@ fn extend_targets_from_vector(targets: &mut Vec<ClickTarget>, vector_list: &List
} }
fn extend_free_point_targets(vector: &Vector, transform: DAffine2) -> impl Iterator<Item = ClickTarget> + '_ { fn extend_free_point_targets(vector: &Vector, transform: DAffine2) -> impl Iterator<Item = ClickTarget> + '_ {
vector.point_domain.ids().iter().filter_map(move |&point_id| { // Mark every point index touched by a segment endpoint in one `O(points + segments)` pass, avoiding a per-point `any_connected` scan
if vector.any_connected(point_id) { let mut connected = vec![false; vector.point_domain.len()];
for &point_index in vector.segment_domain.start_point().iter().chain(vector.segment_domain.end_point()) {
connected[point_index] = true;
}
vector.point_domain.ids().iter().enumerate().filter_map(move |(point_index, &point_id)| {
if connected[point_index] {
return None; return None;
} }
@@ -1223,7 +1223,15 @@ impl Vector {
} }
pub fn is_branching(&self) -> bool { pub fn is_branching(&self) -> bool {
(0..self.point_domain.len()).any(|point_index| self.segment_domain.connected_count(point_index) > 2) // Tally segment endpoints per point in one `O(points + segments)` pass, short-circuiting once any point exceeds two
let mut connected_count = vec![0_u8; self.point_domain.len()];
for &point_index in self.segment_domain.start_point().iter().chain(self.segment_domain.end_point()) {
connected_count[point_index] += 1;
if connected_count[point_index] > 2 {
return true;
}
}
false
} }
pub fn has_regions(&self) -> bool { pub fn has_regions(&self) -> bool {