[DEV] add v1.76.0

This commit is contained in:
2021-10-05 21:37:46 +02:00
parent a97e9ae7d4
commit d0115b733d
45133 changed files with 4744437 additions and 1026325 deletions

View File

@@ -0,0 +1,56 @@
include_directories(${CMAKE_HOME_DIRECTORY})
macro(add_code_gen_executable name)
add_executable(${name} ${name}.cpp)
target_link_libraries(${name} yap)
if (clang_on_linux)
target_link_libraries(${name} c++)
endif ()
endmacro()
add_code_gen_executable(code_gen_samples)
add_code_gen_executable(map_assign_code_gen)
add_code_gen_executable(lazy_vector_perf)
macro(add_perf_executable name)
add_executable(${name} ${name}.cpp)
add_dependencies(${name} benchmark)
target_link_libraries(${name} yap benchmark)
if (clang_on_linux)
target_link_libraries(${name} c++)
endif ()
endmacro()
add_perf_executable(map_assign_perf)
add_perf_executable(arithmetic_perf)
include(Disassemble)
set(disassemble_dump_targets)
foreach(fun eval_as_cpp_expr eval_as_yap_expr eval_as_cpp_expr_4x eval_as_yap_expr_4x)
disassemble(disassemble.arithmetic_perf.${fun} EXECUTABLE arithmetic_perf FUNCTION ${fun})
disassemble(disassemble.code_gen_samples.${fun} EXECUTABLE code_gen_samples FUNCTION ${fun})
add_custom_target(disass_dump.${fun}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target disassemble.arithmetic_perf.${fun}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target disassemble.code_gen_samples.${fun}
)
list(APPEND disassemble_dump_targets disass_dump.${fun})
endforeach()
foreach(fun get_d1_with_yap get_d1_by_hand update_v1_with_yap update_v1_by_hand)
disassemble(disassemble.lazy_vector_perf.${fun} EXECUTABLE lazy_vector_perf FUNCTION ${fun})
add_custom_target(disass_dump.${fun}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target disassemble.lazy_vector_perf.${fun}
)
list(APPEND disassemble_dump_targets disass_dump.${fun})
endforeach()
add_custom_target(perf
COMMAND map_assign_perf
COMMAND arithmetic_perf
DEPENDS ${disassemble_dump_targets}
)

View File

@@ -0,0 +1,141 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>
#include <chrono>
#include <iostream>
#include <benchmark/benchmark.h>
template<typename T>
using term = boost::yap::terminal<boost::yap::expression, T>;
namespace yap = boost::yap;
namespace bh = boost::hana;
//[ arithmetic_perf_decls
namespace user {
struct number
{
double value;
friend number operator+(number lhs, number rhs)
{
return number{lhs.value + rhs.value};
}
friend number operator*(number lhs, number rhs)
{
return number{lhs.value * rhs.value};
}
};
}
//]
double get_noise()
{
auto const start_time = std::chrono::high_resolution_clock::now();
auto const start_time_ns =
std::chrono::time_point_cast<std::chrono::nanoseconds>(start_time);
return 1.0 * start_time_ns.time_since_epoch().count();
}
user::number g_a{get_noise()};
user::number g_x{get_noise()};
user::number g_y{get_noise()};
//[ arithmetic_perf_eval_as_yap_expr
user::number eval_as_yap_expr(user::number a_, user::number x_, user::number y_)
{
term<user::number> a{{a_}};
term<user::number> x{{x_}};
term<user::number> y{{y_}};
auto expr = (a * x + y) * (a * x + y) + (a * x + y);
return yap::evaluate(expr);
}
//]
void BM_eval_as_yap_expr(benchmark::State & state)
{
double d = 0;
while (state.KeepRunning()) {
user::number const n = eval_as_yap_expr(g_a, g_x, g_y);
d += n.value;
}
std::cout << "Sum of doubles=" << d << "\n";
}
//[ arithmetic_perf_eval_as_yap_expr_4x
user::number
eval_as_yap_expr_4x(user::number a_, user::number x_, user::number y_)
{
term<user::number> a{{a_}};
term<user::number> x{{x_}};
term<user::number> y{{y_}};
auto expr = (a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y);
return yap::evaluate(expr);
}
//]
void BM_eval_as_yap_expr_4x(benchmark::State & state)
{
double d = 0;
while (state.KeepRunning()) {
user::number const n = eval_as_yap_expr_4x(g_a, g_x, g_y);
d += n.value;
}
std::cout << "Sum of doubles=" << d << "\n";
}
//[ arithmetic_perf_eval_as_cpp_expr
user::number eval_as_cpp_expr(user::number a, user::number x, user::number y)
{
return (a * x + y) * (a * x + y) + (a * x + y);
}
//]
void BM_eval_as_cpp_expr(benchmark::State & state)
{
double d = 0;
while (state.KeepRunning()) {
user::number const n = eval_as_cpp_expr(g_a, g_x, g_y);
d += n.value;
}
std::cout << "Sum of doubles=" << d << "\n";
}
//[ arithmetic_perf_eval_as_cpp_expr_4x
user::number eval_as_cpp_expr_4x(user::number a, user::number x, user::number y)
{
return (a * x + y) * (a * x + y) + (a * x + y) + (a * x + y) * (a * x + y) +
(a * x + y) + (a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y);
}
//]
void BM_eval_as_cpp_expr_4x(benchmark::State & state)
{
double d = 0;
while (state.KeepRunning()) {
user::number const n = eval_as_cpp_expr_4x(g_a, g_x, g_y);
d += n.value;
}
std::cout << "Sum of doubles=" << d << "\n";
}
BENCHMARK(BM_eval_as_yap_expr);
BENCHMARK(BM_eval_as_yap_expr_4x);
BENCHMARK(BM_eval_as_cpp_expr);
BENCHMARK(BM_eval_as_cpp_expr_4x);
BENCHMARK_MAIN();

