Skip to content

Commit ec13cb0

Browse files
committed
Profile more events, make the profiler more Scala3 idiomatic
1 parent 1aa3305 commit ec13cb0

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
@@ -429,7 +429,7 @@ private sealed trait YSettings:
429429
//.withPostSetHook( _ => YprofileEnabled.value = true )
430430
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 *", "_")
431431
//.withPostSetHook( _ => YprofileEnabled.value = true )
432-
val YprofileTrace: Setting[String] = StringSetting("-Yprofile-trace", "file", "Capture trace of compilation in Chrome Trace format", "profile.trace")
432+
val YprofileTrace: Setting[String] = StringSetting(ForkSetting, "Yprofile-trace", "file", "Capture trace of compilation in Chrome Trace format", "profile.trace")
433433
//.withPostSetHook( _ => YprofileEnabled.value = true )
434434

435435
val YbestEffort: Setting[Boolean] = BooleanSetting(ForkSetting, "Ybest-effort", "Enable best-effort compilation attempting to produce betasty to the META-INF/best-effort directory, regardless of errors, as part of the pickler phase.")

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, hasBetastyExtension}
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.*
@@ -333,7 +333,18 @@ abstract class SymbolLoader extends LazyType { self =>
333333
def description(using Context): String = s"proxy to ${self.description}"
334334
}
335335

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

409420
def compilationUnitInfo: CompilationUnitInfo | Null = CompilationUnitInfo(classfile)
410421

411-
412422
def description(using Context): String = "class file " + classfile.toString
413423

414424
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
@@ -1063,9 +1063,8 @@ trait Implicits:
10631063
* it should be applied, EmptyTree otherwise.
10641064
* @param span The position where errors should be reported.
10651065
*/
1066-
def inferImplicit(pt: Type, argument: Tree, span: Span)(using Context): SearchResult =
1067-
ctx.profiler.beforeImplicitSearch(pt)
1068-
try trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
1066+
def inferImplicit(pt: Type, argument: Tree, span: Span)(using Context): SearchResult = ctx.profiler.onImplicitSearch(pt) {
1067+
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
10691068
record("inferImplicit")
10701069
assert(ctx.phase.allowsImplicitSearch,
10711070
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase.phaseName}"
@@ -1132,7 +1131,8 @@ trait Implicits:
11321131
}
11331132
// If we are at the outermost implicit search then emit the implicit dictionary, if any.
11341133
ctx.searchHistory.emitDictionary(span, result)
1135-
} finally ctx.profiler.afterImplicitSearch(pt)
1134+
}
1135+
}
11361136

11371137
/** Try to typecheck an implicit reference */
11381138
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
@@ -2632,9 +2632,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26322632
if filters == List(MessageFilter.None) then sup.markUsed()
26332633
ctx.run.nn.suppressions.addSuppression(sup)
26342634

2635-
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
2636-
ctx.profiler.beforeTypedImplDef(sym)
2637-
try {
2635+
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedImplDef(sym) {
26382636
val ValDef(name, tpt, _) = vdef
26392637
checkNonRootName(vdef.name, vdef.nameSpan)
26402638
completeAnnotations(vdef, sym)
@@ -2648,7 +2646,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26482646
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
26492647
postProcessInfo(vdef1, sym)
26502648
vdef1.setDefTree
2651-
} finally ctx.profiler.afterTypedImplDef(sym)
2649+
}
26522650

26532651
private def retractDefDef(sym: Symbol)(using Context): Tree =
26542652
// it's a discarded method (synthetic case class method or synthetic java record constructor or overridden member), drop it
@@ -2660,7 +2658,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26602658
sym.owner.info.decls.openForMutations.unlink(sym)
26612659
EmptyTree
26622660

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

26652663
// TODO: - Remove this when `scala.language.experimental.erasedDefinitions` is no longer experimental.
26662664
// - Modify signature to `erased def erasedValue[T]: T`
@@ -2759,7 +2757,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27592757
postProcessInfo(ddef2, sym)
27602758
ddef2.setDefTree
27612759
//todo: make sure dependent method types do not depend on implicits or by-name params
2762-
} finally ctx.profiler.afterTypedImplDef(sym)
2760+
}
27632761

27642762
/** (1) Check that the signature of the class member does not return a repeated parameter type
27652763
* (2) If info is an erased class, set erased flag of member
@@ -2771,9 +2769,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27712769
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
27722770
sym.setFlag(Erased)
27732771

2774-
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {
2775-
ctx.profiler.beforeTypedImplDef(sym)
2776-
try {
2772+
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedImplDef(sym) {
27772773
val TypeDef(name, rhs) = tdef
27782774
completeAnnotations(tdef, sym)
27792775
val rhs1 = tdef.rhs match
@@ -2784,12 +2780,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27842780
checkFullyAppliedType(rhs1)
27852781
if sym.isOpaqueAlias then checkNoContextFunctionType(rhs1)
27862782
assignType(cpy.TypeDef(tdef)(name, rhs1), sym)
2787-
} finally ctx.profiler.afterTypedImplDef(sym)
27882783
}
27892784

2790-
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(using Context): Tree =
2791-
ctx.profiler.beforeTypedImplDef(cls)
2792-
try {
2785+
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(using Context): Tree = ctx.profiler.onTypedImplDef(cls) {
27932786
if (!cls.info.isInstanceOf[ClassInfo]) return EmptyTree.assertingErrorsReported
27942787

27952788
val TypeDef(name, impl @ Template(constr, _, self, _)) = cdef: @unchecked
@@ -2941,7 +2934,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
29412934

29422935
cdef1
29432936
}
2944-
} finally ctx.profiler.afterTypedImplDef(cls)
2937+
}
29452938

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

0 commit comments

Comments
 (0)