Skip to content

Commit

Permalink
Merge pull request #9596 from dwijnand/review-and-look-to-speed-up-st…
Browse files Browse the repository at this point in the history
…atistics
  • Loading branch information
retronym committed Apr 28, 2021
2 parents 812453c + 518e6e0 commit 089bad7
Show file tree
Hide file tree
Showing 9 changed files with 30 additions and 56 deletions.
7 changes: 2 additions & 5 deletions src/compiler/scala/tools/nsc/Global.scala
Expand Up @@ -1281,11 +1281,8 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
checkPhaseSettings(including = true, inclusions.toSeq: _*)
checkPhaseSettings(including = false, exclusions map (_.value): _*)

// Enable or disable depending on the current setting -- useful for interactive behaviour
statistics.initFromSettings(settings)

// Report the overhead of statistics measurements per every run
if (statistics.areStatisticsLocallyEnabled)
if (settings.areStatisticsEnabled)
statistics.reportStatisticsOverhead(reporter)

phase = first //parserPhase
Expand Down Expand Up @@ -1510,7 +1507,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
warnDeprecatedAndConflictingSettings()
globalPhase = fromPhase

val timePhases = statistics.areStatisticsLocallyEnabled
val timePhases = settings.areStatisticsEnabled
val startTotal = if (timePhases) statistics.startTimer(totalCompileTime) else null

