From 69f21d96afa8be0fff0767419fd9c0a3a59d24f5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Mar 2018 07:48:59 +0100 Subject: [PATCH] DI: prepare benchmark of reference cases _not_ using the dependency factory, rather direct access - to a shared object in the enclosing stack frame - to a heap allocated existing object accessed through uniqe_ptr --- research/try.cpp | 37 +++++++++++++++++++-------------- src/lib/test/microbenchmark.hpp | 26 +++++++++++------------ wiki/renderengine.html | 7 +++++-- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index bbd5da11f..9f028ee6b 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -84,31 +84,36 @@ using lumiera::ON_GLOBAL_SHUTDOWN; ///////////////////////////////////////////////////////Usage +class BlackHoleService + : util::NonCopyable + { + volatile int theHole_ = rand() % 1000; + + public: + int readMe() { return theHole_; } + }; + + int main (int, char**) { std::srand(std::time(nullptr)); LifecycleHook::trigger (ON_GLOBAL_INIT); -// DependInject::useSingleton ([&] { return "long{rand() % 100}"; }); -// DependInject::Local dummy ([&]{ return new long{rand() % 100}; }); +// Depend mystery; + std::unique_ptr mystery{new BlackHoleService}; + BlackHoleService mist; - volatile int blackHole{0}; - - cout << "pling..."< ([&]() - { - //volatile int dummy =0; - //dummy == 0; - //++dummy; - blackHole == 0; - //++blackHole; - }) - << endl; - cout << "........"<< blackHole/8< ([&]() + { + 0 == mystery->readMe(); + //0 == mist.readMe(); + } + ,300000000) + << endl; LifecycleHook::trigger (ON_GLOBAL_SHUTDOWN); - cout << "\n.gulp.\n"; +// cout << "\n.gulp.\n"; return 0; } diff --git a/src/lib/test/microbenchmark.hpp b/src/lib/test/microbenchmark.hpp index c0b1ccbce..463bbb8bf 100644 --- a/src/lib/test/microbenchmark.hpp +++ b/src/lib/test/microbenchmark.hpp @@ -64,7 +64,7 @@ namespace lib { namespace test{ namespace { - constexpr size_t NUM_MEASUREMENTS = 10000000; + constexpr size_t DEFAULT_RUNS = 10000000; constexpr double SCALE = 1e6; // Results are in ยต sec } @@ -85,7 +85,7 @@ namespace test{ */ template inline double - microbenchmark(FUN const& subject) + microbenchmark(FUN const& subject, const size_t nRepeat = DEFAULT_RUNS) { using backend::ThreadJoinable; using std::chrono::system_clock; @@ -95,16 +95,16 @@ namespace test{ struct Thread : ThreadJoinable { - Thread(FUN const& subject) + Thread(FUN const& subject, size_t loopCnt) : ThreadJoinable("Micro-Benchmark" - ,[subject, this]() // local copy of the test-subject-Functor - { - syncPoint(); // block until all threads are ready - auto start = system_clock::now(); - for (size_t i=0; i < NUM_MEASUREMENTS; ++i) - subject(); - duration = system_clock::now () - start; - }) + ,[=]() // local copy of the test-subject-Functor + { + syncPoint(); // block until all threads are ready + auto start = system_clock::now(); + for (size_t i=0; i < loopCnt; ++i) + subject(); + duration = system_clock::now () - start; + }) { } /** measured time within thread */ Dur duration{}; @@ -113,7 +113,7 @@ namespace test{ std::vector threads; threads.reserve(nThreads); for (size_t n=0; n -
+
//Access point to dependencies by-name.//
 In the Lumiera code base, we refrain from building or using a full-blown Dependency Injection Container. A lot of FUD has been spread regarding Dependency Injection and Singletons, to the point that a majority of developers confuses and conflates the ~Inversion-of-Control principle (which is essential) with the use of a ~DI-Container. Today, you can not even mention the word "Singleton" without everyone yelling out "Evil! Evil!" -- while most of these people just feel comfortable living in the metadata hell.
 
@@ -1978,9 +1978,12 @@ We acknowledge that such a dependency or service will be accessed frequently and
 Our requirements on (optional) reconfigurability have some impact on the implementation technique though, since we need access to the instance pointer for individual service types. This basically rules out //Meyers Singleton// -- and so the adequate implementation technique for our usage pattern is //Double Checked Locking.// In the past, there was much debate about DCL being broken -- which indeed was true when //assuming full portability and arbitrary target platform.// Since our focus is primarily on ~PC-with-Linux systems, this argument seems rather theoretical though, since the x86/64 platform is known to employ rather strong memory and cache coherency constraints. With the advent of ARM systems, the situation has changed however. Anyway, since C++11 there is a portable solution for writing a correct DCL implementation, based on {{{std::atomic}}}.
 
 To give some idea of the rough proportions of performance impact, in 2018 we conducted some micro benchmarks (using a 8 core AMD 64bit processor running Debian/Jessie building with GCC 4.9)
-The following table lists averaged results in relative numbers
+The following table lists averaged results in relative numbers, in relation to a single threaded direct non virtual member function invocation
 | !Access Technique |>| !development |>| !optimised |
 |~| single threaded|multithreaded | single threaded|multithreaded |
+|direct invoke shared local object                  |   15.13|   16.30|  ''1.00''|   1.59|
+|invoke existing object through unique_ptr  |   60.76|   63.20|     1.20|   1.64|
+