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
Add --ftime-trace to dmd #16363
base: master
Are you sure you want to change the base?
Add --ftime-trace to dmd #16363
Conversation
Thanks for your pull request and interest in making D better, @dkorpel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#16363" |
7d5c46c
to
8c9b81e
Compare
compiler/src/dmd/timetrace.d
Outdated
extern(C++) | ||
void timeTraceProfilerBegin(const(char)* name_ptr, const(char)* detail_ptr, Loc loc) | ||
{ | ||
import dmd.root.rmem : xarraydup; | ||
import core.stdc.string : strdup; | ||
|
||
assert(timeTraceProfiler); | ||
|
||
timeTraceProfiler.beginScope(xarraydup(name_ptr.toDString()), | ||
xarraydup(detail_ptr.toDString()), loc); | ||
} | ||
|
||
extern(C++) | ||
void timeTraceProfilerEnd() |
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.
These are defined but never used. Though actually using these would be preferable to a D struct, as it at least would be overridable to allow alternative time measuring engines to be used.
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.
As mentioned in the PR description, it's currently closely matching LDC's code. I have lots of ideas to refactor the code to be better DMD style, but I'd like to know from LDC maintainers if they plan on keeping their own copy of timetrace.d or whether they want to share with upstream. In that case we need to keep a C++ interface.
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.
In that case we need to keep a C++ interface.
That is what the second sentence is advocating for. The frontend semantic passes are using a D interface and RAII. It would integrate better if it used these C++ hooks instead.
(It would be even better if each stage being traced had an enum value, rather than passing a string name and detail, but one request at a time to nudge it in the right direction).
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.
In LDC, we call these C++ functions in a RAII class and only the RAII class is ever used elsewhere. It is very bug prone to not use RAII, so the D code also uses a RAII struct.
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 added an enum value for each stage, and now use D functions (because they take a delegate
) with help of scope (exit)
for safety, while also keeping the C++ interface for LDC.
compiler/src/dmd/timetrace.d
Outdated
void writeTimeTraceProfile(const(char)* filename_cstr) | ||
{ | ||
if (!timeTraceProfiler) | ||
return; | ||
|
||
const filename = getTimeTraceProfileFilename(filename_cstr); | ||
|
||
OutBuffer buf; |
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.
Consider returning an OutBuffer, or moving this buf
local to a ref
parameter. Doing IO inside public API is regarded as bad style, and rules it out from being unittest-able.
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.
good point
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 moved file IO to main.d
9d3e8c5
to
9f85656
Compare
changelog/dmd.ftime-trace.dd
Outdated
@@ -11,6 +11,6 @@ This will output `app.o.time-trace`. | |||
|
|||
A different output file can be selected with `-ftime-trace-file=trace.json`. | |||
|
|||
The output is in Google Chrome's profiler format, which can be converted to readable text with the included `timetrace2txt` tool, or be viewed in an interactive viewer like [ui.perfetto.dev](https://ui.perfetto.dev). |
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 think the timetrace2txt tool is a necessity for practical use. Traces get very large quite quickly, and then the browser-based visual tooling becomes pretty slow (last time I looked). tracy
https://github.com/wolfpld/tracy does have good performance on large traces though.
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.
Yes, it probably needs to be added to https://github.com/dlang/tools and https://github.com/dlang/installer. My plan is to get this PR approved first and then follow up by adding timetrace2txt, since this PR is already pretty big.
compiler/src/dmd/timetrace.d
Outdated
This file is originally from LDC (the LLVM D compiler). | ||
|
||
Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved | ||
Authors: Johan Engelen, Max Haughton |
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.
add yourself here :)
* sym = Dsymbol which was analyzed | ||
* e = Expression which was analyzed | ||
*/ | ||
void timeTraceEndEvent(TimeTraceEventType eventType) |
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.
extern(C++)
so it can be used by LDC.
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.
overall: think a little about what interface to expose to C++. Delegates are not possible, but it'd be good if C++ can use the TimeTraceEventType, to have output be nicely uniform across backends, and also provide extra string input for that event.
compiler/src/dmd/timetrace.d
Outdated
void timeTraceProfilerEnd() | ||
{ | ||
assert(timeTraceProfiler); | ||
timeTraceProfiler.endScope(TimeTraceEventType.generic, null, null, Loc.initial); |
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.
TimeTraceEventType.generic as (default) parameter
I've tested what the overhead is of normal compilation without
( So ~1% overhead, which is worth it when you see how much build time this feature can save. |
82092ad
to
ca859c4
Compare
compiler/src/dmd/dsymbolsem.d
Outdated
timeTraceBeginEvent(); | ||
scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Import, imp); |
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.
timeTraceBeginEvent(); | |
scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Import, imp); | |
timeTraceBeginEvent(TimeTraceEventType.sema1Import); | |
scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Import, imp); |
If the enum was passed at begin and end then that would be enough for this to work with gcc's time report engine as-is.
Pass Outbuffer by ref, move timetrace filename logic to main.d
Reboot of #13965
This feature has been in LDC for a while now with success, and inclusion into dmd has been pre-approved a long time ago by Walter, but the PR has stalled since then. There's improvements possible with choosing better zones and refactoring the code, but for now I focused on making it closely match LDC's current implementation.
For this PR, I still need to include the
timetrace2txt
tool, and test it a bit better.