-
Notifications
You must be signed in to change notification settings - Fork 69
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
Use MallocAllocator for unique_ptr on macOS. #2906
Conversation
Also add AssertAllocatedBy.
Required for macOS unique_ptr allocator change.
Required for macOS unique_ptr allocator change.
TestablePlugin::ReadFromMessage does an unusual pointer cast.
In the AttachForkWithCopiedBeginError test, a unique_ptr is constructed that owns another unique_ptr's data.
unique_ptr of array and Compressor are not affected.
Update: it crashes on load. It turns out that there are still more I changed all the cases of this I could find to use At this point I don't think this change is feasible as it requires intrusive changes yet does not prevent accidental UB. |
We'll cut the next release, Goldbach, some time this week. The container changes, which I believe are safe, will go in that release. Do you have a sense of how much they gain? As for this PR, let's keep it open for the time being. I want to review it carefully and see if/how it's possible to make things safer and/or less intrusive. |
I made some measurements of how much time per Unity FixedUpdate frame was spent in Principia code (note that this measurement does not cover background threads).
So, the gains vary from ~3× at idle to ~50× at high warp. The container change is definitely the more important of the two changes. |
This was probably a good assessment.
We have not found any way to be smart about it, and your numbers show that #2900 was what mattered anyway. Closing this. |
This is the second version (replacing #2901) of the second part of the fix for #2899.
This change makes the deleter for
std::unique_ptr
on macOS default toAllocatorDeleter
, which uses an allocator for deletion (using the sameprincipia::std
approach as in #2900). The default allocator isstd::allocator
, which aliases toMallocAllocator
on macOS as of #2900. A correspondingstd::make_unique
is also provided.The danger with this approach is that if you have code of the form
std::unique_ptr<Foo>(new Foo())
, it will cause undefined behavior when the pointer is deleted.To avoid this UB, I set
AllocatorDeleter::pointer
to a wrapper class which implicitly converts to aT*
but must be explicitly constructed from aT*
. Consequently, to construct a unique pointer from a raw pointer you have to writestd::unique_ptr<Foo>(AssertAllocatedBy<std::allocator<Foo>(...))
. The code snippet from the previous paragraph would cause a compile error (albeit only on macOS). For the cases whennew
is necessary (private constructors), I provide a tagged placement new as suggested by @eggrobin. It is used like this:new (AllocateWith<std::allocator<Foo>>{}) Foo(…)
. Thus, the snippet from the previous paragraph would be replaced bystd::unique_ptr<Foo>(AssertAllocatedBy<std::allocator<Foo>(new (AllocateWith<std::allocator<Foo>>{}) Foo()))
This is somewhat wordy but the intention is clear (the verbosity could probably be reduced with better naming).
Unfortunately, this change is not as seamless as #2900. It requires code changes in the following places:
new
in factory functions for classes with private constructors (bb1a411; 7 files). There isn't really any way around this; the existingnew
calls are what we are trying to remove. The code changes to the verbose form shown above.new
in tests for convenience (3fc4823; 7 files). Changed to usestd::make_unique
.not_null
assumesstd::unique_ptr<T>::pointer
isT*
and requires some fixes (ce6db1a; 3 files).AssertAllocatedBy
is required to turn them into unique pointers (c44f898; 3 files).
unique_ptr
is constructed from anotherunique_ptr
in an unusual way (a3b2611 and 4d3d18b; 2 files).Additionally, I automatically fall back to
::std::unique_ptr
for the following types:T[]
, notstd::array
). The allocator deallocate function require the number of elements but that is not available to the deleter (neither::std::allocator
norMallocAllocator
actually use this parameter AFAIK, but I still don't want to break the contract).T
wherestd::unique_ptr<T>
is constructed by non-Principia code. This is just one class (google::compression::Compressor
) so I special case it.