├── environment.yml ├── .gitignore ├── modules ├── copyGBenchmark.cmake.in ├── downloadGBenchmark.cmake.in ├── FindBlitz.cmake ├── FindPythran.cmake └── FindNumpy.cmake ├── LICENSE ├── README.md ├── src ├── main.cpp ├── benchmark_broadcasting.hpp ├── benchmark_fixed.hpp ├── benchmark_scalar_assignment.hpp ├── benchmark_iterators.hpp ├── benchmark_add_1d.hpp ├── benchmark_add_2d.hpp ├── benchmark_constructor.hpp └── benchmark_views.hpp ├── bench_over_time.py ├── exploration.ipynb └── CMakeLists.txt /environment.yml: -------------------------------------------------------------------------------- 1 | name: xtensor-benchmark 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - eigen 7 | - armadillo 8 | - xsimd 9 | - xtensor 10 | - xtl 11 | - cmake 12 | - gmp 13 | - numpy 14 | - python 15 | - pip: 16 | - pythran 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | # Prerequisites 4 | *.d 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | *.smod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app -------------------------------------------------------------------------------- /modules/copyGBenchmark.cmake.in: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 2.8.2) 11 | 12 | project(googlebenchmark-download NONE) 13 | 14 | include(ExternalProject) 15 | ExternalProject_Add(benchmark 16 | URL "${googlebenchmark_SRC_DIR}" 17 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src" 18 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build" 19 | CONFIGURE_COMMAND "" 20 | BUILD_COMMAND "" 21 | INSTALL_COMMAND "" 22 | TEST_COMMAND "" 23 | ) 24 | -------------------------------------------------------------------------------- /modules/downloadGBenchmark.cmake.in: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 2.8.2) 11 | 12 | project(googlebenchmark-download NONE) 13 | 14 | include(ExternalProject) 15 | ExternalProject_Add(googlebenchmark 16 | GIT_REPOSITORY https://github.com/google/benchmark.git 17 | GIT_TAG v1.3.0 18 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src" 19 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build" 20 | CONFIGURE_COMMAND "" 21 | BUILD_COMMAND "" 22 | INSTALL_COMMAND "" 23 | TEST_COMMAND "" 24 | ) 25 | -------------------------------------------------------------------------------- /modules/FindBlitz.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find blitz lib 2 | # Once done this will define 3 | # 4 | # BLITZ_FOUND - system has blitz lib 5 | # BLITZ_INCLUDES - the blitz include directory 6 | # BLITZ_LIBRARIES - The libraries needed to use blitz 7 | 8 | # Copyright (c) 2006, Montel Laurent, 9 | # Copyright (c) 2007, Allen Winter, 10 | # Copyright (C) 2008 Gael Guennebaud 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | # include(FindLibraryWithDebug) 15 | 16 | if (BLITZ_INCLUDES AND BLITZ_LIBRARIES) 17 | set(Blitz_FIND_QUIETLY TRUE) 18 | endif (BLITZ_INCLUDES AND BLITZ_LIBRARIES) 19 | 20 | find_path(BLITZ_INCLUDES 21 | NAMES 22 | blitz/array.h 23 | PATH_SUFFIXES blitz* 24 | PATHS 25 | $ENV{BLITZDIR}/include 26 | ${INCLUDE_INSTALL_DIR} 27 | ) 28 | 29 | find_library(BLITZ_LIBRARIES 30 | blitz 31 | PATHS 32 | $ENV{BLITZDIR}/lib 33 | ${LIB_INSTALL_DIR} 34 | ) 35 | 36 | include(FindPackageHandleStandardArgs) 37 | find_package_handle_standard_args(Blitz DEFAULT_MSG 38 | BLITZ_INCLUDES BLITZ_LIBRARIES) 39 | 40 | mark_as_advanced(BLITZ_INCLUDES BLITZ_LIBRARIES) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht 2 | Copyright (c) 2016, QuantStack 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks for linear algebra frameworks 2 | 3 | This benchmarking suite allows a direct comparison of popular linear algebra frameworks in C++. 4 | The libraries are easy-to-install using the conda package manager: 5 | 6 | ``` 7 | conda env create -f environment.yml 8 | ``` 9 | 10 | The environment.yml installs the following libraries: 11 | 12 | - xtensor with xsimd 13 | - Eigen3 14 | - Armadillo 15 | - Blitz++ 16 | 17 | After setting up the environment, it is advised to create a `build` directory, and execute `cmake`: 18 | 19 | ``` 20 | mkdir build 21 | cd build 22 | cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DBENCHMARK_ALL=ON 23 | ``` 24 | 25 | You should see a message for each found library, similar to the following: 26 | 27 | ``` 28 | COMPILING WITH 29 | ====================================== 30 | 31 | 32 | Found eigen : /home/myuser/miniconda3/envs/bench/include/eigen3 33 | Found Blitz : /home/myuser/miniconda3/envs/bench/include | /home/myuser/miniconda3/envs/bench/lib/libblitz.so 34 | Found Armadillo : /home/myuser/miniconda3/envs/bench/include | /home/myuser/miniconda3/envs/bench/lib/libarmadillo.so 35 | Found xtensor : /home/myuser/miniconda3/envs/bench/include 36 | Found xsimd : /home/myuser/miniconda3/envs/bench/include 37 | ``` 38 | 39 | This allows you to make sure you're compiling with the correct, up-to-date versions of the libraries. 40 | 41 | To build and run the benchmarks, just use the following command: 42 | 43 | ``` 44 | make xbenchmark 45 | ``` 46 | 47 | If you are only interested in specific benchmarks, build with `make xtensor_benchmark` and then run manually `./xtensor_benchmark --benchmark_filter=my_benchmark`. The backend to the benchmarks is the popular google-benchmark suite, so look there for more documentation. 48 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "benchmark_add_1d.hpp" 15 | #include "benchmark_add_2d.hpp" 16 | #include "benchmark_views.hpp" 17 | #include "benchmark_broadcasting.hpp" 18 | #include "benchmark_fixed.hpp" 19 | #include "benchmark_constructor.hpp" 20 | #include "benchmark_scalar_assignment.hpp" 21 | #include "benchmark_iterators.hpp" 22 | 23 | 24 | #ifdef XTENSOR_USE_XSIMD 25 | #ifdef __GNUC__ 26 | template 27 | void print_type(T&& /*t*/) 28 | { 29 | std::cout << __PRETTY_FUNCTION__ << std::endl; 30 | } 31 | #endif 32 | void print_stats() 33 | { 34 | std::cout << "USING XSIMD\nSIMD SIZE: " << xsimd::simd_traits::size << "\n\n"; 35 | #ifdef __GNUC__ 36 | print_type(xt::xarray()); 37 | print_type(xt::xtensor()); 38 | #endif 39 | } 40 | #else 41 | void print_stats() 42 | { 43 | std::cout << "NOT USING XSIMD\n\n"; 44 | }; 45 | #endif 46 | 47 | // Custom main function to print SIMD config 48 | int main(int argc, char** argv) 49 | { 50 | print_stats(); 51 | benchmark::Initialize(&argc, argv); 52 | if (benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; 53 | benchmark::RunSpecifiedBenchmarks(); 54 | } 55 | -------------------------------------------------------------------------------- /src/benchmark_broadcasting.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_PYTHONIC 21 | #include 22 | #include 23 | #include 24 | #include 25 | #endif 26 | 27 | #define SZ 100 28 | #define RANGE 3, 1000 29 | #define MULTIPLIER 8 30 | 31 | #ifdef HAS_XTENSOR 32 | void Add3d2dBroadcasting_XTensor(benchmark::State& state) 33 | { 34 | using namespace xt; 35 | 36 | xtensor a = random::rand({state.range(0), state.range(0), state.range(0)}); 37 | xtensor b = random::rand({state.range(0), state.range(0)}); 38 | 39 | for (auto _ : state) 40 | { 41 | xtensor res(a + b); 42 | benchmark::DoNotOptimize(res.data()); 43 | } 44 | } 45 | BENCHMARK(Add3d2dBroadcasting_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 46 | #endif 47 | 48 | #ifdef HAS_PYTHONIC 49 | void pythonic_broadcasting(benchmark::State& state) 50 | { 51 | auto x = pythonic::numpy::random::rand(state.range(0), state.range(0), state.range(0)); 52 | auto y = pythonic::numpy::random::rand(state.range(0), state.range(0)); 53 | 54 | for (auto _ : state) 55 | { 56 | pythonic::types::ndarray z = x + y; 57 | benchmark::DoNotOptimize(z.fbegin()); 58 | } 59 | } 60 | BENCHMARK(pythonic_broadcasting)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 61 | #endif 62 | 63 | #undef SZ 64 | #undef RANGE 65 | #undef MULTIPLIER 66 | -------------------------------------------------------------------------------- /src/benchmark_fixed.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xfixed.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef HAS_XTENSOR 26 | template 27 | void Add2dFixed_XTensor(benchmark::State& state) 28 | { 29 | using namespace xt; 30 | 31 | xtensor_fixed> a = random::rand({N, M}); 32 | xtensor_fixed> b = random::rand({N, M}); 33 | 34 | for (auto _ : state) 35 | { 36 | xtensor_fixed> res; 37 | xt::noalias(res) = a + b; 38 | benchmark::DoNotOptimize(res.data()); 39 | } 40 | } 41 | BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 3, 3); 42 | BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 8, 8); 43 | BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 64, 64); 44 | BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 512, 512); 45 | #endif 46 | 47 | #ifdef HAS_EIGEN 48 | template 49 | void Add2dFixed_Eigen(benchmark::State& state) 50 | { 51 | using namespace Eigen; 52 | Matrix a = Matrix::Random(N, M); 53 | Matrix b = Matrix::Random(N, M); 54 | 55 | for (auto _ : state) 56 | { 57 | Matrix res; 58 | res.noalias() = a + b; 59 | benchmark::DoNotOptimize(res.data()); 60 | } 61 | } 62 | BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 3, 3); 63 | BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 8, 8); 64 | BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 64, 64); 65 | #endif 66 | -------------------------------------------------------------------------------- /src/benchmark_scalar_assignment.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef HAS_BLITZ 26 | #include 27 | #endif 28 | 29 | #define RANGE 3, 1000 30 | #define MULTIPLIER 8 31 | 32 | 33 | #ifdef HAS_XTENSOR 34 | void AssignScalar2D_XTensor(benchmark::State& state) 35 | { 36 | xt::xtensor vTensor({state.range(0), state.range(0)}); 37 | double value = 0.0; 38 | for (auto _ : state) 39 | { 40 | vTensor.fill(value); 41 | value += 1.0; 42 | benchmark::DoNotOptimize(vTensor.data()); 43 | } 44 | } 45 | BENCHMARK(AssignScalar2D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 46 | #endif 47 | 48 | #ifdef HAS_EIGEN 49 | void AssignScalar2D_Eigen(benchmark::State& state) 50 | { 51 | using namespace Eigen; 52 | MatrixXd vMatrix(state.range(0), state.range(0)); 53 | double value = 0.0; 54 | for (auto _ : state) 55 | { 56 | vMatrix.fill(value); 57 | value += 1.0; 58 | benchmark::DoNotOptimize(vMatrix); 59 | } 60 | } 61 | BENCHMARK(AssignScalar2D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 62 | #endif 63 | 64 | #ifdef HAS_BLITZ 65 | void AssignScalar2D_Blitz(benchmark::State& state) 66 | { 67 | using namespace blitz; 68 | Array vArray(state.range(0), state.range(0)); 69 | double value = 0.0; 70 | for (auto _ : state) 71 | { 72 | vArray = value; 73 | value += 1.0; 74 | benchmark::DoNotOptimize(vArray); 75 | } 76 | } 77 | BENCHMARK(AssignScalar2D_Blitz)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 78 | #endif 79 | 80 | #undef RANGE 81 | #undef MULTIPLIER 82 | 83 | -------------------------------------------------------------------------------- /src/benchmark_iterators.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef HAS_BLITZ 26 | #include 27 | #endif 28 | 29 | #define RANGE 3, 1000 30 | #define MULTIPLIER 8 31 | 32 | 33 | #ifdef HAS_XTENSOR 34 | void IterateWhole2D_XTensor(benchmark::State& state) 35 | { 36 | xt::xtensor vTensor({state.range(0), state.range(0)}); 37 | for (auto _ : state) 38 | { 39 | double vTmp = 0.0; 40 | for (auto it = vTensor.begin(); it != vTensor.end(); ++it) { 41 | vTmp += *it; 42 | } 43 | benchmark::DoNotOptimize(vTmp); 44 | } 45 | } 46 | BENCHMARK(IterateWhole2D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 47 | #endif 48 | 49 | //#ifdef HAS_EIGEN 50 | //void IterateWhole2D_Eigen(benchmark::State& state) 51 | //{ 52 | // using namespace Eigen; 53 | // MatrixXd vMatrix(state.range(0), state.range(0)); 54 | // for (auto _ : state) 55 | // { 56 | // double vTmp = 0.0; 57 | // for (auto it = vMatrix.begin(); it != vMatrix.end(); ++it) { 58 | // vTmp += *it; 59 | // } 60 | // benchmark::DoNotOptimize(vTmp); 61 | // } 62 | //} 63 | //BENCHMARK(IterateWhole2D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 64 | //#endif 65 | 66 | #ifdef HAS_BLITZ 67 | void IterateWhole2D_Blitz(benchmark::State& state) 68 | { 69 | using namespace blitz; 70 | Array vArray(state.range(0), state.range(0)); 71 | for (auto _ : state) 72 | { 73 | double vTmp = 0.0; 74 | for (auto it = vArray.begin(); it != vArray.end(); ++it) { 75 | vTmp += *it; 76 | } 77 | benchmark::DoNotOptimize(vTmp); 78 | } 79 | } 80 | BENCHMARK(IterateWhole2D_Blitz)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 81 | #endif 82 | 83 | #undef RANGE 84 | #undef MULTIPLIER 85 | 86 | -------------------------------------------------------------------------------- /modules/FindPythran.cmake: -------------------------------------------------------------------------------- 1 | # - Find the Pythran's Pythonic libraries 2 | # This module finds if Pythran is installed, and sets the following variables 3 | # indicating where it is. 4 | # 5 | # Pythran_FOUND - was Pythran found 6 | # Pythran_VERSION - the version of Pythran found as a string 7 | # Pythran_VERSION_MAJOR - the major version number of Pythran 8 | # Pythran_VERSION_MINOR - the minor version number of Pythran 9 | # Pythran_VERSION_PATCH - the patch version number of Pythran 10 | # Pythran_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 11 | # Pythran_INCLUDE_DIRS - path to the Pythran include files 12 | 13 | # Based on FindNumpy.cmake 14 | # (Copyright 2012 Continuum Analytics, Inc. -- MIT License) 15 | 16 | # Finding Pythran involves calling the Python interpreter 17 | if(Pythran_FIND_REQUIRED) 18 | find_package(PythonInterp REQUIRED) 19 | else() 20 | find_package(PythonInterp) 21 | endif() 22 | 23 | if(NOT PYTHONINTERP_FOUND) 24 | set(Pythran_FOUND FALSE) 25 | endif() 26 | 27 | execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" 28 | "import logging; logging.getLogger('pythran').disabled = True; import inspect; import os; import pythran; print(pythran.__version__); print(os.path.dirname(inspect.getfile(pythran)));" 29 | RESULT_VARIABLE _Pythran_SEARCH_SUCCESS 30 | OUTPUT_VARIABLE _Pythran_VALUES 31 | ERROR_VARIABLE _Pythran_ERROR_VALUE 32 | OUTPUT_STRIP_TRAILING_WHITESPACE) 33 | 34 | if(NOT _Pythran_SEARCH_SUCCESS MATCHES 0) 35 | if(Pythran_FIND_REQUIRED) 36 | message(FATAL_ERROR 37 | "Pythran import failure:\n${_Pythran_ERROR_VALUE}") 38 | endif() 39 | set(Pythran_FOUND FALSE) 40 | endif() 41 | 42 | # Convert the process output into a list 43 | string(REGEX REPLACE ";" "\\\\;" _Pythran_VALUES ${_Pythran_VALUES}) 44 | string(REGEX REPLACE "\n" ";" _Pythran_VALUES ${_Pythran_VALUES}) 45 | list(GET _Pythran_VALUES 0 Pythran_VERSION) 46 | list(GET _Pythran_VALUES 1 Pythran_INCLUDE_DIRS) 47 | 48 | # Make sure all directory separators are '/' 49 | string(REGEX REPLACE "\\\\" "/" Pythran_INCLUDE_DIRS ${Pythran_INCLUDE_DIRS}) 50 | 51 | # Get the major and minor version numbers 52 | string(REGEX REPLACE "\\." ";" _Pythran_VERSION_LIST ${Pythran_VERSION}) 53 | list(GET _Pythran_VERSION_LIST 0 Pythran_VERSION_MAJOR) 54 | list(GET _Pythran_VERSION_LIST 1 Pythran_VERSION_MINOR) 55 | list(GET _Pythran_VERSION_LIST 2 Pythran_VERSION_PATCH) 56 | string(REGEX MATCH "[0-9]*" Pythran_VERSION_PATCH ${Pythran_VERSION_PATCH}) 57 | math(EXPR Pythran_VERSION_DECIMAL 58 | "(${Pythran_VERSION_MAJOR} * 10000) + (${Pythran_VERSION_MINOR} * 100) + ${Pythran_VERSION_PATCH}") 59 | 60 | find_package_message(Pythran 61 | "Found Pythran (Pythonic): version \"${Pythran_VERSION}\" ${Pythran_INCLUDE_DIRS}" 62 | "${Pythran_INCLUDE_DIRS}${Pythran_VERSION}") 63 | 64 | set(Pythran_FOUND TRUE) 65 | -------------------------------------------------------------------------------- /bench_over_time.py: -------------------------------------------------------------------------------- 1 | import subprocess as sp 2 | # import tinydb 3 | import os 4 | import shutil 5 | 6 | absdir = os.path.dirname(os.path.realpath(__file__)) 7 | 8 | CONDA_PREFIX = None 9 | XTENSOR_VERSION = [0, 0, 0] 10 | 11 | def call(arguments): 12 | print(arguments) 13 | os.system(" ".join(arguments)) 14 | 15 | def parse_version(): 16 | global XTENSOR_VERSION 17 | os.chdir(absdir + '/checkouts/xtensor') 18 | with open(absdir + '/checkouts/xtensor/include/xtensor/xtensor_config.hpp') as f: 19 | for line in f.readlines(): 20 | if line.startswith("#define XTENSOR_VERSION_MAJOR"): 21 | XTENSOR_VERSION[0] = int(line.split()[-1]) 22 | if line.startswith("#define XTENSOR_VERSION_MINOR"): 23 | XTENSOR_VERSION[1] = int(line.split()[-1]) 24 | if line.startswith("#define XTENSOR_VERSION_PATCH"): 25 | XTENSOR_VERSION[2] = int(line.split()[-1]) 26 | print(f"Testing against: {XTENSOR_VERSION}") 27 | 28 | def init(): 29 | global CONDA_PREFIX 30 | try: 31 | call(['conda', 'env', 'create']) 32 | except: 33 | pass 34 | try: 35 | shutil.rmtree(absdir + '/stats') 36 | except: 37 | pass 38 | call(['source', 'activate', 'xtensor-benchmark']) 39 | CONDA_PREFIX = os.environ['CONDA_PREFIX'] 40 | print(f"CONDA PREFIX SET TO: {CONDA_PREFIX}") 41 | 42 | def install_xtensor_version(version): 43 | try: 44 | os.mkdir(absdir + '/checkouts') 45 | call(['git', 'clone', 'https://github.com/xtensor-stack/xtensor']) 46 | except: 47 | os.chdir(absdir + '/checkouts/xtensor') 48 | call(['git', 'checkout', 'master']) 49 | call(['git', 'pull']) 50 | call(['git', 'checkout', version]) 51 | 52 | parse_version() 53 | version_string = ".".join([str(el) for el in XTENSOR_VERSION]) 54 | call(['conda', 'install', f'xtensor=={version_string}', '-c conda-forge', '-y']) 55 | 56 | try: 57 | os.mkdir(absdir + '/checkouts/xtensor/build') 58 | except: 59 | pass 60 | 61 | os.chdir(absdir + '/checkouts/xtensor/build') 62 | call(['cmake', '..', '-DCMAKE_INSTALL_LIBDIR=lib', f'-DCMAKE_INSTALL_PREFIX={CONDA_PREFIX}']) 63 | call(['make', 'install']) 64 | 65 | def build_and_bench(version): 66 | try: 67 | os.mkdir(absdir + '/build') 68 | except: 69 | pass 70 | os.chdir(absdir + '/build') 71 | try: 72 | os.mkdir(absdir + '/stats') 73 | except: 74 | pass 75 | call(['cmake', '..', '-DBENCHMARK_EIGEN=ON']) 76 | call(['make', 'xpowerbench']) 77 | os.rename(absdir + '/build/bench.csv', absdir + f'/stats/{version}.csv') 78 | 79 | def run(): 80 | init() 81 | versions = ['master', '0.15.4', '0.14.0'] 82 | for v in versions: 83 | install_xtensor_version(v) 84 | build_and_bench(v) 85 | 86 | if __name__ == '__main__': 87 | run() 88 | -------------------------------------------------------------------------------- /src/benchmark_add_1d.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #ifndef EIGEN_VECTORIZE 24 | static_assert(false, "NOT VECTORIZING"); 25 | #endif 26 | #endif 27 | 28 | #ifdef HAS_BLITZ 29 | #include 30 | #endif 31 | 32 | #ifdef HAS_ARMADILLO 33 | #include 34 | #endif 35 | 36 | #ifdef HAS_PYTHONIC 37 | #include 38 | #include 39 | #include 40 | #include 41 | #endif 42 | 43 | #define RANGE 3, 1000 44 | #define MULTIPLIER 8 45 | 46 | 47 | #ifdef HAS_XTENSOR 48 | void Add1D_XTensor(benchmark::State& state) 49 | { 50 | using namespace xt; 51 | 52 | xtensor a = random::rand({state.range(0)}); 53 | xtensor b = random::rand({state.range(0)}); 54 | 55 | for (auto _ : state) 56 | { 57 | xtensor res(a + b); 58 | benchmark::DoNotOptimize(res.data()); 59 | } 60 | } 61 | BENCHMARK(Add1D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 62 | #endif 63 | 64 | #ifdef HAS_EIGEN 65 | void Add1D_Eigen(benchmark::State& state) 66 | { 67 | using namespace Eigen; 68 | VectorXd a = VectorXd::Random(state.range(0)); 69 | VectorXd b = VectorXd::Random(state.range(0)); 70 | for (auto _ : state) 71 | { 72 | VectorXd res(a + b); 73 | benchmark::DoNotOptimize(res.data()); 74 | } 75 | } 76 | BENCHMARK(Add1D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 77 | #endif 78 | 79 | #ifdef HAS_BLITZ 80 | void Add1D_Blitz(benchmark::State& state) 81 | { 82 | using namespace blitz; 83 | Array a(state.range(0)); 84 | Array b(state.range(0)); 85 | for (auto _ : state) 86 | { 87 | Array res(a + b); 88 | benchmark::DoNotOptimize(res.data()); 89 | } 90 | } 91 | BENCHMARK(Add1D_Blitz)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 92 | #endif 93 | 94 | #ifdef HAS_ARMADILLO 95 | void Add1D_Arma(benchmark::State& state) 96 | { 97 | using namespace arma; 98 | vec a = randu(state.range(0)); 99 | vec b = randu(state.range(0)); 100 | for (auto _ : state) 101 | { 102 | vec res(a + b); 103 | benchmark::DoNotOptimize(res.memptr()); 104 | } 105 | } 106 | BENCHMARK(Add1D_Arma)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 107 | #endif 108 | 109 | #ifdef HAS_PYTHONIC 110 | void Add1D_Pythonic(benchmark::State &state) 111 | { 112 | auto x = pythonic::numpy::random::rand(state.range(0)); 113 | auto y = pythonic::numpy::random::rand(state.range(0)); 114 | 115 | for (auto _ : state) 116 | { 117 | pythonic::types::ndarray z(x + y); 118 | benchmark::DoNotOptimize(z.fbegin()); 119 | } 120 | } 121 | BENCHMARK(Add1D_Pythonic)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 122 | #endif 123 | 124 | #undef RANGE 125 | #undef MULTIPLIER 126 | 127 | -------------------------------------------------------------------------------- /modules/FindNumpy.cmake: -------------------------------------------------------------------------------- 1 | # - Find the NumPy libraries 2 | # This module finds if NumPy is installed, and sets the following variables 3 | # indicating where it is. 4 | # 5 | # TODO: Update to provide the libraries and paths for linking npymath lib. 6 | # 7 | # NUMPY_FOUND - was NumPy found 8 | # NUMPY_VERSION - the version of NumPy found as a string 9 | # NUMPY_VERSION_MAJOR - the major version number of NumPy 10 | # NUMPY_VERSION_MINOR - the minor version number of NumPy 11 | # NUMPY_VERSION_PATCH - the patch version number of NumPy 12 | # NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 13 | # NUMPY_INCLUDE_DIRS - path to the NumPy include files 14 | 15 | #============================================================================ 16 | # Copyright 2012 Continuum Analytics, Inc. 17 | # 18 | # MIT License 19 | # 20 | # Permission is hereby granted, free of charge, to any person obtaining 21 | # a copy of this software and associated documentation files 22 | # (the "Software"), to deal in the Software without restriction, including 23 | # without limitation the rights to use, copy, modify, merge, publish, 24 | # distribute, sublicense, and/or sell copies of the Software, and to permit 25 | # persons to whom the Software is furnished to do so, subject to 26 | # the following conditions: 27 | # 28 | # The above copyright notice and this permission notice shall be included 29 | # in all copies or substantial portions of the Software. 30 | # 31 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 32 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 34 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 35 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 36 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 37 | # OTHER DEALINGS IN THE SOFTWARE. 38 | # 39 | #============================================================================ 40 | 41 | # Finding NumPy involves calling the Python interpreter 42 | if(NumPy_FIND_REQUIRED) 43 | find_package(PythonInterp REQUIRED) 44 | else() 45 | find_package(PythonInterp) 46 | endif() 47 | 48 | if(NOT PYTHONINTERP_FOUND) 49 | set(NUMPY_FOUND FALSE) 50 | endif() 51 | 52 | execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" 53 | "import numpy as n; print(n.__version__); print(n.get_include());" 54 | RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS 55 | OUTPUT_VARIABLE _NUMPY_VALUES 56 | ERROR_VARIABLE _NUMPY_ERROR_VALUE 57 | OUTPUT_STRIP_TRAILING_WHITESPACE) 58 | 59 | if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0) 60 | if(NumPy_FIND_REQUIRED) 61 | message(FATAL_ERROR 62 | "NumPy import failure:\n${_NUMPY_ERROR_VALUE}") 63 | endif() 64 | set(NUMPY_FOUND FALSE) 65 | endif() 66 | 67 | # Convert the process output into a list 68 | string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES}) 69 | string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES}) 70 | list(GET _NUMPY_VALUES 0 NUMPY_VERSION) 71 | list(GET _NUMPY_VALUES 1 NUMPY_INCLUDE_DIRS) 72 | 73 | # Make sure all directory separators are '/' 74 | string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS}) 75 | 76 | # Get the major and minor version numbers 77 | string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION}) 78 | list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR) 79 | list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR) 80 | list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH) 81 | string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH}) 82 | math(EXPR NUMPY_VERSION_DECIMAL 83 | "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") 84 | 85 | find_package_message(NUMPY 86 | "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}" 87 | "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}") 88 | 89 | set(NUMPY_FOUND TRUE) 90 | -------------------------------------------------------------------------------- /exploration.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from matplotlib import pyplot as plt\n", 10 | "import numpy as np" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "import pandas as pd" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "df = pd.read_csv('./stats/0.15.4.csv', skiprows=2)" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "df" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "def plot(prefix, df=df, label='', log=True):\n", 47 | " dt = df[df.name.str.match(f'({prefix}.*)')].real_time.as_matrix()\n", 48 | " xdt = np.arange(dt.shape[0])\n", 49 | " plt.xticks(xdt, [el.split('/')[1] for el in df[df.name.str.match('(xtensor_1D.*)')].name])\n", 50 | " if len(label):\n", 51 | " label = \" \" + label\n", 52 | " if log:\n", 53 | " plt.semilogy(xdt, dt, label=prefix + label)\n", 54 | " else:\n", 55 | " plt.plot(xdt, dt, label=prefix + label)\n", 56 | " plt.legend()\n", 57 | "plot('xtensor_1D')\n", 58 | "plot('xsimd_1D')\n", 59 | "plot('eigen_1D')\n", 60 | "plot('arma_1D')" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "plot('xtensor_2D')\n", 70 | "plot('xsimd_2D')\n", 71 | "plot('eigen_2D')\n", 72 | "plot('arma_2D')" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "df2 = pd.read_csv('./stats/0.15.4.csv', skiprows=2)\n", 82 | "df1 = pd.read_csv('./stats/0.14.0.csv', skiprows=2)" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "plot('xtensor_1D', df1, '0.14.0')\n", 92 | "plot('xtensor_1D', df2, '0.15.2')\n", 93 | "plot('eigen_1D', df2)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "df2 = pd.read_csv('./stats/0.15.4.csv', skiprows=2)\n", 103 | "df1 = pd.read_csv('./stats/0.14.0.csv', skiprows=2)\n", 104 | "df3 = pd.read_csv('./stats/master.csv', skiprows=2)\n", 105 | "log = True\n", 106 | "plot('xtensor_1D', df1, '0.14.0', log)\n", 107 | "plot('xtensor_1D', df2, '0.15.4', log)\n", 108 | "plot('xtensor_1D', df3, 'master', log)\n", 109 | "plot('eigen_1D', df3, '', log)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [] 125 | } 126 | ], 127 | "metadata": { 128 | "kernelspec": { 129 | "display_name": "Python 3", 130 | "language": "python", 131 | "name": "python3" 132 | }, 133 | "language_info": { 134 | "codemirror_mode": { 135 | "name": "ipython", 136 | "version": 3 137 | }, 138 | "file_extension": ".py", 139 | "mimetype": "text/x-python", 140 | "name": "python", 141 | "nbconvert_exporter": "python", 142 | "pygments_lexer": "ipython3", 143 | "version": "3.6.2" 144 | } 145 | }, 146 | "nbformat": 4, 147 | "nbformat_minor": 2 148 | } 149 | -------------------------------------------------------------------------------- /src/benchmark_add_2d.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef HAS_BLITZ 26 | #include 27 | #endif 28 | 29 | #ifdef HAS_ARMADILLO 30 | #include 31 | #endif 32 | 33 | #ifdef HAS_PYTHONIC 34 | #include 35 | #include 36 | #include 37 | #include 38 | #endif 39 | 40 | #define RANGE 3, 1000 41 | #define MULTIPLIER 8 42 | 43 | 44 | #ifdef HAS_XTENSOR 45 | void Add2D_XTensor(benchmark::State& state) 46 | { 47 | using namespace xt; 48 | 49 | xtensor a = random::rand({state.range(0), state.range(0)}); 50 | xtensor b = random::rand({state.range(0), state.range(0)}); 51 | 52 | for (auto _ : state) 53 | { 54 | xtensor res(a + b); 55 | benchmark::DoNotOptimize(res.data()); 56 | } 57 | } 58 | BENCHMARK(Add2D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 59 | #endif 60 | 61 | #ifdef HAS_EIGEN 62 | void Add2D_Eigen(benchmark::State& state) 63 | { 64 | using namespace Eigen; 65 | MatrixXd a = MatrixXd::Random(state.range(0), state.range(0)); 66 | MatrixXd b = MatrixXd::Random(state.range(0), state.range(0)); 67 | for (auto _ : state) 68 | { 69 | MatrixXd res(state.range(0), state.range(0)); 70 | res.noalias() = a + b; 71 | benchmark::DoNotOptimize(res.data()); 72 | } 73 | } 74 | BENCHMARK(Add2D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 75 | #endif 76 | 77 | #ifdef HAS_BLITZ 78 | void Add2D_Blitz(benchmark::State& state) 79 | { 80 | using namespace blitz; 81 | Array a(state.range(0), state.range(0)); 82 | Array b(state.range(0), state.range(0)); 83 | for (auto _ : state) 84 | { 85 | Array res(a + b); 86 | benchmark::DoNotOptimize(res.data()); 87 | } 88 | } 89 | BENCHMARK(Add2D_Blitz)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 90 | #endif 91 | 92 | #ifdef HAS_ARMADILLO 93 | void Add2D_Arma(benchmark::State& state) 94 | { 95 | using namespace arma; 96 | mat a = randu(state.range(0), state.range(0)); 97 | mat b = randu(state.range(0), state.range(0)); 98 | for (auto _ : state) 99 | { 100 | mat res = a + b; 101 | benchmark::DoNotOptimize(res.memptr()); 102 | } 103 | } 104 | BENCHMARK(Add2D_Arma)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 105 | #endif 106 | 107 | #ifdef HAS_PYTHONIC 108 | void Add2D_Pythonic(benchmark::State& state) 109 | { 110 | auto x = pythonic::numpy::random::rand(state.range(0), state.range(0)); 111 | auto y = pythonic::numpy::random::rand(state.range(0), state.range(0)); 112 | 113 | for (auto _ : state) 114 | { 115 | pythonic::types::ndarray z = x + y; 116 | benchmark::DoNotOptimize(z.fbegin()); 117 | } 118 | } 119 | BENCHMARK(Add2D_Pythonic)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 120 | #endif 121 | 122 | #undef RANGE 123 | #undef MULTIPLIER 124 | 125 | -------------------------------------------------------------------------------- /src/benchmark_constructor.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #endif 19 | 20 | #ifdef HAS_EIGEN 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef HAS_BLITZ 26 | #include 27 | #endif 28 | 29 | #define RANGE 3, 1000 30 | #define MULTIPLIER 8 31 | 32 | #ifdef HAS_XTENSOR 33 | void Construct2D_XTensor(benchmark::State& state) 34 | { 35 | for (auto _ : state) 36 | { 37 | xt::xtensor vTensor({state.range(0), state.range(0)}); 38 | benchmark::DoNotOptimize(vTensor); 39 | } 40 | } 41 | BENCHMARK(Construct2D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 42 | #endif 43 | 44 | #ifdef HAS_EIGEN 45 | void Construct2D_Eigen(benchmark::State& state) 46 | { 47 | using namespace Eigen; 48 | for (auto _ : state) 49 | { 50 | MatrixXd vMatrix(state.range(0), state.range(0)); 51 | benchmark::DoNotOptimize(vMatrix); 52 | } 53 | } 54 | BENCHMARK(Construct2D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 55 | #endif 56 | 57 | #ifdef HAS_BLITZ 58 | void Construct2D_Blitz(benchmark::State& state) 59 | { 60 | using namespace blitz; 61 | for (auto _ : state) 62 | { 63 | Array vArray(state.range(0), state.range(0)); 64 | benchmark::DoNotOptimize(vArray); 65 | } 66 | } 67 | BENCHMARK(Construct2D_Blitz)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 68 | #endif 69 | 70 | #ifdef HAS_XTENSOR 71 | void ConstructRandom2D_XTensor(benchmark::State& state) 72 | { 73 | for (auto _ : state) 74 | { 75 | xt::xtensor vTensor = xt::random::rand({state.range(0), state.range(0)}); 76 | benchmark::DoNotOptimize(vTensor); 77 | } 78 | } 79 | BENCHMARK(ConstructRandom2D_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 80 | #endif 81 | 82 | #ifdef HAS_EIGEN 83 | void ConstructRandom2D_Eigen(benchmark::State& state) 84 | { 85 | using namespace Eigen; 86 | for (auto _ : state) 87 | { 88 | MatrixXd vMatrix = MatrixXd::Random(state.range(0), state.range(0)); 89 | benchmark::DoNotOptimize(vMatrix); 90 | } 91 | } 92 | BENCHMARK(ConstructRandom2D_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 93 | #endif 94 | 95 | 96 | #ifdef HAS_XTENSOR 97 | void ConstructView2d_XTensor(benchmark::State& state) 98 | { 99 | using namespace xt; 100 | 101 | xtensor vA = random::rand({state.range(0), state.range(0)}); 102 | 103 | for (auto _ : state) 104 | { 105 | auto vAView = xt::view(vA, all(), all()); 106 | benchmark::DoNotOptimize(vAView); 107 | } 108 | } 109 | BENCHMARK(ConstructView2d_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 110 | #endif 111 | 112 | #ifdef HAS_EIGEN 113 | void ConstructView2d_Eigen(benchmark::State& state) 114 | { 115 | using namespace Eigen; 116 | MatrixXd vA = MatrixXd::Random(state.range(0), state.range(0)); 117 | 118 | for (auto _ : state) 119 | { 120 | auto vAView = vA.topLeftCorner(state.range(0), state.range(0)); 121 | benchmark::DoNotOptimize(vAView); 122 | } 123 | } 124 | BENCHMARK(ConstructView2d_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 125 | #endif 126 | 127 | #undef RANGE 128 | #undef MULTIPLIER 129 | 130 | -------------------------------------------------------------------------------- /src/benchmark_views.hpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 | * Copyright (c) QuantStack * 4 | * * 5 | * Distributed under the terms of the BSD 3-Clause License. * 6 | * * 7 | * The full license is in the file LICENSE, distributed with this software. * 8 | ****************************************************************************/ 9 | 10 | #include 11 | 12 | #ifdef HAS_XTENSOR 13 | #include "xtensor/xnoalias.hpp" 14 | #include "xtensor/xio.hpp" 15 | #include "xtensor/xrandom.hpp" 16 | #include "xtensor/xtensor.hpp" 17 | #include "xtensor/xarray.hpp" 18 | #include "xtensor/xstrided_view.hpp" 19 | #include "xtensor/xview.hpp" 20 | #include "xtensor/xdynamic_view.hpp" 21 | #include "xtensor/xadapt.hpp" 22 | #endif 23 | 24 | #ifdef HAS_EIGEN 25 | #include 26 | #include 27 | #endif 28 | 29 | #ifdef HAS_BLITZ 30 | #include 31 | #endif 32 | 33 | #ifdef HAS_ARMADILLO 34 | #include 35 | #endif 36 | 37 | #define RANGE 3, 1000 38 | #define MULTIPLIER 8 39 | 40 | 41 | #ifdef HAS_XTENSOR 42 | void Add2dView_XTensor(benchmark::State& state) 43 | { 44 | using namespace xt; 45 | 46 | xtensor vA = random::rand({state.range(0), state.range(0)}); 47 | xtensor vB = random::rand({state.range(0), state.range(0)}); 48 | 49 | auto vAView = xt::view(vA, all(), all()); 50 | auto vBView = xt::view(vB, all(), all()); 51 | 52 | for (auto _ : state) 53 | { 54 | xtensor vRes(vAView + vBView); 55 | benchmark::DoNotOptimize(vRes.data()); 56 | } 57 | } 58 | BENCHMARK(Add2dView_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 59 | #endif 60 | 61 | #ifdef HAS_EIGEN 62 | void Add2dView_Eigen(benchmark::State& state) 63 | { 64 | using namespace Eigen; 65 | MatrixXd vA = MatrixXd::Random(state.range(0), state.range(0)); 66 | MatrixXd vB = MatrixXd::Random(state.range(0), state.range(0)); 67 | 68 | auto vAView = vA.topLeftCorner(state.range(0), state.range(0)); 69 | auto vBView = vB.topLeftCorner(state.range(0), state.range(0)); 70 | 71 | for (auto _ : state) 72 | { 73 | MatrixXd vRes(state.range(0), state.range(0)); 74 | vRes.noalias() = vAView + vBView; 75 | benchmark::DoNotOptimize(vRes.data()); 76 | } 77 | } 78 | BENCHMARK(Add2dView_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 79 | 80 | //void Add1dMap_Eigen(benchmark::State& state) 81 | //{ 82 | // using namespace Eigen; 83 | // MatrixXd vA = VectorXd::Random(state.range(0)); 84 | // MatrixXd vB = VectorXd::Random(state.range(0)); 85 | // 86 | // auto vAView = Map>(vA.data(), vA.size()); 87 | // auto vBView = Map>(vB.data(), vB.size()); 88 | // 89 | // for (auto _ : state) 90 | // { 91 | // VectorXd vRes(vAView + vBView); 92 | // benchmark::DoNotOptimize(vRes.data()); 93 | // } 94 | //} 95 | //BENCHMARK(Add1dMap_Eigen)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 96 | #endif 97 | 98 | #ifdef HAS_XTENSOR 99 | void Add2dStridedView_XTensor(benchmark::State& state) 100 | { 101 | using namespace xt; 102 | 103 | xtensor vA = random::rand({state.range(0), state.range(0)}); 104 | xtensor vB = random::rand({state.range(0), state.range(0)}); 105 | 106 | auto vAView = xt::strided_view(vA, {all(), all()}); 107 | auto vBView = xt::strided_view(vB, {all(), all()}); 108 | 109 | for (auto _ : state) 110 | { 111 | xtensor vRes(vAView + vBView); 112 | benchmark::DoNotOptimize(vRes.data()); 113 | } 114 | } 115 | BENCHMARK(Add2dStridedView_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 116 | 117 | void Add2dDynamicView_XTensor(benchmark::State& state) 118 | { 119 | using namespace xt; 120 | 121 | xtensor vA = random::rand({state.range(0), state.range(0)}); 122 | xtensor vB = random::rand({state.range(0), state.range(0)}); 123 | 124 | auto vAView = xt::dynamic_view(vA, {all(), all()}); 125 | auto vBView = xt::dynamic_view(vB, {all(), all()}); 126 | 127 | for (auto _ : state) 128 | { 129 | xtensor vRes(vAView + vBView); 130 | benchmark::DoNotOptimize(vRes.data()); 131 | } 132 | } 133 | BENCHMARK(Add2dDynamicView_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 134 | 135 | void Add2dAdapt_XTensor(benchmark::State& state) 136 | { 137 | using namespace xt; 138 | 139 | xtensor vA = random::rand({state.range(0), state.range(0)}); 140 | xtensor vB = random::rand({state.range(0), state.range(0)}); 141 | std::size_t vSize = static_cast(state.range(0)); 142 | std::array vShape = {vSize, vSize}; 143 | auto vAView = xt::adapt(std::move(vA.data()), vShape); 144 | auto vBView = xt::adapt(std::move(vB.data()), vShape); 145 | 146 | for (auto _ : state) 147 | { 148 | xtensor vRes(vAView + vBView); 149 | benchmark::DoNotOptimize(vRes.data()); 150 | } 151 | } 152 | BENCHMARK(Add2dAdapt_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 153 | 154 | void Add2dLoop_XTensor(benchmark::State& state) 155 | { 156 | using namespace xt; 157 | 158 | xtensor vA = random::rand({state.range(0), state.range(0)}); 159 | xtensor vB = random::rand({state.range(0), state.range(0)}); 160 | std::array vShape = {static_cast(state.range(0)), static_cast(state.range(0))}; 161 | for (auto _ : state) 162 | { 163 | xtensor vRes(vShape); 164 | for (std::size_t i = 0; i < vRes.shape()[0]; ++i) 165 | { 166 | for (std::size_t j = 0; j < vRes.shape()[1]; ++j) 167 | { 168 | vRes(i, j) = vA(i, j) + vB(i, j); 169 | } 170 | } 171 | benchmark::DoNotOptimize(vRes.data()); 172 | } 173 | } 174 | BENCHMARK(Add2dLoop_XTensor)->RangeMultiplier(MULTIPLIER)->Range(RANGE); 175 | #endif 176 | 177 | 178 | #undef RANGE 179 | #undef MULTIPLIER 180 | 181 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # 3 | # Copyright (c) QuantStack # 4 | # # 5 | # Distributed under the terms of the BSD 3-Clause License. # 6 | # # 7 | # The full license is in the file LICENSE, distributed with this software. # 8 | ############################################################################ 9 | 10 | cmake_minimum_required(VERSION 3.1) 11 | 12 | project(xtensor-benchmark) 13 | 14 | message(STATUS "Forcing tests build type to Release") 15 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 16 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/modules/") 17 | include(CheckCXXCompilerFlag) 18 | string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) 19 | 20 | # Optional dependencies 21 | # ===================== 22 | 23 | option(BENCHMARK_XTENSOR "benchmark against xtensor" ON) 24 | option(BENCHMARK_EIGEN "benchmark against eigen" OFF) 25 | option(BENCHMARK_BLITZ "benchmark against Blitz" OFF) 26 | option(BENCHMARK_ARMADILLO "benchmark agains Armadillo" OFF) 27 | option(BENCHMARK_PYTHONIC "benchmark agains numpy + pythran" OFF) 28 | option(BENCHMARK_ALL "benchmark against all libraries" OFF) 29 | option(BUILD_EXTERNAL_GOOGLEBENCHMARK "Download and build google benchmark" OFF) 30 | 31 | if(BENCHMARK_ALL) 32 | set(BENCHMARK_XTENSOR ON) 33 | set(BENCHMARK_EIGEN ON) 34 | set(BENCHMARK_BLITZ ON) 35 | set(BENCHMARK_ARMADILLO ON) 36 | set(BENCHMARK_PYTHONIC ON) 37 | endif() 38 | 39 | # Compilation flags 40 | # ================= 41 | 42 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") 43 | CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) 44 | if (NOT HAS_CPP14_FLAG) 45 | message(FATAL_ERROR "Unsupported compiler -- xtensor requires C++14 support!") 46 | endif() 47 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast -ffast-math -march=native -pthread") 48 | endif() 49 | 50 | if(MSVC) 51 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 52 | add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) 53 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP /bigobj /arch:AVX2") 54 | set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) 55 | endif() 56 | 57 | if(BUILD_EXTERNAL_GOOGLEBENCHMARK) 58 | configure_file(modules/downloadGBenchmark.cmake.in googlebenchmark-download/CMakeLists.txt) 59 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 60 | RESULT_VARIABLE result 61 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download ) 62 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 63 | RESULT_VARIABLE result 64 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download ) 65 | 66 | # Add googlebenchmark directly to our build. This defines 67 | # the gtest and gtest_main targets. 68 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src 69 | ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build) 70 | set(GBENCHMARK_INCLUDE_DIRS "${googlebenchmark_SOURCE_DIR}/include") 71 | set(GBENCHMARK_LIBRARIES benchmark) 72 | else() 73 | find_package(benchmark REQUIRED) 74 | set(GBENCHMARK_LIBRARIES benchmark::benchmark_main) 75 | endif() 76 | 77 | 78 | # Sources and target 79 | # ================== 80 | 81 | set(XTENSOR_BENCHMARK_TARGET xtensor_benchmark) 82 | set(XTENSOR_BENCHMARK 83 | src/benchmark_add_1d.hpp 84 | src/benchmark_add_2d.hpp 85 | src/benchmark_broadcasting.hpp 86 | src/benchmark_views.hpp 87 | src/benchmark_fixed.hpp 88 | src/benchmark_constructor.hpp 89 | src/benchmark_scalar_assignment.hpp 90 | src/benchmark_iterators.hpp 91 | src/main.cpp 92 | ) 93 | 94 | add_executable(${XTENSOR_BENCHMARK_TARGET} ${XTENSOR_BENCHMARK} ${XTENSOR_HEADERS}) 95 | 96 | # Mandatory dependencies 97 | # ====================== 98 | 99 | find_package(xtensor REQUIRED CONFIG) 100 | find_package(xsimd REQUIRED) 101 | find_package(xtl REQUIRED) 102 | find_package(Threads) 103 | 104 | target_include_directories(${XTENSOR_BENCHMARK_TARGET} PRIVATE ${xtensor_INCLUDE_DIRS} ${xtl_INCLUDE_DIRS}) 105 | target_include_directories(${XTENSOR_BENCHMARK_TARGET} PRIVATE ${GBENCHMARK_INCLUDE_DIRS}) 106 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE XTENSOR_USE_XSIMD=1 NDEBUG=1) 107 | set_target_properties(${XTENSOR_BENCHMARK_TARGET} PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS NO) 108 | target_link_libraries(${XTENSOR_BENCHMARK_TARGET} 109 | ${GBENCHMARK_LIBRARIES} 110 | ${CMAKE_THREAD_LIBS_INIT}) 111 | 112 | if(BENCHMARK_XTENSOR) 113 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE HAS_XTENSOR=1) 114 | endif() 115 | 116 | if(BENCHMARK_EIGEN) 117 | find_package(Eigen3 REQUIRED NO_MODULE) 118 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE HAS_EIGEN=1 EIGEN_FAST_MATH=1) 119 | target_link_libraries(${XTENSOR_BENCHMARK_TARGET} Eigen3::Eigen) 120 | endif() 121 | 122 | if(BENCHMARK_BLITZ) 123 | find_package(Blitz REQUIRED) 124 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE HAS_BLITZ=1) 125 | target_include_directories(${XTENSOR_BENCHMARK_TARGET} PRIVATE ${BLITZ_INCLUDES}) 126 | target_link_libraries(${XTENSOR_BENCHMARK_TARGET} ${BLITZ_LIBRARIES}) 127 | endif() 128 | 129 | if(BENCHMARK_ARMADILLO) 130 | find_package(Armadillo REQUIRED) 131 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE HAS_ARMADILLO=1) 132 | target_include_directories(${XTENSOR_BENCHMARK_TARGET} PRIVATE ${ARMADILLO_INCLUDE_DIRS}) 133 | target_link_libraries(${XTENSOR_BENCHMARK_TARGET} ${ARMADILLO_LIBRARIES}) 134 | endif() 135 | 136 | if(BENCHMARK_PYTHONIC) 137 | find_package(PythonLibs) 138 | find_package(NumPy) 139 | find_package(Pythran) 140 | link_directories(${Pythran_INCLUDE_DIRS}) 141 | target_compile_definitions(${XTENSOR_BENCHMARK_TARGET} PRIVATE HAS_PYTHONIC=1 ENABLE_PYTHON_MODULE=1 USE_BOOST_SIMD=1) 142 | target_include_directories(${XTENSOR_BENCHMARK_TARGET} PRIVATE 143 | ${PYTHON_INCLUDE_DIRS} 144 | ${NUMPY_INCLUDE_DIRS} 145 | ${Pythran_INCLUDE_DIRS}) 146 | target_link_libraries(${XTENSOR_BENCHMARK_TARGET} ${PYTHON_LIBRARIES}) 147 | endif() 148 | 149 | 150 | message("\n\n COMPILING WITH\n======================================\n\n") 151 | message("COMPILER : ${CMAKE_CXX_COMPILER}") 152 | message("FLAGS : ${CMAKE_CXX_FLAGS}\n") 153 | if(BENCHMARK_XTENSOR) 154 | message("Found xtensor : ${xtensor_INCLUDE_DIRS}") 155 | message("Found xsimd : ${xsimd_INCLUDE_DIRS}\n\n") 156 | endif() 157 | if(BENCHMARK_EIGEN) 158 | message("Found eigen : ${EIGEN3_INCLUDE_DIR}") 159 | endif() 160 | if(BENCHMARK_BLITZ) 161 | message("Found Blitz : ${BLITZ_INCLUDES} | ${BLITZ_LIBRARIES}") 162 | endif() 163 | if(BENCHMARK_ARMADILLO) 164 | message("Found Armadillo : ${ARMADILLO_INCLUDE_DIRS} | ${ARMADILLO_LIBRARIES}") 165 | endif() 166 | if(BENCHMARK_PYTHONIC) 167 | message("Found Pythran : ${Pythran_INCLUDE_DIRS}") 168 | endif() 169 | message("Using benchmark : ${GBENCHMARK_INCLUDE_DIRS} | ${GBENCHMARK_LIBRARIES}") 170 | 171 | 172 | if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/profile_snip.cpp) 173 | add_executable(profile_snip 174 | src/profile_snip.cpp 175 | ${XTENSOR_HEADERS}) 176 | endif() 177 | 178 | add_custom_target(xbenchmark 179 | COMMAND xtensor_benchmark --benchmark_out=bench.csv --benchmark_out_format=csv 180 | DEPENDS ${XTENSOR_BENCHMARK_TARGET}) 181 | 182 | add_custom_target(xpowerbench 183 | COMMAND echo "sudo needed to set cpu power governor to performance" 184 | COMMAND sudo cpupower frequency-set --governor performance 185 | COMMAND xtensor_benchmark --benchmark_out=bench.csv --benchmark_out_format=csv 186 | COMMAND sudo cpupower frequency-set --governor powersave 187 | DEPENDS ${XTENSOR_BENCHMARK_TARGET}) 188 | --------------------------------------------------------------------------------