You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mp...@apache.org on 2017/08/08 22:54:13 UTC
[2/2] mesos git commit: Reduced copying in `defer`,
`dispatch` and `Future`.
Reduced copying in `defer`, `dispatch` and `Future`.
This reduces number of copies made for each parameter in
a piece of code like this:
```
future.then(defer(pid, &SomeProcess::someMethod, param1, param2));
```
For the objects that do not support move semantics
(e.g., protobuf messages), number of copies is reduced from 8-10 to 6.
If move semantics is supported, then number of copies is reduced from
6-7 to 1 if parameter is passed with `std::move`, or 2 otherwise.
Review: https://reviews.apache.org/r/60003/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/f8e4f11e
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/f8e4f11e
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/f8e4f11e
Branch: refs/heads/master
Commit: f8e4f11e796b2b0d9bd101a7eb6f106e72cbaee1
Parents: 2ce2a0a
Author: Dmitry Zhuk <dz...@twopensource.com>
Authored: Mon Aug 7 11:01:04 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Aug 8 13:33:15 2017 -0700
----------------------------------------------------------------------
3rdparty/libprocess/include/process/defer.hpp | 81 +++++---
.../libprocess/include/process/deferred.hpp | 184 ++++++++++---------
.../libprocess/include/process/dispatch.hpp | 84 +++++----
3rdparty/libprocess/include/process/future.hpp | 45 ++---
3rdparty/libprocess/include/process/http.hpp | 3 +-
3rdparty/libprocess/src/tests/benchmarks.cpp | 86 +++++++++
6 files changed, 318 insertions(+), 165 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/defer.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/defer.hpp b/3rdparty/libprocess/include/process/defer.hpp
index 7f3369e..9457080 100644
--- a/3rdparty/libprocess/include/process/defer.hpp
+++ b/3rdparty/libprocess/include/process/defer.hpp
@@ -58,20 +58,31 @@ Deferred<void()> defer(const Process<T>* process, void (T::*method)())
// libc++) we can't use std::bind with a std::function so we have to
// explicitly use the std::function<R(P...)>::operator() (see
// http://stackoverflow.com/questions/20097616/stdbind-to-a-stdfunction-crashes-with-clang).
+
+// This assumes that type and variable base names are `A` and `a` respectively.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+
#define TEMPLATE(Z, N, DATA) \
template <typename T, \
ENUM_PARAMS(N, typename P), \
ENUM_PARAMS(N, typename A)> \
auto defer(const PID<T>& pid, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<void(ENUM_PARAMS(N, P))>::operator(), std::function<void(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))> /* NOLINT(whitespace/line_length) */ \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<void(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<void(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))> \
{ \
std::function<void(ENUM_PARAMS(N, P))> f( \
[=](ENUM_BINARY_PARAMS(N, P, p)) { \
dispatch(pid, method, ENUM_PARAMS(N, p)); \
}); \
- return std::bind(&std::function<void(ENUM_PARAMS(N, P))>::operator(), std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+ return std::bind( \
+ &std::function<void(ENUM_PARAMS(N, P))>::operator(), \
+ std::move(f), \
+ ENUM(N, FORWARD, _)); \
} \
\
template <typename T, \
@@ -79,10 +90,10 @@ Deferred<void()> defer(const Process<T>* process, void (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const Process<T>& process, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process.self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename T, \
@@ -90,10 +101,10 @@ Deferred<void()> defer(const Process<T>* process, void (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const Process<T>* process, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process->self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -127,14 +138,21 @@ Deferred<Future<R>()> defer(const Process<T>* process, Future<R> (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const PID<T>& pid, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))> /* NOLINT(whitespace/line_length) */ \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))> \
{ \
std::function<Future<R>(ENUM_PARAMS(N, P))> f( \
[=](ENUM_BINARY_PARAMS(N, P, p)) { \
return dispatch(pid, method, ENUM_PARAMS(N, p)); \
}); \
- return std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+ return std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::move(f), \
+ ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -143,10 +161,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, Future<R> (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const Process<T>& process, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process.self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -155,10 +173,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, Future<R> (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const Process<T>* process, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process->self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -192,14 +210,21 @@ Deferred<Future<R>()> defer(const Process<T>* process, R (T::*method)())
ENUM_PARAMS(N, typename A)> \
auto defer(const PID<T>& pid, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))> /* NOLINT(whitespace/line_length) */ \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))> \
{ \
std::function<Future<R>(ENUM_PARAMS(N, P))> f( \
[=](ENUM_BINARY_PARAMS(N, P, p)) { \
return dispatch(pid, method, ENUM_PARAMS(N, p)); \
}); \
- return std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+ return std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::move(f), \
+ ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -209,10 +234,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, R (T::*method)())
auto \
defer(const Process<T>& process, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process.self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -222,15 +247,17 @@ Deferred<Future<R>()> defer(const Process<T>* process, R (T::*method)())
auto \
defer(const Process<T>* process, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a))) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _))) \
{ \
- return defer(process->self(), method, ENUM_PARAMS(N, a)); \
+ return defer(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
#undef TEMPLATE
+#undef FORWARD
+
// Now we define defer calls for functors (with and without a PID):
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/deferred.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/deferred.hpp b/3rdparty/libprocess/include/process/deferred.hpp
index e446621..af65ead 100644
--- a/3rdparty/libprocess/include/process/deferred.hpp
+++ b/3rdparty/libprocess/include/process/deferred.hpp
@@ -63,7 +63,9 @@ private:
template <typename F>
struct _Deferred
{
- operator Deferred<void()>() const
+ // We expect that conversion operators are invoked on rvalues only,
+ // as _Deferred is supposed to be used directly as a result of defer call.
+ operator Deferred<void()>() &&
{
// The 'pid' differentiates an already dispatched functor versus
// one which still needs to be dispatched (which is done
@@ -74,13 +76,13 @@ struct _Deferred
// arguments which will just be dropped when invoking the
// underlying bound function).
if (pid.isNone()) {
- return std::function<void()>(f);
+ return std::function<void()>(std::forward<F>(f));
}
// We need to explicitly copy the members otherwise we'll
// implicitly copy 'this' which might not exist at invocation.
Option<UPID> pid_ = pid;
- F f_ = f;
+ F&& f_ = std::forward<F>(f);
return std::function<void()>(
[=]() {
@@ -88,14 +90,14 @@ struct _Deferred
});
}
- operator std::function<void()>() const
+ operator std::function<void()>() &&
{
if (pid.isNone()) {
- return std::function<void()>(f);
+ return std::function<void()>(std::forward<F>(f));
}
Option<UPID> pid_ = pid;
- F f_ = f;
+ F&& f_ = std::forward<F>(f);
return std::function<void()>(
[=]() {
@@ -104,14 +106,14 @@ struct _Deferred
}
template <typename R>
- operator Deferred<R()>() const
+ operator Deferred<R()>() &&
{
if (pid.isNone()) {
- return std::function<R()>(f);
+ return std::function<R()>(std::forward<F>(f));
}
Option<UPID> pid_ = pid;
- F f_ = f;
+ F&& f_ = std::forward<F>(f);
return std::function<R()>(
[=]() {
@@ -120,14 +122,14 @@ struct _Deferred
}
template <typename R>
- operator std::function<R()>() const
+ operator std::function<R()>() &&
{
if (pid.isNone()) {
- return std::function<R()>(f);
+ return std::function<R()>(std::forward<F>(f));
}
Option<UPID> pid_ = pid;
- F f_ = f;
+ F&& f_ = std::forward<F>(f);
return std::function<R()>(
[=]() {
@@ -141,43 +143,43 @@ struct _Deferred
// libc++) we can't use std::bind with a std::function so we have to
// explicitly use the std::function<R(P...)>::operator() (see
// http://stackoverflow.com/questions/20097616/stdbind-to-a-stdfunction-crashes-with-clang).
-#define TEMPLATE(Z, N, DATA) \
- template <ENUM_PARAMS(N, typename P)> \
- operator Deferred<void(ENUM_PARAMS(N, P))>() const \
- { \
- if (pid.isNone()) { \
- return std::function<void(ENUM_PARAMS(N, P))>(f); \
- } \
- \
- Option<UPID> pid_ = pid; \
- F f_ = f; \
- \
- return std::function<void(ENUM_PARAMS(N, P))>( \
- [=](ENUM_BINARY_PARAMS(N, P, p)) { \
- std::function<void()> f__([=]() { \
- f_(ENUM_PARAMS(N, p)); \
- }); \
- dispatch(pid_.get(), f__); \
- }); \
- } \
- \
- template <ENUM_PARAMS(N, typename P)> \
- operator std::function<void(ENUM_PARAMS(N, P))>() const \
- { \
- if (pid.isNone()) { \
- return std::function<void(ENUM_PARAMS(N, P))>(f); \
- } \
- \
- Option<UPID> pid_ = pid; \
- F f_ = f; \
- \
- return std::function<void(ENUM_PARAMS(N, P))>( \
- [=](ENUM_BINARY_PARAMS(N, P, p)) { \
- std::function<void()> f__([=]() { \
- f_(ENUM_PARAMS(N, p)); \
- }); \
- dispatch(pid_.get(), f__); \
- }); \
+#define TEMPLATE(Z, N, DATA) \
+ template <ENUM_PARAMS(N, typename P)> \
+ operator Deferred<void(ENUM_PARAMS(N, P))>() && \
+ { \
+ if (pid.isNone()) { \
+ return std::function<void(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
+ } \
+ \
+ Option<UPID> pid_ = pid; \
+ F&& f_ = std::forward<F>(f); \
+ \
+ return std::function<void(ENUM_PARAMS(N, P))>( \
+ [=](ENUM_BINARY_PARAMS(N, P, p)) { \
+ std::function<void()> f__([=]() { \
+ f_(ENUM_PARAMS(N, p)); \
+ }); \
+ dispatch(pid_.get(), f__); \
+ }); \
+ } \
+ \
+ template <ENUM_PARAMS(N, typename P)> \
+ operator std::function<void(ENUM_PARAMS(N, P))>() && \
+ { \
+ if (pid.isNone()) { \
+ return std::function<void(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
+ } \
+ \
+ Option<UPID> pid_ = pid; \
+ F&& f_ = std::forward<F>(f); \
+ \
+ return std::function<void(ENUM_PARAMS(N, P))>( \
+ [=](ENUM_BINARY_PARAMS(N, P, p)) { \
+ std::function<void()> f__([=]() { \
+ f_(ENUM_PARAMS(N, p)); \
+ }); \
+ dispatch(pid_.get(), f__); \
+ }); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -185,14 +187,14 @@ struct _Deferred
#define TEMPLATE(Z, N, DATA) \
template <typename R, ENUM_PARAMS(N, typename P)> \
- operator Deferred<R(ENUM_PARAMS(N, P))>() const \
+ operator Deferred<R(ENUM_PARAMS(N, P))>() && \
{ \
if (pid.isNone()) { \
- return std::function<R(ENUM_PARAMS(N, P))>(f); \
+ return std::function<R(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
} \
\
Option<UPID> pid_ = pid; \
- F f_ = f; \
+ F&& f_ = std::forward<F>(f); \
\
return std::function<R(ENUM_PARAMS(N, P))>( \
[=](ENUM_BINARY_PARAMS(N, P, p)) { \
@@ -204,14 +206,14 @@ struct _Deferred
} \
\
template <typename R, ENUM_PARAMS(N, typename P)> \
- operator std::function<R(ENUM_PARAMS(N, P))>() const \
+ operator std::function<R(ENUM_PARAMS(N, P))>() && \
{ \
if (pid.isNone()) { \
- return std::function<R(ENUM_PARAMS(N, P))>(f); \
+ return std::function<R(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
} \
\
Option<UPID> pid_ = pid; \
- F f_ = f; \
+ F&& f_ = std::forward<F>(f); \
\
return std::function<R(ENUM_PARAMS(N, P))>( \
[=](ENUM_BINARY_PARAMS(N, P, p)) { \
@@ -231,47 +233,63 @@ private:
template <typename G>
friend _Deferred<G> defer(const UPID& pid, G&& g);
-#define TEMPLATE(Z, N, DATA) \
- template <typename T, \
- ENUM_PARAMS(N, typename P), \
- ENUM_PARAMS(N, typename A)> \
- friend auto defer(const PID<T>& pid, \
- void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<void(ENUM_PARAMS(N, P))>::operator(), std::function<void(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))>; // NOLINT(whitespace/line_length)
+// This assumes type and variable base names are `A` and `a` respectively.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+
+#define TEMPLATE(Z, N, DATA) \
+ template <typename T, \
+ ENUM_PARAMS(N, typename P), \
+ ENUM_PARAMS(N, typename A)> \
+ friend auto defer(const PID<T>& pid, \
+ void (T::*method)(ENUM_PARAMS(N, P)), \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<void(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<void(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))>;
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
#undef TEMPLATE
-#define TEMPLATE(Z, N, DATA) \
- template <typename R, \
- typename T, \
- ENUM_PARAMS(N, typename P), \
- ENUM_PARAMS(N, typename A)> \
- friend auto defer(const PID<T>& pid, \
- Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))>; // NOLINT(whitespace/line_length)
+#define TEMPLATE(Z, N, DATA) \
+ template <typename R, \
+ typename T, \
+ ENUM_PARAMS(N, typename P), \
+ ENUM_PARAMS(N, typename A)> \
+ friend auto defer(const PID<T>& pid, \
+ Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))>;
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
#undef TEMPLATE
-#define TEMPLATE(Z, N, DATA) \
- template <typename R, \
- typename T, \
- ENUM_PARAMS(N, typename P), \
- ENUM_PARAMS(N, typename A)> \
- friend auto defer(const PID<T>& pid, \
- R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
- -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, a)))>; // NOLINT(whitespace/line_length)
+#define TEMPLATE(Z, N, DATA) \
+ template <typename R, \
+ typename T, \
+ ENUM_PARAMS(N, typename P), \
+ ENUM_PARAMS(N, typename A)> \
+ friend auto defer(const PID<T>& pid, \
+ R (T::*method)(ENUM_PARAMS(N, P)), \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
+ -> _Deferred<decltype( \
+ std::bind( \
+ &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+ std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
+ ENUM(N, FORWARD, _)))>;
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
#undef TEMPLATE
+#undef FORWARD
- _Deferred(const UPID& pid, F f) : pid(pid), f(f) {}
+ _Deferred(const UPID& pid, F&& f) : pid(pid), f(std::forward<F>(f)) {}
- /*implicit*/ _Deferred(F f) : f(f) {}
+ /*implicit*/ _Deferred(F&& f) : f(std::forward<F>(f)) {}
Option<UPID> pid;
F f;
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/dispatch.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/dispatch.hpp b/3rdparty/libprocess/include/process/dispatch.hpp
index 3a07938..096cae0 100644
--- a/3rdparty/libprocess/include/process/dispatch.hpp
+++ b/3rdparty/libprocess/include/process/dispatch.hpp
@@ -19,6 +19,7 @@
#include <process/process.hpp>
+#include <stout/lambda.hpp>
#include <stout/preprocessor.hpp>
#include <stout/result_of.hpp>
@@ -183,6 +184,11 @@ void dispatch(const Process<T>* process, void (T::*method)())
// Due to a bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933)
// with variadic templates and lambdas, we still need to do
// preprocessor expansions.
+
+// The following assumes base names for type and variable are `A` and `a`.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+#define DECL(Z, N, DATA) typename std::decay<A ## N>::type& a ## N
+
#define TEMPLATE(Z, N, DATA) \
template <typename T, \
ENUM_PARAMS(N, typename P), \
@@ -190,16 +196,19 @@ void dispatch(const Process<T>* process, void (T::*method)())
void dispatch( \
const PID<T>& pid, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
std::shared_ptr<std::function<void(ProcessBase*)>> f( \
new std::function<void(ProcessBase*)>( \
- [=](ProcessBase* process) { \
- assert(process != nullptr); \
- T* t = dynamic_cast<T*>(process); \
- assert(t != nullptr); \
- (t->*method)(ENUM_PARAMS(N, a)); \
- })); \
+ std::bind([method](ENUM(N, DECL, _), \
+ ProcessBase* process) { \
+ assert(process != nullptr); \
+ T* t = dynamic_cast<T*>(process); \
+ assert(t != nullptr); \
+ (t->*method)(ENUM_PARAMS(N, a)); \
+ }, \
+ ENUM(N, FORWARD, _), \
+ lambda::_1))); \
\
internal::dispatch(pid, f, &typeid(method)); \
} \
@@ -210,9 +219,9 @@ void dispatch(const Process<T>* process, void (T::*method)())
void dispatch( \
const Process<T>& process, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- dispatch(process.self(), method, ENUM_PARAMS(N, a)); \
+ dispatch(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename T, \
@@ -221,9 +230,9 @@ void dispatch(const Process<T>* process, void (T::*method)())
void dispatch( \
const Process<T>* process, \
void (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- dispatch(process->self(), method, ENUM_PARAMS(N, a)); \
+ dispatch(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -271,18 +280,22 @@ Future<R> dispatch(const Process<T>* process, Future<R> (T::*method)())
Future<R> dispatch( \
const PID<T>& pid, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
std::shared_ptr<Promise<R>> promise(new Promise<R>()); \
\
std::shared_ptr<std::function<void(ProcessBase*)>> f( \
new std::function<void(ProcessBase*)>( \
- [=](ProcessBase* process) { \
- assert(process != nullptr); \
- T* t = dynamic_cast<T*>(process); \
- assert(t != nullptr); \
- promise->associate((t->*method)(ENUM_PARAMS(N, a))); \
- })); \
+ std::bind([promise, method](ENUM(N, DECL, _), \
+ ProcessBase* process) { \
+ assert(process != nullptr); \
+ T* t = dynamic_cast<T*>(process); \
+ assert(t != nullptr); \
+ promise->associate( \
+ (t->*method)(ENUM_PARAMS(N, a))); \
+ }, \
+ ENUM(N, FORWARD, _), \
+ lambda::_1))); \
\
internal::dispatch(pid, f, &typeid(method)); \
\
@@ -296,9 +309,9 @@ Future<R> dispatch(const Process<T>* process, Future<R> (T::*method)())
Future<R> dispatch( \
const Process<T>& process, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- return dispatch(process.self(), method, ENUM_PARAMS(N, a)); \
+ return dispatch(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -308,9 +321,9 @@ Future<R> dispatch(const Process<T>* process, Future<R> (T::*method)())
Future<R> dispatch( \
const Process<T>* process, \
Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- return dispatch(process->self(), method, ENUM_PARAMS(N, a)); \
+ return dispatch(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -358,18 +371,21 @@ Future<R> dispatch(const Process<T>* process, R (T::*method)())
Future<R> dispatch( \
const PID<T>& pid, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
std::shared_ptr<Promise<R>> promise(new Promise<R>()); \
\
std::shared_ptr<std::function<void(ProcessBase*)>> f( \
new std::function<void(ProcessBase*)>( \
- [=](ProcessBase* process) { \
- assert(process != nullptr); \
- T* t = dynamic_cast<T*>(process); \
- assert(t != nullptr); \
- promise->set((t->*method)(ENUM_PARAMS(N, a))); \
- })); \
+ std::bind([promise, method](ENUM(N, DECL, _), \
+ ProcessBase* process) { \
+ assert(process != nullptr); \
+ T* t = dynamic_cast<T*>(process); \
+ assert(t != nullptr); \
+ promise->set((t->*method)(ENUM_PARAMS(N, a))); \
+ }, \
+ ENUM(N, FORWARD, _), \
+ lambda::_1))); \
\
internal::dispatch(pid, f, &typeid(method)); \
\
@@ -383,9 +399,9 @@ Future<R> dispatch(const Process<T>* process, R (T::*method)())
Future<R> dispatch( \
const Process<T>& process, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- return dispatch(process.self(), method, ENUM_PARAMS(N, a)); \
+ return dispatch(process.self(), method, ENUM(N, FORWARD, _)); \
} \
\
template <typename R, \
@@ -395,14 +411,16 @@ Future<R> dispatch(const Process<T>* process, R (T::*method)())
Future<R> dispatch( \
const Process<T>* process, \
R (T::*method)(ENUM_PARAMS(N, P)), \
- ENUM_BINARY_PARAMS(N, A, a)) \
+ ENUM_BINARY_PARAMS(N, A, &&a)) \
{ \
- return dispatch(process->self(), method, ENUM_PARAMS(N, a)); \
+ return dispatch(process->self(), method, ENUM(N, FORWARD, _)); \
}
REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
#undef TEMPLATE
+#undef DECL
+#undef FORWARD
// We use partial specialization of
// - internal::Dispatch<void> vs
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/future.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/future.hpp b/3rdparty/libprocess/include/process/future.hpp
index cce9505..2f5f0a2 100644
--- a/3rdparty/libprocess/include/process/future.hpp
+++ b/3rdparty/libprocess/include/process/future.hpp
@@ -175,32 +175,34 @@ public:
template <typename F>
const Future<T>& onDiscard(_Deferred<F>&& deferred) const
{
- return onDiscard(deferred.operator std::function<void()>());
+ return onDiscard(std::move(deferred).operator std::function<void()>());
}
template <typename F>
const Future<T>& onReady(_Deferred<F>&& deferred) const
{
- return onReady(deferred.operator std::function<void(const T&)>());
+ return onReady(
+ std::move(deferred).operator std::function<void(const T&)>());
}
template <typename F>
const Future<T>& onFailed(_Deferred<F>&& deferred) const
{
return onFailed(
- deferred.operator std::function<void(const std::string&)>());
+ std::move(deferred).operator std::function<void(const std::string&)>());
}
template <typename F>
const Future<T>& onDiscarded(_Deferred<F>&& deferred) const
{
- return onDiscarded(deferred.operator std::function<void()>());
+ return onDiscarded(std::move(deferred).operator std::function<void()>());
}
template <typename F>
const Future<T>& onAny(_Deferred<F>&& deferred) const
{
- return onAny(deferred.operator std::function<void(const Future<T>&)>());
+ return onAny(
+ std::move(deferred).operator std::function<void(const Future<T>&)>());
}
private:
@@ -334,21 +336,22 @@ public:
// and associates the result of the callback with the future that is
// returned to the caller (which may be of a different type).
template <typename X>
- Future<X> then(const lambda::function<Future<X>(const T&)>& f) const;
+ Future<X> then(lambda::function<Future<X>(const T&)> f) const;
template <typename X>
- Future<X> then(const lambda::function<X(const T&)>& f) const;
+ Future<X> then(lambda::function<X(const T&)> f) const;
template <typename X>
- Future<X> then(const lambda::function<Future<X>()>& f) const
+ Future<X> then(lambda::function<Future<X>()> f) const
{
- return then(lambda::function<Future<X>(const T&)>(lambda::bind(f)));
+ return then(
+ lambda::function<Future<X>(const T&)>(lambda::bind(std::move(f))));
}
template <typename X>
- Future<X> then(const lambda::function<X()>& f) const
+ Future<X> then(lambda::function<X()> f) const
{
- return then(lambda::function<X(const T&)>(lambda::bind(f)));
+ return then(lambda::function<X(const T&)>(lambda::bind(std::move(f))));
}
private:
@@ -360,7 +363,7 @@ private:
{
// note the then<X> is necessary to not have an infinite loop with
// then(F&& f)
- return then<X>(f.operator std::function<Future<X>(const T&)>());
+ return then<X>(std::move(f).operator std::function<Future<X>(const T&)>());
}
// Refer to the less preferred version of `onReady` for why these SFINAE
@@ -373,13 +376,13 @@ private:
F>::type()>::type>::type>
Future<X> then(_Deferred<F>&& f, LessPrefer) const
{
- return then<X>(f.operator std::function<Future<X>()>());
+ return then<X>(std::move(f).operator std::function<Future<X>()>());
}
template <typename F, typename X = typename internal::unwrap<typename result_of<F(const T&)>::type>::type> // NOLINT(whitespace/line_length)
Future<X> then(F&& f, Prefer) const
{
- return then<X>(std::function<Future<X>(const T&)>(f));
+ return then<X>(std::function<Future<X>(const T&)>(std::forward<F>(f)));
}
// Refer to the less preferred version of `onReady` for why these SFINAE
@@ -392,7 +395,7 @@ private:
F>::type()>::type>::type>
Future<X> then(F&& f, LessPrefer) const
{
- return then<X>(std::function<Future<X>()>(f));
+ return then<X>(std::function<Future<X>()>(std::forward<F>(f)));
}
public:
@@ -1396,14 +1399,14 @@ void after(
template <typename T>
template <typename X>
-Future<X> Future<T>::then(const lambda::function<Future<X>(const T&)>& f) const
+Future<X> Future<T>::then(lambda::function<Future<X>(const T&)> f) const
{
std::shared_ptr<Promise<X>> promise(new Promise<X>());
lambda::function<void(const Future<T>&)> thenf =
- lambda::bind(&internal::thenf<T, X>, f, promise, lambda::_1);
+ lambda::bind(&internal::thenf<T, X>, std::move(f), promise, lambda::_1);
- onAny(thenf);
+ onAny(std::move(thenf));
// Propagate discarding up the chain. To avoid cyclic dependencies,
// we keep a weak future in the callback.
@@ -1416,14 +1419,14 @@ Future<X> Future<T>::then(const lambda::function<Future<X>(const T&)>& f) const
template <typename T>
template <typename X>
-Future<X> Future<T>::then(const lambda::function<X(const T&)>& f) const
+Future<X> Future<T>::then(lambda::function<X(const T&)> f) const
{
std::shared_ptr<Promise<X>> promise(new Promise<X>());
lambda::function<void(const Future<T>&)> then =
- lambda::bind(&internal::then<T, X>, f, promise, lambda::_1);
+ lambda::bind(&internal::then<T, X>, std::move(f), promise, lambda::_1);
- onAny(then);
+ onAny(std::move(then));
// Propagate discarding up the chain. To avoid cyclic dependencies,
// we keep a weak future in the callback.
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/http.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/http.hpp b/3rdparty/libprocess/include/process/http.hpp
index f637999..ba1b086 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -1017,7 +1017,8 @@ Future<Nothing> serve(
template <typename F>
Future<Nothing> serve(const network::Socket& s, F&& f)
{
- return internal::serve(s, std::function<Future<Response>(const Request&)>(f));
+ return internal::serve(
+ s, std::function<Future<Response>(const Request&)>(std::forward<F>(f)));
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/src/tests/benchmarks.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/benchmarks.cpp b/3rdparty/libprocess/src/tests/benchmarks.cpp
index 245ff77..a691705 100644
--- a/3rdparty/libprocess/src/tests/benchmarks.cpp
+++ b/3rdparty/libprocess/src/tests/benchmarks.cpp
@@ -488,3 +488,89 @@ TEST(ProcessTest, Process_BENCHMARK_ThroughputPerformance)
wait(destination->self());
}
}
+
+
+class DispatchProcess : public Process<DispatchProcess>
+{
+public:
+ struct Movable
+ {
+ std::vector<int> data;
+ };
+
+ // This simulates protobuf objects, which do not support moves.
+ struct Copyable
+ {
+ std::vector<int> data;
+
+ Copyable(std::vector<int>&& data) : data(std::move(data)) {}
+ Copyable(const Copyable& that) = default;
+ Copyable& operator=(const Copyable&) = default;
+ };
+
+ DispatchProcess(Promise<Nothing> *promise, long repeat)
+ : promise(promise), repeat(repeat) {}
+
+ template <typename T>
+ Future<Nothing> handler(const T& data)
+ {
+ count++;
+ if (count >= repeat) {
+ promise->set(Nothing());
+ return Nothing();
+ }
+
+ dispatch(self(), &Self::_handler).then(
+ defer(self(), &Self::handler<T>, data));
+
+ return Nothing();
+ }
+
+ template <typename T>
+ static void run(const string& name, long repeats)
+ {
+ Promise<Nothing> promise;
+
+ Owned<DispatchProcess> process(new DispatchProcess(&promise, repeats));
+ spawn(*process);
+
+ T data{std::vector<int>(10240, 42)};
+
+ Stopwatch watch;
+ watch.start();
+
+ dispatch(process.get(), &DispatchProcess::handler<T>, data);
+
+ AWAIT_READY(promise.future());
+
+ cout << name << " elapsed: " << watch.elapsed() << endl;
+
+ terminate(process.get());
+ wait(process.get());
+ }
+
+private:
+ Future<Nothing> _handler()
+ {
+ return Nothing();
+ }
+
+ Promise<Nothing> *promise;
+ long repeat;
+ long count = 0;
+};
+
+
+TEST(ProcessTest, Process_BENCHMARK_DispatchDefer)
+{
+ constexpr long repeats = 100000;
+
+ // Test performance separately for objects which support std::move,
+ // and which don't (e.g. like protobufs).
+ // Note: DispatchProcess::handler code is not fully optimized,
+ // to take advantage of std::move support, e.g. parameter is passed
+ // by const reference, so some copying is unavoidable, however
+ // this resembles how most of the handlers are currently implemented.
+ DispatchProcess::run<DispatchProcess::Movable>("Movable", repeats);
+ DispatchProcess::run<DispatchProcess::Copyable>("Copyable", repeats);
+}