covfie (pronounced coffee) is a co-processor vector field library. covfie consists of two main components; the first is the header-only C++ library, which can be used by scientific applications using CUDA or other programming platforms. The second is a set of benchmarks which can be used to quantify the computational performance of all the different vector field implementations covfie provides. Arguably, the test suite constitutes a third component.
All covfie vector fields are stored in the covfie::field type and they are
accessed using the covfie::field_view type. These require a backend type
passed as a template parameters, and their behaviour can be expanded using
transformers. The easiest way to get started using covfie is to use a field
builder backend, which allows you to write data to memory (the following
example is included in the repository as
readme_example_1):
using field_t = covfie::field<covfie::backend::strided<
covfie::vector::size2,
covfie::backend::array<covfie::vector::float2>>>;
int main(void)
{
// Initialize the field as a 10x10 field, then create a view from it.
field_t my_field(covfie::make_parameter_pack(
field_t::backend_t::configuration_t{10ul, 10ul}
));
field_t::view_t my_view(my_field);
// Assign f(x, y) = (sin x, cos y)
for (std::size_t x = 0ul; x < 10ul; ++x) {
for (std::size_t y = 0ul; y < 10ul; ++y) {
my_view.at(x, y)[0] = std::sin(static_cast<float>(x));
my_view.at(x, y)[1] = std::cos(static_cast<float>(y));
}
}
// Retrieve the vector value at (2, 3)
field_t::output_t v = my_view.at(2ul, 3ul);
std::cout << "Value at (2, 3) = (" << v[0] << ", " << v[1] << ")"
<< std::endl;
return 0;
}This next example (readme_example_2)
creates a two-dimensional vector field over the natural numbers, stretching 10
indices in each direction. If we want to use real numbers for our vector field,
we can simply add a linear interpolator:
using builder_t = covfie::field<covfie::backend::strided<
covfie::vector::size2,
covfie::backend::array<covfie::vector::float2>>>;
using field_t = covfie::field<covfie::backend::linear<covfie::backend::strided<
covfie::vector::size2,
covfie::backend::array<covfie::vector::float2>>>>;
int main(void)
{
// Initialize the field as a 10x10 field, then create a view from it.
builder_t my_field(covfie::make_parameter_pack(
builder_t::backend_t::configuration_t{10ul, 10ul}
));
builder_t::view_t my_view(my_field);
// Assign f(x, y) = (sin x, cos y)
for (std::size_t x = 0ul; x < 10ul; ++x) {
for (std::size_t y = 0ul; y < 10ul; ++y) {
my_view.at(x, y)[0] = std::sin(static_cast<float>(x));
my_view.at(x, y)[1] = std::cos(static_cast<float>(y));
}
}
field_t new_field(my_field);
field_t::view_t new_view(new_field);
// Retrieve the vector value at (2.31, 3.98)
field_t::output_t v = new_view.at(2.31f, 3.98f);
std::cout << "Value at (2.31, 3.98) = (" << v[0] << ", " << v[1] << ")"
<< std::endl;
return 0;
}covfie types can seem intimidating at first, but they are quite friendly! Also, you only really need to worry about them once, and you can hide them away in a typedef.
A full build of covfie requires a few dependencies, including a CUDA compiler, Google Test, and Google Benchmark. The easiest way to install these is to use the included Spack environment:
spack env create covfie spack.yaml
spack -e covfie concretize -f
spack -e covfie install
spack env activate covfie
Configure a Debug build with COVFIE_BUILD_COVERAGE, run the tests, then
build the report with gcovr:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCOVFIE_BUILD_TESTS=On \
-DCOVFIE_BUILD_COVERAGE=On
cmake --build build
build/tests/core/test_core && build/tests/cpu/test_cpu
gcovr --root . build --html-details coverage/index.html
The build directory is a positional argument to gcovr, and gcovr reads its
filters from gcovr.cfg in the root of the repository. Use a Debug build,
because the inlining done at higher optimisation levels distorts the result.
Two things stop the report from measuring code that no release build
contains. The coverage option defines NDEBUG, which removes the assertions
and the blocks that the library guards with #ifndef NDEBUG; be aware that
assertions therefore do not fire in a coverage build. gcovr.cfg then passes
--exclude-throw-branches, which drops the hidden branch that the compiler
adds to every call that may throw. Together these two raised the reported
branch coverage from 58% to 89% without a single test changing, because the
branches they remove were never reachable from a test.
Note that covfie is a header-only template library, so gcov counts each line once per template instantiation. A header that is instantiated eight times contributes eight times its length to the totals. Branch coverage is the more useful of the two numbers.
If you use covfie in your research, please cite the following paper:
@inproceedings{covfie_paper,
author = {Swatman, Stephen Nicholas and Varbanescu, Ana-Lucia and Pimentel, Andy and Salzburger, Andreas and Krasznahorkay, Attila},
title = {Systematically Exploring High-Performance Representations of Vector Fields Through Compile-Time Composition},
year = {2023},
isbn = {9798400700682},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
doi = {10.1145/3578244.3583723},
booktitle = {Proceedings of the 2023 ACM/SPEC International Conference on Performance Engineering},
pages = {55–66},
numpages = {12},
location = {Coimbra, Portugal},
series = {ICPE '23}
}You may also want to cite the software itself. Unfortunately, academia has not yet progressed to the point where software citations are regarded as highly as paper citations; therefore, we prefer references to the paper (although you may want to cite both). To cite the software, use:
@software{covfie_lib,
author = {Swatman, Stephen Nicholas},
license = {MPL-2.0},
title = {{Covfie: A Compositional Vector Field Library}},
url = {https://github.com/acts-project/covfie}
}All documentation pertaining to covfie can be found on ReadTheDocs at the following URL: https://covfie.readthedocs.io/en/latest/
Given the ATLAS magnetic field
file
in text format, it can be converted into a covfie format using the
convert_bfield example (this requires COVFIE_BUILD_EXAMPLES to be enabled
at configuration time):
build/examples/core/convert_bfield --input ATLASBField_xyz.txt --output atlas_bfield.cvf