#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2023 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_SUPPORT_SOURCE 1 #include "Nuclex/Support/Config.h" #include "Nuclex/Support/Events/Event.h" #include "Nuclex/Support/Events/ConcurrentEvent.h" #include #include // for std::copy_n() #include // for std::mt19937 #include // for std::uint32_t, std::uint64_t #include // for std::string #include // for std::is_signed #include // for std::abs() namespace { // ------------------------------------------------------------------------------------------- // /// Dummy callback that does absolutely nothing /// /// Value that will be processed in a way that prevents the compiler from optimizing /// the entire call away /// void doNothingCallback(int value) { celero::DoNotOptimizeAway(value); } // ------------------------------------------------------------------------------------------- // /// Another dummy callback that does absolutely nothing /// /// Value that will be processed in a way that prevents the compiler from optimizing /// the entire call away /// void doMoreNothingCallback(int value) { celero::DoNotOptimizeAway(value); } // ------------------------------------------------------------------------------------------- // /// Test fixture that takes care of subscribing and unsubscribing an event class Event2Fixture : public celero::TestFixture { /// Called before the benchmark runs to subscribe to an event public: void setUp(const celero::TestFixture::ExperimentValue &) override { this->testEvent.Subscribe<&doNothingCallback>(); this->testEvent.Subscribe<&doMoreNothingCallback>(); } /// Called after the benchmark completes to unsubscribe from the event public: void tearDown() override { this->testEvent.Unsubscribe<&doMoreNothingCallback>(); this->testEvent.Unsubscribe<&doNothingCallback>(); } /// Test event that will have tw subscriptions protected: Nuclex::Support::Events::Event testEvent; }; // ------------------------------------------------------------------------------------------- // /// Test fixture that takes care of subscribing and unsubscribing an event class Event50Fixture : public celero::TestFixture { /// Called before the benchmark runs to subscribe to an event public: void setUp(const celero::TestFixture::ExperimentValue &) override { for(std::size_t index = 0; index < 50; ++index) { this->testEvent.Subscribe<&doNothingCallback>(); } } /// Called after the benchmark completes to unsubscribe from the event public: void tearDown() override { for(std::size_t index = 0; index < 50; ++index) { this->testEvent.Unsubscribe<&doNothingCallback>(); } } /// Test event that will have tw subscriptions protected: Nuclex::Support::Events::Event testEvent; }; // ------------------------------------------------------------------------------------------- // class ConcurrentEvent2Fixture : public celero::TestFixture { public: void setUp(const celero::TestFixture::ExperimentValue &) override { this->testEvent.Subscribe<&doNothingCallback>(); this->testEvent.Subscribe<&doMoreNothingCallback>(); } public: void tearDown() override { this->testEvent.Unsubscribe<&doMoreNothingCallback>(); this->testEvent.Unsubscribe<&doNothingCallback>(); } protected: Nuclex::Support::Events::ConcurrentEvent testEvent; }; // ------------------------------------------------------------------------------------------- // class ConcurrentEvent50Fixture : public celero::TestFixture { public: void setUp(const celero::TestFixture::ExperimentValue &) override { for(std::size_t index = 0; index < 50; ++index) { this->testEvent.Subscribe<&doNothingCallback>(); } } public: void tearDown() override { for(std::size_t index = 0; index < 50; ++index) { this->testEvent.Unsubscribe<&doNothingCallback>(); } } protected: Nuclex::Support::Events::ConcurrentEvent testEvent; }; // ------------------------------------------------------------------------------------------- // /// Fast random number generator used in the benchmark std::mt19937_64 randomNumberGenerator; /// Uniform distribution to make the output cover all possible integers std::uniform_int_distribution randomNumberDistribution; // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Support { namespace Events { // ------------------------------------------------------------------------------------------- // BASELINE(Subscribe2, NuclexEvent, 1000, 0) { Nuclex::Support::Events::Event testEvent; testEvent.Subscribe<&doNothingCallback>(); testEvent.Subscribe<&doMoreNothingCallback>(); } // ------------------------------------------------------------------------------------------- // BENCHMARK(Subscribe2, NuclexConcurrentEvent, 1000, 0) { Nuclex::Support::Events::ConcurrentEvent testEvent; testEvent.Subscribe<&doNothingCallback>(); testEvent.Subscribe<&doMoreNothingCallback>(); } // ------------------------------------------------------------------------------------------- // BASELINE(Subscribe50, NuclexEvent, 1000, 0) { Nuclex::Support::Events::Event testEvent; for(std::size_t index = 0; index < 50; ++index) { testEvent.Subscribe<&doNothingCallback>(); } } // ------------------------------------------------------------------------------------------- // BENCHMARK(Subscribe50, NuclexConcurrentEvent, 1000, 0) { Nuclex::Support::Events::Event testEvent; for(std::size_t index = 0; index < 50; ++index) { testEvent.Subscribe<&doNothingCallback>(); } } // ------------------------------------------------------------------------------------------- // BASELINE(Unsubscribe2, NuclexEvent, 1000, 0) { Nuclex::Support::Events::Event testEvent; testEvent.Subscribe<&doNothingCallback>(); testEvent.Subscribe<&doMoreNothingCallback>(); testEvent.Unsubscribe<&doMoreNothingCallback>(); testEvent.Unsubscribe<&doNothingCallback>(); } // ------------------------------------------------------------------------------------------- // BENCHMARK(Unsubscribe2, NuclexConcurrentEvent, 1000, 0) { Nuclex::Support::Events::ConcurrentEvent testEvent; testEvent.Subscribe<&doNothingCallback>(); testEvent.Subscribe<&doMoreNothingCallback>(); testEvent.Unsubscribe<&doMoreNothingCallback>(); testEvent.Unsubscribe<&doNothingCallback>(); } // ------------------------------------------------------------------------------------------- // BASELINE(Unsubscribe50, NuclexEvent, 1000, 0) { Nuclex::Support::Events::Event testEvent; for(std::size_t index = 0; index < 50; ++index) { testEvent.Subscribe<&doNothingCallback>(); } for(std::size_t index = 0; index < 50; ++index) { testEvent.Unsubscribe<&doNothingCallback>(); } } // ------------------------------------------------------------------------------------------- // BENCHMARK(Unsubscribe50, NuclexConcurrentEvent, 1000, 0) { Nuclex::Support::Events::ConcurrentEvent testEvent; for(std::size_t index = 0; index < 50; ++index) { testEvent.Subscribe<&doNothingCallback>(); } for(std::size_t index = 0; index < 50; ++index) { testEvent.Unsubscribe<&doNothingCallback>(); } } // ------------------------------------------------------------------------------------------- // BASELINE_F(Invoke2_x100, NuclexEvent, Event2Fixture, 1000, 0) { for(std::size_t index = 0; index < 100; ++index) { this->testEvent.Emit(static_cast(index)); } } // ------------------------------------------------------------------------------------------- // BENCHMARK_F(Invoke2_x100, NuclexConcurrentEvent, ConcurrentEvent2Fixture, 1000, 0) { for(std::size_t index = 0; index < 100; ++index) { this->testEvent.Emit(static_cast(index)); } } // ------------------------------------------------------------------------------------------- // BASELINE_F(Invoke50_x100, NuclexEvent, Event50Fixture, 1000, 0) { for(std::size_t index = 0; index < 100; ++index) { this->testEvent.Emit(static_cast(index)); } } // ------------------------------------------------------------------------------------------- // BENCHMARK_F(Invoke50_x100, NuclexConcurrentEvent, ConcurrentEvent50Fixture, 1000, 0) { for(std::size_t index = 0; index < 100; ++index) { this->testEvent.Emit(static_cast(index)); } } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Support::Events