|
61 | 61 | /// `@Setup` asserts each decoded column is the expected encoded type and fails loudly otherwise, |
62 | 62 | /// so the baseline can never silently measure a plain column. |
63 | 63 | /// |
| 64 | +/// Each `filterX`/`sumX` kernel method is paired with a `forLoopX` method holding the true control: |
| 65 | +/// the obvious hand-written accessor loop a developer writes WITHOUT the compute layer — no [Mask], |
| 66 | +/// no [Compute], no off-heap bitmap, just `getDouble(i)`/`getLong(i)` and a counter. The paired |
| 67 | +/// methods share the exact predicate and threshold constant so they cannot drift, giving three |
| 68 | +/// reference points: |
| 69 | +/// - `forLoopX` — the naive decode-per-element loop, the developer's baseline. |
| 70 | +/// - `filterX` — the current kernel, which still decodes through the accessor; the `forLoopX`→ |
| 71 | +/// `filterX` gap is the kernel's overhead (or benefit) today. |
| 72 | +/// - the future encoded-domain specialisation — measured against `forLoopX`, which it must beat by |
| 73 | +/// comparing and reducing in the integer domain instead of decoding every element. |
| 74 | +/// |
64 | 75 | /// Run: java -jar performance/target/benchmarks.jar ComputeKernelBenchmark |
65 | 76 | @State(Scope.Benchmark) |
66 | 77 | @BenchmarkMode(Mode.AverageTime) |
@@ -222,6 +233,90 @@ public Number filterThenSumAlp() { |
222 | 233 | } |
223 | 234 | } |
224 | 235 |
|
| 236 | + /// Naive baseline for [#filterAlpDouble()]: the hand-written `price > 500` count loop over the |
| 237 | + /// ALP accessor, with no [Mask], no [Compute] and no off-heap bitmap. Decodes every double per |
| 238 | + /// element. Returns the count so JMH cannot eliminate the loop. |
| 239 | + /// |
| 240 | + /// @return the number of rows with `price > 500` |
| 241 | + @Benchmark |
| 242 | + public long forLoopAlpDouble() { |
| 243 | + LazyAlpDoubleArray array = price; |
| 244 | + long n = array.length(); |
| 245 | + long count = 0; |
| 246 | + for (long i = 0; i < n; i++) { |
| 247 | + if (array.getDouble(i) > PRICE_THRESHOLD) { |
| 248 | + count++; |
| 249 | + } |
| 250 | + } |
| 251 | + return count; |
| 252 | + } |
| 253 | + |
| 254 | + /// Naive baseline for [#filterForLong()]: the hand-written `measure > base + spread/2` count loop |
| 255 | + /// over the Frame-of-Reference accessor, reconstructing each `offset + ref` long per element. |
| 256 | + /// |
| 257 | + /// @return the number of rows with `measure > base + spread/2` |
| 258 | + @Benchmark |
| 259 | + public long forLoopForLong() { |
| 260 | + LazyForLongArray array = measure; |
| 261 | + long n = array.length(); |
| 262 | + long count = 0; |
| 263 | + for (long i = 0; i < n; i++) { |
| 264 | + if (array.getLong(i) > MEASURE_THRESHOLD) { |
| 265 | + count++; |
| 266 | + } |
| 267 | + } |
| 268 | + return count; |
| 269 | + } |
| 270 | + |
| 271 | + /// Naive baseline for [#filterDict()]: the hand-written `category == 7` count loop over the |
| 272 | + /// dictionary accessor, resolving each code through the dictionary per element. |
| 273 | + /// |
| 274 | + /// @return the number of rows with `category == 7` |
| 275 | + @Benchmark |
| 276 | + public long forLoopDict() { |
| 277 | + DictLongArray array = category; |
| 278 | + long n = array.length(); |
| 279 | + long count = 0; |
| 280 | + for (long i = 0; i < n; i++) { |
| 281 | + if (array.getLong(i) == CATEGORY_VALUE) { |
| 282 | + count++; |
| 283 | + } |
| 284 | + } |
| 285 | + return count; |
| 286 | + } |
| 287 | + |
| 288 | + /// Naive baseline for [#filterPlainControl()]: the hand-written `plain > 0` count loop over the |
| 289 | + /// materialised accessor, reading each long straight from the segment per element. |
| 290 | + /// |
| 291 | + /// @return the number of rows with `plain > 0` |
| 292 | + @Benchmark |
| 293 | + public long forLoopPlainControl() { |
| 294 | + MaterializedLongArray array = plain; |
| 295 | + long n = array.length(); |
| 296 | + long count = 0; |
| 297 | + for (long i = 0; i < n; i++) { |
| 298 | + if (array.getLong(i) > 0L) { |
| 299 | + count++; |
| 300 | + } |
| 301 | + } |
| 302 | + return count; |
| 303 | + } |
| 304 | + |
| 305 | + /// Naive baseline for [#sumAlpDouble()]: the hand-written running sum over the ALP accessor, |
| 306 | + /// decoding every double per element. Returns the sum so JMH cannot eliminate the loop. |
| 307 | + /// |
| 308 | + /// @return the sum of all `price` values |
| 309 | + @Benchmark |
| 310 | + public double forLoopSumAlp() { |
| 311 | + LazyAlpDoubleArray array = price; |
| 312 | + long n = array.length(); |
| 313 | + double acc = 0; |
| 314 | + for (long i = 0; i < n; i++) { |
| 315 | + acc += array.getDouble(i); |
| 316 | + } |
| 317 | + return acc; |
| 318 | + } |
| 319 | + |
225 | 320 | private void write(Path path) throws IOException { |
226 | 321 | double[] priceData = new double[ROWS]; |
227 | 322 | long[] measureData = new long[ROWS]; |
|
0 commit comments