cats-effect
cats-effect copied to clipboard
Draft implementation of `IORuntimeMetrics`
There are a few notable notes regarding this PR:
- The existing implementation of
CpuStarvationMBean somewhat breaks the consistency. All previous MBeans were undercats.effect.unsafe.metricspackage, whileCpuStarvationis available undercats.effect.metrics. I didn't update the MBean name yet. - Platform-specific metrics can be defined in the
IORuntimeMetricsPlatform. For example, JVMIORuntimeMetricsofferscomputeandcpuStarvationmetrics. While JS and Native have onlycpuStarvation.
Personally, the whole implementation feels clunky, hopefully we can find the right direction together.
This PR will not pass MiMa checks. Once we agree on a direction, I will address the bin compat issue.
And a small demo:
Demo
import cats.effect.{IO, IOApp}
import cats.effect.std.Random
import cats.effect.unsafe.IORuntimeMetrics
import cats.syntax.foldable._
import scala.concurrent.duration._
object Test extends IOApp.Simple {
def run: IO[Unit] = {
IO.delay(print(runtime.metrics)).flatMap(IO.println).delayBy(500.millis).foreverM.background.surround {
Random.scalaUtilRandom[IO].flatMap { random =>
val a = random.betweenInt(10, 3000).flatMap { int =>
if (int % 2 == 0) IO.blocking(Thread.sleep(int)) else IO.delay(Thread.sleep(int))
}.start.replicateA(100)
a.flatMap(_.traverse_(_.join))
} >> IO.never
}
}
def print(metrics: IORuntimeMetrics): String = {
s"""
|Compute:
|workerThreadCount: ${metrics.compute.map(_.workerThreadCount())}
|activeThreadCount: ${metrics.compute.map(_.activeThreadCount())}
|searchingThreadCount: ${metrics.compute.map(_.searchingThreadCount())}
|blockedWorkerThreadCount: ${metrics.compute.map(_.blockedWorkerThreadCount())}
|localQueueFiberCount: ${metrics.compute.map(_.localQueueFiberCount())}
|suspendedFiberCount: ${metrics.compute.map(_.suspendedFiberCount())}
|
|CPU Starvation:
|starvationCount: ${metrics.cpuStarvation.starvationCount()}
|maxClockDriftMs: ${metrics.cpuStarvation.maxClockDriftMs()}
|currentClockDriftMs: ${metrics.cpuStarvation.currentClockDriftMs()}
|""".stripMargin
}
}
Output:
Compute:
workerThreadCount: Some(8)
activeThreadCount: Some(8)
searchingThreadCount: Some(0)
blockedWorkerThreadCount: Some(13)
localQueueFiberCount: Some(0)
suspendedFiberCount: Some(2)
CPU Starvation:
starvationCount: 0
maxClockDriftMs: 0
currentClockDriftMs: 0
....
Compute:
workerThreadCount: Some(8)
activeThreadCount: Some(1)
searchingThreadCount: Some(0)
blockedWorkerThreadCount: Some(13)
localQueueFiberCount: Some(0)
suspendedFiberCount: Some(2)
CPU Starvation:
starvationCount: 0
maxClockDriftMs: 11
currentClockDriftMs: 3
Mima is sad:
[error] cats-effect: Failed binary compatibility check against org.typelevel:cats-effect_3:3.4.2 (e:info.apiURL=https://typelevel.org/cats-effect/api/3.x/, e:info.versionScheme=early-semver)! Found 7 potential problems (filtered 2)
[error] * class cats.effect.metrics.CpuStarvation does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.CpuStarvation")
[error] * object cats.effect.metrics.CpuStarvation does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.CpuStarvation$")
[error] * interface cats.effect.metrics.CpuStarvationMBean does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.CpuStarvationMBean")
[error] * interface cats.effect.metrics.CpuStarvationMetrics does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.CpuStarvationMetrics")
[error] * class cats.effect.metrics.JvmCpuStarvationMetrics does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.JvmCpuStarvationMetrics")
[error] * object cats.effect.metrics.JvmCpuStarvationMetrics does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.JvmCpuStarvationMetrics$")
[error] * class cats.effect.metrics.JvmCpuStarvationMetrics#NoOpCpuStarvationMetrics does not have a correspondent in current version
[error] filter with: ProblemFilters.exclude[MissingClassProblem]("cats.effect.metrics.JvmCpuStarvationMetrics$NoOpCpuStarvationMetrics")
Since these classes were private to metrics package, I assume it's safe to add an exclusion.
With https://github.com/typelevel/cats-effect/pull/3526 the linking issue in ScalaJS is solved.