Relocation (= move+destroy)

Marc Glisse marc.glisse@inria.fr
Sat Sep 1 15:00:00 GMT 2018


Hello,

this patch passed bootstrap+regtest on powerpc64le-unknown-linux-gnu.

The main idea is manually performing loop fusion when we see 2 consecutive 
loops where the first moves data from A to B, and the second destroys the 
same elements in A.

This is beneficial because there is one loop fewer (as usual with loop 
fusion), but also because the move constructor and the destructor can 
combine relatively well for several types. I performed some simple tests 
on std::vector<std::string>, and for a loop that just emplace_back many 
empty strings, I see a performance gain close to 20%. With not-small 
strings, I am still seeing a noticable gain (maybe 10%? The noise makes it 
hard to be precise).

I had to add a special case for trivial types, using memmove, to avoid 
perf regressions, since relocation takes precedence over the old path that 
is specialized to call memmove.

_GLIBCXX_ASAN_ANNOTATE_REINIT: I am not familiar with those annotations. 
It was convenient in one function to move this annotation after _Destroy, 
to reduce code duplication. For consistency, I did the same in the whole 
file. As far as I understand, the macro makes it ok to access memory 
between _M_finish and _M_end_of_storage, and at the end of the block marks 
again the region after the new _M_finish as protected. Since _Destroy 
should stop at _M_finish, moving the macro looks safe. But maybe the 
position of the macro was chosen to reduce needless checking in ASAN?

It might be possible to introduce some helpers that do relocate if 
noexcept and copy otherwise, but it is much less convenient than for 
move_if_noexcept, because they don't want to execute the destructors at 
the same point, so we might also want a destroy_if_no_relocate to go with 
it...

The exact form of the relocate functions is whatever I had when things 
started working, it is probably not that important as long as we don't 
document them. I had a _n version taking a size, but I ended up not using 
it, so I removed it.

The change is limited to C++17+, because I felt like using if constexpr. 
Actually, I think g++ accepts if constexpr in C++11 with a warning (ok in 
a system header), I don't remember if I ended up using any other recent 
features...

Possible future stuff:

* use relocation in more places: there should be 1 or 2 places left in 
vector, deque may also be a good candidate, I didn't look elsewhere.

* specialize relocation for some types (maybe deque?) where it can be 
noexcept, possibly even trivial, whereas the move constructor cannot. If 
we do that, we may want to specialize for pair/tuple/array as well, in 
case one of the members is specialized.

2018-09-01  Marc Glisse  <marc.glisse@inria.fr>

 	PR libstdc++/87106
 	* include/bits/alloc_traits.h (_S_construct, _S_destroy, construct,
 	destroy): Add noexcept specification.
 	* include/bits/allocator.h (construct, destroy): Likewise.
 	* include/ext/alloc_traits.h (construct, destroy): Likewise.
 	* include/ext/malloc_allocator.h (construct, destroy): Likewise.
 	* include/ext/new_allocator.h (construct, destroy): Likewise.
 	* include/bits/stl_uninitialized.h (__relocate, __relocate_a,
 	__relocate_a_1): New functions.
 	(__is_trivially_relocatable): New class.
 	* include/bits/stl_vector.h (__use_relocate): New static member.
 	* include/bits/vector.tcc (reserve, _M_realloc_insert,
 	_M_default_append): Use __relocate_a.
 	(reserve, _M_assign_aux, _M_realloc_insert, _M_fill_insert,
 	_M_default_append, _M_range_insert): Move _GLIBCXX_ASAN_ANNOTATE_REINIT
 	after _Destroy.

-- 
Marc Glisse
-------------- next part --------------
A non-text attachment was scrubbed...
Name: reloc.patch
Type: text/x-diff
Size: 23955 bytes
Desc: 
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20180901/c3c29f22/attachment.bin>


More information about the Libstdc++ mailing list