testAtomic.c 4.68 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/*******************************************************************************
 * 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 */
Matthieu Schaller's avatar
Matthieu Schaller committed
78 79
  float *array_f = (float *)malloc(array_size * sizeof(float));
  long long *array_ll = (long long *)malloc(array_size * sizeof(long long));
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

  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;
}