2626import java .nio .file .Path ;
2727import java .util .ArrayList ;
2828import java .util .Arrays ;
29+ import java .util .HashMap ;
2930import java .util .List ;
3031import java .util .Locale ;
32+ import java .util .Map ;
3133import java .util .Random ;
3234import java .util .UUID ;
3335import java .util .function .LongSupplier ;
@@ -186,34 +188,54 @@ private void benchmarkVisibility(int itemCount, int viewerCount, String distribu
186188 }
187189 default -> throw new IllegalArgumentException ("Unknown visibility distribution: " + distribution );
188190 }
189- LongSupplier baseline = () -> linearActiveLabels (items , viewers , VIEW_DISTANCE );
191+ LongSupplier linearReference = () -> linearActiveLabels (items , viewers , VIEW_DISTANCE );
192+ LongSupplier legacyProduction = () -> legacyGridActiveLabels (items , viewers , VIEW_DISTANCE );
190193 LongSupplier candidate = () -> indexedActiveLabels (items , viewers , VIEW_DISTANCE );
191- long expectedLabels = baseline .getAsLong ();
194+ long expectedLabels = linearReference .getAsLong ();
195+ long legacyLabels = legacyProduction .getAsLong ();
192196 long candidateLabels = candidate .getAsLong ();
193- if (expectedLabels != candidateLabels ) {
194- throw new IllegalStateException ("Visibility A/B mismatch: " + expectedLabels + " != " + candidateLabels );
197+ if (expectedLabels != legacyLabels || expectedLabels != candidateLabels ) {
198+ throw new IllegalStateException ("Visibility A/B mismatch: linear=" + expectedLabels
199+ + ", legacy=" + legacyLabels + ", candidate=" + candidateLabels );
200+ }
201+ Comparison productionComparison ;
202+ Comparison referenceComparison ;
203+ if (((itemCount + viewerCount + seed ) & 1 ) == 0 ) {
204+ productionComparison = compare (legacyProduction , candidate );
205+ referenceComparison = compare (linearReference , candidate );
206+ } else {
207+ referenceComparison = compare (linearReference , candidate );
208+ productionComparison = compare (legacyProduction , candidate );
195209 }
196- String candidateStorage = candidateStorage (itemCount , viewers );
197- Comparison comparison = compare (baseline , candidate );
198210 double reduction = itemCount == 0 ? 0.0D : 100.0D * (itemCount - expectedLabels ) / itemCount ;
211+ reportVisibilityComparison ("visibility-production-ab" , "legacy-production-viewer-grid" , true ,
212+ distribution , seed , itemCount , viewerCount , productionComparison , expectedLabels , reduction );
213+ reportVisibilityComparison ("visibility-linear-reference" , "linear-viewer-snapshot-any" , false ,
214+ distribution , seed , itemCount , viewerCount , referenceComparison , expectedLabels , reduction );
215+ }
216+
217+ private void reportVisibilityComparison (String benchmark , String baseline , boolean baselineUsesGrid ,
218+ String distribution , int seed , int itemCount , int viewerCount ,
219+ Comparison comparison , long activeLabels , double reduction ) {
199220 String result = String .format (Locale .ROOT ,
200- "{\" benchmark\" :\" visibility \" ,\" distribution\" :\" %s\" ,\" seed\" :%d," +
221+ "{\" benchmark\" :\" %s \" ,\" distribution\" :\" %s\" ,\" seed\" :%d," +
201222 "\" items\" :%d,\" viewers\" :%d," +
202- "\" range\" :%.1f,\" baseline\" :\" linear-viewer-snapshot-any\" ," +
203- "\" candidate\" :\" production-hybrid-viewer-index\" ,\" candidateStorage\" :\" %s\" ," +
223+ "\" range\" :%.1f,\" baseline\" :\" %s\" ,\" baselineUsesGrid\" :%b," +
224+ "\" candidate\" :\" production-primitive-viewer-index\" ," +
225+ "\" candidateStorage\" :\" primitive-soa\" ," +
204226 "\" indexRebuiltPerOperation\" :true,\" candidateUsesGrid\" :false," +
205227 "\" sampleTargetNs\" :%d,\" measurementRounds\" :%d," +
206228 "\" baselineMedianNs\" :%d,\" baselineP95Ns\" :%d," +
207229 "\" candidateMedianNs\" :%d,\" candidateP95Ns\" :%d,\" speedup\" :%.3f," +
208230 "\" baselineRoundsNs\" :%s,\" candidateRoundsNs\" :%s," +
209231 "\" allLabels\" :%d,\" activeLabels\" :%d," +
210232 "\" labelReductionPct\" :%.3f}" ,
211- distribution , seed , itemCount , viewerCount , VIEW_DISTANCE , candidateStorage ,
233+ benchmark , distribution , seed , itemCount , viewerCount , VIEW_DISTANCE , baseline , baselineUsesGrid ,
212234 SAMPLE_TARGET_NANOS , MEASUREMENT_ROUNDS ,
213235 comparison .baseline ().median (), comparison .baseline ().p95 (),
214236 comparison .candidate ().median (), comparison .candidate ().p95 (), comparison .speedup (),
215237 Arrays .toString (comparison .baselineRoundsNs ()), Arrays .toString (comparison .candidateRoundsNs ()),
216- itemCount , expectedLabels , reduction );
238+ itemCount , activeLabels , reduction );
217239 report (result );
218240 }
219241
@@ -245,8 +267,11 @@ private static long linearActiveLabels(List<Point> items, List<Point> viewers, d
245267 return active ;
246268 }
247269
248- private static long indexedActiveLabels (List <Point > items , List <Point > viewers , double range ) {
249- DroppedItemSpatialIndex .ViewerIndex index = createViewerIndex (viewers , items .size ());
270+ private static long legacyGridActiveLabels (List <Point > items , List <Point > viewers , double range ) {
271+ LegacyViewerIndex index = new LegacyViewerIndex ();
272+ for (Point viewer : viewers ) {
273+ index .addViewer (BENCHMARK_WORLD_ID , viewer .x (), viewer .y (), viewer .z ());
274+ }
250275 long active = 0 ;
251276 for (Point item : items ) {
252277 if (index .hasViewerWithin (BENCHMARK_WORLD_ID , item .x (), item .y (), item .z (), range )) {
@@ -257,13 +282,20 @@ private static long indexedActiveLabels(List<Point> items, List<Point> viewers,
257282 return active ;
258283 }
259284
260- private static String candidateStorage (int itemCount , List <Point > viewers ) {
261- return createViewerIndex (viewers , itemCount ).usesPointStorage () ? "point-array" : "primitive-soa" ;
285+ private static long indexedActiveLabels (List <Point > items , List <Point > viewers , double range ) {
286+ DroppedItemSpatialIndex .ViewerIndex index = createViewerIndex (viewers );
287+ long active = 0 ;
288+ for (Point item : items ) {
289+ if (index .hasViewerWithin (BENCHMARK_WORLD_ID , item .x (), item .y (), item .z (), range )) {
290+ active ++;
291+ }
292+ }
293+ blackhole = active ;
294+ return active ;
262295 }
263296
264- private static DroppedItemSpatialIndex .ViewerIndex createViewerIndex (List <Point > viewers , int itemCount ) {
265- DroppedItemSpatialIndex .ViewerIndex index =
266- new DroppedItemSpatialIndex .ViewerIndex (viewers .size (), itemCount );
297+ private static DroppedItemSpatialIndex .ViewerIndex createViewerIndex (List <Point > viewers ) {
298+ DroppedItemSpatialIndex .ViewerIndex index = new DroppedItemSpatialIndex .ViewerIndex (viewers .size ());
267299 for (Point viewer : viewers ) {
268300 index .addViewer (BENCHMARK_WORLD_ID , viewer .x (), viewer .y (), viewer .z ());
269301 }
@@ -339,6 +371,60 @@ private record Comparison(Samples baseline, Samples candidate, long[] baselineRo
339371 long [] candidateRoundsNs , double speedup ) {
340372 }
341373
374+ /** Exact copy of the viewer-grid strategy used by production before the optimized candidate. */
375+ private static final class LegacyViewerIndex {
376+
377+ private static final double CELL_SIZE = 16.0D ;
378+ private final Map <LegacyViewerCell , List <LegacyViewerPoint >> viewerCells = new HashMap <>();
379+
380+ private void addViewer (UUID worldId , double x , double y , double z ) {
381+ viewerCells .computeIfAbsent (cell (worldId , x , z ), ignored -> new ArrayList <>())
382+ .add (new LegacyViewerPoint (x , y , z ));
383+ }
384+
385+ private boolean hasViewerWithin (UUID worldId , double x , double y , double z , double range ) {
386+ if (range < 0.0D ) {
387+ return false ;
388+ }
389+ int minimumX = coordinate (x - range );
390+ int maximumX = coordinate (x + range );
391+ int minimumZ = coordinate (z - range );
392+ int maximumZ = coordinate (z + range );
393+ double rangeSquared = range * range ;
394+ for (int cellX = minimumX ; cellX <= maximumX ; cellX ++) {
395+ for (int cellZ = minimumZ ; cellZ <= maximumZ ; cellZ ++) {
396+ List <LegacyViewerPoint > points = viewerCells .get (new LegacyViewerCell (worldId , cellX , cellZ ));
397+ if (points == null ) {
398+ continue ;
399+ }
400+ for (LegacyViewerPoint point : points ) {
401+ double deltaX = point .x () - x ;
402+ double deltaY = point .y () - y ;
403+ double deltaZ = point .z () - z ;
404+ if (deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ <= rangeSquared ) {
405+ return true ;
406+ }
407+ }
408+ }
409+ }
410+ return false ;
411+ }
412+
413+ private static LegacyViewerCell cell (UUID worldId , double x , double z ) {
414+ return new LegacyViewerCell (worldId , coordinate (x ), coordinate (z ));
415+ }
416+
417+ private static int coordinate (double value ) {
418+ return (int ) Math .floor (value / CELL_SIZE );
419+ }
420+ }
421+
422+ private record LegacyViewerCell (UUID worldId , int x , int z ) {
423+ }
424+
425+ private record LegacyViewerPoint (double x , double y , double z ) {
426+ }
427+
342428 private record Point (int id , double x , double y , double z ) {
343429
344430 private double distanceSquared (Point other ) {
0 commit comments