This improves fragmentation in some use-cases when mmap sys allocator
is used. In specific terms, it unbreaks
tcmalloc_large_heap_fragmentation_unittest on OSX. They have sbrk that
seemingly always fails (fair game). And this test aggressive
fragmentation use-case pretty much requires tcmalloc to allocate
memory "linearly". Which sbrk does.
Previously, our mmap sys allocator didn't pass any start address hint,
so it caused the test to fail. Now we remember end of previous mmap
allocation into hint_ member variable and try to pass it as address
hint to next mmap.
Note, it doesn't help TCMALLOC_SKIP_SBRK=t to pass this test on Linux,
as Linux tends to pick initial mmap chunk "backwards" and too close to
library allocations. So it leaves not enough address space to extend
into. We may address this use-case some other time.
On OSX and Windows we could end up with "default" and no-op
MallocExtension to be used if MallocExtension::instance() is used
before tcmalloc is fully initialized. It was nearly intended after my
recent change. But thinking about this more, even in use-cases where
we don't replace systems malloc APIs, we want MallocExtension to
reflect tcmalloc's state. So we now truly force tcmalloc
initialization on first MallocExtension::instance() use and
MallocExtension is now abstract class.
Otherwise when _TIME_BITS are set, glibc complains that it seems
_TIME_BITS=64 without seeing _FILE_OFFSET_BITS=64. Thankfully, none of
the code in mmap_hook.cc depends on time_t.
Debian is doing massive rebuild of everything with 64-bit off_t (and
time_t), but on those systems where it matters, glibc still has mmap
with 32-bit off_t argument and mmap64 with 64-bit off_t. Since we're
aiming to match glibc's ABI, we need to see system's native off_t
width.
Some our tests are intended to test behavior of external APIs (like
operator new etc), but they do need occasional ability to peek into
the guts of tcmalloc. We want to make our .so libraries to be built
with -fvisibility=hidden, so we'll loose this ability.
In order to have this limited ability for tests to get into the guts
of tcmalloc, we introduce TestingPortal exactly for that. It uses
carefuly designed and thouroughly undocumented GetNumericProperty
extension to grab pointer to TestingPortal. Then through calling
member functions of this instance, we're able to do the right thing.
Previous implementation only had tcmalloc.cc's TCMallocGuard to
register correct MallocExtension instance. Which is occasionally too
late.
This original design (as well as it's ancestor in abseil tcmalloc)
allows malloc_extension.cc to be built and linked separately from
tcmalloc. So that software that uses extended features can be linked
with non-tcmalloc malloc (or, for example, asan).
In our case, we don't offer such flexibility. But we choose to keep
ability to (re)enable it.
New implementation makes sure to register malloc extension on first
call to memory allocation. Which typically happens super-early.
In case malloc/operator new aren't called early enough, we make sure
that first call to MallocExtension::instance invokes malloc as part of
creating it's 'empty' malloc extension, and thus provoking
tcmalloc (or any other malloc that chose to implement our malloc
extension interface) to register it's proper MallocExtension instance.
It is still somewhat broken and somewhat of a mess, but it is much
lesser mess now.
As part of this change I also amputated a number of unnecessary or too
complicated bits. Like attempt to build both static and shared
versions of tcmalloc libraries at the same time. We stick to cmake's
"common" (seemingly) behavior of defaulting to something (in our case
shared library) and letting users override BUILD_SHARED_LIBS.
All the "install" bits are amputated as well, they're not ready.
It is not clear why we didn't hit this before, but in some cases we
see calloc being optimized away (just like we had with
new/malloc). And noopt is how we deal with it.
Previous implementation used GetEnvironmentVariableA which appears to
be calling into Heap{Alloc,Free}, so in some cases may recurse into
tcmalloc. So we use 'wide' character version and perform trivial
conversion to/from 7-bit ASCII.
In 57d6ecc4ae I removed obsolete
src/windows/TODO but failed to remove it from Makefile.am
I also previously failed to arrange distribution of vendored
googletest. And we also failed to distribute headers in src/tests/
This is all fixed now.
In file included from /home/louwei/arcs/gperftools/src/span.cc:41:0:
/home/louwei/arcs/gperftools/src/static_vars.h:125:37: error: ‘byte’ in namespace ‘std’ does not name a type
alignas(alignof(PageHeap)) std::byte memory[sizeof(PageHeap)];
^~~~
/home/louwei/arcs/gperftools/src/static_vars.h: In static member function ‘static tcmalloc::PageHeap* tcmalloc::Static::pageheap()’:
/home/louwei/arcs/gperftools/src/static_vars.h:76:80: error: ‘struct tcmalloc::Static::<unnamed>’ has no member named ‘memory’
static PageHeap* pageheap() { return reinterpret_cast<PageHeap *>(&pageheap_.memory); }
^~~~~~
The test includes override of
MallocHook_InitAtFirstAllocation_HeapLeakChecker which runs early
enough to trigger FreeBSD bug of not having nearly anything working
early.