/* ************************************************************** * C++ Mathematical Expression Toolkit Library * * * * ExprTk vs Native Benchmarks * * Author: Arash Partow (1999-2013) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the Common Public License. * * http://www.opensource.org/licenses/cpl1.0.php * * * ************************************************************** */ #include #include #include #include #include #include "exprtk.hpp" const std::string expression_list[] = { "(y + x)", "2 * (y + x)", "(2 * y + 2 * x)", "(y + x / y) * (x - y / x)", "x / ((x + y) * (x - y)) / y", "1 - ((x * y) + (y / x)) - 3", "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55", "sin(2 * x) + cos(pi / y)", "1 - sin(2 * x) + cos(pi / y)", "sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333)", "(x^2 / sin(2 * pi / y)) -x / 2", "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x" }; const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); static const double lower_bound_x = -100.0; static const double lower_bound_y = -100.0; static const double upper_bound_x = +100.0; static const double upper_bound_y = +100.0; static const double delta = 0.0173; template class Sequence> bool load_expression(exprtk::symbol_table& symbol_table, Sequence,Allocator>& expr_seq, const typename exprtk::parser::optimization_level& opt_level) { exprtk::parser parser; for (std::size_t i = 0; i < expression_list_size; ++i) { exprtk::expression expression; expression.register_symbol_table(symbol_table); if (!parser.compile(expression_list[i],expression,opt_level)) { printf("[load_expression] - Parser Error: %s\tExpression: %s\n", parser.error().c_str(), expression_list[i].c_str()); return false; } expr_seq.push_back(expression); } return true; } template void run_exprtk_benchmark(T& x, T& y, exprtk::expression& expression, const std::string& expr_string) { double total = 0.0; unsigned int count = 0; exprtk::timer timer; timer.start(); for (x = lower_bound_x; x <= upper_bound_x; x += delta) { for (y = lower_bound_y; y <= upper_bound_y; y += delta) { total += expression.value(); ++count; } } timer.stop(); if (T(0.0) != total) printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", timer.time(), count / timer.time(), expr_string.c_str()); else printf("run_exprtk_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str()); } template inline T func00(const T x, const T y); template inline T func01(const T x, const T y); template inline T func02(const T x, const T y); template inline T func03(const T x, const T y); template inline T func04(const T x, const T y); template inline T func05(const T x, const T y); template inline T func06(const T x, const T y); template inline T func07(const T x, const T y); template inline T func08(const T x, const T y); template inline T func09(const T x, const T y); template inline T func10(const T x, const T y); template inline T func11(const T x, const T y); template inline T func12(const T x, const T y); template inline T func13(const T x, const T y); template inline T func14(const T x, const T y); template void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_string) { double total = 0.0; unsigned int count = 0; exprtk::timer timer; timer.start(); for (x = lower_bound_x; x <= upper_bound_x; x += delta) { for (y = lower_bound_y; y <= upper_bound_y; y += delta) { total += f(x,y); ++count; } } timer.stop(); if (T(0.0) != total) printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n", timer.time(), count / timer.time(), expr_string.c_str()); else printf("run_native_benchmark() - Error running benchmark for expression: %s\n",expr_string.c_str()); } template bool run_parse_benchmark(exprtk::symbol_table& symbol_table) { static const std::size_t rounds = 1000000; exprtk::parser parser; exprtk::expression expression; expression.register_symbol_table(symbol_table); for (std::size_t i = 0; i < expression_list_size; ++i) { exprtk::timer timer; timer.start(); for (std::size_t r = 0; r < rounds; ++r) { if (!parser.compile(expression_list[i],expression)) { printf("[run_parse_benchmark] - Parser Error: %s\tExpression: %s\n", parser.error().c_str(), expression_list[i].c_str()); return false; } } timer.stop(); printf("[parse] Total Time:%12.8f Rate:%14.3fparse/sec Expression: %s\n", timer.time(), rounds / timer.time(), expression_list[i].c_str()); } return true; } void pgo_primer(); int main() { pgo_primer(); double x = 0; double y = 0; exprtk::symbol_table symbol_table; symbol_table.add_constants(); symbol_table.add_variable("x",x); symbol_table.add_variable("y",y); std::deque > optimized_expr_list; std::deque > expr_list; if (!load_expression(symbol_table,optimized_expr_list,exprtk::parser::e_all)) { return 1; } if (!load_expression(symbol_table,expr_list,exprtk::parser::e_none)) { return 1; } { std::cout << "--- EXPRTK [All Optimisations] ---" << std::endl; for (std::size_t i = 0; i < optimized_expr_list.size(); ++i) { run_exprtk_benchmark(x,y,optimized_expr_list[i],expression_list[i]); } std::cout << "--- EXPRTK [No Optimisations] ---" << std::endl; for (std::size_t i = 0; i < expr_list.size(); ++i) { run_exprtk_benchmark(x,y,expr_list[i],expression_list[i]); } } { std::cout << "--- NATIVE ---" << std::endl; run_native_benchmark(x,y,func00,expression_list[ 0]); run_native_benchmark(x,y,func01,expression_list[ 1]); run_native_benchmark(x,y,func02,expression_list[ 2]); run_native_benchmark(x,y,func03,expression_list[ 3]); run_native_benchmark(x,y,func04,expression_list[ 4]); run_native_benchmark(x,y,func05,expression_list[ 5]); run_native_benchmark(x,y,func06,expression_list[ 6]); run_native_benchmark(x,y,func07,expression_list[ 7]); run_native_benchmark(x,y,func08,expression_list[ 8]); run_native_benchmark(x,y,func09,expression_list[ 9]); run_native_benchmark(x,y,func10,expression_list[10]); run_native_benchmark(x,y,func11,expression_list[11]); run_native_benchmark(x,y,func12,expression_list[12]); run_native_benchmark(x,y,func13,expression_list[13]); run_native_benchmark(x,y,func14,expression_list[14]); } { std::cout << "--- PARSE ----" << std::endl; run_parse_benchmark(symbol_table); } return 0; } void pgo_primer() { exprtk::pgo_primer(); static const double lower_bound_x = -50.0; static const double lower_bound_y = -50.0; static const double upper_bound_x = +50.0; static const double upper_bound_y = +50.0; static const double delta = 0.03; double total = 0.0; for (double x = lower_bound_x; x <= upper_bound_x; x += delta) { for (double y = lower_bound_y; y <= upper_bound_y; y += delta) { total += func00(x,y); total += func01(x,y); total += func02(x,y); total += func03(x,y); total += func04(x,y); total += func05(x,y); total += func06(x,y); total += func07(x,y); total += func08(x,y); total += func09(x,y); total += func10(x,y); total += func11(x,y); total += func12(x,y); total += func13(x,y); total += func14(x,y); } } } const double pi = 3.14159265358979323846; template inline T avg(const T v1, const T v2) { return (v1 + v2) / T(2.0); } template inline T clamp(const T l, const T v, const T u) { return ((v < l) ? l : ((v > u) ? u : v)); } template inline T func00(const T x, const T y) { return (y + x); } template inline T func01(const T x, const T y) { return T(2.0) * (y + x); } template inline T func02(const T x, const T y) { return (T(2.0) * y + T(2.0) * x); } template inline T func03(const T x, const T y) { return (y + x / y) * (x - y / x); } template inline T func04(const T x, const T y) { return x / ((x + y) * (x - y)) / y; } template inline T func05(const T x, const T y) { return T(1.0) - ((x * y) + (y / x)) - T(3.0); } template inline T func06(const T x, const T y) { return (1.1*pow(x,T(1.0))+2.2*pow(y,T(2.0))-3.3*pow(x,T(3.0))+4.4*pow(y,T(15.0))-5.5*pow(x,T(23.0))+6.6*pow(y,T(55.0))); } template inline T func07(const T x, const T y) { return std::sin(T(2.0) * x) + std::cos(pi / y); } template inline T func08(const T x, const T y) { return T(1.0) - std::sin(2.0 * x) + std::cos(pi / y); } template inline T func09(const T x, const T y) { return std::sqrt(T(111.111) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(333.333)); } template inline T func10(const T x, const T y) { return (std::pow(x,T(2.0)) / std::sin(T(2.0) * pi / y)) -x / T(2.0); } template inline T func11(const T x, const T y) { return (x + (std::cos(y - std::sin(2 / x * pi)) - std::sin(x - std::cos(2 * y / pi))) - y); } template inline T func12(const T x, const T y) { return clamp(T(-1.0), std::sin(T(2.0) * pi * x) + std::cos(y / T(2.0) * pi), + T(1.0)); } template inline T func13(const T x, const T y) { return std::max(T(3.33), std::min(sqrt(T(1.0) - std::sin(T(2.0) * x) + std::cos(pi / y) / T(3.0)), T(1.11))); } template inline T func14(const T x, const T y) { return ((avg(x,y) <= x + y) ? x - y : x * y) + T(2.0) * pi / x; }