View File

@@ -0,0 +1,99 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>
template<typename T>
using term = boost::yap::terminal<boost::yap::expression, T>;
namespace yap = boost::yap;
namespace bh = boost::hana;
namespace user {
struct number
{
double value;
friend number operator+(number lhs, number rhs)
{
return number{lhs.value + rhs.value};
}
friend number operator*(number lhs, number rhs)
{
return number{lhs.value * rhs.value};
}
};
// A more efficient fused multiply-add operation would normally go here.
number naxpy(number a, number x, number y)
{
return number{a.value * x.value + y.value};
}
// Transforms expressions of the form "a * x + y" to "naxpy(a, x, y)" via
// the implicit transform customiztion point.
template<typename Expr1, typename Expr2, typename Expr3>
decltype(auto) transform_expression(yap::expression<
yap::expr_kind::plus,
bh::tuple<
yap::expression<
yap::expr_kind::multiplies,
bh::tuple<Expr1, Expr2>>,
Expr3>> const & expr)
{
return naxpy(
evaluate(expr.left().left()),
evaluate(expr.left().right()),
evaluate(expr.right()));
}
}
term<user::number> a{{1.0}};
term<user::number> x{{42.0}};
term<user::number> y{{3.0}};
user::number
eval_as_yap_expr(decltype((a * x + y) * (a * x + y) + (a * x + y)) & expr)
{
return yap::evaluate(expr);
}
user::number eval_as_yap_expr_4x(decltype(
(a * x + y) * (a * x + y) + (a * x + y) + (a * x + y) * (a * x + y) +
(a * x + y) + (a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y)) & expr)
{
return yap::evaluate(expr);
}
user::number eval_as_cpp_expr(user::number a, user::number x, user::number y)
{
return (a * x + y) * (a * x + y) + (a * x + y);
}
user::number eval_as_cpp_expr_4x(user::number a, user::number x, user::number y)
{
return (a * x + y) * (a * x + y) + (a * x + y) + (a * x + y) * (a * x + y) +
(a * x + y) + (a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y);
}
int main()
{
auto expr = (a * x + y) * (a * x + y) + (a * x + y);
user::number result_1 = eval_as_yap_expr(expr);
user::number result_2 =
eval_as_cpp_expr(yap::value(a), yap::value(x), yap::value(y));
(void)result_1;
(void)result_2;
return 0;
}

View File

@@ -0,0 +1,151 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//[ lazy_vector
// Defining this allows the assignment below of an expression to a double
// without writing any specific code to do so.
#include <boost/yap/expression.hpp>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
template<boost::yap::expr_kind Kind, typename Tuple>
struct lazy_vector_expr;
// This transform turns a terminal of std::vector<double> into a terminal
// containing the nth double in that vector. Think of it as turning our
// expression of vectors into an expression of scalars.
struct take_nth
{
boost::yap::terminal<lazy_vector_expr, double> operator()(
boost::yap::terminal<lazy_vector_expr, std::vector<double>> const &
expr);
std::size_t n;
};
// A custom expression template that defines lazy + and - operators that
// produce expressions, and an eager [] operator that returns the nth element
// of the expression.
//[ lazy_vector_decl
template<boost::yap::expr_kind Kind, typename Tuple>
struct lazy_vector_expr
{
static const boost::yap::expr_kind kind = Kind;
Tuple elements;
// Note that this does not return an expression; it is greedily evaluated.
auto operator[](std::size_t n) const;
};
BOOST_YAP_USER_BINARY_OPERATOR(plus, lazy_vector_expr, lazy_vector_expr)
BOOST_YAP_USER_BINARY_OPERATOR(minus, lazy_vector_expr, lazy_vector_expr)
//]
template<boost::yap::expr_kind Kind, typename Tuple>
auto lazy_vector_expr<Kind, Tuple>::operator[](std::size_t n) const
{
return boost::yap::evaluate(boost::yap::transform(*this, take_nth{n}));
}
boost::yap::terminal<lazy_vector_expr, double> take_nth::operator()(
boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr)
{
double x = boost::yap::value(expr)[n];
// This move is something of a hack. The move indicates that the terminal
// should keep the value of x (since, being an rvalue, it may be a
// temporary), rather than a reference to x. See the "How Expression
// Operands Are Treated" section of the tutorial for details.
return boost::yap::make_terminal<lazy_vector_expr, double>(std::move(x));
}
// In order to define the += operator with the semantics we want, it's
// convenient to derive a terminal type from a terminal instantiation of
// lazy_vector_expr. note that we could have written a template
// specialization here instead -- either one would work. That would of course
// have required more typing.
struct lazy_vector : lazy_vector_expr<
boost::yap::expr_kind::terminal,
boost::hana::tuple<std::vector<double>>>
{
lazy_vector() {}
explicit lazy_vector(std::vector<double> && vec)
{
elements = boost::hana::tuple<std::vector<double>>(std::move(vec));
}
template<boost::yap::expr_kind Kind, typename Tuple>
lazy_vector & operator+=(lazy_vector_expr<Kind, Tuple> const & rhs)
{
std::vector<double> & this_vec = boost::yap::value(*this);
for (int i = 0, size = (int)this_vec.size(); i < size; ++i) {
this_vec[i] += rhs[i];
}
return *this;
}
};
lazy_vector v1{std::vector<double>(4, 1.0)};
lazy_vector v2{std::vector<double>(4, 2.0)};
lazy_vector v3{std::vector<double>(4, 3.0)};
double get_d1_with_yap()
{
double retval = (v2 + v3)[2];
return retval;
}
double get_d1_by_hand()
{
std::vector<double> & v2_ref = boost::yap::value(v2);
std::vector<double> & v3_ref = boost::yap::value(v3);
double retval = v2_ref[2] + v3_ref[2];
return retval;
}
void update_v1_with_yap() { v1 += v2 - v3; }
void update_v1_by_hand()
{
std::vector<double> & v1_ref = boost::yap::value(v1);
std::vector<double> & v2_ref = boost::yap::value(v2);
std::vector<double> & v3_ref = boost::yap::value(v3);
for (int i = 0, size = (int)v1_ref.size(); i < size; ++i) {
v1_ref[i] += v2_ref[i] - v3_ref[i];
}
}
int main()
{
double d1_1 = get_d1_with_yap();
std::cout << d1_1 << "\n";
double d1_2 = get_d1_by_hand();
std::cout << d1_2 << "\n";
update_v1_with_yap();
std::cout << '{' << v1[0] << ',' << v1[1] << ',' << v1[2] << ',' << v1[3]
<< '}' << "\n";
boost::yap::value(v1) = std::vector<double>(4, 1.0);
update_v1_by_hand();
std::cout << '{' << v1[0] << ',' << v1[1] << ',' << v1[2] << ',' << v1[3]
<< '}' << "\n";
// This expression is disallowed because it does not conform to the
// implicit grammar. operator+= is only defined on terminals, not
// arbitrary expressions.
// (v2 + v3) += v1;
return 0;
}
//]

