forked from symengine/symengine
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add visitor_init benchmark to benchmark init() for
- LambdaRealDoubleVisitor - LLVMDoubleVisitor - LLVMFloatVisitor refactor visitor benchmarks - move expressions to visitor_expressions.h - add SYMENGINE_BENCHMARK_VISITORS macro to generate benchmarks for all expressions add more expressions - two large expressions based on symengine#1612 - one expression with many intrinsic functions copied from test_lambda_double.cpp
- Loading branch information
Showing
4 changed files
with
267 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,173 +1,75 @@ | ||
#include <benchmark/benchmark.h> | ||
#include <math.h> | ||
#include <symengine/add.h> | ||
#include <symengine/integer.h> | ||
#include <symengine/lambda_double.h> | ||
#include <symengine/llvm_double.h> | ||
#include <symengine/mul.h> | ||
#include <symengine/pow.h> | ||
#include <symengine/symbol.h> | ||
#include "visitor_expressions.h" | ||
|
||
using SymEngine::add; | ||
using SymEngine::Basic; | ||
using SymEngine::cos; | ||
using SymEngine::integer; | ||
using SymEngine::LambdaRealDoubleVisitor; | ||
using SymEngine::LLVMDoubleVisitor; | ||
using SymEngine::LLVMFloatVisitor; | ||
using SymEngine::mul; | ||
using SymEngine::pow; | ||
using SymEngine::RCP; | ||
using SymEngine::sin; | ||
using SymEngine::symbol; | ||
using SymEngine::vec_basic; | ||
|
||
struct Expr1 { | ||
vec_basic vec{{symbol("x"), symbol("y"), symbol("z")}}; | ||
vec_basic expr() | ||
{ | ||
vec_basic r{symbol("r0")}; | ||
r[0] = sin(add(vec[0], | ||
cos(add(mul(vec[1], vec[2]), pow(vec[0], integer(2)))))); | ||
r[0] = mul(add(integer(3), r[0]), add(integer(2), r[0])); | ||
r[0] = pow(add(integer(5), r[0]), add(integer(-2), r[0])); | ||
return r; | ||
} | ||
static void compiled_expr(double *d, const double *v) | ||
struct CompiledExpr1 { | ||
void call(double *d, const double *v) | ||
{ | ||
double r1 | ||
= std::sin(v[0] + std::cos((v[1] * v[2]) + std::pow(v[0], 2))); | ||
double r2 = (3 + r1) * (2 + r1); | ||
*d = std::pow((5 + r2), (r2 - 2)); | ||
} | ||
static void compiled_expr(float *d, const float *v) | ||
void call(float *d, const float *v) | ||
{ | ||
float r1 = sinf(v[0] + cosf((v[1] * v[2]) + powf(v[0], 2))); | ||
float r2 = (3 + r1) * (2 + r1); | ||
*d = powf((5 + r2), (r2 - 2)); | ||
} | ||
}; | ||
|
||
struct Expr2 { | ||
vec_basic vec{{symbol("x"), symbol("y"), symbol("z")}}; | ||
vec_basic expr() | ||
{ | ||
vec_basic r{symbol("r0"), symbol("r1"), symbol("r2")}; | ||
r[0] = mul(integer(2), add(vec[0], add(vec[0], mul(vec[1], vec[2])))); | ||
r[1] = add(vec[0], add(vec[0], mul(vec[2], vec[1]))); | ||
r[2] = mul(integer(-2), add(vec[0], add(vec[0], mul(vec[1], vec[2])))); | ||
return r; | ||
} | ||
struct CompiledExpr2 { | ||
template <typename Real> | ||
static void compiled_expr(Real *d, const Real *v) | ||
void call(Real *d, const Real *v) | ||
{ | ||
d[0] = 2.0 * (v[0] + v[0] + (v[1] * v[2])); | ||
d[0] = static_cast<Real>(2.0) * (v[0] + v[0] + (v[1] * v[2])); | ||
d[1] = v[0] + v[0] + (v[2] * v[1]); | ||
d[2] = -2.0 * (v[0] + v[0] + (v[1] * v[2])); | ||
d[2] = -static_cast<Real>(2.0) * (v[0] + v[0] + (v[1] * v[2])); | ||
} | ||
}; | ||
|
||
template <typename Real> | ||
struct NativeVisitor { | ||
void (*f)(Real *, const Real *){nullptr}; | ||
void call(Real *d, const Real *v) | ||
{ | ||
f(d, v); | ||
} | ||
}; | ||
void init(CompiledExpr1 &v, const vec_basic &args, const vec_basic &expr, | ||
bool cse, unsigned opt_level){}; | ||
|
||
template <typename Expr, typename Real> | ||
std::string init(NativeVisitor<Real> &v, bool cse, unsigned opt_level) | ||
{ | ||
v.f = &Expr::compiled_expr; | ||
return {}; | ||
} | ||
|
||
template <typename Expr> | ||
std::string init(LambdaRealDoubleVisitor &v, bool cse, unsigned opt_level) | ||
{ | ||
std::string label; | ||
Expr e; | ||
v.init(e.vec, e.expr(), cse); | ||
if (cse) { | ||
label = "cse"; | ||
} | ||
return label; | ||
} | ||
|
||
template <typename Expr> | ||
std::string init(LLVMDoubleVisitor &v, bool cse, unsigned opt_level) | ||
{ | ||
std::string label; | ||
Expr e; | ||
v.init(e.vec, e.expr(), cse, opt_level); | ||
if (cse) { | ||
label.append("cse_"); | ||
} | ||
label.append("O"); | ||
label.append(std::to_string(opt_level)); | ||
return label; | ||
} | ||
|
||
template <typename Expr> | ||
std::string init(LLVMFloatVisitor &v, bool cse, unsigned opt_level) | ||
{ | ||
std::string label; | ||
Expr e; | ||
v.init(e.vec, e.expr(), cse, opt_level); | ||
if (cse) { | ||
label.append("cse_"); | ||
} | ||
label.append("O"); | ||
label.append(std::to_string(opt_level)); | ||
return label; | ||
} | ||
void init(CompiledExpr2 &v, const vec_basic &args, const vec_basic &expr, | ||
bool cse, unsigned opt_level){}; | ||
|
||
template <typename Visitor, typename Expr, typename Real> | ||
static void Call(benchmark::State &state) | ||
{ | ||
std::vector<Real> s{0.0, 0.0, 0.0}; | ||
std::vector<Real> d{0.0, 0.0, 0.0}; | ||
std::vector<Real> x{1.0, 4.4365, 12.8}; | ||
Expr e; | ||
vec_basic inputs{e.vec}; | ||
vec_basic outputs{e.expr()}; | ||
const std::size_t n_inputs{inputs.size()}; | ||
const std::size_t n_outputs{outputs.size()}; | ||
std::vector<Real> s(n_outputs, 0.0); | ||
std::vector<Real> d(n_outputs, 0.0); | ||
std::vector<Real> x(n_inputs, 0.0); | ||
for (std::size_t i = 0; i < n_inputs; ++i) { | ||
x[i] = static_cast<Real>(1.732 * i); | ||
} | ||
Visitor v; | ||
bool cse{static_cast<bool>(state.range(0))}; | ||
unsigned opt_level{static_cast<unsigned>(state.range(1))}; | ||
auto label = init<Expr>(v, cse, opt_level); | ||
init(v, inputs, outputs, cse, opt_level); | ||
for (auto _ : state) { | ||
x[0] += 0.1; | ||
x[1] += 0.2; | ||
x[2] += 0.3; | ||
for (std::size_t i = 0; i < n_inputs; ++i) { | ||
x[i] += static_cast<Real>(0.1); | ||
} | ||
v.call(d.data(), x.data()); | ||
benchmark::ClobberMemory(); | ||
s[0] += d[0]; | ||
s[1] += d[1]; | ||
s[2] += d[2]; | ||
for (std::size_t i = 0; i < n_outputs; ++i) { | ||
s[i] += d[i]; | ||
} | ||
} | ||
state.SetLabel(label); | ||
state.SetLabel(to_label(cse, opt_level)); | ||
} | ||
|
||
// BENCHMARK_TEMPLATE(BenchmarkName, VisitorClass, | ||
// ExpressionClass, RealType)->ArgsProduct({{cse values}, {opt_level values}}); | ||
|
||
static std::vector<int64_t> opt_code_values{0, 1, 2, 3}; | ||
static std::vector<int64_t> cse_values{0, 1}; | ||
|
||
BENCHMARK_TEMPLATE(Call, LambdaRealDoubleVisitor, Expr1, double) | ||
->ArgsProduct({cse_values, {0}}); | ||
BENCHMARK_TEMPLATE(Call, LLVMDoubleVisitor, Expr1, double) | ||
->ArgsProduct({cse_values, opt_code_values}); | ||
BENCHMARK_TEMPLATE(Call, NativeVisitor<double>, Expr1, double)->Args({0, 0}); | ||
BENCHMARK_TEMPLATE(Call, LLVMFloatVisitor, Expr1, float) | ||
->ArgsProduct({cse_values, opt_code_values}); | ||
BENCHMARK_TEMPLATE(Call, NativeVisitor<float>, Expr1, float)->Args({0, 0}); | ||
SYMENGINE_BENCHMARK_VISITORS(Call); | ||
|
||
BENCHMARK_TEMPLATE(Call, LambdaRealDoubleVisitor, Expr2, double) | ||
->ArgsProduct({cse_values, {0}}); | ||
BENCHMARK_TEMPLATE(Call, LLVMDoubleVisitor, Expr2, double) | ||
->ArgsProduct({cse_values, opt_code_values}); | ||
BENCHMARK_TEMPLATE(Call, NativeVisitor<double>, Expr2, double)->Args({0, 0}); | ||
BENCHMARK_TEMPLATE(Call, LLVMFloatVisitor, Expr2, float) | ||
->ArgsProduct({cse_values, opt_code_values}); | ||
BENCHMARK_TEMPLATE(Call, NativeVisitor<float>, Expr2, float)->Args({0, 0}); | ||
// repeat benchmarks with natively compiled version of expressions | ||
BENCHMARK_TEMPLATE(Call, CompiledExpr1, Expr1, double)->Args({0, 0}); | ||
BENCHMARK_TEMPLATE(Call, CompiledExpr1, Expr1, float)->Args({0, 0}); | ||
BENCHMARK_TEMPLATE(Call, CompiledExpr2, Expr2, double)->Args({0, 0}); | ||
BENCHMARK_TEMPLATE(Call, CompiledExpr2, Expr2, float)->Args({0, 0}); | ||
|
||
BENCHMARK_MAIN(); |
Oops, something went wrong.