while (globalPhase.hasNext && !reporter.hasErrors) {
Expand Down
5 changes: 2 additions & 3 deletions src/compiler/scala/tools/nsc/MainBench.scala
Expand Up @@ -29,9 +29,8 @@ object MainBench extends Driver with EvalLoop {
var start = System.nanoTime()
for (i <- 0 until NIter) {
if (i == NIter-1) {
theCompiler.settings.Ystatistics.value = List("all")
theCompiler.statistics.enabled = true
theCompiler.statistics.hotEnabled = true
theCompiler.settings.Ystatistics.value = List("all")
theCompiler.settings.YhotStatisticsEnabled.value = true
}
process(args)
val end = System.nanoTime()
Expand Down
Expand Up @@ -63,7 +63,7 @@ abstract class ClassfileWriters {

def apply(global: Global): ClassfileWriter = {
//Note dont import global._ - its too easy to leak non threadsafe structures
import global.{cleanup, log, settings, statistics}
import global.{ cleanup, log, settings }
def jarManifestMainClass: Option[String] = settings.mainClass.valueSetByUser.orElse {
cleanup.getEntryPoints match {
case List(name) => Some(name)
Expand Down Expand Up @@ -91,7 +91,7 @@ abstract class ClassfileWriters {
new DebugClassWriter(basicClassWriter, asmp, dump)
}

val enableStats = statistics.enabled && settings.YaddBackendThreads.value == 1
val enableStats = settings.areStatisticsEnabled && settings.YaddBackendThreads.value == 1
if (enableStats) new WithStatsWriter(withAdditionalFormats) else withAdditionalFormats
}

Expand Down
Expand Up @@ -59,7 +59,7 @@ private[jvm] object GeneratedClassHandler {
new SyncWritingClassHandler(postProcessor)

case maxThreads =>
if (statistics.enabled)
if (settings.areStatisticsEnabled)
runReporting.warning(NoPosition, "jvm statistics are not reliable with multi-threaded jvm class writing", WarningCategory.Other, site = "")
val additionalThreads = maxThreads - 1
// The thread pool queue is limited in size. When it's full, the `CallerRunsPolicy` causes
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -23,7 +23,7 @@ import scala.language.existentials
import scala.annotation.elidable
import scala.tools.util.PathResolver.Defaults
import scala.collection.mutable
import scala.reflect.internal.util.StringContextStripMarginOps
import scala.reflect.internal.util.{ StatisticsStatics, StringContextStripMarginOps }
import scala.tools.nsc.util.DefaultJarFactory
import scala.util.chaining._

Expand Down Expand Up @@ -496,9 +496,9 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
val Ystatistics = PhasesSetting("-Vstatistics", "Print compiler statistics for specific phases", "parser,typer,patmat,erasure,cleanup,jvm")
.withPostSetHook(s => YstatisticsEnabled.value = s.value.nonEmpty)
.withAbbreviation("-Ystatistics")
val YstatisticsEnabled = BooleanSetting("-Ystatistics-enabled", "Internal setting, indicating that statistics are enabled for some phase.").internalOnly()
val YstatisticsEnabled = BooleanSetting("-Ystatistics-enabled", "Internal setting, indicating that statistics are enabled for some phase.").internalOnly().withPostSetHook(s => if (s) StatisticsStatics.enableColdStatsAndDeoptimize())
val YhotStatisticsEnabled = BooleanSetting("-Vhot-statistics", s"Enable `${Ystatistics.name}` to also print hot statistics.")
.withAbbreviation("-Yhot-statistics")
.withAbbreviation("-Yhot-statistics").withPostSetHook(s => if (s && YstatisticsEnabled) StatisticsStatics.enableHotStatsAndDeoptimize())
val Yshowsyms = BooleanSetting("-Vsymbols", "Print the AST symbol hierarchy after each phase.") withAbbreviation "-Yshow-syms"
val Ytyperdebug = BooleanSetting("-Vtyper", "Trace type assignments.") withAbbreviation "-Ytyper-debug"
val Vimplicits = BooleanSetting("-Vimplicits", "Print dependent missing implicits.").withAbbreviation("-Xlog-implicits")
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -6003,7 +6003,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper

def typed(tree: Tree, mode: Mode, pt: Type): Tree = {
lastTreeToTyper = tree
val statsEnabled = StatisticsStatics.areSomeHotStatsEnabled() && statistics.areHotStatsLocallyEnabled
val statsEnabled = StatisticsStatics.areSomeHotStatsEnabled && settings.areStatisticsEnabled && settings.YhotStatisticsEnabled
val startByType = if (statsEnabled) statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null
if (statsEnabled) statistics.incCounter(visitsByType, tree.getClass)
val shouldPrintTyping = printTypings && !phase.erasedTypes && !noPrintTyping(tree)
Expand Down
Expand Up @@ -16,6 +16,8 @@ package scala
package reflect.internal
package settings

import scala.reflect.internal.util.StatisticsStatics

/** A mutable Settings object.
*/
abstract class MutableSettings extends AbsSettings {
Expand Down Expand Up @@ -69,4 +71,8 @@ object MutableSettings {
import scala.language.implicitConversions
/** Support the common use case, `if (settings.debug) println("Hello, martin.")` */
@inline implicit def reflectSettingToBoolean(s: MutableSettings#BooleanSetting): Boolean = s.value

implicit class SettingsOps(private val settings: MutableSettings) extends AnyVal {
@inline final def areStatisticsEnabled = StatisticsStatics.areSomeColdStatsEnabled && settings.YstatisticsEnabled
}
}
49 changes: 10 additions & 39 deletions src/reflect/scala/reflect/internal/util/Statistics.scala
Expand Up @@ -22,57 +22,49 @@ import scala.annotation.nowarn
import scala.runtime.LongRef

abstract class Statistics(val symbolTable: SymbolTable, settings: MutableSettings) {

initFromSettings(settings)

def initFromSettings(currentSettings: MutableSettings): Unit = {
enabled = currentSettings.YstatisticsEnabled
hotEnabled = currentSettings.YhotStatisticsEnabled
}

type TimerSnapshot = (Long, Long)

/** If enabled, increment counter by one */
@inline final def incCounter(c: Counter): Unit = {
if (areStatisticsLocallyEnabled && c != null) c.value += 1
if (enabled && c != null) c.value += 1
}

/** If enabled, increment counter by given delta */
@inline final def incCounter(c: Counter, delta: Int): Unit = {
if (areStatisticsLocallyEnabled && c != null) c.value += delta
if (enabled && c != null) c.value += delta
}

/** If enabled, increment counter in map `ctrs` at index `key` by one */
@inline final def incCounter[K](ctrs: QuantMap[K, Counter], key: K) =
if (areStatisticsLocallyEnabled && ctrs != null) ctrs(key).value += 1
if (enabled && ctrs != null) ctrs(key).value += 1

/** If enabled, start subcounter. While active it will track all increments of
* its base counter.
*/
@inline final def startCounter(sc: SubCounter): (Int, Int) =
if (areStatisticsLocallyEnabled && sc != null) sc.start() else null
if (enabled && sc != null) sc.start() else null

/** If enabled, stop subcounter from tracking its base counter. */
@inline final def stopCounter(sc: SubCounter, start: (Int, Int)): Unit = {
if (areStatisticsLocallyEnabled && sc != null) sc.stop(start)
if (enabled && sc != null) sc.stop(start)
}

/** If enabled, start timer */
@inline final def startTimer(tm: Timer): TimerSnapshot =
if (areStatisticsLocallyEnabled && tm != null) tm.start() else null
if (enabled && tm != null) tm.start() else null

/** If enabled, stop timer */
@inline final def stopTimer(tm: Timer, start: TimerSnapshot): Unit = {
if (areStatisticsLocallyEnabled && tm != null) tm.stop(start)
if (enabled && tm != null) tm.stop(start)
}

/** If enabled, push and start a new timer in timer stack */
@inline final def pushTimer(timers: TimerStack, timer: => StackableTimer): TimerSnapshot =
if (areStatisticsLocallyEnabled && timers != null) timers.push(timer) else null
if (enabled && timers != null) timers.push(timer) else null

/** If enabled, stop and pop timer from timer stack */
@inline final def popTimer(timers: TimerStack, prev: TimerSnapshot): Unit = {
if (areStatisticsLocallyEnabled && timers != null) timers.pop(prev)
if (enabled && timers != null) timers.pop(prev)
}

/** Create a new counter that shows as `prefix` and is active in given phases */
Expand Down Expand Up @@ -294,29 +286,8 @@ quant)
}

private[this] val qs = new mutable.HashMap[String, Quantity]
private[scala] var areColdStatsLocallyEnabled: Boolean = false
private[scala] var areHotStatsLocallyEnabled: Boolean = false

/** Represents whether normal statistics can or cannot be enabled. */
@inline final def enabled: Boolean = areColdStatsLocallyEnabled
def enabled_=(cond: Boolean) = {
if (cond && !enabled) {
StatisticsStatics.enableColdStatsAndDeoptimize()
areColdStatsLocallyEnabled = true
}
}

/** Represents whether hot statistics can or cannot be enabled. */
@inline final def hotEnabled: Boolean = enabled && areHotStatsLocallyEnabled
def hotEnabled_=(cond: Boolean) = {
if (cond && enabled && !areHotStatsLocallyEnabled) {
StatisticsStatics.enableHotStatsAndDeoptimize()
areHotStatsLocallyEnabled = true
}
}

/** Tells whether statistics should be definitely reported to the user for this `Global` instance. */
@inline final def areStatisticsLocallyEnabled: Boolean = areColdStatsLocallyEnabled
@inline final def enabled: Boolean = settings.areStatisticsEnabled

import scala.reflect.internal.Reporter
/** Reports the overhead of measuring statistics via the nanoseconds variation. */
Expand Down
5 changes: 3 additions & 2 deletions src/reflect/scala/reflect/runtime/Settings.scala
Expand Up @@ -15,6 +15,7 @@ package reflect
package runtime

import scala.reflect.internal.settings.MutableSettings
import scala.reflect.internal.util.StatisticsStatics

/** The Settings class for runtime reflection.
* This should be refined, so that settings are settable via command
Expand Down Expand Up @@ -57,8 +58,8 @@ private[reflect] class Settings extends MutableSettings {
val uniqid = new BooleanSetting(false)
val verbose = new BooleanSetting(false)

val YhotStatisticsEnabled = new BooleanSetting(false)
val YstatisticsEnabled = new BooleanSetting(false)
val YhotStatisticsEnabled = new BooleanSetting(false) { override def postSetHook() = if (v && YstatisticsEnabled) StatisticsStatics.enableHotStatsAndDeoptimize() }
val YstatisticsEnabled = new BooleanSetting(false) { override def postSetHook() = if (v) StatisticsStatics.enableColdStatsAndDeoptimize() }

val Yrecursion = new IntSetting(0)
def isScala212 = true
Expand Down

0 comments on commit 089bad7

Please sign in to comment.