[libcxx-commits] [libcxx] [tzdb] Replace shared_mutex with mutex. (PR #87929)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Apr 7 10:02:36 PDT 2024


https://github.com/EricWF updated https://github.com/llvm/llvm-project/pull/87929

>From ea4795778633c06815e73cfa307bbb7ededc14f1 Mon Sep 17 00:00:00 2001
From: Eric Fiselier <eric at efcs.ca>
Date: Sun, 7 Apr 2024 12:53:04 -0400
Subject: [PATCH 1/2] [tzdb] Replace shared_mutex with mutex.

The overhead of taking a std::mutex is much lower than taking a reader
lock on a shared mutex, even under heavy contention.

The benifit of shared_mutex only occurs as the amount of
time spent in the critical sections grows large enough.

In our case all we do is read a pointer and return the lock.
As a result, using a shared lock can be ~50%-100% slower
---
 libcxx/benchmarks/CMakeLists.txt              |  1 +
 .../shared_mutex_vs_mutex.bench.cpp           | 41 +++++++++++++++++++
 libcxx/src/include/tzdb/tzdb_list_private.h   |  8 ++--
 3 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp

diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt
index 928238c1ac69ba..527a2acf2d3b36 100644
--- a/libcxx/benchmarks/CMakeLists.txt
+++ b/libcxx/benchmarks/CMakeLists.txt
@@ -221,6 +221,7 @@ set(BENCHMARK_TESTS
     map.bench.cpp
     monotonic_buffer.bench.cpp
     ordered_set.bench.cpp
+    shared_mutex_vs_mutex.bench.cpp
     stop_token.bench.cpp
     std_format_spec_string_unicode.bench.cpp
     string.bench.cpp
diff --git a/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp b/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp
new file mode 100644
index 00000000000000..7d06857d0ad6e7
--- /dev/null
+++ b/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This benchmark compares the performance of std::mutex and std::shared_mutex in contended scenarios.
+// it's meant to establish a baseline overhead for std::shared_mutex and std::mutex, and to help inform decisions about
+// which mutex to use when selecting a mutex type for a given use case.
+
+#include <atomic>
+#include <mutex>
+#include <numeric>
+#include <thread>
+#include <shared_mutex>
+
+#include "benchmark/benchmark.h"
+
+int global_value = 42;
+std::mutex m;
+std::shared_mutex sm;
+
+static void BM_shared_mutex(benchmark::State& state) {
+  for (auto _ : state) {
+    std::shared_lock<std::shared_mutex> lock(sm);
+    benchmark::DoNotOptimize(global_value);
+  }
+}
+
+static void BM_mutex(benchmark::State& state) {
+  for (auto _ : state) {
+    std::lock_guard<std::mutex> lock(m);
+    benchmark::DoNotOptimize(global_value);
+  }
+}
+
+BENCHMARK(BM_shared_mutex)->Threads(1)->Threads(2)->Threads(4)->Threads(8)->Threads(32);
+BENCHMARK(BM_mutex)->Threads(1)->Threads(2)->Threads(4)->Threads(8)->Threads(32);
+
+BENCHMARK_MAIN();
diff --git a/libcxx/src/include/tzdb/tzdb_list_private.h b/libcxx/src/include/tzdb/tzdb_list_private.h
index 969b2b9f8a9f63..c0598cb6e24b16 100644
--- a/libcxx/src/include/tzdb/tzdb_list_private.h
+++ b/libcxx/src/include/tzdb/tzdb_list_private.h
@@ -16,7 +16,7 @@
 
 // When threads are not available the locking is not required.
 #ifndef _LIBCPP_HAS_NO_THREADS
-#  include <shared_mutex>
+#  include <mutex>
 #endif
 
 #include "types_private.h"
@@ -56,7 +56,7 @@ class tzdb_list::__impl {
 
   const tzdb& __front() const noexcept {
 #ifndef _LIBCPP_HAS_NO_THREADS
-    shared_lock __lock{__mutex_};
+    unique_lock __lock{__mutex_};
 #endif
     return __tzdb_.front();
   }
@@ -72,7 +72,7 @@ class tzdb_list::__impl {
 
   const_iterator __begin() const noexcept {
 #ifndef _LIBCPP_HAS_NO_THREADS
-    shared_lock __lock{__mutex_};
+    unique_lock __lock{__mutex_};
 #endif
     return __tzdb_.begin();
   }
@@ -87,7 +87,7 @@ class tzdb_list::__impl {
   void __load_no_lock() { chrono::__init_tzdb(__tzdb_.emplace_front(), __rules_.emplace_front()); }
 
 #ifndef _LIBCPP_HAS_NO_THREADS
-  mutable shared_mutex __mutex_;
+  mutable mutex __mutex_;
 #endif
   forward_list<tzdb> __tzdb_;
 

>From 4c233a02a0c2ca76ec265da6740c1700a24a0dbd Mon Sep 17 00:00:00 2001
From: Eric Fiselier <eric at efcs.ca>
Date: Sun, 7 Apr 2024 13:02:27 -0400
Subject: [PATCH 2/2] respect the formatter

---
 libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp b/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp
index 7d06857d0ad6e7..19d13b799cc137 100644
--- a/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp
+++ b/libcxx/benchmarks/shared_mutex_vs_mutex.bench.cpp
@@ -12,8 +12,8 @@
 #include <atomic>
 #include <mutex>
 #include <numeric>
-#include <thread>
 #include <shared_mutex>
+#include <thread>
 
 #include "benchmark/benchmark.h"
 



More information about the libcxx-commits mailing list