-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allocation profiling fix - pthread TLS storage (#290)
- Manage TLS storage with pthread APIs. A user provided a case where __tls_get_addr was calling back into Go, which was calling back into mmap. This was causing an infinite recursive loop By managing the lifetime of TLS variables, we can fix this. - Add a test to check if TLS variables are being used - Symbol overrides: Minor fix on the usage of wrong pointer for realloc array - Add some settings to the allocation tracking benchmark
- Loading branch information
Showing
19 changed files
with
892 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
|
||
#include "span.hpp" | ||
|
||
#include <cstdint> | ||
#include <random> | ||
#include <sys/types.h> | ||
|
||
namespace ddprof { | ||
|
||
struct TrackerThreadLocalState { | ||
int64_t remaining_bytes; // remaining allocation bytes until next sample | ||
bool remaining_bytes_initialized; // false if remaining_bytes is not | ||
// initialized | ||
ddprof::span<const byte> stack_bounds; | ||
|
||
// In the choice of random generators, this one is smaller | ||
// - smaller than mt19937 (8 vs 5K) | ||
std::minstd_rand _gen{std::random_device{}()}; | ||
|
||
pid_t tid; // cache of tid | ||
|
||
bool reentry_guard; // prevent reentry in AllocationTracker (eg. when | ||
// allocation are done inside AllocationTracker) | ||
bool double_tracking_guard; // prevent mmap tracking within a malloc | ||
}; | ||
|
||
} // namespace ddprof |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. This product includes software | ||
// developed at Datadog (https://www.datadoghq.com/). Copyright 2021-Present | ||
// Datadog, Inc. | ||
|
||
#pragma once | ||
|
||
#include <cstdarg> | ||
#include <cstdio> | ||
#include <mutex> | ||
|
||
namespace ddprof { | ||
template <typename... Args> | ||
void log_once(char const *const format, Args... args) { | ||
#ifndef DEBUG | ||
static std::once_flag flag; | ||
std::call_once(flag, [&, format]() { fprintf(stderr, format, args...); }); | ||
#else | ||
fprintf(stderr, format, args...); | ||
#endif | ||
} | ||
} // namespace ddprof |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. This product includes software | ||
// developed at Datadog (https://www.datadoghq.com/). Copyright 2021-Present | ||
// Datadog, Inc. | ||
|
||
#pragma once | ||
|
||
#include <array> | ||
#include <atomic> | ||
#include <thread> | ||
|
||
namespace ddprof { | ||
|
||
class ThreadEntries { | ||
public: | ||
static constexpr size_t max_threads = 10; | ||
std::array<std::atomic<pid_t>, max_threads> thread_entries; | ||
ThreadEntries() { reset(); } | ||
void reset() { | ||
for (auto &entry : thread_entries) { | ||
entry.store(-1, std::memory_order_relaxed); | ||
} | ||
} | ||
}; | ||
|
||
class TLReentryGuard { | ||
public: | ||
explicit TLReentryGuard(ThreadEntries &entries, pid_t tid) | ||
: _entries(entries), _tid(tid), _ok(false), _index(-1) { | ||
while (true) { | ||
for (size_t i = 0; i < ThreadEntries::max_threads; ++i) { | ||
pid_t expected = -1; | ||
if (_entries.thread_entries[i].compare_exchange_weak( | ||
expected, tid, std::memory_order_acq_rel)) { | ||
_ok = true; | ||
_index = i; | ||
return; | ||
} else if (expected == tid) { | ||
// This thread is already in the entries. | ||
return; | ||
} | ||
} | ||
// If we've reached here, all slots are occupied and none of them belongs | ||
// to this thread. Let's yield to other threads and then try again. | ||
std::this_thread::yield(); | ||
} | ||
} | ||
|
||
~TLReentryGuard() { | ||
if (_ok) { | ||
_entries.thread_entries[_index].store(-1, std::memory_order_release); | ||
} | ||
} | ||
|
||
explicit operator bool() const { return _ok; } | ||
|
||
TLReentryGuard(const TLReentryGuard &) = delete; | ||
TLReentryGuard &operator=(const TLReentryGuard &) = delete; | ||
|
||
private: | ||
ThreadEntries &_entries; | ||
pid_t _tid; | ||
bool _ok; | ||
int _index; | ||
}; | ||
|
||
class ReentryGuard { | ||
public: | ||
explicit ReentryGuard(bool *reentry_guard) | ||
: _reentry_guard(reentry_guard), _ok(false) { | ||
if (_reentry_guard) { | ||
_ok = (!*_reentry_guard); | ||
*_reentry_guard = true; | ||
} | ||
} | ||
|
||
~ReentryGuard() { | ||
if (_ok) { | ||
*_reentry_guard = false; | ||
} | ||
} | ||
|
||
bool register_guard(bool *reentry_guard) { | ||
if (_reentry_guard) { | ||
// not supported (already registered to other bool) | ||
return false; | ||
} | ||
if (reentry_guard) { | ||
_reentry_guard = reentry_guard; | ||
_ok = (!*_reentry_guard); | ||
*_reentry_guard = true; | ||
} | ||
return _ok; | ||
} | ||
|
||
explicit operator bool() const { return _ok; } | ||
|
||
ReentryGuard(const ReentryGuard &) = delete; | ||
ReentryGuard &operator=(const ReentryGuard &) = delete; | ||
|
||
private: | ||
bool *_reentry_guard; | ||
bool _ok; | ||
}; | ||
|
||
} // namespace ddprof |
Oops, something went wrong.