Last active
August 30, 2021 12:20
-
-
Save ghik/794588a00b6e0b58e8f0f36f8945246b to your computer and use it in GitHub Desktop.
Benchmarks for explicit list bounds checking vs relying on exceptions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [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