takafumi blog

日々の勉強メモ

scala: jmhでreifnedのパフォーマンスを(適当に)調べてみる

環境   Scala 2.13.8

ちょっと気になってrefinedのPositiveなどに比べて、requireで契約的に正数を縛る場合、どのくらいのパフォーマンス差があるか調べてみた。

コードはだいぶ適当だが以下

package bench

import cats.implicits._
import eu.timepit.refined._
import eu.timepit.refined.api._
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
import eu.timepit.refined.types.numeric._
import scala.util._

import org.openjdk.jmh.annotations._

class JMHSample {
  @throws
  def convertPositiveInt(i: Int): Int = {
    require(i >= 0)
    i
  }

  @Benchmark
  def measureAgreementPosInt(): Either[String, Int] = {
    try {
      Right[String, Int](convertPositiveInt(1))
    } catch {
      case t: Throwable => Left[String, Int](t.getMessage)
    }
  }

  @Benchmark
  def measureAgreementPosIntFPLike(): Either[String, Int] = {
    Try(convertPositiveInt(1)).toEither.leftMap(t => t.getMessage)
  }

  @Benchmark
  def measurePosInt(): Either[String, PosInt] = {
    RefType.applyRef[PosInt](1)
  }

  @Benchmark
  def measureIntRefinedPositive(): Either[String, Int Refined Positive] = {
    refineV[Positive](1)
  }
}

結果

sbt:jmh-example> Jmh / run -i 3 -wi 3 -f1 -t 1
...
[info] Benchmark                                Mode  Cnt          Score          Error  Units
[info] JMHSample.measureAgreementPosInt        thrpt    3  365097651.422 ± 19080986.848  ops/s
[info] JMHSample.measureAgreementPosIntFPLike  thrpt    3  344466648.190 ± 20924629.667  ops/s
[info] JMHSample.measureIntRefinedPositive     thrpt    3   73142259.692 ± 16294716.321  ops/s
[info] JMHSample.measurePosInt                 thrpt    3   78952274.799 ± 58359188.751  ops/s
[success] Total time: 241 s (04:01), completed 2022/10/16 14:03:36

おおむね1/3~1/5くらいrefinedの方がパフォーマンスは劣化する。 とはいえ普通にアプリケーション実装するときとかは、I/Oとかと比べれば微細なレベルだと思うので、有用な時は使えばよいと思う。