OpcUaCanOpen
CANopen OPC-UA server
exprtk_benchmark.cpp
Go to the documentation of this file.
1 /*
2  **************************************************************
3  * C++ Mathematical Expression Toolkit Library *
4  * *
5  * ExprTk vs Native Benchmarks *
6  * Author: Arash Partow (1999-2019) *
7  * URL: http://www.partow.net/programming/exprtk/index.html *
8  * *
9  * Copyright notice: *
10  * Free use of the Mathematical Expression Toolkit Library is *
11  * permitted under the guidelines and in accordance with the *
12  * most current version of the MIT License. *
13  * http://www.opensource.org/licenses/MIT *
14  * *
15  **************************************************************
16 */
17 
18 
19 #include <cstdio>
20 #include <cmath>
21 #include <iostream>
22 #include <fstream>
23 #include <string>
24 #include <deque>
25 
26 #include "exprtk.hpp"
27 
28 
30  = {
31  "(y + x)",
32  "2 * (y + x)",
33  "(2 * y + 2 * x)",
34  "((1.23 * x^2) / y) - 123.123",
35  "(y + x / y) * (x - y / x)",
36  "x / ((x + y) + (x - y)) / y",
37  "1 - ((x * y) + (y / x)) - 3",
38  "(5.5 + x) + (2 * x - 2 / 3 * y) * (x / 3 + y / 4) + (y + 7.7)",
39  "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55",
40  "sin(2 * x) + cos(pi / y)",
41  "1 - sin(2 * x) + cos(pi / y)",
42  "sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333)",
43  "(x^2 / sin(2 * pi / y)) - x / 2",
44  "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y",
45  "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)",
46  "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))",
47  "if((y + (x * 2.2)) <= (x + y + 1.1), x - y, x * y) + 2 * pi / x"
48  };
49 
50 const std::size_t global_expression_list_size = sizeof(global_expression_list) / sizeof(std::string);
51 
52 static const double global_lower_bound_x = -100.0;
53 static const double global_lower_bound_y = -100.0;
54 static const double global_upper_bound_x = +100.0;
55 static const double global_upper_bound_y = +100.0;
56 static const double global_delta = 0.0111;
57 
58 
59 template <typename T,
60  typename Allocator,
61  template <typename,typename> class Sequence>
63  Sequence<exprtk::expression<T>,Allocator>& expr_seq)
64 {
66 
67  for (std::size_t i = 0; i < global_expression_list_size; ++i)
68  {
69  exprtk::expression<double> expression;
70  expression.register_symbol_table(symbol_table);
71 
72  if (!parser.compile(global_expression_list[i],expression))
73  {
74  printf("[load_expression] - Parser Error: %s\tExpression: %s\n",
75  parser.error().c_str(),
76  global_expression_list[i].c_str());
77 
78  return false;
79  }
80 
81  expr_seq.push_back(expression);
82  }
83 
84  return true;
85 }
86 
87 template <typename T>
88 void run_exprtk_benchmark(T& x, T& y,
89  exprtk::expression<T>& expression,
90  const std::string& expr_string)
91 {
92  T total = T(0);
93  unsigned int count = 0;
94 
95  exprtk::timer timer;
96  timer.start();
97 
99  {
101  {
102  total += expression.value();
103  ++count;
104  }
105  }
106 
107  timer.stop();
108 
109  if (T(0) != total)
110  printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
111  timer.time(),
112  count / timer.time(),
113  expr_string.c_str());
114  else
115  printf("run_exprtk_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
116 }
117 
118 template <typename T> struct native;
119 
120 template <typename T, typename NativeFunction>
121 void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_string)
122 {
123  T total = T(0);
124  unsigned int count = 0;
125 
126  exprtk::timer timer;
127  timer.start();
128 
130  {
132  {
133  total += f(x,y);
134  ++count;
135  }
136  }
137 
138  timer.stop();
139 
140  if (T(0) != total)
141  printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
142  timer.time(),
143  count / timer.time(),
144  expr_string.c_str());
145  else
146  printf("run_native_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str());
147 }
148 
149 template <typename T>
151 {
152  static const std::size_t rounds = 100000;
154  exprtk::expression<double> expression;
155 
156  expression.register_symbol_table(symbol_table);
157 
158  for (std::size_t i = 0; i < global_expression_list_size; ++i)
159  {
160  exprtk::timer timer;
161  timer.start();
162 
163  for (std::size_t r = 0; r < rounds; ++r)
164  {
165  if (!parser.compile(global_expression_list[i],expression))
166  {
167  printf("[run_parse_benchmark] - Parser Error: %s\tExpression: %s\n",
168  parser.error().c_str(),
169  global_expression_list[i].c_str());
170 
171  return false;
172  }
173  }
174 
175  timer.stop();
176 
177  printf("[parse] Total Time:%12.8f Rate:%14.3fparse/sec Expression: %s\n",
178  timer.time(),
179  rounds / timer.time(),
180  global_expression_list[i].c_str());
181  }
182 
183  return true;
184 }
185 
186 const double pi = 3.141592653589793238462643383279502;
187 
188 template <typename T>
189 struct native
190 {
192  typedef typename functor_t::Type Type;
193 
194  static inline T avg(Type x, Type y)
195  {
196  return (x + y) / T(2);
197  }
198 
199  static inline T clamp(const Type l, const Type v, const Type u)
200  {
201  return ((v < l) ? l : ((v > u) ? u : v));
202  }
203 
204  static inline T func00(Type x, Type y)
205  {
206  return (y + x);
207  }
208 
209  static inline T func01(Type x, Type y)
210  {
211  return T(2) * (y + x);
212  }
213 
214  static inline T func02(Type x, Type y)
215  {
216  return (T(2) * y + T(2) * x);
217  }
218 
219  static inline T func03(Type x, Type y)
220  {
221  return ((T(1.23) * (x * x)) / y) - T(123.123);
222  }
223 
224  static inline T func04(Type x, Type y)
225  {
226  return (y + x / y) * (x - y / x);
227  }
228 
229  static inline T func05(Type x, Type y)
230  {
231  return x / ((x + y) + (x - y)) / y;
232  }
233 
234  static inline T func06(Type x, Type y)
235  {
236  return T(1) - ((x * y) + (y / x)) - T(3);
237  }
238 
239  static inline T func07(Type x, Type y)
240  {
241  return (T(5.5) + x) + (T(2) * x - T(2) / T(3) * y) * (x / T(3) + y / T(4)) + (y + T(7.7));
242  }
243 
244  static inline T func08(Type x, Type y)
245  {
246  using namespace std;
247  return (T(1.1)*pow(x,T(1))+T(2.2)*pow(y,T(2))-T(3.3)*pow(x,T(3))+T(4.4)*pow(y,T(15))-T(5.5)*pow(x,T(23))+T(6.6)*pow(y,T(55)));
248  }
249 
250  static inline T func09(Type x, Type y)
251  {
252  return std::sin(T(2) * x) + std::cos(pi / y);
253  }
254 
255  static inline T func10(Type x, Type y)
256  {
257  return T(1) - std::sin(T(2) * x) + std::cos(pi / y);
258  }
259 
260  static inline T func11(Type x, Type y)
261  {
262  return std::sqrt(T(111.111) - std::sin(T(2) * x) + std::cos(pi / y) / T(333.333));
263  }
264 
265  static inline T func12(Type x, Type y)
266  {
267  return ((x * x) / std::sin(T(2) * pi / y)) - x / T(2);
268  }
269 
270  static inline T func13(Type x, Type y)
271  {
272  return (x + (std::cos(y - std::sin(T(2) / x * pi)) - std::sin(x - std::cos(T(2) * y / pi))) - y);
273  }
274 
275  static inline T func14(Type x, Type y)
276  {
277  return clamp(T(-1), std::sin(T(2) * pi * x) + std::cos(y / T(2) * pi), + T(1));
278  }
279 
280  static inline T func15(Type x, Type y)
281  {
282  return std::max(T(3.33), std::min(sqrt(T(1) - std::sin(T(2) * x) + std::cos(pi / y) / T(3)), T(1.11)));
283  }
284 
285  static inline T func16(Type x, Type y)
286  {
287  return (((y + (x * T(2.2))) <= (x + y + T(1.1))) ? x - y : x * y) + T(2) * pi / x;
288  }
289 };
290 
291 void pgo_primer();
292 void perform_file_based_benchmark(const std::string& file_name, const std::size_t& rounds = 100000);
293 
294 int main(int argc, char* argv[])
295 {
296  if (argc >= 2)
297  {
298  const std::string file_name = argv[1];
299 
300  if (argc == 2)
301  perform_file_based_benchmark(file_name);
302  else
303  perform_file_based_benchmark(file_name,atoi(argv[2]));
304 
305  return 0;
306  }
307 
308  pgo_primer();
309 
310  double x = 0;
311  double y = 0;
312 
313  exprtk::symbol_table<double> symbol_table;
314  symbol_table.add_constants();
315  symbol_table.add_variable("x",x);
316  symbol_table.add_variable("y",y);
317 
318  std::deque<exprtk::expression<double> > compiled_expr_list;
319 
320  if (!load_expression(symbol_table,compiled_expr_list))
321  {
322  return 1;
323  }
324 
325  {
326  std::cout << "--- EXPRTK ---" << std::endl;
327  for (std::size_t i = 0; i < compiled_expr_list.size(); ++i)
328  {
329  run_exprtk_benchmark(x,y,compiled_expr_list[i],global_expression_list[i]);
330  }
331  }
332 
333  {
334  std::cout << "--- NATIVE ---" << std::endl;
352  }
353 
354  {
355  std::cout << "--- PARSE ----" << std::endl;
356  run_parse_benchmark(symbol_table);
357  }
358 
359  return 0;
360 }
361 
363 {
364  exprtk::pgo_primer<double>();
365 
366  static const double lower_bound_x = -50.0;
367  static const double lower_bound_y = -50.0;
368  static const double upper_bound_x = +50.0;
369  static const double upper_bound_y = +50.0;
370  static const double delta = 0.07;
371 
372  double total = 0.0;
373 
374  for (double x = lower_bound_x; x <= upper_bound_x; x += delta)
375  {
376  for (double y = lower_bound_y; y <= upper_bound_y; y += delta)
377  {
378  total += native<double>::func00(x,y);
379  total += native<double>::func01(x,y);
380  total += native<double>::func02(x,y);
381  total += native<double>::func03(x,y);
382  total += native<double>::func04(x,y);
383  total += native<double>::func05(x,y);
384  total += native<double>::func06(x,y);
385  total += native<double>::func07(x,y);
386  total += native<double>::func08(x,y);
387  total += native<double>::func09(x,y);
388  total += native<double>::func10(x,y);
389  total += native<double>::func11(x,y);
390  total += native<double>::func12(x,y);
391  total += native<double>::func13(x,y);
392  total += native<double>::func14(x,y);
393  total += native<double>::func15(x,y);
394  total += native<double>::func16(x,y);
395  }
396  }
397 }
398 
399 std::size_t load_expression_file(const std::string& file_name, std::deque<std::string>& expression_list)
400 {
401  std::ifstream stream(file_name.c_str());
402 
403  if (!stream) return 0;
404 
406  buffer.reserve(1024);
407  std::size_t line_count = 0;
408 
409  while (std::getline(stream,buffer))
410  {
411  if (buffer.empty())
412  continue;
413  else if ('#' == buffer[0])
414  continue;
415 
416  ++line_count;
417  expression_list.push_back(buffer);
418  }
419 
420  return line_count;
421 }
422 
423 void perform_file_based_benchmark(const std::string& file_name, const std::size_t& rounds)
424 {
425  std::deque<std::string> expr_str_list;
426 
427  if (0 == load_expression_file(file_name,expr_str_list))
428  {
429  std::cout << "Failed to load any expressions from: " << file_name << "\n";
430  return;
431  }
432 
436 
437  std::deque<expression_t> expression_list;
438 
439  symbol_table_t symbol_table;
440 
441  double a = 1.1;
442  double b = 2.2;
443  double c = 3.3;
444  double x = 2.123456;
445  double y = 3.123456;
446  double z = 4.123456;
447  double w = 5.123456;
448 
449  symbol_table.add_variable("a", a);
450  symbol_table.add_variable("b", b);
451  symbol_table.add_variable("c", c);
452 
453  symbol_table.add_variable("x", x);
454  symbol_table.add_variable("y", y);
455  symbol_table.add_variable("z", z);
456  symbol_table.add_variable("w", w);
457 
470 
471  symbol_table.add_function("poly01", poly01);
472  symbol_table.add_function("poly02", poly02);
473  symbol_table.add_function("poly03", poly03);
474  symbol_table.add_function("poly04", poly04);
475  symbol_table.add_function("poly05", poly05);
476  symbol_table.add_function("poly06", poly06);
477  symbol_table.add_function("poly07", poly07);
478  symbol_table.add_function("poly08", poly08);
479  symbol_table.add_function("poly09", poly09);
480  symbol_table.add_function("poly10", poly10);
481  symbol_table.add_function("poly11", poly11);
482  symbol_table.add_function("poly12", poly12);
483 
485  symbol_table.add_variable("e", e, true);
486 
487  symbol_table.add_constants();
488 
489  {
491 
492  for (std::size_t i = 0; i < expr_str_list.size(); ++i)
493  {
494  expression_t expression;
495  expression.register_symbol_table(symbol_table);
496 
497  if (!parser.compile(expr_str_list[i],expression))
498  {
499  printf("[perform_file_based_benchmark] - Parser Error: %s\tExpression: %s\n",
500  parser.error().c_str(),
501  expr_str_list[i].c_str());
502 
503  return;
504  }
505 
506  expression_list.push_back(expression);
507  }
508  }
509 
510  exprtk::timer total_timer;
511  exprtk::timer timer;
512 
513  double single_eval_total_time = 0.0;
514 
515  total_timer.start();
516 
517  for (std::size_t i = 0; i < expression_list.size(); ++i)
518  {
519  expression_t& expression = expression_list[i];
520 
521  a = 1.1;
522  b = 2.2;
523  c = 3.3;
524  x = 2.123456;
525  y = 3.123456;
526  z = 4.123456;
527  w = 5.123456;
528 
529  timer.start();
530  double sum = 0.0;
531 
532  for (std::size_t r = 0; r < rounds; ++r)
533  {
534  sum += expression.value();
535  std::swap(a,b);
536  std::swap(x,y);
537  }
538 
539  timer.stop();
540 
541  printf("Expression %3d of %3d %9.3f ns\t%10d ns\t(%30.10f) '%s'\n",
542  static_cast<int>(i + 1),
543  static_cast<int>(expression_list.size()),
544  (timer.time() * 1000000000.0) / (1.0 * rounds),
545  static_cast<int>(timer.time() * 1000000000.0),
546  sum,
547  expr_str_list[i].c_str());
548 
549  fflush(stdout);
550 
551  single_eval_total_time += (timer.time() * 1000000000.0) / (1.0 * rounds);
552  }
553 
554  total_timer.stop();
555 
556  printf("[*] Number Of Evals: %15.0f\n",
557  rounds * (expression_list.size() * 1.0));
558 
559  printf("[*] Total Time: %9.3fsec\n",
560  total_timer.time());
561 
562  printf("[*] Total Single Eval Time: %9.3fms\n",
563  single_eval_total_time / 1000000.0);
564 }