From 5ed9ecedf6c1a614513c1157d0a41396f91bb7c0 Mon Sep 17 00:00:00 2001 From: Matthieu Schaller <schaller@strw.leidenuniv.nl> Date: Thu, 2 Apr 2020 14:04:39 +0200 Subject: [PATCH] Added a simple unit test checking the correctness of the atomic implementation --- .gitignore | 1 + tests/Makefile.am | 8 ++- tests/testAtomic.c | 146 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 tests/testAtomic.c diff --git a/.gitignore b/.gitignore index f843002a1c..99aa018c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,7 @@ tests/testInteractions.sh tests/testSymmetry tests/testHydroMPIrules tests/testMaths +tests/testAtomic tests/testRandom tests/testRandomSpacing tests/testThreadpool diff --git a/tests/Makefile.am b/tests/Makefile.am index 11426ac899..e24a2a69b0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,7 +29,8 @@ TESTS = testGreetings testMaths testReading.sh testKernel \ testPeriodicBC.sh testPeriodicBCPerturbed.sh testPotentialSelf \ testPotentialPair testEOS testUtilities testSelectOutput.sh \ testCbrt testCosmology testOutputList testFormat.sh \ - test27cellsStars.sh test27cellsStarsPerturbed.sh testHydroMPIrules + test27cellsStars.sh test27cellsStarsPerturbed.sh testHydroMPIrules \ + testAtomic # List of test programs to compile check_PROGRAMS = testGreetings testReading testTimeIntegration \ @@ -41,7 +42,8 @@ check_PROGRAMS = testGreetings testReading testTimeIntegration \ testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \ testGravityDerivatives testPotentialSelf testPotentialPair testEOS testUtilities \ testSelectOutput testCbrt testCosmology testOutputList test27cellsStars \ - test27cellsStars_subset testCooling testComovingCooling testFeedback testHashmap testHydroMPIrules + test27cellsStars_subset testCooling testComovingCooling testFeedback testHashmap \ + testAtomic testHydroMPIrules # Rebuild tests when SWIFT is updated. $(check_PROGRAMS): ../src/.libs/libswiftsim.a @@ -51,6 +53,8 @@ testGreetings_SOURCES = testGreetings.c testMaths_SOURCES = testMaths.c +testAtomic_SOURCES = testAtomic.c + testRandom_SOURCES = testRandom.c testRandomSpacing_SOURCES = testRandomSpacing.c diff --git a/tests/testAtomic.c b/tests/testAtomic.c new file mode 100644 index 0000000000..47eca7b736 --- /dev/null +++ b/tests/testAtomic.c @@ -0,0 +1,146 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2020 Matthieu Schaller (schaller@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* Standard includes. */ +#include <fenv.h> + +/* Local includes */ +#include "swift.h" + +const int array_size = 2048 * 2048; +const int num_threads = 64; +const int chunk_size = 64; + +void map_function_sum_f(void *data, int num_elements, void *extra_data) { + + float *array = (float *)data; + float *sum = (float *)extra_data; + + for (int i = 0; i < num_elements; ++i) atomic_add_f(sum, array[i]); +} + +void map_function_sum_ll(void *data, int num_elements, void *extra_data) { + + long long *array = (long long *)data; + long long *sum = (long long *)extra_data; + + for (int i = 0; i < num_elements; ++i) atomic_add(sum, array[i]); +} + +void map_function_inc_ll(void *data, int num_elements, void *extra_data) { + + long long *sum = (long long *)extra_data; + + for (int i = 0; i < num_elements; ++i) atomic_inc(sum); +} + +int main(int argc, char *argv[]) { + + /* Initialize CPU frequency, this also starts time. */ + unsigned long long cpufreq = 0; + clocks_set_cpufreq(cpufreq); + +/* Choke on FPEs */ +#ifdef HAVE_FE_ENABLE_EXCEPT + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + /* Get some randomness going */ + const int seed = time(NULL); + message("Seed = %d", seed); + srand(seed); + + /* Start a bunch of threads */ + printf("# Creating threadpool with %d threads\n", num_threads); + struct threadpool tp; + threadpool_init(&tp, num_threads); + + /* Create some random data */ + float *array_f = malloc(array_size * sizeof(float)); + long long *array_ll = malloc(array_size * sizeof(long long)); + + for (int i = 0; i < array_size; ++i) { + array_f[i] = rand() / ((float)RAND_MAX); + array_ll[i] = rand(); + } + + /*** Test the addition atomic ops *******************************/ + + /* float case */ + + /* Compute the real answer */ + float real_sum_f = 0.f; + for (int i = 0; i < array_size; ++i) { + real_sum_f += array_f[i]; + } + + /* Compute the answer via threads and atomic */ + float atomic_sum_f = 0.f; + threadpool_map(&tp, map_function_sum_f, array_f, array_size, sizeof(float), + chunk_size, &atomic_sum_f); + + const double diff_sum_f = (double)real_sum_f - (double)atomic_sum_f; + const double sum_sum_f = (double)real_sum_f + (double)atomic_sum_f; + const double rel_sum_f = 0.5 * fabs(diff_sum_f) / sum_sum_f; + message("Real sum = %.7e -- atomic sum = %.7e rel=%e", real_sum_f, + atomic_sum_f, rel_sum_f); + + /* long long case */ + + /* Compute the real answer */ + long long real_sum_ll = 0.f; + for (int i = 0; i < array_size; ++i) { + real_sum_ll += array_ll[i]; + } + + /* Compute the answer via threads and atomic */ + long long atomic_sum_ll = 0LL; + threadpool_map(&tp, map_function_sum_ll, array_ll, array_size, + sizeof(long long), chunk_size, &atomic_sum_ll); + + const double diff_sum_ll = (double)real_sum_ll - (double)atomic_sum_ll; + const double sum_sum_ll = (double)real_sum_ll + (double)atomic_sum_ll; + const double rel_sum_ll = 0.5 * fabs(diff_sum_ll) / sum_sum_ll; + message("Real sum = %lld -- atomic sum = %lld rel=%e", real_sum_ll, + atomic_sum_ll, rel_sum_ll); + + /*** Test the inc atomic ops *******************************/ + + long long real_inc_ll = array_size; + + /* Compute the answer via threads and atomic */ + long long atomic_inc_ll = 0LL; + threadpool_map(&tp, map_function_inc_ll, array_ll, array_size, + sizeof(long long), chunk_size, &atomic_inc_ll); + + const double diff_inc_ll = (double)real_inc_ll - (double)atomic_inc_ll; + const double sum_inc_ll = (double)real_inc_ll + (double)atomic_inc_ll; + const double rel_inc_ll = 0.5 * fabs(diff_inc_ll) / sum_inc_ll; + message("Real inc = %lld -- atomic inc = %lld rel=%e", real_inc_ll, + atomic_inc_ll, rel_inc_ll); + + /* Be clean */ + threadpool_clean(&tp); + free(array_f); + free(array_ll); + return 0; +} -- GitLab