Skip to content

Instantly share code, notes, and snippets.

@wuservices
Last active May 16, 2016 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wuservices/4568ab3959e5234a9b10e1b1e2cbd0ab to your computer and use it in GitHub Desktop.
Save wuservices/4568ab3959e5234a9b10e1b1e2cbd0ab to your computer and use it in GitHub Desktop.
Informal test to see how much overhead Scalacache introduces on top of Caffeine.
object TimeScalacacheGetCaffeine {
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.blemale.scaffeine.{Cache, Scaffeine}
import scalacache._
import caffeine._
import memoization._
val underlyingCache = Caffeine.newBuilder().build[String, Object]()
implicit val scalaCache = ScalaCache(CaffeineCache(underlyingCache))
val scaffeineCache: Cache[Long, Option[String]] = Scaffeine().build[Long, Option[String]]()
// Test data
val testItem: Option[String] = Option("Some item")
val testItemKey = 5000
def itemUncached(id: Long): Option[String] = {
testItem
}
def itemCachedNoMemoize(id: Long): Future[Option[String]] = {
get[String, NoSerialization](id)
}
def itemCachedMemoize(id: Long): Future[Option[String]] = memoize {
Future {
itemUncached(id)
}
}
def time[T](message: String, startTime: Long = System.nanoTime)(block: => T) = {
val result = block
println(s"$message in ${elapsedTimeMs(startTime)} ms")
result
}
def elapsedTimeMs(startNanoTime: Long) = ((System.nanoTime - startNanoTime) / 1e5).round / 10.toDouble
def main(args: Array[String]): Unit = {
val numIterations = 1000000
for (i <- 1 to 3) {
println(s"Run #$i ($numIterations iterations per run)")
time("Uncached / return directly") {
for(_ <- 1 to numIterations)(itemUncached(testItemKey))
}
// Populate cache without memoize using scalacache
put(testItemKey)(itemUncached(testItemKey))
time("scalacache get no memoize") {
for(_ <- 1 to numIterations)(Await.result(itemCachedNoMemoize(testItemKey), Duration.Inf))
}
// Populate cache through memoize
itemCachedMemoize(testItemKey)
time("scalacache get with memoize") {
for(_ <- 1 to numIterations)(Await.result(itemCachedMemoize(testItemKey), Duration.Inf))
}
time("get from Caffeine directly") {
for(_ <- 1 to numIterations)(underlyingCache.getIfPresent(testItemKey))
}
time("get from underlying ConcurrentHashMap") {
for(_ <- 1 to numIterations)(underlyingCache.asMap.get(testItemKey))
}
// Populate scaffeine cache
scaffeineCache.put(testItemKey, itemUncached(testItemKey))
time("get using scaffeine") {
for(_ <- 1 to numIterations)(scaffeineCache.getIfPresent(testItemKey))
}
}
}
}
@wuservices
Copy link
Author

I got something like this

Run #3 (1000000 iterations per run)
Uncached / return directly in 5.9 ms
scalacache get no memoize in 369.4 ms
scalacache get with memoize in 15857.4 ms
get from Caffeine directly in 9.9 ms
get from underlying ConcurrentHashMap in 11.0 ms
get using scaffeine in 14.6 ms

It seems like scalacache without memoize is 30x+ times slower than Caffeine or ConcurrentHashMap. Once we add memoize, it seems 1500x+ slower. For comparison, I also tried using scaffeine which only seems to add ~50% overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment