Commit 911a6c37 authored by Sebastian Woelke's avatar Sebastian Woelke

Test mailbox performance

parent b89c7db8
...@@ -8,38 +8,167 @@ using std::string; ...@@ -8,38 +8,167 @@ using std::string;
using namespace caf; using namespace caf;
behavior mirror(event_based_actor* self) { using ping_atom = atom_constant<atom("ping")>;
// return the (initial) actor behavior using pong_atom = atom_constant<atom("pong")>;
behavior ping(event_based_actor* self, actor pong_actor, int num) {
self->send(pong_actor, ping_atom::value, 0);
return {
[=](pong_atom, int x) {
if (x == num)
self->quit();
return std::make_tuple(ping_atom::value, x + 1);
}
};
}
behavior pong() {
return {
[=](ping_atom, int x) {
return std::make_tuple(pong_atom::value, x);
}
};
}
behavior vping() {
return { return {
// a handler for messages containing a single string [=](pong_atom, int) {
// that replies with a string // nop
[=](const string& what) -> string {
// prints "Hello World!" via aout (thread-safe cout wrapper)
aout(self) << what << endl;
// reply "!dlroW olleH"
return string(what.rbegin(), what.rend());
} }
}; };
} }
void hello_world(event_based_actor* self, const actor& buddy) { behavior vpong() {
// send "Hello World!" to our buddy ... return {
self->request(buddy, std::chrono::seconds(10), "Hello World!").then( [=](ping_atom, int) {
// ... wait up to 10s for a response ... // nop
[=](const string& what) {
// ... and print it
aout(self) << what << endl;
} }
); };
} }
struct config : actor_system_config {
int n;
int impl;
config() : n(1000), impl(0) {
opt_group{custom_options_, "global"}
.add(n, "num,n", "set nr. of ping messages")
.add(impl, "impl,i", "select implementation");
}
};
int main() { // full CAF stack CAF with mailbox and scheduler
// our CAF environment void impl0(actor_system& sys, const config& cfg) {
actor_system_config cfg; sys.spawn(ping, sys.spawn(pong), cfg.n);
actor_system system{cfg};
// create a new actor that calls 'mirror()'
auto mirror_actor = system.spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)';
system.spawn(hello_world, mirror_actor);
// system will wait until both actors are destroyed before leaving main
} }
#define fixture \
auto pi_hdl = actor_cast<strong_actor_ptr>(sys.spawn<lazy_init>(vping)); \
auto po_hdl = actor_cast<strong_actor_ptr>(sys.spawn<lazy_init>(vpong)); \
auto pi = dynamic_cast<scheduled_actor*>(pi_hdl->get()); \
auto po = dynamic_cast<scheduled_actor*>(po_hdl->get()); \
auto ctx = sys.dummy_execution_unit()
// bypass scheduler + mailbox, allocate mailbox elements, wrap message content
void impl1(actor_system& sys, const config& cfg) {
fixture;
for (auto i = 0; i < cfg.n; ++i) {
{
auto m1 = make_mailbox_element(pi_hdl, message_id::make(), {},
make_message(ping_atom::value, i));
po->activate(ctx, *m1);
}
{
auto m2 = make_mailbox_element(pi_hdl, message_id::make(), {},
make_message(pong_atom::value, i));
pi->activate(ctx, *m2);
}
}
}
// bypass scheduler + mailbox, allocate mailbox elements, don't wrap message content
void impl2(actor_system& sys, const config& cfg) {
fixture;
for (auto i = 0; i < cfg.n; ++i) {
{
auto m1 = make_mailbox_element(pi_hdl, message_id::make(), {}, ping_atom::value, i);
po->activate(ctx, *m1);
}
{
auto m2 = make_mailbox_element(pi_hdl, message_id::make(), {}, pong_atom::value, i);
pi->activate(ctx, *m2);
}
}
}
// bypass scheduler + mailbox, don't allocate mailbox elements, wrap message content
void impl3(actor_system& sys, const config& cfg) {
fixture;
mailbox_element_wrapper me{strong_actor_ptr{}, message_id::make(),
mailbox_element::forwarding_stack{},
make_message()};
for (auto i = 0; i < cfg.n; ++i) {
me.sender = pi_hdl;
me.msg = make_message(ping_atom::value, i);
po->activate(ctx, me);
me.sender = po_hdl;
me.msg = make_message(pong_atom::value, i);
pi->activate(ctx, me);
}
}
// bypass scheduler + mailbox, don't allocate mailbox elements, don't wrap message content
void impl4(actor_system& sys, const config& cfg) {
fixture;
using vals_t = mailbox_element_vals<atom_value, int>;
struct x_t {
x_t() {}
~x_t() {}
union { vals_t me; };
} x;
auto construct = [&](strong_actor_ptr hdl, atom_value atm, int i) {
mailbox_element::forwarding_stack tmp;
new (&x.me) vals_t(std::move(hdl), message_id::make(),
std::move(tmp), atm, i);
};
for (auto i = 0; i < cfg.n; ++i) {
construct(pi_hdl, ping_atom::value, i);
po->activate(ctx, x.me);
x.me.~vals_t();
construct(po_hdl, pong_atom::value, i);
pi->activate(ctx, x.me);
x.me.~vals_t();
}
}
// bypass scheduler + mailbox, allocate mailbox elements, wrap message content
void impl5(actor_system& sys, const config& cfg) {
fixture;
for (auto i = 0; i < cfg.n; ++i) {
{
auto m1 = make_mailbox_element(pi_hdl, message_id::make(), {},
make_message(ping_atom::value, i));
po->mailbox().enqueue(m1.release());
po->resume(ctx, 1);
}
{
auto m2 = make_mailbox_element(pi_hdl, message_id::make(), {},
make_message(pong_atom::value, i));
pi->mailbox().enqueue(m2.release());
pi->resume(ctx, 1);
}
}
}
// for i in {0..5}; do echo -n "impl:$i "; runtime ./hello_world --impl=$i --num=2000000; done
// for i in {0..5}; do echo -n "impl:$i "; runtime ./hello_world --caf#scheduler.policy='sharing' --caf#scheduler.max-threads=1 --impl=$i --num=2000000; done
void caf_main(actor_system& sys, const config& cfg) {
if (cfg.impl == 0) {
sys.spawn(ping, sys.spawn(pong), cfg.n);
return;
}
using impl_fun = void (*)(actor_system&, const config&);
impl_fun impls[] = {impl0, impl1, impl2, impl3, impl4, impl5};
impls[cfg.impl](sys, cfg);
}
CAF_MAIN()
...@@ -99,7 +99,23 @@ typename Inspector::result_type inspect(Inspector& f, mailbox_element& x) { ...@@ -99,7 +99,23 @@ typename Inspector::result_type inspect(Inspector& f, mailbox_element& x) {
meta::omittable_if_empty(), x.stages, x.content()); meta::omittable_if_empty(), x.stages, x.content());
} }
/// Encapsulates arbitrary data in a message element. /// Stores the content in a `message`.
class mailbox_element_wrapper : public mailbox_element {
public:
mailbox_element_wrapper(strong_actor_ptr&& x0, message_id x1,
forwarding_stack&& x2, message&& x3);
type_erased_tuple& content() override;
message move_content_to_message() override;
message copy_content_to_message() const override;
/// Stores the content of this mailbox element.
message msg;
};
/// Stores the content in a tuple.
template <class... Ts> template <class... Ts>
class mailbox_element_vals class mailbox_element_vals
: public mailbox_element, : public mailbox_element,
...@@ -134,7 +150,7 @@ public: ...@@ -134,7 +150,7 @@ public:
} }
}; };
/// Provides a view for treating arbitrary data as message element. /// Stores references to the content in a tuple.
template <class... Ts> template <class... Ts>
class mailbox_element_view : public mailbox_element, class mailbox_element_view : public mailbox_element,
public detail::type_erased_tuple_view<Ts...> { public detail::type_erased_tuple_view<Ts...> {
......
...@@ -21,39 +21,28 @@ ...@@ -21,39 +21,28 @@
namespace caf { namespace caf {
namespace { mailbox_element_wrapper::mailbox_element_wrapper(strong_actor_ptr&& x0,
message_id x1,
/// Wraps a `message` into a mailbox element. forwarding_stack&& x2,
class mailbox_element_wrapper : public mailbox_element { message&& x3)
public: : mailbox_element(std::move(x0), x1, std::move(x2)), msg(std::move(x3)) {
mailbox_element_wrapper(strong_actor_ptr&& x0, message_id x1, // nop
forwarding_stack&& x2, message&& x3) }
: mailbox_element(std::move(x0), x1, std::move(x2)),
msg_(std::move(x3)) {
// nop
}
type_erased_tuple& content() override {
auto ptr = msg_.vals().raw_ptr();
if (ptr != nullptr)
return *ptr;
return dummy_;
}
message move_content_to_message() override {
return std::move(msg_);
}
message copy_content_to_message() const override { type_erased_tuple& mailbox_element_wrapper::content() {
return msg_; auto ptr = msg.vals().raw_ptr();
} if (ptr != nullptr)
return *ptr;
return dummy_;
}
private: message mailbox_element_wrapper::move_content_to_message() {
/// Stores the content of this mailbox element. return std::move(msg);
message msg_; }
};
} // namespace <anonymous> message mailbox_element_wrapper::copy_content_to_message() const {
return msg;
}
mailbox_element::mailbox_element() mailbox_element::mailbox_element()
: next(nullptr), : next(nullptr),
......
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