From cf0070a5e5bf573bf06735a3ce6f5e3f36d5c0a5 Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Wed, 30 Sep 2026 18:39:10 +0800 Subject: [PATCH] isl: record where the threaded visibility sweep pays and where it does not A single visibility test costs a few nanoseconds, so the thread start up is only repaid by a large matrix. Measured on sixteen cores the parallel form gains from a few hundred satellites and loses below that, so the note says so and points a small shell at the sequential form. --- crates/network/apsis-isl/src/batch.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/network/apsis-isl/src/batch.rs b/crates/network/apsis-isl/src/batch.rs index 4e9500f..63b8f1f 100644 --- a/crates/network/apsis-isl/src/batch.rs +++ b/crates/network/apsis-isl/src/batch.rs @@ -40,8 +40,18 @@ pub fn visibility_matrix(positions: &[Vec3], body_radius: f64) -> Vec { /// same order. The pairs are independent, so splitting the flat index space /// across threads needs no coordination and produces the same matrix however /// the work is divided. +/// +/// The gain from threading is modest here and shrinks as the matrix shrinks. +/// A single visibility test is a few nanoseconds, so the cost of starting the +/// threads is only repaid by a large matrix: on a sixteen core machine a few +/// hundred satellites already gain, while a few dozen lose. The sequential +/// form is the better choice for a small shell, and this one exists for the +/// large ones where the quadratic sweep dominates. pub fn visibility_matrix_parallel(positions: &[Vec3], body_radius: f64) -> Vec { let len = positions.len(); + // The pairs are independent, so splitting the flat index space across + // threads needs no coordination. `map_index` owns the output buffer, + // which is what lets the threads write disjoint slots of one allocation. map_index(len * len, |index| { let row = index / len; let column = index - row * len;