All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.util.ResourceTracker.scala Maven / Gradle / Ivy

package com.twitter.util

import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.LongAdder

private[twitter] object ResourceTracker {
  private[this] final val threadMxBean = java.lang.management.ManagementFactory.getThreadMXBean()

  /**
   * An indicator if the running JDK supports querying thread statistics.
   */
  final val threadCpuTimeSupported = threadMxBean.isCurrentThreadCpuTimeSupported

  /**
   * Retreive the current thread's cpu time only if [[threadCpuTimeSupported]] is true.
   * Otherwise, -1 is returned. Results may vary depending on the JDK's management implementation
   */
  final def currentThreadCpuTime: Long = {
    if (threadCpuTimeSupported) threadMxBean.getCurrentThreadCpuTime
    else -1
  }

  /**
   * Wrap the invocation of `f` with low-level resource usage that's pushed to the `tracker`.
   */
  private[util] def wrapAndMeasureUsage[A, B](
    f: A => B,
    tracker: ResourceTracker
  ): A => B = { (result) =>
    {
      tracker.incContinuations()
      val cpuStart = threadMxBean.getCurrentThreadCpuTime
      try f(result)
      finally {
        val cpuTime = threadMxBean.getCurrentThreadCpuTime - cpuStart
        tracker.addCpuTime(cpuTime)
      }
    }
  }

  /**
   * Wrap the invocation of `f` with low-level resource usage that's pushed to the `tracker`.
   */
  private[util] def wrapAndMeasureUsage[T](
    f: => T,
    tracker: ResourceTracker
  ): () => T = { () =>
    {
      tracker.incContinuations()
      val cpuStart = threadMxBean.getCurrentThreadCpuTime
      try f
      finally {
        val cpuTime = threadMxBean.getCurrentThreadCpuTime - cpuStart
        tracker.addCpuTime(cpuTime)
      }
    }
  }

  // exposed for testing
  private[util] def let[T](tracker: ResourceTracker)(f: => T): T = {
    val oldCtx = Local.save()
    val newCtx = oldCtx.setResourceTracker(tracker)
    Local.restore(newCtx)
    try f
    finally Local.restore(oldCtx)
  }

  // exposed for testing
  private[util] def set(tracker: ResourceTracker): Unit = {
    val oldCtx = Local.save()
    val newCtx = oldCtx.setResourceTracker(tracker)
    Local.restore(newCtx)
  }

  // exposed for testing
  private[util] def clear(): Unit = {
    val oldCtx = Local.save()
    val newCtx = oldCtx.removeResourceTracker()
    if (newCtx ne oldCtx) Local.restore(newCtx)
  }

  /**
   * Track the execution of completed [[Future]]s within `f`.
   */
  def apply[A](f: ResourceTracker => A) = {
    val accumulator = new ResourceTracker()
    let(accumulator)(f(accumulator))
  }
}

/**
 * A class used as the value for the local [[ResourceTracker#resourceTracker]] that's updated
 * with low level resource usage as [[Promise]] continuations are executed.
 *
 * @note some measurements such as the cpu time relies on the JDK's implementation of the
 * management interfaces. This means that the results may vary between JDK implementations.
 */
private[twitter] class ResourceTracker {
  private[this] val cpuTime: LongAdder = new LongAdder()
  private[this] val continuations: AtomicInteger = new AtomicInteger()

  private[util] def addCpuTime(time: Long): Unit = cpuTime.add(time)
  private[util] def incContinuations(): Unit = continuations.getAndIncrement()
  private[util] def addContinuations(count: Int): Unit = continuations.getAndAdd(count)

  /**
   * Retrieve the total accumulated CPU time
   */
  def totalCpuTime(): Long = cpuTime.sum()

  /**
   * Retrieve the total number of executed continuations
   */
  def numContinuations(): Int = continuations.get()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy