From 39cbd6578fbf3a98d8a213c8ec3f5147557d065e Mon Sep 17 00:00:00 2001 From: Sebastien Boisvert Date: Thu, 11 Jun 2020 23:43:25 +0000 Subject: Fix #1911: add benchmark for move semantics with fixed-size matrix $ clang++ -O3 bench/bench_move_semantics.cpp -I. -std=c++11 \ -o bench_move_semantics $ ./bench_move_semantics float copy semantics: 1755.97 ms float move semantics: 55.063 ms double copy semantics: 2457.65 ms double move semantics: 55.034 ms --- Eigen/src/Core/DenseStorage.h | 12 +++++++++ bench/bench_move_semantics.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ test/MovableScalar.h | 35 ++++++++++++++++++++++++++ test/rvalue_types.cpp | 39 +++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 bench/bench_move_semantics.cpp create mode 100644 test/MovableScalar.h diff --git a/Eigen/src/Core/DenseStorage.h b/Eigen/src/Core/DenseStorage.h index a8bb8a624..6966513b3 100644 --- a/Eigen/src/Core/DenseStorage.h +++ b/Eigen/src/Core/DenseStorage.h @@ -200,6 +200,18 @@ template class DenseSt if (this != &other) m_data = other.m_data; return *this; } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + { + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + if (this != &other) + m_data = std::move(other.m_data); + return *this; + } +#endif EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); diff --git a/bench/bench_move_semantics.cpp b/bench/bench_move_semantics.cpp new file mode 100644 index 000000000..323d80417 --- /dev/null +++ b/bench/bench_move_semantics.cpp @@ -0,0 +1,57 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2020 Sebastien Boisvert +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "BenchTimer.h" +#include "../test/MovableScalar.h" + +#include + +#include +#include + +template +void copy_matrix(MatrixType& m) +{ + MatrixType tmp(m); + m = tmp; +} + +template +void move_matrix(MatrixType&& m) +{ + MatrixType tmp(std::move(m)); + m = std::move(tmp); +} + +template +void bench(const std::string& label) +{ + using MatrixType = Eigen::Matrix,1,10>; + Eigen::BenchTimer t; + + int tries = 10; + int rep = 1000000; + + MatrixType data = MatrixType::Random().eval(); + MatrixType dest; + + BENCH(t, tries, rep, copy_matrix(data)); + std::cout << label << " copy semantics: " << 1e3*t.best(Eigen::CPU_TIMER) << " ms" << std::endl; + + BENCH(t, tries, rep, move_matrix(std::move(data))); + std::cout << label << " move semantics: " << 1e3*t.best(Eigen::CPU_TIMER) << " ms" << std::endl; +} + +int main() +{ + bench("float"); + bench("double"); + return 0; +} + diff --git a/test/MovableScalar.h b/test/MovableScalar.h new file mode 100644 index 000000000..6a90d037a --- /dev/null +++ b/test/MovableScalar.h @@ -0,0 +1,35 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2020 Sebastien Boisvert +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MISC_MOVABLE_SCALAR_H +#define EIGEN_MISC_MOVABLE_SCALAR_H + +#include + +namespace Eigen +{ +template > +struct MovableScalar : public Base +{ + MovableScalar() = default; + ~MovableScalar() = default; + MovableScalar(const MovableScalar&) = default; + MovableScalar(MovableScalar&& other) = default; + MovableScalar& operator=(const MovableScalar&) = default; + MovableScalar& operator=(MovableScalar&& other) = default; + MovableScalar(Scalar scalar) : Base(100, scalar) {} + + operator Scalar() const { return this->size() > 0 ? this->back() : Scalar(); } +}; + +template<> struct NumTraits> : GenericNumTraits {}; +} + +#endif + diff --git a/test/rvalue_types.cpp b/test/rvalue_types.cpp index 1e1f8560a..2eef47d1f 100644 --- a/test/rvalue_types.cpp +++ b/test/rvalue_types.cpp @@ -10,6 +10,9 @@ #define EIGEN_RUNTIME_NO_MALLOC #include "main.h" +#if EIGEN_HAS_CXX11 +#include "MovableScalar.h" +#endif #include @@ -75,11 +78,43 @@ void rvalue_transpositions(Index rows) Eigen::internal::set_is_malloc_allowed(true); } + +template +void rvalue_move(const MatrixType& m) +{ + // lvalue reference is copied + MatrixType b(m); + VERIFY_IS_EQUAL(b, m); + + // lvalue reference is copied + MatrixType c{m}; + VERIFY_IS_EQUAL(c, m); + + // lvalue reference is copied + MatrixType d = m; + VERIFY_IS_EQUAL(d, m); + + // rvalue reference is moved + MatrixType e_src(m); + VERIFY_IS_EQUAL(e_src, m); + MatrixType e_dst(std::move(e_src)); + VERIFY_IS_EQUAL(e_src, MatrixType()); + VERIFY_IS_EQUAL(e_dst, m); + + // rvalue reference is moved + MatrixType f_src(m); + VERIFY_IS_EQUAL(f_src, m); + MatrixType f_dst = std::move(f_src); + VERIFY_IS_EQUAL(f_src, MatrixType()); + VERIFY_IS_EQUAL(f_dst, m); +} #else template void rvalue_copyassign(const MatrixType&) {} template void rvalue_transpositions(Index) {} +template +void rvalue_move(const MatrixType&) {} #endif EIGEN_DECLARE_TEST(rvalue_types) @@ -106,5 +141,9 @@ EIGEN_DECLARE_TEST(rvalue_types) CALL_SUBTEST_3((rvalue_transpositions >(internal::random(1,EIGEN_TEST_MAX_SIZE)))); CALL_SUBTEST_4((rvalue_transpositions >(internal::random(1,EIGEN_TEST_MAX_SIZE)))); CALL_SUBTEST_4((rvalue_transpositions >(internal::random(1,EIGEN_TEST_MAX_SIZE)))); + +#if EIGEN_HAS_CXX11 + CALL_SUBTEST_5(rvalue_move(Eigen::Matrix,1,3>::Random().eval())); +#endif } } -- cgit v1.2.3