View File

@@ -0,0 +1,149 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>
#include <boost/assign/list_of.hpp>
#include <map>
#include <iostream>
template<typename Key, typename Value, typename Allocator>
struct map_list_of_transform
{
template<typename Fn, typename Key2, typename Value2>
auto operator()(
boost::yap::expr_tag<boost::yap::expr_kind::call>,
Fn const & fn,
Key2 && key,
Value2 && value)
{
boost::yap::transform(
boost::yap::as_expr<boost::yap::minimal_expr>(fn), *this);
map.emplace(
Key{std::forward<Key2 &&>(key)},
Value{std::forward<Value2 &&>(value)});
return 0;
}
std::map<Key, Value, Allocator> map;
};
template<boost::yap::expr_kind Kind, typename Tuple>
struct map_list_of_expr
{
static boost::yap::expr_kind const kind = Kind;
Tuple elements;
template<typename Key, typename Value, typename Allocator>
operator std::map<Key, Value, Allocator>() const
{
map_list_of_transform<Key, Value, Allocator> transform;
boost::yap::transform(*this, transform);
return transform.map;
}
BOOST_YAP_USER_CALL_OPERATOR(::map_list_of_expr)
};
struct map_list_of_tag
{};
auto map_list_of =
boost::yap::make_terminal<map_list_of_expr>(map_list_of_tag{});
#if __GNUC__ || __clang__
#define NOINLINE __attribute__((noinline))
#else
#define NOINLINE
#endif
NOINLINE std::map<std::string, int> make_map_with_boost_yap()
{
return map_list_of("<", 1)("<=", 2)(">", 3)(">=", 4)("=", 5)("<>", 6);
}
NOINLINE std::map<std::string, int> make_map_with_boost_assign()
{
return boost::assign::map_list_of("<", 1)("<=", 2)(">", 3)(">=", 4)("=", 5)(
"<>", 6);
}
NOINLINE std::map<std::string, int> make_map_manually()
{
std::map<std::string, int> retval;
retval.emplace("<", 1);
retval.emplace("<=", 2);
retval.emplace(">", 3);
retval.emplace(">=", 4);
retval.emplace("=", 5);
retval.emplace("<>", 6);
return retval;
}
NOINLINE std::map<std::string, int> make_map_inializer_list()
{
std::map<std::string, int> retval = {
{"<", 1}, {"<=", 2}, {">", 3}, {">=", 4}, {"=", 5}, {"<>", 6}};
return retval;
}
int main()
{
{
std::map<std::string, int> op = make_map_with_boost_yap();
std::cout << "\"<\" --> " << op["<"] << std::endl;
std::cout << "\"<=\" --> " << op["<="] << std::endl;
std::cout << "\">\" --> " << op[">"] << std::endl;
std::cout << "\">=\" --> " << op[">="] << std::endl;
std::cout << "\"=\" --> " << op["="] << std::endl;
std::cout << "\"<>\" --> " << op["<>"] << std::endl;
}
{
std::map<std::string, int> op = make_map_with_boost_assign();
std::cout << "\"<\" --> " << op["<"] << std::endl;
std::cout << "\"<=\" --> " << op["<="] << std::endl;
std::cout << "\">\" --> " << op[">"] << std::endl;
std::cout << "\">=\" --> " << op[">="] << std::endl;
std::cout << "\"=\" --> " << op["="] << std::endl;
std::cout << "\"<>\" --> " << op["<>"] << std::endl;
}
{
std::map<std::string, int> op = make_map_manually();
std::cout << "\"<\" --> " << op["<"] << std::endl;
std::cout << "\"<=\" --> " << op["<="] << std::endl;
std::cout << "\">\" --> " << op[">"] << std::endl;
std::cout << "\">=\" --> " << op[">="] << std::endl;
std::cout << "\"=\" --> " << op["="] << std::endl;
std::cout << "\"<>\" --> " << op["<>"] << std::endl;
}
{
std::map<std::string, int> op = make_map_inializer_list();
std::cout << "\"<\" --> " << op["<"] << std::endl;
std::cout << "\"<=\" --> " << op["<="] << std::endl;
std::cout << "\">\" --> " << op[">"] << std::endl;
std::cout << "\">=\" --> " << op[">="] << std::endl;
std::cout << "\"=\" --> " << op["="] << std::endl;
std::cout << "\"<>\" --> " << op["<>"] << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,162 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>
#include <boost/assign/list_of.hpp>
#include <map>
#include <iostream>
#include <benchmark/benchmark.h>
template<typename Key, typename Value, typename Allocator>
struct map_list_of_transform
{
template<typename Fn, typename Key2, typename Value2>
auto operator()(
boost::yap::expr_tag<boost::yap::expr_kind::call>,
Fn const & fn,
Key2 && key,
Value2 && value)
{
boost::yap::transform(
boost::yap::as_expr<boost::yap::minimal_expr>(fn), *this);
map.emplace(
Key{std::forward<Key2 &&>(key)},
Value{std::forward<Value2 &&>(value)});
return 0;
}
std::map<Key, Value, Allocator> map;
};
template<boost::yap::expr_kind Kind, typename Tuple>
struct map_list_of_expr
{
static boost::yap::expr_kind const kind = Kind;
Tuple elements;
template<typename Key, typename Value, typename Allocator>
operator std::map<Key, Value, Allocator>() const
{
map_list_of_transform<Key, Value, Allocator> transform;
boost::yap::transform(*this, transform);
return transform.map;
}
BOOST_YAP_USER_CALL_OPERATOR(::map_list_of_expr)
};
struct map_list_of_tag
{};
auto map_list_of =
boost::yap::make_terminal<map_list_of_expr>(map_list_of_tag{});
std::map<std::string, int> make_map_with_boost_yap()
{
return map_list_of("<", 1)("<=", 2)(">", 3)(">=", 4)("=", 5)("<>", 6);
}
void BM_make_map_with_boost_yap(benchmark::State & state)
{
int i = 0;
while (state.KeepRunning()) {
{
std::map<std::string, int> map = make_map_with_boost_yap();
state.PauseTiming();
for (auto && x : map) {
i += x.second;
}
}
state.ResumeTiming();
}
std::cout << "Sum of ints in all maps made=" << i << "\n";
}
std::map<std::string, int> make_map_with_boost_assign()
{
return boost::assign::map_list_of("<", 1)("<=", 2)(">", 3)(">=", 4)("=", 5)(
"<>", 6);
}
void BM_make_map_with_boost_assign(benchmark::State & state)
{
int i = 0;
while (state.KeepRunning()) {
{
std::map<std::string, int> map = make_map_with_boost_assign();
state.PauseTiming();
for (auto && x : map) {
i += x.second;
}
}
state.ResumeTiming();
}
std::cout << "Sum of ints in all maps made=" << i << "\n";
}
std::map<std::string, int> make_map_manually()
{
std::map<std::string, int> retval;
retval.emplace("<", 1);
retval.emplace("<=", 2);
retval.emplace(">", 3);
retval.emplace(">=", 4);
retval.emplace("=", 5);
retval.emplace("<>", 6);
return retval;
}
void BM_make_map_manually(benchmark::State & state)
{
int i = 0;
while (state.KeepRunning()) {
{
std::map<std::string, int> map = make_map_manually();
state.PauseTiming();
for (auto && x : map) {
i += x.second;
}
}
state.ResumeTiming();
}
std::cout << "Sum of ints in all maps made=" << i << "\n";
}
std::map<std::string, int> make_map_inializer_list()
{
std::map<std::string, int> retval = {
{"<", 1}, {"<=", 2}, {">", 3}, {">=", 4}, {"=", 5}, {"<>", 6}};
return retval;
}
void BM_make_map_inializer_list(benchmark::State & state)
{
int i = 0;
while (state.KeepRunning()) {
{
std::map<std::string, int> map = make_map_inializer_list();
state.PauseTiming();
for (auto && x : map) {
i += x.second;
}
}
state.ResumeTiming();
}
std::cout << "Sum of ints in all maps made=" << i << "\n";
}
BENCHMARK(BM_make_map_with_boost_yap);
BENCHMARK(BM_make_map_with_boost_assign);
BENCHMARK(BM_make_map_manually);
BENCHMARK(BM_make_map_inializer_list);
BENCHMARK_MAIN();