Skip to content

Instantly share code, notes, and snippets.

@ghik
Last active August 30, 2021 12:20
Show Gist options
  • Select an option

  • Save ghik/794588a00b6e0b58e8f0f36f8945246b to your computer and use it in GitHub Desktop.

Select an option

Save ghik/794588a00b6e0b58e8f0f36f8945246b to your computer and use it in GitHub Desktop.
Benchmarks for explicit list bounds checking vs relying on exceptions
import org.openjdk.jmh.annotations._
final class NoStackTraceIndexOutOfBoundsException extends IndexOutOfBoundsException {
override def fillInStackTrace(): Throwable = this
}
final class NoStackTraceArraySeq[+T](values: Array[T]) {
val size: Int = values.length
def apply(idx: Int): T =
if (idx < 0 || idx >= size) throw new NoStackTraceIndexOutOfBoundsException
else values(idx)
}
final class StackTraceArraySeq[+T](values: Array[T]) {
val size: Int = values.length
def apply(idx: Int): T =
if (idx < 0 || idx >= size) throw new IndexOutOfBoundsException
else values(idx)
}
@Warmup(iterations = 5)
@Measurement(iterations = 10)
@Fork(1)
@BenchmarkMode(Array(Mode.Throughput))
@State(Scope.Thread)
class BoundsChecking {
private val ints: Array[Int] = Array.iterate(429, 1000)(x => if (x % 2 == 0) x / 2 else 3 * x + 1)
private val nstSeq = new NoStackTraceArraySeq(ints)
private val stSeq = new StackTraceArraySeq(ints)
@Benchmark
// 2 index checks per iteration
def noStackTraceExceptionBasedLoop(): Int = {
var sum = 0
try {
var i = 0
while (true) {
sum += nstSeq(i)
i += 1
}
sum
} catch {
case _: NoStackTraceIndexOutOfBoundsException => sum
}
}
@Benchmark
// 2 index checks per iteration
def stackTraceExceptionBasedLoop(): Int = {
var sum = 0
try {
var i = 0
while (true) {
sum += stSeq(i)
i += 1
}
sum
} catch {
case _: IndexOutOfBoundsException => sum
}
}
@Benchmark
// 3 index checks per iteration
def indexBasedLoop(): Int = {
var sum = 0
var i = 0
val siz = nstSeq.size
while (i < siz) {
sum += nstSeq(i)
i += 1
}
sum
}
}
[info] running (fork) org.openjdk.jmh.Main com.avsystem.commons.loops.BoundsChecking
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.indexBasedLoop
[info] # Run progress: 0,00% complete, ETA 00:07:30
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 1701304,650 ops/s
[info] # Warmup Iteration 2: 1713617,513 ops/s
[info] # Warmup Iteration 3: 1724013,868 ops/s
[info] # Warmup Iteration 4: 1810721,283 ops/s
[info] # Warmup Iteration 5: 1764937,228 ops/s
[info] Iteration 1: 1367395,353 ops/s
[info] Iteration 2: 1787172,949 ops/s
[info] Iteration 3: 1767660,404 ops/s
[info] Iteration 4: 1787200,960 ops/s
[info] Iteration 5: 1699246,621 ops/s
[info] Iteration 6: 1626717,181 ops/s
[info] Iteration 7: 1769147,226 ops/s
[info] Iteration 8: 1820586,454 ops/s
[info] Iteration 9: 1790520,006 ops/s
[info] Iteration 10: 1836280,437 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.indexBasedLoop":
[info] 1725192,759 ´┐Ż(99.9%) 211131,269 ops/s [Average]
[info] (min, avg, max) = (1367395,353, 1725192,759, 1836280,437), stdev = 139650,262
[info] CI (99.9%): [1514061,491, 1936324,028] (assumes normal distribution)
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.noStackTraceExceptionBasedLoop
[info] # Run progress: 33,33% complete, ETA 00:05:01
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 1621672,850 ops/s
[info] # Warmup Iteration 2: 1769320,227 ops/s
[info] # Warmup Iteration 3: 1197841,636 ops/s
[info] # Warmup Iteration 4: 1210820,363 ops/s
[info] # Warmup Iteration 5: 1202093,680 ops/s
[info] Iteration 1: 1188436,030 ops/s
[info] Iteration 2: 1203497,454 ops/s
[info] Iteration 3: 1211719,128 ops/s
[info] Iteration 4: 1202993,093 ops/s
[info] Iteration 5: 1208418,817 ops/s
[info] Iteration 6: 1170186,175 ops/s
[info] Iteration 7: 1182133,808 ops/s
[info] Iteration 8: 1179468,264 ops/s
[info] Iteration 9: 1199190,802 ops/s
[info] Iteration 10: 1196345,748 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.noStackTraceExceptionBasedLoop":
[info] 1194238,932 ´┐Ż(99.9%) 20624,262 ops/s [Average]
[info] (min, avg, max) = (1170186,175, 1194238,932, 1211719,128), stdev = 13641,673
[info] CI (99.9%): [1173614,670, 1214863,194] (assumes normal distribution)
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.stackTraceExceptionBasedLoop
[info] # Run progress: 66,67% complete, ETA 00:02:30
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 517526,742 ops/s
[info] # Warmup Iteration 2: 583845,683 ops/s
[info] # Warmup Iteration 3: 499244,654 ops/s
[info] # Warmup Iteration 4: 566714,205 ops/s
[info] # Warmup Iteration 5: 576831,870 ops/s
[info] Iteration 1: 585009,309 ops/s
[info] Iteration 2: 580023,499 ops/s
[info] Iteration 3: 575513,965 ops/s
[info] Iteration 4: 579903,811 ops/s
[info] Iteration 5: 596120,530 ops/s
[info] Iteration 6: 585501,119 ops/s
[info] Iteration 7: 587867,456 ops/s
[info] Iteration 8: 567432,802 ops/s
[info] Iteration 9: 587330,980 ops/s
[info] Iteration 10: 562584,654 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.stackTraceExceptionBasedLoop":
[info] 580728,813 ´┐Ż(99.9%) 15176,572 ops/s [Average]
[info] (min, avg, max) = (562584,654, 580728,813, 596120,530), stdev = 10038,362
[info] CI (99.9%): [565552,241, 595905,384] (assumes normal distribution)
[info] # Run complete. Total time: 00:07:32
[info] REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
[info] why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
[info] experiments, perform baseline and negative tests that provide experimental control, make sure
[info] the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
[info] Do not assume the numbers tell you what you want them to tell.
[info] Benchmark Mode Cnt Score Error Units
[info] BoundsChecking.indexBasedLoop thrpt 10 1725192,759 ´┐Ż 211131,269 ops/s
[info] BoundsChecking.noStackTraceExceptionBasedLoop thrpt 10 1194238,932 ´┐Ż 20624,262 ops/s
[info] BoundsChecking.stackTraceExceptionBasedLoop thrpt 10 580728,813 ´┐Ż 15176,572 ops/s
[info] running (fork) org.openjdk.jmh.Main com.avsystem.commons.loops.BoundsChecking
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: <none>
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.indexBasedLoop
[info] # Run progress: 0,00% complete, ETA 00:07:30
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 288104,295 ops/s
[info] # Warmup Iteration 2: 309541,359 ops/s
[info] # Warmup Iteration 3: 268087,568 ops/s
[info] # Warmup Iteration 4: 269256,016 ops/s
[info] # Warmup Iteration 5: 271174,425 ops/s
[info] Iteration 1: 272770,756 ops/s
[info] Iteration 2: 273104,193 ops/s
[info] Iteration 3: 269865,816 ops/s
[info] Iteration 4: 268960,446 ops/s
[info] Iteration 5: 273145,363 ops/s
[info] Iteration 6: 267990,810 ops/s
[info] Iteration 7: 270096,150 ops/s
[info] Iteration 8: 267560,476 ops/s
[info] Iteration 9: 269752,656 ops/s
[info] Iteration 10: 270390,418 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.indexBasedLoop":
[info] 270363,708 ´┐Ż(99.9%) 3073,417 ops/s [Average]
[info] (min, avg, max) = (267560,476, 270363,708, 273145,363), stdev = 2032,875
[info] CI (99.9%): [267290,292, 273437,125] (assumes normal distribution)
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: <none>
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.noStackTraceExceptionBasedLoop
[info] # Run progress: 33,33% complete, ETA 00:05:01
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 270598,784 ops/s
[info] # Warmup Iteration 2: 269995,881 ops/s
[info] # Warmup Iteration 3: 338444,808 ops/s
[info] # Warmup Iteration 4: 339503,568 ops/s
[info] # Warmup Iteration 5: 230984,975 ops/s
[info] Iteration 1: 347996,899 ops/s
[info] Iteration 2: 344723,916 ops/s
[info] Iteration 3: 345448,205 ops/s
[info] Iteration 4: 341071,276 ops/s
[info] Iteration 5: 351253,879 ops/s
[info] Iteration 6: 342533,013 ops/s
[info] Iteration 7: 352052,757 ops/s
[info] Iteration 8: 348517,788 ops/s
[info] Iteration 9: 343823,141 ops/s
[info] Iteration 10: 340530,196 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.noStackTraceExceptionBasedLoop":
[info] 345795,107 ´┐Ż(99.9%) 6111,113 ops/s [Average]
[info] (min, avg, max) = (340530,196, 345795,107, 352052,757), stdev = 4042,123
[info] CI (99.9%): [339683,994, 351906,220] (assumes normal distribution)
[info] # JMH version: 1.32
[info] # VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
[info] # VM invoker: C:\Program Files\OpenJDK\openjdk-11.0.11_9\bin\java.exe
[info] # VM options: <none>
[info] # Blackhole mode: full + dont-inline hint
[info] # Warmup: 5 iterations, 10 s each
[info] # Measurement: 10 iterations, 10 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: com.avsystem.commons.loops.BoundsChecking.stackTraceExceptionBasedLoop
[info] # Run progress: 66,67% complete, ETA 00:02:30
[info] # Fork: 1 of 1
[info] # Warmup Iteration 1: 203835,296 ops/s
[info] # Warmup Iteration 2: 208534,115 ops/s
[info] # Warmup Iteration 3: 239465,367 ops/s
[info] # Warmup Iteration 4: 244448,633 ops/s
[info] # Warmup Iteration 5: 246615,238 ops/s
[info] Iteration 1: 246729,425 ops/s
[info] Iteration 2: 250248,150 ops/s
[info] Iteration 3: 242505,625 ops/s
[info] Iteration 4: 242776,790 ops/s
[info] Iteration 5: 235954,980 ops/s
[info] Iteration 6: 242249,390 ops/s
[info] Iteration 7: 242437,241 ops/s
[info] Iteration 8: 246017,314 ops/s
[info] Iteration 9: 243136,007 ops/s
[info] Iteration 10: 238091,496 ops/s
[info] Result "com.avsystem.commons.loops.BoundsChecking.stackTraceExceptionBasedLoop":
[info] 243014,642 ´┐Ż(99.9%) 6181,689 ops/s [Average]
[info] (min, avg, max) = (235954,980, 243014,642, 250248,150), stdev = 4088,804
[info] CI (99.9%): [236832,953, 249196,331] (assumes normal distribution)
[info] # Run complete. Total time: 00:07:32
[info] REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
[info] why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
[info] experiments, perform baseline and negative tests that provide experimental control, make sure
[info] the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
[info] Do not assume the numbers tell you what you want them to tell.
[info] Benchmark Mode Cnt Score Error Units
[info] BoundsChecking.indexBasedLoop thrpt 10 270363,708 ´┐Ż 3073,417 ops/s
[info] BoundsChecking.noStackTraceExceptionBasedLoop thrpt 10 345795,107 ´┐Ż 6111,113 ops/s
[info] BoundsChecking.stackTraceExceptionBasedLoop thrpt 10 243014,642 ´┐Ż 6181,689 ops/s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment