Skip to content

Commit 1c7775d

Browse files
committed
Profile more events, make the profiler more Scala3 idiomatic
1 parent 7697029 commit 1c7775d

File tree

7 files changed

+90
-29
lines changed

7 files changed

+90
-29
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ private sealed trait YSettings:
413413
//.withPostSetHook( _ => YprofileEnabled.value = true )
414414
val YprofileRunGcBetweenPhases: Setting[List[String]] = PhasesSetting(ForkSetting, "Yprofile-run-gc", "Run a GC between phases - this allows heap size to be accurate at the expense of more time. Specify a list of phases, or *", "_")
415415
//.withPostSetHook( _ => YprofileEnabled.value = true )
416-
val YprofileTrace: Setting[String] = StringSetting("-Yprofile-trace", "file", "Capture trace of compilation in Chrome Trace format", "profile.trace")
416+
val YprofileTrace: Setting[String] = StringSetting(ForkSetting, "Yprofile-trace", "file", "Capture trace of compilation in Chrome Trace format", "profile.trace")
417417
//.withPostSetHook( _ => YprofileEnabled.value = true )
418418

419419
// Experimental language features

compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.nio.channels.ClosedByInterruptException
88
import scala.util.control.NonFatal
99

1010
import dotty.tools.dotc.classpath.FileUtils.hasTastyExtension
11-
import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile }
11+
import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile, NoAbstractFile }
1212
import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
1313

1414
import Contexts.*, Symbols.*, Flags.*, SymDenotations.*, Types.*, Scopes.*, Names.*
@@ -331,7 +331,18 @@ abstract class SymbolLoader extends LazyType { self =>
331331
def description(using Context): String = s"proxy to ${self.description}"
332332
}
333333

