summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-06-18 17:20:14 +0200
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-06-19 10:38:48 +0200
commit8284486a155f145bf61019fc0bd8b56b8d327ff2 (patch)
tree3babc67e2ca41656eac8827f3e83bff0c129f2e9 /src
parent736f622f770700a9c18b84e6a76e31260990496c (diff)
downloadscala-8284486a155f145bf61019fc0bd8b56b8d327ff2.tar.gz
scala-8284486a155f145bf61019fc0bd8b56b8d327ff2.tar.bz2
scala-8284486a155f145bf61019fc0bd8b56b8d327ff2.zip
Statistics reorganization
Statistics were broken since the move to reflect.internal. They are now re-organized, made more robost and modular.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala153
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala39
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala91
-rw-r--r--src/compiler/scala/tools/nsc/util/Statistics.scala200
-rw-r--r--src/compiler/scala/tools/nsc/util/StatisticsInfo.scala38
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala18
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala86
-rw-r--r--src/reflect/scala/reflect/internal/util/StatBase.scala97
-rw-r--r--src/reflect/scala/reflect/internal/util/Statistics.scala261
16 files changed, 546 insertions, 497 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 787c9c7f57..954e98742a 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -12,7 +12,7 @@ import scala.tools.util.PathResolver
import scala.collection.{ mutable, immutable }
import io.{ SourceReader, AbstractFile, Path }
import reporters.{ Reporter, ConsoleReporter }
-import util.{ Exceptional, ClassPath, MergedClassPath, Statistics, StatisticsInfo, ScalaClassLoader, returning }
+import util.{ Exceptional, ClassPath, MergedClassPath, StatisticsInfo, ScalaClassLoader, returning }
import scala.reflect.internal.util.{ NoPosition, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile }
import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat }
import settings.{ AestheticSettings }
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 04acba06e8..9b223a13ba 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -160,7 +160,7 @@ trait ScalaSettings extends AbsScalaSettings
val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "")
val Ynosqueeze = BooleanSetting ("-Yno-squeeze", "Disable creation of compact code in matching.")
- val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (util.Statistics.enabled = _)
+ val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (scala.reflect.internal.util.Statistics.enabled = _)
val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat
val stopBefore = PhasesSetting ("-Ystop-before", "Stop before")
val refinementMethodDispatch
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 15edac16d5..0c988ceae4 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -12,7 +12,7 @@ import scala.tools.nsc.util.{ ClassPath }
import classfile.ClassfileParser
import reflect.internal.Flags._
import reflect.internal.MissingRequirementError
-import util.Statistics._
+import reflect.internal.util.Statistics
import scala.tools.nsc.io.{ AbstractFile, MsilFile }
/** This class ...
@@ -23,6 +23,7 @@ import scala.tools.nsc.io.{ AbstractFile, MsilFile }
abstract class SymbolLoaders {
val global: Global
import global._
+ import SymbolLoadersStats._
protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
assert(owner.info.decls.lookup(member.name) == NoSymbol, owner.fullName + "." + member.name)
@@ -236,7 +237,7 @@ abstract class SymbolLoaders {
protected def description = "class file "+ classfile.toString
protected def doComplete(root: Symbol) {
- val start = startTimer(classReadNanos)
+ val start = Statistics.startTimer(classReadNanos)
classfileParser.parse(classfile, root)
if (root.associatedFile eq null) {
root match {
@@ -248,7 +249,7 @@ abstract class SymbolLoaders {
debuglog("Not setting associatedFile to %s because %s is a %s".format(classfile, root.name, root.shortSymbolClass))
}
}
- stopTimer(classReadNanos, start)
+ Statistics.stopTimer(classReadNanos, start)
}
override def sourcefile: Option[AbstractFile] = classfileParser.srcfile
}
@@ -284,3 +285,8 @@ abstract class SymbolLoaders {
var parentsLevel = 0
var pendingLoadActions: List[() => Unit] = Nil
}
+
+object SymbolLoadersStats {
+ import reflect.internal.TypesStats.typerNanos
+ val classReadNanos = Statistics.newSubTimer ("time classfilereading", typerNanos)
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index a77df71312..2077ab0997 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package typechecker
-import util.Statistics._
+import reflect.internal.util.Statistics
/** The main attribution phase.
*/
@@ -72,6 +72,7 @@ trait Analyzer extends AnyRef
}
object typerFactory extends SubComponent {
+ import reflect.internal.TypesStats.typerNanos
val global: Analyzer.this.global.type = Analyzer.this.global
val phaseName = "typer"
val runsAfter = List[String]()
@@ -84,13 +85,13 @@ trait Analyzer extends AnyRef
// compiler run). This is good enough for the resident compiler, which was the most affected.
undoLog.clear()
override def run() {
- val start = startTimer(typerNanos)
+ val start = Statistics.startTimer(typerNanos)
global.echoPhaseSummary(this)
currentRun.units foreach applyPhase
undoLog.clear()
// need to clear it after as well or 10K+ accumulated entries are
// uncollectable the rest of the way.
- stopTimer(typerNanos, start)
+ Statistics.stopTimer(typerNanos, start)
}
def apply(unit: CompilationUnit) {
try {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 37380fd5c0..f7e00109ae 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -16,7 +16,7 @@ import scala.collection.{ mutable, immutable }
import mutable.{ LinkedHashMap, ListBuffer }
import scala.util.matching.Regex
import symtab.Flags._
-import util.Statistics._
+import scala.reflect.internal.util.Statistics
import language.implicitConversions
/** This trait provides methods to find various kinds of implicits.
@@ -29,6 +29,7 @@ trait Implicits {
import global._
import definitions._
+ import ImplicitsStats._
import typeDebug.{ ptTree, ptBlock, ptLine }
import global.typer.{ printTyping, deindentTyping, indentTyping, printInference }
@@ -71,10 +72,10 @@ trait Implicits {
)
indentTyping()
- val rawTypeStart = startCounter(rawTypeImpl)
- val findMemberStart = startCounter(findMemberImpl)
- val subtypeStart = startCounter(subtypeImpl)
- val start = startTimer(implicitNanos)
+ val rawTypeStart = Statistics.startCounter(rawTypeImpl)
+ val findMemberStart = Statistics.startCounter(findMemberImpl)
+ val subtypeStart = Statistics.startCounter(subtypeImpl)
+ val start = Statistics.startTimer(implicitNanos)
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
@@ -86,10 +87,10 @@ trait Implicits {
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains
- stopTimer(implicitNanos, start)
- stopCounter(rawTypeImpl, rawTypeStart)
- stopCounter(findMemberImpl, findMemberStart)
- stopCounter(subtypeImpl, subtypeStart)
+ Statistics.stopTimer(implicitNanos, start)
+ Statistics.stopCounter(rawTypeImpl, rawTypeStart)
+ Statistics.stopCounter(findMemberImpl, findMemberStart)
+ Statistics.stopCounter(subtypeImpl, subtypeStart)
deindentTyping()
printTyping("Implicit search yielded: "+ result)
result
@@ -307,12 +308,12 @@ trait Implicits {
/** Is implicit info `info1` better than implicit info `info2`?
*/
def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
- incCounter(improvesCount)
+ Statistics.incCounter(improvesCount)
(info2 == NoImplicitInfo) ||
(info1 != NoImplicitInfo) && {
if (info1.sym.isStatic && info2.sym.isStatic) {
improvesCache get (info1, info2) match {
- case Some(b) => incCounter(improvesCachedCount); b
+ case Some(b) => Statistics.incCounter(improvesCachedCount); b
case None =>
val result = isStrictlyMoreSpecific(info1.tpe, info2.tpe, info1.sym, info2.sym)
improvesCache((info1, info2)) = result
@@ -376,7 +377,7 @@ trait Implicits {
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}
- incCounter(implicitSearchCount)
+ Statistics.incCounter(implicitSearchCount)
/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams
@@ -428,7 +429,7 @@ trait Implicits {
* This method is performance critical: 5-8% of typechecking time.
*/
private def matchesPt(tp: Type, pt: Type, undet: List[Symbol]): Boolean = {
- val start = startTimer(matchesPtNanos)
+ val start = Statistics.startTimer(matchesPtNanos)
val result = normSubType(tp, pt) || isView && {
pt match {
case TypeRef(_, Function1.Sym, args) =>
@@ -437,7 +438,7 @@ trait Implicits {
false
}
}
- stopTimer(matchesPtNanos, start)
+ Statistics.stopTimer(matchesPtNanos, start)
result
}
private def matchesPt(info: ImplicitInfo): Boolean = (
@@ -536,7 +537,7 @@ trait Implicits {
}
private def typedImplicit0(info: ImplicitInfo, ptChecked: Boolean, isLocal: Boolean): SearchResult = {
- incCounter(plausiblyCompatibleImplicits)
+ Statistics.incCounter(plausiblyCompatibleImplicits)
printTyping (
ptBlock("typedImplicit0",
"info.name" -> info.name,
@@ -556,7 +557,7 @@ trait Implicits {
}
private def typedImplicit1(info: ImplicitInfo, isLocal: Boolean): SearchResult = {
- incCounter(matchingImplicits)
+ Statistics.incCounter(matchingImplicits)
val itree = atPos(pos.focus) {
// workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
@@ -594,7 +595,7 @@ trait Implicits {
if (context.hasErrors)
return fail("typed implicit %s has errors".format(info.sym.fullLocationString))
- incCounter(typedImplicits)
+ Statistics.incCounter(typedImplicits)
printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
@@ -677,7 +678,7 @@ trait Implicits {
fail("typing TypeApply reported errors for the implicit tree")
else {
val result = new SearchResult(itree2, subst)
- incCounter(foundImplicits)
+ Statistics.incCounter(foundImplicits)
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
result
}
@@ -904,11 +905,11 @@ trait Implicits {
* @return map from infos to search results
*/
def applicableInfos(iss: Infoss, isLocal: Boolean): Map[ImplicitInfo, SearchResult] = {
- val start = startCounter(subtypeAppInfos)
+ val start = Statistics.startCounter(subtypeAppInfos)
val computation = new ImplicitComputation(iss, isLocal) { }
val applicable = computation.findAll()
- stopCounter(subtypeAppInfos, start)
+ Statistics.stopCounter(subtypeAppInfos, start)
applicable
}
@@ -1123,26 +1124,28 @@ trait Implicits {
* These are all implicits found in companion objects of classes C
* such that some part of `tp` has C as one of its superclasses.
*/
- private def implicitsOfExpectedType: Infoss = implicitsCache get pt match {
- case Some(implicitInfoss) =>
- incCounter(implicitCacheHits)
- implicitInfoss
- case None =>
- incCounter(implicitCacheMisses)
- val start = startTimer(subtypeETNanos)
-// val implicitInfoss = companionImplicits(pt)
- val implicitInfoss1 = companionImplicitMap(pt).valuesIterator.toList
-// val is1 = implicitInfoss.flatten.toSet
-// val is2 = implicitInfoss1.flatten.toSet
-// for (i <- is1)
-// if (!(is2 contains i)) println("!!! implicit infos of "+pt+" differ, new does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
-// for (i <- is2)
-// if (!(is1 contains i)) println("!!! implicit infos of "+pt+" differ, old does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
- stopTimer(subtypeETNanos, start)
- implicitsCache(pt) = implicitInfoss1
- if (implicitsCache.size >= sizeLimit)
- implicitsCache -= implicitsCache.keysIterator.next
- implicitInfoss1
+ private def implicitsOfExpectedType: Infoss = {
+ Statistics.incCounter(implicitCacheHits)
+ implicitsCache get pt match {
+ case Some(implicitInfoss) =>
+ Statistics.incCounter(implicitCacheHits)
+ implicitInfoss
+ case None =>
+ val start = Statistics.startTimer(subtypeETNanos)
+ // val implicitInfoss = companionImplicits(pt)
+ val implicitInfoss1 = companionImplicitMap(pt).valuesIterator.toList
+ // val is1 = implicitInfoss.flatten.toSet
+ // val is2 = implicitInfoss1.flatten.toSet
+ // for (i <- is1)
+ // if (!(is2 contains i)) println("!!! implicit infos of "+pt+" differ, new does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
+ // for (i <- is2)
+ // if (!(is1 contains i)) println("!!! implicit infos of "+pt+" differ, old does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
+ Statistics.stopTimer(subtypeETNanos, start)
+ implicitsCache(pt) = implicitInfoss1
+ if (implicitsCache.size >= sizeLimit)
+ implicitsCache -= implicitsCache.keysIterator.next
+ implicitInfoss1
+ }
}
private def TagSymbols = TagMaterializers.keySet
@@ -1368,30 +1371,30 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = startTimer(inscopeFailNanos)
- val succstart = startTimer(inscopeSucceedNanos)
+ val failstart = Statistics.startTimer(inscopeFailNanos)
+ val succstart = Statistics.startTimer(inscopeSucceedNanos)
var result = searchImplicit(context.implicitss, true)
if (result == SearchFailure) {
- stopTimer(inscopeFailNanos, failstart)
+ Statistics.stopTimer(inscopeFailNanos, failstart)
} else {
- stopTimer(inscopeSucceedNanos, succstart)
- incCounter(inscopeImplicitHits)
+ Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ Statistics.incCounter(inscopeImplicitHits)
}
if (result == SearchFailure) {
val previousErrs = context.flushAndReturnBuffer()
- val failstart = startTimer(oftypeFailNanos)
- val succstart = startTimer(oftypeSucceedNanos)
+ val failstart = Statistics.startTimer(oftypeFailNanos)
+ val succstart = Statistics.startTimer(oftypeSucceedNanos)
result = implicitTagOrOfExpectedType(pt)
if (result == SearchFailure) {
context.updateBuffer(previousErrs)
- stopTimer(oftypeFailNanos, failstart)
+ Statistics.stopTimer(oftypeFailNanos, failstart)
} else {
- stopTimer(oftypeSucceedNanos, succstart)
- incCounter(oftypeImplicitHits)
+ Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ Statistics.incCounter(oftypeImplicitHits)
}
}
@@ -1415,19 +1418,19 @@ trait Implicits {
val eligible = new ImplicitComputation(iss, isLocal).eligible
eligible.toList.flatMap {
(ii: ImplicitInfo) =>
- // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
- // thus, start each type var off with a fresh for every typedImplicit
- resetTVars()
- // any previous errors should not affect us now
- context.flushBuffer()
+ // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
+ // thus, start each type var off with a fresh for every typedImplicit
+ resetTVars()
+ // any previous errors should not affect us now
+ context.flushBuffer()
val res = typedImplicit(ii, ptChecked = false, isLocal)
- if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
- else Nil
- }
+ if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
+ else Nil
}
- eligibleInfos(context.implicitss, isLocal = true) ++ eligibleInfos(implicitsOfExpectedType, isLocal = false)
}
+ eligibleInfos(context.implicitss, isLocal = true) ++ eligibleInfos(implicitsOfExpectedType, isLocal = false)
+ }
}
object ImplicitNotFoundMsg {
@@ -1472,5 +1475,37 @@ trait Implicits {
}
}
}
+
+object ImplicitsStats {
+
+ import reflect.internal.TypesStats._
+
+ val rawTypeImpl = Statistics.newSubCounter (" of which in implicits", rawTypeCount)
+ val subtypeImpl = Statistics.newSubCounter(" of which in implicit", subtypeCount)
+ val findMemberImpl = Statistics.newSubCounter(" of which in implicit", findMemberCount)
+ val subtypeAppInfos = Statistics.newSubCounter(" of which in app impl", subtypeCount)
+ val subtypeImprovCount = Statistics.newSubCounter(" of which in improves", subtypeCount)
+ val implicitSearchCount = Statistics.newCounter ("#implicit searches", "typer")
+ val triedImplicits = Statistics.newSubCounter(" #tried", implicitSearchCount)
+ val plausiblyCompatibleImplicits
+ = Statistics.newSubCounter(" #plausibly compatible", implicitSearchCount)
+ val matchingImplicits = Statistics.newSubCounter(" #matching", implicitSearchCount)
+ val typedImplicits = Statistics.newSubCounter(" #typed", implicitSearchCount)
+ val foundImplicits = Statistics.newSubCounter(" #found", implicitSearchCount)
+ val improvesCount = Statistics.newSubCounter("implicit improves tests", implicitSearchCount)
+ val improvesCachedCount = Statistics.newSubCounter("#implicit improves cached ", implicitSearchCount)
+ val inscopeImplicitHits = Statistics.newSubCounter("#implicit inscope hits", implicitSearchCount)
+ val oftypeImplicitHits = Statistics.newSubCounter("#implicit oftype hits ", implicitSearchCount)
+ val implicitNanos = Statistics.newSubTimer ("time spent in implicits", typerNanos)
+ val inscopeSucceedNanos = Statistics.newSubTimer (" successful in scope", typerNanos)
+ val inscopeFailNanos = Statistics.newSubTimer (" failed in scope", typerNanos)
+ val oftypeSucceedNanos = Statistics.newSubTimer (" successful of type", typerNanos)
+ val oftypeFailNanos = Statistics.newSubTimer (" failed of type", typerNanos)
+ val subtypeETNanos = Statistics.newSubTimer (" assembling parts", typerNanos)
+ val matchesPtNanos = Statistics.newSubTimer (" matchesPT", typerNanos)
+ val implicitCacheAccs = Statistics.newCounter ("implicit cache accesses", "typer")
+ val implicitCacheHits = Statistics.newSubCounter("implicit cache hits", implicitCacheAccs)
+}
+
class DivergentImplicit extends Exception
object DivergentImplicit extends DivergentImplicit
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index ec14476d1a..d157666e47 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -7,7 +7,7 @@ import scala.tools.nsc.util.ClassPath._
import scala.reflect.runtime.ReflectionUtils
import scala.collection.mutable.ListBuffer
import scala.compat.Platform.EOL
-import util.Statistics._
+import reflect.internal.util.Statistics
import scala.reflect.makro.util._
import java.lang.{Class => jClass}
import java.lang.reflect.{Array => jArray, Method => jMethod}
@@ -42,6 +42,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
import global._
import definitions._
+ import MacrosStats._
def globalSettings = global.settings
val globalMacroCache = collection.mutable.Map[Any, Any]()
@@ -945,8 +946,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
this.fail(typer, tree, err.errPos, "failed to %s: %s".format(what, err.errMsg))
return expandee
}
- val start = startTimer(macroExpandNanos)
- incCounter(macroExpandCount)
+ val start = Statistics.startTimer(macroExpandNanos)
+ Statistics.incCounter(macroExpandCount)
try {
macroExpand1(typer, expandee) match {
case Success(expanded0) =>
@@ -993,7 +994,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
result
}
} finally {
- stopTimer(macroExpandNanos, start)
+ Statistics.stopTimer(macroExpandNanos, start)
}
}
@@ -1292,3 +1293,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
})
}.transform(expandee)
}
+
+object MacrosStats {
+ import reflect.internal.TypesStats.typerNanos
+ val macroExpandCount = Statistics.newCounter ("#macro expansions", "typer")
+ val macroExpandNanos = Statistics.newSubTimer("time spent in macroExpand", typerNanos)
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 4e8f416b16..9b8ddffb49 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -14,7 +14,7 @@ import scala.tools.nsc.transform.TypingTransformers
import scala.tools.nsc.transform.Transform
import scala.collection.mutable.HashSet
import scala.collection.mutable.HashMap
-import scala.tools.nsc.util.Statistics
+import reflect.internal.util.Statistics
/** Translate pattern matching.
*
@@ -38,6 +38,7 @@ import scala.tools.nsc.util.Statistics
*/
trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL { // self: Analyzer =>
import Statistics._
+ import PatternMatchingStats._
val global: Global // need to repeat here because otherwise last mixin defines global as
// SymbolTable. If we had DOT this would not be an issue
@@ -183,7 +184,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
case _ => tp
}
- val start = startTimer(patmatNanos)
+ val start = Statistics.startTimer(patmatNanos)
val selectorTp = repeatedToSeq(elimAnonymousClass(selector.tpe.widen.withoutAnnotations))
@@ -210,7 +211,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental
val combined = combineCases(selector, selectorSym, cases map translateCase(selectorSym, pt), pt, matchOwner, matchFailGenOverride)
- stopTimer(patmatNanos, start)
+ Statistics.stopTimer(patmatNanos, start)
combined
}
@@ -1694,7 +1695,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// TODO: for V1 representing x1 and V2 standing for x1.head, encode that
// V1 = Nil implies -(V2 = Ci) for all Ci in V2's domain (i.e., it is unassignable)
def removeVarEq(props: List[Prop], considerNull: Boolean = false): (Prop, List[Prop]) = {
- val start = startTimer(patmatAnaVarEq)
+ val start = Statistics.startTimer(patmatAnaVarEq)
val vars = new collection.mutable.HashSet[Var]
@@ -1766,7 +1767,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// patmatDebug("eqAxioms:\n"+ cnfString(eqFreePropToSolvable(eqAxioms)))
// patmatDebug("pure:\n"+ cnfString(eqFreePropToSolvable(pure)))
- stopTimer(patmatAnaVarEq, start)
+ Statistics.stopTimer(patmatAnaVarEq, start)
(eqAxioms, pure)
}
@@ -1865,10 +1866,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- val start = startTimer(patmatCNF)
+ val start = Statistics.startTimer(patmatCNF)
val res = conjunctiveNormalForm(negationNormalForm(p))
- stopTimer(patmatCNF, start)
- patmatCNFSizes(res.size) += 1
+ Statistics.stopTimer(patmatCNF, start)
+ patmatCNFSizes(res.size).value += 1
// patmatDebug("cnf for\n"+ p +"\nis:\n"+cnfString(res))
res
@@ -1945,7 +1946,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// patmatDebug("dpll\n"+ cnfString(f))
- val start = startTimer(patmatAnaDPLL)
+ val start = Statistics.startTimer(patmatAnaDPLL)
val satisfiableWithModel: Model =
if (f isEmpty) EmptyModel
@@ -1983,7 +1984,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- stopTimer(patmatAnaDPLL, start)
+ Statistics.stopTimer(patmatAnaDPLL, start)
satisfiableWithModel
}
@@ -2291,7 +2292,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def makeCondPessimistic(tm: TreeMaker)(recurse: TreeMaker => Cond): Cond = makeCond(tm)(recurse)
}
- val start = startTimer(patmatAnaReach)
+ val start = Statistics.startTimer(patmatAnaReach)
// use the same approximator so we share variables,
// but need different conditions depending on whether we're conservatively looking for failure or success
@@ -2340,7 +2341,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- stopTimer(patmatAnaReach, start)
+ Statistics.stopTimer(patmatAnaReach, start)
if (reachable) None else Some(caseIndex)
} catch {
@@ -2428,7 +2429,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// - back off (to avoid crying exhaustive too often) when:
// - there are guards -->
// - there are extractor calls (that we can't secretly/soundly) rewrite
- val start = startTimer(patmatAnaExhaust)
+ val start = Statistics.startTimer(patmatAnaExhaust)
var backoff = false
object exhaustivityApproximation extends TreeMakersToConds(prevBinder) {
def makeCondExhaustivity(tm: TreeMaker)(recurse: TreeMaker => Cond): Cond = tm match {
@@ -2503,7 +2504,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
val pruned = CounterExample.prune(counterExamples).map(_.toString).sorted
- stopTimer(patmatAnaExhaust, start)
+ Statistics.stopTimer(patmatAnaExhaust, start)
pruned
} catch {
case e : CNFBudgetExceeded =>
@@ -3186,3 +3187,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
}
+
+object PatternMatchingStats {
+ val patmatNanos = Statistics.newTimer ("time spent in patmat", "patmat")
+ val patmatAnaDPLL = Statistics.newSubTimer (" of which DPLL", patmatNanos)
+ val patmatCNF = Statistics.newSubTimer (" of which in CNF conversion", patmatNanos)
+ val patmatCNFSizes = Statistics.newQuantMap[Int, Statistics.Counter](" CNF size counts", "patmat")(Statistics.newCounter(""))
+ val patmatAnaVarEq = Statistics.newSubTimer (" of which variable equality", patmatNanos)
+ val patmatAnaExhaust = Statistics.newSubTimer (" of which in exhaustivity", patmatNanos)
+ val patmatAnaReach = Statistics.newSubTimer (" of which in unreachability", patmatNanos)
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 1193d3013a..6bd1117689 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -16,8 +16,7 @@ import scala.collection.mutable
import scala.reflect.internal.util.BatchSourceFile
import mutable.ListBuffer
import symtab.Flags._
-import util.Statistics
-import util.Statistics._
+import reflect.internal.util.Statistics
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
// like the IDE does.
@@ -31,6 +30,7 @@ trait Typers extends Modes with Adaptations with Tags {
import global._
import definitions._
+ import TypersStats._
import patmat.DefaultOverrideMatchAttachment
final def forArgMode(fun: Tree, mode: Int) =
@@ -707,10 +707,16 @@ trait Typers extends Modes with Adaptations with Tags {
def silent[T](op: Typer => T,
reportAmbiguousErrors: Boolean = context.ambiguousErrors,
newtree: Tree = context.tree): SilentResult[T] = {
- val rawTypeStart = startCounter(rawTypeFailed)
- val findMemberStart = startCounter(findMemberFailed)
- val subtypeStart = startCounter(subtypeFailed)
- val failedSilentStart = startTimer(failedSilentNanos)
+ val rawTypeStart = Statistics.startCounter(rawTypeFailed)
+ val findMemberStart = Statistics.startCounter(findMemberFailed)
+ val subtypeStart = Statistics.startCounter(subtypeFailed)
+ val failedSilentStart = Statistics.startTimer(failedSilentNanos)
+ def stopStats() = {
+ Statistics.stopCounter(rawTypeFailed, rawTypeStart)
+ Statistics.stopCounter(findMemberFailed, findMemberStart)
+ Statistics.stopCounter(subtypeFailed, subtypeStart)
+ Statistics.stopTimer(failedSilentNanos, failedSilentStart)
+ }
try {
if (context.reportErrors ||
reportAmbiguousErrors != context.ambiguousErrors ||
@@ -724,8 +730,10 @@ trait Typers extends Modes with Adaptations with Tags {
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- if (context1.hasErrors) SilentTypeError(context1.errBuffer.head)
- else SilentResultValue(result)
+ if (context1.hasErrors) {
+ stopStats()
+ SilentTypeError(context1.errBuffer.head)
+ } else SilentResultValue(result)
} else {
assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
withSavedContext(context){
@@ -739,10 +747,7 @@ trait Typers extends Modes with Adaptations with Tags {
case ex: TypeError =>
// fallback in case TypeError is still thrown
// @H this happens for example in cps annotation checker
- stopCounter(rawTypeFailed, rawTypeStart)
- stopCounter(findMemberFailed, findMemberStart)
- stopCounter(subtypeFailed, subtypeStart)
- stopTimer(failedSilentNanos, failedSilentStart)
+ stopStats()
SilentTypeError(TypeErrorWrapper(ex))
}
}
@@ -3481,9 +3486,9 @@ trait Typers extends Modes with Adaptations with Tags {
def isCapturedExistential(sym: Symbol) =
(sym hasAllFlags (EXISTENTIAL | CAPTURED)) && {
- val start = startTimer(isReferencedNanos)
+ val start = Statistics.startTimer(isReferencedNanos)
try !isReferencedFrom(context, sym)
- finally stopTimer(isReferencedNanos, start)
+ finally Statistics.stopTimer(isReferencedNanos, start)
}
def packCaptured(tpe: Type): Type = {
@@ -4110,10 +4115,10 @@ trait Typers extends Modes with Adaptations with Tags {
* insert an implicit conversion.
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
- val start = startTimer(failedApplyNanos)
+ val start = Statistics.startTimer(failedApplyNanos)
def onError(typeError: AbsTypeError): Tree = {
- stopTimer(failedApplyNanos, start)
+ Statistics.stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
// See #4712 for a case where this situation arises,
@@ -4176,8 +4181,8 @@ trait Typers extends Modes with Adaptations with Tags {
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
val funpt = if (isPatternMode) pt else WildcardType
- val appStart = startTimer(failedApplyNanos)
- val opeqStart = startTimer(failedOpEqNanos)
+ val appStart = Statistics.startTimer(failedApplyNanos)
+ val opeqStart = Statistics.startTimer(failedOpEqNanos)
def onError(reportError: => Tree): Tree = {
fun match {
@@ -4185,14 +4190,14 @@ trait Typers extends Modes with Adaptations with Tags {
if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
val qual1 = typedQualifier(qual)
if (treeInfo.isVariableOrGetter(qual1)) {
- stopTimer(failedOpEqNanos, opeqStart)
+ Statistics.stopTimer(failedOpEqNanos, opeqStart)
convertToAssignment(fun, qual1, name, args)
} else {
- stopTimer(failedApplyNanos, appStart)
+ Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
case _ =>
- stopTimer(failedApplyNanos, appStart)
+ Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
}
@@ -4201,7 +4206,7 @@ trait Typers extends Modes with Adaptations with Tags {
if ((mode & EXPRmode) != 0) tree else context.tree) match {
case SilentResultValue(fun1) =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
- incCounter(typedApplyCount)
+ Statistics.incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
case mt: MethodType => mt.isImplicit
case _ => false
@@ -4977,7 +4982,7 @@ trait Typers extends Modes with Adaptations with Tags {
typedSelect(qual1, nme.CONSTRUCTOR)
case Select(qual, name) =>
- incCounter(typedSelectCount)
+ Statistics.incCounter(typedSelectCount)
var qual1 = checkDead(typedQualifier(qual, mode))
if (name.isTypeName) qual1 = checkStable(qual1)
@@ -5009,7 +5014,7 @@ trait Typers extends Modes with Adaptations with Tags {
else tree1
case Ident(name) =>
- incCounter(typedIdentCount)
+ Statistics.incCounter(typedIdentCount)
if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
(name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
tree setType makeFullyDefined(pt)
@@ -5084,15 +5089,9 @@ trait Typers extends Modes with Adaptations with Tags {
indentTyping()
var alreadyTyped = false
+ val startByType = Statistics.pushTimerClass(byTypeNanos, tree.getClass)
+ Statistics.incCounter(visitsByType, tree.getClass)
try {
- if (Statistics.enabled) {
- val t = currentTime()
- if (pendingTreeTypes.nonEmpty) {
- microsByType(pendingTreeTypes.head) += ((t - typerTime) / 1000).toInt
- }
- typerTime = t
- pendingTreeTypes = tree.getClass :: pendingTreeTypes
- }
if (context.retyping &&
(tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) {
tree.tpe = null
@@ -5146,14 +5145,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
finally {
deindentTyping()
-
- if (Statistics.enabled) {
- val t = currentTime()
- microsByType(pendingTreeTypes.head) += ((t - typerTime) / 1000).toInt
- visitsByType(pendingTreeTypes.head) += 1
- typerTime = t
- pendingTreeTypes = pendingTreeTypes.tail
- }
+ Statistics.popTimerClass(byTypeNanos, startByType)
}
}
@@ -5329,3 +5321,22 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
+object TypersStats {
+ import reflect.internal.TypesStats._
+ import reflect.internal.BaseTypeSeqsStats._
+ val typedIdentCount = Statistics.newCounter("#typechecked identifiers")
+ val typedSelectCount = Statistics.newCounter("#typechecked selections")
+ val typedApplyCount = Statistics.newCounter("#typechecked applications")
+ val rawTypeFailed = Statistics.newSubCounter (" of which in failed", rawTypeCount)
+ val subtypeFailed = Statistics.newSubCounter(" of which in failed", subtypeCount)
+ val findMemberFailed = Statistics.newSubCounter(" of which in failed", findMemberCount)
+ val compoundBaseTypeSeqCount = Statistics.newSubCounter(" of which for compound types", baseTypeSeqCount)
+ val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount)
+ val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount)
+ val failedSilentNanos = Statistics.newSubTimer ("time spent in failed", typerNanos)
+ val failedApplyNanos = Statistics.newSubTimer (" failed apply", typerNanos)
+ val failedOpEqNanos = Statistics.newSubTimer (" failed op=", typerNanos)
+ val isReferencedNanos = Statistics.newSubTimer ("time spent ref scanning", typerNanos)
+ val visitsByType = Statistics.newByClass ("#visits by tree node", "typer")(Statistics.newCounter(""))
+ val byTypeNanos = Statistics.newByClassTimerStack("time spent by tree node", typerNanos)
+}
diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala
deleted file mode 100644
index 087111a7ba..0000000000
--- a/src/compiler/scala/tools/nsc/util/Statistics.scala
+++ /dev/null
@@ -1,200 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala.tools.nsc
-package util
-
-class Statistics extends scala.reflect.internal.util.Statistics {
-
- var nodeByType = new ClassCounts
-
- var microsByType = new ClassCounts
- var visitsByType = new ClassCounts
- var pendingTreeTypes: List[Class[_]] = List()
- var typerTime: Long = 0L
-
- val typedApplyCount = new Counter
- val typedIdentCount = new Counter
- val typedSelectCount = new Counter
- val typerNanos = new Timer
- val classReadNanos = new Timer
-
- val failedApplyNanos = new Timer
- val failedOpEqNanos = new Timer
- val failedSilentNanos = new Timer
-
- val implicitSearchCount = new Counter
- val implicitNanos = new Timer
- val oftypeImplicitHits = new Counter
- val inscopeImplicitHits = new Counter
-
- val triedImplicits = new Counter
- val plausiblyCompatibleImplicits = new Counter
- val matchingImplicits = new Counter
- val typedImplicits = new Counter
- val foundImplicits = new Counter
-
- val inscopeSucceedNanos = new Timer
- val inscopeFailNanos = new Timer
- val oftypeSucceedNanos = new Timer
- val oftypeFailNanos = new Timer
- val implicitCacheHits = new Counter
- val implicitCacheMisses = new Counter
- val improvesCount = new Counter
- val improvesCachedCount = new Counter
- val subtypeAppInfos = new SubCounter(subtypeCount)
- val subtypeImprovCount = new SubCounter(subtypeCount)
- val subtypeETNanos = new Timer
- val matchesPtNanos = new Timer
- val isReferencedNanos = new Timer
- val ctr1 = new Counter
- val ctr2 = new Counter
- val ctr3 = new Counter
- val ctr4 = new Counter
- val counter1: SubCounter = new SubCounter(subtypeCount)
- val counter2: SubCounter = new SubCounter(subtypeCount)
- val timer1: Timer = new Timer
- val timer2: Timer = new Timer
-
- val macroExpandCount = new Counter
- val macroExpandNanos = new Timer
-
- val patmatNanos = new Timer
- val patmatAnaDPLL = new Timer
- val patmatAnaVarEq = new Timer
- val patmatCNF = new Timer
- val patmatAnaExhaust = new Timer
- val patmatAnaReach = new Timer
- val patmatCNFSizes = new collection.mutable.HashMap[Int, Int] withDefaultValue 0
-}
-
-object Statistics extends Statistics
-
-abstract class StatisticsInfo {
-
- import Statistics._
-
- val global: Global
- import global._
-
- var phasesShown = List("parser", "typer", "patmat", "erasure", "cleanup")
-
- def countNodes(tree: Tree, counts: ClassCounts) {
- for (t <- tree) counts(t.getClass) += 1
- }
-
- def showRelative(base: Long)(value: Long) =
- value+showPercent(value, base)
-
- def showRelTyper(timer: Timer) =
- timer+showPercent(timer.nanos, typerNanos.nanos)
-
- def showRelPatmat(timer: Timer) =
- timer+showPercent(timer.nanos, patmatNanos.nanos)
-
- def showCounts[T](counts: scala.collection.mutable.Map[T, Int]) =
- counts.toSeq.sortWith(_._2 > _._2).map {
- case (cls: Class[_], cnt) =>
- cls.toString.substring(cls.toString.lastIndexOf("$") + 1)+": "+cnt
- case (o, cnt) =>
- o.toString +": "+cnt
- }
-
- def print(phase: Phase) = if (phasesShown contains phase.name) {
- inform("*** Cumulative statistics at phase " + phase)
- inform("#created tree nodes : " + nodeCount)
- inform("#created tree nodes by type: "+showCounts(nodeByType))
- if (phase.name != "parser") {
- val counts = new ClassCounts
- for (u <- currentRun.units; t <- u.body) counts(t.getClass) += 1
- inform("#retained nodes : " + counts.values.sum)
- inform("#retained nodes by type : " + showCounts(counts))
- inform("#typechecked identifiers : " + typedIdentCount)
- inform("#typechecked selections : " + typedSelectCount)
- inform("#typechecked applications: " + typedApplyCount)
- inform("#raw type creations : " + rawTypeCount)
- inform(" of which in failed : " + rawTypeFailed)
- inform(" of which in implicits : " + rawTypeImpl)
- inform("#unique types : " + uniqueTypeCount)
- inform("#symbols : " + symbolCount)
- inform(" of which type symbols : " + typeSymbolCount)
- inform(" of which class symbols : " + classSymbolCount)
- inform("#base type seqs : " + baseTypeSeqCount)
- inform("avg base type seq length : " + baseTypeSeqLenTotal.value.toFloat / baseTypeSeqCount.value)
- inform("#singleton base type seqs: " + singletonBaseTypeSeqCount)
- inform("#compound base type seqs : " + compoundBaseTypeSeqCount)
- inform("#typeref base type seqs : " + typerefBaseTypeSeqCount)
- inform("#findMember ops : " + findMemberCount)
- inform(" of which in failed : " + findMemberFailed)
- inform(" of which in implicits : " + findMemberImpl)
- inform("#notfound member : " + noMemberCount)
- inform("#multiple member : " + multMemberCount)
- inform("#asSeenFrom ops : " + asSeenFromCount)
- inform("#subtype : " + subtypeCount)
- inform(" of which in failed : " + subtypeFailed)
- inform(" of which in implicits : " + subtypeImpl)
- inform(" of which in app impl : " + subtypeAppInfos)
- inform(" of which in improv : " + subtypeImprovCount)
- inform("#sametype : " + sametypeCount)
- inform("#toplevel lub : " + lubCount)
- inform("#all lub : " + nestedLubCount)
- inform("ms type-flow-analysis: " + analysis.timer.millis)
-
- if (phase.name == "typer") {
- inform("time spent typechecking : " + showRelTyper(typerNanos))
- inform("time classfilereading : " + showRelTyper(classReadNanos))
- inform("time spent in implicits : " + showRelTyper(implicitNanos))
- inform(" successful in scope : " + showRelTyper(inscopeSucceedNanos))
- inform(" failed in scope : " + showRelTyper(inscopeFailNanos))
- inform(" successful of type : " + showRelTyper(oftypeSucceedNanos))
- inform(" failed of type : " + showRelTyper(oftypeFailNanos))
- inform(" assembling parts : " + showRelTyper(subtypeETNanos))
- inform(" matchesPT : " + showRelTyper(matchesPtNanos))
- inform("implicit cache hits : " + showRelative(implicitCacheHits.value + implicitCacheMisses.value)(implicitCacheHits.value))
- inform("time spent in failed : " + showRelTyper(failedSilentNanos))
- inform(" failed apply : " + showRelTyper(failedApplyNanos))
- inform(" failed op= : " + showRelTyper(failedOpEqNanos))
- inform("time spent ref scanning : " + showRelTyper(isReferencedNanos))
- inform("time spent in lubs : " + showRelTyper(lubNanos))
- inform("micros by tree node : " + showCounts(microsByType))
- inform("#visits by tree node : " + showCounts(visitsByType))
- val average = new ClassCounts
- for (c <- microsByType.keysIterator) average(c) = microsByType(c)/visitsByType(c)
- inform("avg micros by tree node : " + showCounts(average))
- inform("time spent in <:< : " + showRelTyper(subtypeNanos))
- inform("time spent in findmember : " + showRelTyper(findMemberNanos))
- inform("time spent in asSeenFrom : " + showRelTyper(asSeenFromNanos))
- inform("#implicit searches : " + implicitSearchCount)
- inform("#tried, plausible, matching, typed, found implicits: "+triedImplicits+", "+plausiblyCompatibleImplicits+", "+matchingImplicits+", "+typedImplicits+", "+foundImplicits)
- inform("#implicit improves tests : " + improvesCount)
- inform("#implicit improves cached : " + improvesCachedCount)
- inform("#implicit inscope hits : " + inscopeImplicitHits)
- inform("#implicit oftype hits : " + oftypeImplicitHits)
- inform("#macro expansions : " + macroExpandCount)
- inform("#time spent in macroExpand : " + showRelTyper(macroExpandNanos))
- }
-
- if (ctr1 != null) inform("#ctr1 : " + ctr1)
- if (ctr2 != null) inform("#ctr2 : " + ctr2)
- if (ctr3 != null) inform("#ctr3 : " + ctr3)
- if (ctr4 != null) inform("#ctr4 : " + ctr4)
- if (counter1 != null) inform("#counter1 : " + counter1)
- if (counter2 != null) inform("#counter2 : " + counter2)
- if (timer1 != null) inform("#timer1 : " + timer1)
- if (timer2 != null) inform("#timer2 : " + timer2)
- //for (t <- uniques.iterator) println("unique: "+t)
-
- if (phase.name == "patmat") {
- inform("time spent in patmat : " + patmatNanos )
- inform(" of which DPLL : " + showRelPatmat(patmatAnaDPLL ))
- inform("of which in CNF conversion : " + showRelPatmat(patmatCNF ))
- inform(" CNF size counts : " + showCounts(patmatCNFSizes ))
- inform("of which variable equality : " + showRelPatmat(patmatAnaVarEq ))
- inform(" of which in exhaustivity : " + showRelPatmat(patmatAnaExhaust))
- inform("of which in unreachability : " + showRelPatmat(patmatAnaReach ))
- }
- }
- }
-}
diff --git a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala
new file mode 100644
index 0000000000..f6a1ae1414
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala
@@ -0,0 +1,38 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc
+package util
+
+import reflect.internal.util.Statistics
+
+abstract class StatisticsInfo {
+
+ val global: Global
+ import global._
+ import reflect.internal.TreesStats.nodeByType
+
+ val phasesShown = List("parser", "typer", "patmat", "erasure", "cleanup")
+
+ val retainedCount = Statistics.newCounter("#retained tree nodes")
+ val retainedByType = Statistics.newByClass("#retained tree nodes by type")(Statistics.newCounter(""))
+
+ def print(phase: Phase) = if (phasesShown contains phase.name) {
+ inform("*** Cumulative statistics at phase " + phase)
+ retainedCount.value = 0
+ for (c <- retainedByType.keys)
+ retainedByType(c).value = 0
+ for (u <- currentRun.units; t <- u.body) {
+ retainedCount.value += 1
+ retainedByType(t.getClass).value += 1
+ }
+
+ val quants =
+ if (phase.name == "parser") Seq(treeNodeCount, nodeByType, retainedCount, retainedByType)
+ else Statistics.allQuantities
+
+ for (q <- quants if q.showAt(phase.name)) inform(q.line)
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index 5f78671012..fa758edf05 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -8,7 +8,7 @@ package internal
// todo implement in terms of BitSet
import scala.collection.{ mutable, immutable }
import math.max
-import util.Statistics._
+import util.Statistics
/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types
* of a type. It characterized by the following two laws:
@@ -28,6 +28,7 @@ import util.Statistics._
trait BaseTypeSeqs {
this: SymbolTable =>
import definitions._
+ import BaseTypeSeqsStats._
protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
new BaseTypeSeq(parents, elems)
@@ -38,8 +39,8 @@ trait BaseTypeSeqs {
*/
class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
- incCounter(baseTypeSeqCount)
- incCounter(baseTypeSeqLenTotal, elems.length)
+ Statistics.incCounter(baseTypeSeqCount)
+ Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
/** The number of types in the sequence */
def length: Int = elems.length
@@ -231,3 +232,8 @@ trait BaseTypeSeqs {
val CyclicInheritance = new Throwable
}
+
+object BaseTypeSeqsStats {
+ val baseTypeSeqCount = Statistics.newCounter("#base type seqs")
+ val baseTypeSeqLenTotal = Statistics.newRelCounter("avg base type seq length", baseTypeSeqCount)
+}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 288eb63332..4b0ceeb86b 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -8,18 +8,17 @@ package internal
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.ListBuffer
-import util.Statistics._
+import util.Statistics
import Flags._
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
+ import SymbolsStats._
protected var ids = 0
val emptySymbolArray = new Array[Symbol](0)
- def symbolCount = ids // statistics
-
protected def nextId() = { ids += 1; ids }
/** Used for deciding in the IDE whether we can interrupt the compiler */
@@ -666,7 +665,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isClassLocalToConstructor = false
final def isDerivedValueClass =
- isClass && !hasFlag(PACKAGE | TRAIT) &&
+ isClass && !hasFlag(PACKAGE | TRAIT) &&
info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass
final def isMethodWithExtension =
@@ -2713,7 +2712,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
- incCounter(typeSymbolCount)
+ Statistics.incCounter(typeSymbolCount)
}
implicit val TypeSymbolTag = ClassTag[TypeSymbol](classOf[TypeSymbol])
@@ -2929,7 +2928,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def children = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
- incCounter(classSymbolCount)
+ Statistics.incCounter(classSymbolCount)
}
implicit val ClassSymbolTag = ClassTag[ClassSymbol](classOf[ClassSymbol])
@@ -3188,4 +3187,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
}
+
+ Statistics.newView("#symbols")(ids)
+}
+
+object SymbolsStats {
+ val typeSymbolCount = Statistics.newCounter("#type symbols")
+ val classSymbolCount = Statistics.newCounter("#class symbols")
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 75bb0e6d49..e100e0c1a3 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -9,6 +9,7 @@ package internal
import Flags._
import base.Attachments
import collection.mutable.{ListBuffer, LinkedHashSet}
+import util.Statistics
trait Trees extends api.Trees { self: SymbolTable =>
@@ -18,6 +19,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
+ Statistics.incCounter(TreesStats.nodeByType, getClass)
+
@inline final def pos: Position = rawatt.pos
def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
def setPos(newpos: Position): this.type = { pos = newpos; this }
@@ -1592,4 +1595,11 @@ trait Trees extends api.Trees { self: SymbolTable =>
implicit val TypeBoundsTreeTag = ClassTag[TypeBoundsTree](classOf[TypeBoundsTree])
implicit val ExistentialTypeTreeTag = ClassTag[ExistentialTypeTree](classOf[ExistentialTypeTree])
implicit val TypeTreeTag = ClassTag[TypeTree](classOf[TypeTree])
+
+ val treeNodeCount = Statistics.newView("#created tree nodes")(nodeCount)
+}
+
+object TreesStats {
+ // statistics
+ val nodeByType = Statistics.newByClass("#created tree nodes by type")(Statistics.newCounter(""))
}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 8a4394bf1d..d4b895bcb4 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -13,8 +13,7 @@ import mutable.ListBuffer
import Flags._
import scala.util.control.ControlThrowable
import scala.annotation.tailrec
-import util.Statistics._
-import language.postfixOps
+import util.Statistics
/* A standard type pattern match:
case ErrorType =>
@@ -73,9 +72,7 @@ import language.postfixOps
trait Types extends api.Types { self: SymbolTable =>
import definitions._
-
- //statistics
- def uniqueTypeCount = if (uniques == null) 0 else uniques.size
+ import TypesStats._
private var explainSwitch = false
private final val emptySymbolSet = immutable.Set.empty[Symbol]
@@ -681,8 +678,8 @@ trait Types extends api.Types { self: SymbolTable =>
if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this
else {
// scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") {
- incCounter(asSeenFromCount)
- val start = startTimer(asSeenFromNanos)
+ Statistics.incCounter(asSeenFromCount)
+ val start = Statistics.startTimer(asSeenFromNanos)
val m = new AsSeenFromMap(pre.normalize, clazz)
val tp = m apply this
val tp1 = existentialAbstraction(m.capturedParams, tp)
@@ -690,7 +687,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (m.capturedSkolems.isEmpty) tp1
else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1)
- stopTimer(asSeenFromNanos, start)
+ Statistics.stopTimer(asSeenFromNanos, start)
result
}
}
@@ -828,26 +825,26 @@ trait Types extends api.Types { self: SymbolTable =>
}
def stat_<:<(that: Type): Boolean = {
- incCounter(subtypeCount)
- val start = startTimer(subtypeNanos)
+ Statistics.incCounter(subtypeCount)
+ val start = Statistics.startTimer(subtypeNanos)
val result =
(this eq that) ||
(if (explainSwitch) explain("<:", isSubType, this, that)
else isSubType(this, that, AnyDepth))
- stopTimer(subtypeNanos, start)
+ Statistics.stopTimer(subtypeNanos, start)
result
}
/** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
*/
def weak_<:<(that: Type): Boolean = {
- incCounter(subtypeCount)
- val start = startTimer(subtypeNanos)
+ Statistics.incCounter(subtypeCount)
+ val start = Statistics.startTimer(subtypeNanos)
val result =
((this eq that) ||
(if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
else isWeakSubType(this, that)))
- stopTimer(subtypeNanos, start)
+ Statistics.stopTimer(subtypeNanos, start)
result
}
@@ -1020,8 +1017,8 @@ trait Types extends api.Types { self: SymbolTable =>
// See (t0851) for a situation where this happens.
val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
- incCounter(findMemberCount)
- val start = startTimer(findMemberNanos)
+ Statistics.incCounter(findMemberCount)
+ val start = Statistics.startTimer(findMemberNanos)
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var members: Scope = null
@@ -1048,7 +1045,7 @@ trait Types extends api.Types { self: SymbolTable =>
!sym.isPrivateLocal ||
(bcs0.head.hasTransOwner(bcs.head)))) {
if (name.isTypeName || stableOnly && sym.isStable) {
- stopTimer(findMemberNanos, start)
+ Statistics.stopTimer(findMemberNanos, start)
if (suspension ne null) suspension foreach (_.suspended = false)
return sym
} else if (member == NoSymbol) {
@@ -1094,13 +1091,13 @@ trait Types extends api.Types { self: SymbolTable =>
} // while (!bcs.isEmpty)
excluded = excludedFlags
} // while (continue)
- stopTimer(findMemberNanos, start)
+ Statistics.stopTimer(findMemberNanos, start)
if (suspension ne null) suspension foreach (_.suspended = false)
if (members eq null) {
- if (member == NoSymbol) incCounter(noMemberCount)
+ if (member == NoSymbol) Statistics.incCounter(noMemberCount)
member
} else {
- incCounter(multMemberCount)
+ Statistics.incCounter(multMemberCount)
baseClasses.head.newOverloaded(this, members.toList)
}
}
@@ -1185,7 +1182,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
- incCounter(singletonBaseTypeSeqCount)
+ Statistics.incCounter(singletonBaseTypeSeqCount)
underlying.baseTypeSeq prepend this
}
override def isHigherKinded = false // singleton type classifies objects, thus must be kind *
@@ -1536,7 +1533,7 @@ trait Types extends api.Types { self: SymbolTable =>
val bts = copyRefinedType(tpe.asInstanceOf[RefinedType], tpe.parents map varToParam, varToParam mapOver tpe.decls).baseTypeSeq
tpe.baseTypeSeqCache = bts lateMap paramToVar
} else {
- incCounter(compoundBaseTypeSeqCount)
+ Statistics.incCounter(compoundBaseTypeSeqCount)
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache = if (tpe.typeSymbol.isRefinementClass)
tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe)
@@ -2392,7 +2389,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- incCounter(typerefBaseTypeSeqCount)
+ Statistics.incCounter(typerefBaseTypeSeqCount)
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache = tpe.baseTypeSeqImpl
}
@@ -3702,7 +3699,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var uniqueRunId = NoRunId
protected def unique[T <: Type](tp: T): T = {
- incCounter(rawTypeCount)
+ Statistics.incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.HashSet[Type]("uniques", initialUniquesCapacity)
uniqueRunId = currentRunId
@@ -5104,7 +5101,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** Do `tp1` and `tp2` denote equivalent types? */
def isSameType(tp1: Type, tp2: Type): Boolean = try {
- incCounter(sametypeCount)
+ Statistics.incCounter(sametypeCount)
subsametypeRecursions += 1
undoLog undoUnless {
isSameType1(tp1, tp2)
@@ -6308,14 +6305,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => NothingClass.tpe
case List(t) => t
case _ =>
- incCounter(lubCount)
- val start = startTimer(lubNanos)
+ Statistics.incCounter(lubCount)
+ val start = Statistics.startTimer(lubNanos)
try {
lub(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
- stopTimer(lubNanos, start)
+ Statistics.stopTimer(lubNanos, start)
}
}
@@ -6431,7 +6428,7 @@ trait Types extends api.Types { self: SymbolTable =>
indent = indent + " "
assert(indent.length <= 100)
}
- incCounter(nestedLubCount)
+ Statistics.incCounter(nestedLubCount)
val res = lub0(ts)
if (printLubs) {
indent = indent stripSuffix " "
@@ -6456,14 +6453,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => AnyClass.tpe
case List(t) => t
case ts0 =>
- incCounter(lubCount)
- val start = startTimer(lubNanos)
+ Statistics.incCounter(lubCount)
+ val start = Statistics.startTimer(lubNanos)
try {
glbNorm(ts0, lubDepth(ts0))
} finally {
lubResults.clear()
glbResults.clear()
- stopTimer(lubNanos, start)
+ Statistics.stopTimer(lubNanos, start)
}
}
@@ -6578,7 +6575,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
// if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
- incCounter(nestedLubCount)
+ Statistics.incCounter(nestedLubCount)
val res = glb0(ts)
// if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
@@ -6871,4 +6868,27 @@ trait Types extends api.Types { self: SymbolTable =>
implicit val TypeBoundsTag = ClassTag[TypeBounds](classOf[TypeBounds])
implicit val TypeRefTag = ClassTag[TypeRef](classOf[TypeRef])
implicit val TypeTagg = ClassTag[Type](classOf[Type])
+
+ Statistics.newView("#unique types") { if (uniques == null) 0 else uniques.size }
+}
+
+object TypesStats {
+ import BaseTypeSeqsStats._
+ val rawTypeCount = Statistics.newCounter ("#raw type creations")
+ val asSeenFromCount = Statistics.newCounter ("#asSeenFrom ops")
+ val subtypeCount = Statistics.newCounter ("#subtype ops")
+ val sametypeCount = Statistics.newCounter ("#sametype ops")
+ val lubCount = Statistics.newCounter ("#toplevel lubs/glbs")
+ val nestedLubCount = Statistics.newCounter ("#all lubs/glbs")
+ val findMemberCount = Statistics.newCounter ("#findMember ops")
+ val noMemberCount = Statistics.newSubCounter(" of which not found", findMemberCount)
+ val multMemberCount = Statistics.newSubCounter(" of which multiple overloaded", findMemberCount)
+ val typerNanos = Statistics.newTimer ("time spent typechecking", "typer")
+ val lubNanos = Statistics.newSubTimer ("time spent in lubs", typerNanos)
+ val subtypeNanos = Statistics.newSubTimer ("time spent in <:<", typerNanos)
+ val findMemberNanos = Statistics.newSubTimer ("time spent in findmember", typerNanos)
+ val asSeenFromNanos = Statistics.newSubTimer ("time spent in asSeenFrom", typerNanos)
+ val compoundBaseTypeSeqCount = Statistics.newSubCounter(" of which for compound types", baseTypeSeqCount)
+ val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount)
+ val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount)
}
diff --git a/src/reflect/scala/reflect/internal/util/StatBase.scala b/src/reflect/scala/reflect/internal/util/StatBase.scala
deleted file mode 100644
index b033ff98bc..0000000000
--- a/src/reflect/scala/reflect/internal/util/StatBase.scala
+++ /dev/null
@@ -1,97 +0,0 @@
-package scala.reflect.internal.util
-
-class StatBase {
-
- private var _enabled = false
-
- def enabled = _enabled
- def enabled_=(cond: Boolean) = {
- if (cond && !_enabled) {
- val test = new Timer()
- val start = System.nanoTime()
- var total = 0L
- for (i <- 1 to 10000) {
- val time = System.nanoTime()
- total += System.nanoTime() - time
- }
- val total2 = System.nanoTime() - start
- println("Enabling statistics, measuring overhead = "+
- total/10000.0+"ns to "+total2/10000.0+"ns per timer")
- _enabled = true
- }
- }
-
- def currentTime() =
- if (_enabled) System.nanoTime() else 0L
-
- def showPercent(x: Double, base: Double) =
- if (base == 0) "" else " ("+"%2.1f".format(x / base * 100)+"%)"
-
- def incCounter(c: Counter) {
- if (_enabled) c.value += 1
- }
-
- def incCounter(c: Counter, delta: Int) {
- if (_enabled) c.value += delta
- }
-
- def startCounter(sc: SubCounter): IntPair =
- if (_enabled) sc.start() else null
-
- def stopCounter(sc: SubCounter, start: IntPair) {
- if (_enabled) sc.stop(start)
- }
-
- def startTimer(tm: Timer): LongPair =
- if (_enabled) tm.start() else null
-
- def stopTimer(tm: Timer, start: LongPair) {
- if (_enabled) tm.stop(start)
- }
-
- case class IntPair(x: Int, y: Int)
- case class LongPair(x: Long, y: Long)
-
- class Counter {
- var value: Int = 0
- override def toString = value.toString
- }
-
- class SubCounter(c: Counter) {
- var value: Int = 0
- def start(): IntPair =
- if (_enabled) IntPair(value, c.value) else null
- def stop(prev: IntPair) {
- if (_enabled) {
- val IntPair(value0, cvalue0) = prev
- value = value0 + c.value - cvalue0
- }
- }
- override def toString =
- value+showPercent(value, c.value)
- }
-
- class Timer {
- var nanos: Long = 0
- var timings = 0
- def start(): LongPair =
- if (_enabled) {
- timings += 1
- LongPair(nanos, System.nanoTime())
- } else null
- def stop(prev: LongPair) {
- if (_enabled) {
- val LongPair(nanos0, start) = prev
- nanos = nanos0 + System.nanoTime() - start
- timings += 1
- }
- }
- override def toString = (timings/2)+" spans, "+nanos.toString+"ns"
- }
-
- import Predef.Class
-
- class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] {
- override def default(key: Class[_]) = 0
- }
-} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala
index de0830aa3a..57c9e98174 100644
--- a/src/reflect/scala/reflect/internal/util/Statistics.scala
+++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
@@ -1,37 +1,232 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
package scala.reflect.internal.util
-class Statistics extends StatBase {
- val singletonBaseTypeSeqCount = new Counter
- val compoundBaseTypeSeqCount = new Counter
- val typerefBaseTypeSeqCount = new Counter
- val findMemberCount = new Counter
- val noMemberCount = new Counter
- val multMemberCount = new Counter
- val findMemberNanos = new Timer
- val asSeenFromCount = new Counter
- val asSeenFromNanos = new Timer
- val subtypeCount = new Counter
- val subtypeNanos = new Timer
- val sametypeCount = new Counter
- val rawTypeCount = new Counter
- val rawTypeFailed = new SubCounter(rawTypeCount)
- val findMemberFailed = new SubCounter(findMemberCount)
- val subtypeFailed = new SubCounter(subtypeCount)
- val rawTypeImpl = new SubCounter(rawTypeCount)
- val findMemberImpl = new SubCounter(findMemberCount)
- val subtypeImpl = new SubCounter(subtypeCount)
- val baseTypeSeqCount = new Counter
- val baseTypeSeqLenTotal = new Counter
- val typeSymbolCount = new Counter
- val classSymbolCount = new Counter
- val lubCount = new Counter
- val nestedLubCount = new Counter
- val lubNanos = new Timer
-}
+import collection.mutable
+
+object Statistics {
+
+ /** If enabled, increment counter by one */
+ @inline final def incCounter(c: Counter) {
+ if (_enabled && c != null) c.value += 1
+ }
+
+ /** If enabled, increment counter by given delta */
+ @inline final def incCounter(c: Counter, delta: Int) {
+ 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 (_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 (_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)) {
+ if (_enabled && sc != null) sc.stop(start)
+ }
+
+ /** If enabled, start timer */
+ @inline final def startTimer(tm: Timer): (Long, Long) =
+ if (_enabled && tm != null) tm.start() else null
+
+ /** If enabled, stop timer */
+ @inline final def stopTimer(tm: Timer, start: (Long, Long)) {
+ if (_enabled && tm != null) tm.stop(start)
+ }
+
+ /** If enabled, push and start a new timer in timer stack */
+ @inline final def pushTimerClass(timers: ByClassTimerStack, cls: Class[_]): (Long, Long) =
+ if (_enabled && timers != null) timers.push(cls) else null
+
+ /** If enabled, stop and pop timer from timer stack */
+ @inline final def popTimerClass(timers: ByClassTimerStack, prev: (Long, Long)) {
+ if (_enabled && timers != null) timers.pop(prev)
+ }
+
+ /** Create a new counter that shows as `prefix` and is active in given phases */
+ def newCounter(prefix: String, phases: String*) = new Counter(prefix, phases)
+
+ /** Create a new relative counter that shows as `prefix` and is active
+ * in the same phases as its base counter. Relative counters print as percentages
+ * of their base counters.
+ */
+ def newRelCounter(prefix: String, ctr: Counter): Counter = new RelCounter(prefix, ctr)
+
+ /** Create a new subcounter that shows as `prefix` and is active
+ * in the same phases as its base counter. Subcounters can track
+ * increments of their base counters and print as percentages
+ * of their base counters.
+ */
+ def newSubCounter(prefix: String, ctr: Counter): SubCounter = new SubCounter(prefix, ctr)
+
+ /** Create a new counter that shows as `prefix` and is active in given phases */
+ def newTimer(prefix: String, phases: String*): Timer = new Timer(prefix, phases)
+
+ /** Create a new subtimer that shows as `prefix` and is active
+ * in the same phases as its base timer. Subtimers can track
+ * increments of their base timers and print as percentages
+ * of their base timers.
+ */
+ def newSubTimer(prefix: String, timer: Timer): Timer = new SubTimer(prefix, timer)
+
+ /** Create a new view that shows as `prefix` and is active in given phases.
+ * The view always reflects the current value of `quant` as a quantity.
+ */
+ def newView(prefix: String, phases: String*)(quant: => Any): View = new View(prefix, phases,
+quant)
-object Statistics extends Statistics
+ /** Create a new quantity map that shows as `prefix` and is active in given phases.
+ */
+ def newQuantMap[K, V <% Ordered[V]](prefix: String, phases: String*)(initValue: => V): QuantMap[K, V] = new QuantMap(prefix, phases, initValue)
+ /** Same as newQuantMap, where the key type is fixed to be Class[_] */
+ def newByClass[V <% Ordered[V]](prefix: String, phases: String*)(initValue: => V): QuantMap[Class[_], V] = new QuantMap(prefix, phases, initValue)
+
+ /** Create a new timer stack map, indexed by Class[_]. */
+ def newByClassTimerStack(prefix: String, underlying: Timer) = new ByClassTimerStack(prefix, underlying)
+
+ def allQuantities: Iterable[Quantity] =
+ for ((q, _) <- qs if !q.isInstanceOf[SubQuantity];
+ r <- q :: q.children.toList if r.prefix.nonEmpty) yield r
+
+ private def showPercent(x: Double, base: Double) =
+ if (base == 0) "" else f" (${x / base * 100}%2.1f%)"
+
+ trait Quantity {
+ qs += (this -> ())
+ val prefix: String
+ val phases: Seq[String]
+ def showAt(phase: String) = phases.isEmpty || (phases contains phase)
+ def line = f"$prefix%-30s: ${this}"
+ val children = new mutable.ListBuffer[Quantity]
+ }
+
+ trait SubQuantity extends Quantity {
+ protected def underlying: Quantity
+ underlying.children += this
+ }
+
+ class Counter(val prefix: String, val phases: Seq[String]) extends Quantity with Ordered[Counter] {
+ var value: Int = 0
+ def compare(that: Counter): Int =
+ if (this.value < that.value) -1
+ else if (this.value > that.value) 1
+ else 0
+ override def toString = value.toString
+ }
+
+ class View(val prefix: String, val phases: Seq[String], quant: => Any) extends Quantity {
+ override def toString = quant.toString
+ }
+
+ private class RelCounter(prefix: String, val underlying: Counter) extends Counter(prefix, underlying.phases) with SubQuantity {
+ override def toString =
+ if (value == 0) "0"
+ else {
+ assert(underlying.value != 0, prefix+"/"+underlying.line)
+ f"${value.toFloat / underlying.value}%2.1f"
+ }
+ }
+
+ class SubCounter(prefix: String, override val underlying: Counter) extends Counter(prefix, underlying.phases) with SubQuantity {
+ def start() = (value, underlying.value)
+ def stop(prev: (Int, Int)) {
+ val (value0, uvalue0) = prev
+ value = value0 + underlying.value - uvalue0
+ }
+ override def toString =
+ value + showPercent(value, underlying.value)
+ }
+
+ class Timer(val prefix: String, val phases: Seq[String]) extends Quantity with Ordered[Timer] {
+ var nanos: Long = 0
+ var timings = 0
+ def compare(that: Timer): Int =
+ if (this.nanos < that.nanos) -1
+ else if (this.nanos > that.nanos) 1
+ else 0
+ def start() = {
+ (nanos, System.nanoTime())
+ }
+ def stop(prev: (Long, Long)) {
+ val (nanos0, start) = prev
+ nanos = nanos0 + System.nanoTime() - start
+ timings += 1
+ }
+ override def toString = s"$timings spans, ${nanos/1000}ms"
+ }
+
+ private class SubTimer(prefix: String, override val underlying: Timer) extends Timer(prefix, underlying.phases) with SubQuantity {
+ override def toString: String = super.toString + showPercent(nanos, underlying.nanos)
+ }
+
+ /** A mutable map quantity where missing elements are automatically inserted
+ * on access by executing `initValue`.
+ */
+ class QuantMap[K, V <% Ordered[V]](val prefix: String, val phases: Seq[String], initValue: => V)
+ extends scala.collection.mutable.HashMap[K, V] with Quantity {
+ override def default(key: K) = {
+ val elem = initValue
+ this(key) = elem
+ elem
+ }
+ override def toString =
+ this.toSeq.sortWith(_._2 > _._2).map {
+ case (cls: Class[_], elem) =>
+ s"${cls.toString.substring(cls.toString.lastIndexOf("$") + 1)}: $elem"
+ case (key, elem) =>
+ s"$key: $elem"
+ }.mkString(", ")
+ }
+
+ /** A mutable map quantity that takes class keys to subtimer values, relative to
+ * some `underlying` timer. In addition, class timers can be pushed and popped.
+ * Pushing the timer for a class means stopping the currently active timer.
+ */
+ class ByClassTimerStack(prefix: String, val underlying: Timer)
+ extends QuantMap[Class[_], Timer](prefix, underlying.phases, new SubTimer("", underlying)) with SubQuantity {
+ private var elems: List[(Timer, Long)] = Nil
+ def push(cls: Class[_]): (Long, Long) = {
+ val topTimer = this(cls)
+ elems = (topTimer, 0L) :: elems
+ topTimer.start()
+ }
+ def pop(prev: (Long, Long)) = {
+ val (nanos0, start) = prev
+ val duration = System.nanoTime() - start
+ val (topTimer, nestedNanos) :: rest = elems
+ topTimer.nanos = nanos0 + duration - nestedNanos
+ topTimer.timings += 1
+ elems = rest match {
+ case (outerTimer, outerNested) :: elems1 =>
+ (outerTimer, outerNested + duration) :: elems1
+ case Nil =>
+ Nil
+ }
+ }
+ }
+
+ private var _enabled = false
+ private val qs = new mutable.WeakHashMap[Quantity, Unit]
+
+ def enabled = _enabled
+ def enabled_=(cond: Boolean) = {
+ if (cond && !_enabled) {
+ val test = new Timer("", Nil)
+ val start = System.nanoTime()
+ var total = 0L
+ for (i <- 1 to 10000) {
+ val time = System.nanoTime()
+ total += System.nanoTime() - time
+ }
+ val total2 = System.nanoTime() - start
+ println("Enabling statistics, measuring overhead = "+
+ total/10000.0+"ns to "+total2/10000.0+"ns per timer")
+ _enabled = true
+ }
+ }
+}