Commit 152d1c88 authored by Oliver Sander's avatar Oliver Sander

Import the document on the functions interface

parent 6a7b4f90
Pipeline #9982 passed with stage
in 5 minutes and 55 seconds
......@@ -11,3 +11,5 @@
*.toc
dune-functions-bases.pdf
dune-functions-functions.pdf
......@@ -7,6 +7,7 @@ set(IMAGES
gfx/driven_cavity.pdf
gfx/driven_cavity_result.png
gfx/febasis_interface_schematic.pdf
gfx/functions_interface_schematic.pdf
)
if(LATEX_USABLE)
......@@ -14,4 +15,8 @@ if(LATEX_USABLE)
BIBFILES dune-functions-bases.bib
INPUTS ${SOURCES}
IMAGES ${IMAGES})
dune_add_latex_document(dune-functions-functions.tex
BIBFILES dune-functions-functions.bib
INPUTS ${SOURCES}
IMAGES ${IMAGES})
endif(LATEX_USABLE)
@article{bastian_et_al:dune1:2008,
author = {Bastian, P. and Blatt, M. and Dedner, A. and Engwer, C. and Kl{\"o}fkorn, R. and Ohlberger, M. and Sander, O.},
title = {A Generic Grid Interface for Adaptive and Parallel Scientific Computing. {P}art {I}: Abstract Framework},
journal = {Computing},
year = {2008},
volume = {82},
number = {2--3},
pages = {103--119}
}
@article{bastian_et_al:dune2:2008,
author = {Bastian, P. and Blatt, M. and Dedner, A. and Engwer, C. and Kl\"ofkorn, R. and Kornhuber, R. and Ohlberger, M. and Sander, O.},
title = {A Generic Grid Interface for Adaptive and Parallel Scientific Computing. {P}art {II}: Implementation and Tests in {DUNE}},
journal = {Computing},
year = {2008},
volume = {82},
number = {2--3},
pages = {121--138}
}
@misc{Niebler:rangev3,
title = {Range-v3 library},
author = {Niebler, E.},
howpublished = {\url{https://github.com/ericniebler/range-v3}}
}
@misc{DuneFunctions,
title = {Dune-functions module},
author = {Engwer, C. and Gr{\"a}ser, C. and Müthing, S. and Sander, O.},
howpublished = {\url{http://www.dune-project.org/modules/dune-functions}}
}
@misc{Adobe:asl,
title = {Adobe Source Libraries},
author = {Parent, S. and Marcus, M. and Brereton, F.},
howpublished = {\url{http://stlab.adobe.com/}}
}
@misc{Watanabe:boost_type_erasure,
title = {Boost type erasure library},
author = {Watanabe, S.},
howpublished = {\url{http://www.boost.org/doc/libs/release/libs/type_erasure/}}
}
@misc{Niebler:concepts,
author = {Niebler, E.},
title = {Concept checking in {C}++11},
howpublished = {online blog, \url{http://ericniebler.com/2013/11/23/concept-checking-in-c11}},
year = {2013},
note = {last checked on Dec.\,8.\,2015},
lastchecked = {Dec.\,8.\,2015}
}
@inproceedings{driesen_hoelzle:1996,
author = {Driesen, K. and H\"{o}lzle, U.},
title = {The Direct Cost of Virtual Function Calls in {C}++},
booktitle = {Proceedings of the 11th ACM SIGPLAN Conference on Object-oriented Programming, Systems, Languages, and Applications},
series = {OOPSLA '96},
year = {1996},
pages = {306--323},
acmid = {236369},
publisher = {ACM}
}
@Misc{hubicka:2014,
author = {Hubi\v{c}ka, J.},
title = {Devirtualization in {C}++},
howpublished = {online blog, \url{{http://hubicka.blogspot.de/2014/01/devirtualization-in-c-part-1.html}}},
year = {2014},
note = {(at least) seven parts, last checked on Dec.\,8.\,2015},
url = {http://hubicka.blogspot.de/2014/01/devirtualization-in-c-part-1.html},
lastchecked = {Dec.\,8.\,2015}
}
@misc{cpp_standard:2003,
Author = {{International Organization for Standardization}},
Month = {9},
Shortauthor = {{ISO}},
Title = {{ISO/IEC 14882:2003 Programming Language C++}},
Year = {2003}
}
@misc{cpp_standard:2011,
Author = {{International Organization for Standardization}},
Month = {9},
Shortauthor = {{ISO}},
Title = {{ISO/IEC 14882:2011 Programming Language C++}},
Year = {2011}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# Building and running the code
These are the build instructions for the code to reproduce
the numerical examples in the article
> The interface for functions in the dune-functions module
by Christian Engwer, Carsten Gräser, Steffen Müthing, and Oliver Sander.
## Numerical examples
### Requirements
Since the numerical examples are self-contained, building and running
them does not require special external libraries. In particular, no
Dune installation is necessary. However, in order to exactly reproduce
the numbers in the test, specific compilers and compiler versions are
needed, because the code mainly compares the abilities of different
compiler optimizers. For the results in the text we used
* g++ (c++ compiler of the GNU compiler collection, version 4.9.2)
* clang++ (c++ compiler of the clang compiler suite, version 3.6)
While the presented tests were run with the given compiler versions,
we expect to get comparable results with newer ones.
The script generating the presented plots additionally requires
a python interpreter and the python libraries numpy and matplotlib.
### Building and running the example programs
To build and run the example programs you have to call
./run.sh
This will build the example programs, execute them, and
store the results in the newly generated directories
build_gcc, build_gcc_pgo, and build_clang.
### Generating the plots
After the examples have been built and executed, calling
./generate_plots.sh
in the same directory will generate the plots presented
in the paper.
## Full dune-functions library
Additionally to the example programs used for the paper the
full dune-functions library based on the concepts described
in the paper is also available as a dune-module. This module
requires preview versions of the upcoming 3.0 release of the
dune core modules and the dune-typetree module. These modules,
as well as dune-functions itself, can be obtained using git via
git clone https://gitlab.dune-project.org/core/dune-common.git
git clone https://gitlab.dune-project.org/core/dune-istl.git
git clone https://gitlab.dune-project.org/core/dune-geometry.git
git clone https://gitlab.dune-project.org/core/dune-localfunctions.git
git clone https://gitlab.dune-project.org/core/dune-grid.git
git clone https://gitlab.dune-project.org/staging/dune-functions.git
git clone https://gitlab.dune-project.org/pdelab/dune-typetree.git
The desired versions can be obtained via
cd dune-common ; git checkout 834b14c044 ; cd ..
cd dune-istl ; git checkout b0efdba0e6 ; cd ..
cd dune-geometry ; git checkout 2334a10bdb ; cd ..
cd dune-localfunctions ; git checkout d6ea557cb5 ; cd ..
cd dune-grid ; git checkout a1aa47aac3 ; cd ..
cd dune-typetree ; git checkout 78104bb969 ; cd ..
cd dune-functions ; git checkout aa9ed7a094 ; cd ..
To use those libraries in other dune projects, they can be
configured and build using
./dune-common/bin/dunecontrol --builddir=$PWD/build all
Note that dune-functions does not introduce any dependencies on third
party software beyond what is already required by the Dune core modules.
################################################################################
echo "Generating plots for gcc"
cd build_gcc
python ../plot.py
cp timings.pgf ../timings_gcc.pgf
cd ..
################################################################################
echo "Generating plots for gcc pgo"
cd build_gcc_pgo
python ../plot.py
cp timings.pgf ../timings_gcc_pgo.pgf
cd ..
################################################################################
echo "Generating plots for clang"
cd build_clang
python ../plot.py
cp timings.pgf ../timings_clang.pgf
cd ..
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
//
// Copyright (c) 2015, Carsten Gräser
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <iostream>
#include <iomanip>
#include <array>
#include <chrono>
#include <functional>
template<class K, std::size_t N>
class StaticVector : public std::array<K, N>
{
public:
StaticVector()
{
auto& self = *this;
for (std::size_t i=0; i<N; ++i)
self[i] = 0;
}
StaticVector(const K& k)
{
auto& self = *this;
for (std::size_t i=0; i<N; ++i)
self[i] = k;
}
void axpy(const K& k, const StaticVector& other)
{
auto& self = *this;
for (std::size_t i=0; i<N; ++i)
self[i] += k*other[i];
}
void operator*=(const K& k)
{
auto& self = *this;
for (std::size_t i=0; i<N; ++i)
self[i] *= k;
}
};
template <class K, std::size_t N>
inline std::ostream& operator<< (std::ostream& s, const StaticVector<K,N>& v)
{
s << "[";
for (std::size_t i=0; i<N-1; i++)
s << v[i] << ",";
s << v[N-1] << "]";
return s;
}
template<class Domain, class Range, class F>
Range integrateOverInterval(const F& f, Domain a, Domain b, int n)
{
Domain h = (b-a)/n;
Range result = 0.0;
std::array<std::pair<double,double>,1> quadRule = {{ {0.5, 1} }};
Range localResult = 0.0;
for (std::size_t i=0; i<n; ++i)
{
for (auto&& quadPoint : quadRule)
// localResult.axpy(quadPoint.second, f(a + (i+quadPoint.first)*h));
result.axpy(quadPoint.second, f(a + (i+quadPoint.first)*h));
// result.axpy(h, localResult);
}
result *= h;
return result;
}
template<class Domain, class Range, class F>
Range integrateOverInterval_Evaluate(const F& f, Domain a, Domain b, int n)
{
Domain h = (b-a)/n;
Range result = 0.0;
std::array<std::pair<double,double>,1> quadRule = {{ {0.5, 1} }};
Range temp;
Range localResult = 0.0;
for (std::size_t i=0; i<n; ++i)
{
for (auto&& quadPoint : quadRule)
{
f.evaluate(a + (i+quadPoint.first)*h, temp);
// localResult.axpy(quadPoint.second, temp);
result.axpy(quadPoint.second, temp);
}
// result.axpy(h, localResult);
}
result *= h;
return result;
}
class Timer
{
using TimeStamp = decltype(std::chrono::high_resolution_clock::now());
TimeStamp start_;
public:
Timer () :
start_(std::chrono::high_resolution_clock::now())
{}
double msElapsed() const
{
std::chrono::duration<double, std::milli> elapsed
= std::chrono::high_resolution_clock::now()-start_;
return elapsed.count();
}
};
template<class D, class R>
class VirtualFunction
{
public:
using Domain = D;
using Range = R;
virtual void evaluate(const Domain&, Range&) const = 0;
};
template<class D, class R>
class Function
{
public:
using Domain = D;
using Range = R;
};
template<class Base>
class F : public Base
{
public:
using Range = typename Base::Range;
using Domain = typename Base::Domain;
void imp(const Domain& x, Range& y) const
{
for(std::size_t i=0; i<y.size(); ++i)
{
// y[i] = x*x;
y[i] = x+i;
// y[i] = x*x + i;
}
}
void evaluate(const Domain& x, Range& y) const
{
imp(x,y);
}
Range operator()(const Domain& x) const
{
Range y;
imp(x, y);
return y;
}
};
template<std::size_t blockSize>
void testWithVectorSize(std::size_t n)
{
double a = 0;
double b = 1;
using Range = StaticVector<double,blockSize>;
using Domain = double;
std::array<double, 4> timing;
std::array<Range, 4> result;
std::size_t N = n/blockSize;
// For each test do one warump run with N-1 before.
{
using Interface = Function<Domain, Range>;
auto f = F<Interface>();
for (int k=N-1; k<=N; ++k)
{
Timer t;
result[0] = integrateOverInterval<Domain, Range>(f, a, b, k);
timing[0] = t.msElapsed();
}
}
{
using Interface = Function<Domain, Range>;
auto f = F<Interface>();
for (int k=N-1; k<=N; ++k)
{
Timer t;
result[1] = integrateOverInterval_Evaluate<Domain, Range>(f, a, b, k);
timing[1] = t.msElapsed();
}
}
{
using Interface = Function<Domain, Range>;
auto f = F<Interface>();
for (int k=N-1; k<=N; ++k)
{
Timer t;
result[2] = integrateOverInterval<Domain, Range>(std::function<Range(Domain)>(f), a, b, k);
timing[2] = t.msElapsed();
}
}
{
using Interface = VirtualFunction<Domain, Range>;
std::shared_ptr<Interface> f = std::make_shared<F<Interface>>();
Interface& fBase = *f;
for (int k=N-1; k<=N; ++k)
{
Timer t;
result[3] = integrateOverInterval_Evaluate<Domain, Range, Interface>(fBase, a, b, k);
timing[3] = t.msElapsed();
}
}
std::cout << std::setw(3) << blockSize << " ";
for(int i=0; i<4; ++i)
std::cout << std::setw(14) << (int)(timing[i]);
for(int i=1; i<4; ++i)
if (result[0]!=result[i])
std::cout << " error";
std::cout << std::endl;
}
int main(int argc, char** argv)
{
std::size_t n = 100000000;
std::cout << "size operator() evaluate() std::function v evaluate()" << std::endl;
testWithVectorSize<1>(n);
testWithVectorSize<2>(n);
testWithVectorSize<3>(n);
testWithVectorSize<4>(n);
testWithVectorSize<5>(n);
testWithVectorSize<6>(n);
testWithVectorSize<7>(n);
testWithVectorSize<8>(n);
testWithVectorSize<9>(n);
testWithVectorSize<10>(n);
testWithVectorSize<11>(n);
testWithVectorSize<12>(n);
testWithVectorSize<13>(n);
testWithVectorSize<14>(n);
testWithVectorSize<15>(n);
testWithVectorSize<16>(n);
return 0;
}
import numpy
import matplotlib
# matplotlib.use("pgf")
matplotlib.rcParams.update({
"pgf.texsystem": "pdflatex",
"pgf.preamble": [
r"\usepackage[utf8x]{inputenc}",
r"\usepackage[T1]{fontenc}",
r"\usepackage{cmbright}",
],
"font.family" : "serif",
"font.size": 10,
})
import pylab
data = pylab.loadtxt("timings1", skiprows=1)
for i in range(2,5):
data = pylab.minimum(data, pylab.loadtxt("timings"+str(i), skiprows=1))
pylab.figure(figsize=(5,2.8))
pylab.plot(data[:,0], data[:,1], 'o-k', label='operator()')
pylab.plot(data[:,0], data[:,2], 'o-b', label='evaluate()')
pylab.plot(data[:,0], data[:,3], 'o-r', label='std::function')
pylab.plot(data[:,0], data[:,4], 'o-g', label='virtual evaluate()')
pylab.ylim(ymax = 350, ymin = 0)
pylab.xlim(xmax = 16, xmin = 0)
pylab.legend()
# pylab.title("Title of Plot")
pylab.xlabel("range vector size $N$")
pylab.ylabel("ms")
pylab.tight_layout()
pylab.savefig("timings.pgf")
# pylab.show()
################################################################################
echo "Test with gcc"
mkdir -p build_gcc
cd build_gcc
g++ -std=c++11 -O3 -funroll-loops ../integration-test.cc -o integration-test
rm timings*
./integration-test | tee timings1
./integration-test | tee timings2
./integration-test | tee timings3
./integration-test | tee timings4
cd ..
################################################################################
echo "Test with gcc pgo"
mkdir -p build_gcc_pgo
cd build_gcc_pgo
g++ -std=c++11 -O3 -funroll-loops ../integration-test.cc -o integration-test -fprofile-generate
echo "Generating pgo profile"
./integration-test
g++ -std=c++11 -O3 -funroll-loops ../integration-test.cc -o integration-test -fprofile-use
rm timings*
./integration-test | tee timings1
./integration-test | tee timings2
./integration-test | tee timings3
./integration-test | tee timings4
cd ..
################################################################################
echo "Test with clang"
mkdir -p build_clang
cd build_clang
clang++ -std=c++11 -O3 -funroll-loops ../integration-test.cc -o integration-test
rm timings*
./integration-test | tee timings1
./integration-test | tee timings2