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

Draft implementation of IORuntimeMetrics #3317

Open
wants to merge 3 commits into
base: series/3.x
Choose a base branch
from

Conversation

iRevive
Copy link
Contributor

@iRevive iRevive commented Dec 16, 2022

There are a few notable notes regarding this PR:

  • The existing implementation of CpuStarvation MBean somewhat breaks the consistency. All previous MBeans were under cats.effect.unsafe.metrics package, while CpuStarvation is available under cats.effect.metrics. I didn't update the MBean name yet.
  • Platform-specific metrics can be defined in the IORuntimeMetricsPlatform. For example, JVM IORuntimeMetrics offers compute and cpuStarvation metrics. While JS and Native have only cpuStarvation.

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.

@iRevive iRevive changed the title d of IORuntimeMetrics Draft implementation of IORuntimeMetrics Dec 16, 2022
@iRevive iRevive force-pushed the runtime-metrics branch 2 times, most recently from c10bee1 to 29ebdfa Compare December 16, 2022 14:22
@iRevive
Copy link
Contributor Author

iRevive commented Dec 16, 2022

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

@djspiewak djspiewak added this to the v3.5.0 milestone Jan 16, 2023
@iRevive
Copy link
Contributor Author

iRevive commented Jan 31, 2023

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.

@iRevive
Copy link
Contributor Author

iRevive commented Apr 11, 2023

With #3526 the linking issue in ScalaJS is solved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants