This is an archive of the discontinued LLVM Phabricator instance.

[libunwind] Improve unwinder stack usage
ClosedPublic

Authored by rmaprath on May 10 2016, 11:10 AM.

Details

Summary

This patch is generalization of D19920.

A new native-only libunwind variant (selectable through the -DLIBUNWIND_ENABLE_CROSS_UNWINDING=OFF cmake option) is introduced.

The sizes of Registers_xxx and the associated UnwindCursor<A, R> types are strictly matched against the sizes of unw_context_t and unw_cursor_t types defined in libunwind.h. This improves the stack usage of the unwinder as only just enough memory is reserved on the stack to hold the virtual register set on each architecture.

I've locally tested ARM, AArch64, x86 (compile-only) and x86_64 builds of the new variant. Could not perform any testing of PPC or OpenRISK as I couldn't get the cross compiling to work properly. Ideally, we'll have to switch the buildbots to use this new build option so that these strict limits will be validated (and will continue to be validated). This should be fine I think - if the library works for these restricted limits, the general case (which supports cross-unwinding) should follow.

If the patch is accepted, I will start a discussion on cfe-dev about switching the buildbot configurations (I'm assuming we don't have any cross-unwinding buildbot setups).

Diff Detail

Event Timeline

rmaprath updated this revision to Diff 56747.May 10 2016, 11:10 AM
rmaprath retitled this revision from to [libunwind] Improve unwinder stack usage.
rmaprath updated this object.
rmaprath added reviewers: jroelofs, bcraig.
rmaprath added a subscriber: cfe-commits.
rengolin added inline comments.
include/libunwind.h
49

Wouldn't it be a lot simpler to just define a macro _LIBUNWIND_DATA_SIZE or something and have just one line here?

rmaprath added inline comments.May 10 2016, 11:55 AM
include/libunwind.h
49

Yes (*facepalm*). Will fix.

rmaprath updated this revision to Diff 56779.May 10 2016, 12:30 PM

Address review comments by @rengolin:

  • Define and use _LIBUNWIND_CONTEXT_SIZE and _LIBUNWIND_CURSOR_SIZE macros
rmaprath marked an inline comment as done.May 10 2016, 12:31 PM

Gentle ping.

jroelofs edited edge metadata.May 17 2016, 7:54 AM

Just one question, otherwise LGTM:

src/UnwindCursor.hpp
580

Is there a good reason to move this static assert out to libunwind.cpp? ISTM it serves its purpose better here.

rmaprath added inline comments.May 17 2016, 8:06 AM
src/UnwindCursor.hpp
580

I removed this thinking there is already an assert in libunwind.cpp checking the same constraint. Didn't realize the latter assert was something I introduced in the patch!

Will fix.

rmaprath updated this revision to Diff 57487.EditedMay 17 2016, 8:57 AM
rmaprath edited edge metadata.

Addressing review comments from @jroelofs:

  • Moved the assertion in libunwind.cpp back to UnwindCursor.cpp where it really belogs.

@jroelofs: I just realized that, with this new native-only build of libunwind, users of libunwind.h would have to explicitly #define the flag _LIBUNWIND_IS_NATIVE_ONLY in order to get the header in-sync with the library. I can't see an immediate problem if they don't define that flag though, it's just that they'll end up passing larger buffers than the library needs. Do you see a problem here?

'libc++' uses a __config_site mechanism to wire the cmake build options into the __config header. We can implement a similar mechanism in libunwind, not sure if that's necessary here.

WDYT?

Thanks.

/ Asiri

@jroelofs: OK to commit?

Thanks.

/ Asiri

Addressing review comments from @jroelofs:

  • Moved the assertion in libunwind.cpp back to UnwindCursor.cpp where it really belogs.

@jroelofs: I just realized that, with this new native-only build of libunwind, users of libunwind.h would have to explicitly #define the flag _LIBUNWIND_IS_NATIVE_ONLY in order to get the header in-sync with the library. I can't see an immediate problem if they don't define that flag though, it's just that they'll end up passing larger buffers than the library needs. Do you see a problem here?

I'm not convinced it's a problem, (though possibly performance left on the table)...

'libc++' uses a __config_site mechanism to wire the cmake build options into the __config header. We can implement a similar mechanism in libunwind, not sure if that's necessary here.

I think that's the right way to go.

Jon

WDYT?

Thanks.

/ Asiri

rmaprath added a comment.EditedMay 23 2016, 2:35 PM

Addressing review comments from @jroelofs:

  • Moved the assertion in libunwind.cpp back to UnwindCursor.cpp where it really belogs.

@jroelofs: I just realized that, with this new native-only build of libunwind, users of libunwind.h would have to explicitly #define the flag _LIBUNWIND_IS_NATIVE_ONLY in order to get the header in-sync with the library. I can't see an immediate problem if they don't define that flag though, it's just that they'll end up passing larger buffers than the library needs. Do you see a problem here?

I'm not convinced it's a problem, (though possibly performance left on the table)...

'libc++' uses a __config_site mechanism to wire the cmake build options into the __config header. We can implement a similar mechanism in libunwind, not sure if that's necessary here.

I think that's the right way to go.

Jon

WDYT?

Thanks.

/ Asiri

Apologies, it looks like we don't have any targets for installing libunwind.h header (or any other headers from libunwind project for that matter). I think this means we use libunwind.h only for building libunwind+libcxxabi libraries, and there's no need to explicitly adjust libunwind.h header as it is not used from outside as-is. Hope this makes sense.

OK to commit? Sorry for the diversion.

/ Asiri

Addressing review comments from @jroelofs:

  • Moved the assertion in libunwind.cpp back to UnwindCursor.cpp where it really belogs.

@jroelofs: I just realized that, with this new native-only build of libunwind, users of libunwind.h would have to explicitly #define the flag _LIBUNWIND_IS_NATIVE_ONLY in order to get the header in-sync with the library. I can't see an immediate problem if they don't define that flag though, it's just that they'll end up passing larger buffers than the library needs. Do you see a problem here?

I'm not convinced it's a problem, (though possibly performance left on the table)...

'libc++' uses a __config_site mechanism to wire the cmake build options into the __config header. We can implement a similar mechanism in libunwind, not sure if that's necessary here.

I think that's the right way to go.

Jon

WDYT?

Thanks.

/ Asiri

Apologies, it looks like we don't have any targets for installing libunwind.h header (or any other headers from libunwind project for that matter). I think this means we use libunwind.h only for building libunwind+libcxxabi libraries, and there's no need to explicitly adjust libunwind.h header as it is not used from outside as-is. Hope this makes sense.

OK to commit? Sorry for the diversion.

Ah, ok. LGTM then!

Jon

/ Asiri

Committed as r270692. But I forgot to mention this phab review in the commit message. Sigh.

rmaprath accepted this revision.May 25 2016, 7:53 AM
rmaprath added a reviewer: rmaprath.
This revision is now accepted and ready to land.May 25 2016, 7:53 AM
rmaprath closed this revision.May 25 2016, 7:54 AM

Accepted + closed. Patch committed as r270692.

rmaprath added a comment.EditedMay 26 2016, 1:52 PM

Looks like this patch breakes gcc builds of libunwind (none of the bots seem to test it though).

The problem is two-fold, in src/config.h we have:

// Define static_assert() unless already defined by compiler.                                                                                                                                                      
#ifndef __has_feature
  #define __has_feature(__x) 0
#endif
#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
  #define static_assert(__b, __m) \
      extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ]  \
                                                  __attribute__( ( unused ) );
#endif

This is not optimal for gcc when targeting -std=c++11, !defined(static_assert) will be false even though the static_assert keyword is present. We can easily fix this by checking for the __cplusplus version instead.

But there is still a problem for compilers that do not support the static_assert keyword, which have to resort to using this macro version of static_assert(x,y). The problem here is that statements like:

static_assert(check_fit<Registers_or1k, unw_context_t>::does_fit,
                "or1k registers do not fit into unw_context_t");

Do not fit into that macro (it thinks we're passing three arguments to a macro that accepts only two - because of the additional comma in the template argument list). I don't see an easy way to address this other than reverting some of the work done in the previous patch.

Do many people care about building libunwind with a compiler that does not support static_assert keyword? If not, I'd prefer to let this slip and get rid of the static_assert macro definition.

Please shout!

Please shout!

Just add some parens:

static_assert((check_fit<Registers_or1k, unw_context_t>::does_fit),
                  "or1k registers do not fit into unw_context_t");

Please shout!

Just add some parens:

static_assert((check_fit<Registers_or1k, unw_context_t>::does_fit),
                  "or1k registers do not fit into unw_context_t");

Don't know why I didn't try that, works like a charm.

Thanks!

/ Asiri