Skip to content
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

[RFC] --stacktrace:noinline: up to 3X speedups with typically same stacktraces #13582

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
genProcParams(m, t, rettype, desc, check, true, true)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
# this is where seemingly dead-code `N_INLINE_PTR` is used
m.s[cfsTypes].addf("typedef $1_PTR($2, $3) $4;$n",
[rope(CallingConvToStr[t.callConv]), rettype, result, desc])
else:
Expand Down
45 changes: 26 additions & 19 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ from lineinfos import
warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile
import dynlib

template isGnerateNimFrame(options, sym): bool =
optStackTrace in options and
(optStackTraceNoInline notin options or sym.typ.callConv != ccInline)

when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
## given a library name pattern `s` write possible library names to `dest`.
Expand Down Expand Up @@ -265,9 +269,11 @@ proc genLineDir(p: BProc, t: PNode) =
p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
# why `sfPure notin p.prc.flags` condition?
(p.prc == nil or (sfPure notin p.prc.flags and isGnerateNimFrame(p.options, p.prc))) and
t.info.fileIndex != InvalidFileIdx and
freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
[line, quotedFilename(p.config, t.info)])

proc postStmtActions(p: BProc) {.inline.} =
Expand Down Expand Up @@ -618,17 +624,19 @@ include ccgcalls, "ccgstmts.nim"

proc initFrame(p: BProc, procname, filename: Rope): Rope =
const frameDefines = """
$1 define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_);

$1 define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);

$1 define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
"""
$1 define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_);

$1 define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
"""
#[
Dead code kept that was used for --debugger:endb, kept comment in case we revive it.
$1 define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
]#
if p.module.s[cfsFrameDefines].len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])

Expand Down Expand Up @@ -1046,12 +1054,11 @@ proc genProcAux(m: BModule, prc: PSym) =
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
m.s[cfsProcHeaders].addf("$1;\n", [header])
generatedProc.add ropecg(p.module, "$1 {$n", [header])
if optStackTrace in prc.options:
generatedProc.add(p.s(cpsLocals))
generatedProc.add(p.s(cpsLocals))
let isNimFrame = isGnerateNimFrame(prc.options, prc)
if isNimFrame:
var procname = makeCString(prc.name.s)
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
else:
generatedProc.add(p.s(cpsLocals))
if optProfiler in prc.options:
# invoke at proc entry for recursion:
appcg(p, cpsInit, "\t#nimProfile();$n", [])
Expand All @@ -1061,7 +1068,7 @@ proc genProcAux(m: BModule, prc: PSym) =
generatedProc.add(p.s(cpsInit))
generatedProc.add(p.s(cpsStmts))
if beforeRetNeeded in p.flags: generatedProc.add(~"\t}BeforeRet_: ;$n")
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
if isNimFrame: generatedProc.add(deinitFrame(p))
generatedProc.add(returnStmt)
generatedProc.add(~"}$N")
m.s[cfsProcs].add(generatedProc)
Expand Down
9 changes: 8 additions & 1 deletion compiler/commands.nim
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const
errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found"
errExpectedButFound = "$1 expected, but '$2' found"

proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
Expand Down Expand Up @@ -280,6 +281,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
of "hints": result = contains(conf.options, optHints)
of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
of "stacktrace": result = contains(conf.options, optStackTrace)
of "stacktraceNoInline": result = contains(conf.options, optStackTraceNoInline)
of "linetrace": result = contains(conf.options, optLineTrace)
of "debugger": result = contains(conf.globalOptions, optCDebug)
of "profiler": result = contains(conf.options, optProfiler)
Expand Down Expand Up @@ -528,7 +530,12 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "hints":
if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
of "stacktrace":
case arg.normalize
of "","on": conf.options.incl optStackTrace
of "off": conf.options.excl optStackTrace
of "noinline": conf.options.incl {optStackTrace, optStackTraceNoInline}
else: localError(conf, info, errExpectedButFound % ["'', 'on', 'off', 'noinline'", arg])
of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
of "debugger":
Expand Down
2 changes: 1 addition & 1 deletion compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type # please make sure we have under 32 options
optOverflowCheck, optNilCheck, optRefCheck,
optNaNCheck, optInfCheck, optStyleCheck,
optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
optOptimizeSpeed, optOptimizeSize, optStackTrace, optStackTraceNoInline, # stack tracing support
optLineTrace, # line tracing support (includes stack tracing)
optByRef, # use pass by ref for objects
# (for interfacing with C)
Expand Down
3 changes: 2 additions & 1 deletion doc/basicopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Options:
see: "compile time define pragmas")
-u, --undef:SYMBOL undefine a conditional symbol
-f, --forceBuild:on|off force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off
--stackTrace:on|off|noinline turn stack tracing on|off; {.inline.} procs
won't be traceable with `noinline` option
--lineTrace:on|off turn line tracing on|off
--threads:on|off turn support for multi-threading on|off
-x, --checks:on|off turn all runtime checks on|off
Expand Down