Commit ff0b6ea4 authored by Swann Perarnau's avatar Swann Perarnau
Browse files

Merge branch 'replicaset' into 'staging'

[feature] High-level block: Replicaset

See merge request !153
parents 3d3c42c2 bdf85141
Pipeline #11294 passed with stages
in 4 minutes and 35 seconds
......@@ -795,7 +795,6 @@ INPUT = ../include \
../include/aml/layout \
../include/aml/tiling \
../include/aml/dma \
../include/aml/scratch \
../include/aml/utils \
../CONTRIBUTING.markdown
......
AM_COLOR_TESTS = yes
AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS)
AM_LDFLAGS = $(top_builddir)/src/libaml.la $(top_builddir)/excit/src/libexcit.la $(PTHREAD_LIBS)
AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS) $(OPENMP_CFLAGS)
AM_LDFLAGS = $(top_builddir)/src/libaml.la $(top_builddir)/excit/src/libexcit.la $(PTHREAD_LIBS) $(OPENMP_CFLAGS)
if HAVE_CUDA
# LIBS is used instead of AM_LDFLAGS on purpose
......
......@@ -3,6 +3,9 @@ include_HEADERS=aml.h
include_aml_areadir=$(includedir)/aml/area
include_aml_area_HEADERS = aml/area/linux.h
include_aml_replicasetdir=$(includedir)/aml/higher/replicaset
include_aml_replicaset_HEADERS = aml/higher/replicaset.h
include_aml_layoutdir=$(includedir)/aml/layout
include_aml_layout_HEADERS = \
aml/layout/native.h \
......@@ -35,6 +38,7 @@ include_amlutils_HEADERS = \
if HAVE_HWLOC
include_aml_area_HEADERS+= aml/area/hwloc.h
include_aml_replicaset_HEADERS += aml/higher/replicaset/hwloc.h
endif
if HAVE_CUDA
......
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/
#ifndef __AML_HIGHER_REPLICASET_H_
#define __AML_HIGHER_REPLICASET_H_
/**
* @}
* @defgroup aml_replicaset "AML Replicaset"
* @brief Maintain a copy of a data in several areas.
*
* Replicaset is a building block on top of areas and dmas to
* maintain a manage coherency of several copies of a data in several areas.
* @{
**/
// Implementation specific data held in abstract replicaset.
struct aml_replicaset_data;
// Replicaset required methods. See below
struct aml_replicaset_ops;
/**
* High level replicaset structure.
* See specific implementations for instanciation.
*/
struct aml_replicaset {
/** Number of replicas **/
unsigned int n;
/** Size of a single replica **/
size_t size;
/** Pointers to replicated data **/
void **replica;
/** Replicaset methods **/
struct aml_replicaset_ops *ops;
/** Replicaset implementation spepcific data **/
struct aml_replicaset_data *data;
};
/**
* aml_area_ops is a structure containing implementations
* of area operations.
* Users may create or modify implementations by assembling
* appropriate operations in such a structure.
**/
struct aml_replicaset_ops {
/**
* Initialize replicas of a replicaset with some data.
* @param replicaset[in]: The replicaset holding copies.
* @param data[in]: The data to copy.
* @param size[in]: The size of data top copy.
* @param dma[in]: An array of copy functions to copy original data to
*each replica.
* @return A negative AML error code.
**/
int (*init)(struct aml_replicaset *replicaset, const void *data);
/**
* Copy the content of a specific replica into other replicas.
* @param replicaset[in]: The replicaset holding copies.
* @param id[in]: The index of the replica holding data to copy.
* @return An AML error code.
**/
int (*sync)(struct aml_replicaset *replicaset, const unsigned int id);
};
/**
* @see struct aml_replicaset_ops->init()
*/
int aml_replicaset_init(struct aml_replicaset *replicaset, const void *data);
/**
* @see struct aml_replicaset_ops->sync()
*/
int aml_replicaset_sync(struct aml_replicaset *replicaset,
const unsigned int id);
#endif // __AML_HIGHER_REPLICASET_H_
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
#ifndef __AML_HIGHER_REPLICASET_HWLOC_H__
#define __AML_HIGHER_REPLICASET_HWLOC_H__
#include <hwloc.h>
/**
* @defgroup aml_replicaset_hwloc "AML Replicaset hwloc"
* @brief Build a topology aware replicaset on host processor
* using hwloc backend.
*
* Replicas are created using a specific performance criterion.
* Such performance is defined relatively to a set of initiators
* (i.e topology object containing a cpuset) and a set of
* NUMA nodes. For instance it is possible to create a replicaset
* such that initiators can query pointers into relative memory with
* lowest latency or highest bandwidth.
*
* #include <aml/higher/replicaset/hwloc.h>
* @see <hwloc.h>
* @{
**/
/**
* Inner data implementation of replicaset for hwloc backend.
*/
struct aml_replicaset_hwloc_data {
/** The type of object used as initiator. */
hwloc_obj_type_t type;
/** Number of initiators */
unsigned num_ptr;
/**
* Array of pointers to replica.
* Contains one pointer per initiator of the topology.
* Pointers or arranged per initiator logical index.
*/
void **ptr;
};
/** Public methods struct for aml_replicaset_hwloc */
extern struct aml_replicaset_ops aml_replicaset_hwloc_ops;
/**
* Create data stored in generic replicaset structure.
* @param out[out]: A pointer where to allocate the replicaset.
* @param size[in]: Size of replicas in bytes.
* @param initiator_type[in]: One replica per initiator of this type will be
* be created. Initiators must have a non empty cpuset.
* @param kind[in]: A the kind of distance in topology to use. The NUMANODEs
* maximizing performance for the criterion will be used for allocating
*replicas.
* @return -AML_ENOMEM if there was not enough memory to satisfy this call.
* @return -AML EINVAL if initiators does not contain a cpuset.
**/
int aml_replicaset_hwloc_create(struct aml_replicaset **out,
const size_t size,
const hwloc_obj_type_t initiator_type,
const enum hwloc_distances_kind_e kind);
/**
* Destroy hwloc replicaset data.
* @param replicaset: The data to destroy. It is set to NULL after destruction.
**/
void aml_replicaset_hwloc_destroy(struct aml_replicaset **replicaset);
/**
* Copy source data to replicas. Uses memcpy. If openmp is available,
* the copy is parallel.
* @param replicaset[in]: The replicaset where copies are run.
* @param data[in]: The source data used copy.
* @return AML_SUCCESS. Arguments check is performed in the wrapper.
**/
int aml_replicaset_hwloc_init(struct aml_replicaset *replicaset,
const void *data);
/**
* Copy data from one replica to the others.
* If openmp is available, the copy is parallel.
* @param replicaset[in]: The replicaset where copies are run.
* @param id[in]: The replica index used as source of the copy.
* @return AML_SUCCESS. Arguments check is performed in the wrapper.
**/
int aml_replicaset_hwloc_sync(struct aml_replicaset *replicaset,
const unsigned int id);
/**
* Get the replica local to calling thread.
* @param replicaset[in]: The replicaset used to retrieve a replica.
* @return A replica pointer local to calling thread.
* @return NULL if calling thread is not bound.
* @return NULL if calling thread binding is larger than replicaset initiator.
* @return NULL if no memory were available to allocate a cpuset.
*/
void *aml_replicaset_hwloc_local_replica(struct aml_replicaset *replicaset);
/**
* @}
**/
#endif // __AML_HIGHER_REPLICASET_HWLOC_H__
SUFFIXES=.c .cu
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS)
AM_LDFLAGS = $(PTHREAD_LIBS)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS) $(OPENMP_CFLAGS)
AM_LDFLAGS = $(PTHREAD_LIBS) $(OPENMP_CFLAGS)
noinst_LTLIBRARIES=
#############################################
......@@ -39,12 +39,15 @@ UTILS_SOURCES = \
utils/async.c \
utils/features.c
REPLICASET_SOURCES = replicaset/replicaset.c
LIB_SOURCES = \
$(AREA_SOURCES) \
$(DMA_SOURCES) \
$(TILING_SOURCES) \
$(LAYOUT_SOURCES) \
$(UTILS_SOURCES) \
$(REPLICASET_SOURCES) \
aml.c
lib_LTLIBRARIES = libaml.la
......@@ -86,5 +89,5 @@ if HAVE_HWLOC
AM_CPPFLAGS += $(HWLOC_CFLAGS)
AM_LDFLAGS += $(HWLOC_LIBS)
libaml_la_SOURCES+=area/hwloc.c
libaml_la_SOURCES+=area/hwloc.c replicaset/hwloc.c
endif
......@@ -269,10 +269,10 @@ void *aml_area_hwloc_preferred_mmap(const struct aml_area_data *area_data,
(struct aml_area_hwloc_preferred_data *)area_data;
// Allocate data
void *ptr =
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == NULL) {
if (ptr == NULL || ptr == MAP_FAILED) {
aml_errno = AML_ENOMEM;
return NULL;
}
......@@ -777,12 +777,10 @@ int aml_area_hwloc_preferred_create(struct aml_area **area,
return AML_SUCCESS;
}
int aml_area_hwloc_preferred_local_create(struct aml_area **area,
enum hwloc_distances_kind_e kind)
int aml_hwloc_local_initiator(hwloc_obj_t *out)
{
int err;
hwloc_cpuset_t cpuset;
hwloc_obj_t initiator;
/** Collect cpuset binding of current thread **/
cpuset = hwloc_bitmap_alloc();
......@@ -797,22 +795,35 @@ int aml_area_hwloc_preferred_local_create(struct aml_area **area,
}
/** Match cpuset with a location on machine **/
err = hwloc_get_largest_objs_inside_cpuset(aml_topology, cpuset,
&initiator, 1);
err = hwloc_get_largest_objs_inside_cpuset(aml_topology, cpuset, out,
1);
if (err == -1) {
err = -AML_FAILURE;
goto err_with_cpuset;
}
hwloc_bitmap_free(cpuset);
/** Build area with found initiator **/
return aml_area_hwloc_preferred_create(area, initiator, kind);
hwloc_bitmap_free(cpuset);
return AML_SUCCESS;
err_with_cpuset:
hwloc_bitmap_free(cpuset);
return err;
}
int aml_area_hwloc_preferred_local_create(struct aml_area **area,
enum hwloc_distances_kind_e kind)
{
int err;
hwloc_obj_t initiator;
err = aml_hwloc_local_initiator(&initiator);
if (err != AML_SUCCESS)
return err;
/** Build area with found initiator **/
return aml_area_hwloc_preferred_create(area, initiator, kind);
}
struct aml_area_ops aml_area_hwloc_preferred_ops = {
.mmap = aml_area_hwloc_preferred_mmap,
.munmap = aml_area_hwloc_preferred_munmap,
......
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/
#include "aml.h"
#include "aml/area/hwloc.h"
#include "aml/higher/replicaset.h"
#include "aml/higher/replicaset/hwloc.h"
extern hwloc_topology_t aml_topology;
int aml_replicaset_hwloc_alloc(struct aml_replicaset **out,
const hwloc_obj_type_t initiator_type)
{
struct aml_replicaset *replicaset = NULL;
struct aml_replicaset_hwloc_data *data = NULL;
// Check initiator type.
const unsigned int n_initiator =
hwloc_get_nbobjs_by_type(aml_topology, initiator_type);
hwloc_obj_t initiator =
hwloc_get_obj_by_type(aml_topology, initiator_type, 0);
if (n_initiator == 0)
return -AML_EDOM;
if (initiator == NULL || initiator->cpuset == NULL ||
hwloc_bitmap_weight(initiator->cpuset) <= 0)
return -AML_EINVAL;
const unsigned int n_numa =
hwloc_get_nbobjs_by_type(aml_topology, HWLOC_OBJ_NUMANODE);
// Allocation
replicaset = AML_INNER_MALLOC_ARRAY(n_numa + n_initiator, void *,
struct aml_replicaset,
struct aml_replicaset_hwloc_data);
if (replicaset == NULL)
return -AML_ENOMEM;
// Set ops
replicaset->ops = &aml_replicaset_hwloc_ops;
// Set data
replicaset->data =
(struct aml_replicaset_data *)AML_INNER_MALLOC_GET_FIELD(
replicaset, 2, struct aml_replicaset,
struct aml_replicaset_hwloc_data);
data = (struct aml_replicaset_hwloc_data *)replicaset->data;
// Set replica pointers array
replicaset->replica = (void **)AML_INNER_MALLOC_GET_ARRAY(
replicaset, void *, struct aml_replicaset,
struct aml_replicaset_hwloc_data);
for (unsigned i = 0; i < n_numa; i++)
replicaset->replica[i] = NULL;
// Set initiator pointers array
data->ptr = replicaset->replica + n_numa;
// Set number of initiators
data->num_ptr = n_initiator;
// Set number of replicas to 0. Initialization will set
// it to the correct value.
replicaset->n = 0;
*out = replicaset;
return AML_SUCCESS;
}
int aml_replicaset_hwloc_create(struct aml_replicaset **out,
const size_t size,
const hwloc_obj_type_t initiator_type,
const enum hwloc_distances_kind_e kind)
{
int err = -AML_FAILURE;
struct aml_replicaset *replicaset = NULL;
struct aml_replicaset_hwloc_data *data = NULL;
struct aml_area *area = NULL;
struct aml_area_hwloc_preferred_data *area_data = NULL;
const unsigned int n_numa =
hwloc_get_nbobjs_by_type(aml_topology, HWLOC_OBJ_NUMANODE);
hwloc_obj_t targets[n_numa];
err = aml_replicaset_hwloc_alloc(&replicaset, initiator_type);
if (err != AML_SUCCESS)
return err;
replicaset->size = size;
data = (struct aml_replicaset_hwloc_data *)replicaset->data;
// For each initiator allocate replica on preferred area
for (hwloc_obj_t initiator =
hwloc_get_obj_by_type(aml_topology, initiator_type, 0);
initiator != NULL; initiator = initiator->next_cousin) {
// Get preferred area.
err = aml_area_hwloc_preferred_create(&area, initiator, kind);
if (err != AML_SUCCESS)
goto err_with_replicaset;
area_data = (struct aml_area_hwloc_preferred_data *)area->data;
// Search if preferred numa node is already a target
for (unsigned i = 0; i < replicaset->n; i++) {
if (targets[i] == area_data->numanodes[0]) {
data->ptr[initiator->logical_index] =
replicaset->replica[i];
goto next;
}
}
// Preferred numa node is not a target yet.
void *ptr = aml_area_mmap(area, size, NULL);
if (ptr == NULL) {
err = -AML_ENOMEM;
goto err_with_replicas;
}
replicaset->replica[replicaset->n] = ptr;
data->ptr[initiator->logical_index] = ptr;
targets[replicaset->n] = area_data->numanodes[0];
replicaset->n++;
next:
// Area cleanup
aml_area_hwloc_preferred_destroy(&area);
}
// Success
*out = replicaset;
return AML_SUCCESS;
// Failure
err_with_replicas:
for (unsigned i = 0; i < replicaset->n; i++)
munmap(replicaset->replica[i], size);
err_with_replicaset:
free(replicaset);
return err;
}
void aml_replicaset_hwloc_destroy(struct aml_replicaset **replicaset)
{
if (replicaset == NULL || *replicaset == NULL)
return;
for (unsigned int i = 0; i < (*replicaset)->n; i++)
munmap((*replicaset)->replica[i], (*replicaset)->size);
free(*replicaset);
*replicaset = NULL;
}
int aml_replicaset_hwloc_init(struct aml_replicaset *replicaset,
const void *data)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (unsigned i = 0; i < replicaset->n; i++)
memcpy(replicaset->replica[i], data, replicaset->size);
return AML_SUCCESS;
}
int aml_replicaset_hwloc_sync(struct aml_replicaset *replicaset,
const unsigned int id)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (unsigned i = 0; i < replicaset->n; i++)
if (i != id)
memcpy(replicaset->replica[i], replicaset->replica[id],
replicaset->size);
return AML_SUCCESS;
}
// See src/area/hwloc.c
int aml_hwloc_local_initiator(hwloc_obj_t *out);
void *aml_replicaset_hwloc_local_replica(struct aml_replicaset *replicaset)
{
int err;
hwloc_obj_t initiator;
struct aml_replicaset_hwloc_data *data = NULL;
data = (struct aml_replicaset_hwloc_data *)replicaset->data;
err = aml_hwloc_local_initiator(&initiator);
if (err != AML_SUCCESS)
return NULL;
while (initiator != NULL &&
hwloc_get_nbobjs_by_depth(aml_topology, initiator->depth) >
replicaset->n)
initiator = initiator->parent;
if (initiator == NULL)
return NULL;
if (hwloc_get_nbobjs_by_depth(aml_topology, initiator->depth) <
data->num_ptr)
return NULL;
return data->ptr[initiator->logical_index];
}
struct aml_replicaset_ops aml_replicaset_hwloc_ops = {
.init = aml_replicaset_hwloc_init,
.sync = aml_replicaset_hwloc_sync,
};
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/
#include "aml.h"
#include "aml/higher/replicaset.h"
int aml_replicaset_init(struct aml_replicaset *replicaset, const void *data)
{
if (replicaset == NULL || data == NULL)
return -AML_EINVAL;
if (replicaset->ops->init == NULL)
return -AML_ENOTSUP;
return replicaset->ops->init(replicaset, data);
}
int aml_replicaset_sync(struct aml_replicaset *replicaset,
const unsigned int id)
{
if (replicaset == NULL)
return -AML_EINVAL;
if (replicaset->ops->sync == NULL)
return -AML_ENOTSUP;
return replicaset->ops->sync(replicaset, id);
}
AM_COLOR_TESTS = yes
AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS)
AM_LDFLAGS = ../src/libaml.la $(top_builddir)/excit/src/libexcit.la $(PTHREAD_LIBS)
AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/excit/src $(PTHREAD_CFLAGS) $(OPENMP_CFLAGS)
AM_LDFLAGS = ../src/libaml.la $(top_builddir)/excit/src/libexcit.la $(PTHREAD_LIBS) $(OPENMP_CFLAGS)
if HAVE_CUDA
# LIBS is used instead of AM_LDFLAGS on purpose
......@@ -60,6 +60,8 @@ TILING_TESTS = tiling/test_tiling
DMA_TESTS = dma/test_dma_linux_seq \
dma/test_dma_linux_par
REPLICASET_TESTS =
if HAVE_CUDA
AREA_TESTS += area/test_cuda
DMA_TESTS += dma/test_cuda
......@@ -67,6 +69,7 @@ endif
if HAVE_HWLOC
AREA_TESTS += area/test_hwloc
REPLICASET_TESTS += replicaset/test_hwloc
endif
# unit tests
......@@ -75,6 +78,7 @@ UNIT_TESTS = $(UTILS_TESTS) \
$(LAYOUT_TESTS) \
$(BINDING_TESTS) \
$(AREA_TESTS) \
$(REPLICASET_TESTS) \
$(DMA_TESTS)
# all tests
......
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/