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

Add force-frame-pointer flag to allow control of frame pointer ommision #48786

Merged
merged 4 commits into from
May 1, 2018

Conversation

nagisa
Copy link
Member

@nagisa nagisa commented Mar 6, 2018

Rebase of #47152 plus some changes suggested by #48785.

Fixes #11906

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 6, 2018
@@ -598,8 +598,12 @@ impl Session {
}

pub fn must_not_eliminate_frame_pointers(&self) -> bool {
self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
!self.target.target.options.eliminate_frame_pointer
if let Some(x) = self.opts.cg.force_frame_pointers {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, the name "force-frame-pointers" makes it sound like a "no" value would revert to default behavior -- but I guess that's not quite right. (That is, if you give -Cforce-frame-pointer=no and you have debuginfo, it will still strip your frame pointers, right? I think I would expect it not to based on the name.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-Cforce-frame-pointer=no to me sounds like we're asking the compiler to not force any frame pointers. This lets the compiler use frame pointers any way it pleases.

The other proposed names for this flag sounds like they are omitting or stripping frame pointers. LLVM does not support this. You can only ask it to force frame pointers or let it decide how frame pointers are used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lets the compiler use frame pointers any way it pleases.

I agree, it gives us freedom. I guess I'm saying is that what I would expect -C force-frame-pointers=no and not saying anything to be equivalent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, this is basically a bikeshed =) but it argues for @Mark-Simulacrum's "yes/no/auto" formulation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikomatsakis ah I see your point, however, it is something that could apply for all optionally-bool arguments, with auto being the same as if the argument was never specified anywhere in the CLI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tromey @michaelwoerister do you have opinions on the naming of the option?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand it, you cannot completely opt out of frame pointer emission, you can only opt into always generating them, so a simple boolean flag -C always-emit-frame-pointers would suffice, I think. The name is a bit verbose though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find @michaelwoerister's logic compelling, but I'm not sure it's complete. C force-frame-pointers is pretty clear -- if you provide it, it forces frame pointers, otherwise it falls back to our default behavior. I guess the question is whether we want the ability to allow frame-pointers to be optimized also in cases where we would by default include them (e.g., with debuginfo, or on mac, or whatever).

I also find @Mark-Simulacrum's formulation compelling, but it sounds a bit like work. =) I guess we would say that -Cframe-pointers=off errors when you are not in a debug build?

OTOH, if we do go with -Cforce-frame-pointers as a simple boolean, we can clearly expand later and just keep it as a deprecated alias. It seems to commit us to very little. =)

Copy link
Member Author

@nagisa nagisa Mar 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so…

I’d like to direct you all to read the commit message:

This reworks the force-frame-pointer PR to explicitly only consider the
value of the flag if it is provided and also keeps the debug-info =
force-frame-pointer behaviour from before.

Something that was tried but not kept was renaming the flag to
frame-pointer, because for flag frame-pointer=no, it is not
guaranteed, that no frame pointers will be generated. Rather, all it does
is inhibit the removal of the frame pointer.

This explains well why I didn’t choose frame-pointers wording (EDIT: though seems I have botched it at the end in terms of explanation, it should’ve read as "all it does is allow LLVM to remove the frame pointer whenever it wants to do so")

-C always emit-frame-pointers seems like a synonym to -C force-frame-pointers to me.

I read -C force-frame-pointers = no as "Don’t force frame pointers”, rather than anything else, which aligns well with it simply allowing LLVM to omit the frame pointer anywhere it wants, but not guaranteeing that.

I also didn’t add auto at this moment, because it doesn’t seem to imply "default" to me, but I could also be persuaded otherwise. Anyway it is something that can be added later, and since it is more generally useful, considered for all the flags at once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confess I didn't read the commit message. 😛

I read -C force-frame-pointers = no as "Don’t force frame pointers”, rather than anything else

Agreed!

which aligns well with it simply allowing LLVM to omit the frame pointer anywhere it wants, but not guaranteeing that.

Agreed, but it's not the whole story. I think the part that seems a bit surprising is that not specifying the option at all will also 'not force frame pointers', but under different conditions. That is, the behavior of this PR as I understand it:

  • -C force-frame-pointers=yes -- you get frame pointers
  • -C force-frame-pointers=no -- you get frame pointers in debug builds, but in opt builds LLVM might optimize frame pointers out
  • no option -- you get frame pointers in debug builds, or with debuginfo, or on some platforms, but otherwise LLVM might optimize frame pointers out

I'd be happier if that second and third choice were the same -- I'm not sure which of the two is better. Is there a good reason that they are not the same? e.g., how bad would it be if -C force-frame-pointers=no meant the same thing as 'no option' above?

@nikomatsakis
Copy link
Contributor

Well, we can always add an auto later. Let's do this thing.

x
} else {
!self.target.target.options.eliminate_frame_pointer ||
self.opts.debuginfo != DebugInfoLevel::NoDebugInfo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the point of this PR to not tie frame pointer emission to the debuginfo setting?

Copy link
Member Author

@nagisa nagisa Mar 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps frame pointers when debug-info is enabled by default as suggested by the linked issue:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the comments in #11906 ask that -g not affect debuginfo, e.g.: #11906 (comment), #11906 (comment), #11906 (comment).

#48785 disagrees, though maybe leaves the door open to have it be a target setting.

I tend to think it's best if the presence or absence of debuginfo does not affect code generation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we link the two anyway, intitially? Was it something in the way we made debuginfo which is no longer relevant?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we link the two anyway, intitially? Was it something in the way we made debuginfo which is no longer relevant?

Yes, @dotdash fixed things in our LLVM IR generation so that now debuggers can handle function arguments without frame pointers being present. Before, debuggers had problems displaying variables under certain conditions.

@bors
Copy link
Contributor

bors commented Mar 9, 2018

☔ The latest upstream changes (presumably #48849) made this pull request unmergeable. Please resolve the merge conflicts.

@nikomatsakis nikomatsakis added I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 12, 2018
@nikomatsakis
Copy link
Contributor

Nominating for discussion in @rust-lang/compiler meeting. I'd like to get this settled and landed!

@nikomatsakis
Copy link
Contributor

As a compromise, maybe we should just land this in some form but make it a -Zflag?

@michaelwoerister
Copy link
Member

To provide some context:

  1. @dotdash fixed our LLVM IR generation so that now omitting frame pointers does not break debuginfo anymore.
  2. As a consequence we wanted to decouple debuginfo and frame pointer emission (hence the original Don't force-enable frame pointers when generating debug info #47152).
  3. However, that would have left the compiler in a state where there was no stable way of forcing frame pointers (which before was possible by compiling with debuginfo). That would break profilers that rely on frame pointers.
  4. As a consequence we decided to add an insta-stable -Cforce-frame-pointers. We also decided, it seems, to include frame pointers when compiling with debuginfo. That last point is confusing to me because the whole point of the initial PR was to decouple debuginfo and frame pointer emission :)

I think we should really decouple the two which would finally also fix godbolt.org: https://stackoverflow.com/a/45586160
If we don't decouple we can just as well leave things as they are.

@nikomatsakis
Copy link
Contributor

OK, I agree with @michaelwoerister. At this point, I'm also past caring about the name of this damn option, I just want to make a decision. =)

Regarding debug pointers, we're basically talking about the behavior of this function:

pub fn must_not_eliminate_frame_pointers(&self) -> bool {
        if let Some(x) = self.opts.cg.force_frame_pointers {
            x
        } else {
            !self.target.target.options.eliminate_frame_pointer ||
            self.opts.debuginfo != DebugInfoLevel::NoDebugInfo
        }
}

To decouple from debuginfo (huzzah!) we would do this:

pub fn must_not_eliminate_frame_pointers(&self) -> bool {
        if let Some(x) = self.opts.cg.force_frame_pointers {
            x
        } else {
            !self.target.target.options.eliminate_frame_pointer
        }
}

This then means that -Cforce-frame-pointers=yes means, well, force-frame-pointers.

-Cforce-frame-pointers=no overrides the target, which means that frame pointers may be removed, depending on the optimization settings.

Not passing the option at all uses a default value (either yes or no) based on the target settings. We could eventually add a auto or target keyword to explicitly request this value.

I can live with this. @nagisa -- care to make that change to remove the debuginfo dependency?

@nikomatsakis nikomatsakis added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 14, 2018
@nagisa
Copy link
Member Author

nagisa commented Mar 15, 2018 via email

@nikomatsakis
Copy link
Contributor

@bors r+

1 similar comment
@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Mar 20, 2018

📌 Commit 7188f41 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 20, 2018
kennytm added a commit to kennytm/rust that referenced this pull request Mar 21, 2018
Add force-frame-pointer flag to allow control of frame pointer ommision

Rebase of rust-lang#47152 plus some changes suggested by rust-lang#48785.

Fixes rust-lang#11906

r? @nikomatsakis
@nagisa
Copy link
Member Author

nagisa commented Apr 18, 2018

@bors try-

@rust-highfive
Copy link
Collaborator

Your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
127.0.0.1 localhost nettuno travis vagrant
127.0.1.1 travis-job-bda4cbf1-c630-4248-8d08-36b098ebc090 travis-job-bda4cbf1-c630-4248-8d08-36b098ebc090 ip4-loopback trusty64
travis_fold:start:git.checkout
travis_time:start:0d60da19
$ git clone --depth=2 --branch=try https://github.com/rust-lang/rust.git rust-lang/rust
---
[00:05:44]    Compiling arena v0.0.0 (file:///checkout/src/libarena)
[00:05:48]    Compiling rustc_errors v0.0.0 (file:///checkout/src/librustc_errors)
[00:07:09]    Compiling rustc_const_math v0.0.0 (file:///checkout/src/librustc_const_math)
[00:07:09]    Compiling proc_macro v0.0.0 (file:///checkout/src/libproc_macro)
[00:07:11] error[E0560]: struct `target::Target` has no field named `eliminate_frame_pointer`
[00:07:11]   --> librustc_back/target/i686_apple_darwin.rs:32:9
[00:07:11]    |
[00:07:11] 32 |         eliminate_frame_pointer: false,
[00:07:11]    |         ^^^^^^^^^^^^^^^^^^^^^^^ `target::Target` does not have this field
[00:07:11]    |
[00:07:11]    = note: available fields are: `llvm_target`, `target_endian`, `target_pointer_width`, `target_c_int_width`, `target_os` ... and 6 others
[00:07:11] error: aborting due to previous error
[00:07:11] 
[00:07:11] For more information about this error, try `rustc --explain E0560`.
[00:07:11] error: Could not compile `rustc_back`.
[00:07:11] error: Could not compile `rustc_back`.
[00:07:11] 
[00:07:11] Caused by:
[00:07:11]   process didn't exit successfully: `/checkout/obj/build/bootstrap/debug/rustc --crate-name rustc_back librustc_back/lib.rs --color always --error-format json --crate-type dylib --emit=dep-info,link -C prefer-dynamic -C opt-level=2 --cfg feature="jemalloc" -C metadata=0b933717347c7f2e -C extra-filename=-0b933717347c7f2e --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps --target x86_64-unknown-linux-gnu -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/release/deps --extern log=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/liblog-d1e924cc25a87e91.rlib --extern syntax=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/libsyntax-1c8a99d578aabada.so --extern rand=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/librand-1788dd21f5ec4296.rlib --extern serialize=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/libserialize-4e89ae43c7c030bd.so --extern serialize=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/libserialize-4e89ae43c7c030bd.rlib` (exit code: 101)
[00:07:29] error: build failed
[00:07:29] error: build failed
[00:07:29] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" " jemalloc" "--manifest-path" "/checkout/src/rustc/Cargo.toml" "--message-format" "json"
[00:07:29] travis_fold:end:stage0-rustc

[00:07:29] travis_time:end:stage0-rustc:start=1524077112195567231,finish=1524077249136674795,duration=136941107564


[00:07:29] thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1076:9
[00:07:29] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap dist --host x86_64-unknown-linux-gnu --target x86_64-unknown-linux-gnu
[00:07:29] Build completed unsuccessfully in 0:03:22
travis_time:end:0ec66f88:start=1524076800056343278,finish=1524077249388525921,duration=449332182643

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@nagisa
Copy link
Member Author

nagisa commented Apr 18, 2018

@bors try

@bors
Copy link
Contributor

bors commented Apr 18, 2018

⌛ Trying commit b8d764c761830c74cf60bf3c871547f2ae1b52a1 with merge eee9e36c6c7e8b60fdfda53231b10817a6e90310...

@nagisa
Copy link
Member Author

nagisa commented Apr 18, 2018

Ah, I had hoped that try build would build something else than Linux :(

@kennytm
Copy link
Member

kennytm commented Apr 18, 2018

@nagisa You need to modify .travis.yml if you want to build something other than Linux. However, we can't do perf or crater other than Linux at the moment.

@nagisa
Copy link
Member Author

nagisa commented Apr 18, 2018

Oh no, I just had hoped to run the tests on OS X and Windows to make sure they pass.

@kennytm
Copy link
Member

kennytm commented Apr 18, 2018

@nagisa You just need to comment out the if: for the macOS builder in this case. You don't even need a try build, the PR CI is sufficient for testing it (note that the macOS builder might timeout due to the LLVM cache, and that's fine).

diff --git a/.travis.yml b/.travis.yml
index 63831cd596..830eb9aa4d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,7 +57,7 @@ matrix:
         CI_JOB_NAME=x86_64-apple
       os: osx
       osx_image: xcode9.3-moar
-      if: branch = auto
+      # if: branch = auto
 
     - env: >
         RUST_CHECK_TARGET=check

No check for Windows however. We can't use AppVeyor for PR CI and try builds.

@bors
Copy link
Contributor

bors commented Apr 18, 2018

☀️ Test successful - status-travis
State: approved= try=True

@pietroalbini
Copy link
Member

Ping from triage! What's the status on this?

@nikomatsakis
Copy link
Contributor

Seems like @nagisa still wants to try the changes on CI?

@nagisa
Copy link
Member Author

nagisa commented Apr 29, 2018

The only reason I wanted to run tests is to get any information about whether the changes make test suite happy or not.

It is perfectly fine to r+ the PR. In fact, it also doesn’t require me to do changes to CI configuration files to check stuff out.

@nikomatsakis
Copy link
Contributor

@nagisa ok -- well, needs rebase, but r=me

dotdash and others added 4 commits May 1, 2018 10:44
We apparently used to generate bad/incomplete debug info causing
debuggers not to find symbols of stack allocated variables. This was
somehow worked around by having frame pointers.

With the current codegen, this seems no longer necessary, so we can
remove the code that force-enables frame pointers whenever debug info
is requested.

Since certain situations, like profiling code profit from having frame
pointers, we add a -Cforce-frame-pointers flag to always enable frame
pointers.

Fixes rust-lang#11906
This reworks the force-frame-pointer PR to explicitly only consider the
value of the flag if it is provided, and use a target default otherwise.

Something that was tried but not kept was renaming the flag to
`frame-pointer`, because for flag `frame-pointer=no`, there is no
guarante, that LLVM will elide *all* the frame pointers; oposite of what
the literal reading of the flag would suggest.
@nagisa
Copy link
Member Author

nagisa commented May 1, 2018

@bors r=nikomatsakis

Lets see if this works.

@bors
Copy link
Contributor

bors commented May 1, 2018

📌 Commit 7ec0452 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 1, 2018
@bors
Copy link
Contributor

bors commented May 1, 2018

⌛ Testing commit 7ec0452 with merge 0eb68b7...

bors added a commit that referenced this pull request May 1, 2018
Add force-frame-pointer flag to allow control of frame pointer ommision

Rebase of #47152 plus some changes suggested by #48785.

Fixes #11906

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented May 1, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 0eb68b7 to master...

@bors bors merged commit 7ec0452 into rust-lang:master May 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.