-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow forcing traces #5738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow forcing traces #5738
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,34 +7,35 @@ import config.Config | |
import config.Printers | ||
import core.Mode | ||
|
||
object trace { | ||
abstract class TraceSyntax { | ||
val isForced: Boolean | ||
|
||
@forceInline | ||
def onDebug[TD](question: => String)(op: => TD)(implicit ctx: Context): TD = | ||
conditionally(ctx.settings.YdebugTrace.value, question, false)(op) | ||
|
||
@forceInline | ||
def conditionally[TC](cond: Boolean, question: => String, show: Boolean)(op: => TC)(implicit ctx: Context): TC = | ||
if (Config.tracingEnabled) { | ||
if (isForced || Config.tracingEnabled) { | ||
def op1 = op | ||
if (cond) apply[TC](question, Printers.default, show)(op1) | ||
else op1 | ||
} else op | ||
|
||
@forceInline | ||
def apply[T](question: => String, printer: Printers.Printer, showOp: Any => String)(op: => T)(implicit ctx: Context): T = | ||
if (Config.tracingEnabled) { | ||
if (isForced || Config.tracingEnabled) { | ||
def op1 = op | ||
if (printer.eq(config.Printers.noPrinter)) op1 | ||
if (!isForced && printer.eq(config.Printers.noPrinter)) op1 | ||
else doTrace[T](question, printer, showOp)(op1) | ||
} | ||
else op | ||
|
||
@forceInline | ||
def apply[T](question: => String, printer: Printers.Printer, show: Boolean)(op: => T)(implicit ctx: Context): T = | ||
if (Config.tracingEnabled) { | ||
if (isForced || Config.tracingEnabled) { | ||
def op1 = op | ||
if (printer.eq(config.Printers.noPrinter)) op1 | ||
if (!isForced && printer.eq(config.Printers.noPrinter)) op1 | ||
else doTrace[T](question, printer, if (show) showShowable(_) else alwaysToString)(op1) | ||
} | ||
else op | ||
|
@@ -68,20 +69,27 @@ object trace { | |
apply[T](s"==> $q?", (res: Any) => s"<== $q = ${showOp(res)}")(op) | ||
} | ||
|
||
def apply[T](leading: => String, trailing: Any => String)(op: => T)(implicit ctx: Context): T = | ||
def apply[T](leading: => String, trailing: Any => String)(op: => T)(implicit ctx: Context): T = { | ||
val log: String => Unit = if (isForced) Console.println else { | ||
var logctx = ctx | ||
while (logctx.reporter.isInstanceOf[StoreReporter]) logctx = logctx.outer | ||
logctx.log(_) | ||
} | ||
doApply(leading, trailing, log)(op) | ||
} | ||
|
||
def doApply[T](leading: => String, trailing: Any => String, log: String => Unit)(op: => T)(implicit ctx: Context): T = | ||
if (ctx.mode.is(Mode.Printing)) op | ||
else { | ||
var finalized = false | ||
var logctx = ctx | ||
while (logctx.reporter.isInstanceOf[StoreReporter]) logctx = logctx.outer | ||
def finalize(result: Any, note: String) = | ||
if (!finalized) { | ||
ctx.base.indent -= 1 | ||
logctx.log(s"${ctx.base.indentTab * ctx.base.indent}${trailing(result)}$note") | ||
log(s"${ctx.base.indentTab * ctx.base.indent}${trailing(result)}$note") | ||
finalized = true | ||
} | ||
try { | ||
logctx.log(s"${ctx.base.indentTab * ctx.base.indent}$leading") | ||
log(s"${ctx.base.indentTab * ctx.base.indent}$leading") | ||
ctx.base.indent += 1 | ||
val res = op | ||
finalize(res, "") | ||
|
@@ -92,4 +100,11 @@ object trace { | |
throw ex | ||
} | ||
} | ||
} | ||
|
||
object trace extends TraceSyntax { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you using this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This replaces the previous There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Then that might be a could place to put two lines of scaladoc... |
||
final val isForced = false | ||
object force extends TraceSyntax { | ||
final val isForced = true | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use a field
TraceSyntax(isForced: Boolean)
? I would expect it is cheaperThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you be more clear on what it is you call a field? The goal here is to override
isForced
with afinal val
, which should be guaranteed to be inlined whenever referenced, which would then mean that we get rid of useless branches in the inlined logging methods. This is somewhat moot, sinceforceInline
does not seem to inline nested methods properly ( see #5738 (comment) ), but I don't see how makingisForced
a constructor argument makes it any cheaper.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here the
final val
implements an abstract one. It will be compiled to a virtual method call, I don't think the compiler can inline in this case. IfisForced
is a constructor argument, it will be compiled to a field. A field access is much cheaper than a virtual method call.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the reasoning, but all the methods that access
isForced
are@forceInline
, so after the body is inlined the compiler should see that the member being accessed is afinal val
and therefore is inlineable, no? Anyway, this PR has no impact on performance and after we bootstrap we will probably rewrite all the methods in this class toinline
, which will guarantee that they are inlined the way we want.Side note: I am bookmarking this discussion to show the next person that tries to convince me it's a good idea to rely on the optimizer for inlining.