Skip to content

Commit

Permalink
Merge pull request #3136 from typelevel/topic/foldMapA-bench
Browse files Browse the repository at this point in the history
Add benchmark for foldMapA
  • Loading branch information
travisbrown authored Nov 12, 2019
2 parents 624b38f + 45c4837 commit f1ead7d
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 41 deletions.
13 changes: 0 additions & 13 deletions bench/src/main/scala-2.12/cats/bench/ChainBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,26 @@ class ChainBench {
private val largeVector = (0 to 1000000).toVector
private val largeList = (0 to 1000000).toList
private val largeOldChain = (0 to 1000).foldLeft(OldChain.empty[Int])((acc, _) => acc ++ OldChain(0 to 1000))


@Benchmark def mapSmallChain: Chain[Int] = smallChain.map(_ + 1)
@Benchmark def mapSmallCatenable: Catenable[Int] = smallCatenable.map(_ + 1)
@Benchmark def mapSmallVector: Vector[Int] = smallVector.map(_ + 1)
@Benchmark def mapSmallList: List[Int] = smallList.map(_ + 1)
@Benchmark def mapSmallOldChain: OldChain[Int] = smallOldChain.map(_ + 1)


@Benchmark def mapLargeChain: Chain[Int] = largeChain.map(_ + 1)
@Benchmark def mapLargeCatenable: Catenable[Int] = largeCatenable.map(_ + 1)
@Benchmark def mapLargeVector: Vector[Int] = largeVector.map(_ + 1)
@Benchmark def mapLargeList: List[Int] = largeList.map(_ + 1)
@Benchmark def mapLargeOldChain: OldChain[Int] = largeOldChain.map(_ + 1)



@Benchmark def foldLeftSmallChain: Int = smallChain.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallCatenable: Int = smallCatenable.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallVector: Int = smallVector.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallList: Int = smallList.foldLeft(0)(_ + _)
@Benchmark def foldLeftSmallOldChain: Int = smallOldChain.foldLeft(0)(_ + _)


@Benchmark def foldLeftLargeChain: Int = largeChain.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeCatenable: Int = largeCatenable.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeVector: Int = largeVector.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeList: Int = largeList.foldLeft(0)(_ + _)
@Benchmark def foldLeftLargeOldChain: Int = largeOldChain.foldLeft(0)(_ + _)




@Benchmark def consSmallChain: Chain[Int] = 0 +: smallChain
@Benchmark def consSmallCatenable: Catenable[Int] = 0 +: smallCatenable
@Benchmark def consSmallVector: Vector[Int] = 0 +: smallVector
Expand Down
16 changes: 9 additions & 7 deletions bench/src/main/scala-2.12/cats/bench/MapMonoidBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import scalaz.std.anyVal._
import scalaz.std.list._
import scalaz.std.map._

import org.openjdk.jmh.annotations.{ Benchmark, Scope, State }
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Benchmark)
class MapMonoidBench {
Expand Down Expand Up @@ -36,19 +36,21 @@ class MapMonoidBench {

@Benchmark def combineDirect: Map[String, Int] =
maps.foldLeft(Map.empty[String, Int]) {
case (acc, m) => m.foldLeft(acc) {
case (m, (k, v)) => m.updated(k, v + m.getOrElse(k, 0))
}
case (acc, m) =>
m.foldLeft(acc) {
case (m, (k, v)) => m.updated(k, v + m.getOrElse(k, 0))
}
}

@Benchmark def combineGeneric: Map[String, Int] =
combineMapsGeneric[String, Int](maps, 0, _ + _)

def combineMapsGeneric[K, V](maps: List[Map[K, V]], z: V, f: (V, V) => V): Map[K, V] =
maps.foldLeft(Map.empty[K, V]) {
case (acc, m) => m.foldLeft(acc) {
case (m, (k, v)) => m.updated(k, f(v, m.getOrElse(k, z)))
}
case (acc, m) =>
m.foldLeft(acc) {
case (m, (k, v)) => m.updated(k, f(v, m.getOrElse(k, z)))
}
}

@Benchmark def foldMapCats: Map[String, Int] =
Expand Down
42 changes: 42 additions & 0 deletions bench/src/main/scala/cats/bench/FoldMapABench.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cats.bench

import cats.Applicative
import cats.instances.either._
import cats.instances.int._
import cats.instances.vector._
import cats.kernel.Monoid
import cats.syntax.foldable._
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Benchmark)
class FoldMapABench {

val xs: Vector[Int] = (1 to 10000).toVector
val f: Int => Either[Int, Int] = x => if (x >= 5000) Left(x) else Right(x)
val g: Int => Either[Int, Int] = x => if (x >= 5000) Right(0) else Right(x)
val M: Monoid[Either[Int, Int]] = Applicative.monoid[Either[Int, ?], Int]

@Benchmark
def foldMapMShortCircuit: Either[Int, Int] = xs.foldMapM(f)

@Benchmark
def foldMapAShortCircuit: Either[Int, Int] = xs.foldMapA(f)

// Note that this doesn't actually short-circuit; it will keep combining
// even after it reaches the `Left` value.
@Benchmark
def foldLeftShortCircuit: Either[Int, Int] = xs.foldLeft(M.empty) {
case (acc, x) => M.combine(acc, f(x))
}

@Benchmark
def foldMapM: Either[Int, Int] = xs.foldMapM(g)

@Benchmark
def foldMapA: Either[Int, Int] = xs.foldMapA(g)

@Benchmark
def foldLeft: Either[Int, Int] = xs.foldLeft(M.empty) {
case (acc, x) => M.combine(acc, g(x))
}
}
3 changes: 1 addition & 2 deletions bench/src/main/scala/cats/bench/StateTBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ class StateTBench {
var count: Int = _

@Benchmark
def single(): Long = {
def single(): Long =
randLong.run(32311).value._2
}

@Benchmark
def repeatedLeftBinds(): Int = {
Expand Down
42 changes: 23 additions & 19 deletions bench/src/main/scala/cats/bench/TrampolineBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,31 @@ class TrampolineBench {
def eval(): Int = evalFib(N).value

def evalFib(n: Int): Eval[Int] =
if (n < 2) Eval.now(n) else for {
x <- Eval.defer(evalFib(n - 1))
y <- Eval.defer(evalFib(n - 2))
} yield x + y


if (n < 2) Eval.now(n)
else
for {
x <- Eval.defer(evalFib(n - 1))
y <- Eval.defer(evalFib(n - 2))
} yield x + y
@Benchmark
def trampoline(): Int = trampolineFib(N).run

def trampolineFib(n: Int): Trampoline[Int] =
if (n < 2) Trampoline.done(n) else for {
x <- Trampoline.defer(trampolineFib(n - 1))
y <- Trampoline.defer(trampolineFib(n - 2))
} yield x + y

@Benchmark
def stdlib(): Int = stdlibFib(N).result

def stdlibFib(n: Int): TailCalls.TailRec[Int] =
if (n < 2) TailCalls.done(n) else for {
x <- TailCalls.tailcall(stdlibFib(n - 1))
y <- TailCalls.tailcall(stdlibFib(n - 2))
} yield x + y
if (n < 2) Trampoline.done(n)
else
for {
x <- Trampoline.defer(trampolineFib(n - 1))
y <- Trampoline.defer(trampolineFib(n - 2))
} yield x + y

@Benchmark
def stdlib(): Int = stdlibFib(N).result

def stdlibFib(n: Int): TailCalls.TailRec[Int] =
if (n < 2) TailCalls.done(n)
else
for {
x <- TailCalls.tailcall(stdlibFib(n - 1))
y <- TailCalls.tailcall(stdlibFib(n - 2))
} yield x + y
}

0 comments on commit f1ead7d

Please sign in to comment.