summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala69
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala4
-rw-r--r--src/compiler/scala/tools/util/Profiling.scala15
-rw-r--r--src/yourkit/scala/tools/util/YourkitProfiling.scala45
-rwxr-xr-xtools/locker_scala8
-rwxr-xr-xtools/locker_scalac8
-rwxr-xr-xtools/lockercp10
-rwxr-xr-xtools/profile_scala17
-rwxr-xr-xtools/profile_scalac25
-rwxr-xr-xtools/quickcp6
10 files changed, 160 insertions, 47 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 244319a5ff..684490b84d 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -238,22 +238,23 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// 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
- def fatalWarnings = settings.Xwarnfatal.value
- def logClasspath = settings.Ylogcp.value
- def printLate = settings.printLate.value
- def printStats = settings.Ystatistics.value
- def profileClass = settings.YprofileClass.value
- def richExes = settings.YrichExes.value
- def showTrees = settings.Xshowtrees.value
- def target = settings.target.value
- def typerDebug = settings.Ytyperdebug.value
- def unchecked = settings.unchecked.value
- def verbose = settings.verbose.value
- def writeICode = settings.writeICode.value
- def declsOnly = false
+ def debug = settings.debug.value
+ def deprecation = settings.deprecation.value
+ def experimental = settings.Xexperimental.value
+ def fatalWarnings = settings.Xwarnfatal.value
+ def logClasspath = settings.Ylogcp.value
+ def printLate = settings.printLate.value
+ def printStats = settings.Ystatistics.value
+ def profileClass = settings.YprofileClass.value
+ def profileMem = settings.YprofileMem.value
+ def richExes = settings.YrichExes.value
+ def showTrees = settings.Xshowtrees.value
+ def target = settings.target.value
+ def typerDebug = settings.Ytyperdebug.value
+ def unchecked = settings.unchecked.value
+ def verbose = settings.verbose.value
+ def writeICode = settings.writeICode.value
+ def declsOnly = false
/** Flags as applied to the current or previous phase */
def browsePhase = isActive(settings.browse)
@@ -261,11 +262,13 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
def logPhase = isActive(settings.log)
def printPhase = isActive(settings.Xprint)
def showPhase = isActive(settings.Yshow)
- def profilePhase = isActive(settings.Yprofile) && !profileAll
+ def profCPUPhase = isActive(settings.Yprofile) && !profileAll
/** Derived values */
+ def noShow = settings.Yshow.isDefault
def showNames = List(showClass, showObject).flatten
def profileAll = settings.Yprofile.doAllPhases
+ def profileAny = !settings.Yprofile.isDefault || !settings.YprofileMem.isDefault
def jvm = target startsWith "jvm"
def msil = target == "msil"
def verboseDebug = debug && verbose
@@ -663,14 +666,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
/** To be initialized from firstPhase. */
private var terminalPhase: Phase = NoPhase
- if (settings.YprofileRes.value) {
- System.gc();
- print("Saving snapshot..")
- profiler.captureSnapshot()
- println("[saved]")
- specializeTypes.printSpecStats()
- }
-
/** Whether compilation should stop at or skip the phase with given name. */
protected def stopPhase(name: String) = settings.stop contains name
protected def skipPhase(name: String) = settings.skip contains name
@@ -872,12 +867,16 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val startTime = currentTime
phase = globalPhase
- if (opt.profilePhase) {
+ if (opt.profCPUPhase) {
inform("starting CPU profiling on phase " + globalPhase.name)
profiler profile globalPhase.run
}
else globalPhase.run
+ // Create a profiling generation for each phase's allocations
+ if (opt.profileAny)
+ profiler.advanceGeneration(globalPhase.name)
+
// progress update
informTime(globalPhase.description, startTime)
phaseTimings(globalPhase) = currentTime - startTime
@@ -912,15 +911,14 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
advancePhase
}
- if (opt.profileAll) {
+ if (opt.profileAll)
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)
+ // In case no phase was specified for -Xshow-class/object, show it now for sure.
+ if (opt.noShow)
showMembers()
if (reporter.hasErrors) {
@@ -943,6 +941,15 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
symSource.keys foreach (x => resetPackageClass(x.owner))
informTime("total", startTime)
+ // save heap snapshot if requested
+ if (opt.profileMem) {
+ inform("Saving heap snapshot, this could take a while...")
+ System.gc()
+ profiler.captureSnapshot()
+ inform("...done saving heap snapshot.")
+ specializeTypes.printSpecStats()
+ }
+
// record dependency data
if (!dependencyAnalysis.off)
dependencyAnalysis.saveDependencyAnalysis()
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 20a93edb5f..627fdac2d0 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -112,8 +112,8 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports.")
// Not actually doing anything, so disabled.
// val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values.")
- val Yprofile = PhasesSetting ("-Yprofile", "(Requires jvm -agentpath to contain yjgpagent) Profile")
- val YprofileRes = BooleanSetting ("-Yprofile-resident", "Profile memory, get heap snapshot after each compiler run (requires yjpagent, see above).")
+ val Yprofile = PhasesSetting ("-Yprofile", "(Requires jvm -agentpath to contain yjgpagent) Profile CPU usage of given phases.")
+ val YprofileMem = BooleanSetting ("-Yprofile-memory", "Profile memory, get heap snapshot after each compiler run (requires yjpagent, see above).")
val YprofileClass = StringSetting ("-Yprofile-class", "class", "Name of profiler class.", "scala.tools.util.YourkitProfiling")
val Yrecursion = IntSetting ("-Yrecursion", "Set recursion depth used when locking symbols.", 0, Some(0, Int.MaxValue), (_: String) => None)
val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.")
diff --git a/src/compiler/scala/tools/util/Profiling.scala b/src/compiler/scala/tools/util/Profiling.scala
index e0a1a0e2a0..aada795ee2 100644
--- a/src/compiler/scala/tools/util/Profiling.scala
+++ b/src/compiler/scala/tools/util/Profiling.scala
@@ -22,7 +22,13 @@ abstract class Profiling {
def stopProfiling(): Unit
def captureSnapshot(): Unit
- def profile[T](body: => T): T = {
+ def allocationFreq: Option[Int] // record every Nth allocation
+ def startRecordingAllocations(): Unit
+ def stopRecordingAllocations(): Unit
+
+ def profile[T](body: => T): T = profileCPU(body)
+
+ def profileCPU[T](body: => T): T = {
startProfiling()
val result = body
stopProfiling()
@@ -30,6 +36,13 @@ abstract class Profiling {
result
}
+ def profileMem[T](body: => T): T = {
+ startRecordingAllocations()
+ val result = body
+ stopRecordingAllocations()
+ result
+ }
+
/** Advance the current object generation.
*
* Each object on the heap is associated to a generation number. Generations
diff --git a/src/yourkit/scala/tools/util/YourkitProfiling.scala b/src/yourkit/scala/tools/util/YourkitProfiling.scala
index 9d166d9a03..fb07eb1101 100644
--- a/src/yourkit/scala/tools/util/YourkitProfiling.scala
+++ b/src/yourkit/scala/tools/util/YourkitProfiling.scala
@@ -2,34 +2,57 @@ package scala.tools
package util
import com.yourkit.api._
+import com.yourkit.runtime._
import nsc.io._
class YourkitProfiling extends Profiling {
@volatile private var active = false
- private var recordAllocation = false
+ @volatile private var freq: Option[Int] = None
lazy val controller = new Controller
+ def defaultFreq = 100
+ def allocationFreq = freq
+ def setAllocationFreq(x: Int) = freq = if (x <= 0) None else Some(x)
+
+ def startRecordingAllocations() = {
+ controller.startAllocationRecording(true, freq getOrElse defaultFreq, false, 0)
+ }
+ def stopRecordingAllocations() = {
+ controller.stopAllocationRecording()
+ }
+
def startProfiling(): Unit = {
if (isActive)
return
active = true
daemonize(true) {
- controller.startCPUProfiling(ProfilingModes.CPU_SAMPLING, Controller.DEFAULT_FILTERS)
- if (recordAllocation)
- controller.startAllocationRecording(true, 100, false, 0)
+ try {
+ controller.startCPUProfiling(ProfilingModes.CPU_SAMPLING, Controller.DEFAULT_FILTERS)
+ if (freq.isDefined)
+ startRecordingAllocations()
+ }
+ catch {
+ case _: PresentableException => () // if it's already running, no big deal
+ }
}
}
- def captureSnapshot() =
- daemonize(false)(controller.captureSnapshot(ProfilingModes.SNAPSHOT_WITH_HEAP))
+ def captureSnapshot() = {
+ daemonize(true)(controller.captureSnapshot(ProfilingModes.SNAPSHOT_WITH_HEAP))
+ }
def stopProfiling() = {
- if (recordAllocation)
- controller.stopAllocationRecording()
+ try {
+ if (freq.isDefined)
+ stopRecordingAllocations()
- controller.stopCPUProfiling()
- active = false
+ controller.stopCPUProfiling()
+ }
+ catch {
+ case _: PresentableException => () // if it's already running, no big deal
+ }
+ finally active = false
}
def advanceGeneration(desc: String) {
@@ -37,4 +60,4 @@ class YourkitProfiling extends Profiling {
}
def isActive = active
-} \ No newline at end of file
+}
diff --git a/tools/locker_scala b/tools/locker_scala
new file mode 100755
index 0000000000..4434c94bf3
--- /dev/null
+++ b/tools/locker_scala
@@ -0,0 +1,8 @@
+#!/bin/bash
+#
+
+THISDIR=`dirname $0`
+CP=`$THISDIR/lockercp`
+CLASS="scala.tools.nsc.MainGenericRunner"
+
+java -classpath "$CP" $CLASS -usejavacp "$@"
diff --git a/tools/locker_scalac b/tools/locker_scalac
new file mode 100755
index 0000000000..2ad153e929
--- /dev/null
+++ b/tools/locker_scalac
@@ -0,0 +1,8 @@
+#!/bin/bash
+#
+
+THISDIR=`dirname $0`
+CP=`$THISDIR/lockercp`
+CLASS="scala.tools.nsc.Main"
+
+java -classpath "$CP" $CLASS -usejavacp "$@"
diff --git a/tools/lockercp b/tools/lockercp
new file mode 100755
index 0000000000..3e8799596f
--- /dev/null
+++ b/tools/lockercp
@@ -0,0 +1,10 @@
+#!/bin/sh
+#
+
+THISDIR=`dirname $0`
+ABS=${THISDIR}/abspath
+LIBDIR=`$ABS $THISDIR/../lib`
+
+cp=`${THISDIR}/cpof ${THISDIR}/../build/locker/classes`
+
+echo ${cp}:$LIBDIR/fjbg.jar:$LIBDIR/msil.jar:$LIBDIR/forkjoin.jar:$LIBDIR/jline.jar:$LIBDIR/extra/'*'
diff --git a/tools/profile_scala b/tools/profile_scala
new file mode 100755
index 0000000000..037fc327bd
--- /dev/null
+++ b/tools/profile_scala
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+
+# Uses quick by default
+CLASSPATH=`tools/quickcp`
+
+AGENT=${YOURKIT_PATH:-/Applications/YourKit.app/bin/mac/libyjpagent.jnilib}
+
+java $JAVA_OPTS \
+ -classpath $CLASSPATH \
+ -agentpath:$AGENT=$YNP_STARTUP_OPTIONS \
+ scala.tools.nsc.MainGenericRunner -usejavacp \
+ -i <(cat <<EOF
+lazy val profiler = new scala.tools.util.YourkitProfiling { }
+import profiler._
+EOF
+) "$@"
diff --git a/tools/profile_scalac b/tools/profile_scalac
new file mode 100755
index 0000000000..f29b5b6fa4
--- /dev/null
+++ b/tools/profile_scalac
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# To influence behavior, you can set:
+#
+# YOURKIT_PATH
+# YOURKIT_PROFILE_PHASES
+# YNP_STARTUP_OPTIONS
+#
+
+# Start cpu sampling immediately
+DEFAULT_OPTS="sampling,onexit=snapshot"
+
+# Uses quick by default
+CLASSPATH=`tools/quickcp`
+
+AGENT=${YOURKIT_PATH:-/Applications/YourKit.app/bin/mac/libyjpagent.jnilib}
+OPTS=${YNP_STARTUP_OPTIONS:-$DEFAULT_OPTS}
+PHASES=${YOURKIT_PROFILE_PHASES:-all}
+
+java $JAVA_OPTS \
+ -classpath $CLASSPATH \
+ -agentpath:$AGENT=$OPTS \
+ scala.tools.nsc.Main -usejavacp \
+ -Yprofile:$PHASES \
+ "$@"
diff --git a/tools/quickcp b/tools/quickcp
index 0bfcad1941..dd5251d30f 100755
--- a/tools/quickcp
+++ b/tools/quickcp
@@ -2,7 +2,9 @@
#
THISDIR=`dirname $0`
+ABS=${THISDIR}/abspath
+LIBDIR=`$ABS $THISDIR/../lib`
+
cp=`${THISDIR}/cpof ${THISDIR}/../build/quick/classes`
-fjbg=`${THISDIR}/abspath ${THISDIR}/../lib/fjbg.jar`
-echo ${cp}:${fjbg}
+echo ${cp}:$LIBDIR/fjbg.jar:$LIBDIR/msil.jar:$LIBDIR/forkjoin.jar:$LIBDIR/jline.jar:$LIBDIR/extra/'*'