Commit 886a70d9 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot

Optimizations, support for exceptions and big return values for lock_combine

Summary:
Some optimizations and changes to make mutex migrations easier:
- Add exception handling support, this allows using lock_combine pretty much
  anywhere a unique_lock would be used and makes transitioning between lock
  methods easier and more efficient as users aren't required to maintain their
  own unions anywhere (eg. with folly::Try)
- Add support for big return values so people can return anything from the
  critical section.  Without this, users would have to use code of the following
  form, which is prone to false sharing with metadata for the waiting thread
```
auto value = ReturnValue{};
mutex.lock_combine([&]() {
  value = critical_section();
});
```
- Add some optimizations like inlining the combine codepath and an optimistic
  load to elide a branch.  This gets us a ~8% throughput improvement from
  before.  More importantly, This prevents compilers from messing up the
  generated code to dereference the waiter node whenever they feel like.
- Defer time publishing for combinable threads until a preemption.  This gets us
  to the same level of efficiency as std::atomic even on broadwell, takes us to
  7x of the baseline (std::mutex) on the NUMA-less machines and almost perfectly
  parallel in the moderate concurrency levels.  I suspect we can do better with
  NUMA-awareness, but that's for another diff

Reviewed By: yfeldblum

Differential Revision: D15522658

fbshipit-source-id: 420f4202503305d57b6bd59a9a4ecb67d4dd3c2e
parent 92c4c7e2
......@@ -276,6 +276,10 @@ class DistributedMutex {
* Here, because we used a combined critical section, we have introduced a
* dependency from one -> three that might not obvious to the reader
*
* This function is exception-safe. If the passed task throws an exception,
* it will be propagated to the caller, even if the task is running on
* another thread
*
* There are three notable cases where this method causes undefined
* behavior:
*
......@@ -291,7 +295,7 @@ class DistributedMutex {
* at compile time or runtime, so we have no checks against this
*/
template <typename Task>
auto lock_combine(Task task) noexcept -> folly::invoke_result_t<const Task&>;
auto lock_combine(Task task) -> folly::invoke_result_t<const Task&>;
/**
* Try to combine a task as a combined critical section untill the given time
......@@ -311,7 +315,7 @@ class DistributedMutex {
typename ReturnType = decltype(std::declval<Task&>()())>
folly::Optional<ReturnType> try_lock_combine_for(
const std::chrono::duration<Rep, Period>& duration,
Task task) noexcept;
Task task);
/**
* Try to combine a task as a combined critical section untill the given time
......@@ -326,7 +330,7 @@ class DistributedMutex {
typename ReturnType = decltype(std::declval<Task&>()())>
folly::Optional<ReturnType> try_lock_combine_until(
const std::chrono::time_point<Clock, Duration>& deadline,
Task task) noexcept;
Task task);
private:
Atomic<std::uintptr_t> state_{0};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment