Lumiera  0.pre.03
»edit your freedom«
microbenchmark.hpp
Go to the documentation of this file.
1 /*
2  MICROBENCHMARK.hpp - multithreaded timing measurement
3 
4  Copyright (C)
5  2018, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
44 #ifndef LIB_TEST_MICROBENCHMARK_H
45 #define LIB_TEST_MICROBENCHMARK_H
46 
47 
48 #include "lib/meta/function.hpp"
50 #include "lib/sync-barrier.hpp"
51 #include "lib/thread.hpp"
52 
54 
55 #include <chrono>
56 
57 
58 
59 namespace lib {
60 namespace test{
61 
62  namespace {
63  constexpr size_t DEFAULT_RUNS = 10'000'000;
64  using CLOCK_SCALE = std::micro; // Results are in µ-sec
65  }
66 
67 
74  template<class FUN>
75  inline double
76  benchmarkTime (FUN const& invokeTestCode, const size_t repeatCnt =1)
77  {
78  using std::chrono::steady_clock;
79  using Dur = std::chrono::duration<double, CLOCK_SCALE>;
80 
81  auto start = steady_clock::now();
82  invokeTestCode();
83  Dur duration = steady_clock::now () - start;
84  return duration.count() / repeatCnt;
85  };
86 
87 
93  template<class FUN>
94  inline size_t
95  benchmarkLoop (FUN const& testSubject, const size_t repeatCnt = DEFAULT_RUNS)
96  {
97  // the test subject gets the current loop-index and returns a checksum value
98  auto subject4benchmark = microbenchmark::adapted4benchmark (testSubject);
99 
100  size_t checksum{0};
101  for (size_t i=0; i<repeatCnt; ++i)
102  checksum += subject4benchmark(i);
103  return checksum;
104  }
105 
106 
116  template<class FUN>
117  inline auto
118  microBenchmark (FUN const& testSubject, const size_t repeatCnt = DEFAULT_RUNS)
119  {
120  volatile size_t checksum{0};
121  auto invokeTestLoop = [&]{ checksum = benchmarkLoop (testSubject, repeatCnt); };
122  double micros = benchmarkTime (invokeTestLoop, repeatCnt);
123  return std::make_pair (micros, checksum);
124  }
125 
126 
127 
128 
145  template<size_t nThreads, class FUN>
146  inline auto
147  threadBenchmark(FUN const& subject, const size_t repeatCnt = DEFAULT_RUNS)
148  {
149  using std::chrono::steady_clock;
150  using Dur = std::chrono::duration<double, CLOCK_SCALE>;
151 
152  // the test subject gets the current loop-index and returns a checksum value
153  auto subject4benchmark = microbenchmark::adapted4benchmark (subject);
154  using Subject = decltype(subject4benchmark);
155 
156  struct Thread
158  {
159  Thread(Subject const& subject, size_t loopCnt, SyncBarrier& testStart)
160  : ThreadJoinable{"Micro-Benchmark"
161  ,[this,loopCnt, testSubject=subject, &testStart]
162  () mutable // local (mutable) copy of the test-subject-Functor
163  {
164  testStart.sync(); // block until all threads are ready
165  auto start = steady_clock::now();
166  for (size_t i=0; i < loopCnt; ++i)
167  checksum += testSubject(i);
168  duration = steady_clock::now () - start;
169  }}
170  { }
171  // Note: barrier at begin and join at end both ensure data synchronisation
172  Dur duration{}; // measured time within thread
173  size_t checksum{0}; // collected checksum
174  };
175 
176  SyncBarrier testStart{nThreads + 1}; // coordinated start of timing measurement
177  lib::ScopedCollection<Thread> threads(nThreads);
178  for (size_t n=0; n<nThreads; ++n) // create test threads
179  threads.emplace (subject4benchmark, repeatCnt, testStart);
180 
181  testStart.sync(); // barrier until all threads are ready
182 
183  size_t checksum{0};
184  Dur sumDuration{0.0};
185  for (auto& thread : threads)
186  {
187  thread.join(); // block on measurement end (fence)
188  sumDuration += thread.duration;
189  checksum += thread.checksum;
190  }
191 
192  double micros = sumDuration.count() / (nThreads * repeatCnt);
193  return std::make_tuple (micros, checksum);
194  }
195 
196 
197 
198 }} // namespace lib::test
199 #endif /*LIB_TEST_MICROBENCHMARK_H*/
Variant of the standard case, requiring to wait and join() on the termination of this thread...
Definition: thread.hpp:668
auto threadBenchmark(FUN const &subject, const size_t repeatCnt=DEFAULT_RUNS)
perform a multithreaded microbenchmark.
A fixed collection of non-copyable polymorphic objects.
Definition: run.hpp:40
TY & emplace(ARGS &&...args)
push new entry at the end of this container and build object of type TY in place there ...
Implementation namespace for support and library code.
Helpers and wrappers so simplify usage of micobenchmark.hpp.
auto microBenchmark(FUN const &testSubject, const size_t repeatCnt=DEFAULT_RUNS)
perform a simple looped microbenchmark.
Managing a collection of non-copyable polymorphic objects in compact storage.
double benchmarkTime(FUN const &invokeTestCode, const size_t repeatCnt=1)
Helper to invoke a functor or λ to observe its running time.
Metaprogramming tools for transforming functor types.
Convenience front-end to simplify and codify basic thread handling.
A one time N-fold mutual synchronisation barrier.
A thin convenience wrapper to simplify thread-handling.
Definition: thread.hpp:648
size_t benchmarkLoop(FUN const &testSubject, const size_t repeatCnt=DEFAULT_RUNS)
Benchmark building block to invoke a functor or λ in a tight loop, passing the current loop index and...
A N-fold synchronisation latch using yield-wait until fulfilment.