summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-12-18 02:13:07 +0000
committerPaul Phillips <paulp@improving.org>2010-12-18 02:13:07 +0000
commite911fdab94900bea85645201311f5ec2dc758fcd (patch)
treeb54f4b2a9cf4d8e6a55e93640ca26a3f796391b9 /src
parent9cbadc4d7cb11a303e500cc47af9e050b5adb96d (diff)
downloadscala-e911fdab94900bea85645201311f5ec2dc758fcd.tar.gz
scala-e911fdab94900bea85645201311f5ec2dc758fcd.tar.bz2
scala-e911fdab94900bea85645201311f5ec2dc758fcd.zip
Added some infrastructure for tracking and disp...
Added some infrastructure for tracking and displaying information. Used it to generate phase timing tables. Couldn't bring myself to add another option so it's temporarily behind a system property until I sort out the output options. % scalac -Dscala.timings foo.scala // or: ant -Djvm.opts="-Dscala.timings" [...] phase id ms share -------------- -- ---- ----- typer 4 5816 44.94 mixin 20 1220 9.43 specialize 13 1179 9.11 erasure 15 916 7.08 ...etc. No review.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala19
-rw-r--r--src/compiler/scala/tools/nsc/Phase.scala34
-rw-r--r--src/compiler/scala/tools/nsc/PhaseAssembly.scala34
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugins.scala8
-rw-r--r--src/compiler/scala/tools/nsc/util/TableDef.scala2
5 files changed, 73 insertions, 24 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 45fb691904..1f10d304c1 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -144,10 +144,13 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (opt.fatalWarnings) globalError(msg)
else reporter.warning(NoPosition, msg)
+ private def elapsedMessage(msg: String, start: Long) =
+ msg + " in " + (currentTime - start) + "ms"
+
def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg))
def informProgress(msg: String) = if (opt.verbose) inform("[" + msg + "]")
def inform[T](msg: String, value: T): T = returning(value)(x => inform(msg + x))
- def informTime(msg: String, start: Long) = informProgress(msg + " in " + (currentTime - start) + "ms")
+ def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start))
def logError(msg: String, t: Throwable): Unit = ()
def log(msg: => AnyRef): Unit = if (opt.logPhase) inform("[log " + phase + "] " + msg)
@@ -231,6 +234,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
def encoding = optSetting[String](settings.encoding)
def sourceReader = optSetting[String](settings.sourceReader)
+ // XXX: short term, but I can't bear to add another option.
+ // scalac -Dscala.timings will make this true.
+ def timings = system.props contains "scala.timings"
+
def debug = settings.debug.value
def deprecation = settings.deprecation.value
def experimental = settings.Xexperimental.value
@@ -605,6 +612,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
/* The set of phase objects that is the basis for the compiler phase chain */
protected lazy val phasesSet = new mutable.HashSet[SubComponent]
protected lazy val phasesDescMap = new mutable.HashMap[SubComponent, String] withDefaultValue ""
+ private lazy val phaseTimings = new Phase.TimingModel // tracking phase stats
protected def addToPhasesSet(sub: SubComponent, descr: String) {
phasesSet += sub
phasesDescMap(sub) = descr
@@ -868,6 +876,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
else globalPhase.run
+ // progress update
+ informTime(globalPhase.description, startTime)
+ phaseTimings(globalPhase) = currentTime - startTime
+
// write icode to *.icode files
if (opt.writeICode && (runIsAt(icodePhase) || opt.printPhase && runIsPast(icodePhase)))
writeICode()
@@ -885,8 +897,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (opt.browsePhase)
treeBrowser browse (phase.name, units)
- // progress update
- informTime(globalPhase.description, startTime)
+ // move the pointer
globalPhase = globalPhase.next
// run tree/icode checkers
@@ -903,6 +914,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
profiler.stopProfiling()
profiler.captureSnapshot()
}
+ if (opt.timings)
+ inform(phaseTimings.formatted)
// If no phase was specified for -Xshow-class/object, show it now.
if (settings.Yshow.isDefault)
diff --git a/src/compiler/scala/tools/nsc/Phase.scala b/src/compiler/scala/tools/nsc/Phase.scala
index 9726834b88..f4cdfdadee 100644
--- a/src/compiler/scala/tools/nsc/Phase.scala
+++ b/src/compiler/scala/tools/nsc/Phase.scala
@@ -6,6 +6,7 @@
package scala.tools.nsc
import symtab.Flags
+import util.TableDef
abstract class Phase(val prev: Phase) {
@@ -48,4 +49,37 @@ abstract class Phase(val prev: Phase) {
}
}
+object Phase {
+ val MaxPhases = 64
+
+ /** A class for tracking something about each phase.
+ */
+ class Model[T: Manifest] {
+ case class Cell(ph: Phase, value: T) {
+ def name = ph.name
+ def id = ph.id
+ }
+ val values = new Array[Cell](MaxPhases + 1)
+ def results = values filterNot (_ == null)
+ def apply(ph: Phase): T = values(ph.id).value
+ def update(ph: Phase, value: T): Unit = values(ph.id) = Cell(ph, value)
+ }
+ /** A class for recording the elapsed time of each phase in the
+ * interests of generating a classy and informative table.
+ */
+ class TimingModel extends Model[Long] {
+ var total: Long = 0
+ def table() = {
+ total = results map (_.value) sum;
+ new Format.Table(results sortBy (-_.value))
+ }
+ object Format extends TableDef[Cell] {
+ >> ("phase" -> (_.name)) >+ " "
+ << ("id" -> (_.id)) >+ " "
+ >> ("ms" -> (_.value)) >+ " "
+ << ("share" -> (_.value.toDouble * 100 / total formatted "%.2f"))
+ }
+ def formatted = "" + table()
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
index c121098d56..9a306d939c 100644
--- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala
+++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
@@ -6,8 +6,8 @@
package scala.tools.nsc
-import scala.collection.mutable.{HashSet, HashMap}
-import java.io.{BufferedWriter, FileWriter}
+import java.io.{ BufferedWriter, FileWriter }
+import scala.collection.mutable
/**
* PhaseAssembly
@@ -15,7 +15,8 @@ import java.io.{BufferedWriter, FileWriter}
* the rest of the compiler. See SIP 00002
*
*/
-trait PhaseAssembly { self: Global =>
+trait PhaseAssembly {
+ self: Global =>
/**
* Aux datastructure for solving the constraint system
@@ -35,8 +36,8 @@ trait PhaseAssembly { self: Global =>
class Node(name: String) {
val phasename = name
var phaseobj: Option[List[SubComponent]] = None
- val after = new HashSet[Edge]()
- var before = new HashSet[Edge]()
+ val after = new mutable.HashSet[Edge]()
+ var before = new mutable.HashSet[Edge]()
var visited = false
var level = 0
@@ -46,8 +47,8 @@ trait PhaseAssembly { self: Global =>
}
}
- val nodes = new HashMap[String,Node]()
- val edges = new HashSet[Edge]()
+ val nodes = new mutable.HashMap[String,Node]()
+ val edges = new mutable.HashSet[Edge]()
/* Given a phase object, get the node for this phase object. If the
* node object does not exist, then create it.
@@ -184,22 +185,19 @@ trait PhaseAssembly { self: Global =>
* dependency on something that is dropped.
*/
def removeDanglingNodes() {
- var dnodes = nodes.valuesIterator filter (_.phaseobj.isEmpty)
- for (node <- dnodes) {
+ for (node <- nodes.valuesIterator filter (_.phaseobj.isEmpty)) {
val msg = "dropping dependency on node with no phase object: "+node.phasename
informProgress(msg)
nodes -= node.phasename
+
for (edge <- node.before) {
edges -= edge
edge.frm.after -= edge
- edge.frm.phaseobj match {
- case Some(lsc) => if (! lsc.head.internal) warning(msg)
- case _ =>
- }
+ if (edge.frm.phaseobj exists (lsc => !lsc.head.internal))
+ warning(msg)
}
}
}
-
}
/* Method called from computePhaseDescriptors in class Global
@@ -241,7 +239,7 @@ trait PhaseAssembly { self: Global =>
/** Given the phases set, will build a dependency graph from the phases set
* Using the aux. method of the DependencyGraph to create nodes and egdes.
*/
- private def phasesSetToDepGraph(phsSet: HashSet[SubComponent]): DependencyGraph = {
+ private def phasesSetToDepGraph(phsSet: mutable.HashSet[SubComponent]): DependencyGraph = {
val graph = new DependencyGraph()
for (phs <- phsSet) {
@@ -283,9 +281,9 @@ trait PhaseAssembly { self: Global =>
* Plug-in supplied phases are marked as green nodes and hard links are marked as blue edges.
*/
private def graphToDotFile(graph: DependencyGraph, filename: String) {
- var sbuf = new StringBuilder
- var extnodes = new HashSet[graph.Node]()
- var fatnodes = new HashSet[graph.Node]()
+ val sbuf = new StringBuilder
+ val extnodes = new mutable.HashSet[graph.Node]()
+ val fatnodes = new mutable.HashSet[graph.Node]()
sbuf.append("digraph G {\n")
for (edge <- graph.edges) {
sbuf.append("\"" + edge.frm.allPhaseNames + "(" + edge.frm.level + ")" + "\"->\"" + edge.to.allPhaseNames + "(" + edge.to.level + ")" + "\"")
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
index 24962ee085..e2f4806c01 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
@@ -105,8 +105,12 @@ trait Plugins {
* Extract all phases supplied by plugins and add them to the phasesSet.
* @see phasesSet
*/
- protected def computePluginPhases(): Unit =
- phasesSet ++= (plugins flatMap (_.components))
+ protected def computePluginPhases(): Unit = {
+ // For reasons not yet apparent to me, plugins started appearing
+ // as null when I added phaseTimings to global.
+ if (plugins != null)
+ phasesSet ++= (plugins flatMap (_.components))
+ }
/** Summary of the options for all loaded plugins */
def pluginOptionsHelp: String =
diff --git a/src/compiler/scala/tools/nsc/util/TableDef.scala b/src/compiler/scala/tools/nsc/util/TableDef.scala
index b18eaaa400..10c63eeee2 100644
--- a/src/compiler/scala/tools/nsc/util/TableDef.scala
+++ b/src/compiler/scala/tools/nsc/util/TableDef.scala
@@ -4,7 +4,7 @@ package util
import TableDef._
/** A class for representing tabular data in a way that preserves
- * its inner beauty. See JavaStackFrame for an example usage.
+ * its inner beauty. See Exceptional for an example usage.
* One creates an instance of TableDef by defining the columns of
* the table, then uses that to create an instance of Table by
* passing in a sequence of rows.