Skip to content

Performance regression in Scala 2.13 for creation of lists using mutable.ListBuffer #11627

@plokhotnyuk

Description

@plokhotnyuk

For small lists it can be slowdown in ~1.5x times with OpenJDK and in ~7x times with GraalVM.
Most parsers which use it to bind parsed data to List or Seq (because List is a default implementation of Seq) from text or binary messages are affected.

Code of the benchmark to reproduce:

import java.util.concurrent.TimeUnit
import org.openjdk.jmh.annotations._
import scala.collection.mutable.ListBuffer

@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1, jvmArgs = Array(
  "-server",
  "-Xms2g",
  "-Xmx2g",
  "-XX:NewSize=1g",
  "-XX:MaxNewSize=1g",
  "-XX:InitialCodeCacheSize=512m",
  "-XX:ReservedCodeCacheSize=512m",
  "-XX:+UseParallelGC",
  "-XX:-UseBiasedLocking",
  "-XX:+AlwaysPreTouch"))
@BenchmarkMode(Array(Mode.Throughput))
@OutputTimeUnit(TimeUnit.SECONDS)
class ListBufferBenchmark {
  @Param(Array("1", "10", "100"))
  var size: Int = 1000

  @Benchmark
  def intListCreation: List[Int] = {
    val squares = new ListBuffer[Int]()
    var i = 0
    val l = size
    while (i < l) {
      squares += i * i
      i += 1
    }
    squares.toList
  }
}

Command to run:

sbt -java-home /usr/lib/jvm/jdk-11 -no-colors ++2.13.0 'jmh:run ListBufferBenchmark'

Results for Scala 2.13.0 with OpenJDK 11.0.3:

[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                            (size)   Mode  Cnt          Score        Error  Units
[info] ListBufferBenchmark.intListCreation       1  thrpt    5  129974588.015 ± 249971.629  ops/s
[info] ListBufferBenchmark.intListCreation      10  thrpt    5   15160739.436 ±   6815.066  ops/s
[info] ListBufferBenchmark.intListCreation     100  thrpt    5    1415746.679 ±  12507.797  ops/s

Results for Scala 2.12.8 with OpenJDK 11.0.3:

[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                            (size)   Mode  Cnt          Score         Error  Units
[info] ListBufferBenchmark.intListCreation       1  thrpt    5  184201868.557 ± 1525301.419  ops/s
[info] ListBufferBenchmark.intListCreation      10  thrpt    5   21833324.557 ±  540564.835  ops/s
[info] ListBufferBenchmark.intListCreation     100  thrpt    5    1767339.444 ±   23828.567  ops/s

Results for Scala 2.13.0 with GraalVM CE 19.1:

[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                            (size)   Mode  Cnt         Score        Error  Units
[info] ListBufferBenchmark.intListCreation       1  thrpt    5  33947057.954 ± 509483.584  ops/s
[info] ListBufferBenchmark.intListCreation      10  thrpt    5   6072784.266 ±  22838.907  ops/s
[info] ListBufferBenchmark.intListCreation     100  thrpt    5    624114.322 ±   4138.885  ops/s

Results for Scala 2.12.8 with GraalVM CE 19.1:

[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                            (size)   Mode  Cnt          Score        Error  Units
[info] ListBufferBenchmark.intListCreation       1  thrpt    5  238624457.791 ± 859161.435  ops/s
[info] ListBufferBenchmark.intListCreation      10  thrpt    5   30777424.910 ± 427876.116  ops/s
[info] ListBufferBenchmark.intListCreation     100  thrpt    5    1989475.540 ±  21622.259  ops/s

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions