This is an archive of the discontinued LLVM Phabricator instance.

Threading: use independent llvm::thread implementation on Apple platforms to increase stack size
ClosedPublic

Authored by t.p.northover on May 26 2021, 7:06 AM.

Details

Reviewers
dexonsmith
Summary

Darwin's libpthread creates threads with only 512KB of stack space, as opposed to the main thread's 8MB. 512KB often isn't enough to compile properly, so we get stack overflows during ThinLTO.

Unfortunately, with Posix threads the stack size can only be set during creation so there's no way to use the real std::thread to overcome this limit (even with the native handle).

So this patch adds a real implementation of llvm::thread (with the same interface as std::thread) when compiling for Apple that does request the full 8MB stack size. Most of the implementation is cribbed from libc++, with abstractions removed because we know the underlying implementation and target standard (and because we can tell users not to be daft and #define Thread 0).

Diff Detail

Event Timeline

t.p.northover created this revision.May 26 2021, 7:06 AM
t.p.northover requested review of this revision.May 26 2021, 7:06 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 26 2021, 7:06 AM

Actual main thread stack size is 8MB, but I'd accidentally implemented 2MB originally.

I wonder, could this be used to simplify RunSafelyOnThread, and/or llvm_execute_on_thread_impl? I figure all that complexity is because of the same limitation, but maybe it's not something we can fix, since we exposed a libclang API (clang_executeOnThread) that allows specifying a stack size.

I guess one option would be to never use std::thread, and repurpose the guts of llvm_execute_on_thread_impl to implement a cross-platform llvm::thread that allows specifying the stack size as an optional constructor parameter (and then change llvm_execute_on_thread to use llvm::thread). WDYT?

@dblaikie, wouldn't mind your thoughts on this idea (expanding the interface of llvm::thread to include an optional stack size parameter).

I guess one option would be to never use std::thread, and repurpose the guts of llvm_execute_on_thread_impl to implement a cross-platform llvm::thread that allows specifying the stack size as an optional constructor parameter (and then change llvm_execute_on_thread to use llvm::thread). WDYT?

The llvm_execute_on_thread family only seems to have three users and is definitely a less appealing interface, I'd be very tempted round this llvm::thread out as you suggest and switch all users to it.

I guess one option would be to never use std::thread, and repurpose the guts of llvm_execute_on_thread_impl to implement a cross-platform llvm::thread that allows specifying the stack size as an optional constructor parameter (and then change llvm_execute_on_thread to use llvm::thread). WDYT?

The llvm_execute_on_thread family only seems to have three users and is definitely a less appealing interface, I'd be very tempted round this llvm::thread out as you suggest and switch all users to it.

SGTM; not sure if there'll be other opinions, but it does seem like a nice general cleanup. Also this way llvm::thread users that don't need full-sized stacks can continue getting the Darwin default of smaller pages.

  • Add llvm::thread for all potential platforms, allowing stack size to be specified.
  • llvm::thread based on the Threading.inc where possible, else std::thread, else in-thread synchronous execution (with progressively more failures).
  • Remove llvm_execute_on_thread* in favour of this new llvm::thread.

I've managed to test it on all 3 major platforms, and the fallbacks by fiddling #ifs. So it should at least compile everywhere.

Also this way llvm::thread users that don't need full-sized stacks can continue getting the Darwin default of smaller pages.

I'm not sure I've implemented this, since I've just made 8MB the Darwin default here. The case I care about is LTOBackend via ThreadPool. Would you prefer me to push an optional StackSize argument into ThreadPool too and make LTOBackend specify it?

I kind of think this has come up often enough (it's at least the second time I've had to fix it somewhere), and 8MB is small enough for anything running Clang that it's better to make sure it doesn't happen again.

Herald added a project: Restricted Project. · View Herald TranscriptJun 1 2021, 6:33 AM
t.p.northover added inline comments.Jun 1 2021, 6:35 AM
llvm/include/llvm/Support/thread.h
168

An alternative here would have been to inherit from std::thread but that seemed a bit icky to me. Happy to switch if the consensus is otherwise.

dexonsmith accepted this revision.Jul 6 2021, 12:43 PM

This LGTM, with some whitespace nits inline.

Also this way llvm::thread users that don't need full-sized stacks can continue getting the Darwin default of smaller pages.

I'm not sure I've implemented this, since I've just made 8MB the Darwin default here. The case I care about is LTOBackend via ThreadPool. Would you prefer me to push an optional StackSize argument into ThreadPool too and make LTOBackend specify it?

I kind of think this has come up often enough (it's at least the second time I've had to fix it somewhere), and 8MB is small enough for anything running Clang that it's better to make sure it doesn't happen again.

8MB by default is probably fine; I don't feel strongly either way.

llvm/include/llvm/Support/thread.h
107

Seems like you might as well run git-clang-format to pick up these changes...

261

Looks like it's missing a newline here at the end of the file.

This revision is now accepted and ready to land.Jul 6 2021, 12:43 PM
t.p.northover closed this revision.Jul 8 2021, 6:52 AM

Thanks Duncan, committed as 727e1c9be3a5

llvm/include/llvm/Support/thread.h
107

Yes, I'd already done that on my local commit.