We had 2 nearly identical implementations. Thankfully C++ templates
facility lets us produce 2 different runtime functions (for different
type widths) without duplicating source.
Amend github issue #1414
As part of cpu profiler we're extracting current PC (program counter)
of out signal's ucontext. Different OS and hardware combinations have
different ways for that. We had a list of variants that we tested at
compile time and populated PC_FROM_UCONTEXT macro into config.h. It
caused duplication and occasional mismatches between our autoconf and
cmake bits.
So this commit changes testing to be compile-time. We remove
complexity from build system and add some to C++ source.
We use SFINAE to find which of those variants compile (and we silently
assume that 'compiles' implies 'works'; this is what config-time
testing did too). Occasionally we'll face situations where several
variants compile. And we couldn't handle this case in pure C++. So we
have a small Ruby program that generates chain of inheritance among
SFINAE-specialized class templates. This handles prioritization among
variants.
List of ucontext->pc extraction variants is mostly same. We dropped
super-obsolete (circa Linux kernel 2.0) arm variant. And NetBSD case
is now improved. We now use their nice architecture-independent macro
instead of x86-specific access.
AARCH64 >= armv8.3-a supports pointer authentication. If this feature is
enabled it modifies the previously unused upper address bits in apointer.
The affected bits need to be cleared in order for stacktrace to work.
Signed-off-by: Aliaksey Kandratsenka <alkondratenko@gmail.com>
[alkondratenko@gmail.com: added succinct subject line]
As we recently found out, initializing static struct fields or
variables with lambdas, sets up runtime initialization instead of
static initialization as we assumed. So lets avoid this too for null
stacktrace implementation.
Otherwise mmap calling to do_mmap_with_hooks might tail-call (instead
of inlining), which will then break GetCallerStackTrace
facility (since only mmap is placed into special malloc_hook section).
This unbreaks heap checker on gcc 5, but is in general right thing to
do.
Testing every 7th size is a bit slow on slower machines. No need to be
as thorough. We now bump by about 1/128th each step which is still
more steps than size classes we have.
We used msync to verify that address is readable. But msync gives
false positives for PROT_NONE mappings. And we recently got bug report
from user hitting this exact condition.
For correct access check, we steal idea from Abseil and do sigprocmask
with address used as new signal mask and with invalid HOW
argument. This works in today's Linux kernels and is among fastest
methods available. But is brittle w.r.t. possible kernel changes. So
we supply fallback method that does 2 syscalls.
For non-Linux systems we implement usual "write to pipe" trick. Which
also has decent performance, but requires occasional pipe draining and
uses fds which could occasionally be damaged by some forking codes.
We also finally cover all new code with unit test.
Fixes github issue #1426
As we see in github issue #1428, msvc arranges full "init on first
use" initialization for local static usage of TrivialOnce even if that
initialization is completely empty. Fair game, even if stupid.
POD with no initialization should be safely zero-initialized with no
games or tricks from the compilers.
We could have and perhaps at some point should do constexpr for
TrivialOnce and SpinLock (abseil has been liberated from
LinkerInitialized for perphaps well over decade now, including their
fork of SpinLock, of course). But C++ legalese rules are complex
enough and bugs happened in past, so I don't want to be in the tough
business of interpreting standard. So at least for now we keep
things simple.
Default MPICH builds use the Hydra process manager (mpiexec) which sets
PMI_RANK in the application environment. Update GetUniquePathFromEnv()
test accordingly.
Signed-off-by: Ken Raffenetti <raffenet@mcs.anl.gov>
Without this fix we're failing unit tests on ubuntu 18.04 and centos 7
and 6. It looks like clone() in old glibc-s doesn't align stack, so
lets handle it ourselves. How we didn't hit this much earlier (before
massive thread listing refactoring), I am not sure. Most likely pure
luck(?)
* Add support for known HPC environments (TODO: needs to be extended
with more nevironments)
* Added the "CPUPROFILE_USE_PID" environment variable to force appending
PID for the non-covered environments
* Preserve the old way of handling the Child-Parent case
Signed-off-by: Artem Polyakov <artpol84@gmail.com>
It actually found real (but arguably minor) issue with memory region
map locking.
As part of that we're replacing PageHeap::DeleteAndUnlock that had
somewhat ambitious 'move' of SpinLockHolder, with more straightforward
PageHeap::PrepareAndDelete. Doesn't look like we can support move
thingy with thread annotations.
Some years back we fixed memalign vs realloc bug, but we preserved
'wrong' malloc_size/GetAllocatedSize implementation for debug
allocator.
This commit refactors old code making sure we always use right
data_size and it fixes GetAllocatedSize. We update our unittest
accordingly.
Closes#738
As noted on github issue #880 'temporarily' thing saves us not just on
freeing thread cache, but also returning thread's share of thread
cache (max_size_) into common pool. And the later has caused trouble
to mongo folk who originally proposed 'temporarily' thing. They claim
they don't use it anymore.
And thus with no users and no clear benefit, it makes no sense for us
to keep this API. For API and ABI compat sake we keep it, but it is
now identical to regular MarkThreadIdle.
Fixes issue #880
This unbreaks some cases where patching complains about too short
functions to patch.
What happens is we first locate one of CRT-s (like ucrt or msvcrt) and
patch __expand there, redirecting to our implementation. Then "static"
__expand replacement is patched, but it is usually imported from that
same C runtime DLL. And through several jmp redirections we end up at
our own __expand from libc<1>. Patching that (and other cases) is
wrong, but I am unsure how to fix it properly. So we do most simple
workaround. I found that when it not fails is either in debug builds
where empty expand is not too short or when MSVC deduplicates multiple
identical __expand implementations into single function, or when
64-bit patching has to do extra trampoline thingy. And then our
patching code checks if we're trying to replace some function with
itself. So we "just" take advantage of that and get immediate issue
fixed, while punting on more general "duplicate" patching for later.
Update github issue #667
This is nearly impossible in practice, but still. Somehow we missed
this logic that DoSampledAllocation always returns actual object, but
in that condition where stacktrace_allocator failed to get us
StackTrace object we ended up returning span instead of it's object.
Actual growthz list is now lockless since we never delete anything
from it. And we now pass special 'locking context' object down page
heap allocation path, both as a documentation that it is under lock
and for tracking whether we needed to grow heap and by how much. Then
whenever lock is released in RAII fashion, we're able to trigger
growthz recording outside of lock.
Closes#1159
While there is still plenty of code that takes pageheap_lock outside
of page_heap module for all kinds of reasons, at least
bread-and-butter logic of allocating/deallocating larger chunks of
memory is now handling page heap locking inside PageHeap itself. This
gives us flexibility.
Update issue #1159
I.e. this covers case of arms that by default compile tcmalloc for 8k
logical pages (assuming 4k system pages), but can actually run on
systems with 64k pages.
Closes#1135