Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add benchmark for foldMapA #3136

Merged
merged 2 commits into from
Nov 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}