334-
override def complete(root: SymDenotation)(using Context): Unit = {
334+
private inline def tryProfileCompletion[T](root: SymDenotation)(inline body: T)(using Context): T = {
335+
if ctx.profiler eq null
336+
then body
337+
else
338+
val sym = root.symbol
339+
val associatedFile = root.symbol.associatedFile match
340+
case file: AbstractFile => file
341+
case _ => NoAbstractFile
342+
ctx.profiler.onCompletion(sym, associatedFile)(body)
343+
}
344+
345+
override def complete(root: SymDenotation)(using Context): Unit = tryProfileCompletion(root) {
335346
def signalError(ex: Exception): Unit = {
336347
if (ctx.debug) ex.printStackTrace()
337348
val msg = ex.getMessage()
@@ -406,7 +417,6 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
406417

407418
def compilationUnitInfo: CompilationUnitInfo | Null = CompilationUnitInfo(classfile)
408419

409-
410420
def description(using Context): String = "class file " + classfile.toString
411421

412422
override def doComplete(root: SymDenotation)(using Context): Unit =

compiler/src/dotty/tools/dotc/profile/ChromeTrace.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ final class ChromeTrace(f: Path) extends Closeable {
6363
traceWriter.close()
6464
}
6565

66-
def traceDurationEvent(name: String, startNanos: Long, durationNanos: Long, tid: String = this.tid(), pidSuffix: String = ""): Unit = {
66+
def traceDurationEvent(name: String, startNanos: Long, durationNanos: Long, tid: String = this.tid(), pidSuffix: String = ""): Unit = synchronized {
6767
val durationMicros = nanosToMicros(durationNanos)
6868
val startMicros = nanosToMicros(startNanos)
6969
objStart()
@@ -85,7 +85,7 @@ final class ChromeTrace(f: Path) extends Closeable {
8585
str2("pid", pid, "-", pidSuffix)
8686
}
8787

88-
def traceCounterEvent(name: String, counterName: String, count: Long, processWide: Boolean): Unit = {
88+
def traceCounterEvent(name: String, counterName: String, count: Long, processWide: Boolean): Unit = synchronized {
8989
objStart()
9090
str("cat", "scalac")
9191
str("name", name)
@@ -104,7 +104,7 @@ final class ChromeTrace(f: Path) extends Closeable {
104104
def traceDurationEventStart(cat: String, name: String, colour: String = "", pidSuffix: String = tid()): Unit = traceDurationEventStartEnd(EventType.Start, cat, name, colour, pidSuffix)
105105
def traceDurationEventEnd(cat: String, name: String, colour: String = "", pidSuffix: String = tid()): Unit = traceDurationEventStartEnd(EventType.End, cat, name, colour, pidSuffix)
106106

107-
private def traceDurationEventStartEnd(eventType: String, cat: String, name: String, colour: String, pidSuffix: String = ""): Unit = {
107+
private def traceDurationEventStartEnd(eventType: String, cat: String, name: String, colour: String, pidSuffix: String = ""): Unit = synchronized {
108108
objStart()
109109
str("cat", cat)
110110
str("name", name)

compiler/src/dotty/tools/dotc/profile/Profiler.scala

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ import dotty.tools.dotc.core.Contexts.*
1616
import dotty.tools.dotc.CompilationUnit
1717
import dotty.tools.dotc.core.Types.Type
1818
import dotty.tools.dotc.core.Symbols.Symbol
19+
import dotty.tools.dotc.core.Flags
20+
import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
1921
import dotty.tools.io.AbstractFile
2022
import annotation.internal.sharable
23+
import dotty.tools.dotc.core.Symbols.NoSymbol
2124

2225
object Profiler {
2326
def apply()(using Context): Profiler =
@@ -78,15 +81,39 @@ sealed trait Profiler {
7881

7982
def afterPhase(phase: Phase, profileBefore: ProfileSnap): Unit
8083

84+
inline def onUnit[T](phase: Phase, unit: CompilationUnit)(inline body: T): T =
85+
beforeUnit(phase, unit)
86+
try body
87+
finally afterUnit(phase, unit)
8188
def beforeUnit(phase: Phase, unit: CompilationUnit): Unit = ()
8289
def afterUnit(phase: Phase, unit: CompilationUnit): Unit = ()
8390

91+
inline def onTypedImplDef[T](sym: Symbol)(inline body: T): T =
92+
beforeTypedImplDef(sym)
93+
try body
94+
finally afterTypedImplDef(sym)
8495
def beforeTypedImplDef(sym: Symbol): Unit = ()
8596
def afterTypedImplDef(sym: Symbol): Unit = ()
8697

98+
99+
inline def onImplicitSearch[T](pt: Type)(inline body: T): T =
100+
beforeImplicitSearch(pt)
101+
try body
102+
finally afterImplicitSearch(pt)
87103
def beforeImplicitSearch(pt: Type): Unit = ()
88104
def afterImplicitSearch(pt: Type): Unit = ()
89105

106+
inline def onMacroExpansion[T](macroSym: Symbol)(inline body: T): T =
107+
beforeMacroExpansion(macroSym)
108+
try body
109+
finally afterMacroExpansion(macroSym)
110+
def beforeMacroExpansion(macroSym: Symbol): Unit = ()
111+
def afterMacroExpansion(macroSym: Symbol): Unit = ()
112+
113+
inline def onCompletion[T](root: Symbol, associatedFile: AbstractFile)(inline body: T): T =
114+
beforeCompletion(root, associatedFile)
115+
try body
116+
finally afterCompletion(root, associatedFile)
90117
def beforeCompletion(root: Symbol, associatedFile: AbstractFile): Unit = ()
91118
def afterCompletion(root: Symbol, associatedFile: AbstractFile): Unit = ()
92119
}
@@ -280,13 +307,42 @@ private [profile] class RealProfiler(reporter : ProfileReporter)(using Context)
280307

281308
override def beforeImplicitSearch(pt: Type): Unit =
282309
if chromeTrace != null
283-
then chromeTrace.traceDurationEventStart(Category.Implicit, "?[" + pt.typeSymbol.fullName + "]", colour = "yellow")
284-
310+
then chromeTrace.traceDurationEventStart(Category.Implicit, s"?[${symbolName(pt.typeSymbol)}]", colour = "yellow")
285311

286312
override def afterImplicitSearch(pt: Type): Unit =
287313
if chromeTrace != null
288-
then chromeTrace.traceDurationEventEnd(Category.Implicit, "?[" + pt.typeSymbol.fullName + "]", colour = "yellow")
314+
then chromeTrace.traceDurationEventEnd(Category.Implicit, s"?[${symbolName(pt.typeSymbol)}]", colour = "yellow")
315+
316+
override def beforeMacroExpansion(macroSym: Symbol): Unit =
317+
if chromeTrace != null
318+
then chromeTrace.traceDurationEventStart(Category.Macro, s"«${symbolName(macroSym)}»", colour = "olive")
319+
320+
override def afterMacroExpansion(macroSym: Symbol): Unit =
321+
if chromeTrace != null
322+
then chromeTrace.traceDurationEventEnd(Category.Macro, s"«${symbolName(macroSym)}»", colour = "olive")
323+
324+
override def beforeCompletion(root: Symbol, associatedFile: AbstractFile): Unit =
325+
if chromeTrace != null
326+
then
327+
chromeTrace.traceDurationEventStart(Category.Completion, "", colour = "thread_state_sleeping")
328+
chromeTrace.traceDurationEventStart(Category.File, associatedFile.name)
329+
chromeTrace.traceDurationEventStart(Category.Completion, completionName(root, associatedFile))
289330

331+
override def afterCompletion(root: Symbol, associatedFile: AbstractFile): Unit =
332+
if chromeTrace != null
333+
then
334+
chromeTrace.traceDurationEventEnd(Category.Completion, completionName(root, associatedFile))
335+
chromeTrace.traceDurationEventEnd(Category.File, associatedFile.name)
336+
chromeTrace.traceDurationEventEnd(Category.Completion, "", colour = "thread_state_sleeping")
337+
338+
private def symbolName(sym: Symbol): String = sym.name.toString
339+
private def completionName(root: Symbol, associatedFile: AbstractFile): String =
340+
def isTopLevel = root.owner != NoSymbol && root.owner.is(Flags.Package)
341+
if root.is(Flags.Package) || isTopLevel
342+
then root.javaBinaryName
343+
else
344+
val enclosing = root.enclosingClass
345+
s"${enclosing.javaBinaryName}::${root.name}"
290346
}
291347

292348
case class EventType(name: String)

compiler/src/dotty/tools/dotc/quoted/Interpreter.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ class Interpreter(pos: SrcPos, classLoader0: ClassLoader)(using Context):
171171
val clazz = inst.getClass
172172
val name = fn.name.asTermName
173173
val method = getMethod(clazz, name, paramsSig(fn))
174-
stopIfRuntimeException(method.invoke(inst, args*), method)
174+
ctx.profiler.onMacroExpansion(fn){
175+
stopIfRuntimeException(method.invoke(inst, args*), method)
176+
}
175177
}
176178

177179
private def interpretedStaticFieldAccess(sym: Symbol): Object = {

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,9 +1061,8 @@ trait Implicits:
10611061
* it should be applied, EmptyTree otherwise.
10621062
* @param span The position where errors should be reported.
10631063
*/
1064-
def inferImplicit(pt: Type, argument: Tree, span: Span)(using Context): SearchResult =
1065-
ctx.profiler.beforeImplicitSearch(pt)
1066-
try trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
1064+
def inferImplicit(pt: Type, argument: Tree, span: Span)(using Context): SearchResult = ctx.profiler.onImplicitSearch(pt) {
1065+
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
10671066
record("inferImplicit")
10681067
assert(ctx.phase.allowsImplicitSearch,
10691068
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase.phaseName}"
@@ -1125,7 +1124,8 @@ trait Implicits:
11251124
}
11261125
// If we are at the outermost implicit search then emit the implicit dictionary, if any.
11271126
ctx.searchHistory.emitDictionary(span, result)
1128-
} finally ctx.profiler.afterImplicitSearch(pt)
1127+
}
1128+
}
11291129

11301130
/** Try to typecheck an implicit reference */
11311131
def typedImplicit(cand: Candidate, pt: Type, argument: Tree, span: Span)(using Context): SearchResult = trace(i"typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) {

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,9 +2552,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25522552
if filters == List(MessageFilter.None) then sup.markUsed()
25532553
ctx.run.nn.suppressions.addSuppression(sup)
25542554

2555-
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
2556-
ctx.profiler.beforeTypedImplDef(sym)
2557-
try {
2555+
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedImplDef(sym) {
25582556
val ValDef(name, tpt, _) = vdef
25592557
checkNonRootName(vdef.name, vdef.nameSpan)
25602558
completeAnnotations(vdef, sym)
@@ -2568,7 +2566,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25682566
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
25692567
postProcessInfo(vdef1, sym)
25702568
vdef1.setDefTree
2571-
} finally ctx.profiler.afterTypedImplDef(sym)
2569+
}
25722570

25732571
private def retractDefDef(sym: Symbol)(using Context): Tree =
25742572
// it's a discarded method (synthetic case class method or synthetic java record constructor or overridden member), drop it
@@ -2580,7 +2578,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25802578
sym.owner.info.decls.openForMutations.unlink(sym)
25812579
EmptyTree
25822580

2583-
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = if !sym.info.exists then retractDefDef(sym) else {
2581+
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = if !sym.info.exists then retractDefDef(sym) else ctx.profiler.onTypedImplDef {
25842582

25852583
// TODO: - Remove this when `scala.language.experimental.erasedDefinitions` is no longer experimental.
25862584
// - Modify signature to `erased def erasedValue[T]: T`
@@ -2679,7 +2677,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26792677
postProcessInfo(ddef2, sym)
26802678
ddef2.setDefTree
26812679
//todo: make sure dependent method types do not depend on implicits or by-name params
2682-
} finally ctx.profiler.afterTypedImplDef(sym)
2680+
}
26832681

26842682
/** (1) Check that the signature of the class member does not return a repeated parameter type
26852683
* (2) If info is an erased class, set erased flag of member
@@ -2691,9 +2689,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26912689
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
26922690
sym.setFlag(Erased)
26932691

2694-
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {
2695-
ctx.profiler.beforeTypedImplDef(sym)
2696-
try {
2692+
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedImplDef(sym) {
26972693
val TypeDef(name, rhs) = tdef
26982694
completeAnnotations(tdef, sym)
26992695
val rhs1 = tdef.rhs match
@@ -2704,12 +2700,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27042700
checkFullyAppliedType(rhs1)
27052701
if sym.isOpaqueAlias then checkNoContextFunctionType(rhs1)
27062702
assignType(cpy.TypeDef(tdef)(name, rhs1), sym)
2707-
} finally ctx.profiler.afterTypedImplDef(sym)
27082703
}
27092704

2710-
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(using Context): Tree =
2711-
ctx.profiler.beforeTypedImplDef(cls)
2712-
try {
2705+
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(using Context): Tree = ctx.profiler.onTypedImplDef(cls) {
27132706
if (!cls.info.isInstanceOf[ClassInfo]) return EmptyTree.assertingErrorsReported
27142707

27152708
val TypeDef(name, impl @ Template(constr, _, self, _)) = cdef: @unchecked
@@ -2861,7 +2854,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28612854

28622855
cdef1
28632856
}
2864-
} finally ctx.profiler.afterTypedImplDef(cls)
2857+
}
28652858

28662859
// todo later: check that
28672860
// 1. If class is non-abstract, it is instantiatable:

0 commit comments

Comments
 (0)