forked from OSchip/llvm-project
[sanitizer] Run Stack compression in background thread
Depends on D114495. Reviewed By: dvyukov Differential Revision: https://reviews.llvm.org/D114498
This commit is contained in:
parent
98f5ab6af3
commit
fa24c4a1c0
|
@ -15,13 +15,14 @@
|
|||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_flags.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
|
||||
#include "sanitizer_stackdepot.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
#if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO
|
||||
// Weak default implementation for when sanitizer_stackdepot is not linked in.
|
||||
SANITIZER_WEAK_ATTRIBUTE StackDepotStats StackDepotGetStats() { return {}; }
|
||||
SANITIZER_WEAK_ATTRIBUTE void StackDepotStopBackgroundThread() {}
|
||||
|
||||
void *BackgroundThread(void *arg) {
|
||||
VPrintf(1, "%s: Started BackgroundThread\n", SanitizerToolName);
|
||||
|
@ -201,6 +202,9 @@ void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start,
|
|||
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
|
||||
__sanitizer_sandbox_arguments *args) {
|
||||
#if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO
|
||||
__sanitizer::StackDepotStopBackgroundThread();
|
||||
#endif
|
||||
__sanitizer::PlatformPrepareForSandboxing(args);
|
||||
if (__sanitizer::sandboxing_callback)
|
||||
__sanitizer::sandboxing_callback();
|
||||
|
|
|
@ -484,6 +484,9 @@ u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
|
|||
|
||||
uptr GetRSS() { UNIMPLEMENTED(); }
|
||||
|
||||
void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
|
||||
void internal_join_thread(void *th) {}
|
||||
|
||||
void InitializePlatformCommonFlags(CommonFlags *cf) {}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
|
||||
#include "sanitizer_stackdepot.h"
|
||||
|
||||
#include "sanitizer_atomic.h"
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_hash.h"
|
||||
#include "sanitizer_mutex.h"
|
||||
#include "sanitizer_stack_store.h"
|
||||
#include "sanitizer_stackdepotbase.h"
|
||||
|
||||
|
@ -75,7 +77,7 @@ uptr StackDepotNode::allocated() {
|
|||
static void CompressStackStore() {
|
||||
u64 start = MonotonicNanoTime();
|
||||
uptr diff = stackStore.Pack(static_cast<StackStore::Compression>(
|
||||
common_flags()->compress_stack_depot));
|
||||
Abs(common_flags()->compress_stack_depot)));
|
||||
if (!diff)
|
||||
return;
|
||||
u64 finish = MonotonicNanoTime();
|
||||
|
@ -85,12 +87,112 @@ static void CompressStackStore() {
|
|||
(finish - start) / 1000000);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CompressThread {
|
||||
public:
|
||||
constexpr CompressThread() = default;
|
||||
void NewWorkNotify();
|
||||
void Stop();
|
||||
void LockAndStop() NO_THREAD_SAFETY_ANALYSIS;
|
||||
void Unlock() NO_THREAD_SAFETY_ANALYSIS;
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
NotStarted = 0,
|
||||
Started,
|
||||
Failed,
|
||||
Stopped,
|
||||
};
|
||||
|
||||
void Run();
|
||||
|
||||
bool WaitForWork() {
|
||||
semaphore_.Wait();
|
||||
return atomic_load(&run_, memory_order_acquire);
|
||||
}
|
||||
|
||||
Semaphore semaphore_ = {};
|
||||
StaticSpinMutex mutex_ = {};
|
||||
State state_ GUARDED_BY(mutex_) = State::NotStarted;
|
||||
void *thread_ GUARDED_BY(mutex_) = nullptr;
|
||||
atomic_uint8_t run_ = {};
|
||||
};
|
||||
|
||||
static CompressThread compress_thread;
|
||||
|
||||
void CompressThread::NewWorkNotify() {
|
||||
int compress = common_flags()->compress_stack_depot;
|
||||
if (!compress)
|
||||
return;
|
||||
if (compress > 0 /* for testing or debugging */) {
|
||||
SpinMutexLock l(&mutex_);
|
||||
if (state_ == State::NotStarted) {
|
||||
atomic_store(&run_, 1, memory_order_release);
|
||||
CHECK_EQ(nullptr, thread_);
|
||||
thread_ = internal_start_thread(
|
||||
[](void *arg) -> void * {
|
||||
reinterpret_cast<CompressThread *>(arg)->Run();
|
||||
return nullptr;
|
||||
},
|
||||
this);
|
||||
state_ = thread_ ? State::Started : State::Failed;
|
||||
}
|
||||
if (state_ == State::Started) {
|
||||
semaphore_.Post();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CompressStackStore();
|
||||
}
|
||||
|
||||
void CompressThread::Run() {
|
||||
VPrintf(1, "%s: StackDepot compression thread started\n", SanitizerToolName);
|
||||
while (WaitForWork()) CompressStackStore();
|
||||
VPrintf(1, "%s: StackDepot compression thread stopped\n", SanitizerToolName);
|
||||
}
|
||||
|
||||
void CompressThread::Stop() {
|
||||
void *t = nullptr;
|
||||
{
|
||||
SpinMutexLock l(&mutex_);
|
||||
if (state_ != State::Started)
|
||||
return;
|
||||
state_ = State::Stopped;
|
||||
CHECK_NE(nullptr, thread_);
|
||||
t = thread_;
|
||||
thread_ = nullptr;
|
||||
}
|
||||
atomic_store(&run_, 0, memory_order_release);
|
||||
semaphore_.Post();
|
||||
internal_join_thread(t);
|
||||
}
|
||||
|
||||
void CompressThread::LockAndStop() {
|
||||
mutex_.Lock();
|
||||
if (state_ != State::Started)
|
||||
return;
|
||||
CHECK_NE(nullptr, thread_);
|
||||
|
||||
atomic_store(&run_, 0, memory_order_release);
|
||||
semaphore_.Post();
|
||||
internal_join_thread(thread_);
|
||||
// Allow to restart after Unlock() if needed.
|
||||
state_ = State::NotStarted;
|
||||
thread_ = nullptr;
|
||||
}
|
||||
|
||||
void CompressThread::Unlock() { mutex_.Unlock(); }
|
||||
|
||||
} // namespace
|
||||
|
||||
void StackDepotNode::store(u32 id, const args_type &args, hash_type hash) {
|
||||
stack_hash = hash;
|
||||
uptr pack = 0;
|
||||
store_id = stackStore.Store(args, &pack);
|
||||
if (pack && common_flags()->compress_stack_depot)
|
||||
CompressStackStore();
|
||||
if (LIKELY(!pack))
|
||||
return;
|
||||
compress_thread.NewWorkNotify();
|
||||
}
|
||||
|
||||
StackDepotNode::args_type StackDepotNode::load(u32 id) const {
|
||||
|
@ -113,11 +215,13 @@ StackTrace StackDepotGet(u32 id) {
|
|||
|
||||
void StackDepotLockAll() {
|
||||
theDepot.LockAll();
|
||||
compress_thread.LockAndStop();
|
||||
stackStore.LockAll();
|
||||
}
|
||||
|
||||
void StackDepotUnlockAll() {
|
||||
stackStore.UnlockAll();
|
||||
compress_thread.Unlock();
|
||||
theDepot.UnlockAll();
|
||||
}
|
||||
|
||||
|
@ -127,6 +231,8 @@ void StackDepotPrintAll() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void StackDepotStopBackgroundThread() { compress_thread.Stop(); }
|
||||
|
||||
StackDepotHandle StackDepotNode::get_handle(u32 id) {
|
||||
return StackDepotHandle(&theDepot.nodes[id], id);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ StackTrace StackDepotGet(u32 id);
|
|||
void StackDepotLockAll();
|
||||
void StackDepotUnlockAll();
|
||||
void StackDepotPrintAll();
|
||||
void StackDepotStopBackgroundThread();
|
||||
|
||||
void StackDepotTestOnlyUnmap();
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// RUN: %clangxx %s -fsanitize-memory-track-origins=1 -o %t
|
||||
// RUN: %env_tool_opts="compress_stack_depot=0:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --implicit-check-not="StackDepot released"
|
||||
// RUN: %env_tool_opts="compress_stack_depot=1:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS
|
||||
// RUN: %env_tool_opts="compress_stack_depot=2:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS
|
||||
// RUN: %env_tool_opts="compress_stack_depot=-1:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS
|
||||
// RUN: %env_tool_opts="compress_stack_depot=-2:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS
|
||||
// RUN: %env_tool_opts="compress_stack_depot=1:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS,THREAD
|
||||
// RUN: %env_tool_opts="compress_stack_depot=2:malloc_context_size=128:verbosity=1" %run %t 2>&1 | FileCheck %s --check-prefixes=COMPRESS,THREAD
|
||||
|
||||
// Ubsan does not store stacks.
|
||||
// UNSUPPORTED: ubsan
|
||||
|
@ -9,6 +11,8 @@
|
|||
// FIXME: Fails for unknown reason.
|
||||
// UNSUPPORTED: s390x
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
__attribute__((noinline)) void a(unsigned v);
|
||||
|
@ -35,7 +39,13 @@ __attribute__((noinline)) void b(unsigned v) { return a(v); }
|
|||
int main(int argc, char *argv[]) {
|
||||
for (unsigned i = 0; i < 100000; ++i)
|
||||
a(i + (i << 16));
|
||||
|
||||
__sanitizer_sandbox_arguments args = {0};
|
||||
__sanitizer_sandbox_on_notify(&args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// THREAD: StackDepot compression thread started
|
||||
// COMPRESS: StackDepot released {{[0-9]+}}
|
||||
// THREAD: StackDepot compression thread stopped
|
||||
|
|
Loading…
Reference in New Issue