mirror of
https://github.com/gelldur/EventBus.git
synced 2024-12-27 12:21:02 +08:00
Add new implementation of EventBus
Simply new version breaks back compability and simply is better ;)
This commit is contained in:
parent
2cb0e6e60f
commit
1db41d903a
@ -9,7 +9,9 @@ PROJECT(EventBus
|
||||
ADD_LIBRARY(EventBus
|
||||
src/eventbus/EventCollector.cpp include/eventbus/EventCollector.h
|
||||
src/eventbus/Notification.cpp include/eventbus/Notification.h
|
||||
include/eventbus/Notification2.h
|
||||
include/eventbus/Notifier.h
|
||||
include/eventbus/EventBus.h
|
||||
)
|
||||
ADD_LIBRARY(Dexode::EventBus ALIAS EventBus)
|
||||
|
||||
@ -20,8 +22,12 @@ TARGET_INCLUDE_DIRECTORIES(EventBus PUBLIC
|
||||
)
|
||||
|
||||
TARGET_COMPILE_OPTIONS(EventBus
|
||||
PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-std=c++14>
|
||||
PRIVATE -Wall -pedantic -Wno-unused-private-field -Wnon-virtual-dtor -Werror
|
||||
PRIVATE -Wall -pedantic -Wno-unused-private-field -Wnon-virtual-dtor #-Werror
|
||||
)
|
||||
|
||||
SET_TARGET_PROPERTIES(EventBus PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
)
|
||||
|
||||
TARGET_COMPILE_FEATURES(EventBus
|
||||
|
202
include/eventbus/EventBus.h
Normal file
202
include/eventbus/EventBus.h
Normal file
@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Notification2.h"
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
#error This library needs at least a C++14 compliant compiler
|
||||
#endif
|
||||
|
||||
namespace Dexode
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct eventbus_traits
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class EventBus
|
||||
{
|
||||
public:
|
||||
EventBus() = default;
|
||||
|
||||
~EventBus()
|
||||
{
|
||||
_callbacks.clear();
|
||||
}
|
||||
|
||||
EventBus(const EventBus&) = delete;
|
||||
EventBus(EventBus&&) = delete;
|
||||
|
||||
EventBus& operator=(EventBus&&) = delete;
|
||||
EventBus& operator=(const EventBus&) = delete;
|
||||
|
||||
/**
|
||||
* Register listener for notification. Returns token used for unlisten
|
||||
*
|
||||
* @param notification
|
||||
* @param callback - your callback to handle notification
|
||||
* @return token used for unlisten
|
||||
*/
|
||||
template<typename ... Args>
|
||||
int listen(const Notification2<Args...>& notification
|
||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||
{
|
||||
const int token = ++_tokener;
|
||||
listen(token, notification, callback);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register listener for notification. Returns token used for unlisten
|
||||
*
|
||||
* @param notification - name of your notification
|
||||
* @param callback - your callback to handle notification
|
||||
* @return token used for unlisten
|
||||
*/
|
||||
template<typename ... Args>
|
||||
int listen(const std::string& notificationName
|
||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||
{
|
||||
return listen(Dexode::Notification2<Args...>{notificationName}, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token - unique token for identification receiver. Simply pass token from @see EventBus::listen
|
||||
* @param notification - pass notification like "getNotificationXYZ()"
|
||||
* @param callback - your callback to handle notification
|
||||
*/
|
||||
template<typename ... Args>
|
||||
void listen(const int token
|
||||
, const Notification2<Args...>& notification
|
||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||
{
|
||||
using CallbackType = std::function<void(Args...)>;
|
||||
using Vector = VectorImpl<CallbackType>;
|
||||
|
||||
assert(callback && "Please set it");//Check for valid object
|
||||
|
||||
std::unique_ptr<VectorInterface>& vector = _callbacks[notification.getKey()];
|
||||
if (vector == nullptr)
|
||||
{
|
||||
vector.reset(new Vector{});
|
||||
}
|
||||
|
||||
assert(dynamic_cast<Vector*>(vector.get()));
|
||||
Vector* vectorImpl = static_cast<Vector*>(vector.get());
|
||||
vectorImpl->container.emplace_back(std::make_pair(callback, token));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token - token from EventBus::listen
|
||||
*/
|
||||
void unlistenAll(const int token)
|
||||
{
|
||||
for (auto& element : _callbacks)
|
||||
{
|
||||
element.second->remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token - token from EventBus::listen
|
||||
* @param notification - notification you wan't to unlisten. @see Notiier::listen
|
||||
*/
|
||||
template<typename NotificationType, typename ... Args>
|
||||
void unlisten(const int token, const NotificationType& notification)
|
||||
{
|
||||
auto found = _callbacks.find(notification.getKey());
|
||||
if (found != _callbacks.end())
|
||||
{
|
||||
found.second->remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename NotificationType, typename ... Args>
|
||||
void notify(const NotificationType& notification, Args&& ... params)
|
||||
{
|
||||
using CallbackType = typename notification_traits<NotificationType>::callback_type;
|
||||
using Vector = VectorImpl<CallbackType>;
|
||||
|
||||
auto found = _callbacks.find(notification.getKey());
|
||||
if (found == _callbacks.end())
|
||||
{
|
||||
return;// no such notifications
|
||||
}
|
||||
|
||||
std::unique_ptr<VectorInterface>& vector = found->second;
|
||||
assert(dynamic_cast<Vector*>(vector.get()));
|
||||
Vector* vectorImpl = static_cast<Vector*>(vector.get());
|
||||
|
||||
//Copy? TODO think about it Use 2 vectors?
|
||||
for (auto& element : vectorImpl->container)
|
||||
{
|
||||
element.first(std::forward<Args>(params)...);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to call this in form like: notify<int>("yes",value)
|
||||
// We can't reduce it to notify("yes",value)
|
||||
// It wouldn't be obvious which to call Notification<int> or Notification<int&>
|
||||
// So it can take to a lot of mistakes
|
||||
template<typename ... Args>
|
||||
void notify(const std::string& notificationName, Args&& ... params)
|
||||
{
|
||||
notify(Dexode::Notification2<Args...>{notificationName}, std::forward<Args>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
struct VectorInterface
|
||||
{
|
||||
virtual ~VectorInterface() = default;
|
||||
|
||||
virtual void remove(const int token) = 0;
|
||||
virtual void removeAll() = 0;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct VectorImpl : public VectorInterface
|
||||
{
|
||||
std::vector<std::pair<Type, int>> container;
|
||||
|
||||
virtual ~VectorImpl()
|
||||
{
|
||||
removeAll();
|
||||
}
|
||||
|
||||
virtual void removeAll() override
|
||||
{
|
||||
container.clear();
|
||||
}
|
||||
|
||||
virtual void remove(const int token) override
|
||||
{
|
||||
auto removeFrom = std::remove_if(container.begin(), container.end()
|
||||
, [token](const std::pair<Type, int>& element)
|
||||
{
|
||||
return element.second == token;
|
||||
});
|
||||
if (removeFrom == container.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
container.erase(removeFrom, container.end());
|
||||
}
|
||||
};
|
||||
|
||||
int _tokener = 0;
|
||||
std::map<std::size_t, std::unique_ptr<VectorInterface>> _callbacks;
|
||||
};
|
||||
|
||||
} /* namespace Dexode */
|
78
include/eventbus/Notification2.h
Normal file
78
include/eventbus/Notification2.h
Normal file
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
|
||||
namespace Dexode
|
||||
{
|
||||
|
||||
template<typename ... Args>
|
||||
class Notification2
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void(Args...)>;
|
||||
|
||||
constexpr explicit Notification2(const std::string& name)
|
||||
: _key{std::hash<std::string>{}(name + typeid(Callback).name())}
|
||||
, _name{name}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Notification2(const Notification2& other)
|
||||
: _key{other._key}
|
||||
, _name{other._name}
|
||||
{
|
||||
}
|
||||
|
||||
Notification2(Notification2&& other)
|
||||
: _key{other._key}
|
||||
, _name{other._name}
|
||||
{
|
||||
}
|
||||
|
||||
Notification2& operator=(Notification2&&) = delete;
|
||||
|
||||
Notification2& operator=(const Notification2&) = delete;
|
||||
|
||||
const size_t getKey() const
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
const std::string& getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
bool operator==(const Notification2& rhs) const
|
||||
{
|
||||
return _key == rhs._key &&
|
||||
_name == rhs._name;
|
||||
}
|
||||
|
||||
bool operator!=(const Notification2& rhs) const
|
||||
{
|
||||
return !(rhs == *this);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Notification2& notification)
|
||||
{
|
||||
stream << "Notification{name: " << notification._name << " key: " << notification._key;
|
||||
return stream;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::size_t _key;
|
||||
const std::string _name;
|
||||
};
|
||||
|
||||
template<typename NotificationType>
|
||||
struct notification_traits;
|
||||
|
||||
template<typename ... Args>
|
||||
struct notification_traits<Notification2<Args...>>
|
||||
{
|
||||
using callback_type = typename std::function<void(Args...)>;
|
||||
};
|
||||
|
||||
}
|
@ -4,13 +4,23 @@
|
||||
ADD_SUBDIRECTORY(benchmark/)
|
||||
|
||||
# If you want to compare with CCNotificationCenter read about it in README and uncomment line below
|
||||
INCLUDE(cocos2d-x-compare/Cocos2dxCompare.cmake)
|
||||
#INCLUDE(cocos2d-x-compare/Cocos2dxCompare.cmake)
|
||||
|
||||
ADD_EXECUTABLE(EventBusPerformance
|
||||
eventbus/EventBusPerformance.cpp
|
||||
eventbus/EventBus2Performance.cpp
|
||||
${CCNOTIFICATION_CENTER_SRC}
|
||||
)
|
||||
|
||||
TARGET_COMPILE_OPTIONS(EventBusPerformance
|
||||
PRIVATE -Wall -pedantic -Wno-unused-private-field -Wnon-virtual-dtor #-Werror
|
||||
)
|
||||
|
||||
SET_TARGET_PROPERTIES(EventBusPerformance PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
)
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(EventBusPerformance PRIVATE
|
||||
./
|
||||
${CCNOTIFICATION_CENTER_INCLUDE}
|
||||
|
@ -40,30 +40,44 @@ git apply ../CCNotificationCenterPerformance.patch
|
||||
|
||||
```
|
||||
Run on (8 X 3600 MHz CPU s)
|
||||
2017-08-05 19:30:38
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
2017-08-06 00:09:43
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations UserCounters...
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
checkSimpleNotification 6 ns 6 ns 109393759 sum=417.304M
|
||||
check10Listeners 22 ns 22 ns 32170743 sum=1.19845G
|
||||
check100Listeners 213 ns 213 ns 3299613 sum=1.2292G
|
||||
check1kListeners 2094 ns 2093 ns 333683 sum=1.24307G
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
call1kLambdas_compare 2181 ns 2181 ns 308722 sum=1.15008G
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
check10NotificationsFor1kListeners 267 ns 267 ns 2607581 sum=-1.81421G
|
||||
check100NotificationsFor1kListeners 107 ns 107 ns 6373043 sum=1.8782G
|
||||
check1kNotificationsFor1kListeners 129 ns 129 ns 5497132 sum=1.11759G
|
||||
check100NotificationsFor10kListeners 314 ns 314 ns 2226597 sum=543.525M
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
CCNotificationCenter_checkSimpleNotification 168 ns 168 ns 4259511 sum=16.2487M
|
||||
CCNotificationCenter_check10Listeners 275 ns 275 ns 2484477 sum=94.7753M
|
||||
CCNotificationCenter_check100Listeners 1399 ns 1398 ns 514899 sum=196.418M
|
||||
CCNotificationCenter_check1kListeners 13124 ns 13123 ns 53271 sum=203.213M
|
||||
CCNotificationCenter_check10NotificationsFor1kListeners 11379 ns 11378 ns 62138 sum=53.3993M
|
||||
CCNotificationCenter_check100NotificationsFor1kListeners 9583 ns 9582 ns 64665 sum=61.3059M
|
||||
CCNotificationCenter_check1kNotificationsFor1kListeners 9451 ns 9451 ns 64162 sum=61.5188M
|
||||
CCNotificationCenter_check100NotificationsFor10kListeners 107082 ns 107074 ns 6603 sum=62.1745M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check100Listeners 234 ns 234 ns 3006299 sum=1.11993G
|
||||
check100Listeners_EventBus2 216 ns 216 ns 3238994 sum=1.20662G
|
||||
check100Listeners_CCNotificationCenter 1353 ns 1353 ns 535779 sum=204.383M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check100NotificationsFor10kListeners 315 ns 315 ns 2208261 sum=370.782M
|
||||
check100NotificationsFor10kListeners_EventBus2 307 ns 307 ns 2288071 sum=1122.83M
|
||||
check100NotificationsFor10kListeners_CCNotificationCenter 109629 ns 109620 ns 6493 sum=61.1035M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check100NotificationsFor1kListeners 108 ns 108 ns 6351160 sum=1.85786G
|
||||
check100NotificationsFor1kListeners_EventBus2 102 ns 102 ns 6985920 sum=-1.55558G
|
||||
check100NotificationsFor1kListeners_CCNotificationCenter 9684 ns 9683 ns 67812 sum=64.3065M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check10Listeners 22 ns 22 ns 32136715 sum=1.19719G
|
||||
check10Listeners_EventBus2 21 ns 21 ns 32519065 sum=1.21143G
|
||||
check10Listeners_CCNotificationCenter 264 ns 264 ns 2572170 sum=98.1205M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check10NotificationsFor1kListeners 273 ns 273 ns 2609987 sum=-1.81219G
|
||||
check10NotificationsFor1kListeners_EventBus2 267 ns 267 ns 2652159 sum=-1.77676G
|
||||
check10NotificationsFor1kListeners_CCNotificationCenter 11172 ns 11171 ns 62865 sum=54.023M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check1kListeners 2158 ns 2158 ns 317734 sum=1.18365G
|
||||
check1kListeners_EventBus2 2168 ns 2168 ns 326126 sum=1.21491G
|
||||
check1kListeners_CCNotificationCenter 12919 ns 12918 ns 54781 sum=208.973M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
check1kNotificationsFor1kListeners 129 ns 129 ns 5459854 sum=1108.69M
|
||||
check1kNotificationsFor1kListeners_EventBus2 103 ns 103 ns 6867175 sum=-1.60612G
|
||||
check1kNotificationsFor1kListeners_CCNotificationCenter 9711 ns 9710 ns 67611 sum=64.9171M
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
checkNotifyFor10kListenersWhenNoOneListens 2 ns 2 ns 399367972 sum=0
|
||||
checkNotifyFor10kListenersWhenNoOneListens_EventBus2 2 ns 2 ns 400616370 sum=0
|
||||
checkNotifyFor10kListenersWhenNoOneListens_CCNotificationCenter 125173 ns 125162 ns 5657 sum=0```
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
checkSimpleNotification 7 ns 7 ns 100833112 sum=384.648M
|
||||
checkSimpleNotification_EventBus2 5 ns 5 ns 144959897 sum=552.978M
|
||||
checkSimpleNotification_CCNotificationCenter 172 ns 172 ns 4179021 sum=15.9417M
|
||||
```
|
||||
|
||||
So comparing to CCNotificationCenter, EventBus is something like ~10x FASTER specially when we have more unique notifications.
|
||||
|
@ -22,7 +22,7 @@ struct SampleObserver : public cocos2d::CCObject
|
||||
}
|
||||
};
|
||||
|
||||
void CCNotificationCenter_checkNListeners(benchmark::State& state, const int listenersCount)
|
||||
void checkNListeners(benchmark::State& state, const int listenersCount)
|
||||
{
|
||||
using namespace cocos2d;
|
||||
cocos2d::CCNotificationCenter bus;
|
||||
@ -46,27 +46,27 @@ void CCNotificationCenter_checkNListeners(benchmark::State& state, const int lis
|
||||
CCPoolManager::sharedPoolManager()->purgePoolManager();
|
||||
}
|
||||
|
||||
void CCNotificationCenter_checkSimpleNotification(benchmark::State& state)
|
||||
void checkSimpleNotification_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNListeners(state, 1);
|
||||
checkNListeners(state, 1);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check10Listeners(benchmark::State& state)
|
||||
void check10Listeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNListeners(state, 10);
|
||||
checkNListeners(state, 10);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check100Listeners(benchmark::State& state)
|
||||
void check100Listeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNListeners(state, 100);
|
||||
checkNListeners(state, 100);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check1kListeners(benchmark::State& state)
|
||||
void check1kListeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNListeners(state, 1000);
|
||||
checkNListeners(state, 1000);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_checkNNotificationsForNListeners(benchmark::State& state
|
||||
void checkNNotificationsForNListeners(benchmark::State& state
|
||||
, const int notificationsCount
|
||||
, const int listenersCount)
|
||||
{
|
||||
@ -112,32 +112,57 @@ void CCNotificationCenter_checkNNotificationsForNListeners(benchmark::State& sta
|
||||
CCPoolManager::sharedPoolManager()->purgePoolManager();
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check10NotificationsFor1kListeners(benchmark::State& state)
|
||||
void check10NotificationsFor1kListeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNNotificationsForNListeners(state, 10, 1000);
|
||||
checkNNotificationsForNListeners(state, 10, 1000);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check100NotificationsFor1kListeners(benchmark::State& state)
|
||||
void check100NotificationsFor1kListeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNNotificationsForNListeners(state, 100, 1000);
|
||||
checkNNotificationsForNListeners(state, 100, 1000);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check1kNotificationsFor1kListeners(benchmark::State& state)
|
||||
void check1kNotificationsFor1kListeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNNotificationsForNListeners(state, 1000, 1000);
|
||||
checkNNotificationsForNListeners(state, 1000, 1000);
|
||||
}
|
||||
|
||||
void CCNotificationCenter_check100NotificationsFor10kListeners(benchmark::State& state)
|
||||
void check100NotificationsFor10kListeners_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
CCNotificationCenter_checkNNotificationsForNListeners(state, 100, 10000);
|
||||
checkNNotificationsForNListeners(state, 100, 10000);
|
||||
}
|
||||
|
||||
BENCHMARK(CCNotificationCenter_checkSimpleNotification);
|
||||
BENCHMARK(CCNotificationCenter_check10Listeners);
|
||||
BENCHMARK(CCNotificationCenter_check100Listeners);
|
||||
BENCHMARK(CCNotificationCenter_check1kListeners);
|
||||
BENCHMARK(CCNotificationCenter_check10NotificationsFor1kListeners);
|
||||
BENCHMARK(CCNotificationCenter_check100NotificationsFor1kListeners);
|
||||
BENCHMARK(CCNotificationCenter_check1kNotificationsFor1kListeners);
|
||||
BENCHMARK(CCNotificationCenter_check100NotificationsFor10kListeners);
|
||||
void checkNotifyFor10kListenersWhenNoOneListens_CCNotificationCenter(benchmark::State& state)
|
||||
{
|
||||
using namespace cocos2d;
|
||||
cocos2d::CCNotificationCenter bus;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
auto observer = new SampleObserver{};
|
||||
observer->autorelease();
|
||||
observer->callback = [&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);
|
||||
};
|
||||
bus.addObserver(observer, callfuncO_selector(SampleObserver::onCall), "sample", nullptr);
|
||||
}
|
||||
auto number = CCInteger::create(2);
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
bus.postNotification("unknown", number);
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
CCPoolManager::sharedPoolManager()->purgePoolManager();
|
||||
}
|
||||
|
||||
BENCHMARK(checkSimpleNotification_CCNotificationCenter);
|
||||
BENCHMARK(check10Listeners_CCNotificationCenter);
|
||||
BENCHMARK(check100Listeners_CCNotificationCenter);
|
||||
BENCHMARK(check1kListeners_CCNotificationCenter);
|
||||
BENCHMARK(check10NotificationsFor1kListeners_CCNotificationCenter);
|
||||
BENCHMARK(check100NotificationsFor1kListeners_CCNotificationCenter);
|
||||
BENCHMARK(check1kNotificationsFor1kListeners_CCNotificationCenter);
|
||||
BENCHMARK(check100NotificationsFor10kListeners_CCNotificationCenter);
|
||||
BENCHMARK(checkNotifyFor10kListenersWhenNoOneListens_CCNotificationCenter);
|
||||
}
|
||||
|
165
performance/eventbus/EventBus2Performance.cpp
Normal file
165
performance/eventbus/EventBus2Performance.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
//
|
||||
// Created by Dawid Drozd aka Gelldur on 05.08.17.
|
||||
//
|
||||
#include <random>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <eventbus/EventBus.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void checkNListeners(benchmark::State& state, const int listenersCount)
|
||||
{
|
||||
Dexode::EventBus bus;
|
||||
int sum = 0;
|
||||
|
||||
Dexode::Notification2<int> simpleNotification("simple");
|
||||
for (int i = 0; i < listenersCount; ++i)
|
||||
{
|
||||
bus.listen(simpleNotification, [&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);
|
||||
});
|
||||
}
|
||||
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
bus.notify(simpleNotification, 2);
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
}
|
||||
|
||||
void checkSimpleNotification_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNListeners(state, 1);
|
||||
}
|
||||
|
||||
void check10Listeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNListeners(state, 10);
|
||||
}
|
||||
|
||||
void check100Listeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNListeners(state, 100);
|
||||
}
|
||||
|
||||
void check1kListeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNListeners(state, 1000);
|
||||
}
|
||||
|
||||
void call1kLambdas_compare_EventBus2(benchmark::State& state)
|
||||
{
|
||||
int sum = 0;
|
||||
std::vector<std::function<void(int)>> callbacks;
|
||||
callbacks.reserve(1000);
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
callbacks.emplace_back([&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);
|
||||
});
|
||||
}
|
||||
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
// for (auto& callback :callbacks)
|
||||
{
|
||||
callbacks[i](2);
|
||||
}
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
}
|
||||
|
||||
void checkNNotificationsForNListeners(benchmark::State& state, const int notificationsCount, const int listenersCount)
|
||||
{
|
||||
std::mt19937 generator(311281);
|
||||
std::uniform_int_distribution<int> uniformDistribution(0, notificationsCount - 1);
|
||||
|
||||
//We generate here N different notifications
|
||||
std::vector<Dexode::Notification2<int>> notifications;
|
||||
notifications.reserve(notificationsCount);
|
||||
for (int i = 0; i < notificationsCount; ++i)
|
||||
{
|
||||
notifications.emplace_back(std::string{"notify_"} + std::to_string(i));
|
||||
}
|
||||
|
||||
Dexode::EventBus bus;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < listenersCount; ++i)//We register M listeners for N notifications using uniform distribution
|
||||
{
|
||||
const auto& notification = notifications.at(uniformDistribution(generator));
|
||||
bus.listen(notification, [&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);//we use it to prevent some? optimizations
|
||||
});
|
||||
}
|
||||
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
//Pick random notification
|
||||
const auto& notification = notifications.at(uniformDistribution(generator));
|
||||
bus.notify(notification, uniformDistribution(generator));
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
}
|
||||
|
||||
void check10NotificationsFor1kListeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNNotificationsForNListeners(state, 10, 1000);
|
||||
}
|
||||
|
||||
void check100NotificationsFor1kListeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNNotificationsForNListeners(state, 100, 1000);
|
||||
}
|
||||
|
||||
void check1kNotificationsFor1kListeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNNotificationsForNListeners(state, 1000, 1000);
|
||||
}
|
||||
|
||||
void check100NotificationsFor10kListeners_EventBus2(benchmark::State& state)
|
||||
{
|
||||
checkNNotificationsForNListeners(state, 100, 10000);
|
||||
}
|
||||
|
||||
void checkNotifyFor10kListenersWhenNoOneListens_EventBus2(benchmark::State& state)
|
||||
{
|
||||
Dexode::EventBus bus;
|
||||
Dexode::Notification2<int> simpleNotification("simple");
|
||||
Dexode::Notification2<int> unknownNotification("unknown");
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
bus.listen(simpleNotification, [&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);
|
||||
});
|
||||
}
|
||||
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
bus.notify(unknownNotification, 2);
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BENCHMARK(call1kLambdas_compare_EventBus2);
|
||||
|
||||
BENCHMARK(checkSimpleNotification_EventBus2);
|
||||
BENCHMARK(check10Listeners_EventBus2);
|
||||
BENCHMARK(check100Listeners_EventBus2);
|
||||
BENCHMARK(check1kListeners_EventBus2);
|
||||
BENCHMARK(check10NotificationsFor1kListeners_EventBus2);
|
||||
BENCHMARK(check100NotificationsFor1kListeners_EventBus2);
|
||||
BENCHMARK(check1kNotificationsFor1kListeners_EventBus2);
|
||||
BENCHMARK(check100NotificationsFor10kListeners_EventBus2);
|
||||
BENCHMARK(checkNotifyFor10kListenersWhenNoOneListens_EventBus2);
|
@ -127,16 +127,39 @@ void check100NotificationsFor10kListeners(benchmark::State& state)
|
||||
checkNNotificationsForNListeners(state, 100, 10000);
|
||||
}
|
||||
|
||||
MAKE_NOTIFICATION(UnknownNotification, int);
|
||||
|
||||
void checkNotifyFor10kListenersWhenNoOneListens(benchmark::State& state)
|
||||
{
|
||||
Dexode::Notifier bus;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
bus.listen(getNotificationSimpleNotification(), [&](int value)
|
||||
{
|
||||
benchmark::DoNotOptimize(sum += value * 2);
|
||||
});
|
||||
}
|
||||
|
||||
while (state.KeepRunning())//Performance area!
|
||||
{
|
||||
bus.notify(getNotificationUnknownNotification(), 2);
|
||||
}
|
||||
state.counters["sum"] = sum;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BENCHMARK(call1kLambdas_compare);
|
||||
|
||||
BENCHMARK(checkSimpleNotification);
|
||||
BENCHMARK(check10Listeners);
|
||||
BENCHMARK(check100Listeners);
|
||||
BENCHMARK(check1kListeners);
|
||||
BENCHMARK(call1kLambdas_compare);
|
||||
BENCHMARK(check10NotificationsFor1kListeners);
|
||||
BENCHMARK(check100NotificationsFor1kListeners);
|
||||
BENCHMARK(check1kNotificationsFor1kListeners);
|
||||
BENCHMARK(check100NotificationsFor10kListeners);
|
||||
BENCHMARK(checkNotifyFor10kListenersWhenNoOneListens);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
@ -4,6 +4,15 @@
|
||||
ADD_EXECUTABLE(EventBusTest
|
||||
eventbus/EventCollectorTest.cpp
|
||||
eventbus/NotifierTest.cpp
|
||||
eventbus/NotificationTest.cpp)
|
||||
|
||||
SET_TARGET_PROPERTIES(EventBusTest PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
)
|
||||
|
||||
TARGET_COMPILE_OPTIONS(EventBusTest
|
||||
PRIVATE -Wall -pedantic -Wno-unused-private-field -Wnon-virtual-dtor #-Werror
|
||||
)
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(EventBusTest PRIVATE Catch/single_include/)
|
||||
|
51
test/eventbus/NotificationTest.cpp
Normal file
51
test/eventbus/NotificationTest.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// Created by Dawid Drozd aka Gelldur on 05.08.17.
|
||||
//
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <eventbus/Notification2.h>
|
||||
|
||||
TEST_CASE("eventbus/Notification same", "Notifications should be same")
|
||||
{
|
||||
{
|
||||
Dexode::Notification2<int> one("one");
|
||||
Dexode::Notification2<int> two("one");
|
||||
REQUIRE(one == two);
|
||||
}
|
||||
{
|
||||
Dexode::Notification2<int> one("one");
|
||||
Dexode::Notification2<signed> two("one");
|
||||
REQUIRE(one == two);//int == signed
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eventbus/Notification not same", "Notifications should different")
|
||||
{
|
||||
{
|
||||
Dexode::Notification2<int> one("one");
|
||||
Dexode::Notification2<int> two("two");
|
||||
REQUIRE(one != two);
|
||||
}
|
||||
{
|
||||
Dexode::Notification2<int> one("one");
|
||||
Dexode::Notification2<int&> two("two");
|
||||
//REQUIRE(one != two); //Different types!
|
||||
}
|
||||
{
|
||||
Dexode::Notification2<unsigned> one("one");
|
||||
Dexode::Notification2<signed> two("one");
|
||||
//REQUIRE(one != two); //Different types!
|
||||
}
|
||||
{
|
||||
Dexode::Notification2<int, int> one("one");
|
||||
Dexode::Notification2<int, unsigned> two("one");
|
||||
//REQUIRE(one != two); //Different types!
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eventbus/Notification should copy constructable", "Notifications should be copy constructable")
|
||||
{
|
||||
Dexode::Notification2<int> one("one");
|
||||
Dexode::Notification2<int> two = one;
|
||||
REQUIRE(one == two);
|
||||
}
|
@ -5,52 +5,102 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <eventbus/Notifier.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
MAKE_NOTIFICATION(SimpleNotification, int);
|
||||
|
||||
MAKE_NOTIFICATION(RefNotification, int &);
|
||||
|
||||
}
|
||||
#include <eventbus/EventBus.h>
|
||||
|
||||
TEST_CASE("eventbus/Simple test", "Simple test")
|
||||
{
|
||||
Dexode::Notifier bus;
|
||||
const auto token = bus.listen(getNotificationSimpleNotification(), [](int value)
|
||||
Dexode::EventBus bus;
|
||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
||||
|
||||
const auto token = bus.listen(simpleNotification, [](int value)
|
||||
{
|
||||
REQUIRE(value == 3);
|
||||
});
|
||||
|
||||
bus.notify(getNotificationSimpleNotification(), 3);
|
||||
bus.notify(simpleNotification, 3);
|
||||
bus.unlistenAll(token);
|
||||
bus.notify(getNotificationSimpleNotification(), 2);
|
||||
bus.notify(simpleNotification, 2);
|
||||
|
||||
bus.listen(getNotificationSimpleNotification(), [](int value)
|
||||
bus.listen(simpleNotification, [](int value)
|
||||
{
|
||||
REQUIRE(value == 1);
|
||||
});
|
||||
bus.notify(getNotificationSimpleNotification(), 1);
|
||||
bus.notify(simpleNotification, 1);
|
||||
}
|
||||
|
||||
TEST_CASE("eventbus/Multiple listen on same token", "Listening on the same token")
|
||||
{
|
||||
Dexode::Notifier bus;
|
||||
const auto token = bus.listen(getNotificationRefNotification(), [](int& value)
|
||||
Dexode::EventBus bus;
|
||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
||||
Dexode::Notification2<int&> simpleRefNotification{"simple"};
|
||||
const auto token = bus.listen(simpleRefNotification, [](int& value)
|
||||
{
|
||||
REQUIRE(value == 3);
|
||||
--value;
|
||||
});
|
||||
bus.listen(token, getNotificationRefNotification(), [](int& value)
|
||||
bus.listen(token, simpleRefNotification, [](int& value)
|
||||
{
|
||||
REQUIRE(value == 2);
|
||||
});
|
||||
|
||||
int value = 3;
|
||||
bus.notify(getNotificationRefNotification(), value);
|
||||
bus.notify(simpleRefNotification, value);
|
||||
|
||||
bus.unlistenAll(token);
|
||||
bus.notify(getNotificationSimpleNotification(), 2);
|
||||
bus.notify(simpleNotification, value);
|
||||
REQUIRE(value == 2);
|
||||
bus.notify(simpleRefNotification, value);
|
||||
REQUIRE(value == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("eventbus/EventBus listen", "Listen without notification object. Using only string")
|
||||
{
|
||||
int isCalled = 0;
|
||||
Dexode::EventBus bus;
|
||||
const auto token = bus.listen<int>("simple", [&](int value)
|
||||
{
|
||||
++isCalled;
|
||||
REQUIRE(value == 3);
|
||||
});
|
||||
|
||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
||||
REQUIRE(isCalled == 0);
|
||||
bus.notify(simpleNotification, 3);
|
||||
REQUIRE(isCalled == 1);
|
||||
bus.unlistenAll(token);
|
||||
bus.notify(simpleNotification, 2);
|
||||
|
||||
bus.listen(simpleNotification, [&](int value)
|
||||
{
|
||||
++isCalled;
|
||||
REQUIRE(value == 1);
|
||||
});
|
||||
REQUIRE(isCalled == 1);
|
||||
bus.notify(simpleNotification, 1);
|
||||
REQUIRE(isCalled == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("eventbus/EventBus listen & notify", "Listen & notify without notification object. Using only string")
|
||||
{
|
||||
int isCalled = 0;
|
||||
Dexode::EventBus bus;
|
||||
const auto token = bus.listen<int>("simple", [&](int value)
|
||||
{
|
||||
++isCalled;
|
||||
REQUIRE(value == 3);
|
||||
});
|
||||
REQUIRE(isCalled == 0);
|
||||
bus.notify<int>(std::string{"simple"}, 3);
|
||||
REQUIRE(isCalled == 1);
|
||||
bus.unlistenAll(token);
|
||||
bus.notify<int>("simple", 2);
|
||||
REQUIRE(isCalled == 1);
|
||||
|
||||
bus.listen<int>("simple", [&](int value)
|
||||
{
|
||||
++isCalled;
|
||||
REQUIRE(value == 1);
|
||||
});
|
||||
bus.notify<int>("simple", 1);
|
||||
REQUIRE(isCalled == 2);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user