Commit bcb6c923 authored by Swann Perarnau's avatar Swann Perarnau

[feature] Add initial tiling and binding support

Implement 1d tiling and simple binding support. The idea is to allow
an application to explain the AML how data should be organized, and to
be able to reuse this info when dealing with memory movement.

The current interfaces are not great, but they work.
parent 000e11d1
...@@ -21,7 +21,7 @@ AC_PROG_CC ...@@ -21,7 +21,7 @@ AC_PROG_CC
AC_PROG_CC_STDC AC_PROG_CC_STDC
AC_PROG_CPP AC_PROG_CPP
AC_TYPE_SIZE_T AC_TYPE_SIZE_T
AC_TYPE_INTPTR_T
# support for testing with valgrind # support for testing with valgrind
AC_ARG_ENABLE(valgrind, AC_ARG_ENABLE(valgrind,
......
...@@ -10,10 +10,19 @@ AREA_LINUX_CSOURCES = area_linux.c \ ...@@ -10,10 +10,19 @@ AREA_LINUX_CSOURCES = area_linux.c \
AREA_POSIX_CSOURCES = area_posix.c AREA_POSIX_CSOURCES = area_posix.c
TILING_CSOURCES = tiling.c tiling_1d.c
BINDING_CSOURCES = binding.c \
binding_single.c \
binding_interleave.c
LIBCSOURCES = aml.c area.c arena.c \ LIBCSOURCES = aml.c area.c arena.c \
$(ARENA_JEMALLOC_CSOURCES) \ $(ARENA_JEMALLOC_CSOURCES) \
$(AREA_LINUX_CSOURCES) \ $(AREA_LINUX_CSOURCES) \
$(AREA_POSIX_CSOURCES) $(AREA_POSIX_CSOURCES) \
$(TILING_CSOURCES) \
$(BINDING_CSOURCES)
LIBHSOURCES = aml.h LIBHSOURCES = aml.h
libaml_la_SOURCES = $(LIBCSOURCES) $(LIBHSOURCES) libaml_la_SOURCES = $(LIBCSOURCES) $(LIBHSOURCES)
......
#ifndef AML_H #ifndef AML_H
#define AML_H 1 #define AML_H 1
#include <numa.h> #include <inttypes.h>
#include <memkind.h> #include <memkind.h>
#include <numa.h>
#include <numaif.h>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/******************************************************************************* /*******************************************************************************
* Forward Declarations: * Forward Declarations:
...@@ -121,6 +134,13 @@ int aml_area_linux_manager_single_destroy(struct aml_area_linux_manager_data *); ...@@ -121,6 +134,13 @@ int aml_area_linux_manager_single_destroy(struct aml_area_linux_manager_data *);
#define AML_NODEMASK_BYTES (AML_MAX_NUMA_NODES/8) #define AML_NODEMASK_BYTES (AML_MAX_NUMA_NODES/8)
#define AML_NODEMASK_SZ (AML_NODEMASK_BYTES/sizeof(unsigned long)) #define AML_NODEMASK_SZ (AML_NODEMASK_BYTES/sizeof(unsigned long))
#define AML_NODEMASK_NBITS (8*sizeof(unsigned long))
#define AML_NODEMASK_ELT(i) ((i) / AML_NODEMASK_NBITS)
#define AML_NODEMASK_BITMASK(i) ((unsigned long)1 << ((i) % AML_NODEMASK_NBITS))
#define AML_NODEMASK_ISSET(mask, i) \
((mask[AML_NODEMASK_ELT(i)] & AML_NODEMASK_BITMASK(i)) != 0)
struct aml_area_linux_mbind_data { struct aml_area_linux_mbind_data {
unsigned long nodemask[AML_NODEMASK_SZ]; unsigned long nodemask[AML_NODEMASK_SZ];
int policy; int policy;
...@@ -224,6 +244,189 @@ int aml_dma_move(struct aml_dma *, struct aml_area *, struct aml_area *, ...@@ -224,6 +244,189 @@ int aml_dma_move(struct aml_dma *, struct aml_area *, struct aml_area *,
void *, size_t); void *, size_t);
/*******************************************************************************
* Tiling:
* Representation of a data structure organization in memory.
******************************************************************************/
/* opaque handle to all tilings */
struct aml_tiling_data;
struct aml_tiling_iterator_data;
/*forward declarations */
struct aml_tiling_iterator_ops;
struct aml_tiling_iterator;
struct aml_tiling_ops {
int (*create_iterator)(struct aml_tiling_data *,
struct aml_tiling_iterator **, int);
int (*init_iterator)(struct aml_tiling_data *,
struct aml_tiling_iterator *, int);
int (*destroy_iterator)(struct aml_tiling_data *,
struct aml_tiling_iterator *);
size_t (*tilesize)(struct aml_tiling_data *, va_list);
void* (*tilestart)(struct aml_tiling_data *, void *, va_list);
};
struct aml_tiling {
struct aml_tiling_ops *ops;
struct aml_tiling_data *data;
};
size_t aml_tiling_tilesize(struct aml_tiling *, ...);
size_t aml_tiling_vtilesize(struct aml_tiling *, va_list);
void* aml_tiling_tilestart(struct aml_tiling *, void *, ...);
void* aml_tiling_vtilestart(struct aml_tiling *, void *, va_list);
int aml_tiling_create_iterator(struct aml_tiling *,
struct aml_tiling_iterator **, int);
int aml_tiling_init_iterator(struct aml_tiling *,
struct aml_tiling_iterator *, int);
int aml_tiling_destroy_iterator(struct aml_tiling *,
struct aml_tiling_iterator *);
struct aml_tiling_iterator_ops {
int (*reset)(struct aml_tiling_iterator_data *);
int (*next)(struct aml_tiling_iterator_data *);
int (*end)(struct aml_tiling_iterator_data *);
int (*get)(struct aml_tiling_iterator_data *, va_list);
};
struct aml_tiling_iterator {
struct aml_tiling_iterator_ops *ops;
struct aml_tiling_iterator_data *data;
};
int aml_tiling_iterator_reset(struct aml_tiling_iterator *);
int aml_tiling_iterator_next(struct aml_tiling_iterator *);
int aml_tiling_iterator_end(struct aml_tiling_iterator *);
int aml_tiling_iterator_get(struct aml_tiling_iterator *, ...);
#define AML_TILING_TYPE_1D 0
int aml_tiling_create(struct aml_tiling **, int type, ...);
int aml_tiling_init(struct aml_tiling *, int type, ...);
int aml_tiling_vinit(struct aml_tiling *, int type, va_list);
int aml_tiling_destroy(struct aml_tiling *, int type);
/*******************************************************************************
* Tiling 1D:
******************************************************************************/
extern struct aml_tiling_ops aml_tiling_1d_ops;
extern struct aml_tiling_iterator_ops aml_tiling_iterator_1d_ops;
struct aml_tiling_1d_data {
size_t blocksize;
size_t totalsize;
};
struct aml_tiling_iterator_1d_data {
size_t i;
struct aml_tiling_1d_data *tiling;
};
#define AML_TILING_1D_DECL(name) \
struct aml_tiling_1d_data __ ##name## _inner_data; \
struct aml_tiling name = { \
&aml_tiling_1d_ops, \
(struct aml_tiling_data *)&__ ## name ## _inner_data, \
};
#define AML_TILING_ITERATOR_1D_DECL(name) \
struct aml_tiling_iterator_1d_data __ ##name## _inner_data; \
struct aml_tiling_iterator name = { \
&aml_tiling_iterator_1d_ops, \
(struct aml_tiling_iterator_data *)&__ ## name ## _inner_data, \
};
#define AML_TILING_1D_ALLOCSIZE (sizeof(struct aml_tiling_1d_data) + \
sizeof(struct aml_tiling))
#define AML_TILING_ITERATOR_1D_ALLOCSIZE \
(sizeof(struct aml_tiling_iterator_1d_data) + \
sizeof(struct aml_tiling_iterator))
/*******************************************************************************
* Binding:
* Representation of page bindings in an area
******************************************************************************/
/* opaque handle to all bindings */
struct aml_binding_data;
struct aml_binding_ops {
int (*nbpages)(struct aml_binding_data *, struct aml_tiling *,
void *, va_list);
int (*pages)(struct aml_binding_data *, void **, struct aml_tiling *,
void *, va_list);
int (*nodes)(struct aml_binding_data *, int *, struct aml_tiling *,
void *, va_list);
};
struct aml_binding {
struct aml_binding_ops *ops;
struct aml_binding_data *data;
};
int aml_binding_nbpages(struct aml_binding *, struct aml_tiling *, void*, ...);
int aml_binding_pages(struct aml_binding *, void **, struct aml_tiling *, void*, ...);
int aml_binding_nodes(struct aml_binding *, int *, struct aml_tiling *, void *, ...);
#define AML_BINDING_TYPE_SINGLE 0
#define AML_BINDING_TYPE_INTERLEAVE 1
int aml_binding_create(struct aml_binding **, int type, ...);
int aml_binding_init(struct aml_binding *, int type, ...);
int aml_binding_vinit(struct aml_binding *, int type, va_list);
int aml_binding_destroy(struct aml_binding *, int type);
/*******************************************************************************
* Single Binding:
* All pages on the same node
******************************************************************************/
extern struct aml_binding_ops aml_binding_single_ops;
struct aml_binding_single_data {
int node;
};
#define AML_BINDING_SINGLE_DECL(name) \
struct aml_binding_single_data __ ##name## _inner_data; \
struct aml_binding name = { \
&aml_binding_single_ops, \
(struct aml_binding_data *)&__ ## name ## _inner_data, \
};
#define AML_BINDING_SINGLE_ALLOCSIZE (sizeof(struct aml_binding_single_data) + \
sizeof(struct aml_binding))
/*******************************************************************************
* Interleave Binding:
* each page, of each tile, interleaved across nodes.
******************************************************************************/
extern struct aml_binding_ops aml_binding_interleave_ops;
struct aml_binding_interleave_data {
int nodes[AML_MAX_NUMA_NODES];
int count;
};
#define AML_BINDING_INTERLEAVE_DECL(name) \
struct aml_binding_interleave_data __ ##name## _inner_data; \
struct aml_binding name = { \
&aml_binding_interleave_ops, \
(struct aml_binding_data *)&__ ## name ## _inner_data, \
};
#define AML_BINDING_INTERLEAVE_ALLOCSIZE \
(sizeof(struct aml_binding_interleave_data) + \
sizeof(struct aml_binding))
/******************************************************************************* /*******************************************************************************
* General functions: * General functions:
* Initialize internal structures, cleanup everything at the end. * Initialize internal structures, cleanup everything at the end.
......
#include <assert.h> #include <assert.h>
#include <aml.h> #include <aml.h>
#include <jemalloc/jemalloc-aml.h> #include <jemalloc/jemalloc-aml.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/mman.h> #include <sys/mman.h>
/******************************************************************************* /*******************************************************************************
......
#include <aml.h>
#include <assert.h>
/*******************************************************************************
* Binding functions
* Most of the stuff is dispatched to a different layer, using type-specific
* functions.
******************************************************************************/
int aml_binding_nbpages(struct aml_binding *binding,
struct aml_tiling *tiling, void *ptr, ...)
{
assert(binding != NULL);
assert(tiling != NULL);
va_list ap;
int ret;
va_start(ap, ptr);
ret = binding->ops->nbpages(binding->data, tiling, ptr, ap);
va_end(ap);
return ret;
}
int aml_binding_pages(struct aml_binding *binding,
void **pages, struct aml_tiling *tiling, void *ptr, ...)
{
assert(binding != NULL);
assert(pages != NULL);
assert(tiling != NULL);
va_list ap;
int ret;
va_start(ap, ptr);
ret = binding->ops->pages(binding->data, pages, tiling, ptr, ap);
va_end(ap);
return ret;
}
int aml_binding_nodes(struct aml_binding *binding,
int *nodes, struct aml_tiling *tiling, void *ptr, ...)
{
assert(binding != NULL);
assert(nodes != NULL);
assert(tiling != NULL);
va_list ap;
int ret;
va_start(ap, ptr);
ret = binding->ops->nodes(binding->data, nodes, tiling, ptr, ap);
va_end(ap);
return ret;
}
/*******************************************************************************
* Init functions
******************************************************************************/
/* allocate and init the binding according to type */
int aml_binding_create(struct aml_binding **b, int type, ...)
{
va_list ap;
va_start(ap, type);
struct aml_binding *ret = NULL;
intptr_t baseptr, dataptr;
if(type == AML_BINDING_TYPE_SINGLE)
{
/* alloc */
baseptr = (intptr_t) calloc(1, AML_BINDING_SINGLE_ALLOCSIZE);
dataptr = baseptr + sizeof(struct aml_binding);
ret = (struct aml_binding *)baseptr;
ret->data = (struct aml_binding_data *)dataptr;
aml_binding_vinit(ret, type, ap);
}
else if(type == AML_BINDING_TYPE_INTERLEAVE)
{
/* alloc */
baseptr = (intptr_t) calloc(1, AML_BINDING_INTERLEAVE_ALLOCSIZE);
dataptr = baseptr + sizeof(struct aml_binding);
ret = (struct aml_binding *)baseptr;
ret->data = (struct aml_binding_data *)dataptr;
aml_binding_vinit(ret, type, ap);
}
va_end(ap);
*b = ret;
return 0;
}
int aml_binding_vinit(struct aml_binding *b, int type, va_list ap)
{
if(type == AML_BINDING_TYPE_SINGLE)
{
b->ops = &aml_binding_single_ops;
struct aml_binding_single_data *data =
(struct aml_binding_single_data *)b->data;
data->node = va_arg(ap, int);
}
else if(type == AML_BINDING_TYPE_INTERLEAVE)
{
b->ops = &aml_binding_interleave_ops;
struct aml_binding_interleave_data *data =
(struct aml_binding_interleave_data *)b->data;
/* receive a nodemask, transform into a list of nodes */
unsigned long *mask = va_arg(ap, unsigned long*);
data->count = 0;
for(int i = 0; i < AML_MAX_NUMA_NODES; i++)
if(AML_NODEMASK_ISSET(mask, i))
{
data->nodes[data->count] = i;
data->count++;
}
}
return 0;
}
int aml_binding_init(struct aml_binding *b, int type, ...)
{
int err;
va_list ap;
va_start(ap, type);
err = aml_binding_vinit(b, type, ap);
va_end(ap);
return err;
}
int aml_binding_destroy(struct aml_binding *b, int type)
{
return 0;
}
#include <aml.h>
#include <assert.h>
/*******************************************************************************
* interleave Binding
* Pages interleaved across all nodes
******************************************************************************/
int aml_binding_interleave_getinfo(struct aml_binding_data *data,
intptr_t *start, intptr_t *end,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(tiling != NULL);
size_t size = aml_tiling_tilesize(tiling, args);
*start = (intptr_t) aml_tiling_vtilestart(tiling, ptr, args);
*end = *start + size;
/* include first and last pages */
*start -= *start % PAGE_SIZE;
*end += (PAGE_SIZE - (*end % PAGE_SIZE)) % PAGE_SIZE;
return (*end - *start) / PAGE_SIZE;
}
int aml_binding_interleave_nbpages(struct aml_binding_data *data,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(tiling != NULL);
intptr_t start, end;
return aml_binding_interleave_getinfo(data, &start, &end, tiling, ptr, args);
}
int aml_binding_interleave_pages(struct aml_binding_data *data, void **pages,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(pages != NULL);
assert(tiling != NULL);
intptr_t start, end;
int i, count;
count = aml_binding_interleave_getinfo(data, &start, &end, tiling, ptr, args);
for(i = 0; i < count; i++)
pages[i] = (void *)(start + i * PAGE_SIZE);
return 0;
}
int aml_binding_interleave_nodes(struct aml_binding_data *data, int *nodes,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(nodes != NULL);
assert(tiling != NULL);
struct aml_binding_interleave_data *binding =
(struct aml_binding_interleave_data *)data;
intptr_t start, end;
int i, count;
count = aml_binding_interleave_getinfo(data, &start, &end, tiling, ptr, args);
for(i = 0; i < count; i++)
nodes[i] = binding->nodes[i%binding->count];
return 0;
}
struct aml_binding_ops aml_binding_interleave_ops = {
aml_binding_interleave_nbpages,
aml_binding_interleave_pages,
aml_binding_interleave_nodes,
};
#include <aml.h>
#include <assert.h>
/*******************************************************************************
* Single Binding
* All pages on the same node
******************************************************************************/
int aml_binding_single_getinfo(struct aml_binding_data *data,
intptr_t *start, intptr_t *end,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(tiling != NULL);
size_t size = aml_tiling_tilesize(tiling, args);
*start = (intptr_t) aml_tiling_vtilestart(tiling, ptr, args);
*end = *start + size;
/* include first and last pages */
*start -= *start % PAGE_SIZE;
*end += (PAGE_SIZE - (*end % PAGE_SIZE)) % PAGE_SIZE;
return (*end - *start) / PAGE_SIZE;
}
int aml_binding_single_nbpages(struct aml_binding_data *data,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(tiling != NULL);
intptr_t start, end;
return aml_binding_single_getinfo(data, &start, &end, tiling, ptr, args);
}
int aml_binding_single_pages(struct aml_binding_data *data, void **pages,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(pages != NULL);
assert(tiling != NULL);
intptr_t start, end;
int i, count;
count = aml_binding_single_getinfo(data, &start, &end, tiling, ptr, args);
for(i = 0; i < count; i++)
pages[i] = (void *)(start + i * PAGE_SIZE);
return 0;
}
int aml_binding_single_nodes(struct aml_binding_data *data, int *nodes,
struct aml_tiling *tiling, void *ptr,
va_list args)
{
assert(data != NULL);
assert(nodes != NULL);
assert(tiling != NULL);
struct aml_binding_single_data *binding =
(struct aml_binding_single_data *)data;
intptr_t start, end;
int i, count;
count = aml_binding_single_getinfo(data, &start, &end, tiling, ptr, args);
for(i = 0; i < count; i++)
nodes[i] = binding->node;
return 0;
}
struct aml_binding_ops aml_binding_single_ops = {
aml_binding_single_nbpages,
aml_binding_single_pages,
aml_binding_single_nodes,
};
#include <aml.h>
#include <assert.h>
/*******************************************************************************
* Tiling functions
******************************************************************************/
size_t aml_tiling_vtilesize(struct aml_tiling *t, va_list args)
{
assert(t != NULL);
return t->ops->tilesize(t->data, args);
}
size_t aml_tiling_tilesize(struct aml_tiling *t, ...)
{
assert(t != NULL);
va_list ap;
size_t ret;
va_start(ap, t);
ret = aml_tiling_vtilesize(t, ap);
va_end(ap);
return ret;
}
void* aml_tiling_vtilestart(struct aml_tiling *t, void *ptr, va_list args)
{
assert(t != NULL);
return t->ops->tilestart(t->data, ptr, args);
}
void* aml_tiling_tilestart(struct aml_tiling *t, void *ptr, ...)
{
assert(t != NULL);
va_list ap;
void* ret;
va_start(ap, ptr);
ret = aml_tiling_vtilestart(t, ptr, ap);
va_end(ap);
return ret;
}
/*******************************************************************************
* Tiling Iterator functions
******************************************************************************/
int aml_tiling_iterator_reset(struct aml_tiling_iterator *it)
{
assert(it != NULL);
return it->ops->reset(it->data);
}
int aml_tiling_iterator_next(struct aml_tiling_iterator *it)
{
assert(it != NULL);
return it->ops->next(it->data);
}
int aml_tiling_iterator_end(struct aml_tiling_iterator *it)
{
assert(it != NULL);
return it->ops->end(it->data);
}
int aml_tiling_iterator_get(struct aml_tiling_iterator *it, ...)
{
assert(it != NULL);
va_list ap;
va_start(ap, it);
it->ops->get(it->data, ap);
va_end(ap);
return 0;
}
/*******************************************************************************
* Iterator Init
* We can't do the allocation ourselves here, as we don't have the type of the
* tiling.
******************************************************************************/
int aml_tiling_create_iterator(struct aml_tiling *t,
struct aml_tiling_iterator **it, int flags)
{
assert(t != NULL);
assert(it != NULL);
return t->ops->create_iterator(t->data, it, flags);
}
int aml_tiling_init_iterator(struct aml_tiling *t,
struct aml_tiling_iterator *it, int flags)
{
assert(t != NULL);
assert(it != NULL);
return t->ops->init_iterator(t->data, it, flags);
}
int aml_tiling_destroy_iterator(struct aml_tiling *t,
struct aml_tiling_iterator *it)
{
assert(t != NULL);
assert(it != NULL);
return t->ops->destroy_iterator(t->data, it);
}
/*******************************************************************************
* Init functions
******************************************************************************/
/* allocate and init the tiling according to type */
int aml_tiling_create(struct aml_tiling **t, int type, ...)
{
va_list ap;
va_start(ap, type);
struct aml_tiling *ret = NULL;
intptr_t baseptr, dataptr;
if(type == AML_TILING_TYPE_1D)
{
/* alloc */
baseptr = (intptr_t) calloc(1, AML_TILING_1D_ALLOCSIZE);
dataptr = baseptr + sizeof(struct aml_tiling);
ret = (struct aml_tiling *)baseptr;
ret->data = (struct aml_tiling_data *)dataptr;
aml_tiling_vinit(ret, type, ap);
}
va_end(ap);
*t = ret;
return 0;
}
int aml_tiling_vinit(struct aml_tiling *t, int type, va_list ap)
{
if(type == AML_TILING_TYPE_1D)
{
t->ops = &aml_tiling_1d_ops;
struct aml_tiling_1d_data *data =
(struct aml_tiling_1d_data *)t->data;
data->blocksize = va_arg(ap, size_t);
data->totalsize = va_arg(ap, size_t);
}
return 0;
}
int aml_tiling_init(struct aml_tiling *t, int type, ...)
{
int err;
va_list ap;
va_start(ap, type);
err = aml_tiling_vinit(t, type, ap);
va_end(ap);
return err;
}
int aml_tiling_destroy(struct aml_tiling *b, int type)
{
return 0;
}
#include <aml.h>
#include <assert.h>
/*******************************************************************************
* 1D Iterator