[compiler-rt] fa24c4a - [sanitizer] Run Stack compression in background thread

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 9 10:43:32 PST 2021


Author: Vitaly Buka
Date: 2021-12-09T10:29:50-08:00
New Revision: fa24c4a1c07ad17c9709e086d86ca6f792fe79f2

URL: https://github.com/llvm/llvm-project/commit/fa24c4a1c07ad17c9709e086d86ca6f792fe79f2
DIFF: https://github.com/llvm/llvm-project/commit/fa24c4a1c07ad17c9709e086d86ca6f792fe79f2.diff

LOG: [sanitizer] Run Stack compression in background thread

Depends on D114495.

Reviewed By: dvyukov

Differential Revision: https://reviews.llvm.org/D114498

Added: 
    

Modified: 
    compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
    compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
index 13624a83865d7..50564e62645de 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
@@ -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();

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
index 6fdf2c424ba59..66a0fd64a05a8 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
@@ -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

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
index 1d3ac5cc778a7..c755b1829d2a3 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
@@ -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);
 }

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
index 56d655d9404ca..cca6fd5346883 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -42,6 +42,7 @@ StackTrace StackDepotGet(u32 id);
 void StackDepotLockAll();
 void StackDepotUnlockAll();
 void StackDepotPrintAll();
+void StackDepotStopBackgroundThread();
 
 void StackDepotTestOnlyUnmap();
 

diff  --git a/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp b/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp
index c64c9392a107b..6bf067618f950 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp
+++ b/compiler-rt/test/sanitizer_common/TestCases/compress_stack_depot.cpp
@@ -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


        


More information about the llvm-commits mailing list