Commit 3c01c21b authored by Lorenz Huedepohl's avatar Lorenz Huedepohl

Refactor elpa_options.c

Supports multiple indexes now, to be used for non-tunable 'parameters'
parent 0b245d01
......@@ -27,6 +27,7 @@ libelpa@SUFFIX@_private_la_SOURCES = \
src/helpers/mod_precision.F90 \
src/helpers/mod_mpi.F90 \
src/helpers/mod_mpi_stubs.F90 \
src/elpa_generated_fortran_interfaces.F90 \
src/elpa2/mod_redist_band.F90 \
src/elpa2/mod_pack_unpack_cpu.F90 \
src/elpa2/mod_compute_hh_trafo.F90 \
......@@ -35,7 +36,6 @@ libelpa@SUFFIX@_private_la_SOURCES = \
src/elpa1/elpa1_compute_private.F90 \
src/elpa2/elpa2_determine_workload.F90 \
src/elpa2/elpa2_compute.F90 \
src/elpa2/kernels/mod_fortran_interfaces.F90 \
src/elpa2/kernels/mod_single_hh_trafo_real.F90 \
src/elpa_driver/legacy_interface/elpa_driver_c_interface_legacy.F90 \
src/elpa1/legacy_interface/elpa_1stage_c_interface_legacy.F90 \
......@@ -50,6 +50,7 @@ libelpa@SUFFIX@_private_la_SOURCES = \
src/elpa2/qr/elpa_pdgeqrf.F90 \
src/elpa1/elpa1_new_interface.F90 \
src/elpa2/elpa2_new_interface.F90 \
src/elpa_index.c \
src/elpa_options.c
EXTRA_libelpa@SUFFIX@_private_la_DEPENDENCIES = \
......
define extract_interface
@echo "Generating $@...";
@echo "Extracting interface marked with '$1' from $@...";
@grep -h "^ *$1" $^ | sed 's/^ *$1//;' >> $@ || { rm $@; exit 1; }
endef
......@@ -16,12 +16,15 @@ config-f90.h: config.h
elpa/elpa_generated.h: $(top_srcdir)/src/elpa_driver/legacy_interface/elpa_driver_c_interface_legacy.F90 \
$(top_srcdir)/src/elpa1/legacy_interface/elpa_1stage_c_interface_legacy.F90 \
$(top_srcdir)/src/elpa2/legacy_interface/elpa_2stage_c_interface_legacy.F90 | elpa
@rm -f $@
$(call extract_interface,!c>)
test/shared/generated.h: $(wildcard $(top_srcdir)/test/shared/*.*90) | test/shared
@rm -f $@
$(call extract_interface,!c>)
elpa/elpa_generated_fortran_interfaces.h: $(wildcard $(top_srcdir)/src/elpa2/kernels/*.c) $(wildcard $(top_srcdir)/src/elpa2/kernels/*.s) | elpa
elpa/elpa_generated_fortran_interfaces.h: $(wildcard $(top_srcdir)/src/elpa2/kernels/*.c $(top_srcdir)/src/elpa2/kernels/*.s $(top_srcdir)/src/*.[ch]) | elpa
@rm -f $@
$(call extract_interface,!f>)
$(call extract_interface,#!f>)
......
......@@ -115,10 +115,7 @@
#else
use timings_dummy
#endif
#if defined(HAVE_AVX) || defined(HAVE_AVX2) || defined(HAVE_SSE_INTRINSICS) || defined(HAVE_SSE_ASSEMBLY) || defined(HAVE_AVX512)
use kernel_interfaces
#endif
use elpa_generated_fortran_interfaces
implicit none
real(kind=c_double), intent(inout) :: kernel_time ! MPI_WTIME always needs double
integer(kind=lik) :: kernel_flops
......
#include "config-f90.h"
module kernel_interfaces
module elpa_generated_fortran_interfaces
use iso_c_binding
implicit none
#include "elpa/elpa_generated_fortran_interfaces.h"
......
// This file is part of ELPA.
//
// The ELPA library was originally created by the ELPA consortium,
// consisting of the following organizations:
//
// - Max Planck Computing and Data Facility (MPCDF), formerly known as
// Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
// - Bergische Universität Wuppertal, Lehrstuhl für angewandte
// Informatik,
// - Technische Universität München, Lehrstuhl für Informatik mit
// Schwerpunkt Wissenschaftliches Rechnen ,
// - Fritz-Haber-Institut, Berlin, Abt. Theorie,
// - Max-Plack-Institut für Mathematik in den Naturwissenschaften,
// Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
// and
// - IBM Deutschland GmbH
//
// This particular source code file contains additions, changes and
// enhancements authored by Intel Corporation which is not part of
// the ELPA consortium.
//
// More information can be found here:
// http://elpa.mpcdf.mpg.de/
//
// ELPA is free software: you can redistribute it and/or modify
// it under the terms of the version 3 of the license of the
// GNU Lesser General Public License as published by the Free
// Software Foundation.
//
// ELPA 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with ELPA. If not, see <http://www.gnu.org/licenses/>
//
// ELPA reflects a substantial effort on the part of the original
// ELPA consortium, and we ask you to respect the spirit of the
// license that we chose: i.e., please contribute any changes you
// may have back to the original ELPA library distribution, and keep
// any derivatives of ELPA under the same license that we chose for
// the original distribution, the GNU Lesser General Public License.
//
// Authors: L. Huedepohl and A. Marek, MPCDF
#include "elpa_index.h"
elpa_index_t elpa_allocate_index(int n_entries, elpa_int_entry_t int_entries[n_entries]) {
elpa_index_t index = (elpa_index_t) calloc(1, sizeof(struct elpa_index_struct));
/* Integer entries */
index->n_int_entries = n_entries;
index->int_values = (int*) calloc(index->n_int_entries, sizeof(int));
index->int_entries = int_entries;
for (int i = 0; i < index->n_int_entries; i++) {
index->int_values[i] = int_entries[i].default_value;
}
return index;
}
void elpa_free_index(elpa_index_t index) {
free(index->int_values);
free(index);
}
static int compar(const void *key, const void *member) {
const char *name = (const char *) key;
elpa_int_entry_t *entry = (elpa_int_entry_t *) member;
int l1 = strlen(entry->name);
int l2 = strlen(name);
if (l1 != l2) {
return 1;
}
if (strncmp(name, entry->name, l1) == 0) {
return 0;
} else {
return 1;
}
}
static int find_int_entry(elpa_index_t index, const char *name) {
elpa_int_entry_t *entry;
size_t nmembers = index->n_int_entries;
entry = lfind((const void*) name, (const void *) index->int_entries, &nmembers, sizeof(elpa_int_entry_t), compar);
if (entry) {
return (entry - &index->int_entries[0]);
} else {
return -1;
}
}
int elpa_get_int_entry(elpa_index_t index, const char *name, int *success) {
int n = find_int_entry(index, name);
if (n >= 0) {
if (success != NULL) {
*success = ELPA_OK;
}
return index->int_values[n];
} else {
if (success != NULL) {
*success = ELPA_ERROR;
} else {
fprintf(stderr, "ELPA: No such entry '%s' and you did not check for errors, returning ELPA_INVALID_INT!\n", name);
}
return ELPA_INVALID_INT;
}
}
int elpa_set_int_entry(elpa_index_t index, const char *name, int value) {
int n = find_int_entry(index, name);
int res = ELPA_ERROR;
if (n >= 0) {
res = index->int_entries[n].valid(index, value);
if (res == ELPA_OK) {
index->int_values[n] = value;
}
}
return res;
}
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
#include <elpa/elpa.h>
#define nelements(x) (sizeof(x)/sizeof(x[0]))
/* A simple structure for storing values to a pre-set
* number of keys */
/* Forward declaration of configuration structure */
typedef struct elpa_index_struct* elpa_index_t;
/* Function pointer type for the cardinality */
typedef int (*cardinality_t)();
/* Function pointer type to enumerate all possible values (if possible) */
typedef const int (*enumerate_int_option_t)(unsigned int n);
/* Function pointer type check validity of option */
typedef int (*valid_int_t)(elpa_index_t index, int value);
typedef struct {
const char *name;
int default_value;
cardinality_t cardinality;
enumerate_int_option_t enumerate_option;
valid_int_t valid;
} elpa_int_entry_t;
struct elpa_index_struct {
int n_int_entries;
int *int_values;
elpa_int_entry_t *int_entries;
};
elpa_index_t elpa_allocate_index(int n_entries, elpa_int_entry_t int_entries[n_entries]);
/*
!f> interface
!f> subroutine elpa_free_index(index) bind(C, name="elpa_free_index")
!f> import c_ptr
!f> type(c_ptr), value :: index
!f> end subroutine
!f> end interface
*/
void elpa_free_index(elpa_index_t index);
/*
!f> interface
!f> function elpa_get_int_entry(index, name, success) result(value) bind(C, name="elpa_get_int_entry")
!f> import c_ptr, c_int, c_char
!f> type(c_ptr), value :: index
!f> character(kind=c_char), intent(in) :: name(*)
!f> integer(kind=c_int) :: value
!f> integer(kind=c_int), optional :: success
!f> end function
!f> end interface
*/
int elpa_get_int_entry(elpa_index_t index, const char *name, int *success);
/*
!f> interface
!f> function elpa_set_int_entry(index, name, value) result(success) bind(C, name="elpa_set_int_entry")
!f> import c_ptr, c_int, c_char
!f> type(c_ptr), value :: index
!f> character(kind=c_char), intent(in) :: name(*)
!f> integer(kind=c_int),intent(in), value :: value
!f> integer(kind=c_int) :: success
!f> end function
!f> end interface
*/
int elpa_set_int_entry(elpa_index_t index, const char *name, int value);
// This file is part of ELPA.
//
// The ELPA library was originally created by the ELPA consortium,
// consisting of the following organizations:
//
// - Max Planck Computing and Data Facility (MPCDF), formerly known as
// Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
// - Bergische Universität Wuppertal, Lehrstuhl für angewandte
// Informatik,
// - Technische Universität München, Lehrstuhl für Informatik mit
// Schwerpunkt Wissenschaftliches Rechnen ,
// - Fritz-Haber-Institut, Berlin, Abt. Theorie,
// - Max-Plack-Institut für Mathematik in den Naturwissenschaften,
// Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
// and
// - IBM Deutschland GmbH
//
// This particular source code file contains additions, changes and
// enhancements authored by Intel Corporation which is not part of
// the ELPA consortium.
//
// More information can be found here:
// http://elpa.mpcdf.mpg.de/
//
// ELPA is free software: you can redistribute it and/or modify
// it under the terms of the version 3 of the license of the
// GNU Lesser General Public License as published by the Free
// Software Foundation.
//
// ELPA 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with ELPA. If not, see <http://www.gnu.org/licenses/>
//
// ELPA reflects a substantial effort on the part of the original
// ELPA consortium, and we ask you to respect the spirit of the
// license that we chose: i.e., please contribute any changes you
// may have back to the original ELPA library distribution, and keep
// any derivatives of ELPA under the same license that we chose for
// the original distribution, the GNU Lesser General Public License.
//
// Authors: L. Huedepohl and A. Marek, MPCDF
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
#include <elpa/elpa.h>
#define nelements(x) (sizeof(x)/sizeof(x[0]))
/* Incomplete forward declaration of configuration structure */
typedef struct elpa_options_struct* elpa_options_t;
/* Function pointer type for the cardinality */
typedef int (*cardinality_t)();
/* Function pointer type to enumerate all possible options */
typedef const int (*enumerate_int_option_t)(unsigned int n);
/* Function pointer type check validity of option */
typedef int (*valid_int_t)(elpa_options_t options, int value);
typedef struct {
const char *name;
int default_value;
cardinality_t cardinality;
enumerate_int_option_t enumerate_option;
valid_int_t valid;
} elpa_int_option_t;
/** OPTIONS **/
#include "elpa_index.h"
/* summary timings */
int summary_timings_cardinality() {
static int summary_timings_cardinality() {
return 2;
}
const int summary_timings_enumerate_option(unsigned int n) {
static const int summary_timings_enumerate_option(unsigned int n) {
return n;
}
int summary_timings_valid(elpa_options_t options, int value) {
static int summary_timings_valid(elpa_index_t options, int value) {
if (value >= 0 && value < summary_timings_cardinality()) {
return ELPA_OK;
} else {
......@@ -96,15 +19,15 @@ int summary_timings_valid(elpa_options_t options, int value) {
/* wantDebug */
int wantDebug_cardinality() {
static int wantDebug_cardinality() {
return 2;
}
const int wantDebug_enumerate_option(unsigned int n) {
static const int wantDebug_enumerate_option(unsigned int n) {
return n;
}
int wantDebug_valid(elpa_options_t options, int value) {
static int wantDebug_valid(elpa_index_t options, int value) {
if (value >= 0 && value < wantDebug_cardinality()) {
return ELPA_OK;
} else {
......@@ -113,15 +36,15 @@ int wantDebug_valid(elpa_options_t options, int value) {
}
/* QR */
int qr_cardinality() {
static int qr_cardinality() {
return 2;
}
const int qr_enumerate_option(unsigned int n) {
static const int qr_enumerate_option(unsigned int n) {
return n;
}
int qr_valid(elpa_options_t options, int value) {
static int qr_valid(elpa_index_t options, int value) {
if (value >= 0 && value < qr_cardinality()) {
return ELPA_OK;
} else {
......@@ -130,15 +53,15 @@ int qr_valid(elpa_options_t options, int value) {
}
/* GPU */
int gpu_cardinality() {
static int gpu_cardinality() {
return 2;
}
const int gpu_enumerate_option(unsigned int n) {
static const int gpu_enumerate_option(unsigned int n) {
return n;
}
int gpu_valid(elpa_options_t options, int value) {
static int gpu_valid(elpa_index_t options, int value) {
if (value >= 0 && value < gpu_cardinality()) {
return ELPA_OK;
} else {
......@@ -147,15 +70,15 @@ int gpu_valid(elpa_options_t options, int value) {
}
/* Solver */
int solver_cardinality() {
static int solver_cardinality() {
return ELPA_NUMBER_OF_SOLVERS;
}
const int solver_enumerate_option(unsigned int n) {
static const int solver_enumerate_option(unsigned int n) {
return n+1;
}
int solver_valid(elpa_options_t options, int value) {
static int solver_valid(elpa_index_t options, int value) {
if (value >= 1 && value <= solver_cardinality()) {
return ELPA_OK;
} else {
......@@ -165,15 +88,15 @@ int solver_valid(elpa_options_t options, int value) {
/* Real Kernel */
int real_kernel_cardinality() {
static int real_kernel_cardinality() {
return ELPA_2STAGE_NUMBER_OF_REAL_KERNELS;
}
const int real_kernel_enumerate_option(unsigned int n) {
static const int real_kernel_enumerate_option(unsigned int n) {
return n+1;
}
int real_kernel_valid(elpa_options_t options, int value) {
static int real_kernel_valid(elpa_index_t options, int value) {
if (value >= 1 && value <= real_kernel_cardinality()) {
return ELPA_OK;
} else {
......@@ -183,15 +106,15 @@ int real_kernel_valid(elpa_options_t options, int value) {
/* Complex Kernel */
int complex_kernel_cardinality() {
static int complex_kernel_cardinality() {
return ELPA_2STAGE_NUMBER_OF_COMPLEX_KERNELS;
}
const int complex_kernel_enumerate_option(unsigned int n) {
static const int complex_kernel_enumerate_option(unsigned int n) {
return n+1;
}
int complex_kernel_valid(elpa_options_t options, int value) {
static int complex_kernel_valid(elpa_index_t options, int value) {
if (value >= 1 && value <= complex_kernel_cardinality()) {
return ELPA_OK;
} else {
......@@ -201,8 +124,7 @@ int complex_kernel_valid(elpa_options_t options, int value) {
/** END OF OPTIONS **/
elpa_int_option_t elpa_int_options[] = {
static elpa_int_entry_t elpa_int_options[] = {
{"summary_timings", 0, summary_timings_cardinality, summary_timings_enumerate_option, summary_timings_valid},
{"wantDebug", 0, wantDebug_cardinality, wantDebug_enumerate_option, wantDebug_valid},
{"qr", 0, qr_cardinality, qr_enumerate_option, qr_valid},
......@@ -212,75 +134,14 @@ elpa_int_option_t elpa_int_options[] = {
{"complex_kernel", ELPA_2STAGE_COMPLEX_DEFAULT, complex_kernel_cardinality, complex_kernel_enumerate_option, complex_kernel_valid},
};
struct elpa_options_struct {
int int_options[nelements(elpa_int_options)];
};
elpa_options_t elpa_allocate_options() {
elpa_options_t options = (elpa_options_t) calloc(1, sizeof(struct elpa_options_struct));
int i;
for (i = 0; i < nelements(elpa_int_options); i++) {
options->int_options[i] = elpa_int_options[i].default_value;
}
return options;
}
void elpa_free_options(elpa_options_t options) {
free(options);
}
int compar(const void *key, const void *member) {
const char *name = (const char *) key;
elpa_int_option_t *option = (elpa_int_option_t *) member;
int l1 = strlen(option->name);
int l2 = strlen(name);
if (l1 != l2) {
return 1;
}
if (strncmp(name, option->name, l1) == 0) {
return 0;
} else {
return 1;
}
}
int find_int_option(const char *name) {
elpa_int_option_t *option;
size_t nmembers = nelements(elpa_int_options);
option = lfind((const void*) name, (const void *) &elpa_int_options, &nmembers, sizeof(elpa_int_option_t), compar);
if (option) {
return (option - &elpa_int_options[0]);
} else {
return -1;
}
}
int get_int_option(elpa_options_t options, const char *name, int *success) {
int n = find_int_option(name);
if (n >= 0) {
if (success != NULL) {
*success = ELPA_OK;
}
return options->int_options[n];
} else {
if (success != NULL) {
*success = ELPA_ERROR;
} else {
fprintf(stderr, "ELPA: No such option '%s' and you did not check for errors, returning ELPA_INVALID_INT!\n", name);
}
return ELPA_INVALID_INT;
}
}
int set_int_option(elpa_options_t options, const char *name, int value) {
int n = find_int_option(name);
int res = ELPA_ERROR;
if (n >= 0) {
res = elpa_int_options[n].valid(options, value);
if (res == ELPA_OK) {
options->int_options[n] = value;
}
}
return res;
/*
!f> interface
!f> function elpa_allocate_options() result(options) bind(C, name="elpa_allocate_options")
!f> import c_ptr
!f> type(c_ptr) :: options
!f> end function
!f> end interface
*/
elpa_index_t elpa_allocate_options() {
elpa_index_t options = elpa_allocate_index(nelements(elpa_int_options), elpa_int_options);
}
......@@ -179,47 +179,8 @@ module elpa_type
integer, parameter :: earliest_api_version = 20170403
integer, parameter :: current_api_version = 20170403
interface
function elpa_allocate_options() result(options) bind(C, name="elpa_allocate_options")
import c_ptr
type(c_ptr) :: options
end function
end interface
interface
subroutine elpa_free_options(options) bind(C, name="elpa_free_options")
import c_ptr
type(c_ptr), value :: options
end subroutine
end interface
interface
function get_int_option(options, name, success) result(value) bind(C, name="get_int_option")
import c_ptr, c_char, c_int
type(c_ptr), value :: options
character(kind=c_char), intent(in) :: name(*)
integer(kind=c_int) :: value
integer(kind=c_int), optional :: success
end function
end interface
interface
function set_int_option(options, name, value) result(success) bind(C, name="set_int_option")
import c_ptr, c_char, c_int
type(c_ptr), value :: options
character(kind=c_char), intent(in) :: name(*)
integer(kind=c_int), intent(in), value :: value
integer(kind=c_int) :: success
end function
end interface
contains
function elpa_init(api_version) result(success)
use elpa_utilities, only : error_unit
implicit none
......@@ -252,6 +213,7 @@ module elpa_type
use elpa_mpi
use elpa_utilities, only : error_unit
use elpa1_impl, only : elpa_get_communicators_impl
use elpa_generated_fortran_interfaces
implicit none
integer(kind=ik), intent(in) :: na, nev, local_nrows, local_ncols, nblk
......@@ -298,6 +260,7 @@ module elpa_type
use elpa_mpi
use elpa_utilities, only : error_unit
use elpa1_impl, only : elpa_get_communicators_impl
use elpa_generated_fortran_interfaces
implicit none
integer(kind=ik), intent(in) :: na, nev, local_nrows, local_ncols, nblk
......@@ -348,6 +311,7 @@ module elpa_type
subroutine elpa_set_integer(self, name, value, success)
use iso_c_binding
use elpa_generated_fortran_interfaces
use elpa_utilities, only : error_unit
implicit none
class(elpa_t) :: self
......@@ -356,7 +320,7 @@ module elpa_type
integer, optional :: success
integer :: actual_success
actual_success = set_int_option(self%options, name // c_null_char, value)
actual_success = elpa_set_int_entry(self%options, name // c_null_char, value)
if (present(success)) then
success = actual_success
......@@ -371,6 +335,7 @@ module elpa_type
function elpa_get_integer(self, name, success) result(value)