Skip to content

2.12 performance regression from ArrayOps allocations on vectors/seqs #11304

@twenovales

Description

@twenovales

tl;dr: allocation of ArrayOps (.ofInt, et al.) for some common operations like .count, .isEmpty, etc. result in performance regressions in Scala 2.12 vs. 2.11. This seems to affect performance of Vectors (and, by proxy, the default Seq).

https://github.com/twenovales/scala-collections-benchmark is a test case for this.

2.12.8:

[info] Benchmark                                                                     Mode  Cnt      Score      Error   Units
[info] CollectionsBenchmark.existsEmptinessAfter                                    thrpt   25  94329.046 ± 1874.541   ops/s
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.alloc.rate                     thrpt   25   1379.420 ±   27.431  MB/sec
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.alloc.rate.norm                thrpt   25  16104.000 ±    0.001    B/op
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Eden_Space            thrpt   25   1379.108 ±   27.570  MB/sec
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Eden_Space.norm       thrpt   25  16100.461 ±   54.457    B/op
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Survivor_Space        thrpt   25      0.044 ±    0.009  MB/sec
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Survivor_Space.norm   thrpt   25      0.517 ±    0.099    B/op
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.count                          thrpt   25   3179.000             counts
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.time                           thrpt   25   2173.000                 ms
[info] CollectionsBenchmark.existsEmptinessBefore                                   thrpt   25  50941.865 ± 1343.292   ops/s
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.alloc.rate                    thrpt   25    513.863 ±   17.343  MB/sec
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.alloc.rate.norm               thrpt   25  11105.601 ±   98.347    B/op
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Eden_Space           thrpt   25    514.373 ±   17.452  MB/sec
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Eden_Space.norm      thrpt   25  11116.552 ±  101.305    B/op
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Survivor_Space       thrpt   25      0.035 ±    0.007  MB/sec
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Survivor_Space.norm  thrpt   25      0.764 ±    0.160    B/op
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.count                         thrpt   25   3137.000             counts
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.time                          thrpt   25   2104.000                 ms

2.11.11

[info] Benchmark                                                                 Mode  Cnt       Score      Error   Units
[info] CollectionsBenchmark.existsEmptinessAfter                                thrpt   25  181176.834 ± 4285.124   ops/s
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.alloc.rate                 thrpt   25      15.793 ±    0.373  MB/sec
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.alloc.rate.norm            thrpt   25      96.000 ±    0.001    B/op
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Eden_Space        thrpt   25      16.364 ±   25.165  MB/sec
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.churn.PS_Eden_Space.norm   thrpt   25      99.492 ±  152.775    B/op
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.count                      thrpt   25       5.000             counts
[info] CollectionsBenchmark.existsEmptinessAfter:·gc.time                       thrpt   25       4.000                 ms
[info] CollectionsBenchmark.existsEmptinessBefore                               thrpt   25  180176.343 ± 6345.755   ops/s
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.alloc.rate                thrpt   25      15.706 ±    0.552  MB/sec
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.alloc.rate.norm           thrpt   25      96.000 ±    0.001    B/op
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Eden_Space       thrpt   25      14.658 ±   30.346  MB/sec
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.churn.PS_Eden_Space.norm  thrpt   25      90.158 ±  186.701    B/op
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.count                     thrpt   25       3.000             counts
[info] CollectionsBenchmark.existsEmptinessBefore:·gc.time                      thrpt   25       2.000                 ms

Note the difference in gc.alloc.rate.norm. A heap dump indicated that these were instances of ArrayOps.ofInt, but I believe this will apply to any instance.

(There are some additional commented-out benchmarks in the example, which, from some earlier testing, all showed regressions. These benchmarks show no performance regression from 2.11 to 2.12 when written with types like List.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions