SPH
Session.h
Go to the documentation of this file.
1 #pragma once
2 
7 
8 #include "bench/Common.h"
9 #include "bench/Stats.h"
10 #include "io/Logger.h"
11 #include "io/Path.h"
17 #include "system/Timer.h"
18 #include <fstream>
19 #include <map>
20 
22 
24 enum class Mode {
25  SIMPLE,
28 };
29 
30 struct Target {
32  uint64_t duration;
34 };
35 
36 struct Result {
37  uint64_t duration;
43 };
44 
46 class Context {
47 private:
48  Target target;
49 
50  bool state = true;
51 
52  Size iterateCnt = 0;
53 
54  Timer timer;
55 
56  Timer iterationTimer;
57 
58  Stats stats;
59 
61  std::string name;
62 
63 public:
64  Context(const Target target, const std::string& name)
65  : target(target)
66  , timer(target.duration)
67  , name(name) {}
68 
70  INLINE bool running() {
71  state = this->shouldContinue();
72  if (iterateCnt <= 2) {
73  // restart to discard benchmark setup time and first few iterations (startup)
74  timer.restart();
75  } else {
76  stats.add(1.e-3_f * iterationTimer.elapsed(TimerUnit::MICROSECOND));
77  }
78  iterationTimer.restart();
79  iterateCnt++;
80  return state;
81  }
82 
83  INLINE uint64_t elapsed() const {
84  return timer.elapsed(TimerUnit::MILLISECOND);
85  }
86 
88  return iterateCnt;
89  }
90 
91  INLINE Stats getStats() const {
92  return stats;
93  }
94 
96  template <typename... TArgs>
97  INLINE void log(TArgs&&... args) {
98  StdOutLogger logger;
99  logger.write(std::forward<TArgs>(args)...);
100  }
101 
102 private:
103  INLINE bool shouldContinue() const {
104  switch (target.mode) {
105  case Mode::SIMPLE:
106  case Mode::MAKE_BASELINE:
107  // either not enough time passed, or not enough iterations
108  return iterateCnt < target.iterateCnt || !timer.isExpired();
110  return iterateCnt < target.iterateCnt;
111  default:
113  }
114  }
115 };
116 
118 class Unit {
119 private:
120  std::string name;
121 
122  using Function = void (*)(Context&);
123  Function function;
124 
125 public:
126  Unit(const std::string& name, const Function func)
127  : name(name)
128  , function(func) {
129  SPH_ASSERT(function != nullptr);
130  }
131 
132  const std::string& getName() const {
133  return name;
134  }
135 
136  Expected<Result> run(const Target target) {
137  Context context(target, name);
138  function(context);
139  uint64_t elapsed = context.elapsed();
140  Stats stats = context.getStats();
141  return Result{
142  elapsed, context.iterationCnt() - 1, stats.mean(), stats.variance(), stats.min(), stats.max()
143  };
144  }
145 };
146 
147 class Group {
148 private:
149  std::string name;
150  Array<SharedPtr<Unit>> benchmarks;
151 
152 public:
153  Group() = default;
154 
155  Group(const std::string& name)
156  : name(name) {}
157 
158  const std::string& getName() const {
159  return name;
160  }
161 
162  void addBenchmark(const SharedPtr<Unit>& benchmark) {
163  benchmarks.push(benchmark);
164  }
165 
166  auto begin() const {
167  return benchmarks.begin();
168  }
169 
170  auto end() const {
171  return benchmarks.end();
172  }
173 
174  Size size() const {
175  return benchmarks.size();
176  }
177 };
178 
179 template <class T>
180 INLINE T&& doNotOptimize(T&& value) {
181 #if defined(__clang__)
182  asm volatile("" : : "g"(value) : "memory");
183 #else
184  asm volatile("" : : "i,r,m"(value) : "memory");
185 #endif
186  return std::forward<T>(value);
187 }
188 
189 // Force the compiler to flush pending writes to global memory. Acts as an effective read/write barrier
191  asm volatile("" : : : "memory");
192 }
193 
194 class Baseline {
195 private:
196  std::map<std::string, Result> benchs;
197 
198 public:
199  Baseline() = default;
200 
201  bool parse(const Path& path) {
202  benchs.clear();
203  std::ifstream ifs(path.native());
204  std::string line;
205  while (std::getline(ifs, line)) {
206  std::size_t n = line.find_last_of('/');
207  if (n == std::string::npos) {
208  return false;
209  }
210  const std::string name = trim(line.substr(0, n));
211  Array<std::string> values = split(line.substr(n + 1), ',');
212  if (values.size() != 6) {
213  return false;
214  }
215  Result result;
216  result.duration = std::stoi(values[0]);
217  result.iterateCnt = std::stoi(values[1]);
218  result.mean = std::stof(values[2]);
219  result.variance = std::stof(values[3]);
220  result.min = std::stof(values[4]);
221  result.max = std::stof(values[5]);
222 
223  benchs[name] = result;
224  }
225  return true;
226  }
227 
228  bool isRecorded(const std::string& name) {
229  return benchs.find(name) != benchs.end();
230  }
231 
232  INLINE Result operator[](const std::string& name) {
233  return benchs[name];
234  }
235 };
236 
237 class Session {
238 private:
240  static AutoPtr<Session> instance;
241 
243  Array<SharedPtr<Unit>> benchmarks;
244 
246  Array<Group> groups;
247 
249  AutoPtr<ILogger> logger;
250 
252  Outcome status = SUCCESS;
253 
254  enum class Flag {
255  RUN_AGAINST_BASELINE = 1 << 0,
256 
257  MAKE_BASELINE = 1 << 1,
258 
259  SILENT = 1 << 2,
260  };
261 
262  struct {
264  std::string group;
265 
267 
268  struct {
272 
274 
275  Target target{ Mode::SIMPLE, 500 /*ms*/, 10 };
276 
277  Float confidence = 6._f; // sigma
278 
281  uint64_t maxAllowedDuration = 5000 /*ms*/;
282  } params;
283 
284 public:
285  Session();
286 
287  static Session& getInstance();
288 
290  void registerBenchmark(const SharedPtr<Unit>& benchmark, const std::string& groupName);
291 
293  void run(int argc, char* argv[]);
294 
296 
297 private:
298  Group& getGroupByName(const std::string& groupName);
299 
300  Outcome parseArgs(int arcs, char* argv[]);
301 
302  void printHelp();
303 
304  void writeBaseline(const std::string& name, const Result& measured);
305 
306  Path getBaselinePath();
307 
308  void compareResults(const Result& measured, const Result& baseline);
309 
310  template <typename... TArgs>
311  void log(TArgs&&... args);
312 
313  template <typename... TArgs>
314  void logError(TArgs&&... args);
315 };
316 
320 
321 class Register {
322 public:
323  Register(const SharedPtr<Unit>& benchmark, const std::string& groupName);
324 };
325 
326 #define BENCHMARK_UNIQUE_NAME_IMPL(prefix, line) prefix##line
327 
328 #define BENCHMARK_UNIQUE_NAME(prefix, line) BENCHMARK_UNIQUE_NAME_IMPL(prefix, line)
329 
330 #define BENCHMARK_FUNCTION_NAME BENCHMARK_UNIQUE_NAME(BENCHMARK, __LINE__)
331 
332 #define BENCHMARK_REGISTER_NAME BENCHMARK_UNIQUE_NAME(REGISTER, __LINE__)
333 
334 #define BENCHMARK(name, group, ...) \
335  static void BENCHMARK_FUNCTION_NAME(__VA_ARGS__); \
336  namespace { \
337  ::Sph::Benchmark::Register BENCHMARK_REGISTER_NAME( \
338  makeShared<::Sph::Benchmark::Unit>(name, &BENCHMARK_FUNCTION_NAME), \
339  group); \
340  } \
341  static void BENCHMARK_FUNCTION_NAME(__VA_ARGS__)
342 
Generic dynamically allocated resizable storage.
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
Wrapper of type containing either a value or an error message.
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
Logging routines of the run.
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
Return value of function that may fail, containing either SUCCEES (true) or error message.
const SuccessTag SUCCESS
Global constant for successful outcome.
Definition: Outcome.h:141
Object representing a path on a filesystem, similar to std::filesystem::path in c++17.
Mode
Benchmark mode.
Definition: Session.h:24
@ RUN_AGAINST_BASELINE
Compare iteration numbers with recorded baseline.
@ MAKE_BASELINE
Store iteration numbers to baseline file.
@ SIMPLE
Just run benchmarks and report statistics.
INLINE T && doNotOptimize(T &&value)
Definition: Session.h:180
INLINE void clobberMemory()
Definition: Session.h:190
Benchmark statistics.
std::string trim(const std::string &s)
Removes all leading and trailing spaces from a string.
Definition: StringUtils.cpp:74
Array< std::string > split(const std::string &s, const char delimiter)
Splits a string into an array of string using given delimiter.
Measuring time intervals and executing periodic events.
#define NAMESPACE_BENCHMARK_BEGIN
Definition: Common.h:7
#define NAMESPACE_BENCHMARK_END
Definition: Common.h:8
Generic dynamically allocated resizable storage.
Definition: Array.h:43
INLINE Iterator< StorageType > end() noexcept
Definition: Array.h:462
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
INLINE TCounter size() const noexcept
Definition: Array.h:193
INLINE Iterator< StorageType > begin() noexcept
Definition: Array.h:450
Baseline()=default
bool parse(const Path &path)
Definition: Session.h:201
INLINE Result operator[](const std::string &name)
Definition: Session.h:232
bool isRecorded(const std::string &name)
Definition: Session.h:228
Accessible from benchmarks.
Definition: Session.h:46
INLINE bool running()
Whether to keep running or exit.
Definition: Session.h:70
INLINE uint64_t elapsed() const
Definition: Session.h:83
Context(const Target target, const std::string &name)
Definition: Session.h:64
INLINE void log(TArgs &&... args)
Writes given message into the logger.
Definition: Session.h:97
INLINE Stats getStats() const
Definition: Session.h:91
INLINE Size iterationCnt() const
Definition: Session.h:87
Wrapper of type that either contains a value of given type, or an error message.
Definition: Expected.h:25
Definition: Session.h:147
Group(const std::string &name)
Definition: Session.h:155
void addBenchmark(const SharedPtr< Unit > &benchmark)
Definition: Session.h:162
auto begin() const
Definition: Session.h:166
auto end() const
Definition: Session.h:170
Size size() const
Definition: Session.h:174
const std::string & getName() const
Definition: Session.h:158
Group()=default
void write(TArgs &&... args)
Creates and logs a message by concatenating arguments.
Definition: Logger.h:37
Object representing a path on a filesystem.
Definition: Path.h:17
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
Register(const SharedPtr< Unit > &benchmark, const std::string &groupName)
Definition: Session.cpp:226
Session()
Definition: Session.cpp:9
Size commit
Definition: Session.h:270
void run(int argc, char *argv[])
Runs all benchmarks.
Definition: Session.cpp:38
struct Session::@0::@1 baseline
std::string group
Run only selected group of benchmarks.
Definition: Session.h:264
void registerBenchmark(const SharedPtr< Unit > &benchmark, const std::string &groupName)
Adds a new benchmark into the session.
Definition: Session.cpp:26
Target target
Definition: Session.h:275
uint64_t maxAllowedDuration
Definition: Session.h:281
static Session & getInstance()
Definition: Session.cpp:19
Flags< Flag > flags
Definition: Session.h:266
Path path
Definition: Session.h:269
Float confidence
Definition: Session.h:277
Array< std::string > benchmarksToRun
Definition: Session.h:273
Definition: Stats.h:13
INLINE Float max() const
Definition: Stats.h:49
INLINE void add(const Float value)
Definition: Stats.h:21
INLINE Float mean() const
Definition: Stats.h:28
INLINE Float variance() const
Definition: Stats.h:33
INLINE Float min() const
Definition: Stats.h:45
Standard output logger.
Definition: Logger.h:138
Basic time-measuring tool. Starts automatically when constructed.
Definition: Timer.h:27
bool isExpired() const
Checks if the interval has already passed.
Definition: Timer.h:53
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
Definition: Timer.cpp:55
void restart()
Reset elapsed duration to zero.
Definition: Timer.cpp:51
Single benchmark unit.
Definition: Session.h:118
Expected< Result > run(const Target target)
Definition: Session.h:136
const std::string & getName() const
Definition: Session.h:132
Unit(const std::string &name, const Function func)
Definition: Session.h:126
Definition: Session.h:36
uint64_t duration
Definition: Session.h:37
Float max
Definition: Session.h:42
Size iterateCnt
Definition: Session.h:38
Float min
Definition: Session.h:41
Float variance
Definition: Session.h:40
Float mean
Definition: Session.h:39
Definition: Session.h:30
Mode mode
Definition: Session.h:31
Size iterateCnt
Definition: Session.h:33
uint64_t duration
Definition: Session.h:32