From beb6599ee4385fdffc747dc866db46e160be1358 Mon Sep 17 00:00:00 2001 From: Dawid Drozd Date: Tue, 24 Jul 2018 14:16:05 +0200 Subject: [PATCH] Add performance compare to Poco::NotifactionCenter --- performance/CMakeLists.txt | 14 +- performance/src/EventBusPerformance.cpp | 269 +++++++++--------- .../src/PocoNotificationCenterPerformance.cpp | 101 +++++++ 3 files changed, 239 insertions(+), 145 deletions(-) create mode 100644 performance/src/PocoNotificationCenterPerformance.cpp diff --git a/performance/CMakeLists.txt b/performance/CMakeLists.txt index a02faec..06aea99 100644 --- a/performance/CMakeLists.txt +++ b/performance/CMakeLists.txt @@ -3,11 +3,13 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) # http://www.levelofindirection.com/journal/2010/12/28/unit-testing-in-c-and-objective-c-just-got-easier.html # Thanks for CATCH! +find_package(Poco COMPONENTS Foundation Util) + add_subdirectory(benchmark/) -if(NOT TARGET Dexode::EventBus) +if (NOT TARGET Dexode::EventBus) find_package(EventBus CONFIG REQUIRED) -endif() +endif () # If you want to compare with CCNotificationCenter read about it in README and uncomment line below #INCLUDE(cocos2d-x-compare/Cocos2dxCompare.cmake) @@ -15,6 +17,7 @@ endif() add_executable(EventBusPerformance src/EventBusPerformance.cpp ${CCNOTIFICATION_CENTER_SRC} + $<$:src/PocoEventBus.cpp> ) target_compile_options(EventBusPerformance PUBLIC @@ -38,4 +41,9 @@ target_include_directories(EventBusPerformance PUBLIC ${CCNOTIFICATION_CENTER_INCLUDE} ) -target_link_libraries(EventBusPerformance PUBLIC Dexode::EventBus benchmark) +target_link_libraries(EventBusPerformance PUBLIC + Dexode::EventBus + benchmark + $<$:Poco::Foundation> + $<$:Poco::Util> + ) \ No newline at end of file diff --git a/performance/src/EventBusPerformance.cpp b/performance/src/EventBusPerformance.cpp index 41bdd49..11363a0 100644 --- a/performance/src/EventBusPerformance.cpp +++ b/performance/src/EventBusPerformance.cpp @@ -19,17 +19,15 @@ void checkNListeners(benchmark::State& state, const int listenersCount) int value; }; - for (int i = 0; i < listenersCount; ++i) + for(int i = 0; i < listenersCount; ++i) { - bus.listen([&](const SimpleEvent& event) - { - benchmark::DoNotOptimize(sum += event.value * 2); - }); + bus.listen( + [&](const SimpleEvent& event) { benchmark::DoNotOptimize(sum += event.value * 2); }); } - const auto event = SimpleEvent{2}; - while (state.KeepRunning())//Performance area! + while(state.KeepRunning()) // Performance area! { + const auto event = SimpleEvent{2}; bus.notify(event); } state.counters["sum"] = sum; @@ -60,18 +58,15 @@ void call1kLambdas_compare(benchmark::State& state) int sum = 0; std::vector> callbacks; callbacks.reserve(1000); - for (int i = 0; i < 1000; ++i) + for(int i = 0; i < 1000; ++i) { - callbacks.emplace_back([&](int value) - { - benchmark::DoNotOptimize(sum += value * 2); - }); + callbacks.emplace_back([&](int value) { benchmark::DoNotOptimize(sum += value * 2); }); } - while (state.KeepRunning())//Performance area! + while(state.KeepRunning()) // Performance area! { - for (int i = 0; i < 1000; ++i) - // for (auto& callback :callbacks) + for(int i = 0; i < 1000; ++i) + // for (auto& callback :callbacks) { callbacks[i](2); } @@ -79,140 +74,133 @@ void call1kLambdas_compare(benchmark::State& state) state.counters["sum"] = sum; } -template +template struct SimpleEvent { int value = N; }; -void checkNNotificationsForNListeners(benchmark::State& state, const int notificationsCount, const int listenersCount) +void checkNNotificationsForNListeners(benchmark::State& state, + const int notificationsCount, + const int listenersCount) { std::mt19937 generator(311281); std::uniform_int_distribution uniformDistribution(0, notificationsCount - 1); Dexode::EventBus bus; int sum = 0; - for (int i = 0; i < listenersCount; ++i)//We register M listeners for N notifications using uniform distribution + for(int i = 0; i < listenersCount; + ++i) // We register M listeners for N notifications using uniform distribution { const auto which = uniformDistribution(generator); - //We generate here N different notifications - switch (which) + // We generate here N different notifications + switch(which) { - case 0: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 1: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 2: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 3: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 4: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 5: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 6: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 7: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 8: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - case 9: - bus.listen>([&](const auto& event) - { - benchmark::DoNotOptimize(sum += event.value * - 2);//we use it to prevent some? optimizations - }); - break; - default: - assert(false); + case 0: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 1: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 2: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 3: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 4: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 5: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 6: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 7: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 8: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + case 9: + bus.listen>([&](const auto& event) { + benchmark::DoNotOptimize(sum += event.value * + 2); // we use it to prevent some? optimizations + }); + break; + default: + assert(false); } } - while (state.KeepRunning())//Performance area! + while(state.KeepRunning()) // Performance area! { - //Pick random notification + // Pick random notification const auto which = uniformDistribution(generator); const auto number = uniformDistribution(generator); - //We generate here N different notifications - switch (which) + // We generate here N different notifications + switch(which) { - case 0: - bus.notify(SimpleEvent<0>{number}); - break; - case 1: - bus.notify(SimpleEvent<1>{number}); - break; - case 2: - bus.notify(SimpleEvent<2>{number}); - break; - case 3: - bus.notify(SimpleEvent<3>{number}); - break; - case 4: - bus.notify(SimpleEvent<4>{number}); - break; - case 5: - bus.notify(SimpleEvent<5>{number}); - break; - case 6: - bus.notify(SimpleEvent<6>{number}); - break; - case 7: - bus.notify(SimpleEvent<7>{number}); - break; - case 8: - bus.notify(SimpleEvent<8>{number}); - break; - case 9: - bus.notify(SimpleEvent<9>{number}); - break; - default: - assert(false); + case 0: + bus.notify(SimpleEvent<0>{number}); + break; + case 1: + bus.notify(SimpleEvent<1>{number}); + break; + case 2: + bus.notify(SimpleEvent<2>{number}); + break; + case 3: + bus.notify(SimpleEvent<3>{number}); + break; + case 4: + bus.notify(SimpleEvent<4>{number}); + break; + case 5: + bus.notify(SimpleEvent<5>{number}); + break; + case 6: + bus.notify(SimpleEvent<6>{number}); + break; + case 7: + bus.notify(SimpleEvent<7>{number}); + break; + case 8: + bus.notify(SimpleEvent<8>{number}); + break; + case 9: + bus.notify(SimpleEvent<9>{number}); + break; + default: + assert(false); } } state.counters["sum"] = sum; @@ -223,18 +211,18 @@ void check10NotificationsFor1kListeners(benchmark::State& state) checkNNotificationsForNListeners(state, 10, 1000); } -//Sorry not available -//void check100NotificationsFor1kListeners(benchmark::State& state) +// Sorry not available +// void check100NotificationsFor1kListeners(benchmark::State& state) //{ // checkNNotificationsForNListeners(state, 100, 1000); //} // -//void check1kNotificationsFor1kListeners(benchmark::State& state) +// void check1kNotificationsFor1kListeners(benchmark::State& state) //{ // checkNNotificationsForNListeners(state, 1000, 1000); //} // -//void check100NotificationsFor10kListeners(benchmark::State& state) +// void check100NotificationsFor10kListeners(benchmark::State& state) //{ // checkNNotificationsForNListeners(state, 100, 10000); //} @@ -251,22 +239,19 @@ void checkNotifyFor10kListenersWhenNoOneListens(benchmark::State& state) { int value; }; - for (int i = 0; i < 10000; ++i) + for(int i = 0; i < 10000; ++i) { - bus.listen([&](const SimpleEvent& event) - { - benchmark::DoNotOptimize(sum += event.value * 2); - }); + bus.listen( + [&](const SimpleEvent& event) { benchmark::DoNotOptimize(sum += event.value * 2); }); } const auto unknownEvent = UnknownEvent{2}; - while (state.KeepRunning())//Performance area! + while(state.KeepRunning()) // Performance area! { bus.notify(unknownEvent); } state.counters["sum"] = sum; } - } BENCHMARK(call1kLambdas_compare); @@ -276,9 +261,9 @@ BENCHMARK(check10Listeners); BENCHMARK(check100Listeners); BENCHMARK(check1kListeners); BENCHMARK(check10NotificationsFor1kListeners); -//BENCHMARK(check100NotificationsFor1kListeners); //Not available -//BENCHMARK(check1kNotificationsFor1kListeners); //Not available -//BENCHMARK(check100NotificationsFor10kListeners); //Not available +// BENCHMARK(check100NotificationsFor1kListeners); //Not available +// BENCHMARK(check1kNotificationsFor1kListeners); //Not available +// BENCHMARK(check100NotificationsFor10kListeners); //Not available BENCHMARK(checkNotifyFor10kListenersWhenNoOneListens); BENCHMARK_MAIN() diff --git a/performance/src/PocoNotificationCenterPerformance.cpp b/performance/src/PocoNotificationCenterPerformance.cpp new file mode 100644 index 0000000..bbf7a47 --- /dev/null +++ b/performance/src/PocoNotificationCenterPerformance.cpp @@ -0,0 +1,101 @@ +// +// Created by Dawid Drozd aka Gelldur on 24.07.18. +// +#include +#include + +#include + +#include +#include +#include + +namespace +{ + +template +struct Wrapper : public Poco::Notification +{ + T data; + + Wrapper(T data) + : data(std::move(data)) + { + } +}; + +template +class Target +{ +public: + Target(std::function callback) + : _callback(std::move(callback)) + { + } + + void handle(const Poco::AutoPtr>& event) + { + _callback((*event.get()).data); + } + +private: + std::function _callback; +}; + +void checkNListeners(benchmark::State& state, const int listenersCount) +{ + Poco::NotificationCenter bus; + int sum = 0; + + struct SimpleEvent + { + int value; + }; + + using MyEvent = Wrapper; + using Listener = Target; + + std::vector targets; + targets.reserve(listenersCount + 1); + + for(int i = 0; i < listenersCount; ++i) + { + targets.emplace_back( + [&](const SimpleEvent& event) { benchmark::DoNotOptimize(sum += event.value * 2); }); + + bus.addObserver(Poco::NObserver(targets.back(), &Listener::handle)); + } + + while(state.KeepRunning()) // Performance area! + { + const Poco::AutoPtr event = new Wrapper{SimpleEvent{2}}; + bus.postNotification(event); + } + state.counters["sum"] = sum; +} + +void Poco_checkSimpleNotification(benchmark::State& state) +{ + checkNListeners(state, 1); +} + +void Poco_check10Listeners(benchmark::State& state) +{ + checkNListeners(state, 10); +} + +void Poco_check100Listeners(benchmark::State& state) +{ + checkNListeners(state, 100); +} + +void Poco_check1kListeners(benchmark::State& state) +{ + checkNListeners(state, 1000); +} + +BENCHMARK(Poco_checkSimpleNotification); +BENCHMARK(Poco_check10Listeners); +BENCHMARK(Poco_check100Listeners); +BENCHMARK(Poco_check1kListeners); +} \ No newline at end of file