Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit beb293a

Browse files
committed
Add a JMH benchmark for ArrayDeque
1 parent de8bb67 commit beb293a

File tree

1 file changed

+310
-10
lines changed

1 file changed

+310
-10
lines changed

benchmarks/time/src/main/scala/strawman/collection/mutable/ArrayDequeBenchmark.scala

Lines changed: 310 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package strawman.collection.mutable
22

3-
import scala._
4-
import scala.collection.mutable
5-
import scala.Predef._
6-
73
import java.lang.System.nanoTime
4+
import scala.Predef.{ assert, println, intWrapper }
5+
import strawman.collection.arrayToArrayOps
86

9-
object ArrayDequeBenchmark extends App {
10-
val candidates = Seq(
7+
// Because the JMH benchmark is not usable for prepend and append
8+
object ArrayDequeBenchmarkAdhoc extends App {
9+
val candidates = Seq[IndexedOptimizedBuffer[Int]](
1110
strawman.collection.mutable.ArrayDeque.empty[Int],
12-
scala.collection.mutable.ArrayBuffer.empty[Int]
11+
strawman.collection.mutable.ArrayBuffer.empty[Int]
1312
)
1413

15-
def benchmark[U](name: String, f: mutable.Buffer[Int] => U) = {
16-
def profile(buffer: mutable.Buffer[Int]) = {
14+
def benchmark[U](name: String, f: Buffer[Int] => U) = {
15+
def profile(buffer: Buffer[Int]) = {
1716
val t1 = nanoTime()
1817
f(buffer)
1918
(nanoTime() - t1)/1e6
@@ -34,7 +33,7 @@ object ArrayDequeBenchmark extends App {
3433
benchmark("Drop some items from a tail index", b => b.remove(b.length - 10000, 10000))
3534
benchmark("Append lots of items one by one", b => range10m.foreach(b.+=))
3635
benchmark("Prepend few items one by one", b => (1 to 1000).foreach(_ +=: b))
37-
benchmark("Prepend lots of items at once", range10m ++=: _)
36+
// benchmark("Prepend lots of items at once", _.prependAll(range10m))
3837
benchmark("Insert items near head", _.insertAll(1000, range10m))
3938
benchmark("Reversal", _.reverse)
4039
benchmark("Insert items near tail", b => b.insertAll(b.size - 1000, range10m))
@@ -43,3 +42,304 @@ object ArrayDequeBenchmark extends App {
4342
benchmark("toArray", _.toArray)
4443
benchmark("Clear lots of items", _.clear())
4544
}
45+
46+
import java.util.concurrent.TimeUnit
47+
48+
import org.openjdk.jmh.annotations._
49+
import org.openjdk.jmh.infra.Blackhole
50+
51+
import scala.{Any, AnyRef, Int, Long, Unit, math}
52+
import scala.Predef.{intWrapper, $conforms}
53+
54+
@BenchmarkMode(scala.Array(Mode.AverageTime))
55+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
56+
@Fork(1)
57+
@Warmup(iterations = 8)
58+
@Measurement(iterations = 8)
59+
@State(Scope.Benchmark)
60+
class ArrayDequeBenchmark {
61+
@Param(scala.Array("0", "1", "2", "3", "4", "7", "8", "15", "16", "17", "39", "282", "4096", "131070", "7312102"))
62+
var size: Int = _
63+
64+
var xs: ArrayDeque[Long] = _
65+
var zs: ArrayDeque[Long] = _
66+
var zipped: ArrayDeque[(Long, Long)] = _
67+
var randomIndices: scala.Array[Int] = _
68+
def fresh(n: Int) = ArrayDeque((1 to n).map(_.toLong): _*)
69+
70+
@Setup(Level.Trial)
71+
def initTrial(): Unit = {
72+
xs = fresh(size)
73+
zs = fresh((size / 1000) max 2).map(-_)
74+
zipped = xs.map(x => (x, x))
75+
if (size > 0) {
76+
randomIndices = scala.Array.fill(1000)(scala.util.Random.nextInt(size))
77+
}
78+
}
79+
80+
@Benchmark
81+
def create(bh: Blackhole): Unit = bh.consume(fresh(size))
82+
83+
@Benchmark
84+
@OperationsPerInvocation(1000)
85+
def expand_prepend(bh: Blackhole): Unit = {
86+
val ys = xs
87+
var i = 0L
88+
while (i < 1000) {
89+
ys.prepend(i)
90+
i += 1
91+
}
92+
bh.consume(ys)
93+
}
94+
95+
@Benchmark
96+
@OperationsPerInvocation(1000)
97+
def expand_prependTail(bh: Blackhole): Unit = {
98+
var ys = xs
99+
var i = 0L
100+
while (i < 1000) {
101+
ys.insert(0, i)
102+
i += 1
103+
ys = ys.tail
104+
}
105+
bh.consume(ys)
106+
}
107+
108+
@Benchmark
109+
@OperationsPerInvocation(1000)
110+
def expand_append(bh: Blackhole): Unit = {
111+
val ys = xs
112+
var i = 0L
113+
while (i < 1000) {
114+
ys.addOne(i)
115+
i += 1
116+
}
117+
bh.consume(ys)
118+
}
119+
120+
@Benchmark
121+
@OperationsPerInvocation(1000)
122+
def expand_appendInit(bh: Blackhole): Unit = {
123+
var ys = xs
124+
var i = 0L
125+
while (i < 1000) {
126+
ys.addOne(i)
127+
i += 1
128+
ys = ys.init
129+
}
130+
bh.consume(ys)
131+
}
132+
133+
@Benchmark
134+
@OperationsPerInvocation(1000)
135+
def expand_prependAppend(bh: Blackhole): Unit = {
136+
val ys = xs
137+
var i = 0L
138+
while (i < 1000) {
139+
if ((i & 1) == 1) ys.addOne(i)
140+
else ys.insert(0, i)
141+
i += 1
142+
}
143+
bh.consume(ys)
144+
}
145+
146+
@Benchmark
147+
@OperationsPerInvocation(1000)
148+
def expand_prependAll(bh: Blackhole): Unit = {
149+
val ys = xs
150+
var i = 0L
151+
while (i < 1000) {
152+
ys.insertAll(0, zs)
153+
i += 1
154+
}
155+
bh.consume(ys)
156+
}
157+
158+
@Benchmark
159+
@OperationsPerInvocation(1000)
160+
def expand_appendAll(bh: Blackhole): Unit = {
161+
val ys = xs
162+
var i = 0L
163+
while (i < 1000) {
164+
ys.addAll(zs)
165+
i += 1
166+
}
167+
bh.consume(ys)
168+
}
169+
170+
@Benchmark
171+
@OperationsPerInvocation(1000)
172+
def expand_prependAllAppendAll(bh: Blackhole): Unit = {
173+
val ys = xs
174+
var i = 0L
175+
while (i < 1000) {
176+
if ((i & 1) == 1) ys.addAll(zs)
177+
else ys.insertAll(0, zs)
178+
i += 1
179+
}
180+
bh.consume(ys)
181+
}
182+
183+
@Benchmark
184+
def expand_padTo(bh: Blackhole): Unit = bh.consume(xs.padTo(size * 2, 42))
185+
186+
@Benchmark
187+
def traverse_foreach(bh: Blackhole): Unit = xs.foreach(x => bh.consume(x))
188+
189+
@Benchmark
190+
def traverse_headTail(bh: Blackhole): Unit = {
191+
var ys = xs
192+
while (ys.nonEmpty) {
193+
bh.consume(ys.head)
194+
ys = ys.tail
195+
}
196+
}
197+
198+
@Benchmark
199+
def traverse_initLast(bh: Blackhole): Unit = {
200+
var ys = xs
201+
while (ys.nonEmpty) {
202+
bh.consume(ys.last)
203+
ys = ys.init
204+
}
205+
}
206+
207+
@Benchmark
208+
def traverse_iterator(bh: Blackhole): Unit = {
209+
val it = xs.iterator()
210+
while (it.hasNext) {
211+
bh.consume(it.next())
212+
}
213+
}
214+
215+
@Benchmark
216+
def traverse_foldLeft(bh: Blackhole): Unit = bh.consume(xs.foldLeft(0) {
217+
case (acc, n) =>
218+
bh.consume(n)
219+
acc + 1
220+
})
221+
222+
@Benchmark
223+
def traverse_foldRight(bh: Blackhole): Unit = bh.consume(xs.foldRight(0) {
224+
case (n, acc) =>
225+
bh.consume(n)
226+
acc - 1
227+
})
228+
229+
@Benchmark
230+
@OperationsPerInvocation(1000)
231+
def access_last(bh: Blackhole): Unit = {
232+
var i = 0
233+
while (i < 1000) {
234+
bh.consume(xs(size - 1))
235+
i += 1
236+
}
237+
}
238+
239+
@Benchmark
240+
@OperationsPerInvocation(1000)
241+
def access_random(bh: Blackhole): Unit = {
242+
var i = 0
243+
while (i < 1000) {
244+
bh.consume(xs(randomIndices(i)))
245+
i += 1
246+
}
247+
}
248+
249+
@Benchmark
250+
def access_tail(bh: Blackhole): Unit = bh.consume(xs.tail)
251+
252+
@Benchmark
253+
def access_init(bh: Blackhole): Unit = bh.consume(xs.init)
254+
255+
@Benchmark
256+
@OperationsPerInvocation(100)
257+
def access_slice(bh: Blackhole): Unit = {
258+
var i = 0
259+
while (i < 100) {
260+
bh.consume(xs.slice(size - size / (i + 1), size))
261+
i += 1
262+
}
263+
}
264+
265+
@Benchmark
266+
@OperationsPerInvocation(1000)
267+
def transform_updateLast(bh: Blackhole): Unit = {
268+
var i = 0
269+
while (i < 1000) {
270+
bh.consume(xs.update(size - 1, i))
271+
i += 1
272+
}
273+
}
274+
275+
@Benchmark
276+
@OperationsPerInvocation(1000)
277+
def transform_updateRandom(bh: Blackhole): Unit = {
278+
var i = 0
279+
while (i < 1000) {
280+
bh.consume(xs.update(randomIndices(i), i))
281+
i += 1
282+
}
283+
}
284+
285+
@Benchmark
286+
@OperationsPerInvocation(100)
287+
def transform_patch(bh: Blackhole): Unit = {
288+
var i = 0
289+
while (i < 100) {
290+
val from = randomIndices(i)
291+
val replaced = randomIndices(if (i > 0) i - 1 else math.min(i + 1, size - 1))
292+
val length = randomIndices(if (i > 1) i - 2 else math.min(i + 2, size - 1))
293+
bh.consume(xs.patchInPlace(from, xs.take(length), replaced))
294+
i += 1
295+
}
296+
}
297+
298+
@Benchmark
299+
def transform_distinct(bh: Blackhole): Unit = bh.consume(xs.distinct)
300+
301+
@Benchmark
302+
def transform_distinctBy(bh: Blackhole): Unit = bh.consume(xs.distinctBy(_ % 2))
303+
304+
@Benchmark
305+
def transform_map(bh: Blackhole): Unit = bh.consume(xs.map(x => x + 1))
306+
307+
@Benchmark
308+
@OperationsPerInvocation(100)
309+
def transform_span(bh: Blackhole): Unit = {
310+
var i = 0
311+
while (i < 100) {
312+
val (xs1, xs2) = xs.span(x => x < randomIndices(i))
313+
bh.consume(xs1)
314+
bh.consume(xs2)
315+
i += 1
316+
}
317+
}
318+
319+
@Benchmark
320+
def transform_zip(bh: Blackhole): Unit = bh.consume(xs.zip(xs))
321+
322+
@Benchmark
323+
def transform_zipMapTupled(bh: Blackhole): Unit = {
324+
val f = (a: Long, b: Long) => (a, b)
325+
bh.consume(xs.zip(xs).map(f.tupled))
326+
}
327+
328+
@Benchmark
329+
def transform_zipWithIndex(bh: Blackhole): Unit = bh.consume(xs.zipWithIndex)
330+
331+
@Benchmark
332+
def transform_lazyZip(bh: Blackhole): Unit = bh.consume(xs.lazyZip(xs).map((_, _)))
333+
334+
@Benchmark
335+
def transform_unzip(bh: Blackhole): Unit = bh.consume(zipped.unzip)
336+
337+
@Benchmark
338+
def transform_reverse(bh: Blackhole): Unit = bh.consume(xs.reverse)
339+
340+
@Benchmark
341+
def transform_groupBy(bh: Blackhole): Unit = {
342+
val result = xs.groupBy(_ % 5)
343+
bh.consume(result)
344+
}
345+
}

0 commit comments

Comments
 (0)